Himayatic rev_400 Writeup (.NET Crackme)
Hello, today I'll crack a .NET crackme, it was featured on Himayatic CTF, November 2nd 2017.
Download link : https://drive.google.com/open?id=0B7U3AsTA9UVfRHdTY2hfQzZrQm8
Let's start :)
First, we notice that it's a .NET crackme, it asks for a serial, and displays "Wrong Serial ... !!!" when we enter a random one.
The code looks obfuscated, we follow the N and M functions in the namespace A, and we find this:
Looks like they used CryptoObfuscator to obfuscate the code, we'll use a .NET deobfuscator (de4dot : https://github.com/0xd4d/de4dot ) to clean the executable.
We open the cleaned executable in dnSpy, the obfuscation is gone!
We suspect that it uses the RunPE technique, which in short works like this:
It spawns itself as a new process in suspended state
It locates the base address of the new exe.
It uses WriteProcessMemory or a similar API to write every section to the new exe
It sets the context of the main thread of the new process
It resumes the new process
We go back to dnSpy, and we find out that we were correct, the code is in the Skins class.
Now, this is what I did : I used pd (process dump : http://split-code.com/processdump.html ) to dump the process and all its DLLs while it was running, this way I got the final exe.
I opened the new exe in dnSpy, and it's a different one :p
More fake flags :p after more investigation, we find this function :
It Loads another Base64-encoded assembly, we look for T1.Text to T4.Text, they are initialized in the InitializeComponent method in FZero class, all this way:
this.T1.Text = componentResourceManager.GetString("T1.Text");
We find the strings in the resources
We concatenate them, decode as base64, and save output as a file, it's a DLL.
We load it in dnSpy, and this time, we find the real check :
the method V calls the method E to encrypt the user input, then it calls the method VR to check if it's correct, VR compares a fixed twice-base64 encoded string (stored encoded once in ressources) with the encrypted and twice-encoded user input, then it calls DS if the check succeeds, we find "Wrong Serial ... !!|Yeah,, you did it :)'" in the resources.
the method E (which encrypts) looks like this:
It concatenates the second argument with "Himayatic_0xC001", then hashes the result using md5, then it initializes a buffer of 32 characters, then it copies the md5 hash to a buffer starting at index 0 (copies 16 characters), then copies the same md5 hash to the same buffer starting at index 15 (copies 16 characters), so it overwrites the last character of the first copy, then it uses the buffer as the key to encrypt the first function parameter, it encrypts it using AES in ECB mode, then encodes it using base64.
We go back to where the assembly is loaded and used, we look for references to the function GetSkin, which returns an instance of CTFs__.Himayatic
We find it in FZero_Load : this.o = RuntimeHelpers.GetObjectValue(this.Himayatic.getSkin());
We look for references to this.o, and we find this :
It's pretty straightforward to understand this code, it's calling the method V, something like this : V( this.FL__.Text, this.Name, true)
this.FL__.Text is the user input, this.Name can be found in FZero class ( this.Name = "FZero"; ).
After that, it's pretty simple to get the flag, just a simple Ruby script:
require'base64';
require'openssl';
require'digest';
begin
enc = Base64.decode64 "FQUFl/85WMFJp5XXfJX5Xykt8WhTPcy1MD0/0+SqEsj/IdMrolb3Haaq9yiZvcuH";
e = OpenSSL::Cipher::AES.new(256,:ECB)
e.decrypt; # initialize it for decryption
md5 = Digest::MD5.digest("FZero" + "Himayatic_0xC001");
key = "\x00" * 32;
key[0,16] = md5;
key[15, 16] = md5;
e.key = key;
puts (e.update(enc)+e.final); # should output the flag
rescue Exception => e
p e;
p e.message;
p e.backtrace
ensure
gets
end
Himayatic{*1LLu510N__W17h0u7_C4rD5*}
Really nice challenge :p
Download link : https://drive.google.com/open?id=0B7U3AsTA9UVfRHdTY2hfQzZrQm8
Let's start :)
First, we notice that it's a .NET crackme, it asks for a serial, and displays "Wrong Serial ... !!!" when we enter a random one.
We open it in a .NET decompiler (I used dnSpy, which is a fork of ILSpy), and we immediately locate this function :
The code looks obfuscated, we follow the N and M functions in the namespace A, and we find this:
Looks like they used CryptoObfuscator to obfuscate the code, we'll use a .NET deobfuscator (de4dot : https://github.com/0xd4d/de4dot ) to clean the executable.
We open the cleaned executable in dnSpy, the obfuscation is gone!
But it's a wrong flag, if it were the real flag, the else part would display "Wrong Serial ... !!!" and not "Illusion ... !!" (of course, we still try it, who knows :p).
We don't find anything interesting in the Form class, so we try debugging in x64dbg, we notice that when we open the program with x64dbg, it spawns itself in a new process and then exits from the main process, we breakpoint on CreateProcessA and CreateProcessW, just to ensure that we are correct, and yes, we hit the breakpoint on CreateProcessW, I did not notice the CREATE_SUSPENDED state in dwCreationFlags, I immediately went back to the decompiler, to find out where it spawns the new process, and what it does exactly.
We don't find anything interesting in the Form class, so we try debugging in x64dbg, we notice that when we open the program with x64dbg, it spawns itself in a new process and then exits from the main process, we breakpoint on CreateProcessA and CreateProcessW, just to ensure that we are correct, and yes, we hit the breakpoint on CreateProcessW, I did not notice the CREATE_SUSPENDED state in dwCreationFlags, I immediately went back to the decompiler, to find out where it spawns the new process, and what it does exactly.
We suspect that it uses the RunPE technique, which in short works like this:
It spawns itself as a new process in suspended state
It locates the base address of the new exe.
It uses WriteProcessMemory or a similar API to write every section to the new exe
It sets the context of the main thread of the new process
It resumes the new process
We go back to dnSpy, and we find out that we were correct, the code is in the Skins class.
Now, this is what I did : I used pd (process dump : http://split-code.com/processdump.html ) to dump the process and all its DLLs while it was running, this way I got the final exe.
I opened the new exe in dnSpy, and it's a different one :p
More fake flags :p after more investigation, we find this function :
It Loads another Base64-encoded assembly, we look for T1.Text to T4.Text, they are initialized in the InitializeComponent method in FZero class, all this way:
this.T1.Text = componentResourceManager.GetString("T1.Text");
We find the strings in the resources
We concatenate them, decode as base64, and save output as a file, it's a DLL.
We load it in dnSpy, and this time, we find the real check :
the method V calls the method E to encrypt the user input, then it calls the method VR to check if it's correct, VR compares a fixed twice-base64 encoded string (stored encoded once in ressources) with the encrypted and twice-encoded user input, then it calls DS if the check succeeds, we find "Wrong Serial ... !!|Yeah,, you did it :)'" in the resources.
the method E (which encrypts) looks like this:
It concatenates the second argument with "Himayatic_0xC001", then hashes the result using md5, then it initializes a buffer of 32 characters, then it copies the md5 hash to a buffer starting at index 0 (copies 16 characters), then copies the same md5 hash to the same buffer starting at index 15 (copies 16 characters), so it overwrites the last character of the first copy, then it uses the buffer as the key to encrypt the first function parameter, it encrypts it using AES in ECB mode, then encodes it using base64.
We go back to where the assembly is loaded and used, we look for references to the function GetSkin, which returns an instance of CTFs__.Himayatic
We find it in FZero_Load : this.o = RuntimeHelpers.GetObjectValue(this.Himayatic.getSkin());
We look for references to this.o, and we find this :
It's pretty straightforward to understand this code, it's calling the method V, something like this : V( this.FL__.Text, this.Name, true)
this.FL__.Text is the user input, this.Name can be found in FZero class ( this.Name = "FZero"; ).
After that, it's pretty simple to get the flag, just a simple Ruby script:
require'base64';
require'openssl';
require'digest';
begin
enc = Base64.decode64 "FQUFl/85WMFJp5XXfJX5Xykt8WhTPcy1MD0/0+SqEsj/IdMrolb3Haaq9yiZvcuH";
e = OpenSSL::Cipher::AES.new(256,:ECB)
e.decrypt; # initialize it for decryption
md5 = Digest::MD5.digest("FZero" + "Himayatic_0xC001");
key = "\x00" * 32;
key[0,16] = md5;
key[15, 16] = md5;
e.key = key;
puts (e.update(enc)+e.final); # should output the flag
rescue Exception => e
p e;
p e.message;
p e.backtrace
ensure
gets
end
Himayatic{*1LLu510N__W17h0u7_C4rD5*}
Really nice challenge :p
Nice Writeup, THANKS!
RépondreSupprimerYou're welcome :)
SupprimerHimayatic Rev_400 Writeup (.Net Crackme) >>>>> Download Now
Supprimer>>>>> Download Full
Himayatic Rev_400 Writeup (.Net Crackme) >>>>> Download LINK
>>>>> Download Now
Himayatic Rev_400 Writeup (.Net Crackme) >>>>> Download Full
>>>>> Download LINK 7K
Himayatic Rev_400 Writeup (.Net Crackme) >>>>> Download Now
RépondreSupprimer>>>>> Download Full
Himayatic Rev_400 Writeup (.Net Crackme) >>>>> Download LINK
>>>>> Download Now
Himayatic Rev_400 Writeup (.Net Crackme) >>>>> Download Full
>>>>> Download LINK DI