Unknown 2 | GrabCon CTF 2021

Fichier(s)

Nécessaires

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 pas le lancer.

bash
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 :

Alt text

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 trouvé ceci :

Java
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 :

Java
 public static final String IlLLIILIlIILLIllIIILLIlLILlLILLLLLIILIIlLIIIILlIlLlllLIIlLLllLlIlLLIIIIIlIllLlILILLLIILlLILIIllllLIlIlLLllIIILIllIllIllIlIIIIILlLILLLIIIILIILlLlIIIlLILlILllIlllIlLlILllllLlILIlllIlIlLILIlILILIlLLLIIlIlLlLlLlIIIlLILILIILLILLLLILIlLlILILLLIIILILIlLILllLIllILLLLlILlllLlIIlIILlLlILLlIllILlILIIlLlLLlIILllIIILlIIIlLlLlllLlLIIIILlIIILlLIlILLlILLLLLlIILIlLlllIIllLIILIILlLLlLLLllLLlLLLIIlIlllllIlLIILlIlLLLIlIllLLllILlLIILLlILLlLLIIlllIILIIllIlIlILlLILLILILIIIILlLIIlllllLlILIIIIlIlllILlIILLllLlLIIlIIIlILI = „«{zg£}k…nswši–y†…wƒ¼|‘€¡˜¢«¨¥‚“›¦¨jy–ט;

Le padding du nom obfusqué de la fonction faisait qu’on ne les voyait pas tous de suite.

Un nouveau petit souci se pose. On ne peut pas les récupérer en les copiant collant. Sûrement 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 :

Jdax

Il présente les mêmes fonctionnalités que l’autre outil de décompilation.

Maintenant que nous le pouvons, récupérons les strings chiffrés :

python
allstring = [
'„«{`›zg£}k…nswši–y†…wƒ¼|‘€¡˜¢«¨¥‚“›¦¨jy–ט',
'¤Úšai›«m©…nŒ€id”ldŒ‘ì’”hŠªŸdz¢{a°¥¡—…¦˜Éz',
'„¿…ƒ§¤ˆ—š‚}™udˆ™››ŽmŽ™µd`Ž–wª~„±¨¥~ˆxƒi¡¥Àۅ',
'¢¸sq†}¯ i©d–b“œ¬£•k¨f~à_¥–¤¨h§¤°‘Ÿf«¢©g©Âë­',
'„Å—†ª°‰xiœ†e|œh•v†£›‚Ùt„¨|¤žŸ › œsf¢bcl‡ƒšÃ`',
'»Ý…š„„¬ª~—™¢t¤¡že®­†¯Ö{~eš¢l…c®e¤¤¨ry}lwȸs',
'š¶•u†‘…Žœˆgš¦˜j~‚„Šx„褗…¨œz–•gx«¦©y†ˆz­ž¼Èe',
'¹¥’¨|¨¨¤mš‡§b|j˜¬ƒ¬j£âd_›ig}j…y«œ¦¬dj¯w‡£Ê¡',
'“Üf–„¬§‹†i‡ghiƒŽ—ª˜¸gu—ˆzd~­Š|‹°„¥ˆ¡‡ßŸ',
'´ç‚•…¢xŠn§¨~~w«ªƒ¬ˆ«•Ùwy–¢jmš•r®€Š~Ša†Žvgµ¥£',
'…ârg‡£eh§€¤¯˜zhІ˜y‰h³Ä†a¦kd §•¤ŸŠdŠo}†¡w“È‚',
'¶¨~¤›px¢ƒ|¢g™ª±`di¬©»¿†’ƒ|‚f„w}h«¡¬`¤™ŒŸæy',
'¤Úšai›«m©…nŒ€id”ldŒ‘ì’”hŠªŸdz¢{a°¥¡—…¦˜Éz',
'»Ë¡~t~i‹§‰š…t†z…§ªƒ~ƒÜx šlhfg}uy…œŽ…––˜‹ž±Õ',
'’Åe¡¤™‚}{q†¦šm`cmf®¤¨€…j›¦†fƒa®‚ˆ‹}€¬œd–²ã¤',
'³Å†|“«¢œ¯©ƒŠ|y¤£ubŸŠn”Õg«£m‰¥fw©Œ¨°†¨¡ªh¹Àb',
'„«{e©Š•wf{˜sr¢šc›«‹¯à|œi¯h„Ž“wkpw€„ŠÀٜ',
'µÈf›”‰™†ŽfˆœsŸ¦¡edp™x›Øa‡“¯š}m{az‡¨nu®kx€Üˆ',
'¥³ae–o{‚ƒ€c™}…‰¢¦~kz©»Æha¦‰¢x€u”yzž‰Š§–€|nß',
'¥Ü˜~~z‰xk‰¤§¦|˜o€šžªe‘Ë¡› ‡Š¯¢i€‡dŒ™{ŠÁçš'
]

