This document discusses software vulnerabilities and exploits. It begins with an introduction to remote code execution and provides legal aspects of data interception for Germany and Switzerland. It then discusses the goals of preventing teaching how to write malware or hack systems illegally. The document covers basics of function calls, stack smashing vulnerabilities, and how to redirect program flow to injected shellcode through buffer overflows. It provides examples of finding vulnerabilities using debuggers and generating exploits in Python to execute shellcode by overwriting return addresses. Methods discussed include placing shellcode in registers or on the stack and dealing with gaps between the stack pointer and shellcode.
3. 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.
4. 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.
5. 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
6. 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
7. 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?
8. 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
0x7FFDF000
PED: Process Execution Block:
location of main executable
dll addresses, heap infos
9. 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)
10. 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
11. 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
12. 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]
EIP
ESP
EBP
13. 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
EBP
ESP
EBP
14. 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
EBP
ESPEBP
15. 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)
16. 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
EBP
EBP
ESP
Array
17. 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, ECX
INC ECX
Main
stackframe
Stack
ptr to argv[1]
EIP
EBP
EBP
ESP
Array
18. 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
EBP
EBP ESP
Array
Leave Step 1: MOV ESP, EBP
19. 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
20. 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
21. 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])
}
22. 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])
}
23. 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
EBP
EBP
ESP
Array
24. 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
25. Shell code
• How to inject shell code in the
programs memory?
• Use program IO similar as for
overwriting EIP
• write OP_CODES into
input array behind EIP
Main
stackframe
Stack
ptr to argv[1]
EIP
EBP
EBP
ESP
Array
Shellcode
26. 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
EBP
EBP
ESP
Array
Shellcode
27. 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 differentOS 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
28. 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
29. 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
30. 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 $esp
x/x, x/d, x/u to dump hex, signed,
unsigned
dump 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 library
addresses
shown by default on the top of
the output
info sharedlibrary
Windbg can be installed as crash debugger using: „windbg –I“
31. Example
void readfile(char *filename){
char file[10]; memset(file, 0, sizeof(file));
FILE *f = fopen(filename,"r");
if (!f) {
printf("FILE NOT FOUNDn");
return;
}
fseek(f, 0L, SEEK_END);
int size = ftell(f);
rewind(f);
printf("Size: %dn", size);
fread(file, size, 1, f);
printf("%s", file);
}
32. Example
int main(int argc, char** argv){
char *filename = "C:/foo.txt";
printf("Open file: %sn", filename);
readfile(filename);
}
33. 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
34. Example
• Dump stack
• Wingdb: “d esp“
• Stack contains many ‘A‘
Base and stored Instruction Pointer are overwritten
when returning Instruction Pointer is set to AAAA or 41414141
behind the stack pointer there are many ‘A’ place shellcode here
35. Example
• Dump the base pointer:
• Wingdb: “d ebp“
• EBP contains now the address 41414141
• ‘A‘ is 0x41 in ASCI
• Same for the instruction pointer
36. 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)
37. 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
38. 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
39. 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()
40. 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
41. 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
EBP
EBP
ESP
Array
Shellcode
gap
42. Search the address of the shellcode on the
stack
• Sometimes the shellcode address is not in
any 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 EIP
with an address that points on a
“pop pop ret”
Main
stackframe
Stack
ptr to argv[1]
EIP
EBP
EBP
ESP
Array
Shellcode
address
gap
Shellcode
43. What if only a few bytes are usable for the
shellcode
• Sometimes only a few bytes are usable
for shellcode behind EIP
• but you can place more shellcode above
• use the few bytes to jmp the the shellcode
above:
• 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
EBP
EBP
ESP
Array Shellcode
Shellcode
44. 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
45. 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 chain
OS exception handler kicks in
Main
stackframe
Stack
EH
ptr to argv[1]
EIP
Array
EBP
46. 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 instruction
that will bring you back to next EH and execute
the jmpcode
(e.g. pop pop ret)
• The shellcode can be directly after the overwritten
EH.
next EH
next EH
FFFFFFFF
EH1
EH2
EH3
47. Stack Cookies
• Compiler flag (only for string buffer)
• Random value is computed when application
starts (stack cookie)
• Stored in .data section on the program
• After saving EBP and EIP push stack cookie
on 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 .data
Main
stackframe
Stack
EH
EIP
Stack Cookie
Array
ptr to argv[1]
ESP
48. 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 andCompatible 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 futureCPU-architectures are less vulnerable (MILLCPU)
• 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
49. 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
50. 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
51. 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