SQLmap注入启发式检测算法

Posted 疏桐

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQLmap注入启发式检测算法相关的知识,希望对你有一定的参考价值。

1、经过setTargetEnv()就进入了checkWaf()的环节

def checkWaf():

    """
    Reference: http://seclists.org/nmap-dev/2011/q2/att-1005/http-waf-detect.nse
    """
    if any((conf.string, conf.notString, conf.regexp, conf.dummy, conf.offline, conf.skipWaf)):
        return None
    = hashDBRetrieve(HASHDB_KEYS.CHECK_WAF_RESULT, True)
    if is not None:
        if _:
            warnMsg = "previous heuristics detected that the target "
            warnMsg += "is protected by some kind of WAF/IPS/IDS"
            logger.critical(warnMsg)
        return _
    infoMsg = "checking if the target is protected by "
    infoMsg += "some kind of WAF/IPS/IDS"
    logger.info(infoMsg)
    retVal = False
    payload = "%d %s" % (randomInt(), IDS_WAF_CHECK_PAYLOAD)
    value = "" if not conf.parameters.get(PLACE.GET) else conf.parameters[PLACE.GET] + DEFAULT_GET_POST_DELIMITER
    value += agent.addPayloadDelimiters("%s=%s" % (randomStr(), payload))
    pushValue(conf.timeout)
    conf.timeout = IDS_WAF_CHECK_TIMEOUT
    try:
        retVal = Request.queryPage(place=PLACE.GET, value=value, getRatioValue=True, noteResponseTime=False, silent=True)[1] < IDS_WAF_CHECK_RATIO
    except SqlmapConnectionException:
        retVal = True
    finally:
        kb.matchRatio = None
        conf.timeout = popValue()
    if retVal:
        warnMsg = "heuristics detected that the target "
        warnMsg += "is protected by some kind of WAF/IPS/IDS"
        logger.critical(warnMsg)
        if not conf.identifyWaf:
            message = "do you want sqlmap to try to detect backend "
            message += "WAF/IPS/IDS? [y/N] "
            if readInput(message, default=‘N‘, boolean=True):
                conf.identifyWaf = True
        if conf.timeout == defaults.timeout:
            logger.warning("dropping timeout to %d seconds (i.e. ‘--timeout=%d‘)" % (IDS_WAF_CHECK_TIMEOUT, IDS_WAF_CHECK_TIMEOUT))
            conf.timeout = IDS_WAF_CHECK_TIMEOUT
    hashDBWrite(HASHDB_KEYS.CHECK_WAF_RESULT, retVal, True)
    return retVal
