TryHackMe Writeup：Grep

# はじめに
本記事はTryHackMeのWriteupです。

Roomは[Grep](https://tryhackme.com/r/room/greprtp)、Difficulty（難易度）はEasyです。

このRoomでは、偵察及びOSINTスキルについて学ぶことができます。

## Grep
架空のスタートアップ企業であるSuperSecure Corpをハッキングします。

このタスクを解決するためには、OSINT技術を使用して公開されているソースから情報を収集し、Webアプリケーションの潜在的な脆弱性を悪用します。

まずは、ポートスキャンから行います。

### ポートスキャン
ここでは事前に用意したシェルを介してポートスキャンを実行しています。

```console
##################
# Port scan tool #
##################
 *Detailed scan :1
 *Full scan     :2


 ***Select scanning method by number***
1
Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-05-27 20:54 JST
Nmap scan report for 10.10.161.58
Host is up (0.27s latency).

PORT      STATE SERVICE  VERSION
22/tcp    open  ssh      OpenSSH 8.2p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 42:d1:ce:4c:90:af:6c:2e:0b:99:1b:a2:43:89:9f:99 (RSA)
|   256 ba:8f:0d:8a:50:34:7b:34:85:db:0e:bb:0f:86:65:b7 (ECDSA)
|_  256 dd:12:56:5a:89:96:c3:cd:44:ad:d5:d2:10:1d:40:29 (ED25519)
80/tcp    open  http     Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Apache2 Ubuntu Default Page: It works
443/tcp   open  ssl/http Apache httpd 2.4.41
|_http-server-header: Apache/2.4.41 (Ubuntu)
| tls-alpn: 
|_  http/1.1
|_http-title: 400 Bad Request
| ssl-cert: Subject: commonName=grep.thm/organizationName=SearchME/stateOrProvinceName=Some-State/countryName=US
| Not valid before: 2023-06-14T13:03:09
|_Not valid after:  2024-06-13T13:03:09
|_ssl-date: TLS randomness does not represent time
51337/tcp open  http     Apache httpd 2.4.41
|_http-title: 400 Bad Request
|_http-server-header: Apache/2.4.41 (Ubuntu)
Service Info: Host: ip-10-10-161-58.eu-west-1.compute.internal; 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 51.12 seconds
Scan completed
```

ポートスキャンの結果を基に調査を行います。

### SearchME!
上記ポートスキャンの結果を踏まえて、80番と443番ポートでWebサーバが稼働していることが分かります。

80番ポートでは特に何もなかったため、443番ポートを調べると証明書のSubject情報からgrep.thmのドメインが確認できます。hostsファイルに追記してブラウザからアクセスすると、以下の様な画面が表示されます。

![スクリーンショット 2024-05-27 21.10.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/ff30af67-ed3a-e7b4-4eb3-0bfdc9d22b13.png)

Register画面にアクセスしてユーザー登録を行います。

![スクリーンショット 2024-05-27 21.13.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/f299229f-3e29-d11b-3300-1b8a22b55cc2.png)

試しに情報を入力してRegisterボタンを押すと、以下の様な「Invalid or Expired API key」のメッセージが出力されて登録できません。

![スクリーンショット 2024-05-27 21.16.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/c89dc69b-b253-f1be-450a-c8460c8d51dd.png)

上記メッセージを踏まえて、Register画面で実行されている`register.php`のコードを調査します。調べた結果、Registerボタンを押すと、JavaScriptとして読み込まれている`register.js`の`register()`関数が実行されていることが分かります。

```php
<input type="button" value="Register" onclick="register()" class="btn btn-primary">
```

`register.js`の`register()`関数を確認します。

```javascript
function register() {
    var username = document.getElementById('username').value;
    var password = document.getElementById('password').value;
    var email = document.getElementById('email').value;
    var name = document.getElementById('name').value;
    fetch('../../api/register.php', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Thm-Api-Key': 'e8d25b4208b80008a9e15c8698640e85'
      },
      body: JSON.stringify({
        username: username,
        password: password,
        email: email,
        name: name,
      }),
    })
    .then(response => response.json())
    .then(data => {
      if (data.error) {
        alert(data.error);
      } else {
        alert('Registration successful! Please login.');
        window.location.href = 'login.php';
      }
    })
    .catch((error) => {
      console.error('Error:', error);
    });
  }
  ```

上記コードを確認した結果、fetch関数の引数に設定された`register.php`に対するリクエストで指定している`X-Thm-Api-Key`が無効でした。

### OSINT
パブリックなソースからAPIキーを探すにあたって、OSINTを行います。

XでSuperSecure Corpらしきアカウントを発見しましたが、APIキーに繋がる様なポストは見当たりませんでした。

また、Googleで`site:github.com`を指定してSuperSecure Corpの単語で検索しても特にヒントは見つかりません。

引き続きGitHubで調べた結果、以下の怪しいリポジトリが見つかりました。

![スクリーンショット 2024-05-27 21.37.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/773589b2-4932-f24c-0db0-044d3f2564a3.png)

コミット履歴を確認すると、APIキーを発見しました。

![スクリーンショット 2024-05-27 21.37.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/51a23348-4aba-a0c7-052e-ef09152e885b.png)

Burp Suiteを使用して、上記APIキーを用いたリクエストを発行します。ユーザー登録後にログインすると、最初のフラグが取得できます。

### リバースシェル
次のフラグを取得するためには、マシンへの侵入が必要になると思われるため、gobusterを用いて列挙を行います。

`$ gobuster dir -u https://grep.thm/public/html/ -w /usr/share/wordlists/dirb/common.txt -k -x php`

```console
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     https://grep.thm/public/html/
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirb/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Extensions:              php
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.php                 (Status: 403) [Size: 274]
/.hta                 (Status: 403) [Size: 274]
/.hta.php             (Status: 403) [Size: 274]
/.htaccess            (Status: 403) [Size: 274]
/.htpasswd            (Status: 403) [Size: 274]
/.htaccess.php        (Status: 403) [Size: 274]
/.htpasswd.php        (Status: 403) [Size: 274]
/admin.php            (Status: 403) [Size: 0]
/admin.php            (Status: 403) [Size: 0]
/dashboard.php        (Status: 403) [Size: 0]
/index.php            (Status: 200) [Size: 1471]
/index.php            (Status: 200) [Size: 1471]
/login.php            (Status: 200) [Size: 1981]
/logout.php           (Status: 200) [Size: 154]
/register.php         (Status: 200) [Size: 2346]
/upload.php           (Status: 403) [Size: 0]
Progress: 9228 / 9230 (99.98%)
===============================================================
Finished
===============================================================
```

上記結果を踏まえて、`upload.php`にアクセスすると、以下の様なファイルアップロードの画面が表示されます。

![スクリーンショット 2024-05-28 21.28.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/39e762f4-446a-80fe-7426-620437ac0302.png)

試しにリバースシェルとして動作するphpファイルをアップロードすると、以下の様なエラーが出力されてアップロードできません。

![スクリーンショット 2024-05-28 21.30.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/32279877-ecce-137d-beb7-48bc94ed44fe.png)

先ほどのOSINTの結果からapiで使用している`upload.php`ファイルを確認すると、マジックバイトで判定していることが分かります。

```php
function checkMagicBytes($fileTmpPath, $validMagicBytes) {
    $fileMagicBytes = file_get_contents($fileTmpPath, false, null, 0, 4);
    return in_array(bin2hex($fileMagicBytes), $validMagicBytes);
}

$allowedExtensions = ['jpg', 'jpeg', 'png', 'bmp'];
$validMagicBytes = [
    'jpg' => 'ffd8ffe0', 
    'png' => '89504e47', 
    'bmp' => '424d'
];
```

用意したphpファイルについて、許容されている任意の画像ファイルのマジックバイトに変更することで、アップロードできます。

![スクリーンショット 2024-05-28 21.33.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/d203aaf7-f3c9-3ecd-bda1-d8b89d277752.png)

アップロードしたphpファイルは、api配下のuploadsディレクトリに格納されるため、リスナーを起動した状態でphpファイルにアクセスします。

![スクリーンショット 2024-05-28 21.35.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/acd59832-c888-c1f7-382d-076504d48faf.png)

リバースシェルを取得しました。

```console
listening on [any] 4444 ...
connect to [Your IP address] from (UNKNOWN) [10.10.27.59] 47822
Linux ip-10-10-27-59 5.15.0-1038-aws #43~20.04.1-Ubuntu SMP Fri Jun 2 17:10:57 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
 12:36:44 up 31 min,  0 users,  load average: 0.00, 0.00, 0.01
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ 
```

### 調査
残りのフラグを探すため、探索します。

`/var/www/`配下のディレクトリを見ると、怪しい`backup`ディレクトリを発見しました。

```console
www-data@ip-10-10-27-59:/$ ll /var/www/
total 40
drwxr-xr-x 2 ubuntu www-data 4096 Jun 14  2023 backup
-rw-r--r-- 1 root   root     1131 Jun 14  2023 certificate.crt
-rw-r--r-- 1 root   root      960 Jun  2  2023 certificate.csr
drwxr-xr-x 2 ubuntu www-data 4096 Jun 14  2023 default_html
drwxr-xr-x 4 ubuntu www-data 4096 Jun  7  2023 html
-rw-r--r-- 1 root   root     1208 Jun 14  2023 leak_certificate.crt
-rw-r--r-- 1 root   root     1001 Jun 14  2023 leak_certificate.csr
drwxr-xr-x 2 ubuntu www-data 4096 Jun 14  2023 leakchecker
-rw------- 1 root   root     1874 Jun  2  2023 private.key
-rw------- 1 root   root     1704 Jun 14  2023 private_unencrypted.key
```

`backup`ディレクトリ配下を確認すると、`users.sql`ファイルが確認できます。

```console
www-data@ip-10-10-27-59:/$ ll /var/www/backup/
total 4
-rw-rw-r-- 1 ubuntu ubuntu 1888 Jun 14  2023 users.sql
```

`users.sql`ファイルを参照すると、「admin」ユーザーのメールアドレスが確認できました。

```sql
INSERT INTO `users` (`id`, `username`, `password`, `email`, `name`, `role`) VALUES
(1, 'test', '$2y$10$dE6VAdZJCN4repNAFdsO2ePDr3StRdOhUJ1O/41XVQg91qBEBQU3G', 'test@grep.thm', 'Test User', 'user'),
(2, 'admin', '$2y$10$3V62f66VxzdTzqXF4WHJI.Mpgcaj3WxwYsh7YDPyv1xIPss4qCT9C', '******************************', 'Admin User', 'admin');
```

引き続き調査を行ない`/var/www/leakchecker/`ディレクトリを確認しましたが、権限上見ることはできません。

```console
www-data@ip-10-10-27-59:/$ ll /var/www/leakchecker/
total 8
-r-------- 1 ubuntu ubuntu  440 Jun 14  2023 check_email.php
-r-------- 1 ubuntu ubuntu 1243 Jun  2  2023 index.php
```

ポートスキャンの結果を振り返ると、51337番ポートが利用されていたため、hostsファイルを編集してアクセスすると、電子メールを入力して漏洩の可能性をチェックするアプリケーションを発見しました。

![スクリーンショット 2024-05-28 22.03.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/cbabe0be-c8c3-17b4-5cf6-e302063648c1.png)

上記で取得した「admin」ユーザーのメールアドレスを入力すると、フラグが取得できます。

![スクリーンショット 2024-05-28 22.03.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221759/86150bb8-8ad0-7df3-f9ea-b2fcb0845c5d.png)

# おわりに
OSINTの検索スキルを養うことができる面白いルームでした。