I. Stack-Smashing Attacks A. background on machine architecture 1. memory layout ------------------------------------------ MEMORY LAYOUT (Intel x86) high |----------------| addresses | command line | |args & env vars | |----------------| | stack | local vars |(grows downwards) esp ---> |----------------| | v | | | | (unused) | | | | ^ | |----------------| | heap | dynamic mem. | (grows upwards)| |----------------| | .bss | uninit globals |----------------| | .data | init. globals |----------------| | code | low | (read only) | addresses |----------------| ------------------------------------------ 2. stack frames What is a stack frame? Is there one stack frame per function call? Why? ------------------------------------------ STACK FRAMES IN CONTEXT int main() { f(); } void f() { g(); } void g() { /* ... */ } +---------------------+ | frame for main() | | | +---------------------+ | frame for f() | | | | | +---------------------+ | frame for g() | stack | | pointer | | esp --> +---------------------+ ------------------------------------------ If g() calls a function h(), what does the stack look like then? If g() returns, what does the stack look like then? ------------------------------------------ INDIVIDUAL STACK FRAME (Intel x86) high +---------------------+ addresses | caller's stack | | frame | | | +=====================+ | | +---------------------+ | | | | +---------------------+ | | +---------------------+ frame ptr | | EBP---> +---------------------+ | | | | stack ptr | | ESP---> +=====================+ low addresses ------------------------------------------ Are the roles of the information stored in stack frames separated? B. the attack ------------------------------------------ ATTACK BACKGROUND Affects C and C++ code plus other languages that do not check array accesses. In C (and C++): - buffers have - buffers can be In many machine architectures: - return addresses are stored on the - data can be ------------------------------------------ ------------------------------------------ STACK SMASHING ATTACKS Attack Idea: 1. Find a stack-allocated buffer 2. Design malicious code to: a. contain b. overwrite a 3. Give the program What happens when the program runs? ------------------------------------------ What is a buffer? What key security service was violated? Why do we still use programming languages like C (and C++) that don't check array bounds? Why do we use machine architectures that mix control and data? 1. affected code ------------------------------------------ AFFECTED CODE The Morris finger worm: char buf[20]; gets(buf); The blaster worm: while (*pwszTemp != L'\\') *pwszServerName++ = *pwszTemp++; ------------------------------------------ ------------------------------------------ MORE PROBLEMS Tricky C library interfaces: char buf[20]; char prefix[] = "http://"; strcpy(buf, prefix); strncat(buf, users_path, sizeof(buf)); Use of dangerous functions: char buf[MAX_PATH]; sprintf(buf, "%s - %d\n", users_path, errno); General confusion: char buf[32]; strncpy(buf, user_data, strlen(user_data)); ------------------------------------------ 2. implications ------------------------------------------ IMPLICATIONS Possible effects: History: The Morris worm exploited a buffer overflow in 'finger' ------------------------------------------ Are these effects worse if the application runs as root? 3. summary ------------------------------------------ KEY FEATURES OF BUFFER OVERFLOW ATTACK 1. input from user read from user input, read from file or the net read from command line 2. accepting user input ------------------------------------------ 4. related sins ------------------------------------------ RELATED SINS Integer overflow: ptr = malloc(sizeof(type) * users_count); Unbounded write to array: a[users_index] = ... ------------------------------------------ What happens if the user-supplied users_count is very large? C. remediation 1. in C ------------------------------------------ REMEDIATION IN C Code reviews: Look for: - user input - unsafe handling of user input - mistakes in arithmetic in calculating sizes, remaining size. Replace unsafe string functions: gets strcpy strcat sprintf Use better libraries: SafeCRT ------------------------------------------ 2. in C++ ------------------------------------------ REMEDIATION IN C++ Use C++ Strings std::string or std::wstring Use STL containers like vector ------------------------------------------ 3. Use stack protection ------------------------------------------ STACK PROTECTION Canaries on the stack: special random values that can be tested to Address Space Layout Randomization (ASLR) load code into random places ------------------------------------------ Why do they have to be random? What does ALSR do? 4. Use analysis tools What does the "static" in "static analysis" mean? ------------------------------------------ STATIC ANAYSIS TOOLS Klocwork Code Coverity PREfast in Visual Studio: use /analyze flag in VS Fortify (for Java and .NET) ------------------------------------------ D. examples 1. c++ ------------------------------------------ FOR YOU: IS THIS CODE SUSCEPTIBLE? C++ code: char buf[BUFSIZE]; cin >> buf; ------------------------------------------ ------------------------------------------ FOR YOU: IS THIS CODE SUSCEPTIBLE? C++ code: std::string buf; cin >> buf; ------------------------------------------ 2. C ------------------------------------------ FOR YOU: IS THIS CODE SUSCEPTIBLE? char buf[64], in[MAX_SIZE]; printf("Enter buffer contents:\n"); size_t sz = read(0, in, MAX_SIZE-1); memcpy(buf, in, 64); ------------------------------------------ ------------------------------------------ FOR YOU: IS THIS CODE SUSCEPTIBLE? char buf[64], in[MAX_SIZE]; printf("Enter buffer contents:\n"); read(0, in, MAX_SIZE-1); printf("Bytes to copy:\n"); scanf("%d", &bytes); memcpy(buf, in, bytes); ------------------------------------------ ------------------------------------------ FOR YOU: IS THIS CODE SUSCEPTIBLE? char *lccopy(const char *str) { char buf[BUFSIZE]; char *p; strcpy(buf, str); for (p = buf; *p; p++) { if (isupper(*p)) { *p = tolower(*p); } } return strdup(buf); } ------------------------------------------ ------------------------------------------ FOR YOU: IS THIS CODE SUSCEPTIBLE? char *lccopy(const char *str) { char buf[BUFSIZE]; char *p; if (strlen(str) > BUFSIZE) { return NULL; } else { strncpy(buf, str, BUFSIZE); } for (p = buf; *p; p++) { if (isupper(*p)) { *p = tolower(*p); } } return strdup(buf); } ------------------------------------------ ------------------------------------------ FOR YOU: IS THIS CODE SUSCEPTIBLE? if (!(png_ptr->mode & PNG_HAVE_PLTE)) { /* Should be an error, but we can cope with it */ png_warning(png_ptr, "Missing PLTE before tRNS"); } else if (length > (png_uint_32)png_ptr->num_palette) { png_warning(png_ptr, "Incorrect tRNS chunk length"); png_crc_finish(png_ptr, length); return; } /* ... */ png_crc_read(png_ptr, readbuf, (png_size_t)length); ------------------------------------------ ------------------------------------------ FOR YOU: IS THIS CODE SUSCEPTIBLE? if (!(png_ptr->mode & PNG_HAVE_PLTE)) { /* Should be an error, but we can cope with it */ png_warning(png_ptr, "Missing PLTE before tRNS"); return; } if (length > (png_uint_32)png_ptr->num_palette) { png_warning(png_ptr, "Incorrect tRNS chunk length"); png_crc_finish(png_ptr, length); return; } /* ... */ png_crc_read(png_ptr, readbuf, (png_size_t)length); ------------------------------------------ 3. unicode troubles ------------------------------------------ FOR YOU: IS THIS CODE SUSCEPTIBLE? void getUserInfo(char *username, struct _USER_INFO_2 info) { WCHAR unicodeUser[UNLEN+1]; MultiByteToWideChar(CP_ACP, 0, username, -1, unicodeUser, sizeof(unicodeUser)); NetUserGetInfo(NULL, unicodeUser, 2, (LPBYTE *)&info); } ------------------------------------------ ------------------------------------------ FOR YOU: IS THIS CODE SUSCEPTIBLE? void getUserInfo(char *username, struct _USER_INFO_2 info) { WCHAR unicodeUser[sizeof(WCHAR)*UNLEN+1]; MultiByteToWideChar(CP_ACP, 0, username, -1, unicodeUser, sizeof(unicodeUser)); NetUserGetInfo(NULL, unicodeUser, 2, (LPBYTE *)&info); } ------------------------------------------ E. fuzz testing 1. description ------------------------------------------ FUZZ TESTING Goal: find software faults automatically by automated search Basic algorithm: - Use debugger to find likely vulnerabilities - Generate test data based on: - known problematic tests, - random guessing, or - heuristics ------------------------------------------ 2. tools ------------------------------------------ TOOLS FOR FUZZ TESTING For web applications: ZAP https://www.owasp.org/index.php/ OWASP_Zed_Attack_Proxy_Project JBroFuzz https://www.owasp.org/index.php/JBroFuzz For web services: WSFuzzer https://www.owasp.org/index.php/WSFuzzer BurpSuite: https://portswigger.net/burp/download.html For files (in apps): SDL MiniFuzz File Fuzzer https://www.microsoft.com/en-us/download/ details.aspx?id=21769 For regular expressions: SDL Regex Fuzzer http://www.microsoft.com/en-us/download/ details.aspx?id=20095 ------------------------------------------ II. Format String Attacks A. attack 1. background ------------------------------------------ FORMAT STRINGS AND PRINTF-STYLE FUNCTIONS fprintf, printf, sprintf, etc. take format strings as arguments such as %d, %s, etc. printf("i = %d\n", i); The interpreter uses the format string to: - specify - determine ------------------------------------------ Does C check the number of arguments given match the number determined by the format string? What happens if the number determined by the string is larger than the number of arguments? 2. overview ------------------------------------------ FORMAT STRING ATTACK 1. Find use of 2. Supply ------------------------------------------ 3. example confidentiality loss ------------------------------------------ EXAMPLES /* echo.c */ #include int main(int argc, char* argv[]) { /* char *passwd = "secret"; */ int i; for (i=1; i < argc; i++) { printf(argv[i]); if (i < argc-1) { printf(" "); } } printf("\n"); return 0; } ------------------------------------------ Is this susceptible to the attack? What other attacks is this like? ------------------------------------------ EXAMPLE int main(int argc, char **argv) { char buf[128]; ... snprintf(buf,128,argv[1]); } ------------------------------------------ Is this susceptible to the attack? Can an attacker view the contents of the stack? Can an attacker write over parts of the stack? 4. The %n format directive ------------------------------------------ THE MEANING OF %n FORMAT DIRECTIVES The %n format stores the number of bytes written so far into the corresponding (int) pointer argument Example: int n; printf("%s: %nFoo\n", "hello", &n); printf("%*sBar\n", n, ""); prints: hello: Foo Bar ------------------------------------------ ------------------------------------------ DANGER OF %n DIRECTIVES What happens if user-input specifies %n? ------------------------------------------ Is this dangerous? B. Severity ------------------------------------------ SEVERITY Suppose fprintf writes a log file, what harm could happen from attacker-controlled formats? ------------------------------------------ C. Mitigation 1. code review ------------------------------------------ FIXES TO LOOK FOR IN REVIEW Change printf(user_input); to printf( ------------------------------------------ What should be done in C++? ------------------------------------------ IS THIS SUSCEPTIBLE? fprintf(STDERR, err_msg); ------------------------------------------ If so, what should be done about it? ------------------------------------------ IS THIS SUSCEPTIBLE? fprintf(file, msg_format, arg1, arg2); ------------------------------------------ ------------------------------------------ THINGS TO LOOK FOR IN REVIEW Look for: printf(user_input); fprintf(file, user_input); and calls to any function with ... in its type void syslog(int priority, const char *format, ...); ------------------------------------------ 2. tools ------------------------------------------ TOOLS TO FIND THESE BUGS Use gcc -Wformat=2 or gcc -format -Wformat-security source code scanners: RATS flawfinder ------------------------------------------ 3. testing ------------------------------------------ TESTING TECHNIQUES For C/C++: Use %x in inputs, see if get hex output For other languages, adjust ------------------------------------------ What other problems could happen if an app gives back your input? III. Integer Overflow Attacks A. Background ------------------------------------------ INTEGER ARITHMETIC In C, C++, Java, C# is modulo arithmetic ------------------------------------------ 1. C conversion rules ------------------------------------------ C CONVERSION RULES Integer promotions: numbers smaller than int are promoted: to int, if possible to unsigned int, otherwise char c1 = 200; char c2 = 56; char c = c1 + c2; Integer Conversion Rank lattice (C99): long long int unsigned long long int | | long int unsigned long int | | int unsigned int | / \ | short int unsigned short int | \ / | signed char char unsigned char \ | / _Bool ------------------------------------------ Why would C do integer promotions? What is the value of c? ------------------------------------------ Usual Arithmetic Conversions: Goal: balance argument types 1. Stop after integer promotion, if balanced 2. If both are signed (or unsigned), convert the argument with lower integer rank to the higher integer rank 3. If the arg with higher rank is unsigned, convert the other arg to that type 4. Otherwise, convert the other arg to the higher signed type ------------------------------------------ ------------------------------------------ EXAMPLE What does this C code print? int si = -1; unsigned int ui = 1; printf("%d\n", si < ui); What can happen in this code? const long int MAXLEN = 0x7fff; short len = strlen(input); if (len < MAXLEN) { printf("sad\n"); } else { printf("happy\n"); } ------------------------------------------ What answers can the second code give? 2. gotchas ------------------------------------------ GOTCHAS What does this print? signed char c = -128; signed char result = c/-1; printf("result = %d\n", result); Comparisons between signed and unsigned ints Binary operators on signed ints: int flags = 0x7f; char LowByte = 0x80; if ((char)flags ^ LowByte == 0xff) { return SUCCESS; } return FAILURE; ------------------------------------------ 3. other languages ------------------------------------------ OTHER LANGUAGES Java - has only signed integers built in - rules are just like C (on purpose) - no exceptions for overflows C# - rules are like Java (and thus C) but will use 64 bit integers - has stricter type checking than C byte a=1, b=255; byte c = a+b; // type error! - has checked code blocks, throws error on overflow Perl - uses double precision floats to represent all numbers ------------------------------------------ B. attack 1. steps ------------------------------------------ ATTACK 1. Find a calculation that 2. Feed the program inputs that 3. Use that to ------------------------------------------ Where is the user input used in this attack? 2. implications ------------------------------------------ IMPLICATIONS Mac OS X 10.4.11 - denial of service from integer overflows Android SDK: special BMP file with negative offset field leads to buffer overflow attack Microsoft IIS server: HTR handler accepted length of 64K-1, then added 1, and allocated 0 bytes ------------------------------------------ C. remediation ------------------------------------------ REMEDIATION 1. Do the math ? Size = (elements * sizeof(element)) + sizeof(header) How many elements can be handled? 2. Temporarily write out casts to help unsigned int x; short a, b; /* ... */ if (a+b < x) { DoSomething(); } 3. Don't use "clever tricks" int a, b, c; c = a*b; /* check for overflows */ if (c < 0) { return OVERFLOW; } ------------------------------------------ What would be the casts in the code for 2? What's wrong with the code in 3? How could you fix that? ------------------------------------------ OTHER DEFENSES Use SafeInt package www.codeplex.com/SafeInt In gcc can catch signed integer overflows using -ftrapv Static analysis tools ------------------------------------------ IV. C++ Catastrophes A. background ------------------------------------------ DEFAULT METHODS IN C++ class CountedPtr { public: int count; void *ptr; } desugars to: class CountedPtr { public: int count; void *ptr; inline CountedPtr() // default constr. : count(0), ptr(NULL) {} CountedPtr(const CountedPtr& rhs) // copy constr. { count = rhs.count; ptr = rhs.ptr; } CountedPtr& operator= // assignment opr. (const CountedPtr& rhs) { count = rhs.count; ptr = rhs.ptr; } ~CountedPtr() // default destr. { delete ptr; } } ------------------------------------------ What code should these have? B. attack overview ------------------------------------------ C++ CODE ATTACKS Attack Steps 1. Find code that passes around 2. Exploit coding error ------------------------------------------ How does a double free of code hurt in C++? C. examples of problems that are exploitable 1. mismatched calls to delete ------------------------------------------ MISMATCHED CALLS TO DELETE or DELETE[] objects allocated with new should be freed using delete objects allocated with new[] should be freed using delete[] Problem n[]d: char* pChars = new char[128]; // ... delete pChars; Problem nd[]: widget *mw = new widget; //... delete[] mw; ------------------------------------------ What is the difference between new and new[]? What happens in the problem n[]d example? What happens in the problem nd[] example? 2. constructor problems ------------------------------------------ CONSTRUCTOR PROBLEMS uninitialized members could be controlled by attacker How? ------------------------------------------ D. remediation 1. don't use arrays, use vectors from the STL ------------------------------------------ USE STL See the STL Tutorial and Reference Guide (Musser et al., 2001) Vectors, instead of arrays: vector arr(10); vector::iterator it; for(it = arr.begin(); it != arr.end(); ++it) { T& obj = (*it); //... } Safer code, Harder to make buffer overflows Pointer Containers Use auto_ptr (or unique_ptr) or the Use the boost pointer container library boost::shared_ptr See www.boost.org/doc/libs/ 1_35_0/libs/ptr_container/ ------------------------------------------ 2. general remediation steps ------------------------------------------ REMEDIATION STEPS Thoroughly understand C++ Stop using arrays in C++, and For resource classes, no copying, so: get rid of the copy constructor and assignment operator private: Make constructors initialize all data members, with no exceptions! For complex constructions, use Destructors should ------------------------------------------ V. Bad Exception Handling A. background ------------------------------------------ EXCEPTION HANDLING BACKGROUND Java, C#, and C++ are similar try-catch blocks set up handlers try { char* pSz = new char[count]; } catch (...) { cerr << "Out of memory!\n"; abort(); } finally { printf("bye!"); } The catch(...) catches A clause like catch(std::bad_alloc& e) is ------------------------------------------ ------------------------------------------ C's Structured Exception Handling (SEH) __try, __except, __finally macros mimic C++ exception handling. ------------------------------------------ B. attack 1. plan ------------------------------------------ ATTACK STEPS 1. Find code that catches exceptions but 2. Provoke app to throw that exception 3. Exploit ------------------------------------------ 2. invariants ------------------------------------------ HOW TO KNOW IF AN OBJECT IS IN A GOOD STATE? Use an invariant! def: an *object invariant* is a property that should be ------------------------------------------ ------------------------------------------ INVARIANTS: STABILITY PROPERTIES Example (in Java): import java.util.ArrayList; public class IntSet { private int size = 0; private ArrayList elems = (ArrayList) new ArrayList(); // invariant: size is the number of elements in elems //@ private invariant size == elems.size(); // invariant: no duplicate elements in elems /*@ private invariant @ (\forall int j; 0 <= j && j < elems.size(); @ (\forall int k; 0 <= k && k < elems.size(); @ (elems.get(j).equals(elems.get(k))) ==> j == k)); @*/ public IntSet() {} public boolean has(int i) { for (int e : elems) { if (e == i) { return true; } } return false; } public void add(int i) { if (has(i)) { return; } elems.add(i); } public void delete(int i) { if(elems.remove(new Integer(i))) { size--; } } // ... } ------------------------------------------ How does the code maintain that invariant? What could happen if the invariant is false? 3. using invariants with exceptions ------------------------------------------ USING INVARIANTS WITH EXCEPTIONS Assumptions: invariant holds at start of each method Obligations: establish invariant at end of constructor establish invariant when exit method, (except destructor) either normally or by exception establish invariant before calling another method ------------------------------------------ C. redemption ------------------------------------------ REDEMPTION STEPS - Write down invariants for all classes - Check that either: - invariants are re-established when exceptions are caught, or - the program exits (aborts) Don't catch all exceptions with catch(...) or catch(Exception e) unless aborting the program Don't handle segmentation fault signals Handle signals using safe functions ------------------------------------------ VI. Command Injection A. attack ------------------------------------------ ATTACK OVERVIEW 1. find/guess where input is 2. provide input that Example: /* IRIX login screen printing */ char buf[1024]; snprintf(buf, "system lpr -P %s %s", users_printer, doc_selection, sizeof(buf)-1); system(buf); ------------------------------------------ What's this like that we have seen before? In the example, what could happen? ------------------------------------------ AFFECTED LANGUAGES Any language that can call an interpreter Perl, Ruby, Python prone because easy to pass commands to shell Python example: def call_func(user_input, system_data): exec 'special_function_%s("%s")' % (system_data, user_input) ------------------------------------------ What does the Python code do? B. summary ------------------------------------------ SUMMARY Like SQL injection, the problem is: - using untrusted - using concatenation instead of Problem symptoms: - mixing commands with - running ------------------------------------------ C. remediation 1. code review ------------------------------------------ CODE REVIEW Track Validate all Never run Find calls to ------------------------------------------ 2. other measures ------------------------------------------ OTHER DEFENSIVE MEASURES Run app using least privilege Be conservative, use an "allow only" approach, not a Use taint mode in Perl and Ruby ------------------------------------------ Why is an allow list approach better than a deny list? VII. Failure to handle errors correctly A. attack ------------------------------------------ ATTACK OVERVIEW 1. discover how to 2. Give input that 3. Exploit the result to cause: ------------------------------------------ B. varieties of the problem 1. too much information ------------------------------------------ PROBLEM: TOO MUCH INFORMATION (INFO. LEAKAGE) Telling the user about ------------------------------------------ Do normal users want to see all that debugging information? 2. ignoring errors ------------------------------------------ PROBLEM: IGNORING ERRORS Ignoring return values (in C) or exceptions that indicate errors Examples: Can this Windows code cause problems? ImpersonateSelf(Client); /* ... carry on as the client ...*/ RevertToSelf(); In C, can this cause any problems? FILE* lf = fopen(logfile, "a"); fprintf(lf, "%s\n", entry); fclose(lf); ------------------------------------------ 3. misinterpreting errors ------------------------------------------ MININTERPRETING ERRORS recv() for getting socket data >0 means length of message in bytes =0 means no messages available -1 means error malloc() =0 is okay if size argument was 0 NULL if size argument was >0 and out of memory realloc() NULL if size argument is 0 and okay NULL if size argument is >0 and not enough memory fgets() NULL if there is an error NULL if the no data are read MulDiv() windows 64 bit integer function -1 on error ------------------------------------------ What problems do these return conventions pose? C. remediation ------------------------------------------ REMEDIATION In C be sure to check return values when appropriate In Java/C# don't ignore mandatory exceptions Code reviews are good for spotting problems Look especially for: - C code that does not check return values - Windows code that does not check return values of impersonation functions Use Microsoft Visual C++ annotation _Check_return_ or Java checked exceptions to force caller to check for the return value (C++) or handle exceptions (Java) ------------------------------------------ ------------------------------------------ WHEN TO USE CHECKED EXCEPTIONS I.e., when to force users to handle exceptions? When it is not usually possible or easy for caller to ------------------------------------------ What are some examples where checked exceptions are appropriate? VIII. Information Leakage A. attack ------------------------------------------ ATTACK OVERVIEW 1. Cause the system to reveal This can happen: - intentionally, when - accidentally due to logic error or a side channel or a debugging ------------------------------------------ Does this affect any particular programming language? B. privacy ------------------------------------------ PRIVACY Don't compromise privacy of users Do protect any personal information users give the program Why? ------------------------------------------ ------------------------------------------ PRIVACY VS. USABILITY Should credit card numbers be saved or forgotten? ------------------------------------------ C. accidental information leakage 1. side channels ------------------------------------------ SIDE CHANNEL A *side channel* is a way of obtaining information other than through the Two main types: - timing channels - storage channels ------------------------------------------ a. timing channels ------------------------------------------ TIMING CHANNELS Measure how long operations take (using a clock) E.g., timing how long it takes to check a login attempt Blind SQL injection attacks: if exists (select * from foo..table) waitfor delay '0:0:5' ------------------------------------------ What does the SQL do? b. storage channels ------------------------------------------ STORAGE CHANNELS Obtain information from data online E.g., name of a file: Plan to Buy Midas Corp.docx length of a network message senders and receivers IP addresses from headers of packets ------------------------------------------ What kind of information might someone get from a file name? What kind of information might an attacker get from message length? Why might a user not want to have their IP address revealed? c. too much information, especially in error messages ------------------------------------------ TOO MUCH INFORMATION Network servers: should be conservative in information given to callers, in case caller is an attacker Version information should be hidden Prelude to an attack: fingerprinting of systems - find out what software and versions is running on a system e.g., web server GET request shows banner ------------------------------------------ i. host network information ------------------------------------------ HOST NETWORK INFORMATION Leaking internal network information: - MAC addresses - machine names - IP addresses Why not leak that? ------------------------------------------ ii. application information ------------------------------------------ APPLICATION INFORMATION Error messages shouldn't leak sensitive information ------------------------------------------ What kind of application information shouldn't be leaked? ------------------------------------------ FOR YOU TO DO: IS THIS OKAY? Java code: try { // ... } catch(Exception e) { System.out.println(e.toString()); } ------------------------------------------ D. information flow security (confidentiality and integrity) ------------------------------------------ BELL-LAPADULA MODEL Confidentiality: who can read what can read user public secret top secret ======================================== top secret ^ | secret ^ | public Integrity: who can write what can write user public secret top secret ======================================== top secret | v secret | v public ------------------------------------------ Which users are the most trusted? Which users can write anywhere? E. remediation ------------------------------------------ REMEDIES First, specify information policy Who needs access to what data? What kinds of information are high value? Protect sensitive data - at rest use ACLs or permissions and encryption or rights management - in transmission, use encryption For error messages: - log problem - only give details to certain users and only if they are local if (IPAddress.IsLoopback(ip)) { // local user } Can perform "output validation" check if output obeys policy ------------------------------------------ F. auditing ------------------------------------------ CODE AUDITING What to look for: - process sending output from - the OS - the run-time system/environment - Operations on sensitive data that don't - accidental use of sensitive/private info - unprotected or weakly protected sensitive data - unprotected or sensitive data sent over insecure channels ------------------------------------------ How do we know what data is sensitive? ------------------------------------------ WHAT TO LOOK FOR Language Keywords/functions ======================================== C/C++ (*nix) errno, strerror, perror C/C++ (Windows) GetLastError() C#, VB.NET, Any exception ASP.NET Python Any exception Ruby Any exception Java Any exception PHP Any exception ------------------------------------------ How to find exceptions? ------------------------------------------ FINDING TIMING CHANNELS 1. Identify secret data 2. Can operations vary in time, based on secret data ------------------------------------------ What could be done with testing? IX. Guiding principles for software security How do we construct software so that it doesn't suffer from unknown vulnerabilities? A. principles based on risk management ------------------------------------------ PRINCIPLES FOR AVOIDING FUTURE PROBLEMS From "Building Secure Software: How to Avoid Security Problems the Right Way" by John Viega and Gary McGraw (Addison-Wesley, 2002), chapter 5. Overall idea: risk management 1. Secure the weakest link. 2. Practice defense in depth. 3. Fail securely. 4. Follow the principle of least privilege. 5. Compartmentalize. 6. Keep it simple. 7. Promote privacy. 8. Remember that hiding secrets is hard. 9. Be reluctant to trust. 10. Use your community resources. ------------------------------------------ 1. Secure the weakest link ------------------------------------------ 1. SECURE THE WEAKEST LINK A system is only as secure as its weakest component Assumes attackers will seek and attack it Examples: - cryptography - firewalls Lesson: - do a - address the - prioritize ------------------------------------------ Which is robbed more often: a bank or a 7-11 store? ------------------------------------------ SOCIAL ENGINEERING Often a weak link for a system Example: technical support staff - reset passwords for callers How to fix this attack? - limit the capabilities of technical support staff to ------------------------------------------ 2. Practice defense in depth ------------------------------------------ 2. PRACTICE DEFENSE IN DEPTH Real-world Examples: - bank security (cameras, guards, vault) - prisons (cells, several walls, guards) - military fortresses (moat, walls, cannon, soldiers) Computer system examples: ------------------------------------------ Have you ever visited St. Augustine's fort (Castillo de San Marcos)? 3. Fail securely ------------------------------------------ 3. FAIL SECURELY Plan for failure of the system, and fail to a secure state. Think about the invariants of the system! Example: - design a forced upgrade path in case - when exiting ------------------------------------------ 4. use the principle of least privilege ------------------------------------------ 4. USE PRINCIPLE OF LEAST PRIVILEGE Not: "here, take my wallet and get me a coke" but "here's $1.25, go buy me a coke" Examples: - run app with - give/get file permissions that - run mobile code in ------------------------------------------ Is there a tradeoff with usability? 5. Compartmentalize ------------------------------------------ 5. COMPARTMENTALIZE Idea: breach of one "compartment" doesn't sink the entire ship System examples: - Trusted Solaris breaks system into roles: e.g., LogWriter Negative examples: - root access in Unix needed to open a port < 1024 so sendmail runs as root... ------------------------------------------ 6. Keep it Simple ------------------------------------------ 6. KEEP IT SIMPLE Complexity increases risk of problems "There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult." -- Tony Hoare, Turing Award lecture, 1980 Complex designs are Complex implementations are Do reuse code of high quality, experience builds assurance ------------------------------------------ Is this principle at odds with another principle? ------------------------------------------ HOW TO DESIGN SIMPLICITY IN? Have a small number of choke points - small interfaces - helps to avoid - no "back doors"! Make the system usable easily - users shouldn't have to think hard to be secure - users shouldn't have to read documentation - get inputs directly from users - err on the safe side (securely) - users are lazy, so don't burden them with choices they don't want ------------------------------------------ 7. promote privacy ------------------------------------------ 7. PROMOTE PRIVACY Don't compromise user's privacy Protect personal information Keep security-related information private - especially in error messages ------------------------------------------ Why promote privacy of user information? 8. remember that keeping secrets is hard ------------------------------------------ 8. REMEMBER THAT KEEPING SECRETS IS HARD E.g., PII of users cryptographic keys Compilation does not hide secrets, attackers can - don't hide cryptographic keys in code Insider attacks are real most attacks done by insiders ------------------------------------------ Where should cryptographic keys be? 9. be reluctant to trust ------------------------------------------ 9. BE RELUCTANT TO TRUST Examples: - servers vs. clients - technical support for customers - use independent code audits Trust is transitive - you trusting code means you trust whatever that calls ------------------------------------------ 10. use your community resources ------------------------------------------ 10. USE YOUR COMMUNITY RESOURCES Don't write your own cryptography routines use standard ones Use security libraries that are - widely used - widely scrutinized However: - open source software can have flaws e.g., heartbleed bug, FTP server ------------------------------------------