This challenge is second in a 3 part series ,the first one being reversing and the rest pwn. This writeup involves only the challenge favourite architecture flag1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
arch riscv baddr 0x10000 binsz 384184 bintype elf bits 64 canary false class ELF64 compiler GCC: (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0 crypto false endian little havecode true laddr 0x0 lang c linenum false lsyms false machine RISC V nx false os linux
A quick look in radare2 tells us that there’s no canary and NX is disabled , but the qemu we had was patched to allow only certain syscalls
+ switch (num) { + // syscall whitelist + case TARGET_NR_brk: + case TARGET_NR_uname: + case TARGET_NR_readlinkat: + case TARGET_NR_faccessat: + case TARGET_NR_openat2: + case TARGET_NR_openat: + case TARGET_NR_read: + case TARGET_NR_readv: + case TARGET_NR_write: + case TARGET_NR_writev: + case TARGET_NR_mmap: + case TARGET_NR_munmap: + case TARGET_NR_exit: + case TARGET_NR_exit_group: + case TARGET_NR_mprotect: + ret = do_syscall1(cpu_env, num, arg1, arg2, arg3, arg4, + arg5, arg6, arg7, arg8); + break; + default: + printf("[!] %d bad system call\n", num); + ret = -1; + break; + }
Debugging
After spending hours finding a way to debug,I came across this toolchain for RISC-V development which includes a gdb for RISC-V , pretty neat!
Reversing the binary isn’t necessary for this part atleast. Triggering the bug is pretty straightforward, an input having length greater than 288 bytes gets you pc control (Instruction Pointer). Since the qemu user doesn’t have aslr enabled we dont have to worry about leaking stack
Shellcode
Since there was a large overflow and with NX being disabled ,shellcode was the way to go . unlike x86 , in RISC-V instructions are fixed in size ;32 or 16 bits to be precise. This needs to be taken into account while scripting the exploit.
The patched qemu disables execve syscall,but we do have openatread and write which is perfect , now we can construct an ORW shellcode to read the flag
This was my first time coding assembly is RISC-V, after going through multiple manuals about the instruction-set I managed to write a half decent assembler code. To make a Syscall we make use of the ecall instruction and set the registers a0-a7 accordingly. Also remember , the syscall numbers for RISC-V are quite different from x86 refer syscall table
pwn-solo@m4ch1n3:~/ctf/favourite_architecture/share$ python3 exploit.py local [+] Starting local process './qemu-riscv64': pid 19543 [*] Switching to interactive mode flag{test_flag} [*] Got EOF while reading in interactive $ [*] Interrupted