Enfin, nous allons utiliser python pour inverser le chiffrement.

La première chose importante que nous voyons tout de suite est qu’une string n’est pas obfusquée :

Java
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
Java
char[] cArr = new char[str.length()];
  • Loop sur la longueur de la string d’entrée
Java
for (int i = 0; i < str.length(); i++) { }
  • Ajout d’une lettre dans la string cArr
Java
 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ée avec l’index de la lettre de la clé trouvée plus haut.

Grâce à ceci, on peut écrire ce petit script python :

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…nswši–y†…wƒ¼|‘€¡˜¢«¨¥‚“›¦¨jy–ט',
'¤Úšai›«m©…nŒ€id”ldŒ‘ì’”hŠªŸdz¢{a°¥¡—…¦˜Éz',
'„¿…ƒ§¤ˆ—š‚}™udˆ™››ŽmŽ™µd`Ž–wª~„±¨¥~ˆxƒi¡¥Àۅ',
'¢¸sq†}¯ i©d–b“œ¬£•k¨f~à_¥–¤¨h§¤°‘Ÿf«¢©g©Âë­',
'„Å—†ª°‰xiœ†e|œh•v†£›‚Ùt„¨|¤žŸ › œsf¢bcl‡ƒšÃ`',
'»Ý…š„„¬ª~—™¢t¤¡že®­†¯Ö{~eš¢l…c®e¤¤¨ry}lwȸs',
'š¶•u†‘…Žœˆgš¦˜j~‚„Šx„褗…¨œz–•gx«¦©y†ˆz­ž¼Èe',
'¹¥’¨|¨¨¤mš‡§b|j˜¬ƒ¬j£âd_›ig}j…y«œ¦¬dj¯w‡£Ê¡',
'“Üf–„¬§‹†i‡ghiƒŽ—ª˜¸gu—ˆzd~­Š|‹°„¥ˆ¡‡ßŸ',
'´ç‚•…¢xŠn§¨~~w«ªƒ¬ˆ«•Ùwy–¢jmš•r®€Š~Ša†Žvgµ¥£',
'…ârg‡£eh§€¤¯˜zhІ˜y‰h³Ä†a¦kd §•¤ŸŠdŠo}†¡w“È‚',
'¶¨~¤›px¢ƒ|¢g™ª±`di¬©»¿†’ƒ|‚f„w}h«¡¬`¤™ŒŸæy',
'¤Úšai›«m©…nŒ€id”ldŒ‘ì’”hŠªŸdz¢{a°¥¡—…¦˜Éz',
'»Ë¡~t~i‹§‰š…t†z…§ªƒ~ƒÜx šlhfg}uy…œŽ…––˜‹ž±Õ',
'’Åe¡¤™‚}{q†¦šm`cmf®¤¨€…j›¦†fƒa®‚ˆ‹}€¬œd–²ã¤',
'³Å†|“«¢œ¯©ƒŠ|y¤£ubŸŠn”Õg«£m‰¥fw©Œ¨°†¨¡ªh¹Àb',
'„«{e©Š•wf{˜sr¢šc›«‹¯à|œi¯h„Ž“wkpw€„ŠÀٜ',
'µÈf›”‰™†ŽfˆœsŸ¦¡edp™x›Øa‡“¯š}m{az‡¨nu®kx€Üˆ',
'¥³ae–o{‚ƒ€c™}…‰¢¦~kz©»Æha¦‰¢x€u”yzž‰Š§–€|nß',
'¥Ü˜~~z‰xk‰¤§¦|˜o€šžªe‘Ë¡› ‡Š¯¢i€‡dŒ™{ŠÁçš'
]

for string in allstring:
  print(rev(string))

Celui-ci nous donne le flag une fois exécuté !!!

Alt text