Tags: elf pwn exploitation pwning bufferoverflow rev buffer-overflow reversing netcat linux 

Rating: 4.0

Original Article at<span>:

Pwning 25 (Ultra baby)

The attachment contains an ELF binary named “ultrababy”. This binary is similar to one being hosted as a service on the socket provided in the challenge’s description. The only difference between the two is that the binary included in the attachment contains a pseudo flag rather than the actual flag. This was probably done so that you can’t just look inside the binary strings of the attachment in order to find the flag. This setup forces you to actually attack the service being run on the provided socket.


  1. Once you download the REC Decompiler, you will need to setup some additional things in the environment. The first one would be to create an “output” folder directly under the extracted “RecStudioWin” folder. Note that I’m using the Windows version of REC Decompiler if it wasn’t obvious.
  2. Next, you will need to get the “ultrababy” binary in a place where the “RecCLI.exe” program will be easily be able to access it. In my case, I simply moved “ultrababy” binary inside the “bin” folder – right beside the “RecCLI.exe” program.
  3. Open a Command Prompt window and navigate to the “bin” folder of your copy of REC Studio, and then execute “RecCLI.exe ultrababy ultrababy.c”
  4. The decompilation results for the “ultrababy” ELF binary will appear inside the “output” folder you created earlier. The file name should be “ultrababy.c”.
  5. Open the file using your favourite text editor and navigate to the segment shown below. This is the only segment which will be of interest to us.
  6. We want to be able to call the “Flag” function located at memory address 0x000007F3. This function will print the flag directly onto the screen. If you’re wondering why we can’t just grab the flag right there, it’s because that’s only a pseudo flag. The real flag is on the binary running as a service on the socket specified in the description of the puzzle. This is still some pretty useful information however, as it tells us how our exploitation target operates.
  7. Look at the “main” function. Specifically, look the at the call to the “_v16” function (it’s the last one)
  8. Notice that “_v16” isn’t really a function. It’s a variable. What happens there is that the program calls the function whose address is stored inside the “_v16” variable
  9. If you look at the initialisation of the “_v16” variable, you will find that it is assigned the value of 0x7E0. This is the address of the “Bye” function. If we could change the value of “_v16” from 0x7E0 to 0x7F3, then we would be able to call the “Flag” function which in turn will print the flag onto the screen.
  10. Our point of attack shall be the “read” function. What this function does is that it reads some string from the Standard Input (user input) and places the string onto the specified buffer (which in this case is the “_v40” variable). This function does not perform any bounds checking, so if we place an input that is larger than the size of the “_v40” buffer, the extra input will overflow onto the “_v16” variable. This will allow us to overwrite the contents of the “_v16” variable and call the “Flag” function.
  11. At this point, we have no idea how big the “_v40” buffer is, so we’re going to have to find out. To do this, we just feed an increasing number of characters into the Standard Input of the “ultrababy” program until we get a Segmentation Fault.
  12. Once we get a Segmentation Fault, we will know how big the “_v40” buffer is. In this case, the program broke at 25 characters. This means that the “_v40” buffer is 24 bytes long. It broke at 25 characters because we accidentally wrote over the first byte of the “_v16” variable, and, as we remember, this variable is used by the program to call some function. If we place an invalid address there, the program will result in a Segmentation Fault.
  13. We now know how big the “_v40” buffer is (24 bytes), and we also know the address of the “Flag” function (0x7F3). The only thing we need to do now is to formulate a specially crafted input that we will feed into the Standard Input of the “ultrababy” program in order to overwrite the “_v16” variable with the value of 0x7F3.
  14. For this task, we will use the “echo” command in Linux and pipe its output to the Standard Input of an “ultrababy” instance, but this time, we’re going to pipe it into the “ultrababy” instance running as a service on the socket provided in the description of the puzzle.
  15. The command that we will use is “echo -n -e “AAAAAAAAAAAAAAAAAAAAAAAA\xf3\x07\x00\x00”. The “-n” flag tells the echo command not to append an extra newline at the end of the string it will output. This is important because we need to be exact with the data that we will feed into the “ultrababy” service. The “-e” flag tells echo that it shall interpret backslash escaped characters. This is important because we want the “\xf3\x07\x00\x00” part of the data we’re feeding into the echo command to be transformed into the appropriate byte values (i.e. we want \xf3 to be transformed into a byte with the value of 0xf3 rather than a “\xf3” literal string). We’re feeding the address in reverse order because addresses are commonly stored in little-endian format. This means that the higher part of the address is in a higher memory location and the lower part of the address is in a lower memory location. Meanwhile, strings are stored in such a way that the first character is in a lower memory location and the last character is in a higher memory location. This means that the lower part of the “_v16” variable will be written first, hence the reverse order of our input.
  16. Lastly, we simply pipe our echo command into a netcat command which connects to the “ultrababy” service, and then we’ll have our flag.
  17. The flag is EKO{Welcome_to_pwning_challs_2k16}