© anders ingeborn +46-8-662 10 70 ids evasion design tricks for buffer overflow exploits
TRANSCRIPT
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
IDS Evasion Design Tricks for Buffer Overflow Exploits
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Why buffer overflows?
• Very effective attacks– Run attacker’s code of choice– Allowed protocols goes through firewalls
• Very common problem– Most common for the past 10 years!
• Oregon Institute of Technology (1999)
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Why these design tricks?
• Get around mismanaged bounds check– Adds possible exploitations
• Evade network based IDS
• Evade host based IDS
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Agenda
• Theory– Double injection– Existing network connection– Function calls to .dll’s
• Example
• Countermeasures
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Brief reminder
• E.g. strcpy() w/o bounds check
– copies until ’0x00’-byte
• Write outside dedicated stack memory
• Overwrite stored instruction pointer
• Jump into your code
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Simple illustration
EIP
00 12 FF 00
00 12 FF 04
00 12 FF 08
00 12 FF 0C
00 12 FF 10
00 12 FF 14
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Mismanaged bounds check
• Let’s say a vulnerable server performs a bounds check on receive – but not on strcpy()
• Let’s say strncpy() is used– but there has been a miscalculation
• It is still possible to inject
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Size restrictions?
• Separate buffers for injector and payload– Restrictions on injector, but not on payload?
• Same buffer for injector and payload– Restrictions also on payload– Do everything using as few bytes as possible
• Naive, but OK
– Change design concept• Double injection
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Simple small ”shell”
• Functional requirements– Listen for requests over network– Execute those as system commands
• Every byte counts– Keep number of libraries low– Keep number of functions low
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
250 bytes example
• Two libraries: Winsock & Kernel32
• Datagram socket instead of stream– don’t need listen() nor accept()
• Loop– Call to recvfrom()– Execute with call to WinExec()
• http://www.securityfocus/bid/2200/
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Another design concept
• Double injection– Use first payload to upload and execute
second payload
• Benefits– Very small first payload (43 bytes)– No restrictions on the size of the second
payload
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
”Double injection”
Stack
Server
pnex()
Client
First callStack
#1
Stack#2
First payload
Strcpy()
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
”Double injection”
Stack
Client Stack#1
First payload
Second payload
Second call
Communicationchannel
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
What to send 2nd time?
• Your code of choice!– May still use the socket– May still use the jump table– No need to XOR-protect NULLs
• Raw data over socket
• Proof-of-concept implementation– Confirms by sending a message
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
OK, this seems nice
• How to minimize code?
• Use pre-loaded functions– Server has already loaded some .dll’s
• Use existing network connection– Server has already an existing TCP
session with you– Find the socket descriptor, re-use it
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
How to find descriptor
• Find accept() call– Set breakpoint, debug– Where is returned value stored?
• Lots of disassemblers available– Freeware, e.g. ”dsassm”– Commercial, e.g. IDA Pro
• Example on slide 38
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Benefits
• By using pre-loaded functions– Fewer bytes
• By using same network connection– Some network based intrusion detection
systems might be evaded– No new TCP-handshakes– No haxor 31337 ports
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Benefits
• By writing a minimal injector/payload
• Stack frame below is not disrupted
• A clean return might be possible– The server process won’t crash– No log entry for a host based intrustion
detection system to detect
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
”Might” be possible?
• We got to find the correct return address– A ”static” disassemble of the .dll shows
compile time requested base address– Might not be used at run time
• We might need to restore some internal register values
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Correct return address?
• The original return address is overwritten– Our way to control, 1st injection
• Two ways to handle this– Calculate return address manually– Pop another stack frame
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Pop another frame
• Let’s say– Main calls a function in .dll– 1st function in .dll calls 2nd function– 2nd function is exploited
• Maybe we can return to main?– Return point in main at 0x40ABCD– This adress won’t change from a
disassembly of the ”static” exe
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Situation #1 illustrated
Main stack
Stack #1
Stack #2Injection
Use this return address
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Calculate return address
• Return to the ”correct” function
• A fix distance down the stack– Below stack frame #1– Is the ret addr to ”main” 0x40..– And a fix distance from there is the call
address to function #1– And a fix distance from the call (start)
address is ”our” ret addr
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
What?!
• Let’s have a look at function calls
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Function calls
pnex.dll
0x4030F2
0x40B1A8 0x1000112C
0x1000112CJMP [0x40B1A8]
0x40120F CALL 0x4030F2
”Main”
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Why do they look like this?
• OS only need to patch one place in the code, not every call
• OS does not need to know how to generate complete jump instructions, just patch in address of function
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Find call/start address
0x4030F2
0x40B1A8 0x1000112C
JMP [0x40B1A8]
0x40120F CALL 0x4030F2
”Main”
Main stack
0x401214
Stack #1
Injection0x401214
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Calculate return address
0x4030F2
0x40B1A8 0x1000112C
JMP [0x40B1A8]
0x40120F CALL 0x4030F2
”Main”
pnex.dll
0x401214
0x1000112C
0x1000113C0x10001137 CALL …
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Might be possible?
• We got to find the correct return address– A ”static” disassemble of the .dll shows
compile time requested base address– Might not be used at run time
• We might need to restore some internal register values
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Internal register values
• Internal register values of function #1 might be stored on the stack– When function #2 starts executing
• These has to be restored– Function #2 restores them before RET– But our first injector overwrites their
stored values during the string copy
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Function call
Stack #1
Stack #2
Arguments
RegistersRET address
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Function call
Stack #1
Stack #2
Arguments
RegistersRET address
String copy
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Clean return requirement
• We need to be able to restore neccessary internal registers– A normal execution/debug shows which
registers are neccessary to restore
• We have to restore them manually– Predictable/static values?– Possible to calculate from other
untouched information at fix positions?
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
OK, this sounds cool, but?
• Proof-of-concept implementation– Simple vulnerable server– Remote client with exploit
• Is included on CD
• Will be available on BlackHat website
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Implementation exposed
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Server
– Accept connections• Receive ”commands”• Upper limit at 100 bytes
– Call parse and execute function in dynamically linked library pnex.dll
• parsnexec()
– Parsnexec() calls internal function• internal()• contains a stack overflow vulnerability
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Initial injection
• Server uses strncpy()– But a miscalculation is present
• Injection– Point EIP to a RET in ”main”
• Null terminated injector, 0x004010D7
– Program will jump to address just below– Which points to argument (our buffer)
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
First payload
• Find socket descriptor
• Find address of recv() function
• Call recv()
• Store second payload in free memory
• Jump to second payload
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Find socket descriptor
00401171 lea eax, [ebp-4]00401174 push eax00401175 lea eax, [ebp-0DCh]0040117B push eax0040117C push dword ptr [ebp-29Ch]00401182 call _accept@1200401187 mov [ebp-298h], eax0040118D cmp dword ptr [ebp-298h], 000401194 jge short loc_4011A900401196 push offset aErrorOnAccept ; "Error on accept!\n"0040119B call _printf
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Using the socket
Stack frame #1
Stack memory • Stack frames’ placement might change• Socket’s position within frame doesn’t• Fix relative distance from top of frame
Stack frame #2
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Debug and look at memory
Orig. RET Argument
0x40 RET Argument Argument
Socket
Stack
Stack
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Offset
• Socket descriptor will always be 32 bytes from where ESP points to after the injection
• ESP points one byte down the stack frame of parsnexec()
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Code
0x89,0xE5, // 1-2 mov ebp, esp
0x66,0x81,0xEC,0xF0,0x03, // 3-7 sub sp
0x31,0xC0, // 8-9 xor
0x50, //10 push "flags"
0x6A,0x7F, //11-12 push "size"
0x8D,0x44,0x24,0x08, //13-16 lea [esp+8] "buff"
0x50, //17 push eax
0x8D,0x45,0x20, //18-20 lea [ebp+20] "sock"
0xFF,0x30, //21-22 push [eax]
0xB8,0xFF,0xEC,0x30,0x40, //23-27 mov eax, 0x4030ec
0xC1,0xE8,0x08, //28-30 shr eax,8
0xFF,0xD0, //31-32 call eax
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Find recv() function
0040B180 ; 0040B180 ; Imports from WS2_32.dll0040B180 ; 0040B180 extrn __imp__WSAStartup@8:dword ; DATA XREF: .text:00402FA40040B184 extrn __imp__socket@12:dword ; DATA XREF: .text:00402FAA0040B188 extrn __imp__htonl@4:dword ; DATA XREF: .text:004030CE0040B18C extrn __imp__htons@4:dword ; DATA XREF: .text:004030D40040B190 extrn __imp__bind@12:dword ; DATA XREF: .text:004030DA0040B194 extrn __imp__listen@8:dword ; DATA XREF: .text:004030E00040B198 extrn __imp__accept@12:dword ; DATA XREF: .text:004030E60040B19C extrn __imp__recv@16:dword ; DATA XREF: .text:004030EC0040B1A0 extrn __imp__send@16:dword ; DATA XREF: .text:0040318C
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Recevie call
Inject. ESPEBP
?? Overwritten by injector
flags
socketbufflength
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Second payload
• Send message back to client– Still using same TCP session
• Calculate return address
• Restore all registers and return clean!– EBP, ESP, EBX and EIP
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Send message
Find send() function through disassembly
0040B180 ; 0040B180 ; Imports from WS2_32.dll0040B180 ; 0040B180 extrn __imp__WSAStartup@8:dword ; DATA XREF: .text:00402FA40040B184 extrn __imp__socket@12:dword ; DATA XREF: .text:00402FAA0040B188 extrn __imp__htonl@4:dword ; DATA XREF: .text:004030CE0040B18C extrn __imp__htons@4:dword ; DATA XREF: .text:004030D40040B190 extrn __imp__bind@12:dword ; DATA XREF: .text:004030DA0040B194 extrn __imp__listen@8:dword ; DATA XREF: .text:004030E00040B198 extrn __imp__accept@12:dword ; DATA XREF: .text:004030E60040B19C extrn __imp__recv@16:dword ; DATA XREF: .text:004030EC0040B1A0 extrn __imp__send@16:dword ; DATA XREF: .text:0040318C
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Still using the same socket
0x6A,0x00, //push 0x0 "flags"
0x6A,0x1D, //push "length"
0x8D,0x47,0x43, //lea eax,dword ptr [edi+0x43]
0x50, //push "buf"
0x8D,0x45,0x20, //lea eax,dword ptr [ebp+0x20]
0xFF,0x30, //push [eax] "socket"
0xB8,0x8C,0x31,0x40,0x00, //mov eax, 0x40318c
0xFF,0xD0, //call eax
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Finding return address
• Demo implementation returns to function parsnexec() in pnex.dll
• Return address manually calculated
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Find call/start address
0x40B1A8 0x1000112C
0x40120F CALL 0x4030F2
”Main”
Main stack
0x401214
Stack #1
Injection0x401214
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Calculate return address
0x4030F2
0x40B1A8 0x1000112C
JMP [0x40B1A8]
0x40120F CALL 0x4030F2
”Main”
pnex.dll
0x401214
0x1000112C
0x1000113C0x10001137 CALL …
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Code
0x8D,0x45,0x0C, //lea eax, [ebp+0xC]0x8B,0x18, //mov ebx, [eax] "ret to main"0x81,0xC3,0x94,0x9F,0x00,0x00,
//add ebx, 0x9F94 "fix offset in main"0x8B,0x03, //mov eax, [ebx] "fix offset in .dll"0x83,0xC0,0x10, //add eax, 0x10 "ret to parsnexec"
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Restore internal registers
• Calculated from top of stack frame of parsnexec()– ESP shall point to top of frame– EBP shall point to base of frame
• Size of frame is fix, just add
– EBX shall point to an variable in frame• Position within frame is fix, just add
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Code
0x89,0xFC, //mov esp, edi "set esp"0x81,0xC4,0xEC,0x03,0x00,0x00, //add esp
0x89,0xE5, //mov ebp, esp ”set ebp"0x81,0xC5,0xBC,0x02,0x00,0x00, //add ebp,
0x89,0xE3, //mov ebx, esp "set reg. ebx"0x81,0xC3,0x54,0x02,0x00,0x00, //add ebx, 0x254 "ptr to res buf"
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Summary
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Summary
• Double injection– Let the first payload upload a second – Jump to second payload
• Execute your code of choice
• Use existing network connection– Socket descriptor– Use existing functions, i.e. jump table
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Benefits
• Evade network based IDS– No unrecognized 31337 ports– No new TCP handshakes
• Evade host based IDS– No new connections– No log entry
• Access violation• Unexpected termination...
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Countermeasures
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
IDS countermeasures
• NIDS application protocol interpretation– ASCII-encoding (currently hot topic)– Payloads may use fake headers– Interpretation adds complexity to IDS,
i.e. slows down analysis
• HIDS ”strange behavior” awareness– Statistically ”long” session etc.– Adds complexity
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Other countermeasures
• Prohibit execution on stack
• Put a reverse application proxy in front of server
© Anders Ingeborn +46-8-662 10 70 www.ixsecurity.com
Questions?
• Catch me during the conference!
• E-mail: [email protected]