來源:http://bbs.ichunqiu.com/thread-9619-1-1.html?from=ch
0x00 簡介
分布式掃描好多人都寫過,例如:
burp的sqli插件
Matt前輩的http://zone.wooyun.org/content/24172
豬豬俠前輩的http://zone.wooyun.org/content/21289
Ver007前輩的http://zone.wooyun.org/content/24333
0x_Jin前輩的http://zone.wooyun.org/content/24341
填上個坑填的心煩,想著也造個輪子绍坝,忙活了幾天,寫了一個簡單的雛形
Github:https://github.com/liuxigu/ScanSqlTestchromeExtensions
在此感謝bstaint宵荒、sunshadow的幫助
Sqlmapapi本來就是為了實現分布式注入寫的,在被動掃描的基礎上 加節(jié)點就實現分布式了
最初想的是用chrome插件來實現代碼注入
用js來獲取標簽的同域url,用js是防止一些站的反爬蟲措施,還有對于a href指向相對鏈接的的情況,用js會自動補全域名.
Chrome webRequest API OnBeforeRequest獲取即將請求的url
設想獲取url后 喂給sqlmapapi, 將能注入的url寫入到文本里,js 的 FileSystemObject gg.. 本來是準備用php實現文件io的…
talk is cheap show me the code.
0x01 Chrome manifest.json
[AppleScript]純文本查看復制代碼
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#!js
{
"name":"sqlInjectionTest",
"version":"0.1",
"description":"you know...",
"manifest_version":2,
"content_scripts":[{
"matches":["*://*/*"],
"js":["inject.js"]
}],
"permissions":[
"*://*/*",
"webRequest",
"webRequestBlocking"
],
"browser_action":{
"default_icon":"icon.png",
"default_title":"scan url inject"
}
}
0x02 Sqlmapapi.py code
一:固定Admin Id
Sqlmapapi啟動后 是這樣子:
[AppleScript]純文本查看復制代碼
1
2
3
4
5
6#!bash
root@kali:~/桌面/sqlmap# python sqlmapapi.py -s
[22:02:17] [INFO] Running REST-JSON API serverat'127.0.0.1:8775'..
[22:02:17] [INFO] Admin ID:7c4be58c7aab5f38cb09eb534a41d86b
[22:02:17] [DEBUG] IPC database:/tmp/sqlmapipc-5JVeNo
[22:02:17] [DEBUG] REST-JSON API server connectedtoIPC database
AdminID每次都會變,這樣導致任務管理不方便,我們更改一下sqlmap的源碼
定位到/sqlmap/lib/utils/api.py 的server函數
看到644行的os.urandom,直接改成一個固定字符串就行了
例如 我改成了DataStore.admin_id = hexencode('wooyun')
以后就固定是Admin ID: 776f6f79756e
還有個更簡單的辦法
return True
二:sqlmap掃描任務結束自動寫入文本
判斷當前任務是否掃描完成 訪問http://127.0.0.1:8775/admin/ss/list
[AppleScript]純文本查看復制代碼
1
2
3
4
5
6
7
8#!python
{
"tasks":{
"4db4e3bd4410efa9":"terminated"
},
"tasks_num":1,
"success":true
}
Terminated代表任務已終止,
http://127.0.0.1:8775/scan/4db4e3bd4410efa9/data
[AppleScript]純文本查看復制代碼
1
2
3
4
5
6#!python
{
"data":[],
"success":true,
"error":[]
}
“data”存放了sqlmapapi檢測時用的payload, “data”非空就代表當前任務是可注入的,sqlmapapi并沒有自帶回調方式…輪詢浪費開銷,這里我選擇修改源碼
定位到scan_data函數 ,可以看到,假如可注入,就會從data表檢索數據并寫入到json_data_message,表名為data, 代碼向上翻,定位到將數據入庫的代碼
在StdDbOut類里,第230行汁雷,在insert前 插入
[AppleScript]純文本查看復制代碼
01
02
03
04
05
06
07
08
09
10#!python
withopen('/tmp/'+str(self.taskid)+'.txt','a+')asfileHandleTemp,\
closing(requests.get('http://127.0.0.1:8775/option/'+str(self.taskid)+'/list',stream=True))asreqTemp:
fileHandleTemp.write(
json.loads(reqTemp.text)['options']['url']+'\n'+
json.loads(reqTemp.text)['options']['data']+'\n'+
json.loads(reqTemp.text)['options']['Cookie']+'\n'+
json.loads(reqTemp.text)['options']['Referer']+'\n'
)
記得加載三個模塊
[AppleScript]純文本查看復制代碼
1
2
3
4#!python
import json
import requests
fromcontextlib importclosing
本意是獲取能注入的url寫入到文本里,在源碼里沒找到繼承這個類的地方…懶得去找了
訪問http://127.0.0.1:8775/option/id/list
[AppleScript]純文本查看復制代碼
01
02
03
04
05
06
07
08
09
10
11#!python
Response:
{
"options":{
......
"url":[url]http://58.59.39.43:9080/wscgs/xwl.do?smid=02&bgid=01&bj=8[/url]
……
}
"success":{
...
}
0x03 inject.js code
1.
那么要過濾掉javascript::偽協議和無sql操作的href
看到有這樣寫的:
[AppleScript]純文本查看復制代碼
1
2#!js
ifre.match('^(javascript|:;|#)',_url) or _url is None or re.match('.(jpg|png|bmp|mp3|wma|wmv|gz|zip|rar|iso|pdf|txt|db)$',_url):
甚至這樣的:
[AppleScript]純文本查看復制代碼
01
02
03
04
05
06
07
08
09
10#!js
filename=urlpath[i+1:len(urlpath)]
?0?2?0?2?0?2?0?2print?0?2"Filename:?0?2",filename
?0?2?0?2?0?2?0?2res=filename.split('.')
?0?2?0?2?0?2?0?2if(len(res)>1):
?0?2?0?2?0?2?0?2?0?2?0?2?0?2?0?2extname=res[-1]
?0?2?0?2?0?2?0?2?0?2?0?2?0?2?0?2ext=["css","js","jpg","jpeg","gif","png","bmp","html","htm","swf","ico","ttf","woff","svg","cur","woff2"]
?0?2?0?2?0?2?0?2?0?2?0?2?0?2?0?2for?0?2blacklist?0?2in?0?2ext:
?0?2?0?2?0?2?0?2?0?2?0?2?0?2?0?2?0?2?0?2?0?2?0?2if(extname==blacklist):
?0?2?0?2?0?2?0?2?0?2?0?2?0?2?0?2?0?2?0?2?0?2?0?2?0?2?0?2?0?2?0?2return?0?2False
這兩種方式假如遇到這樣的url: http://xxx/aaa/ ,就會造成無意義的開銷.
判斷是否可以進行get注入測試,其實只需要
str.match(/[\?]/); 無get參數的頁面會返回null
我們這樣寫: /http(s)?:\/\/ ([\w\W-]+\/)+ ([\w\W]+\?)+/;
再加上同域過濾净嘀,js中沒有php那樣可以在字符串中用{}引用變量的值,要在正則中拼接變量需要用RegExp對象:
[AppleScript]純文本查看復制代碼
1
2
3#!js
var urlLegalExpr="http(s)?:\/\/"+document.domain+"([\\/\\w\\W]+\\?)+";
var objExpr=newRegExp(urlLegalExpr,"gi");
2.
Js是在http response后執(zhí)行的,要進行post注入侠讯,必須在OnBeforeRequest之前獲取,chrome提供了相關的api,這個沒什么可說的 ,看代碼吧
inject.js code:
[AppleScript]純文本查看復制代碼
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121#!js
main();
functionmain(){
var urlLegalExpr="http(s)?:\/\/"+document.domain+"([\\/\\w\\W]+\\?)+";
var objExpr=newRegExp(urlLegalExpr,"gi");
urlArray=document.getElementsByTagName('a');
for(i=0;i
if(objExpr.test(urlArray[i].href)){
sqlScanTest(urlArray[i].href);
}
}
}
function sqlScanTest(url,payload){
sqlmapIpPort="http://127.0.0.1:8775";
var payload=arguments[1] ||'{"url":"'+url+'","User-Agent":"wooyun"}';
Connection('GET',sqlmapIpPort+'/task/new','',function(callback){
var response=JSON.parse(callback);
if(response.success){
Connection('POST',sqlmapIpPort+'/scan/'+response.taskid+'/start',payload,function(callback){
var responseTemp=JSON.parse(callback);
if(!responseTemp.success){
alert('urlsendtosqlmapapierror');
}
}
)
}
else{
alert('sqlmapapi create taskerror');
}
}
)
}
function Connection(Sendtype,url,content,callback){
if(window.XMLHttpRequest){
var xmlhttp=newXMLHttpRequest();
}
else{
var xmlhttp=newActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function(){
if(xmlhttp.readyState==4&&xmlhttp.status==200)
{
callback(xmlhttp.responseText);
}
}
xmlhttp.open(Sendtype,url,true);
xmlhttp.setRequestHeader("Content-Type","application/json");
xmlhttp.send(content);
}
function judgeUrl(url){
var objExpr=newRegExp(/^http(s)?:\/\/127\.0\.0\.1/);
returnobjExpr.test(url);
}
var payload={};
chrome.webRequest.onBeforeRequest.addListener(
function(details){
if(details.method=="POST"&&!judgeUrl(details.url)){
var saveParamTemp="";
for(var iindetails.requestBody.formData){
saveParamTemp+="&"+i+"="+details.requestBody.formData[i][0];
}
saveParamTemp=saveParamTemp.replace(/^&/,'');
//console.log(saveParamTemp);
payload["url"]=details.url;
payload["data"]=saveParamTemp;
}
//console.log(details);
},
{urls:[""]},
["requestBody"]);
chrome.webRequest.onBeforeSendHeaders.addListener(
function(details){
if(details.method=="POST"&&!judgeUrl(details.url)){
//var cookieTemp="",uaTemp="",refererTemp="";
for(var ecx=0;ecx
switch(details.requestHeaders[ecx].name){
case"Cookie":
payload["Cookie"]=details.requestHeaders[ecx].value;
break;
case"User-Agent":
payload["User-Agent"]=details.requestHeaders[ecx].value;
break;
case"Referer":
payload["Referer"]=details.requestHeaders[ecx].value;
break;
default:
break;
}
}
sqlScanTest("test",JSON.stringify(payload));
return{requestHeaders:details.requestHeaders};
}
},
{urls:[""]},
["requestHeaders"]);
Sqlmap能用的選項都可以在http://ip:port/option/taskid/list里查看,用到哪項寫到payload里就行了,最好是做成實時刷新代理,之前寫過爬蟲的時候寫過一個python版的挖藏,有空的話會改成js加入到inject.js里.
201602040648396999862.jpg(163.2 KB, 下載次數: 0)
6?小時前上傳
0x04 參考文獻
《使用sqlmapapi.py批量化掃描實踐》http://drops.wooyun.org/tips/6653
《chrome webRequest API》https://developer.chrome.com/extensions/webRequest