part 4: secure coding
DESCRIPTION
Part 4: Secure Coding. Many attacks are due to invalidated input to programs and faulty programming Secure Coding: Immensely important Not taught, not well understood Major problem with software development Languages used commonly are unsafe C, C++ are unsafe Java is much safer - PowerPoint PPT PresentationTRANSCRIPT
1
Part 4: Secure Coding
Many attacks are due to invalidated input to programs and faulty programming
Secure Coding: Immensely important Not taught, not well understood Major problem with software development
Languages used commonly are unsafe C, C++ are unsafe Java is much safer
We will use C to show common programming errors
Code examples from “Secure Coding in C and C++” by Robert Seacord.
2
Two fundamental attacks
1. Buffer Overflow
- writing past the end of an array or structure
2. Arbitrary Memory Write
- writing to some arbitrary memory location
The data written and the memory location chosen is under the control of the input data
Input data is crafted by the attacker
3
gets is BAD
Never use gets, there is no safe way to use gets. Even if you use getc, there could be problems (be careful)
//gets problemvoid main (void) { char password[80]; puts ( “ Enter 8 char password: “); gets(password);}
4
Strings are Trouble
Strcpy, strcat are unsafe, in most cases.//string problemsvoid main (int argc, char *argv[] ) { char name[2048]; // which line may overwrite? strcpy (name, argv[1]); strcat (name, “ = “); strcat (name, argv[2]);}
//goodint main (int argc, char *argv[] ) { char *buff = (char *)malloc(strlen(argv[1]+1); if (buf != NULL) { strcpy(buff, argv[1]); printf(“argv[1] =%s\n”, buff); } else { /* could not alloc, recover… */ } return 0;}
5
Off by one errors
Spot the errors
//errorint main (int argc, char *argv[] ) { char source[10]; strcpy(source, “0123456789”) char *dest = (char *)malloc(strlen(source)); for (int I = 1; i<=11; i++) { dest[i] = source[i]; } dest[i] = ‘\0’; printf(“dest = %s\n”, dest);}
6
More Grief
Counting errors
What happens after execution (difficult)?
//bad, counting errorsint main (int argc, char *argv[] ) { char a[16], b[16], c[32]; strcpy(a, ”0123456789abcdef”); strcpy(b, ”0123456789abcdef”); strcpy(c, a); strcpy(c, b); printf(”c = %s \n”, c);}
7
Double Dumb
Not just gets, more trouble
bool IsPasswdOK(void) { char password[12]; gets(password); if (!strcmp(password, “goodpass”)) return(true) else return(false);}
8
Safe String Operations
fgets, gets_s : Allows input size specifications
strcpy_s, strcat_s : same
strncpy (dest, source, size-1) : watch out for counting errors
strncat : same
Microsoft STRSAFE library
n = read(fd, buff, n) // safe but complex programming needed
9
Overflow “protection”
Compiler checked bounds Often inadequate, slow
Stackgap : introduce random gaps in stack Canaries Libsafe : replaces normal string operations, ensures
overflows do not cross stack frame boundaries
Nothing can match proper input validation
10
Attack prone
Looks safe, but is not, wrong use of safe functions Attacker can cause arc injection
// call wrong functionvoid good_f(char* str) { … }void main ( );{ static char buf [10] static void (*fptr)(char *str); fptr = &good_fl strnpy(buf, argv[1], strlen(argv[1]) fptr(argv[2]);
}Attacker can overwrite fptr and provide args to fptr
11
Memory Layout
generic Unix Win32
code code
code
data
heap
stack
Global data
BSS segment
heap
stack
Reserved
stack
Reserved Reserved Reserved
heap
Reserved
stack
heap
Reserved
heap
stack
constant varsstatic vars
un-init-vars
12
Where do these go?
// memory layoutstatic int initial = 1; // global datastatic int non-init; // BSS segment
void main(int argc, char* argv[]) // stack{ int i = 1, j; //stack static int x = 2 // global data static int y; // BSS segment int *buf = malloc (30); // buff on stack, contents on heap
}
13
Arbitrary Memory Write
Via Overflow
// bad memory writevoid foo (int* arg, int len);{ char buff [50] ; int val = 25; int *ptr; = 30; memcpy(buff, arg, len); *ptr = val; …}
14
Function Pointer
Use of function pointer may be harmful
// attackable function callsgood-f(char *str) { printf(str) }; // watch outvoid main(int argc, char* argv[]){ void (*fptr) (const char *str); fptr = &good_f; *fptr(“hi ”); //attackable Good_f(“there\n”); //non-attackable}
15
Dangling Pointer
Free list structure is complex, and damage can be done by: Using free memory Double free
Prestored pointers are a source of errors
p = malloc(50);….Some code……free(p)……Some code……*p is used here
16
Free Memory Error
Check the return value of malloc, else you may get…
//referencing free memoryint *mat(int *a, *b, n){ int *c = malloc(n * sizeof(int)); // no check? int i; for (i=0; i<n; i++) c += a[i] + b[i]; return c;}
//two errors, subtlefor (p=head; p != NULL; p = p->next) { // error 1 q = p-> next; free(p) ; // error 2}
17
Double Free
More common that you think
// freeing same memory twicex = malloc (size);//work on itfree(x);y = malloc(size);//work on it;free(x); // often a cut and paste error
18
The Unlink Attack
Overflow in allocated memory may make unlinking dangerous
Buffer overflow in HEAP – unlink attackint main(int arrgc, char *argv[]);{ char first, second, third; first = malloc (222); second = malloc (12); third = malloc (12); strcpy(first, argv[1]); // may mess up mem alloc free(first); free(second); free(third);}
19
Mitigations
Make pointer null after freefree(p); p = NULL;
Use consistent strategy Do it in constructors and destructors Do it at beginning and end of each module Pair malloc and free Keep you own free list (fixed size items)
Canaries Guard pages Randomization of malloc strategy
20
Integers are rather complex
C/C++ has many integer types Unsigned, short, long, long long
Integers have ranks Integer promotions are not well understood, conversions are also
used and can cause errors (truncation, overflow) Mixing unsigned ans signed integers are a problem, assigning
negative numbers to unsigned integers is common (attack)
21
Size Matters
Obvious error
INTEGER Securityint main (int argc, char **argv); { unsigned short int total; total = strlen(argv[1])+strlen(argv[2]); char *buf = malloc (total); strcpy (buf, argv[1]); strcpy (buf, argv2));}
22
Automatic promotions and casting
May not work, and then may
//integer promotionschar c1, c2, c3 result;c1 = 100;c2 = 90;c3 = -120;result = c1+c2+c3;// will work correctly (BAD)
23
From Real Life
Jpeg file comment size includes some other 2 bytes
//JPEG vulnerabilityvoid getcomment(unsigned int len, char *src) { unsigned int size; size = len - 2; char comment = (char *) malloc(size + 1); memcpy (comment, src, size);}read the value of len from JPG file and then get comment.
24
Easy Heap Overflow
What does memcpy expect as type of len?
// buffer overflow with –ve numbermain (argc, argv){ int len, char buf [size]; //size is a constant len = atoi(argv[1]); if (len <= size) ( memcpy(buf, argv[2], len); else printf(“too much data”);}
25
skip
// truncation errormain(argc, argv){ unsigned short int total; total = strlen(argv[1])+strlen(argv[2]); char *buf = malloc (total) strcpy(buf, argv[1]); strcat(buf, argv[2]);}
26
Skip
// truncation problem with conversionbool func(char * name, long cbBuf); unsigned short bufSize = cbBuf; char *buf = (char *) malloc (bufSize); if buf { memcpy ( buf, name, cbBuf); }
27
Attackers think -ve
Most programs do not check for –ve values
//negative indexint *table = null;int insert(int pos, int value) { if (!table) table = maloc (400) if (pos > 99) { return -1} table[pos] = value;}
28
printf can be harmful
Check for user provided input What does argv[0] actually contain?
//usage exploitvoid usage(char *p) { char str[1024]; snprintf(str, 1024, “Usage: %s <targets>\n”, p); printf(usageStr);}Main(){if argc not > 2 usage(argv[0]);
//easier to attack…printf(argv[1]);
29
Printf attacks
//simplestfunc(char *user){ printf(user);}
attack1: %s%s%s%s%s%s………… may crashattack2: %08x, %08x, %08x, …………attack3: use %x a few times and then use %sattack4: \xdc\xf5\x42\x01%08x%08x%08x%08x%s (very tricky)
30
skip
//buffer overflowchar buffer[512]; sprintf(buffer, “Wrong command: %s\n”, user);//stretchable bufferchar outbuf[512], buffer[512];sprintf(buffer, “Wrong Command: %.400s”, user);sprintf(outbuf, buffer);
-> input %497\x3c\xd3\xff\xbf\....[shellcode]
31
Memory Writes with printf
%n = write # of chars outputted%u wite integer using u spaces
//overwriting memoryint i;printf(“Hello %n\n”, (int*) &i);
also:printf(“\xdc\xf5\x42\x0108x%08x%08x%08x%n”)
//[write specific address]int i;printf("%10u%n", 1, &i); //i=10printf("%100u%n", 1, &i); //i=100
32
An incomplete example
unsigned char foo[8]printf(%x16u%n, 1, &foo[0]);printf(%x32u%n, 1, &foo[1]);printf(%x64u%n, 1, &foo[2]);printf(%x128u%n, 1, &foo[3]);printf("%16u%16u%32u%64u%n", 1, &foo[1], 1, &foo[2], 1, &foo[3], 1, &foo[4]);
33
Args to Prinf
void foo(int p,int q, char *r, int s, int t){ int a[4] = {1,2,3,4}; print the stack here};main(){ foo(55, 56,"abcdefgh", 57, 58); };
bfabf458: 1 bfabf45c: 2 bfabf460: 3 bfabf464: 4 bfabf468: bfabf488 // base pointerbfabf46c: 8048410 // return addressbfabf470: 37 // 55 - arg 1bfabf474: 38 // 56 - arg 2bfabf478: 8048520 // address for "abc...bfabf47c: 39 // 57 - arg 3bfabf480: 3a // 58 - arg 4