Our team: http://www.ph4nt0m.org
Author: Yun Shu (wustyunshu@hotmail.com)
This article can be reproduced at will, but please keep it complete and keep the original source. Thank you.
Cause
A foreigner wrote an articleArticle<Writing a. Net security exploit POC>CodeThe address is http://www.frijters.net/typesafetyexploitpoc.cs.txt. KJ can be used in SQL Server 2005, and the shell can be obtained by loading C # code to bypass the sandbox restriction. After the test, the Code failed to run. I conducted some preliminary debugging and found that the Code failed to search for the address of the winexec function in the memory and returned 0, so it could not be executed smoothly.
At this time, the thorn is added. We split the header and thought that we do not need to perform Memory search in C #. Since we can write the machine code, we can directly write a shellcode. So I found a shellcode in the http://metasploit.com, modify the original POC, the thorn also made a modified POC code that can be successfully run.
In the evening, kJ took the job home and tested it in SQL Server 2005. But there are still many restrictions, so it is basically a chicken fault. Please refer to his article. The address is Baidu. But the code is not complex, but what is the principle? They are not very familiar with C #, so the responsibility falls on me and started the debugging of code running in a painful virtual machine. As for this POC code, I sent it to our mail list, the address is http://groups.google.com/group/ph4nt0m/browse_thread/thread/1ee957d07b33931f/6a0e158cb1deb078? Show_docid = 6a0e158cb1deb078. In my reply, I will not write it here.
Principle
To understand the concept of this POC, you must first understand the basis of CLR. I have tracked and analyzed these documents, but they are not necessarily correct. Just listen. Define arrays directly in C # And save elements in the stack. However, if an array is a member of a class, only one pointer is saved in the stack when the class is instantiated and the array is initialized. This Pointer Points to the place where the elements are actually stored. The memory to be pointed to. The first four bytes stores methodtable, the second four bytes stores the number of elements, and the third four bytes begins to store real array elements.
In POC, union2 class has an arr array as its member, and another o member is assigned a value by a delegate, which is actually a function pointer, 4 bytes. The unsafeunion struct with U1 and U2 instances declares [structlayout (layoutkind. explicit)] and [fieldoffset (0)], indicating that the U1 and U2 offsets in the memory are both 0 bytes. Because U1 is a two int, both of which are 4 bytes, while U2's O member and ARR are both pointer and 4 bytes. Therefore, the I elements of U1 and the O elements of U2 are re-integrated in the memory. The J elements of U1 and the ARR elements of U2 are re-integrated in the memory, and U1 and U2 are fully integrated in the memory.
The Del delegate in the POC points to the dummymethod function. In the CLR language, you cannot obtain the function pointer through safe code. Therefore, you can only indirectly pass the function address by assigning del to object o. Finally, by modifying the value of int type J, the address that arr points to is indirectly modified, and the ARR points to the dummymethod function. In the end, the ARR is modified by modifying the code of the dummymethod function. When the function is executed through delegation, the custom shellcode is executed and the sandbox jumps out.
The POC author is familiar with C # And not familiar with security, so the code is long and not reliable enough. Just modify it. The principle is somewhat bypassed. I will use dynamic tracking to prove this.
Debugging
C # The code runs in the CLR virtual machine, so it is basically impossible to use ollydbg for debugging. If someone has a solution, please give me some advice. After some searches at Microsoft, Visual Studio 2008 is used to load SOS. DLL for dynamic tracking. You can search for SOS. DLL for specific documents. The following is a brief introduction to my debugging process, because I think this is very interesting. Of course, this is the case after the exploration, so it looks very smooth. In fact, it took me more than two days to complete the learning from SOS. DLL to tracking and analysis.
First, load the Code project I modified, break the breakpoint at the first line of the main function, open the memory window, and then enter the command in the immediate window in the lower right corner. load SOS load. DLL module. The entire interface is shown in. We hope this is the only one.
Javascript: drawimage (this);>
. Load SOS
Extension c: \ windows \ Microsoft. NET \ framework \ v2.0.50727 \ SOS. dll loaded
We can see that SOS. dll is successfully loaded and can be used! View the help information of the Debug Command provided by the SOS module. For more information, see the manual.
One step to view the stack information of the CLR virtual machine. The result is as follows:
! Clrstack-
OS thread ID: 0x8f4 (2292)
ESP EIP
0012f418 00e500e4 typesafetyexploitpoc. Main (system. String [])
Parameters:
ARGs = 0x01301628
Locals:
0x0012f440 = 0x00000000
0x0012f43c = 0x01301664
0x0012f438 = 0x00000000
0x0012f434 = 0x00000000
0x0012f430 = 0x00000000
0x0012f42c = 0x00000000
0x0012f428 = 0x00000000
0x0012f424 = 0x00000000
0x0012f420 = 0x00000000
0x0012f41c = 0x00000000
0x0012f418 = 0x00000000
0012f69c 79e7c74b [gcframe: 0012f69c]
As you can see, the U2 variable has been defined and the address in the stack is 0x01301664. Go to the u2.o = del statement in a single step. Check the stack and you will find that u1, U2, and del are defined, in addition, the memory that U1 and U2 point to is the same as what I mentioned above. They all point to 0x01301664 -- of course, the specific memory address depends on the machine. The Del value is 0x01301674.
In the memory window, view the memory at the 0x01301664 address, complete the u2.o = del statement in one step, and then check the memory. The memory at 0x01301664 + 4 is changed to the Del value, that is, 0x01301674. Note that U1 and U2 completely overlap in the memory, so the u1. I value is also changed to 0x01301674. Why is the memory 0x01301664 + 4 instead of 0x01301664? Check the U2 structure as follows:
! Dumpobj 0x01301664
Name: union2
Methodtable: 009830fc
Eeclass: 00981344
Size: 16 (0x10) bytes
(E: \ testexp \ bin \ debug \ testexp.exe)
Fields:
MT field offset type vt attr Value Name
790fd0f0 4000003 4 system. Object 0 instance 01301674 o
7912d7c0 4000004 8 system. int32 [] 0 instance 00000000 arr
We can see that the first element offset of U2 is indeed 4, and the offset is 0, which stores the methodtable address and records some internal information.
After walking through u1.j = u1. I in one step, we can see that the value of memory 0x01301664 + 8 has changed. The reason for the overlap between U1 and U2 memory is that u1. I, u1.j, u2.o, and u2.arr all become the same value, that is, the del value, that is, the value of the function pointer.
The following command u1.j = u2.arr [2]-12 is the most critical entry of POC, or the command that changes the value of u1.j due to memory coincidence, indirectly modifies the address that arr points to, so that arr points to the memory that the function pointer points. Therefore, when we modify the ARR, we actually modify the memory pointed to by the function pointer, that is, the instruction to delegate the del pointer to the function dummymethod. After this code is executed, view the ARR value as follows:
! Dumpobj 0x01301664
<Note: This object has an invalid class field>
Name: union2
Methodtable: 009830fc
Eeclass: 00981344
Size: 16 (0x10) bytes
(E: \ testexp \ bin \ debug \ testexp.exe)
Fields:
MT field offset type vt attr Value Name
790fd0f0 4000003 4 system. Object 0 instance 01301674 o
7912d7c0 4000004 8 system. int32 [] 0 instance 0098c054 arr
We can see that the data in the array is already saved at address 0x0098c054. Let's take a look at the content of the function pointer 0x01301674.
! Dumpobj 0x01301674
Name: system. Threading. threadstart
Methodtable: 791249e8
Eeclass: 790347b8
Size: 32 (0x20) bytes
(C: \ WINDOWS \ Assembly \ gac_32 \ mscorlib.0.0.0 _ b77a5c561934e089 \ mscorlib. dll)
Fields:
MT field offset type vt attr Value Name
790fd0f0 40000ff 4 system. Object 0 instance 01301674 _ target
7910ebc8 4000100 8... ection. methodbase 0 instance 0130182c _ methodbase
791016bc 4000101 C system. intptr 1 instance 003b20c4 _ methodptr
791016bc 4000102 10 system. intptr 1 instance 0098c060 _ methodptraux
790fd0f0 400010c 14 system. Object 0 instance 00000000 _ invocationlist
791016bc 400010d 18 system. intptr 1 instance 00000000 _ invocationcount
Pay attention to the value of _ methodptraux, compare the memory pointed to by arr above, and find that it does fall into it. In fact, the value obtained by arr [2] is the content of this _ methodptraux. The next thing is simple. Copy shellcode to ARR, that is, copy it to the memory of the dummymethod function, and rewrite the dummymethod function. Finally, call the del delegate to call dummymethod indirectly, and then execute our shellcode to break through sandbox.