This presentation provides a detailed exploration of writing shell code for Windows NT, primarily through buffer overflow exploits. It begins by establishing fundamental concepts, illustrating a simple buffer overflow on Linux to explain stack frames, return addresses, and the mechanics of overwriting program control flow. The speakers then pivot to the unique and considerably more complex challenges presented by Windows NT, such as its position-dependent system calls, reliance on specific DLLs, and the necessity to avoid null bytes and other restricted characters in the shell code. Using the IIS HTR exploit as a practical example, the discussion covers techniques for discovering memory offsets (e.g., using patterns and debuggers), crafting position-independent code, and employing arithmetic tricks to circumvent prohibited characters. A significant portion highlights undocumented behaviors of NT, including random byte alterations in the shell code (theorized to be Unicode translation issues) and path conversion quirks, emphasizing the indispensable role of a debugger for iterative development and problem diagnosis. The overall message underscores that while NT shell code is achievable, it demands extensive experimentation and a deep understanding of low-level system intricacies, making platforms like Linux a much simpler starting point.
Summarizing NT Shell Code: Concepts, Challenges, and Techniques
0:00 Introduction to Shell Code: The presentation introduces how to write NT Shell Code, starting with general explanations of shell code and its conversion to Assembly Language.
0:45 NT vs. Unix Shell Code: Unix shell code is presented as simpler (e.g., easy shell opening), while NT requires special DLLs (like winsock.dll) and has less straightforward system calls and piping.
2:11 IIS HTR Exploit Example: The 1998 IIS HTR exploit, a buffer overflow in the file name, is used as a case study to demonstrate code execution on NT.
3:10 Buffer Overflow Mechanics (Linux): A C code example on Linux demonstrates how an excessively long environment variable (Fu) can overflow a static buffer, overwriting the program's return address on the stack.
8:01 Stack Frame & Return Address: Explains the stack frame setup, including the base pointer and allocation for local variables, and how overwriting the return address redirects program execution.
15:59 Debugger for Exploit Analysis: Debuggers are crucial for observing memory addresses and understanding program flow during a buffer overflow, noting that exploits often cause program crashes.
20:29 Little-Endian Byte Order: Intel CPUs use little-endian byte order, meaning the least significant byte of an address is stored first, impacting how buffer overflows overwrite addresses.
23:17 Zero Bytes and C Strings: C string functions terminate at null bytes (zeroes), making their presence in shell code problematic as they truncate the payload.
24:29 Essential Tools: Key tools for NT exploits include a vulnerable system, compiler, a debugger (like SoftICE or MS C++ debugger), and strong assembly programming skills.
26:28 Linux Recommended for Testing: It's advised to develop and test buffer overflows on Linux first, as NT's system calls are less forgiving and can easily crash the entire operating system.
27:17 Library Independence: Shell code must be small and avoid reliance on standard libraries, which might be too large or have incompatible versions on the target system.
30:06 NT System Call Challenges: NT system calls use load-time patched offsets to specific kernel functions, making shell code position-dependent and difficult to write compared to Linux's position-independent interrupt system calls.
31:51 Pattern-Based Offset Discovery: A technique involves filling the overflow buffer with unique byte patterns (e.g., repeating sequences, 'A's) to determine the exact offset of the overwritten return address via debugger register dumps.
40:02 Exploit-Specific Character Restrictions: The IIS HTR exploit, for instance, prohibited dots (.) in the filename portion of the URL, as they were interpreted as file extension separators.
41:53 Environment Variables for Code Placement: One method to place shell code is within environment variables, then calculating its address to use as the overwritten return address.
45:59 NOP Sleds: "No Operation" (NOP) sleds are blocks of NOP instructions placed before the actual shell code. Overwriting the return address to any point within the sled will "slide" execution to the shell code, increasing reliability.
46:46 General Shell Code Constraints: Beyond null bytes, shell code can be constrained by other prohibited characters (e.g., dots, line ends) depending on the exploit context and transport mechanism (like URLs).
52:46 C to Assembly for System Calls: A common strategy is to write the desired functionality in C, compile it, and then use a debugger to analyze the resulting assembly, identifying the low-level system calls.
58:45 NT's Position-Dependent System Calls: NT directly calls fixed addresses in system DLLs (e.g., ntdll.dll), making exploit code brittle as these addresses can change with Service Packs or system configurations.
59:23 Relative CALL Instructions: Intel's CALL instruction often uses relative offsets, meaning its binary representation changes based on its position, complicating shell code construction.
1:07:44 Avoiding Zero Bytes (Arithmetic Tricks): Techniques like XOR REG, REG or SUB REG, REG are used to zero out registers without introducing null bytes into the shell code.
1:08:31 Obtaining Current Address (CALL/POP): A trick to get the current instruction pointer without null bytes involves a CALL to the next instruction followed by POP into a register.
1:11:02 Advanced Arithmetic for Offsets: More complex arithmetic (adding/subtracting "magic numbers," bit shifting) is used to calculate addresses and constants without generating problematic zero bytes.
1:14:53INT 3 for Debugging: The INT 3 instruction (debugger interrupt) is a single-byte breakpoint, invaluable for debugging shell code on NT by forcing the debugger to activate at specific points.
1:16:05 Non-Zero Call Offsets: A complex JMP sequence is shown to create a non-zero, negative offset for CALL instructions, circumventing issues with zero-byte offsets.
1:26:37 Undocumented NT Code Alterations: A critical discovery for the IIS HTR exploit was that the NT server mysteriously and deterministically altered bytes within the uploaded shell code in memory, possibly due to Unicode translation.
1:28:06 Iterative Re-engineering: Overcoming these undocumented alterations required extensive trial-and-error (hundreds of attempts) and re-engineering the shell code to avoid specific byte sequences that triggered unwanted changes.
1:30:02 Runtime String Patching: To deal with IIS's character restrictions, shell code was designed to initially contain "safe" placeholder characters (e.g., !, {) and then patch them back to the desired characters (., /) at runtime.
1:34:02 Pathname Conversion Issues: NT's automatic conversion of forward slashes to backslashes, and fusion of multiple backslashes, further complicated string manipulation within the shell code.
1:35:09 Code Availability: The detailed shell code will be made available on an FTP server, requiring NASM for assembly.