15 minutes
Writeup On1on | Tsj 2022 | Catégorie reverse | [Vozec/FR]
Fichier(s)
Nécessaires
- Dnspy
- Windows
- ExtremeDumper
Flag
NOT FOUND
Description
TSJ's PC is contaminated by malware again! Luckily, TSJ's hacker friends figured out that the malware was nothing more than shenanigans. To be more specific, it seems that the executable is wrapped with layers and layers of onion-like junk files. Can you help TSJ figure out what the malware is doing?
NOTE: on10n.exe is not a real malware. So don't worry :)
Hint
1 | (.exe (.cs (.docm (.vb (.ps1 (.bin (.pdf (.js))))))))
Solution détaillée
Ce challenge est très long car il est décomposé en plusieurs étapes caractéristiques .
-
Etape1
Ouvrons le binaire sur ghidra :
On voit plusieurs choses intéressantes à l’importation :
- Une compilation via Visual Studio
- Une Destination vers Windows
- Un Fichier .pdb et un nom original avec l’extension .dll
Cela ressemble à
un programme C#
avec .NetCoreCela est confirmé par l’analyse de ghidra , en effet celui si n’arrive pas à retrouver une arborescence propre contrairement aux fichiers C par exemple (dans la plupart des cas)
On sait aussi que l’on peut coder en C# avec deux packages microsoft différents:
- .NetFramework
- .NetCore
NetCore est plus récente mais elle est plus dur à reverse malheureusement pour nous. La différence majeure qui nous intéresse est que .NetFramework compile le code directement dans un fichier
.exe
. Tandis que .NetCore compile le code dans une Dll et compile un seconde code microsoft en C qui appelle cette DllCette nuance est a notée pour la suite.
Regardons ce que nous donnes DnSpy et DetectItEasy:
On observe que le fichier est reconnu comme compilé en C et DnSpy ne décompile rien du tout. Le fichier semble packé.
Pour rappel , voici un schéma du fonctionnement d’un exécutable packé
Ouvrons l’exécutable et regardons-en Runtime les Dlls qui sont chargés grâce à ExtremeDumper.
On voit 5 Dlls drops dans le dossier temporaire. On est donc bien sûr que c’est un outils
codé en C# .net
Toujours avec ExtremeDumper , un peut Dump le process depuis la mémoire . (‘Click Droit’ -> ‘Dump Selected Process’)
On obtient :
On à toutes les Dll .Net packé qui étaient l’exécutable mais **surtout ; la fameuse dll évoqué précédemment qui contient tous le code C# !!! **
Analysons on10n.dll
On obtient les 2 fonctions si dessous :
private void MainWindow_Loaded(object sender, RoutedEventArgs e) { IPAddress[] hostAddresses = Dns.GetHostAddresses(Dns.GetHostName()); uint seed = 0U; bool flag = false; foreach (IPAddress ipaddress in hostAddresses) { if (ipaddress.AddressFamily == AddressFamily.InterNetwork) { uint num = BitConverter.ToUInt32(ipaddress.GetAddressBytes(), 0); uint num2 = num; List<uint> list = new List<uint>(); List<uint> list2 = new List<uint>(); uint num3 = 2U; while (num > 1U) { if (num % num3 == 0U) { uint num4 = 0U; while (num % num3 == 0U) { num /= num3; num4 += 1U; } list.Add(num3); list2.Add(num4); } num3 += 1U; } if (this.sameFactor(list, list2)) { seed = num2; flag = true; break; } } } if (flag) { MessageBox.Show("OK", "on10n", MessageBoxButton.OK); Random random = new Random((int)seed); byte[] nantouPoliceOfficeBureau = on10n.Properties.Resources.NantouPoliceOfficeBureau; byte[] array2 = new byte[124814]; for (int j = 0; j < 124814; j++) { array2[j] = (byte)random.Next(0, 256); byte[] array3 = array2; int num5 = j; array3[num5] ^= nantouPoliceOfficeBureau[j]; } return; } MessageBox.Show("Nope", "on10n", MessageBoxButton.OK); }
et
private bool sameFactor(List<uint> factors, List<uint> exponents) { uint[] array = new uint[] { 2U, 5U, 3371U, 30347U }; uint[] array2 = new uint[] { 1U, 1U, 1U, 1U }; if (factors.Count != 4 || exponents.Count != 4) { return false; } for (int i = 0; i < 4; i++) { if (factors[i] != array[i] || exponents[i] != array2[i]) { return false; } } return true; }
-
Analyse
Le script récupère les adresses ip et les convertis en INT . Ce INT est passé dans un algorithme qui en sort 2 listes. Ces 2 listes sont comparés avec des listes de référence :
[2,5,3371,30347]
[1,1,1,1]
Enfin ; si la clé (INT) est valide , le programme seed un objet random avec cette clé et génère des nombres pseudo-aléatoirement afin de les xor , byte par byte avec un fichier du nom de NantouPoliceOfficeBureau .
Cherchons cette clé pour retrouver le fichier NantouPoliceOfficeBureau décodé !
-
Méthode 1
Tentons de bruteforce les ips :
public async static Task MainAsync()
{
int nbthread = 0;
all = possibilities();
Thread counter = new Thread(count);
counter.Start();
for (int k = 0; k < 1; k++)
{
new Thread((ThreadStart)(async () =>
{
nbthread += 1;
while (all.Count > 0)
{
await semaphoreSlim.WaitAsync();
var ip = all[new Random().Next(0, all.Count - 1)];
all.Remove(ip);
semaphoreSlim.Release();
await Test(ip);
}
nbthread -= 1;
}))
{
IsBackground = true
}.Start();
}
while (all.Count > 0 || nbthread != 0)
{
await Task.Delay(5000);
}
Console.WriteLine("Ended !");
Console.WriteLine();
Console.ReadLine();
}
public static List<List<int>> possibilities()
{
List<List<int>> all = new List<List<int>>();
for(int i = 0; i < 255; i++)
{
for (int j = 0; j < 255; j++)
{
List<int> possible = new List<int>();
possible.Add(192);
possible.Add(168);
possible.Add(i);
possible.Add(j);
all.Add(possible);
}
}
return all;
}
public static async Task Test(List<int> ip)
{
var a1 = ip[0];
var a2 = ip[1];
var a3 = ip[2];
var a4 = ip[3];
byte[] all_bytes = { (byte)a1, (byte)a2, (byte)a3, (byte)a4 };
uint num = BitConverter.ToUInt32(all_bytes, 0);
Console.ForegroundColor = ConsoleColor.White;
var res = encrypt(num);
var res2 = rev(num).ToString();
Console.WriteLine("Test ing: " + res2 + " | Result: ".PadLeft(40-("Test ing: "+ res2).Length, ' ') + res);
if (res.Contains("[1 1 1 1 ]") || res.Contains("[2 5 3371 30347 ]"))
{
Console.WriteLine("##########################################");
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine(res);
Console.WriteLine(rev(num).ToString());
Console.ReadLine();
Console.WriteLine("##########################################");
File.WriteAllText("found.txt", rev(num).ToString());
}
}
public static string rev(uint num)
{
return String.Join(" ", BitConverter.GetBytes(num));
}
private static bool sameFactor(List<uint> factors, List<uint> exponents)
{
uint[] array = new uint[]
{
2U,
5U,
3371U,
30347U
};
uint[] array2 = new uint[]
{
1U,
1U,
1U,
1U
};
if (factors.Count != 4 || exponents.Count != 4)
{
return false;
}
for (int i = 0; i < 4; i++)
{
if (factors[i] != array[i] || exponents[i] != array2[i])
{
return false;
}
}
return true;
}
public static string encrypt(uint input)
{
uint seed = 0U;
bool flag = false;
uint num2 = input;
List<uint> list = new List<uint>();
List<uint> list2 = new List<uint>();
uint num3 = 2U;
while (input > 1U)
{
if (input % num3 == 0U)
{
uint num4 = 0U;
while (input % num3 == 0U)
{
input /= num3;
num4 += 1U;
}
list.Add(num3);
list2.Add(num4);
}
num3 += 1U;
}
if (sameFactor(list, list2))
{
seed = num2;
flag = true;
Console.WriteLine("Seed FOUND !!!");
Console.WriteLine(input.ToString());
Console.ReadLine();
Console.ReadLine();
Console.ReadLine();
Console.ReadLine();
}
var res = "[";
for (int i = 0; i < list.Count; i++)
{
res += list[i].ToString() + " ";
}
res += "] ";
var res2 = " [";
for (int j = 0; j < list2.Count; j++)
{
res2 += list2[j].ToString() + " ";
}
res2 += "]";
res += res2.PadLeft(40 - (res).Length, ' ');
return res;
}
Voici le résultat :
L’idée était bonne mais malheureusement , on ne peut pas bruteforce , l’ip n’est pas privé donc l’ip ne commence pas par 192.168
-
Méthode 2
Nous allons inverser le processus afin de trouver la clé valide ; à partir des 2 listes.
D’abord , j’ai recoder l’algorithme en
python
pour plus de facilité :def cipher(input_): seed = 0 flag = False num2 = input_ list1 = [] list2 = [] num3 = 2 while input_ > 1: if(input_ % num3 == 0): num4 = 0 while(input_ % num3 == 0): input_ /= num3; num4 += 1 list1.append(num3) list2.append(num4) num3 += 1 return list1,list2 key = 3371 * 30347 # == 1022997370 list1,list2 = cipher(key) if(list1 == [2,5,3371,30347] and list2==[1,1,1,1]): print(f'Found ! {key}') else: print(f'Invalid ... {list1,list2}')
On voit que le script cherche les facteurs multiplicateur de la clé , on trouve :
key= 3371 * 30347 #1022997370
On a enfin la clé ! On sauvegarde le fichier à xor NantouPoliceOfficeBureau depuis DnSpy
J’éxécute ce code :
public async static Task Xor() { int code = 1022997370; Random random = new Random((int)code); byte[] nantouPoliceOfficeBureau = File.ReadAllBytes("NantouPoliceOfficeBureau"); byte[] array2 = new byte[124814]; for (int j = 0; j < 124814; j++) { array2[j] = (byte)random.Next(0, 256); array2[j] ^= nantouPoliceOfficeBureau[j]; } try { using (var fs = new FileStream("output.docm", FileMode.Create, FileAccess.Write)) { fs.Write(array2, 0, array2.Length); } } catch (Exception ex) { Console.WriteLine("Exception caught in process: {0}", ex); } File.WriteAllBytes("output.docm", array2); }
Enfin ! Nous avons finis l’étape 1. Nous avons un document output.docm valide
Voici le projet final : on10n Project
-
Etape2
On obtient donc un fichier .docm , On suppose donc que le fichier contient une macro VBA à analyser ! Le fichier contient des nombres sur plus de 50 pages … BIZARRE.
Ouvrons les macros du document, on trouve :
Sub AutoOpen()
ibnhEErDWpGoUub
End Sub
Function ibnhEErDWpGoUub()
Dim RkQlPERVCJMmC As String
Dim WKKYbcDtyyJZavE As Long
RkQlPERVCJMmC = ActiveDocument.Name
Dim MxJgtSaOgVVjlz((2 Xor 5)) As String
MxJgtSaOgVVjlz(0) = TEUaYEHeQLSK(Array(((24 + 6) Xor (40 + 35)), ((75 + 7) Xor ((264 - 74) + (54 - 25))), (6 + 47), ((48 - 18) + 12)), Array(((45 - 15) + 72), ((122 + (34 - 15)) Xor 66), (((21 - 2) + 2) Xor 97), ((0 + (0 - 0)) Xor (0 + 105))))
MxJgtSaOgVVjlz(1) = TEUaYEHeQLSK(Array(98, 19, 2, ((42 - 0) Xor (47 + (39 - 9)))), Array(84, ((31 - 3) + 11), 64, 34))
MxJgtSaOgVVjlz(2) = TEUaYEHeQLSK(Array(((73 - 27) Xor 134), (16 Xor (148 - 48)), (((17 - 4) + (83 - 34)) Xor 85), (6 + 16)), Array(238, (73 - 4), (41 + (8 - 2)), ((43 - 18) Xor (95 - 38))))
MxJgtSaOgVVjlz((3 - 0)) = TEUaYEHeQLSK(Array((260 - 102), ((8 + 1) Xor (14 + (70 - 8))), 91), Array((82 Xor ((336 - 103) + 16)), (2 + 1), (16 Xor 126)))
MxJgtSaOgVVjlz((0 Xor (7 - 3))) = TEUaYEHeQLSK(Array((39 Xor 165), (24 - 9), (124 - 46), 200), Array(((26 + 149) Xor 108), ((78 - 31) Xor (11 + 7)), 127, (211 Xor (4 + 41))))
MxJgtSaOgVVjlz((3 + 2)) = TEUaYEHeQLSK(Array((214 - 32), ((29 - 0) + (54 - 22)), 88, (46 Xor ((19 - 0) + 83))), Array(130, 9, (76 Xor 39), (((8 - 4) + 1) Xor (3 + 11))))
MxJgtSaOgVVjlz(((2 - 1) Xor 7)) = TEUaYEHeQLSK(Array((70 Xor 63), (43 Xor 94), (122 + (42 - 5)), ((106 - 1) + 11)), Array(((47 - 10) + 21), (32 + (55 - 18)), ((66 - 17) + 173), (80 - 4)))
For i = 1 To (13 - 6)
Dim RvvwCstwOcTmn
RvvwCstwOcTmn = Mid(RkQlPERVCJMmC, 3 * (i - ((0 + 0) Xor (1 - 0))) + 1, (6 - 3))
If bTkfDsyoeYKIp(RvvwCstwOcTmn) <> MxJgtSaOgVVjlz(i - ((0 - 0) Xor (1 + 0))) Then
MsgBox TEUaYEHeQLSK(Array((183 Xor (10 + 3)), ((128 - 57) + 76), 128, 48), Array(244, (74 Xor 182), (154 Xor (98 + 8)), 85))
Exit Function
Else
For JLiFGdziyvzxk = (0 + 1) To (1 + 2)
WKKYbcDtyyJZavE = WKKYbcDtyyJZavE + Asc(Mid(RvvwCstwOcTmn, JLiFGdziyvzxk, 1))
Next JLiFGdziyvzxk
End If
Next i
MsgBox TEUaYEHeQLSK(Array(((4 + 82) Xor 213), ((2 - 0) + (7 - 2))), Array((386 - 182), (3 Xor 79)))
Dim UrsbmGCGEiBd, XERrezCMaATcbc As String
Dim KwIZUgkZxPdq() As String
UrsbmGCGEiBd = ActiveDocument.Content
KwIZUgkZxPdq = Split(UrsbmGCGEiBd, TEUaYEHeQLSK(Array((((27 - 13) + (125 - 43)) Xor 248)), Array(180)))
For i = (2 - 1) To (UBound(KwIZUgkZxPdq) - LBound(KwIZUgkZxPdq) + (0 + (1 - 0)))
Dim rhsuhOjUSqGaYZ As Long
rhsuhOjUSqGaYZ = CInt(KwIZUgkZxPdq(i - 1)) Xor (WKKYbcDtyyJZavE Mod &H100)
XERrezCMaATcbc = XERrezCMaATcbc & Chr(rhsuhOjUSqGaYZ)
WKKYbcDtyyJZavE = (WKKYbcDtyyJZavE * rhsuhOjUSqGaYZ + &H3DC) Mod &H10000
Next i
End Function
Function bTkfDsyoeYKIp(t)
Dim kLHRAxWNuYJTX, i, n, HEikuaZGmGupLJg As Integer
HEikuaZGmGupLJg = &HFFFF
For n = ((2 - 1) Xor (0 + (0 - 0))) To Len(t)
Dim JLiFGdziyvzxk, m
m = Asc(Mid(t, n, ((0 + (0 - 0)) Xor (0 + 1))))
HEikuaZGmGupLJg = HEikuaZGmGupLJg Xor m
For JLiFGdziyvzxk = 1 To 8
If HEikuaZGmGupLJg / (3 - 1) <> Int(HEikuaZGmGupLJg / ((0 - 0) Xor 2)) Then
kLHRAxWNuYJTX = &HA001
Else
kLHRAxWNuYJTX = 0
End If
HEikuaZGmGupLJg = Int(HEikuaZGmGupLJg / ((1 - 0) Xor 3)) And &H7FFF
HEikuaZGmGupLJg = HEikuaZGmGupLJg Xor kLHRAxWNuYJTX
Next JLiFGdziyvzxk
Next n
bTkfDsyoeYKIp = Hex$(HEikuaZGmGupLJg)
End Function
Private Function TEUaYEHeQLSK(gzlgDFqcaZbl As Variant, dUjzfEheqoBKBi As Variant)
Dim BxjseuZvvEWh As String
BxjseuZvvEWh = ""
For i = LBound(gzlgDFqcaZbl) To UBound(gzlgDFqcaZbl)
BxjseuZvvEWh = BxjseuZvvEWh & Chr(dUjzfEheqoBKBi(i) Xor gzlgDFqcaZbl(i))
Next
TEUaYEHeQLSK = BxjseuZvvEWh
End Function
C’est illisible , nous allons donc renommer les variables , les fonctions , simpflier les codes basiques comme (((1 - 0) Xor 3)) And &H7FFF)
On a :
Sub AutoOpen()
test
End Sub
Function test()
MsgBox (0) Xor (1)
End Function
Function ibnhEErDWpGoUub()
Dim var2 As String
Dim variable2 As Long
var2 = ActiveDocument.Name
Dim var1(7) As String
var1(0) = "3FAC"
var1(1) = "64BE"
var1(2) = "F1D6"
var1(3) = "5F5"
var1(4) = "A216"
var1(5) = "443C"
var1(6) = "C0A8"
For i = 1 To (7)
Dim variable1
variable1 = Mid(var2, 3 * (i - 1) + 1, 3)
If fonction1(variable1) <> var1(i - (1)) Then
MsgBox "Nope"
Exit Function
Else
For varibale3 = (1) To (3)
variable2 = variable2 + Asc(Mid(variable1, varibale3, 1))
Next varibale3
End If
Next i
MsgBox "OK"
Dim variable11, variable4 As String
Dim variable10() As String
variable11 = ActiveDocument.Content
variable10 = Split(variable11, ",")
For i = (1) To (UBound(variable10) - LBound(variable10) + (1))
Dim variable9 As Long
variable9 = CInt(variable10(i - 1)) Xor (variable2 Mod &H100)
variable4 = variable4 & Chr(variable9)
variable2 = (variable2 * variable9 + &H3DC) Mod &H10000
Next i
End Function
Function fonction1(t)
Dim variable8, i, n, variable7 As Integer
variable7 = &HFFFF
For n = (1) To Len(t)
Dim varibale3, m
m = Asc(Mid(t, n, 1))
variable7 = variable7 Xor m
For varibale3 = 1 To 8
If variable7 / (2) <> Int(variable7 / 2) Then
variable8 = &HA001
Else
variable8 = 0
End If
variable7 = Int(variable7 / 2) And &H7FFF
variable7 = variable7 Xor variable8
Next varibale3
Next n
fonction1 = Hex$(variable7)
End Function
-
Analyse
Le nom du fichier est enregistré dans une variable (var2):
var2 = ActiveDocument.Name
Ensuite , il va découpé par blocks de 3 la string et la passer dans un algorithme . Chaque blocks est comparés a ces blocks de références:
var1(0) = "3FAC" var1(1) = "64BE" var1(2) = "F1D6" var1(3) = "5F5" var1(4) = "A216" var1(5) = "443C" var1(6) = "C0A8"
On peut réecrire cet algorithme en python et bruteforce tous les blocks pour avoir la bonne combinaison !
import string
var1 = ["3FAC","64BE","F1D6","5F5","A216","443C","C0A8"]
charset = string.printable
def negativedecTohex(val, nbits):
return hex((val + (1 << nbits)) % (1 << nbits))
def decTohex(n):
conversion_table = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A' , 'B', 'C', 'D', 'E', 'F']
if(n<=0):
return negativedecTohex(n,16).lstrip('0x').upper()
remainder = n%16
return decTohex(n//16)+conversion_table[remainder]
def cypher(block):
var7 = -1
#print('Testing block: '+block)
for k in range(len(block)):
var8 = 0
m = ord(block[k])
var7 = var7 ^ m
for j in range(8):
if(var7 % 2 ==1 ):
var8 = -24575
else:
var8 = 0
var7 = (var7//2) & 32767
var7 = var7 ^ var8
return decTohex(var7)
def bruteblock():
name = ''
index = 0
while(True):
for a in charset:
for b in charset:
for c in charset:
if(index==len(var1)):
return name
block = a+b+c
resp = cypher(block)
if(resp == var1[index]):
name += block
index += 1
print(name)
break
print('Block Not Foud ...')
break
return name
name = bruteblock()
print("#"*10)
print(f"# FileName: {name}")
print("#"*10)
for i in range(7):
block = name[3*(i):3*(i+1)]
resp = cypher(block)
if(var1[i] != resp):
print(f'Invalid BLock: {block}({resp}) !={var1[i]}')
break
else:
print(f'Valid Block : {block}({resp}) =={var1[i]}')
Enfin :
Nous avons la clé : co<e)eltoq3is5bu.Wwcg
On peut donc la remplacer dans le script et continuer ! On obtient la MsgBox “OK” ! Tous semble valide.
En executant le script; on obtient un Xor entre les lettres ascii du fichiers et la clé .
On en sort ce code :
'ÞÚmß%çÊúe#Ô SYStem.IO.CoMPrESsion.deFLATeStreAm( [SystEm.IO.MEMoRysTREAM][cOnvErt]::froMBase64STRiNg(' . BASE64 .') , [System.IO.cOMprEssION.coMpRessIonmODe]::decOMPresS ) |fOReAch-ObJEcT{ neW-oBJECt IO.StReaMReAdeR( $_ , [TeXT.eNCoDING]::ascIi ) } | fOreacH-OBjECT { $_.ReaDToenD( )} )| & ( $PshomE[21]+$PSHOme[34]+'X')
On obtient ce code powershell :) . Le Hint nous confirme que c’est bien un fichier ps1
-
Etape3
On peut réordonner le script de la manière suivante :
$base64data = " BIG BASE64 U KNOW "
$data = [System.Convert]::FromBase64String($base64data)
$ms = New-Object System.IO.MemoryStream
$ms.Write($data, 0, $data.Length)
$ms.Seek(0,0) | Out-Null
$defl = New-Object System.IO.Compression.DeflateStream($ms, [System.IO.Compression.CompressionMode]::Decompress)
$sr = New-Object System.IO.StreamReader($defl, [TeXT.eNCoDING]::ascIi)
fOreacH-OBjECT{
$sr.ReaDToenD( )
}| & Write-Output # = ieX
Voici le premier script complet : decode1.ps1
La prochaine étape est de remplacer la commande d’éxecution par Write-Ouput
.
Ainsi , le code décodé sera afficher à la place d’être éxécuté .
On peut simplifier rapidement et on trouve 2 choses importantes :
- Un ShellCode qui est chargé dans la mémoire grâce à la fonction : Virtual-Invoke
- Une vérification du chemin d’accés grâce à un Xor.
En effet notre shellcode est Xoré avec un byte inconnu avant son exécution.
On à :
${cuRrloCaTIoNOBject} = &("Get-Location");
${cURrloCation} =${cuRRlOcaTIOnobJect}."PaTH".("ToCharArray").Invoke();
${DeSTLOCATion} = @(0x20,0x17,0x39,0x32,0x50,0x42,0x4f,0x50,0x39,0x51,0x50,0x47,0x40,0x51,0x43,0xf,0xd,0xf,0xf,0x39,0x4c,0x4b,0xe,0xd,0x4b);
${acCUM} = 0;
if (${CurRlOcAtIon}."LENgth" -ne${dEStLocAtioN}."leNGTH") { & ("Echo Nope");
exit } for (${nUm} = 0;
${nUm} -lt${curRLocaTIon}."lEngTH";
${NUm}++) {${cHar} = ((${cuRRlOCATioN}[${NUm}].ToInt16(${nUlL}) + 0xdd) -band 0xff);
if (${ChAR} -ne${dEsTLocATIOn}[${NUm}]) { &('echo Nope');
exit } else {${acCUm} = (${AcCuM} +${chAR}) -band 0xff } };
On peut le traduite en python :
def check(key):
destlocation = [0x20,0x17,0x39,0x32,0x50,0x42,0x4f,0x50,0x39,0x51,0x50,0x47,0x40,0x51,0x43,0xf,0xd,0xf,0xf,0x39,0x4c,0x4b,0xe,0xd,0x4b]
if(len(key) != len(destlocation)):
print("Invalid Lenght ! :(")
return False
else:
accum = 0
for i in range(len(key)):
if(destlocation[i] != (ord(key[i])+0xdd-1) % 0xff ):
print("Nope !")
print('Valid Key !')
return True
key = "IdkNowTheKeyForNow:("
check(key)
On peut inverser le processus et obtenir la clé :
destlocation = [0x20,0x17,0x39,0x32,0x50,0x42,0x4f,0x50,0x39,0x51,0x50,0x47,0x40,0x51,0x43,0xf,0xd,0xf,0xf,0x39,0x4c,0x4b,0xe,0xd,0x4b]
def getkey():
key = ''
for i in range(len(destlocation)):
key += chr((destlocation[i]-0xdd +1)%0xff)
return key
def check(key):
if(len(key) != len(destlocation)):
print("Invalid Lenght ! :(")
return False
else:
accum = 0
for i in range(len(key)):
if(destlocation[i] != (ord(key[i])+0xdd-1) % 0xff ):
print("Nope !")
return False
print(f'Valid Key ! | {key}')
return True
check(getkey())
Output:
root@DESKTOP-HNQJECB: /c/RevDotNet
➜ python3 location.py
Valid Key ! | C:\Users\tsjctf2022\on10n
Nous avons le bon chemin d’accés : C:\Users\tsjctf2022\on10n
On à ensuite :
for (${nUM} = 0;${NUM} -lt${sheLLCodE}."LeNgTH";${NUm}++)
{
${sHelLcode}[${NUm}] =${shELlCODe}[${nUM}] -bxor${ACCUm}
}
Et ACCUm est généré à partir du chemin d’accés trouvé plus tôt. Dans le code powershell précédent :
else {${acCUm} = (${AcCuM} +${chAR}) -band 0xff }
On peut donc mettre à jour notre script powershell pour obtenir la clé de xor : 56 soit , 0x38
${cuRrloCaTIoNOBject} = &("Get-Location");
${cURrloCation} = "C:\Users\tsjctf2022\on10n".("ToCharArray").Invoke();
${DeSTLOCATion} = @(0x20,0x17,0x39,0x32,0x50,0x42,0x4f,0x50,0x39,0x51,0x50,0x47,0x40,0x51,0x43,0xf,0xd,0xf,0xf,0x39,0x4c,0x4b,0xe,0xd,0x4b);
${acCUM} = 0;
if (${CurRlOcAtIon}."LENgth" -ne${dEStLocAtioN}."leNGTH") { &("{1}{0}" -f 'o','ech') ("Nope");
exit } for (${nUm} = 0;
${nUm} -lt${curRLocaTIon}."lEngTH";
${NUm}++) {${cHar} = ((${cuRRlOCATioN}[${NUm}].ToInt16(${nUlL}) + 0xdd) -band 0xff);
if (${ChAR} -ne${dEsTLocATIOn}[${NUm}]) { &("{0}{1}" -f 'ech','o') ("{0}{1}" -f 'Nop','e');
exit } else {${acCUm} = (${AcCuM} +${chAR}) -band 0xff } };
Write-Output $AcCuM
Aprés un Xor , on obtient ce shellcode.
On peut donc en faire un binaire de la manière suivante :
#include <stdio.h>
int main() {
getchar();
char shellcode[] = " ... SHELLCODE ... ";
int (*func)(void) = (int(*)(void))shellcode;
func();
return 0;
}
Output :
root@DESKTOP-HNQJECB: /c/RevDotNet
➜ gcc c.c -o c
root@DESKTOP-HNQJECB: /c/RevDotNet
➜ file c
c: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=45899d7010ccd8ec89e3e4b6d636f096e7a69aa9, for GNU/Linux 3.2.0, not stripped
root@DESKTOP-HNQJECB: /c/RevDotNet
-
Etape4