Software VulnerabilityI N TR O D U C TI O N I N S O F TWAR E E X P LO ITIN G
What does Remote code executing mean?
Legal Aspects (for Germany)
• § 202b Abfangen von Daten
• Wer unbefugt sich oder einem anderen unter Anwendung von technischen Mitteln nicht für ihn bestimmte Daten (§ 202a Abs. 2) aus einer nichtöffentlichen Datenübermittlung oder aus der elektromagnetischen Abstrahlung einer Datenverarbeitungsanlage verschafft, wird mit Freiheitsstrafe bis zu zwei Jahren oder mit Geldstrafe bestraft, wenn die Tat nicht in anderen Vorschriften mit schwererer Strafe bedroht ist.
• § 202c Vorbereiten des Ausspähens und Abfangens von Daten
• Wer eine Straftat nach § 202a oder § 202b vorbereitet, indem er
• Passwörter oder sonstige Sicherungscodes, die den Zugang zu Daten (§ 202a Abs. 2) ermöglichen, oder
• Computerprogramme, deren Zweck die Begehung einer solchen Tat ist,
• herstellt, sich oder einem anderen verschafft, verkauft, einem anderen überlässt, verbreitet oder sonst zugänglich macht, wird mit Freiheitsstrafe bis zu einem Jahr oder mit Geldstrafe bestraft.
Legal Aspects (for Switzerland)
• Art. 144 Datenbeschädigung
• Wer unbefugt elektronisch oder in vergleichbarer Weise gespeicherte oder übermittelte Daten verändert, löscht oder unbrauchbar macht, wird, auf Antrag, mit Freiheitsstrafe bis zu drei Jahren oder Geldstrafe bestraft
• Hat der Täter einen grossen Schaden verursacht, so kann auf Freiheitsstrafe von einem Jahr bis zu fünf Jahren erkannt werden. Die Tat wird von Amtes wegen verfolgt.
• Wer Programme, von denen er weiss oder annehmen muss, dass sie zu den in Ziffer 1 genannten Zwecken verwendet werden sollen, herstellt, einführt, in Verkehr bringt, anpreist, anbietet oder sonst wie zugänglich macht oder zu ihrer Herstellung Anleitung gibt, wird mit Freiheitsstrafe bis zu drei Jahren oder Geldstrafe bestraft.
• Handelt der Täter gewerbsmässig, so kann auf Freiheitsstrafe von einem Jahr bis zu fünf Jahren erkannt werden.
What are NOT the goals of this workshop
• Teaching how to write malware
• Hacking course
• Reverse engineering
• Cracking Software
• Motivate you to break the law
• But: to secure software it is important to understand how it will be attacked
What are the goals of this workshop
• Sensitize for commonest mistakes
• It’s easy to redirect the program flow if a programmer do not care
• If a programmer care it may be harder to exploit
• Software won’t be perfect secured
• Keep at least script kiddies out
• Explain principles of
• Finding software exploits
• Using software exploits
• Present existing counter mechanisms
• Small project
Essentials
• Goal: redirect original program flow to shell code
• Shell code: compiled code sequence
• = series of opcodes (e.g. 0xEB 0x06 0x90 0x90)
• In this case: malicious code to be executed
• How comes the shell code into the program?
• How to jump to the shell code?
Windows Process and Memory management
0x00000000
0x7FFFFFFF
0x00400000
stack
heap
Push: decrement stack pointer
Grows to higher addresses
Program image:PE header.text (code).data (data), etc.
Additional Heap space
Space for DLLs DLLs have header, .text, .data, etc
PEB
Shared user page
No Access
0x7FFDF000PED: Process Execution Block:
location of main executabledll addresses, heap infos
Basic: Function Calls
• Each function has its own stack frame (space for local variables)
• Stack pointer: points on the top of the stack frame.
• Frame/Base pointer: points on the button of the stack frame.
• Instruction Pointer: points on the next instruction to be executed.
• Before entering a function:
• Push function parameter on the stack
• Push current Instruction pointer to the stack
• Used to return the program flow
• Push Base Pointer to the stack
• After entering a function:
• MOV EBP, ESP (current stack pointer becomes new base pointer)
Basic: Function Calls
Main stackframe
void do_sth(char *buf){char var[128];…
}int main(int argc, char** argv){
do_sth(argv[1])}
1. after program initialization
Stack
ESP
EBP
Basic: Function Calls
Main stackframe
void do_sth(char *buf){char var[128];…
}int main(int argc, char** argv){
do_sth(argv[1])}
2. push function parameter
Stack
ptr to argv[1]
ESP
EBP
Basic: Function Calls
Main stackframe
void do_sth(char *buf){char var[128];…
}int main(int argc, char** argv){
do_sth(argv[1])}
3. Push instruction pointer
Stack
ptr to argv[1]
EIPESP
EBP
Basic: Function Calls
void do_sth(char *buf){char var[128];…
}int main(int argc, char** argv){
do_sth(argv[1])}
4. push base pointer
Main stackframe
Stack
ptr to argv[1]
EIP
EBPESP
EBP
Basic: Function Calls
void do_sth(char *buf){char var[128];…
}int main(int argc, char** argv){
do_sth(argv[1])}
5. new stack frame: MOV EBP, ESP
Main stackframe
Stack
ptr to argv[1]
EIP
EBPESPEBP
Basic: Stack space allocation
• Local variables of a function are stored on the current stack frame
• decrement stack pointer to store a new variable on top of the stack
• How to allocate arrays?
• SUB ESP, <arraysize>
• decrement stack pointer with array size
• How to store data in a array?
• Array begin + position
• Find “array begin” with fixed offset or LEA (load effective address) instruction
• Remember: a[4] == *(a+4)
Basic: Allocate Stack Array
void do_sth(char *buf){char var[128];…
}int main(int argc, char** argv){
do_sth(argv[1])}
6. Allocate array:SUB ESP, 0x80
Main stackframe
Stack
ptr to argv[1]
EIP
EBPEBP
ESP
Array
Basic: Write to Stack Array
void do_sth(char *buf){char var[128];…
}int main(int argc, char** argv){
do_sth(argv[1])}
7. Allocate array:MOV ESP, ECXINC ECX
Main stackframe
Stack
ptr to argv[1]
EIP
EBPEBP
ESP
Array
Basic: Return from a function: LEAVE
void do_sth(char *buf){char var[128];…
}int main(int argc, char** argv){
do_sth(argv[1])}
8. Return: LEAVE
Main stackframe
Stack
ptr to argv[1]
EIP
EBPEBP ESP
Array
Leave Step 1: MOV ESP, EBP
Basic: Return from a function: LEAVE
void do_sth(char *buf){char var[128];…
}int main(int argc, char** argv){
do_sth(argv[1])}
9. Return: LEAVE
Main stackframe
Stack
ptr to argv[1]
EIP
EBP
EBP
Array
Leave Step 2: POP EBP
ESP
Basic: Return from a function: RET
void do_sth(char *buf){char var[128];…
}int main(int argc, char** argv){
do_sth(argv[1])}
10. Return: RETN
Main stackframe
Stack
ptr to argv[1]
EIP
EBP
EBP
Array
Restore the instruction pointer
ESP
Stack smashing
• What can possibly go wrong?
void do_sth(char *buf){char var[128];strcpy(var, buffer);
}int main(int argc, char** argv){
do_sth(argv[1])}
Stack smashing
• What can possible go wrong?
• strcpy terminates when a ‘\0’ character is reached
• What happens if argv[1]is larger than 128 characters?
void do_sth(char *buf){char var[128];strcpy(var, buffer);
}int main(int argc, char** argv){
do_sth(argv[1])}
Stack smashing
• What can possible go wrong?
• strcpy terminates when a ‘\0’ character is reached!
• What happens if argv[1]is larger than 128 characters?
• EBP and EIP are overwritten, and possible other stack frames program will crash
void do_sth(char *buf){char var[128];strcpy(var, buffer);
}int main(int argc, char** argv){
do_sth(argv[1])}
Main stackframe
Stack
ptr to argv[1]
EIP
EBPEBP
ESP
Array
From stack smashing to exploiting
• Used to redirect the program flow
• Overwrite the return address of a function call with address of injected shellcode
• Program flow is changed
• Execute Shell code
• Software Exploit:
• An advanced version of stack smashing
• Use an buffer overflow attack
• Overwrite the stored EIP with a meaningful address
Shell code
• How to inject shell code in the programs memory?
• Use program IO similar as for overwriting EIP
• write OP_CODES intoinput array behind EIP
Main stackframe
Stack
ptr to argv[1]
EIP
EBPEBP
ESP
Array
Shellcode
Shell code
• How to start the shell code?
• Jump to address where shell code is stored
• BUT: when executing on different machines the address may be different!
• Additional:0x00 in the address breaks the exploit
• you cannot overwrite EIP with hardcoded address
Main stackframe
Stack
ptr to argv[1]
EIP
EBPEBP
ESP
Array
Shellcode
Shell code
• How to start the shell code?
• Idea: After executing “ret” ESP points below the stored EIP
• search an address which contains jmp esp
• In a application dll (address is constant there)
• In a system dll (may differ in different OS versions)
• Overwrite EIP with this address
• When ret is executed the program will jmp to address jmp esp is executed shellcode is executed
Main stackframe
Stack
ptr to argv[1]
EIP
EBP
EBP
ESP
Array
Shellcode
Reliable jmp to Shell code
• Search for an address in the .text where JMP ESP is executed
• Overwrite EIP with this address.
• This is reliable, since the address of a program code is constant
• Search in shared libraries / DLLs for OP_CODES to jmp to the shell code
• Not necessary JMP ESP
• CALL ESP effects the same
• use another register if it points on your shellcode
• May use multiple instructions like: POP; JMP ESP etc.
• depends on position of your shell code
Shell code development
Write shellcode:
• There is a metasploit compiler to create shellcode
• gcc –c filename and objdump –d
• Write own opcodes:
• Look in disassembly
• Search in opcode table
Find opcodes to jump to shell code
• Search in disassembly,
• or use debugger for op-code search
• First search in program, then in system libraries
Windbg/GNU GDB to find vulnerability
Windgb GNU GDB
breakpoint bp label address break file:line
Memory dump d address (e.g. “d esp”) • dump (binary/memory) start_adr end_adr
• x function• x $espx/x, x/d, x/u to dump hex, signed, unsigneddump 4 words as hex:x/4xw $sp
disassemble u/uf address/function_name disassemble address/function_name
search in binary s start_addr end_addr pattern find start_addr end_addr pattern
show libraryaddresses
shown by default on the top of the output
info sharedlibrary
Windbg can be installed as crash debugger using: „windbg –I“
Example
void readfile(char *filename){char file[10]; memset(file, 0, sizeof(file));FILE *f = fopen(filename,"r");if (!f) {
printf("FILE NOT FOUND\n");return;
}fseek(f, 0L, SEEK_END);int size = ftell(f);rewind(f);printf("Size: %d\n", size);fread(file, size, 1, f);printf("%s", file);
}
Example
int main(int argc, char** argv){char *filename = "C:/foo.txt";printf("Open file: %s\n", filename);readfile(filename);
}
Example
• Start application with large file will crash it! (char file[10]) overflow)
• e.g. use a file with many ‘A‘
• Debugger shows an Access violation
Example
• Dump stack
• Wingdb: “d esp“
• Stack contains many ‘A‘ Base and stored Instruction Pointer are overwrittenwhen returning Instruction Pointer is set to AAAA or 41414141 behind the stack pointer there are many ‘A’ place shellcode here
Example
• Dump the base pointer:
• Wingdb: “d ebp“
• EBP contains now the address 41414141
• ‘A‘ is 0x41 in ASCI
• Same for the instruction pointer
Example
• How to find the address of the instruction pointer?
• Use meaningful content for the exploit and dump eip:
• ABCDEFGHIJKLMNOPQUVWXYZabcdefghijklmnopquvwxyz
• The instruction pointer now contains: 63646566
• (intel is little endian)
• EIP is where cdef is (look in ASCII table)
Example
• How to place shell code?
• Place shellcode behind the instruction pointer on the stack
• dump ESP
• ESP is where the ’f’ is
• Simple shellcode: 9090eef4
• twice NOP and jump back to esp
• eef4 is the opcode for “jmp esp”
• 0x90 is opcode for NOP
Example
• What address to use to overwrite the EIP?
• ffe4 is the opcode for “jmp esp”
• Search this opcode in ddl and the binary
• Kernel32.dll is loaded in address space 7c800000 to 7c906000
• It contains ffe4 at 0x7c803234
• replace cdef with 3432807c to execute jmp esp
• Program hang in a loop
Entire Exploit generation (Python)
f = open('C:/foo.txt', 'w')
offset1 = „ABCEDEFHIJKLMNOPQRSTUVWXYZab"
eip = chr (0x34) + chr (0x32) + chr (0x80) + chr(0x7c) #jmp esp is on this address in dll
opcode = chr(0x90) + chr(0x90) +chr(0xff) + chr(0xe4) # NOP, NOP, jmp esp
for i in offset1:f.write(i)
for i in eip:f.write(i)
for i in opcode:f.write(i)
f.close()
Jumping
• For some reason you cannot place your shellcode in ESP
• Search the shellcode in other registers:
• jmp EAX or jmp EBX
• Search the shellcode on the stack
• Search the address of the shellcode on the stack
• What if only a few bytes are usable for the shellcode
• What if
Gap between ESP and shellcode
• Sometimes it is not possible to write the shellcode directly to ESP
• May overwritten by other data or
• OS counter mechanism.
• Assume you have 8 byte gap overwrite EIP with an address that
contains “pop pop ret” first bytes of the shellcode are address
of “jmp esp”
• Pop takes 4 byte from stack (32bit)
• ret loads the first stack value in EIP
• goto “jmp esp” address and execute shellcode
• popad removes 32bytes from stack if pop is not enough
Main stackframe
Stack
ptr to argv[1]
EIP
EBPEBP
ESP
Array
Shellcode
gap
Search the address of the shellcode on the stack
• Sometimes the shellcode address is not inany register
• but it can be found on the stack
• POP until you reached shellcode address
• execute ret to load the address to EIP
• if the gap is 8 bytes again overwrite EIPwith an address that points on a“pop pop ret”
Main stackframe
Stack
ptr to argv[1]
EIP
EBPEBP
ESP
Array
Shellcodeaddress
gap
Shellcode
What if only a few bytes are usable for theshellcode
• Sometimes only a few bytes are usablefor shellcode behind EIP
• but you can place more shellcode above
• use the few bytes to jmp the the shellcodeabove:
• Small shellcode can be:sub esp, 80 jmp esp
• Start shellcode with NOPs
• no exact jmp required Main stackframe
Stack
ptr to argv[1]
EIP
EBPEBP
ESP
Array Shellcode
Shellcode
Counter Mechanisms
• GS
• Reorder variables on the stack. Put arrays to higher addresses
• Other variables cannot be overwritten, but still EIP
• DEP
• Stack is not executable.
• Enforced by hardware.
• OS can disable it (required for JIT programs)
• You can ret to the lib function that disable DEP
• Stack Cookie
SEH (Structured Exception Handler) exploits
• a try-catch block runs in its own stack frame
• Information about the EH are pushed on the stack
• 8bytes:
• pointer to the next exception handler(for the case the current exception handler cannot handle the exception)
• pointer to the actual exception handler
• Chain of exception handlers
• FFFFFFFF marks the end of the chainOS exception handler kicks in
Main stackframe
Stack
EH
ptr to argv[1]
EIP
Array
EBP
SEH (Structured Exception Handler) exploits
• Cause an exception to kick EH in
• Overwrite the pointer to the next EH record with some jmpcode (to jmp to shellcode)e.g. eb069090 = jmp +06 NOP NOP
• Overwrite the EH with a pointer to an instructionthat will bring you back to next EH and executethe jmpcode(e.g. pop pop ret)
• The shellcode can be directly after the overwrittenEH.
next EH
next EH
FFFFFFFF
EH1
EH2
EH3
Stack Cookies
• Compiler flag (only for string buffer)
• Random value is computed when applicationstarts (stack cookie)
• Stored in .data section on the program
• After saving EBP and EIP push stack cookieon the stack
• To overwrite EIP you have to overwrite the Stack Cookie
• Before ret the stack cookie will be checked.
• So do not return, overwrite SEH to exploit
• Sometimes you can compute the value or it is constant
• Overwrite stack cookie in .dataMain
stackframe
Stack
EH
EIP
Stack Cookie
Array
ptr to argv[1]
ESP
Final words
• Check array bounds
• ensure nobody can overwrite
• Be carefully with pointer arithmetic
• Use secure programming languages (C#, Java, Haskell, Ada)
• but down forget:• it runs on a unsecure basis
• JAVA programs cannot be exploited with buffer overruns - theoretically
• JVM is written without focus on security there are many issues!
• SoftBound + CETS: Complete and Compatible Full Memory Safety for C
• proven approach to eliminate all possible bufferoverflows!
• Most of this problem are not caused by OS or software, but by unsafe CPU-architectures.
• Possible future CPU-architectures are less vulnerable (MILL CPU)
• on this architecture concept call stack cannot be overwritten to redirect program flow
• many popular exploiting technics become harder or impossible
• not classic buffer overruns, but there are other technics e.g. dangling pointers
Preventing Buffer Overflows
• ALWAY check array boundaries
• Do NOT forget to check for index overflows:
0 1 2 3 4 5 6 7 8 9 10 11 12
base bound
int array[4]:
ptr: array
• Iterate through the array: ++array;
• Boundary check:array > base && array+elementsize < bound
Preventing Buffer Overflows
• ALWAY check array boundaries
• Do NOT forget to check for index overflows:
0 1 2 3 4 5 6 7 8 9 10 11 12
boundbase
int array[4]:
ptr: array
• Boundary check:array > base && array+elementsize < bound
• Point with long long *ptr2 on element 12:• ptr2 > base: 12 > 9 • ptr2 + 1 < bound: 1 < 12 Access to element 0!
ptr2
Preventing Buffer Overflows
• ALWAY check array boundaries
• Do NOT forget to check for index overflows:
0 1 2 3 4 5 6 7 8 9 10 11 12
boundbase
int array[4]:
ptr: array ptr2
• Boundary check correct:array > base && array+elementsize < bound&& base < array+elementsize• ptr2 > base: 12 > 9 • ptr2 + 1 < bound: 0 < 12
• ptr2 + 1 > base: 0 > 9 X
Any Questions?