前言
一樣先附個記分板,然後初賽的部分因為我失憶(?)了,所以就不附了,而且我也不記得題目了w

超過半年沒來這裡寫東西了w
這半年做了滿多事的,也開始跟10sec打了一些比賽,靠著台灣保送名額也在場外打過HITCON Final (Attack & Defense類的CTF)了w
不過自己真的還是好弱,還有很多很多東西還沒學,原本大一上想跟著旁聽計算機安全,不過後來因為發生一些事也沒聽完
這次是splitline突然密我要不要一起組隊打EOF,不然其實也沒考慮要打w
總之最後還是進了決賽,不過超遺憾的是這次決賽因為2019-nCoV(武漢肺炎)的原因直接變成在家打,而且打兩天,其實有點失望,而且實際上打得時候總題不太勁來…
最後拿了第五,不過完全沒感覺w跟上面差距太大了QAQ,而且我們整隊沒人做pwn,感覺超傷的…
總之,先附個官方write-up好了,不過不是很完整
- PWN
- Web
- Crypto
- Misc
接下來把我有做的東東寫一寫好了,雖然因為我太晚起有些flag不是我丟的w,然後剩下可能附個檔案這樣w
阿如果有人想撤掉檔案的話,歡迎PM我,或是去開個issuew
Misc
recovery
載下來拿到一個1GB的diskimage(也所以我沒辦法把他丟上來QAQ),同時題目給了一個提示
someone broke my disk! could you help me recover the important message stored in it?
所以直接對著那個file用TestDisk
然後就找出三個檔案看起來最特別,復原回來後發現裡面是base64後的東西,把它分別decode後拿到
1 | EOF{B43kvp_3u34yth |
1 | 1ng_b3fORe_Y04_dO_A |
1 | 4y_Ch4ng3_t0_d14k} |
湊起來就是完整的Flag: EOF{B43kvp_3u34yth1ng_b3fORe_Y04_dO_A4y_Ch4ng3_t0_d14k}
TT
yuawn說這是pwn出爛變成misc,可是我最後還是用了一些pwn的知識(?)才做出來QAQ
附個檔案: tt, libc-2.29.so
IDA F5後
1 | void __fastcall __noreturn main(__int64 a1, char **a2, char **a3) |
可以看到他free掉之後還繼續寫東西,不過我其實不知道這樣會怎樣w
比賽的時候去看了CTF-wiki,發現我只要malloc, free, write, malloc, malloc就可以任意寫值,同時也看到有個東西是__free_hook,會在free的時候執行他指向的內容,所以我們就把他只到one gadget上就可以get shell了
附個exploit
1 | #!/usr/bin/env python3 |
最後FLag: EOF{I_th1nk_th1s_sh0u1d_b3_m1sc_TT}
Unlucky
題目開起來拿到一個python檔,我們可以nc上去跟他互動
1 | #!/usr/bin/env python3 |
然後ls -al可以看到裡面有個flag跟readflag
1 | total 92 |
原本以為直接跑個./readflag就好,結果沒成功,後來把它cat出來才發現他會先吃個stdin
1 |
|
盯了很久感覺應該一定要把檔案就回來才可以,後來發現他雖然rm掉了,可是fd沒關,所以/proc/self/fd/3裡還可以把它弄回來,可是因為subprocess.Popen的特性,fork出來的小孩不會繼承fd,所以想了一段時間才知道怎麼做,具體來說我們可以nc上去看當前的pid,接著再趕快nc上去一次,這時的pid會是上次的pid+4,所以我們就可以把它的fd cat出來的,這裡附個拿shell的python script
1 | #!/usr/bin/env python3 |
拿到shell之後是個簡單fmt漏洞,可以構造payload %p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p 之類的來把stack上的buffer內容弄出來,附個那時的輸入輸出
1 | %p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p,%p |
最後p64還原成string後得到flag: EOF{f4mili4R_w1th_Linux???}
Crypto
Lucky
拿到一個python寫的腳本,然後我們可以連線上去跟他互動
1 | #!/usr/bin/env python3 |
看了看發現是經典的mt19937實作,看起來跟mt19937的predict很有關係,所以看著Mersenne Twister Predictor 跟一篇中國人的Blog研究了一下後發現我們可以預測mt19937是因為我們可以透過mt19937的輸出回復它當下某個register的內容,而正常那種需要624輸出的作法,就只是奠基在mt19937的register大小就是624,所以我們知道連續624的輸出之後就可以把整個mt19937的狀態記錄下來,接下來就只要模擬就好。
再定睛一看我們這題比較不一樣的是可以指定要第幾個register的內容,但是只能問兩次,接著就必須回答下一次的輸出。
觀察了一下mt19937做twist的部分,發現它會利用$r_i$的high bit跟$r_{i+1}$的low 31個bit算出一些東西後,把$r_i$變成$r_{i+397}$ xor 一些東西 (其中這裡的$r$代表mt19937的register),所以我們就可以考慮預測twist後的那個$r_0$,這樣的話我們會需要twist前的$r_0, r_1, r_{397}$,不過$r_0$的部分我們只需要一個bit,所以可以直接random撞撞看就好了,這樣我們就只要兩個輸出就可以預測下一個輸出了XD
怎麼做的部分就是我們拿到輸出的第1個數跟第397個數(0-base)還原出$r_1, r_{397}$接著讓他剛好twist一遍,我們也照著模擬twist的操作就可以拿到twist後的$r_0$了XD
附個exploit
1 | #!/usr/bin/env python3 |
最後Flag: EOF{4noTh3r_m3tH0d_t0_Br3aK_M3rSeNne_tWistEr}
Art
一樣拿到一個python寫的腳本,然後我們可以連線上去跟他互動
1 | #!/usr/bin/env python3 |
發現是個四個質數的RSA,而且$d$特別的小,所以就在想可不可以做Wiener’s attack
然而看了wikipedia,只覺得可以拿到$\varphi(N), d$,但是不像兩個質數的RSA,我構造不出一個方式可以分解$N$,後來是google wiener attack multiple factor,看到一篇文章,裡面給出了一種類似miller rabin的做法可以分解$N$,來證明拿到$d$其實跟分解$N$差不多難,同時它也有給出好的機率證明它的演算法。
最後照著寫了一波就做完了w
sol.py
1 | #!/usr/bin/env python3 |
wiener.py
1 | import ContFrac |
ContFrac.py
1 | def r_to_fr(a, b): |
arithm.py
1 | ''' |
最後Flag: EOF{Did_you_USe_Wiener_Or_Boneh_Durfee?}
Train Revenge
附個檔案server.py, BlockCipher.py
然後留個坑,沒看完這題w
Reverse
Gift
拿到一個gz檔,解開拿到一個binary,拖進IDA後看到一個很不知道要幹嘛的東西
1 | __int64 __fastcall main(__int64 a1, char **a2, char **a3) |
嘗試把那個字串塞進stdin後噴出一堆莫名其妙的東西,後來把他輸出成檔案後,file一下發現輸出是個一個類似結構的東西,連續做了好幾次後就覺得是要一職重複做這件事,但是很麻煩的是我又不知道要怎麼把那個字串弄出來,strings出來的東西也不好grep,最後決定掛個LD_PRELOAD,把strcmp直接蓋成跟strcpy差不多的東西,具體如下
1 | int strcmp ( const char * str1, const char * str2 ) { |
這樣他每次檢查都會通過,而且就幫我填好buffer了XD
接著重複跑個大概1000多次後,輸出的東西就變成flag了XD
最後Flag: EOF{re_re_re_re_reverse_U_ju5t_reverse_m3_1000_times!!}
Vault
附個檔案 vault.html, vault.js, vault.wasm
splitline做的@@
不太會逆web assembly
Tree
附個檔案 tree
IDA開起來看到是一個Treap based的Link/Cut Tree就放棄了w
超級不喜歡Link/Cut Tree的說(其實只是我爛)
想說拿angr直接炸,不過最後也沒炸出來w
附個出題者在聊天室留的解
就是經過觀察之後會發現,每次會檢查樹上一條鏈的總和是否為X,然後檢查1000次 然後把輸入裡面的六個字代入2^(1~6)然後剩下的代入2^7,然後用gdb看看適用什麼東西跟X做檢查
最後整理一下就會得到一堆2k7
一堆的N元一次方程式
然後丟z3就解掉了
Compiler
附個檔案 compiler
不過我沒看這題@@
然後周逸表示
compiler我估計用這個方法就能做掉了 https://ctf-wiki.github.io/ctf-tools/binary_core_tools/instrumentation/intel_pin/
Web
這次web看起來都很血腥就沒看了,而且想說splitline的web比我強太多了,除非有看起來很水但他懶得做的我再去看看就好了w
babyRMI2
splitline做的,初賽我也沒做babyRMI,看到Java就逃了w
下次應該認真看的
附個檔案 src.zip
Babyfirst Revenge: Remastered
不熟windows command line,但總覺得也該學一下,完整可以看官方的解
Imagination
沒看@@
splitline說是蓋python cache,不過他好像沒空做完QAQ
CureURL
Cyku出的,不過我不熟Redis,所以看到redis就跳過了QAQ
附個檔案 cureurl.zip
Pwn
今年還是不會Pwn QAQ
附個檔案在這
Whitehole
Blackhole
EasierROP
nonono_revenge
nonono_revenge, fake_flag, libc.so.6