Context

One of courses I’m taking at University this sem is callled “System and Web Security”. The first lecture was about buffer overflows.

Now the thing is there are some facts that you simply have to know, and I’m just going to put them here so that you don’t have to go through the pain of finding them out yourself. Because it’s really time consuming and just a massive rabbit hole. Finding it and digesting it is a massive pain in the butt, and so I’m just going to give you pre-digested stuff to make it easier :))

Disclaimer: I am not a security expert, and I don’t claim to be one. This is just a collection of things I wish I knew before I took the course. Also, there are some things in here that might be specific to the virtual machine that we were given for breaking. The machine has certain settings to make it easier to hack, like, for example, the address space randomization feature is off, so that we have consistent addresses to work with. So, please don’t take everything here as gospel…just a good starting point, especially if you’re a “noob”.

Buffer Overflows

  • When a function calls another function, let’s say function A calls function B, function A pushes state onto the stack. This state includes certain things that are of particular interest to us (in order from left to right):
    • The base pointer of function A, which is the address of the stack frame of function A. This is used to access local variables and parameters of function A.
    • The return address of function A, which is the address of the instruction that will be executed after function B returns.
  • Secondly, the biggest addresses are to the right of the stack, and all new functions have a smaller address. Weirdly, enough the stack grows leftwards, and into smaller addresses. Don’t ask why, I don’t know and I’m not sure that’a a rabbit hole I have the time to explore. Might be fun though.

Other Stuff

  • A NOP sled is simply a bunch of NOP instructions that we can redirect execution of the vulnerable program to, so that we can execute our shellcode. The idea is that we can just jump to the NOP sled, and then the NOP sled will just slide us down to the shellcode. This is a common technique used in buffer overflow attacks to increase the chances of successfully executing shellcode.
  • The sled is followed by the actual attack - the shellcode. The shellcode is the code that we want to execute when we successfully exploit the buffer overflow. The shellcode is usually a small piece of code that spawns a shell or executes a command.

The Exploit

Now, when doing a buffer overflow, it’s quite likely that you don’t know the address of the vulnerable buffer that you’re pumping with malicious code.

Quick note, you should compile like this:

gcc -m32 -fno-stack-protector -z execstack your-prog.c -o your-prog


Let’s continue.

1. If you’re directly running the victim program - then you can actually just get it to show you the buffer address using gdb.

  • Run your program with gdb, and set a breakpoint after the buffer has been created. Use break <line_number> to set a breakpoint, where <line_number> is some line number in the victim program after the buffer has been created.
  • Run the command run <victim_program.c> to run the program with the input file that you want to use to exploit the buffer overflow. If you have any args, add those as well.
  • Ideally it should break at the line you set the breakpoint at.
  • Now, run the command p &<buffer_name> to print the address of the buffer. This should give you the address of the buffer in memory.

This is the address of the vulnerable buffer, and it’s what you should overwrite the return address I mentioned earleir with. You’ll have to do a little bit of a calculation, because you want to overwrite the EBP along with the return address stored on the stack.

2. If you’r running the attack program, which uses a system call like execve to run the vulnerable program with some input that it generates as a command line argument, then:

  • Guess an initial starting address where the buffer might be. It doesn’t really matter. Just ensure it’s a valid address, that’s maybe somewhere in your shellcode.
  • Use the command gdb <your_program> to run the program in gdb.
  • Run the command run <your_program.c> to run the program with the input file that you want to use to exploit the buffer overflow.
  • You will most likely get a segmentation fault. This is good, because it means that the program crashed, and you can now use gdb to find out what went wrong.
  • What we want to find is the address of the buffer that we pumped with shellcode. So what we do, is pick the address that the program seg-faulted on, go to a considerably smaller address and view a massive number of instructions forward.
    • The idea is to hunt for the NOP sled. We know that’ll show up as NOP instructions, which in binary, is 0x90. So we can just look for a sequence of NOP instructions, and then we can just use that address as the address of the buffer.
    • Run the command x/1000i <address_that_the_program_broke_at - quite bytes> to examine (hence the x) the instructions at that address. This will give you a list of instructions, and you can just Ctrl-F or Cmd-F for 0x90 to find the NOP sled.
    • The address of the NOP sled is the address of the buffer that you can use to overwrite the return address with. This is the address that you should use in your exploit.

That’s…pretty much it…atleast for buffer overflow attacks.