我是怎样打造一款自动化SQL注入东西的

0×01 前言

各位看官看到标题吐槽帝就开始了:已经有了各种各样的注入东西,为什么还要手工打造一个?

事实上,做为一名苦逼乙方测试工程师以及破绽盒子�潘堪酌弊� ,在疲于应对各种死缠滥打的甲方以及成堆的web测试需求时,我经常遇到以下场景:

(1)有大批量的网站须要检测的场景

乙方工程师工作辛苦劳累从来都不抱怨,有名目一定都是最能抗的,向无数奋斗在一线的乙方工程师致敬!

(2)体系内部业务复杂可能会存在众多测注入点

很多系内部业务复杂,查询功效较多,此时可能会较多的注入点,手工测试紧,容易纰漏,此时须要一个提取burpsuit的history记录的东西,来主动帮你分析问题所在。

(3)破绽盒子测试须要争分夺秒

在破绽盒子停止名目安全测试时,就是金钱——谁能以更快的速度挖到破绽谁就能拿到更多的奖励.

体系框架组成:

[核心检测引擎]Sqlmap[核心信息收集引擎]Python代办[][Web展示]Bootstrap主题+JQuery(Ajax)

0×02 体系设计过程

先介绍一下Sqlmapi及其用法:

Sqlmapapi在sqlmap中是自带的功效,可能许多人都忽略了.当咱们下载到sqlmap源码的适合会发现在根目录下还有一个sqlmapapi.py的文件,此时,应用命令python sqlmapapi.py -s -H 127.0.0.1 -p 8889就能够启动了

启动后会天生一个Admin ID,这个AdminID就是咱们用于治理Sqlmapapi应用治理id

但是注意,在新建sqlmap义务的,这个AdminID没有什么作用,只是在检查义务和删除义务的才有用.这个AdminID也是后面PHP程序对sqlmapapi停止治理的时间应用的AdminID,但是为了方便,我将这一局部代码停止了重写,使得天生的AdminID是唯一的/或者写入一个特定的文件让PHP去读取。

应用的时间须要应用HTTP协议与该API停止交互。新建一个空义务,然后再向该义务POST sql注入的相关参数来启动该义务,/task/new为新建义务,/scan/taskid/start为启动义务接口。

须要应用POST方法向该接口提交json格式的数据,详情可参考后文的req2sqlmap.py

有了sqlmapapi的背景知识后,咱们的打造自己的主动sql注入东西之路就开始了:

这款东西后台由Python代办实现且支持Https,启动sqlmapapi进程后,Python代办会截取http恳求并将该恳求发送给Sqlmapapi,Sqlmap就开始停止注入尝试,Web界面局部负责天生最后的成果便于测试人员直接分析,Web局部由PHP负责监控sqlmapapi并获取注入成果保存入,此处我写了一个单独的类库sqlmapapi.class.php处理,只要实例化一个对象并传入固定的adminid(sqlmap的治理id)就能够对sqlmapapi进程停止治理。

sqlmapapi.class.php代码如下:

phpclass sqlmapapi {    private $adminid='';    private $sqlmapapi=SQLMAPAPI;    private $tasknumber=0;    function __construct($adminid=null) {        if($adminid!=null){            $this->adminid=$adminid;        }        $this->AutoTask();        return 0;    }    //主动处理所有义务    function AutoTask(){        $tasklistarr=  $this->getTasklist();        foreach ($tasklistarr as $taskid) {            //查询成果并入库            $this->Task2db($taskid);        }        return TRUE;    }        function getTasklist($adminid=null){        if($adminid==null){            $adminid=$this->adminid;        }        $jsonres=$this->doGet("/admin/".$this->adminid."/list");        $jsonobj= json_decode($jsonres);        $tasklist=$jsonobj->tasks;        $tasknumber=$jsonobj->tasks_num;        $this->tasknumber=$tasknumber;        print_r($tasklist);        return $tasklist;    }    function flushTask($adminid=null){        if($adminid==null){            $adminid=$this->adminid;        }        $jsonres=$this->doGet("/admin/".$this->adminid."/list");        $res=  json_decode($jsonres);        if($res['success']==true){            return TRUE;        }else{            return FALSE;        }    }    function Task2db($taskid){        $jsonres=  $this->doGet("/scan/".$taskid."/status");        print_r($jsonres);        $jsonobj=  json_decode($jsonres);        $taskstatus=$jsonobj->status;        if($taskstatus=='terminated'){            $jsonres=  $this->doGet("/scan/".$taskid."/data");            $jsonobj=  json_decode($jsonres);            $data=$jsonobj->data;            if($data==null || empty($data)||count($data)==0){                $this->delTask($taskid);                return TRUE;            }            $error=$jsonobj->error;            $taskoptionlist=  $this->getOptionList($taskid);            $url=$taskoptionlist->url;            $urlarr=parse_url($url);            $schema=$urlarr['scheme'];            $host=$urlarr['host'];            $port=0;            if(!isset($urlarr['port'])){                if($urlarr['scheme']=='http'){                    $port=80;                }elseif($urlarr['scheme']=='https'){                    $port=443;                }            }else{                $port=$urlarr['port'];            }            $cookie=$taskoptionlist->cookie;            $headers=$taskoptionlist->headers;            $postdata=$taskoptionlist->data;            $uasplit=split("User-Agent:", $headers);            $ua=$uasplit[1];            $taskscandata=  serialize($data);            $taskscanlog=  $this->getTaskScanLog($taskid);            $taskerror=  serialize($error);            $save2dbres=$this->save2Db($host, $port, $schema, $url, $cookie, $postdata,$ua, serialize($taskoptionlist), $taskscandata, serialize($taskscanlog), $taskerror);            if($save2dbres){                $this->delTask($taskid);                return TRUE;            }else{                return FALSE;            }                    }elseif($taskstatus=='not running'){            $this->delTask($taskid);            return TRUE;        }elseif ($taskstatus=="running") {            return FALSE;                    }            }    function save2Db($host,$port,$schema,$url,$cookie,$postdata,$ua,$taskoptiondata,$taskscandata,$taskscanlog,$taskerror){        global $mysqli;        var_dump(mysqli_error($mysqli));        if($num>0){            return TRUE;        }else{            return FALSE;        }            }    function getOptionList($taskid){        $jsonres=  $this->doGet("/option/".$taskid."/list");        $jsonobj=  json_decode($jsonres);//天生数组        return $jsonobj->options;    }    function getTaskScanLog($taskid){        $jsonres=  $this->doGet("/scan/".$taskid."/log");        $jsonobj=  json_decode($jsonres);        return $jsonobj->log;    }    function getUrl($taskid){            }    function delTask($taskid){        $jsonres=$this->doGet('/task/'.$taskid."/delete");        $jsonobj=  json_decode($jsonres);        if($jsonobj->success=='true'){            return TRUE;        }else{            return FALSE;        }    }            function __get($name) {        return $this->$name;    }    function __set($name, $value) {        $this->$name=$value;    }    function doGet($api){        $options = array(                CURLOPT_URL =>  $this->sqlmapapi.$api ,                CURLOPT_POST=>false,                CURLOPT_RETURNTRANSFER=>true,                CURLOPT_HEADER=>false,                CURLOPT_USERAGENT=>'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.17',        );         $myres=$this->mycurl($options);       return  $myres;    }    function doPost($api,$body){        $header = array(            'Content-Type: application/json',        );        $options = array(                CURLOPT_URL =>$this->sqlmapapi.$api ,                CURLOPT_POST=>true,                CURLOPT_RETURNTRANSFER=>true,                CURLOPT_POSTFIELDS=>$body,                CURLOPT_HEADER=>$header,                CURLOPT_USERAGENT=>'Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.57 Safari/537.17',        );        return $this->mycurl($options);    }    function mycurl($options){        $c=curl_init();        curl_setopt_array($c,$options);        $result=curl_exec($c);        curl_close($c);        return $result;    }}

我拜读了sqlmapapi的源代码和相关代码后根据情况停止了局部修改,使得其能够更好的实用于这款主动sql注入东西。

应用方法简单:测试人员只须要将浏览器代办设置为该东西所在主机的IP和端口,然后在须要测试的位置点击鼠标即可,稍后能够登录到web前端局部去检查成果。

为了成果的直观性,咱们对sql注入的成果数据和中间数据停止了整理,并将几个常用信息直接入库,这样会使得sqlmap注入完成后,测试人员能够直接还原sqlmap注入的整个语句。

0×03 体系界面效果

是不是很简洁?因为他功效少!不要打我~其实我是来骗稿费的。

0×04 体系sql注入界面截图

上图设计几个实用功效:

点击主机名能够检查sqlmap注入成果的详细数据,包括payload,可用于手工测试.

点击V按钮,能够检查恳求的简要信息,如URL,POSTDATA,UserAgent,Cookie等信息

点击R能够生产实用于Burpsuit的恳求原文

点击Sql能够天生用于sqlmap测试的bash语句(如下图,方便我这样的懒人去复现~)

0×05 附code

核心代办引擎名目地址:点我!

这个代办虽然能够用,但是实现上存在一些bug,我做了少量的修改,以使得更加实用于主动sql注入东西

以下是我基于上面的代办服务器写的插件,该插件能够将恳求包发给sqlmapapi

req2sqlmap.py #encoding=utf-8import urllibimport urllib2import reimport  jsonfrom urlparse import urlparse #每一个分布式客户端须要又一个唯一的clientid,否则会引起冲突#如果重启代办,相当于添加一个新的client,因此也须要更换clientidClintId="f3ca2b6f1b2fc73f148b6cbd0db70f42" #sqlmapapiurl 注意后面不能有 /sqlmapapiurl="https://127.0.0.1:8775" def getSeqKey(reqresdata):    reqresdata=str(reqresdata)    index=reqresdata.index('#')    seq=reqresdata[0:index]    returndef getSeqNum(reqresdata):    reqresdata=str(reqresdata)    index=reqresdata.index('#')    reqresdata=reqresdata[index+2:]    index=reqresdata.index('#')    seq=reqresdata[0:index]    return seq#天生用户唯一的标识def generateSeq(reqresseq):    return str(reqresseq)+str(ClintId) def doGet(url,cookies='',ua=''):    req=urllib2.Request(url)    if cookies!='':        req.add_header('Cookie',cookies)    if(''==ua):        req.add_header('User-Agent','Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36')    else:        req.add_header('User-Agent',ua)    f=urllib2.urlopen(req)    return f.read()def doPost(url,data='',cookies='',ua=''):    if data=='':        data={}    req=urllib2.Request(url,data,{'Content-Type': 'application/json'})    if cookies!='':        req.add_header('Cookie',cookies)    if(''==ua):        req.add_header('User-Agent','Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.118 Safari/537.36')    else:        req.add_header('User-Agent',ua)    f=urllib2.urlopen(req)    return f.read()def send2Sqlmap(url,ua,cookie='',body='',otherheaders=''):      sqlurl=sqlmapapiurl+'/task/new'    resjson=doGet(sqlurl)    jsonobj=json.loads(resjson)    taskid=jsonobj['taskid']    data={}    data['url']=url    if(cookie!=[] and cookie!=''):        data['cookie']=cookie[0]    data['headers']="User-Agent:"+ua[0]    if(''!=body):        data['data']=body    myjsondata=json.dumps(data)    sqlurl=sqlmapapiurl+'/scan/'+taskid+'/start'    doPost(sqlurl,myjsondata,cookie,ua)    if(otherheaders!=''):        print otherheadersdef sendReq2Api():     returndef sendRes2Api():    returndef proxy_mangle_request(req):    ReqSeqNum=getSeqNum(req)    print "ReqSeqNum: "+str(ReqSeqNum)    cookie=req.getHeader("Cookie")    ua=req.getHeader("User-Agent")    body=req.body    url=req.url    if(req.method=="CONNECT"):        url="https://"+url    if(isHavaParam(url,body)):        send2Sqlmap(url,ua,cookie,body)        print "send["+url+"]to sqlmapapi"    return reqdef proxy_mangle_response(res):    #print res    print "ResSeq: "+str(getSeqNum(res))    return resdef fileNameCheck(urlpath):    i = len(urlpath) - 1    while i > 0:        if urlpath[i] == '/':            break        i = i - 1    filename=urlpath[i+1:len(urlpath)]    print "Filename: ",filename    res=filename.split('.')    if(len(res)>1):        extname=res[-1]        ext=["css","","jpg","jpeg","gif","png","bmp","html","htm","swf","ico","ttf","woff","svg","cur","woff2"]        for blacklist in ext:            if(extname==blacklist):                return False    return Truedef isHavaParam(urlori,body=''):    url = urlparse(urlori)    #放过治理地址URL    if(url.hostname=='termite.xseclab.com'):        return False    if not fileNameCheck(url.path):        return False    if(''!=body or url.params!='' or url.query!='' or url.username!=None or url.password!=None):        return True    #you can add your own filter here!    return False

【责任编辑: TEL:(010)68476606】

转载自:https://netsecurity.51cto.com/art/201508/487972.htm

声明: 除非转自他站(如有侵权,请联系处理)外,本文采用 BY-NC-SA 协议进行授权 | 智乐兔
转载请注明:转自《我是怎样打造一款自动化SQL注入东西的
本文地址:https://www.zhiletu.com/archives-4524.html
关注公众号:智乐兔

赞赏

wechat pay微信赞赏alipay pay支付宝赞赏

上一篇
下一篇

相关文章

在线留言

你必须 登录后 才能留言!

在线客服
在线客服 X

售前: 点击这里给我发消息
售后: 点击这里给我发消息

智乐兔官微