2、启发式注入检测
def heuristicCheckSqlInjection(place, parameter):
    if kb.nullConnection:
        debugMsg = "heuristic check skipped because NULL connection used"
        logger.debug(debugMsg)
        return None
    origValue = conf.paramDict[place][parameter]
    paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place
    prefix = ""
    suffix = ""
    randStr = ""
    if conf.prefix or conf.suffix:
        if conf.prefix:
            prefix = conf.prefix
        if conf.suffix:
            suffix = conf.suffix
    while randStr.count(‘\‘‘) != 1 or randStr.count(‘\"‘) != 1:
        randStr = randomStr(length=10, alphabet=HEURISTIC_CHECK_ALPHABET)
    kb.heuristicMode = True
    payload = "%s%s%s" % (prefix, randStr, suffix)
    payload = agent.payload(place, parameter, newValue=payload)
    page, _, _ = Request.queryPage(payload, place, content=True, raise404=False)
    kb.heuristicPage = page
    kb.heuristicMode = False
    parseFilePaths(page)
    result = wasLastResponseDBMSError()
    infoMsg = "heuristic (basic) test shows that %s parameter " % paramType
    infoMsg += "‘%s‘ might " % parameter
    def _(page):
        return any(_ in (page or "") for in FORMAT_EXCEPTION_STRINGS)
    casting = _(page) and not _(kb.originalPage)
    if not casting and not result and kb.dynamicParameter and origValue.isdigit():
        randInt = int(randomInt())
        payload = "%s%s%s" % (prefix, "%d-%d" % (int(origValue) + randInt, randInt), suffix)
        payload = agent.payload(place, parameter, newValue=payload, where=PAYLOAD.WHERE.REPLACE)
        result = Request.queryPage(payload, place, raise404=False)
        if not result:
            randStr = randomStr()
            payload = "%s%s%s" % (prefix, "%s.%d%s" % (origValue, random.randint(19), randStr), suffix)
            payload = agent.payload(place, parameter, newValue=payload, where=PAYLOAD.WHERE.REPLACE)
            casting = Request.queryPage(payload, place, raise404=False)
    kb.heuristicTest = HEURISTIC_TEST.CASTED if casting else HEURISTIC_TEST.NEGATIVE if not result else HEURISTIC_TEST.POSITIVE
    if casting:
        errMsg = "possible %s casting " % ("integer" if origValue.isdigit() else "type")
        errMsg += "detected (e.g. \"$%s=intval($_REQUEST[‘%s‘])\") " % (parameter, parameter)
        errMsg += "at the back-end web application"
        logger.error(errMsg)
        if kb.ignoreCasted is None:
            message = "do you want to skip those kind of cases (and save scanning time)? %s " % ("[Y/n]" if conf.multipleTargets else "[y/N]")
            kb.ignoreCasted = readInput(message, default=‘Y‘ if conf.multipleTargets else ‘N‘, boolean=True)
    elif result:
        infoMsg += "be injectable"
        if Backend.getErrorParsedDBMSes():
            infoMsg += " (possible DBMS: ‘%s‘)" % Format.getErrorParsedDBMSes()
        logger.info(infoMsg)
    else:
        infoMsg += "not be injectable"
        logger.warn(infoMsg)
    kb.heuristicMode = True
    randStr1, randStr2 = randomStr(NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH), randomStr(NON_SQLI_CHECK_PREFIX_SUFFIX_LENGTH)
    value = "%s%s%s" % (randStr1, DUMMY_NON_SQLI_CHECK_APPENDIX, randStr2)
    payload = "%s%s%s" % (prefix, "‘%s" % value, suffix)
    payload = agent.payload(place, parameter, newValue=payload)
    page, _, _ = Request.queryPage(payload, place, content=True, raise404=False)
    paramType = conf.method if conf.method not in (None, HTTPMETHOD.GET, HTTPMETHOD.POST) else place
    if value.lower() in (page or "").lower():
        infoMsg = "heuristic (XSS) test shows that %s parameter " % paramType
        infoMsg += "‘%s‘ might be vulnerable to cross-site scripting attacks" % parameter
        logger.info(infoMsg)
    for match in re.finditer(FI_ERROR_REGEX, page or ""):
        if randStr1.lower() in match.group(0).lower():
            infoMsg = "heuristic (FI) test shows that %s parameter " % paramType
            infoMsg += "‘%s‘ might be vulnerable to file inclusion attacks" % parameter
            logger.info(infoMsg)
            break
    kb.heuristicMode = False
    return kb.heuristicTest

首先是对sql注入的检测

1
payload = "%s%s%s" % (prefix, randStr, suffix)

randStr就是随机生成的可导致sql语句因闭合问题而报错的字符,这个payload不是用来注入的,而是将其产生的页面作为启发式注入标准页面(kb.heuristicPage),与不注入产生的正常页面(kb.originalPage)作为一个基准性对比。

接下来是一个关键变量casting

1
casting = _(page) and not _(kb.originalPage)

_()函数如下

1
2
def _(page):
    return any(_ in (page or "") for in FORMAT_EXCEPTION_STRINGS)

FORMAT_EXCEPTION_STRINGS 是一些在Web服务中常见的sql语句关于变量类型出错的报错

(‘Type mismatch‘, ‘Error converting‘, ‘Conversion failed‘, ‘String or binary data would be truncated‘, ‘Failed to convert‘, ‘unable to interpret text value‘, ‘Input string was not in a correct format‘, ‘System.FormatException‘, ‘java.lang.NumberFormatException‘, ‘ValueError: invalid literal‘, ‘DataTypeMismatchException‘, ‘CF_SQL_INTEGER‘, ‘ for CFSQLTYPE ‘, ‘cfqueryparam cfsqltype‘, ‘InvalidParamTypeException‘, ‘Invalid parameter type‘, ‘is not of type numeric‘, ‘<cfif Not IsNumeric(‘, ‘invalid input syntax for integer‘, ‘invalid input syntax for type‘, ‘invalid number‘, ‘character to number conversion error‘, ‘unable to interpret text value‘, ‘String was not recognized as a valid‘, ‘Convert.ToInt‘, ‘cannot be converted to a ‘, ‘InvalidDataException‘)

casting为false就代表这种注入样例因为变量类型不统一而无法使用,所以用户可以选择跳过这些样例

第二个关键变量 result

1
result = wasLastResponseDBMSError()

函数如下

1
2
3
4
5
6
def wasLastResponseDBMSError():
    """
    Returns True if the last web request resulted in a (recognized) DBMS error page
    """
    threadData = getCurrentThreadData()
    return threadData.lastErrorPage and threadData.lastErrorPage[0== threadData.lastRequestUID

如果启发式注入标准页面是可识别的,则返回ture,否则返回false

这也作为sqlmap启发性测试结果的标志,为true就代表可能存在注入,为false就可能不存在注入

接下来就是对于非sql注入漏洞的检测,sqlmap会随机生成可引发其他类型漏洞报错的字符,然后进行注入测试,在sqlmap源码中可以看出除了sql注入,还测试了xss与文件包含漏洞

1、内部类,java编译器生成的内部类的字节码文件的名字和通常的不同,内部类对应的字节码文件名字的格式是“外嵌类名&内部类类名”,如果将内部类添加修饰词static,则可以这样调用,  RedCowForm.RedCow redCow=new RedCowForm.RedCow(122,232,333);

public class NeiBuLai {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        RedCowForm form=new RedCowForm("德纳司");
        form.showMessage();
    RedCowForm.RedCow redCow=new RedCowForm.RedCow(122,232,333);
    }
}
class RedCowForm{
    static String formName;
    RedCow cow;
    RedCowForm(){
    }
    RedCowForm(String s){
        cow=new RedCow(12,23,34);
        formName=s;
    }
    public void showMessage(){
        cow.speak();
    }
     static class RedCow{
        String cowName="bed wos";
        int height,weight,price;
//        int t=0;int w=0;int p=0;
        RedCow(int h, int w,int p){
            height=h;
            weight=w;
            price=p;
        }
        void speak(){
            System.out.println("mingzi"+cowName+"shenggao"+height+"tizhong"+weight+"shenghuozai"+formName);
        }
    }
}

2、匿名类匿名类继承父类的方法一个可以重写父类的方法,匿名类必须是内部类。用匿名类创建对象时直接使用父类的构造方法。

public class NiMingLei {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ShowBoard board=new ShowBoard();
        board.showMessge(new OutPutEnglish());//这是一个OutPutAlpaabe的子类对象
        board.showMessge(new OutPutAlphabe(){ public void output(){
            for(char c=‘@‘;c<‘*‘;c++)
                        System.out.printf("%3c",c);
                }
                }
                );//这里是OutPutAlphabe的一个匿名类也是他的一个子类对象
    }
}
abstract class OutPutAlphabet{
    public abstract void output();
}
class OutPutEnglish extends OutPutAlphabet{
    public void output(){
        for(char c=‘a‘;c<‘z‘;c++){
            System.out.printf("%3c",c);
        }
    }
}
class ShowBoard{
    void showMessge(OutPutAlphabet show){
        show.output();
    }
}

3、接口匿名类

public class JieKouNiMIng {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        
        HelloMachine machine=new HelloMachine();
        machine.turnON(new SpeakHello(){
            
            public void spaek(){
                System.out.println("Hello ,you are wellcome");
            }

            @Override
            public void speak() {
                // TODO Auto-generated method stub
            }
        });
        machine.turnON(new SpeakHello(){
            public void spaek(){
                System.out.println("Hello ");
            }

            @Override
            public void speak() {
                // TODO Auto-generated method stub
                
            }
        });
    }

}
interface SpeakHello{
    void speak();
}
class HelloMachine{
    public void turnON(SpeakHello hello){
        hello.speak();
    }
}
4、异常类的处理以及自定义异常类使用

 

以上是关于SQLmap注入启发式检测算法的主要内容,如果未能解决你的问题,请参考以下文章

安全牛学习笔记​SQLMAP- 自动注入

sqlmap注入工具

sql注入神器 - sqlmap

Burpsuite+sqlmap批量扫描sql漏洞

SQLMAP自动注入

sqlmap和burpsuite绕过csrf token进行SQL注入检测