Exploit development: Buffer overflow

Buffer overflows are still found in various applications. The Exploit Database shows 48 buffer overflow related exploits published so far this year (July 2020). They are still highly visible. However, modern operating systems have made it tremendously more difficult to execute these types of attacks. Countermeasures such as DEP and ASLR has been introduced throughout the years. However, in this article, the focus will be on the buffer overflow concept rather than the modern security measures.

Buffer overflow theory

The image above shows a simple (but vulnerable) application written in the programming language C. It will ask for the user’s name and print the output. However, if the input exceeds with 18 bytes; it will lead to a buffer overflow. A properly developed application would ignore every byte beyond the designated value, which is 10 bytes.

The application allows the user to overwrite the EBP and EIP, which is a critical security flaw. Shortly explained, the EIP is the instruction which tells the application “what to do next”. If an attacker can control the EIP, the user can control the “execution flow” and direct the application to a malicious payload.

The application above shows how a buffer overflow is triggered by entering 18 bytes into the application. The EIP gets overwritten, and the application crashes. The instruction “AAAA” (\x41\x41\x41\x41 in hex) is not understood by the application.

Furthermore, rewriting the C application and using fgets rather than puts removes the security flaw. The image above shows that the user cannot exceed 10 bytes. In practice, the user cannot control the EIP.

Application fuzzing

The vulnerable application chosen for demo purposes is PCMan FTP Server 2.0.7. The application has a series of buffer overflow vulnerabilities. However, the focus is on the PORT command within the FTP application. The targeted system is Windows XP SP3.

The Python program shown above logs on as the anonymous user on the FTP server before fuzzing the PORT command. The fuzzing string starts with PORT + 200 A characters (\x41). For every round, the string will exceed with another 200 characters. If the application crashes – the string length is printed and the Python program exits.

Furthermore, the fuzzer successfully detected the buffer overflow at 2400 characters, as shown above. The FTP server crashed, which is a good sign; as the EIP has been overwritten with \x41\x41\x41\x41.

Exploit development

Moreover, the exact offset to the EIP is still unknown. The PORT command crashed at 2400 characters. However, when does the fuzzer begin to overwrite the EIP? 2050 character? 2300 characters? Therefore, a specially crafted pattern must be sent into the application to detect the offset. The image above shows the Metasploit tool pattern_create.rb creating a unique pattern of 2500 characters. This will be used to detect the EIP’s offset.

The pattern is put into the Python program and sent to the application. The pattern will overwrite the EIP, which will be used to detect the offset.

The FTP application is attached to Immunity Debugger, which can be used to view the EIP while interacting with the FTP server. When executing the application whilst the debugger is active; the Python program sends the pattern. Four bytes of the pattern is found in the application’s EIP, as shown in the image above. The value is 43396F43.

Moreover, now that the EIP has been overwritten with 43396F43 (which is located in the pattern), the offset can be identified using the pattern_offset.rb tool, which queries the previously created pattern. The offset is 2007 characters. This means that any character after 2007 bytes will begin to overwrite the EIP.

Now that the offset is known, it can be verified using both Python and Immunity Debugger. Verifying the results can, in some cases, help to remove any errors during the exploit development. Sending in 2007 bytes of \x41, followed by \x42 * 4 and \x43 * 4 can verify that the EIP’s four bytes only consists of \x42\x42\x42\x42, and no other values. The Python program above will parse these values to the application.

Furthermore, after executing the Python program, the EIP consists of \x42\x42\x42\x42, which means that the exact offset is confirmed. The EIP can now be controlled.

The next step can be conducted without the use of automated tools. Mona.py is a Python plugin for Immunity Debugger. It can execute a series of commands to aid during the exploit development. However, mona.py is used to query the JMP ESP instructions. The JMP ESP instruction can be designated to the EIP, which can make an attacker point directly to a malicious payload. The image above shows the output from the command !mona jmp -r esp in Immunity Debugger. Mona.py suggests a series of JMP ESP addresses which can be used to point to the payload.

The chosen JMP ESP instruction was USER32.dll with the address 0x7e429353. However, as the targeted system’s CPU is little-endian, the address must be reversed. Little-endian CPU’s read instructions from right to left. Therefore, the EIP value must be set to 5393427e. In the Python exploit, the value will be \x53\x93\x42\x7e.

Moreover, the payload is generating using msfvenom. The payload could either be a reverse or bind shell – depending on the situation and preferences. The output is set to Python, as it can be copied directly into the exploit code. However, \x0a\x00\x0d are identified as bad characters. These characters can be identified using mona.py. Identifying bad characters is often redundant and time-consuming. The identified characters were excluded from the payload, as they will disrupt the exploit.

Furthermore, the final step is to connect every section together in the exploit code, as shown in the image above. A buffer overflow exploit is more reliable when using a NOP sled, which has the value \x90. The NOP sled is put directly after the EIP.

JUNK -> EIP -> NOP SLED -> MALICIOUS PAYLOAD

The exploit is now ready to be executed against the targeted system. The code will fill up the target’s buffer with 2007 bytes of junk (\x41) until the exact offset is hit. From thereon, the value \x53\x93\x42\x7e (JMP ESP) tells the application to “point” to the NOP sled before executing the malicious payload.

  1. Start Metasploit’s multi/handler
  2. Set the payload, lhost, and lport
  3. Run the module
  4. Execute the Python exploit
  5. Meterpreter session 1 opened

Conclusion

Buffer overflow vulnerabilities are very serious, as they could lead to remote access. They are still common to find in the year 2020, as shown in the Exploit Database. However, strict security measures have been implemented throughout the years to prevent these types of attacks. Thus, they are still possible to conduct on modern operating systems.