關注我們
QRcode 郵件聯系

我是如何打造一款自動化SQL注入工具的

 feng  5,775 ℃  6條點評

??0×01 前言??

??各位看官看到標題吐槽帝就開始了:已經有了各種各樣的注入工具,為什么還要手工打造一個???

事實上,做為一名苦逼乙方測試工程師以及漏洞盒子屌絲白帽子 ,在疲于應對各種死纏濫打的甲方以及成堆的web測試需求時,我經常遇到以下場景:

(1)有大批量的網站需要檢測的場景??

??乙方工程師工作辛苦勞累從來都不抱怨,有項目一定都是最能抗的,向無數奮斗在一線的乙方工程師致敬!??

??(2)系統內部業務復雜可能會存在眾多測注入點??

很多系內部業務復雜,查詢功能較多,此時可能會較多的注入點,手工測試時間緊,容易紕漏,此時需要一個提取burpsuit的history記錄的工具,來自動幫你分析問題所在。

??(3)漏洞盒子測試時間需要爭分奪秒??

在漏洞盒子進行項目安全測試時,時間就是金錢——誰能以更快的速度挖到漏洞誰就能拿到更多的獎勵.

系統框架組成:

我是如何打造一款自動化SQL注入工具的

[核心檢測引擎] Sqlmap [核心信息收集引擎] Python代理 [數據庫] mysql [Web展示] Bootstrap主題+JQuery(Ajax)

0×02 系統設計過程

??先介紹一下Sqlmapi及其用法:??

??Sqlmapapi在sqlmap中是自帶的功能,可能許多人都忽略了.當我們下載到sqlmap源碼的適合會發現在根目錄下還有一個sqlmapapi.py的文件,此時,使用命令python sqlmapapi.py -s -H 127.0.0.1 -p 8889就可以啟動了??

我是如何打造一款自動化SQL注入工具的

啟動后會生成一個Admin ID,這個AdminID就是我們用于管理Sqlmapapi使用管理id

我是如何打造一款自動化SQL注入工具的

但是注意,在新建sqlmap任務的時候,這個AdminID沒有什么作用,只是在查看任務和刪除任務的時候才有用.這個AdminID也是后面PHP程序對sqlmapapi進行管理的時候使用的AdminID,但是為了方便,我將這一部分代碼進行了重寫,使得生成的AdminID是唯一的/或者寫入一個特定的文件讓PHP去讀取。

使用的時候需要使用HTTP協議與該API進行交互。新建一個空任務,然后再向該任務POST sql注入的相關參數來啟動該任務,/task/new為新建任務,/scan/taskid/start為啟動任務接口。

需要使用POST方法向該接口提交json格式的數據,詳情可參考后文的req2sqlmap.py

我是如何打造一款自動化SQL注入工具的

有了sqlmapapi的背景知識后,我們的打造自己的自動sql注入工具之路就開始了:

這款工具后臺由Python代理實現且支持Https,啟動sqlmapapi進程后,Python代理會截取http請求并將該請求發送給Sqlmapapi,Sqlmap就開始進行注入嘗試,Web界面部分負責生成最后的結果便于測試人員直接分析,Web部分由PHP負責監控sqlmapapi并獲取注入結果保存入mysql數據庫,此處我寫了一個單獨的類庫sqlmapapi.class.php處理,只要實例化一個對象并傳入固定的adminid(sqlmap的管理id)就可以對sqlmapapi進程進行管理。

sqlmapapi.class.php代碼如下:

<?php  class 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 系統界面效果

我是如何打造一款自動化SQL注入工具的

是不是很簡潔?因為他功能少!不要打我~其實我是來騙稿費的。

0×04 系統sql注入界面截圖

我是如何打造一款自動化SQL注入工具的

上圖設計幾個實用功能:

點擊主機名可以查看sqlmap注入結果的詳細數據,包括payload,可用于手工測試. 點擊V按鈕,可以查看請求的簡要信息,如URL,POSTDATA,UserAgent,Cookie等信息 點擊R可以生產適用于Burpsuit的請求原文 點擊Sql可以生成用于sqlmap測試的bash語句(如下圖,方便我這樣的懶人去復現~)

我是如何打造一款自動化SQL注入工具的

0×05 附code

核心代理引擎項目地址:點我!

這個代理雖然可以用,但是實現上存在一些bug,我做了少量的修改,以使得更加適用于自動sql注入工具
以下是我基于上面的代理服務器寫的插件,該插件可以將請求包發給sqlmapapi

req2sqlmap.py   #encoding=utf-8 import urllib import urllib2 import re import  json from urlparse import urlparse   #每一個分布式客戶端需要又一個唯一的clientid,否則會引起沖突 #如果重啟代理,相當于添加一個新的client,因此也需要更換clientid ClintId="f3ca2b6f1b2fc73f148b6cbd0db70f42"   #sqlmapapiurl 注意后面不能有 / sqlmapapiurl="http://127.0.0.1:8775"   def getSeqKey(reqresdata):     reqresdata=str(reqresdata)     index=reqresdata.index('#')     seq=reqresdata[0:index]     return def 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 otherheaders def sendReq2Api():       return def sendRes2Api():     return def 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 req def proxy_mangle_response(res):     #print res     print "ResSeq: "+str(getSeqNum(res))     return res def 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","js","jpg","jpeg","gif","png","bmp","html","htm","swf","ico","ttf","woff","svg","cur","woff2"]         for blacklist in ext:             if(extname==blacklist):                 return False     return True def 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

*本文來自FreeBuf特約作者扛把子首席小弟投稿,屬FreeBuf黑客與極客(Freebuf.COM)獨家發布,未經允許禁止轉載

本文標簽:、
分析勒索軟件Cerber的攻擊方法
內網滲透之域滲透01-域基礎知識及介紹
Joy:一款用于捕獲和分析網絡內部流量數據的工具Joy:一款用于捕獲和分析網絡內部流量數據的工具One-Lin3r:懶人的福音,滲透測試單行化工具One-Lin3r:懶人的福音,滲透測試單行化工具EvilURL v2.0一個生成用于釣魚攻擊的IDN域名的工具EvilURL v2.0一個生成用于釣魚攻擊的IDN域名的工具國產網站惡意代碼監測(網馬監控)工具優化版國產網站惡意代碼監測(網馬監控)工具優化版

已有6條評論,歡迎點評!

smiley smiley smiley smiley smiley smiley smiley smiley smiley smiley smiley smiley smiley smiley smiley smiley

  1. #6 煙臺

    謝謝分享,頂一個!

    2016-09-06 上午 8:49回復
  2. #5 福利博客

    的確!認可!

    2016-10-30 上午 8:06回復
  3. #4 鋁材

    這樣注入的方法很特別,應該是熟能生巧吧。

    2016-11-05 上午 2:34回復
  4. #3 天下

    謝謝分享哦,學習了

    2016-11-17 上午 6:09回復
  5. #2 凱哥自媒體

    挺好的,感謝博主的分享。

    2017-01-10 上午 7:33回復
  6. #1 blog

    感覺還是非常復雜的呢。。。。

    2017-05-27 上午 10:32回復


河北家乡麻将下载 大圣捕鱼下载免费下载 不可思议棋牌下载官网 新疆福彩喜乐彩 平特一肖的正确买法 内蒙古11选5 ewin棋牌官方版游戏预约 麻将怎么打广东 群英会20选5稳赚 极速时时彩是正规的吗 下载申城棋牌 北京pk拾彩票网官网app 江苏体彩七位数开奖走势图 贵州快三下期预测分析 财神捕鱼攻略 好友联机麻将手机游戏 麻将杭州