Writeup Crackity | TFC CTF 2021 | Catégorie reverse
Unknown 2 | GrabCon CTF 2021
Fichier(s)
Nécessaires
- jd-gui
- Python3
Flag
TFCCTF{j4v4_0bfusc4t10n_1s_pr3tty_n0t_pr3tty}
Solution détaillée
La solution n’est pas très longue mais elle permet d’introduire le reverse de fichier .jar avec un exemple assez basique.
Nous avons donc un fichier java
à reverse pour trouver le Flag.
J’ai d’abord essayé d’exécuter le fichier mais il semble cassé, et je ne peux le lancer.
root@DESKTOP-HNQJECB: /c
➜ java crackity.jar
Error: Could not find or load main class crackity.jar
Caused by: java.lang.ClassNotFoundException: crackity.jar
Ouvrons donc avec jd-gui le fichier pour comprendre comment fonctionne le code :
Aïe … C’est laid ; Le code est obfusqué. J’ai donc cherché ce qu’il y avait de lisible et j’ai d’abord trouver ceci :
public static final String f4x82c624da = ("Nr" + (Math.log(3.0d) / 4.0d));
public static String IlLLIILIlIILLIllIIILLIlLILlLILLLLLIILIIlLIIIILlIlLlllLIIlLLllLlIlLLIIIIIlIllLlILILLLIILlLILIIllllLIlIlLLllIIILIllIllIllIlIIIIILlLILLLIIIILIILlLlIIIlLILlILllIlllIlLlILllllLlILIlllIlIlLILIlILILIlLLLIIlIlLlLlLlIIIlLILILIILLILLLLILIlLlILILLLIIILILIlLILllLIllILLLLlILlllLlIIlIILlLlILLlIllILlILIIlLlLLlIILllIIILlIIIlLlLlllLlLIIIILlIIILlLIlILLlILLLLLlIILIlLlllIIllLIILIILlLLlLLLllLLlLLLIIlIlllllIlLIILlIlLLLIlIllLLllILlLIILLlILLlLLIIlllIILIIllIlIlILlLILLILILIIIILlLIIlllllLlILIIIIlIlllILlIILLllLlLIIlIIIlILI(String paramString) {
char[] arrayOfChar = new char[paramString.length()];
for (byte b = 0; b < paramString.length(); b++)
arrayOfChar[b] = (char)(paramString.charAt(b) - IlLLI.charAt(b % IlLLI.length()));
return new String(arrayOfChar);
}
La fonction prend en paramètre une string. Allons donc chercher plus loin dans le code. Nous reviendrons sur ce code juste après.
Après quelques secondes :
On trouve ce type de string :
public static final String IlLLIILIlIILLIllIIILLIlLILlLILLLLLIILIIlLIIIILlIlLlllLIIlLLllLlIlLLIIIIIlIllLlILILLLIILlLILIIllllLIlIlLLllIIILIllIllIllIlIIIIILlLILLLIIIILIILlLlIIIlLILlILllIlllIlLlILllllLlILIlllIlIlLILIlILILIlLLLIIlIlLlLlLlIIIlLILILIILLILLLLILIlLlILILLLIIILILIlLILllLIllILLLLlILlllLlIIlIILlLlILLlIllILlILIIlLlLLlIILllIIILlIIIlLlLlllLlLIIIILlIIILlLIlILLlILLLLLlIILIlLlllIIllLIILIILlLLlLLLllLLlLLLIIlIlllllIlLIILlIlLLLIlIllLLllILlLIILLlILLlLLIIlllIILIIllIlIlILlLILLILILIIIILlLIIlllllLlILIIIIlIlllILlIILLllLlLIIlIIIlILI = «{`zg£}k
nswiy
w¼|¡¢«¨¥¦¨jy×;
Le padding du nom obfusqué de la fonction faisait qu’on ne les voyait pas tous de suite.
Un nouveau petit souci ce pose. On ne peut pas les récupérer en les copiant collant. Surement qu’il y a une sorte de sanitizing lors de la copie dans jd-gui .
Je vais donc utiliser un autre outil pour récupérer les strings et les placer dans un fichier texte :
Il présente les mêmes fonctionnalités que l’autre outils de décompilation.
Maintenant que nous le pouvons, récupérons les strings chiffrés :
allstring = [
'«{`zg£}k
nswiy
w¼|¡¢«¨¥¦¨jy×',
'¤Úai«m©
nidldìhªdz¢{a°¥¡
¦Éz',
'¿
§¤}udmµd`wª~±¨¥~xi¡¥ÀÛ
',
'¢¸sq}¯ i©db¬£k¨f~à_¥¤¨h§¤°f«¢©g©Âë',
'Ū°xie|hv£Ùt¨|¤ sf¢bclÃ`',
'»Ý
¬ª~¢t¤¡e®¯Ö{~e¢l
c®e¤¤¨ry}lwȸs',
'¶u
g¦j~xè¤
¨zgx«¦©yz¼Èe',
'¹¥¨|¨¨¤m§b|j¬¬j£âd_ig}j
y«¦¬dj¯w£Ê¡',
'Üf¬§ighiª¸guzd~|°¥¡ß',
'´ç
¢xn§¨~~w«ª¬«Ùwy¢jmr®~avgµ¥£',
'
ârg£eh§¤¯zhyh³Äa¦kd §¤do}¡wÈ',
'¶¨~¤px¢|¢gª±`di¬©»¿|fw}h«¡¬`¤æy',
'¤Úai«m©
nidldìhªdz¢{a°¥¡
¦Éz',
'»Ë¡~t~i§
tz
§ª~Üx lhfg}uy
±Õ',
'Åe¡¤}{q¦m`cmf®¤¨
j¦fa®}¬d²ã¤',
'³Å|«¢¯©|y¤£ubnÕg«£m¥fw©¨°¨¡ªh¹Àb',
'«{e©wf{sr¢c«¯à|i¯hwkpwÀÙ',
'µÈffs¦¡edpxØa¯}m{az¨nu®kxÜ',
'¥³aeo{c}
¢¦~kz©»Æha¦¢xuyz§|nß',
'¥Ü~~zxk¤§¦|oªeË¡ ¯¢id{Áç'
]
Enfin, nous allons utiliser python pour inverser le chiffrement.
La première chose importante que nous voyons tous de suite est qu’une string n’est pas obfusqué :
String f4x82c624da = ("Nr" + (Math.log(3.0d) / 4.0d));
Je l’ai exécuté en local et j’ai obtenu : "Nr0.27465307216702745"
Nous semblons avoir la clef maintenant . Analysons brièvement l’algorithme :
-
Création d’une string
char[] cArr = new char[str.length()];
-
Loop sur la longeur de la string d’entrée
for (int i = 0; i < str.length(); i++) { }
-
Ajout d’une lettre dans la string cArr
cArr[i] = (char) (str.charAt(i) - f4x82c624da.charAt(i % f4x82c624da.length()));
Cette lettre en question est la résultante de la soustraction entre l’index de lettre de la string chiffré avec l’index de la lettre de la clé trouvée plus haut.
Grâce à ceci, on peut écrire ce petit script python :
bigstr = "Nr0.27465307216702745"
def rev(input_):
final = ""
for i in range(len(input_)):
a = ord(input_[i])
b = ord(bigstr[i%len(bigstr)])
final += chr(a - b)
return final
allstring = [
'«{`zg£}k
nswiy
w¼|¡¢«¨¥¦¨jy×',
'¤Úai«m©
nidldìhªdz¢{a°¥¡
¦Éz',
'¿
§¤}udmµd`wª~±¨¥~xi¡¥ÀÛ
',
'¢¸sq}¯ i©db¬£k¨f~à_¥¤¨h§¤°f«¢©g©Âë',
'Ū°xie|hv£Ùt¨|¤ sf¢bclÃ`',
'»Ý
¬ª~¢t¤¡e®¯Ö{~e¢l
c®e¤¤¨ry}lwȸs',
'¶u
g¦j~xè¤
¨zgx«¦©yz¼Èe',
'¹¥¨|¨¨¤m§b|j¬¬j£âd_ig}j
y«¦¬dj¯w£Ê¡',
'Üf¬§ighiª¸guzd~|°¥¡ß',
'´ç
¢xn§¨~~w«ª¬«Ùwy¢jmr®~avgµ¥£',
'
ârg£eh§¤¯zhyh³Äa¦kd §¤do}¡wÈ',
'¶¨~¤px¢|¢gª±`di¬©»¿|fw}h«¡¬`¤æy',
'¤Úai«m©
nidldìhªdz¢{a°¥¡
¦Éz',
'»Ë¡~t~i§
tz
§ª~Üx lhfg}uy
±Õ',
'Åe¡¤}{q¦m`cmf®¤¨
j¦fa®}¬d²ã¤',
'³Å|«¢¯©|y¤£ubnÕg«£m¥fw©¨°¨¡ªh¹Àb',
'«{e©wf{sr¢c«¯à|i¯hwkpwÀÙ',
'µÈffs¦¡edpxØa¯}m{az¨nu®kxÜ',
'¥³aeo{c}
¢¦~kz©»Æha¦¢xuyz§|nß',
'¥Ü~~zxk¤§¦|oªeË¡ ¯¢id{Áç'
]
for string in allstring:
print(rev(string))
Celui-ci nous donne le flag une fois exécuté !!!