關於被動式掃描的碎碎念
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本來就是為了實現分散式注入寫的,在被動掃描的基礎上 加節點就實現分散式了
最初想的是用chrome外掛來實現程式碼注入
- 用js來獲取
<a>
標籤的同域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
#!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啟動後 是這樣子:
#!bash
[email protected]:~/桌面/sqlmap# python sqlmapapi.py -s
[22:02:17] [INFO] Running REST-JSON API server at '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 connected to IPC 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
#!python
{
"tasks": {
"4db4e3bd4410efa9": "terminated"
},
"tasks_num": 1,
"success": true
}
Terminated代表任務已終止,
http://127.0.0.1:8775/scan/4db4e3bd4410efa9/data
#!python
{
"data": [],
"success": true,
"error": []
}
“data”存放了sqlmapapi檢測時用的payload, “data”非空就代表當前任務是可注入的,sqlmapapi並沒有自帶回撥方式…輪詢浪費開銷,這裡我選擇修改原始碼
定位到scan_data
函式 ,可以看到,假如可注入,就會從data表檢索資料並寫入到json_data_message
,表名為data, 程式碼向上翻,定位到將資料入庫的程式碼
在StdDbOut類裡,第230行,在insert前 插入
#!python
with open('/tmp/'+str(self.taskid)+'.txt','a+') as fileHandleTemp,\
closing(requests.get('http://127.0.0.1:8775/option/'+str(self.taskid)+'/list', stream=True)) as reqTemp:
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'
)
記得載入三個模組
#!python
import json
import requests
from contextlib import closing
本意是獲取能注入的url寫入到文字里,在原始碼裡沒找到繼承這個類的地方…懶得去找了
訪問http://127.0.0.1:8775/option/id/list
#!python
Response:
{
"options": {
......
"url": http://58.59.39.43:9080/wscgs/xwl.do?smid=02&bgid=01&bj=8
……
}
"success":{
...
}
0x03 inject.js code
1.
那麼要過濾掉javascript::偽協議和無sql操作的href
看到有這樣寫的:
#!js
if re.match('^(javascript|:;|#)',_url) or _url is None or re.match('.(jpg|png|bmp|mp3|wma|wmv|gz|zip|rar|iso|pdf|txt|db)$',_url):
甚至這樣的:
#!js
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
這兩種方式假如遇到這樣的url: http://xxx/aaa/
,就會造成無意義的開銷.
判斷是否可以進行get注入測試,其實只需要
str.match(/[\?]/);
無get引數的頁面會返回null
我們這樣寫: /http(s)?:\/\/ ([\w\W-]+\/)+ ([\w\W]+\?)+/;
再加上同域過濾,js中沒有php那樣可以在字串中用{}引用變數的值,要在正則中拼接變數需要用RegExp物件:
#!js
var urlLegalExpr="http(s)?:\/\/"+document.domain+"([\\/\\w\\W]+\\?)+";
var objExpr=new RegExp(urlLegalExpr,"gi");
2.
Js是在http response後執行的,要進行post注入,必須在OnBeforeRequest之前獲取,chrome提供了相關的api,這個沒什麼可說的 ,看程式碼吧
inject.js code:
#!js
main();
function main(){
var urlLegalExpr="http(s)?:\/\/"+document.domain+"([\\/\\w\\W]+\\?)+";
var objExpr=new RegExp(urlLegalExpr,"gi");
urlArray=document.getElementsByTagName('a');
for(i=0;i<urlArray.length;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('url send to sqlmapapi error');
}
}
)
}
else{
alert('sqlmapapi create task error');
}
}
)
}
function Connection(Sendtype,url,content,callback){
if (window.XMLHttpRequest){
var xmlhttp=new XMLHttpRequest();
}
else{
var xmlhttp=new ActiveXObject("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=new RegExp(/^http(s)?:\/\/127\.0\.0\.1/);
return objExpr.test(url);
}
var payload={};
chrome.webRequest.onBeforeRequest.addListener(
function(details){
if(details.method=="POST" && !judgeUrl(details.url)){
var saveParamTemp="";
for(var i in details.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: ["<all_urls>"]},
["requestBody"]);
chrome.webRequest.onBeforeSendHeaders.addListener(
function(details) {
if(details.method=="POST" && !judgeUrl(details.url)){
//var cookieTemp="",uaTemp="",refererTemp="";
for(var ecx=0;ecx<details.requestHeaders.length;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: ["<all_urls>"]},
["requestHeaders"]);
Sqlmap能用的選項都可以在http://ip:port/option/taskid/list
裡檢視,用到哪項寫到payload裡就行了,最好是做成實時重新整理代理,之前寫過爬蟲的時候寫過一個python版的,有空的話會改成js加入到inject.js裡.
0x04 參考文獻
- 《使用sqlmapapi.py批次化掃描實踐》 /tips/?id=6653
- 《chrome webRequest API》 https://developer.chrome.com/extensions/webRequest
馬上2016了,希望在年前把上個坑填完
也祝各位心想事成
相關文章
- 關於大學的碎碎念2018-09-15
- 碎碎念八八2024-08-31
- 碎碎念八六2024-06-30
- 2019 碎碎念2019-01-25
- 關於AI訓練資料侵權的碎碎念2024-04-05AI
- 關於近幾年獨立遊戲的碎碎念2021-07-20遊戲
- 關於《What Remains of Edith Finch》的一些碎碎念2019-05-05REMAI
- 雜談 —— 關於面試、實習、保研的碎碎念2024-04-08面試
- 少年碎碎念:《斷肢》2020-11-18
- 城市未來碎碎念2018-11-19
- 前端開發碎碎念2018-04-13前端
- 極客大賽的碎碎念2023-02-27
- 近日一些碎碎念2024-10-17
- os 八股碎碎念2024-09-21
- 日誌列印的碎碎念總結2023-02-17
- LeetCode刷題開始,碎碎念2024-06-30LeetCode
- 資料結構碎碎念(一)2018-09-22資料結構
- 我的2022年-總結、感悟、碎碎念2022-12-19
- 剛開工,閒來無事碎碎念2023-01-28
- 一個十二年老程式猿的碎碎念2018-03-15
- 從《2077》談起,有關開放世界RPG設計理念的碎碎念2020-12-24
- 碎碎念軟體研發02:敏捷之Scrum2022-05-28敏捷Scrum
- 位元組國際化TnS演算法實習的碎碎念2023-12-23演算法
- 海康威視值得去嗎?老年硬體工程師的碎碎念2024-04-04工程師
- 關於http的瑣碎筆記2019-06-13HTTP筆記
- 碎碎念研發01:敏捷簡史和幾種軟體開發模型2022-05-21敏捷模型
- 城市未來碎碎念—從城市運營商到萬物運營商2018-12-24
- 關於 CSS 的零碎知識點2019-02-20CSS
- 從創新取捨到趕工失衡,一個獵人的《怪物獵人:世界》碎碎念2020-01-14
- ch3被動掃描學習2024-09-28
- 瑣碎記錄2019-02-18
- 摘抄——《病隙碎筆》2024-10-06
- [oracle零碎筆記]oracle零碎筆記(持續更新…)2018-10-15Oracle筆記
- win10怎麼關閉defender自動掃描_win10關閉defender自動掃描的步驟2020-06-05Win10
- 瑣碎的想法(五)for 的前世今生2023-01-11
- win10 安全中心關閉定期掃描方法 如何關閉win10自動掃描2020-10-24Win10
- 自制分散式漏洞掃描2020-08-19分散式
- 前端零碎知識點2024-05-26前端