So far, the compass analysis will depend on humans. This function is not complex. We can see that the process of generating a new string is actually completed within canonicalizepathname () (. Text: 7517f856
Call sub_7517fc68 ). This function uses local variables to store new strings in the open space in the stack. This space can be exceeded.
Specifically, the actions before netpwpathcanonicalize () calls canonicalizepathname () include:
1. Determine whether the 6th parameters are 0. Exit if the value is not 0.
2. Check whether the value of the 5th parameters is 0. If the value is 0, perform a netpwpathtype verification call.
3. Check whether the value referred to by the 4th parameters is 0. If the value is not 0, put the indicated string in netpwpathtype for verification.
4. In this verification, if the Unicode length of string 4 exceeds 0x103 (the byte length is 0x206), 0x7b (error_invalid_name) is returned, causing program exit
5. Check whether the buffer size is 0. Otherwise, exit.
6. Call the canonicalizepathname () function.
......
Canonicalizepathname () is a function that actually overflows. Check this function with IDA:
========================== S u B r o u t I n e = ======================================
7517fc68 int _ stdcall sub _ canonicalizepathname (wchar_t *, Int, INT)
7517fc68 push EBP
7517fc69 mov EBP, ESP
7517fc6b sub ESP, 414 H // open up the stack space for temporary saving of the generated string
7517FC71 push ebx
7517FC72 push esi
7517FC73 xor esi, esi
7517FC75 push edi
7517FC76 cmp [ebp + arg_0], esi // determine whether the string 4 address is blank
7517FC79 mov edi, ds :__ imp_wcslen
7517FC7F mov ebx, 411 h
7517FC84 jz short loc_7517FCED
7517FC86 push [ebp + arg_0] // press string 4
7517FC89 call edi; _ imp_wcslen // calculate the unicode length of string 4. Note that it is one/half of the byte length, which is the root cause of the breakthrough in the boundary check, that is, // use UNICODE to check the boundary, while the stack space is opened by byte.
7517FC8B mov esi, eax
7517FC8D pop ecx
7517FC8E test esi, esi
7517FC90 jz short loc_7517FCF4
7517FC92 cmp esi, ebx
7517FC94 ja loc_7517FD3E // exit the program if the request is out of bounds.
7517FC9A push [ebp + arg_0] // string 4 address
7517FC9D lea eax, [ebp + var_414] // stack temporary serial address
7517fa3 push eax
7517FCA4 call ds :__ imp_wcscpy // roll string 4 into the stack for temporary storage. Although the front boundary // check has a defect, it seems that the actually passed string 4 can reach 0 x bytes, however, string 4 was checked in advance by // NetpwPathType () before being passed in to this function. According to the preceding analysis, the length of string 4 cannot exceed 0x206 bytes, so // The inspection defects here alone are not enough to create overflow/output through string 4
7517 FCAA mov ax, [ebp + esi * 2 + var_416] // retrieve the last two bytes of the temporary string (string 4) at the moment, and check whether it is a slash.
7517FCB2 pop ecx
7517FCB3 cmp ax, 5Ch // 0x5C = 92 = ASCII (\\)
7517FCB7 pop ecx
7517FCB8 jz short loc_7517FCD5
7517 FCBA cmp ax, 2Fh // 0x2F = 47 = ASCII (/)
7517 FCBE jz short loc_7517FCD5
7517FCC0 lea eax, [ebp + var_414]
7517FCC6 push offset asc_751717B8 // unicode of the push slash
7517 FCCB push eax
7517 FCCC call ds :__ imp_wcscat // connect the unicode of the Slash to the end of the saved string in the stack
7517FCD2 pop ecx
7517FCD3 inc esi // calculate the length of the slash into the temporary string
7517FCD4 pop ecx
7517FCD5 mov eax, [ebp + arg_4] // retrieve string 1, similar to checking whether the first character of string 1 is // slash or backslash
7517FCD8 mov ax,
7517 FCDB cmp ax, 5Ch
7517 FCDF jz short loc_7517FCE7
7517FCE1 cmp ax, 2Fh
7517FCE5 jnz short loc_7517FCF4
7517FCE7 add [ebp + arg_4], 2
7517 FCEB jmp short loc_7517FCF4
7517 FCED mov [ebp + var_414], si
7517FCF4 push [ebp + arg_4] // string address 1
7517FCF7 call edi; _ imp_wcslen
7517FCF9 add eax, esi // calculate the length of string 4 + slash Length + Length of string 1
7517 FCFB pop ecx
7517 FCFC cmp eax, ebx
7517 FCFE ja short loc_7517FD3E // The second boundary check. From the previous analysis, we can know that overflow cannot be produced only by string 4, but there is no limit to the input of string 1, therefore, you can overflow by adding the string length of string 1. Stack // The space is 0x414. the actual length of the passed string can reach/0 x.
7517FD00 push [ebp + arg_4] // string 1
7517FD03 lea eax, [ebp + var_414]
7517FD09 push eax
7517FD0A call ds :__ imp_wcscat // concatenates 1 into a temporary string in the stack to generate the final path string. This // call causes the final stack overflow.
7517FD10 pop ecx
............
7517FD66 lea eax, [ebp + var_414]
7517FD6C push eax
7517FD6D push [ebp + arg_8]
7517FD70 call ds :__ imp_wcscpy // return the result in the stack to the buffer referred to by the second parameter
7517FD76 pop ecx
7517FD77 xor eax, eax
7517FD79 pop ecx
7517FD7A pop edi
7517FD7B pop esi
7517FD7C pop ebx
7517FD7D leave
7517FD7E retn 14 h
====================== S u B r o u t I N E ====== ======================================
Code 1: netapi32.dll disassembly code snippet. The complete code can be obtained from the disassembly of the DLL file in the attachment.
As described in the comment, the limitations on the boundary of the temporary strings in the stack Are unicode length cannot exceed 0x411, and the converted bytes length is 0x822, the size of the stack space is 0x414 in bytes, which is the root of the failed boundary check.
In addition, string 4 must pass the NetpwPathType () Verification to pass in CanonicalizePathName (). Therefore, the string length cannot exceed 0x206 bytes, But it passes through wcscat () A stack overflow can be created successfully after the string 1 with no length limit.
1.3 OLLYDBG, Ding jieniu
After Static Analysis by IDA, let's try to debug this function dynamically and trigger this overflow. The first thing to do is load the dynamic link library, locate the address of the NetpwPathCanonicalize () function, and then you can call this function.
Local overflow experiments do not have to find machines with vulnerabilities. If your machine is not WIN2000 SP4 or has been patched, you have already mentioned where to find this library file.
For example, use the following method:
========================================================== ========================================
# Include
# Include
Typedef void (* MYPROC) (LPTSTR );
Int main ()
{
HINSTANCE LibHandle;
MYPROC ProcAdd;
Char dllbuf [40] = \ "./netapi32.dll \";
Char Trigger [40] = \ "NetpwPathCanonicalize \";
...... // Function arg define
LibHandle = LoadLibrary (dllbuf );
ProcAdd = (MYPROC) GetProcAddress (LibHandle, Trigger );
...... // Function arg init
(ProcAdd) (arg_1, arg_2, arg_3, arg_4, buf5, 0 );
FreeLibrary (LibHandle );
}
Code 2: DLL mounting. The complete code is located in the attachment local_exploit_040.c.
The above code is the framework of our local overflow experiment code. You can first add a few values to the parameter according to the result of the front edge analysis. During the debugging process, after VC compilation, if the function parameter is "correct", XP Always reports check esp erro during execution, however, remote overflow RPC calls can be executed normally.
Next we will debug this BIN and use OLLYDBG to clarify the execution details of netapi32.dll. Dear friends, are you ready to take a look at Ding Jie Niu's feelings?
Using VC to compile the link to generate a BIN will cause an error. It doesn't matter. We use OLLYDBG to open the executable file. The default loading method stops at the entrance of the program. The executable file we debug should be the debug version generated by VC, so it should be parked in the PE loading area. Note that this is not our main () function.
If you have patience, you may wish to press F8 to take a look at the windows pe loading process and see what you did before main.
1. There will be a call to GetCommandLineA not far from the entry, followed by three push operations on EDX, ECX, and EAX, Which is passing parameters for the main () function. The subsequent call is our main. When F8 goes to this call, you need to add F7 to the main () function.
After entering main (), you will see that OLLDBG has identified standard system API calls for us and automatically commented out. As written in C code, LoadLibarayA, GetProcessAddress, and memset are called in sequence, and a function is called after six consecutive push operations. This corresponds to ProcAdd (arg_1, arg_2, arg_3, arg_4, buf5, 0) Assembly form. Function call parameters are in the stack order from right to left, so the first pressure is 0. If you perform the first dynamic debugging, you can check the values of the parameters pushed in the stack and view the content in the memory at the corresponding memory location, I feel that such debugging is the most direct and effective way to understand the underlying computer system.
After the CPU executes this call, we also use F7 to enter this function. We can see that the Code area switched from 0x004xxxxx to 0x7xxxxxxx, that is to say, the program jumps from the code section of our executable file to the Code section of the netpwpathcanonicalize function in netapi32.dll.