├── Guest ├── easy_pwn │ ├── run.sh │ └── stage2 ├── sample │ ├── run.sh │ ├── run2.sh │ ├── sample │ ├── sample.c │ ├── sample2 │ └── sample2.c └── wrapper │ ├── symarg │ ├── symarg.c │ ├── symfile │ ├── symfile.c │ ├── symio │ ├── symio.c │ ├── symstd │ └── symstd.c ├── README.md ├── sample ├── sample.c ├── sample2.c └── stage2 └── script ├── exploit.sh ├── raw_net.sh ├── s2e.sh └── start.sh /Guest/easy_pwn/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "s2ecmd fork 0" 4 | s2ecmd fork 0 5 | echo "~/wrapper/symarg ./stage2 `python -c "print 'a'*0x1000"`" 6 | ~/wrapper/symarg ./stage2 `python -c "print 'a'*0x1000"` 7 | 8 | -------------------------------------------------------------------------------- /Guest/easy_pwn/stage2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQLab/CRAX-lab/3584f87bb1c49843d29dee136fce57e30e484ea3/Guest/easy_pwn/stage2 -------------------------------------------------------------------------------- /Guest/sample/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "gcc -static sample.c -o sample" 4 | gcc -static sample.c -o sample 5 | echo "s2ecmd fork 0" 6 | s2ecmd fork 0 7 | echo "./sample $(python -c 'print "a"*0x1000')" 8 | ./sample $(python -c 'print "a"*0x1000') 9 | 10 | 11 | -------------------------------------------------------------------------------- /Guest/sample/run2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "gcc -static sample2.c -o sample2" 4 | gcc -static sample2.c -o sample2 5 | echo "s2ecmd fork 0" 6 | s2ecmd fork 0 7 | echo "~/wrapper/symarg ./sample2 `python -c \"print 'a'*0x1000\"`" 8 | ~/wrapper/symarg ./sample2 `python -c "print 'a'*0x1000"` 9 | 10 | 11 | -------------------------------------------------------------------------------- /Guest/sample/sample: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQLab/CRAX-lab/3584f87bb1c49843d29dee136fce57e30e484ea3/Guest/sample/sample -------------------------------------------------------------------------------- /Guest/sample/sample.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void foo(char *a) 4 | { 5 | char b[40]; 6 | strcpy(b, a); 7 | } 8 | 9 | int main(int argc, char** argv) 10 | { 11 | char *a = argv[1]; 12 | s2e_make_concolic(a, 0x1000, "crax"); 13 | foo(a); 14 | } 15 | -------------------------------------------------------------------------------- /Guest/sample/sample2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQLab/CRAX-lab/3584f87bb1c49843d29dee136fce57e30e484ea3/Guest/sample/sample2 -------------------------------------------------------------------------------- /Guest/sample/sample2.c: -------------------------------------------------------------------------------- 1 | 2 | void foo(char *a) 3 | { 4 | char b[40]; 5 | strcpy(b, a); 6 | } 7 | 8 | int main(int argc, char** argv) 9 | { 10 | char *a = argv[1]; 11 | foo(a); 12 | } 13 | -------------------------------------------------------------------------------- /Guest/wrapper/symarg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQLab/CRAX-lab/3584f87bb1c49843d29dee136fce57e30e484ea3/Guest/wrapper/symarg -------------------------------------------------------------------------------- /Guest/wrapper/symarg.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char **argv) 9 | { 10 | if(argc < 2) { 11 | puts("Usage: ./symarg program_path arg0"); 12 | return 0; 13 | } 14 | 15 | pid_t pid; 16 | 17 | //s2e_disable_forking(); 18 | 19 | char *args[argc - 1]; 20 | int i; 21 | for (i = 0; i < argc - 1; i++) 22 | args[i] = argv[i + 1]; 23 | args[i] = NULL; 24 | 25 | s2e_make_concolic(args[1], strlen(args[1]), "crax"); 26 | if(!(pid = fork())) { 27 | execve(args[0], args, NULL); 28 | } else { 29 | wait(); 30 | s2e_kill_state(0, "program terminated"); 31 | } 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /Guest/wrapper/symfile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQLab/CRAX-lab/3584f87bb1c49843d29dee136fce57e30e484ea3/Guest/wrapper/symfile -------------------------------------------------------------------------------- /Guest/wrapper/symfile.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define FILE_LENGTH 120133 11 | 12 | int main(int argc, char** argv) 13 | { 14 | int fd; 15 | pid_t pid; 16 | char *p; 17 | 18 | if (argc < 3) { 19 | puts("Usage: ./symfile symfile program_path [args]"); 20 | return 0; 21 | } 22 | 23 | fd = open(argv[1], O_RDWR); 24 | if (fd < 0) { 25 | printf("open file error \n"); 26 | return 0; 27 | } 28 | 29 | struct stat b; 30 | fstat(fd , &b); 31 | p = mmap(0, b.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); 32 | printf("%c", p[0]); 33 | //s2e_make_symbolic(p, b.st_size, "buf" , 0); 34 | s2e_make_concolic(p, b.st_size, "buf"); 35 | 36 | int i; 37 | char *args[argc - 2]; 38 | for (i = 0; i < argc - 2; i++) 39 | args[i] = argv[i + 2]; 40 | args[i] = NULL; 41 | 42 | if(!(pid = fork())) 43 | execvp(args[0], args); 44 | else 45 | wait(); 46 | 47 | close(fd); 48 | s2e_kill_state(0, "program terminated"); 49 | return 0; 50 | } 51 | 52 | -------------------------------------------------------------------------------- /Guest/wrapper/symio: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQLab/CRAX-lab/3584f87bb1c49843d29dee136fce57e30e484ea3/Guest/wrapper/symio -------------------------------------------------------------------------------- /Guest/wrapper/symio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char **argv) 9 | { 10 | if(argc < 2) { 11 | puts("Usage: ./symio program_path [args]"); 12 | return 0; 13 | } 14 | 15 | int n; 16 | char buf[1024]; 17 | puts("[Get crash input....]"); 18 | n = read(0, buf, sizeof(buf)); 19 | if (n < 0) { 20 | puts("payload error"); 21 | return 0; 22 | } 23 | 24 | int pipe_fd[2]; 25 | pid_t pid; 26 | 27 | //s2e_disable_forking(); 28 | s2e_make_concolic(buf, n, "crax"); 29 | 30 | if(pipe(pipe_fd) < 0) { 31 | printf("pipe error\n"); 32 | exit(1); 33 | } 34 | 35 | write(pipe_fd[1], buf, n); 36 | 37 | char *args[argc - 1]; 38 | int i; 39 | for (i = 0; i < argc - 1; i++) 40 | args[i] = argv[i + 1]; 41 | args[i] = NULL; 42 | 43 | if(!(pid = fork())) { 44 | dup2(pipe_fd[0], 0); 45 | close(pipe_fd[0]); 46 | close(pipe_fd[1]); 47 | execve(args[0], args, NULL); 48 | } else { 49 | close(pipe_fd[0]); 50 | close(pipe_fd[1]); 51 | wait(); 52 | s2e_kill_state(0, "program terminated"); 53 | } 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /Guest/wrapper/symstd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQLab/CRAX-lab/3584f87bb1c49843d29dee136fce57e30e484ea3/Guest/wrapper/symstd -------------------------------------------------------------------------------- /Guest/wrapper/symstd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main(int argc, char **argv) 9 | { 10 | if(argc < 2) { 11 | puts("Usage: ./symio program_path [args]"); 12 | return 0; 13 | } 14 | 15 | size_t len = strlen(argv[2]); 16 | char *buf = malloc(len+1); 17 | strcpy(buf, argv[2]); 18 | if(buf == NULL) 19 | { 20 | puts("allocation failed\n"); 21 | } 22 | 23 | if (len < 0) { 24 | puts("payload error"); 25 | return 0; 26 | } 27 | 28 | int pipe_fd[2]; 29 | pid_t pid; 30 | 31 | //s2e_disable_forking(); 32 | s2e_make_concolic(buf, len, "crax"); 33 | 34 | if(pipe(pipe_fd) < 0) { 35 | printf("pipe error\n"); 36 | exit(1); 37 | } 38 | 39 | write(pipe_fd[1], buf, len); 40 | 41 | char *args[argc - 1]; 42 | int i; 43 | for (i = 0; i < argc - 1; i++) 44 | args[i] = argv[i + 1]; 45 | args[i] = NULL; 46 | 47 | if(!(pid = fork())) { 48 | dup2(pipe_fd[0], 0); 49 | close(pipe_fd[0]); 50 | close(pipe_fd[1]); 51 | execve(args[0], args, NULL); 52 | } else { 53 | close(pipe_fd[0]); 54 | close(pipe_fd[1]); 55 | wait(); 56 | s2e_kill_state(0, "program terminated"); 57 | } 58 | free(buf); 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AIS3 CRAX lab 2 | 3 | [CRAX](https://github.com/SQLab/CRAX) 是 SQLab 所發展的 Automatic Exploit Generator (AEG),利用 symbolic execution 為基礎,對受測程式進行動態分析。 4 | 5 | ## 原理 6 | 在 symbolic execution 執行中 判斷 eip 是否可由 input 控制,當偵測到 eip 可控( eip tainted ),則將目前收集到的 path constraint(路徑限制式) 加上 shellcode constraint 以 SMT solver 嘗試去解可能的 input。 7 | 8 | 由於 symbolic execution 會探索程式執行的所有可能路徑,時間複雜度成指數成長,當受測程式規模大時會使執行效率較差。 9 | 10 | **CRAX** 採用的 symbolic execution engine 是基於 KLEE 更改來的 **S2E**。 11 | 12 | **S2E** 是 select symbolic execution 的縮寫,只對特定的程式區間做 symbolic execution,即 *concolic execution*,以一組隨機的輸入作為初始值開始執行。 13 | 14 | ## CRAX 架構 15 | 16 | Host OS(S2E) 執行 symbolic execution,使用 QEMU 建置 Guest OS 以測試位於各種不同環境上的程式。 17 | S2E 以 API 或允許使用者自訂的 op code(由 S2E 基於它自己的 QEMU 所定義的 machine code) 在 Host OS 和 Guest OS 之間溝通。 18 | 19 | ## CRAX lab 介紹 20 | --- 21 | Host OS 與 Guest OS 的帳密皆為 `ais3 / crax` 22 | 23 | --- 24 | 25 | ### Host OS (Ubuntu 12.04 64-bit) 26 | `ais3@ubuntu:` 27 | 28 | `~/crax/build` **CRAX** 的環境建置 29 | 30 | `~/crax/s2e` 由 [CRAX](https://github.com/SQLab/CRAX) 中下載的 source code,詳細編譯方式參考:https://s2e.epfl.ch/ 31 | 32 | `~/crax/img` 33 | 34 | 1. `crax.raw`:Guest OS image,已放置受測程式。 35 | 36 | 2. `crax.s2e`:S2E 需以 .s2e 為副檔名的 image 做 symbolic execution,其與 crax.raw 內容相同。 37 | 38 | 3. `crax.s2e.demo`:crax.s2e 的 snapshot(snapshot 取名為 demo 即會產生以 .demo 結尾的檔案)。S2E QEMU 開啟此 snapshot 並開始執行 symbolic execution。 39 | (參考:[The S2E VM Image Format](https://github.com/dslab-epfl/s2e/blob/master/docs/ImageInstallation.rst#id2)) 40 | 41 | 4. `crax.qcow2`:用來將 Host OS symbolic execution 後產生的 exploit 檔案傳入 Guest OS 進行 exploit 的 image。(由於 crax.raw 更動過後 crax.s2e 會毀壞,因此不能將 exploit 傳入 crax.raw) 42 | 43 | `~/crax/script` 44 | 45 | 1. `start.sh`:以 S2E mode 的 QEMU 開啟 Guest OS。 46 | 47 | 2. `exploit.sh`:symbolic execution 結束後將 exploit 檔案傳入 Guest OS。以 non-S2E mode 的 QEMU 開啟 Guest OS,並將 Host OS ssh 的 22 port 導至 Guest OS 的 2222 port。 48 | 49 | `~/crax/result`:存放 symbolic execution 結束後的過程紀錄與結果。每結束一次 symbolic execution 就會將最新的紀錄都存放於 `s2e-last` 中。 50 | 51 | ### Guest OS (Debian 32-bit) 52 | `ais@debian:` 53 | 54 | `~/sample`:lab1、2 受測程式與執行的 script。 55 | 56 | `~/easy_pwn`:lab3 受測程式與執行的 script。 57 | 58 | `~/wrapper`:在無法取得原始碼的情況下,以 wrapper 控制 input 為 symbolic variable。 59 | 60 | ## CRAX lab 實作 61 | 請開 AIS3_CRAX 資料夾先用 VMware 裝好 vm (只能用 VMware 開唷~) 62 | 63 | ### lab 1 64 | **lab 1** 將介紹利用 S2E 提供的 API 對程式 make symbolic 的流程 65 | [sample.c](https://github.com/SQLab/CRAX-lab/blob/master/sample/sample.c) 是一個很簡單的 buffer overflow 的小程式 66 | 其中第 12 行 `s2e_make_concolic` 將對某一段 buffer make symbolic 67 | 當 Guest OS 執行到第 12 行就會開始進行 symbolic execution,直到程式結束 68 | 本實驗將展示透過 CRAX 自動生成 exploit 69 | 70 | 1. 開啟 Host 後, 在 `ais@ubuntu:~/crax/result` 底下啟動 Guest 71 | * (Host) `start.sh crax.s2e` -- 以 S2E mode 的 QEMU 開啟 crax.s2e 的 demo snapshot。 72 | 73 | 2. 開啟 Guest 後,在 `ais3@debian:~/sample` 底下執行 `run.sh` 74 | * (Guest) `./run.sh` -- 編譯受測程式,輸入 0x1000 個 a 作為 concrete input 執行程式。 75 | 76 | 3. Host 上的 **CRAX** 會開始進行 symbolic execution 嘗試解出 exploit,exploit 會在 `~/crax/result/s2e-last` 底下 77 | * exploit 可能會不只一個,width 較長的 exploit 比較容易成功。 78 | * (Host) `cd s2e-last && ls exploit*` 79 | * _exploit-bfffe818.bin_ & _exploit-bffff819.bin_ 80 | 81 | 4. 啟動 Guest,並將 exploit 傳進 Guest 82 | * (Host) `exploit.sh crax.qcow2` 83 | * (Host 用另一個 terminal) 84 | * `~/crax/result/s2e-last$ scp -P2222 exploit-xxxxxxxx localhost:~/sample.exp` 85 | 86 | 5. 測試 payload 是不是能成功拿到 shell 87 | * (Guest) `sample/sample $(cat sample.exp)` 88 | 89 | ### lab 2 90 | **lab 2** 將介紹在沒辦法取得原始碼的情況下進行 symbolic execition 91 | [sample2.c](https://github.com/SQLab/CRAX-lab/blob/master/sample/sample2.c) 與 sample.c 基本上一模一樣,除了少 s2e_make_concolic 那一行 92 | 本實驗將透過 symbolic wrapper 對受測程式做 symbolic 93 | 94 | 1. 開啟 Host 後, 在 `ais@ubuntu:~/crax/result` 底下啟動 Guest 95 | * (Host) `start.sh crax.s2e` -- 以 S2E mode 的 QEMU 開啟 crax.s2e 的 demo snapshot。 96 | 97 | 2. 開啟 Guest 後,在 `ais3@debian:~/sample` 底下執行 `run2.sh` 98 | * (Guest) `./run2.sh` -- 以 wrapper 執行程式。 99 | 100 | 3. Host 上的 **CRAX** 會開始進行 symbolic execution 嘗試解出 exploit,exploit 會在 `~/crax/result/s2e-last` 底下 101 | * (Host) `cd s2e-last && ls exploit*` 102 | * _exploit-bfffe818.bin_ & _exploit-bffff819.bin_ 103 | 104 | 4. 啟動 Guest,並將 exploit 傳進 Guest 105 | * (Host) `exploit.sh crax.qcow2` 106 | * (Host 用另一個 terminal) 107 | * `~/crax/result/s2e-last$ scp -P2222 exploit-xxxxxxxx localhost:~/sample2.exp` 108 | 109 | 5. 測試 payload 是不是能成功拿到 shell 110 | * (Guest) `sample/sample2 $(cat sample2.exp)` 111 | 112 | ### lab 3 113 | [stage2](https://github.com/SQLab/CRAX-lab/blob/master/sample/stage2) 是 Defcon quals circa 2004 的題目 114 | 本實驗將使用 CRAX 自動生成 stage2 的 payload 115 | 116 | 1. 開啟 Host 後, 在 `ais@ubuntu:~/crax/result` 底下啟動 Guest 117 | * (Host) `start.sh crax.s2e` -- 以 S2E mode 的 QEMU 開啟 crax.s2e 的 demo snapshot。 118 | 119 | 2. 開啟 Guest 後,在 `ais3@debian:~/easy_pwn` 底下執行 `run.sh` 120 | * (Guest) `./run.sh` -- 以 wrapper 執行程式。 121 | 122 | 3. Host 上的 **CRAX** 會開始進行 symbolic execution 嘗試解出 exploit,exploit 會在 `~/crax/result/s2e-last` 底下 123 | * exploit 可能會不只一個,address 較低的 exploit 比較容易成功。 124 | * (Host) `cd s2e-last && ls exploit*` 125 | * _exploit-bfffede4.bin_ & _exploit-bffffde5.bin_ 126 | 127 | 4. 啟動 Guest,並將 exploit 傳進 Guest 128 | * (Host) `exploit.sh crax.qcow2` 129 | * (Host 用另一個 terminal) 130 | * `~/crax/result/s2e-last$ scp -P2222 exploit-xxxxxxxx localhost:~/stage2.exp` 131 | 132 | 5. 測試 payload 是不是能成功拿到 shell 133 | * (Guest) `easy_pwn/stage2 $(cat stage2.exp)` 134 | -------------------------------------------------------------------------------- /sample/sample.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void foo(char *a) 4 | { 5 | char b[40]; 6 | strcpy(b, a); 7 | } 8 | 9 | int main(int argc, char** argv) 10 | { 11 | char *a = argv[1]; 12 | s2e_make_concolic(a, 300, "crax"); 13 | foo(a); 14 | } 15 | -------------------------------------------------------------------------------- /sample/sample2.c: -------------------------------------------------------------------------------- 1 | 2 | void foo(char *a) 3 | { 4 | char b[40]; 5 | strcpy(b, a); 6 | } 7 | 8 | int main(int argc, char** argv) 9 | { 10 | char *a = argv[1]; 11 | foo(a); 12 | } 13 | -------------------------------------------------------------------------------- /sample/stage2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SQLab/CRAX-lab/3584f87bb1c49843d29dee136fce57e30e484ea3/sample/stage2 -------------------------------------------------------------------------------- /script/exploit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | QEMU=/home/ais3/crax/build/qemu-release/i386-softmmu/qemu-system-i386 4 | if [ -z $1 ]; then 5 | echo "Usage: exploit.sh image" 6 | else 7 | $QEMU -hda $S2EDIR/img/$1 -loadvm demo -redir tcp:2222::22 -monitor stdio 8 | fi 9 | -------------------------------------------------------------------------------- /script/raw_net.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | if [ -z $1 ]; then 3 | echo "Usage: raw.sh image [snapshot]" 4 | elif [ -z $2 ]; then 5 | /home/ais3/crax/build/qemu-release/i386-softmmu/qemu-system-i386 -hda $S2EDIR/img/$1 -redir tcp:2223::22 6 | else 7 | /home/ais3/crax/build/qemu-release/i386-softmmu/qemu-system-i386 -hda $S2EDIR/img/$1 -loadvm $2 -redir tcp:2223::22 8 | fi -------------------------------------------------------------------------------- /script/s2e.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | QEMU=/home/ais3/crax/build/qemu-release/i386-softmmu/qemu-system-i386 4 | if [ -z $1 ]; then 5 | echo "Usage: s2e.sh image [snapshot]" 6 | elif [ -z $2 ]; then 7 | $QEMU -hda $S2EDIR/img/$1 -net none 8 | else 9 | $QEMU -hda $S2EDIR/img/$1 -loadvm $2 -net none 10 | fi 11 | -------------------------------------------------------------------------------- /script/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | CRAX=/home/ais3/crax 4 | QEMU=/home/ais3/crax/build/qemu-release/i386-s2e-softmmu/qemu-system-i386 5 | if [ -z $1 ]; then 6 | echo "Usage: start.sh image" 7 | else 8 | $QEMU -hda $S2EDIR/img/$1 -s2e-config-file $CRAX/s2e/config.lua -loadvm demo -s2e-verbose -net none 9 | fi 10 | --------------------------------------------------------------------------------