summaryrefslogtreecommitdiff
path: root/informationals/teso-i0033.txt
blob: 3a9aaf36034486ebf6377c685516ca12d52e5cc5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
0033 2001/02/25  (not-so) advanced way to find KERNEL32.DLL base address 
==== TESO Informational =======================================================
This piece of information is to be kept confidential.
===============================================================================

Description ..........: shellcode enhancement technique to stabilize NT sploits
Date .................: 2000/12/28 06:00
Author ...............: halvar
Publicity level ......: its very obvious, but not used in any sploits I know
Affected .............: NT/Win32 specific
Type of entity .......: theoretical shit
Type of discovery ....: useful information
Severity/Importance ..: n/a
Found by .............: don't know; I spoke to lorian about this long ago

===============================================================================

Everyone who has played around with NT shellcode knows that we need to rely on
some hardcoded values. As we don't have the luxury of usable syscalls via INT's
as under *NIX, we need to get access to the Windows API by either using values
inside the executable (PE) header or by getting the KERNEL32.DLL base address
somehow. Both approaches rely on hardcoded values; This is bad since we either
need to know the exact NT-Version & Service Pack (for guessing KERNEL32 base)
or the exact version of the executable we're attacking. 

There are a few tricks to figure out the base address of KERNEL32 with maximum
stability, but I will just discuss my favourite one here:

Exception Handler Parsing

NT features something called "third-party-exception-handling" or "structured
exception handling" which allows applications to install exception handlers
that get control when (or if) an exception occurs. 
The excact structure of these things are documented all over the place in 
various articles on Win32 Assembly coding. (winasm32.cjb.net ?)
The structure of these exception handlers is basically a single-linked list
of pointers to functions handling exceptions. 

In memory they consist of two dwords:

[pointer to next handler structure][pointer to handler code]

Every function can establish a new exception handler and layer it on top of 
all the others, so if an exception occurs and is not handled by the most re-
cently installed handler then the next handler will be called until the 
application runs out of self-installed handlers and the default exception 
handler in KERNEL32.DLL is called ("Blablah.exe caused an exception at...").
The default exception handler structure is the end of the chain, and the 
pointer to the next handler structure is 0xFFFFFFFF in this case. 

The beginning of the chain (the most recently installed exception handler
structure) is referenced to by a pointer at fs:0.

So the trick in finding the base address of KERNEL32.DLL is to parse through
the exception handler structures until the end of the chain is reached; The
pointer to the handler code will then point into KERNEL32.DLL. As soon as
we have this address, we scan all page-beginnings backwards (all DLLs are
mapped page-aligned) for a "MZ" signature.

Some example assembly code for this (this is not size optimized, just for
educational purposes):

        xor     ecx, ecx        ; this avoids NULL bytes in the shell
        mov     eax, [fs:ecx]
.tunnel:
        mov     ecx, [eax]      ; Get pointer to next structure
        cmp     ecx, -1         ; Have we reached the end of the chain ?
        jz      .skip1          ; Yes, then jump to .skip1
        mov     eax, ecx        ; No ? Then walk the chain further
        jmp     .tunnel
.skip1:
        mov     eax, [eax+4]    ; Now we have an address inside KERNEL32
        xor     ax, ax          ; Kill low 16 bits and thus page-align
        xor     ecx, ecx        ; Move size of a page in ecx (0x1000)
        mov     ch, 0x10        ; without NULL bytes
.tunnel2:
        mov     dx, word [eax]  ; load first 2 bytes
        cmp     dx, "MZ"        ; compare to our signature
        jz      .skip2          
        sub     eax, ecx        ; scan one page more backwards in mem
        jmp     .tunnel2
.skip2:                

This is a lot more size-efficient than the other methods I've seen to 
find the KERNEL32.DLL base address reliably (relying on hardcoded 
0x00400000 base address for the executable, then parsing its PE header
to find a function imported from KERNEL32.DLL to get an address within
it). 

One note of caution with this, though: It seems that the installation
of Microsoft Kernel Debugging stuff and Visual Studio will screw the
entire NT exception handling in a way that the final exception handler
points into NTDLL.DLL instead of KERNEL32.DLL. So if you're attacking
a system of which you know it is a development workstation with Visual
Studio installed you might want to try parsing the PE header in the 
end :-)

Have fun,
Halvar

===============================================================================