1 / 22

Format String Protection

Format String Protection. David Brumley Sam Wu June 12 th , 2002. Format String Attack Basis. Similar to buffer overflow attacks, it relies on altering flow of control to attacking code Unlike buffer overflow attacks, it takes advantage of C variable argument macros

channer
Télécharger la présentation

Format String Protection

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Format String Protection David Brumley Sam Wu June 12th, 2002

  2. Format String Attack Basis • Similar to buffer overflow attacks, it relies on altering flow of control to attacking code • Unlike buffer overflow attacks, it takes advantage of C variable argument macros • e.g. printf(“%d %n”, a, b) vs printf(“%d %n”, a)

  3. Expected Contributions of our proposal • A Metric: • Previous work has been ad-hoc, and does not generalize well. • General Variatic Solutions: • We propose a generalized solution to dealing with variatic arguments that rely upon ideas first investigated by StackGuard. • Application Specific Protection: • We detail statically inserting dynamic checks into format string specifiers. Thus, coders who don’t want to pay the price of full pointer safety can pay a smaller price for a different safety guarantee.

  4. Foo’s frame: Actual arguments Actual arguments Saved IP for main Custom IP (“/bin/sh”) Saved FP for main Saved FP for main a a Metric: Different Levels of Attacks • Level 1: Common misuse of printf like functions to rewrite return address or frame pointer • e.g. a simplified version foo() { int a; printf(“%d %d %n”); } main() { foo(); } -Also possible: double return, multiple returns attack

  5. with StackGuard… Actual arguments Saved IP Saved FP Canary a Guarding Level 1 Attacks • Statically: • Type inferencing: • Tainted/untainted analysis • Dynamically: • StackGuard: • protect the saved IP and FP from being overwritten by using a random canary However…….

  6. Actual arguments Actual arguments Actual arguments Saved IP Crafted IP Saved IP Saved FP Saved FP Saved FP “%d %n” “Hello World” “%d %n” (buf2[5]) “abcde” “abcde” Tainted/untainted analysis says fine Level 2 Attacks • Also called a “hybrid attack” • Using buffer overflow to taint the format string specifier • e.g. int main(int argc, char argv[]) { char buf1[] = “Hello World”; char buf2[5]; strcpy(buf2, argv[1]); printf(buf1); }

  7. Actual arguments Actual arguments Saved IP Crafted IP Saved FP Saved FP Canary Canary int int How StackGuard fails… • Consider just a simple format string: • printf(“%d %d %d %n”, a, b, c); In theory, you can have any number of % directives that eventually would lead you to write an abitrary location on the stack frame…

  8. main: argc, argv[] Saved IP Saved FP Locals for Main LibSafe: Writable area LibVerify: Check integrity foo: Actual Arguments IP for Main FP for Main Locals for Foo IP for Main Locals for Main FP for Main Actual Arguments Guarding Level 2 Attacks • LibSafe: • Intercepts most library calls and makes sure all buffer writes are within frame bounds • e.g. strcpy, strcat, getwd, gets, fscanf, scanf, realpath, sprintf… • LibVerify: • Wraps all functions such that the integrity of the return address is checked upon function entry and exit Still yet….

  9. argv[] argv[] Saved IP Saved IP Saved FP Saved FP p p’ (buf[30]) (buf[30]) Level 3 Attacks • An attacker can construct an arbitrary pointer during run-time • e.g. int func(char argv[]) { char *p; char buf[30]; p = buf; printf(arg[1]); strncpy(p, arg[2], 29); } • can set p’ points to the global • offset table (GOT) and change • printf() to system(), so executing • printf(“/bin/sh”) becomes system(“/bin/sh”) -demonstrates the ability to alter program control flow to an arbitrary execution point

  10. Guarding Level 3 Attacks • Requires full inter-procedural point-to analysis • However, in the context of dynamic format string, which allows overwriting of (almost) any arbitrary memory location, point-to analysis cannot conclude anything, since any pointer could be rewritten to point to any other data in memory • Bottom line: • Dynamic checking is necessary for ensuring security integrity

  11. A Possible Exploit (where LibSafe failed…) int main(int argc, char **argv) { int x=0; printf(“before x: %#x @ %#x\n”, x, &x); foo(4, argv[1]); printf(“after x: %#x @ %#x\n”, x, &x); return 0; } void foo(int c, char *s, …) { int i; char *j; va_list va; va_start(va, s); j = va_arg(va, char*); printf(“j: %#x @ %#x\n”, *j, j); printf(“abcd: %d%n\n”, 2, j); va_end(va); } Running yields: [root]./a.out before x: 0 @ 0xbffffa04 j: 0 @ 0xbffffa04 abcd: 2 after x: 0x7 @ 0xbffffa04

  12. main: main: argc, **argv argc, **argv Saved IP Saved IP Saved FP Saved FP x = 0 x = 7 va foo: s = &(argv[1]) j c = 4 IP for Main FP for Main Locals for Foo A Possible Exploit (cont’d) void foo(int c, char *s, …) { int i; char *j; va_list va; va_start(va, s); j = va_arg(va, char*); printf(“j: %#x @ %#x\n”, *j, j); printf(“abcd: %d%n\n”, 2, j); va_end(va); } int main(int argc, char **argv) { int x=0; printf(“before x: %#x @ %#x\n”, x, &x); foo(4, argv[1]); printf(“after x: %#x @ %#x\n”, x, &x); return 0; } Locals for Foo

  13. Recall: the va_list mechanism • Recall (as defined in stdarg.h): • void va_start(va_list ap, arg) • Sets up ap to point to first variatic argument (aka. anonymous arguments) placed upon the stack • type va_arg(va_list ap, type) • Returns current values pointed to by ap, then advanc ap by sizeof(type) • void va_end(va_list ap) • Cleans up ap • This mechanism allows one function body to work with multiple arguments without code duplication.

  14. Our Proposal • Previous work: • Has not solved the generic variatic argument and va_list problem; they instead focused on eliminating format string exploits found in practice • Our motivations and goals: • To fix variatic functions such that the program is able to determine at run time where the end of the variatic arguments actually are. • Finer grained than libsafe because it protects against local variables that may be involved in a level 3 attack (recall previous exploit) • Provide a richer functionality than FormatGuard by eliminating attacks in functions that take va_list Three potential solutions…

  15. Canary Protection • Canary protection: • Push onto the stack a canary value before pushing the function actuals onto the stack. Thus function arguments are guarded up the stack by the canary, and down the stack by the start of the anonymous arguments (i.e. what returned by va_start) • Since both values are known at compile time, the va_arg macro can be modified to insert a dynamic check to make sure all accesses are within these bounds

  16. Canary Actual arguments Saved IP Saved FP Locals Canary Protection (cont’d) • Example pseudo code: #define va_arg(x, type) tmp = real_va_arg(x, type) if (tmp == canary) { set perm error return error } else return tmp Pros :access via format string (va_list ultimately) is guarded to only the actuals Cons :the false canary problem :two pointers check per va_arg

  17. Add total size of variatic args • Redefine variatic arguments to include a total size of arguments passed to the function as the first paramter • For va_start, this means also returns the total number of bytes in the va_arg

  18. 3 2 1 $total_size $non_anonymous_args Add total size of variatic args (cont’d) • Pseudo code: #define va_start(x, y) x = va_list(y); va_arg(y); Pros :allows precise bounding of the anonymous argument total size :no false canary problem Cons :recompilation of source, as stack offset is now changed

  19. Reorder the stack • Change function invocation to push the functions actuals onto the stack after the saved IP and FP Pros :one check per va_arg access Cons :does not protect local variables from misuse

  20. Plans of Actions • Require • a protected libc implementation • a compiler that emits the proper code for the bounds check; which we believe to be a medium-hard fix to gcc • a set of tests indicating the performance difference between the three approaches

  21. Related Work • Type Qualifiers (e.g. tainted/untainted static analysis) • Detecting possible flow of tainted buffer to supposedly untainted buffer • Require manual annotations and access to source code • FormatGuard • Statically insert code to check dynamically number of % directives with the number of actual arguments to printf functions • Does not support vprintf like functions (or functions that use va_list), does not handle pointer to printf functions, does not check type of % directives • Metal • Static analysis to find bugs in program • Unsound and incomplete: finding bugs is important to security applications, but is orthogonal to insuring security safety

  22. Related Work (cont’d) • StackGuard • Ensure return address integrity by using a random canary • Run time overhead and require access to source code, and possibly recompilation • LibSafe • Intercepting and redirecting common string functions to safe versions, thus enforcing buffer write within stack frame bound • Does not prevent the exploit previously presented • Fails to protect programs compiled with -fomit-frame-pointer or -static, functions not defined in libsafe, kernel code, programs that do not have return address followed by frame pointer • LibVerify • Wrap all functions and compare return address on function entry and exit to ensure integrity • Require duplication for each function defined (modified function stored on heap)

More Related