├── Makefile ├── README.md ├── alloca ├── alloca.c ├── cast ├── cast.c ├── cfi-simple.cpp ├── cfi.cpp ├── control-flow ├── control-flow-plain ├── control-flow-safe-stack ├── control-flow-simple ├── safe-stack ├── safe-stack-plain ├── safe-stack.c ├── struct-call ├── struct-call.c ├── ud2 └── ud2.c /Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-Wno-unused-result -Wno-format -fPIE -pie -fstack-protector -Wl,-z,now -Wl,-z,relro -D_FORTIFY_SOURCE=2 -O2 2 | 3 | # Obviously this requires clang3.7 4 | all: cast alloca safe-stack-plain safe-stack struct-call control-flow-plain control-flow \ 5 | control-flow-simple control-flow-safe-stack ud2 6 | 7 | ud2: ud2.c 8 | clang $(CFLAGS) -flto ud2.c -o ud2 9 | cast: cast.c 10 | clang $(CFLAGS) -fsanitize=safe-stack cast.c -o cast 11 | alloca: alloca.c 12 | clang $(CFLAGS) -fsanitize=safe-stack alloca.c -o alloca 13 | safe-stack-plain: safe-stack.c 14 | clang $(CFLAGS) safe-stack.c -o safe-stack-plain 15 | safe-stack: safe-stack.c 16 | clang $(CFLAGS) -fsanitize=safe-stack safe-stack.c -o safe-stack 17 | struct-call: struct-call.c 18 | clang $(CFLAGS) -flto -fsanitize=cfi struct-call.c -o struct-call 19 | control-flow-simple: cfi-simple.cpp 20 | clang++ $(CFLAGS) -flto -fsanitize=cfi cfi-simple.cpp -o control-flow-simple 21 | control-flow-plain: cfi.cpp 22 | clang++ $(CFLAGS) -flto cfi.cpp -o control-flow-plain 23 | control-flow: cfi.cpp 24 | clang++ $(CFLAGS) -flto -fsanitize=cfi cfi.cpp -o control-flow 25 | control-flow-safe-stack: cfi.cpp 26 | clang++ $(CFLAGS) -flto -fsanitize=cfi,safe-stack cfi.cpp -o control-flow-safe-stack 27 | 28 | tarball: all 29 | tar --exclude '.git' --exclude 'solutions' -vzcf ../cfi.tgz ../cfi 30 | mv ../cfi.tgz . 31 | 32 | clean: 33 | rm -f cfi.tgz 34 | # These are toy binary to look at the disassembly 35 | rm -f alloca 36 | rm -f cast 37 | rm -f control-flow-simple 38 | rm -f struct-call 39 | rm -f ud2 40 | # These are exploity ones 41 | rm -f safe-stack-plain 42 | rm -f safe-stack 43 | rm -f control-flow-plain 44 | rm -f control-flow 45 | rm -f control-flow-safe-stack 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CFI and Safe Stack 2 | 3 | Some binaries to play around with the new LLVM exploit mitigations. Binaries are just a basic 64-bit write8/read8/printf loop with standard exploit mitigations enabled (relro, pie, cookies, nx). 4 | 5 | * cast: simple example of trying to cast a stack pointer onto the fake stack 6 | * ud2: example of `-flto` turning use of un-initialized memory to a `ud2` instruction 7 | * alloca: non-exploitable binary with `-fsanitize=safe-stack` to show behavior of `alloca(3)` 8 | * safe-stack: `-fsanitize=safe-stack` 9 | * safe-stack-plain: Same binary, without `-fsanitize=safe-stack` 10 | * struct-call: `-fsanitize=cfi` applied to a C function pointer 11 | * control-flow-simple: Basic `-fsanitize=cfi` binary to look at guards 12 | * control-flow: `-fsanitize=cfi` 13 | * control-flow-safe-stack: `-fsanitize=cfi,safe-stack` 14 | * control-flow-plain: Same binary, without either. 15 | 16 | I'd suggest reading the Makefile. 17 | 18 | If there's anything you want me to add/remove, let me know (@yrp604 or email) and I'll try to hook it up. 19 | 20 | Some notes: 21 | * `-fsanitize=safe-stack` adds quite a bit of code to the resulting binaries 22 | * `-fsanitize=cfi` requires a `LLVMgold.so` which seems to require a current binutils 23 | * More detailed `safe-stack` notes [here](https://gist.github.com/yrp604/70bd281dd04a982b0397). 24 | * More detailed `cfi` notes [here](https://gist.github.com/yrp604/2e1b13f76c18186ea203) 25 | -------------------------------------------------------------------------------- /alloca: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yrp604/cfi/d10a5e4cb95efbafce10e6da1b532138e11e7ab8/alloca -------------------------------------------------------------------------------- /alloca.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char **argv) { 7 | char *buf; 8 | buf = alloca(strtoul(argv[1], NULL, 0)); 9 | printf("%p\n", buf); 10 | 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /cast: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yrp604/cfi/d10a5e4cb95efbafce10e6da1b532138e11e7ab8/cast -------------------------------------------------------------------------------- /cast.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | char buf[20]; 5 | unsigned long x; 6 | x = (unsigned long)buf; 7 | printf("%p\n", x); 8 | return 0; 9 | } 10 | -------------------------------------------------------------------------------- /cfi-simple.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | class obj { 9 | public: 10 | virtual void fp() { printf("[-] ?\n"); } 11 | }; 12 | 13 | class thing : public obj { 14 | public: 15 | void fp() { printf("[-] :(\n"); } 16 | }; 17 | 18 | void __attribute__ ((noinline)) doit(obj *o) { 19 | o->fp(); 20 | } 21 | 22 | int main(int argc, char **argv) { 23 | obj *o; 24 | thing *t; 25 | 26 | t = new thing; 27 | o = new obj; 28 | 29 | printf("[+] Calling o/t->fp()...\n"); 30 | doit(o); 31 | doit(t); 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /cfi.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | class obj { 9 | public: 10 | virtual void fp() { printf("[-] ?\n"); } 11 | }; 12 | 13 | class thing : public obj { 14 | public: 15 | virtual void fp() { printf("[-] :(\n"); } 16 | }; 17 | 18 | class gadget : public thing { 19 | public: 20 | void fp() { printf("[-] !\n"); } 21 | }; 22 | 23 | void doit_o(obj *o) { 24 | char buf[20]; 25 | printf("%p\n", buf); 26 | o->fp(); 27 | } 28 | 29 | void doit_t(thing *t) { 30 | puts("doit_t"); 31 | t->fp(); 32 | } 33 | 34 | void doit_g(gadget *g) { 35 | puts("doit_g"); 36 | g->fp(); 37 | } 38 | 39 | int main(int argc, char **argv) { 40 | char buf[20]; 41 | void *code; 42 | unsigned int i = 0; 43 | unsigned long x, y, *write; 44 | thing *t; 45 | obj *o; 46 | gadget *g; 47 | 48 | code = mmap(NULL, 0x1000, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 49 | 50 | if (getenv("SHELLCODE")) 51 | strncpy((char *)code, getenv("SHELLCODE"), 0x1000); 52 | 53 | o = new obj; 54 | t = new thing; 55 | g = new gadget; 56 | 57 | printf("[+] main @ 0x%llx\n", main); 58 | printf("[+] printf @ 0x%llx\n", printf); 59 | printf("[+] buf @ 0x%llx\n", buf); 60 | printf("[+] code @ 0x%llx\n", code); 61 | printf("[+] t @ 0x%llx\n", t); 62 | 63 | write = (unsigned long *)buf; 64 | 65 | for (;;) { 66 | printf("[*] Write #%u\n", i++); 67 | printf("[*] x:\n"); 68 | fgets(buf, sizeof(buf), stdin); 69 | x = strtoul(buf, NULL, 0); 70 | 71 | printf("[*] y:\n"); 72 | fgets(buf, sizeof(buf), stdin); 73 | y = strtoul(buf, NULL, 0); 74 | 75 | if (x == 0xdeadbeef && y == 0xdeadbeef) 76 | break; 77 | 78 | printf("[+] write8 *0x%llx = 0x%llx\n", &write[x], y); 79 | write[x] = y; 80 | 81 | printf("[*] read8 index:\n"); 82 | fgets(buf, sizeof(buf), stdin); 83 | x = strtoul(buf, NULL, 0); 84 | printf("[+] read8 0x%llx: 0x%llx\n", &write[x], write[x]); 85 | 86 | printf("[*] print str:\n"); 87 | fgets(buf, sizeof(buf), stdin); 88 | printf(buf); 89 | } 90 | printf("[+] Calling o->fp()...\n"); 91 | doit_o(o); 92 | 93 | printf("[+] Calling t->fp()...\n"); 94 | doit_o(t); 95 | doit_t(t); 96 | 97 | printf("[+] Calling g->fp()...\n"); 98 | doit_o(g); 99 | doit_t(g); 100 | doit_g(g); 101 | } 102 | -------------------------------------------------------------------------------- /control-flow: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yrp604/cfi/d10a5e4cb95efbafce10e6da1b532138e11e7ab8/control-flow -------------------------------------------------------------------------------- /control-flow-plain: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yrp604/cfi/d10a5e4cb95efbafce10e6da1b532138e11e7ab8/control-flow-plain -------------------------------------------------------------------------------- /control-flow-safe-stack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yrp604/cfi/d10a5e4cb95efbafce10e6da1b532138e11e7ab8/control-flow-safe-stack -------------------------------------------------------------------------------- /control-flow-simple: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yrp604/cfi/d10a5e4cb95efbafce10e6da1b532138e11e7ab8/control-flow-simple -------------------------------------------------------------------------------- /safe-stack: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yrp604/cfi/d10a5e4cb95efbafce10e6da1b532138e11e7ab8/safe-stack -------------------------------------------------------------------------------- /safe-stack-plain: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yrp604/cfi/d10a5e4cb95efbafce10e6da1b532138e11e7ab8/safe-stack-plain -------------------------------------------------------------------------------- /safe-stack.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char **argv) { 8 | char buf[20]; 9 | void *code; 10 | unsigned int i = 0; 11 | unsigned long x, y, *write; 12 | 13 | code = mmap(NULL, 0x1000, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 14 | 15 | if (getenv("SHELLCODE")) 16 | strncpy((char *)code, getenv("SHELLCODE"), 0x1000); 17 | 18 | printf("[+] main @ 0x%llx\n", main); 19 | printf("[+] printf @ 0x%llx\n", printf); 20 | printf("[+] buf @ 0x%llx\n", buf); 21 | printf("[+] code @ 0x%llx\n", code); 22 | 23 | write = (unsigned long *)buf; 24 | 25 | for (;;) { 26 | printf("[*] Read/Write #%u\n", i++); 27 | printf("[*] write8 index:\n"); 28 | fgets(buf, sizeof(buf), stdin); 29 | x = strtoul(buf, NULL, 0); 30 | 31 | printf("[*] write8 value:\n"); 32 | fgets(buf, sizeof(buf), stdin); 33 | y = strtoul(buf, NULL, 0); 34 | 35 | if (x == 0xdeadbeef && y == 0xdeadbeef) 36 | break; 37 | 38 | printf("[+] write8 *0x%llx = 0x%llx\n", &write[x], y); 39 | write[x] = y; 40 | 41 | printf("[*] read8 index:\n"); 42 | fgets(buf, sizeof(buf), stdin); 43 | x = strtoul(buf, NULL, 0); 44 | printf("[+] read8 0x%llx: 0x%llx\n", &write[x], write[x]); 45 | 46 | printf("[*] print str:\n"); 47 | fgets(buf, sizeof(buf), stdin); 48 | printf(buf); 49 | } 50 | 51 | printf("[+] Returning from main...\n"); 52 | } 53 | -------------------------------------------------------------------------------- /struct-call: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yrp604/cfi/d10a5e4cb95efbafce10e6da1b532138e11e7ab8/struct-call -------------------------------------------------------------------------------- /struct-call.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct obj { 5 | int (*fp)(const char *); 6 | } *o; 7 | 8 | int main(int argc, char **argv) { 9 | //o = malloc(sizeof(struct obj)); 10 | 11 | o->fp = puts; 12 | 13 | o->fp(argv[0]); 14 | 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /ud2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yrp604/cfi/d10a5e4cb95efbafce10e6da1b532138e11e7ab8/ud2 -------------------------------------------------------------------------------- /ud2.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct obj { 4 | void (*f)(int); 5 | } *o; 6 | 7 | int main() { 8 | o->f = exit; 9 | o->f(1); 10 | 11 | return 0; 12 | } 13 | --------------------------------------------------------------------------------