Permalink
Browse files

python/smb - let dionaea talk to WannaCry, MS17-010 honeypot and coll…

…ect Double Pulsar payload

- dionaea will act and respond as it had the Double Pulsar implanted
- once WannaCry try to scan and found “hey, you have implanted with DoublePulsar. Let me start to deliver my payload", dionaea will capture the payload nicely
- modify SMB_Sessionsetup_AndX_Response to make dionaea a Windows 7 machine (it was Windows 2000 for years)
- update SMB_COM_TRANSACTION2 packet handling, collecting payload to disk and logging
- add new classes: SMB_NT_Trans_Request, SMB_NT_Trans_Response, SMB_Trans2_Secondary_Request
  • Loading branch information...
gento committed May 23, 2017
1 parent 13fd187 commit d17ebf359f71b8e53c42a943dccba1e623a9e278
@@ -839,8 +839,10 @@ class SMB_Sessionsetup_AndX_Response2(Packet):
XLEShortField("Action",1),
MultiFieldLenField("ByteCount", None, fmt='<H', length_of=("Padding","NativeOS", "NativeLanManager", "PrimaryDomain")),
ConditionalField(StrFixedLenField("Padding", b'\0', 1), lambda x:x.underlayer.Flags2 & SMB_FLAGS2_UNICODE),
SMBNullField("NativeOS","Windows 5.1", utf16=lambda x:x.underlayer.Flags2 & SMB_FLAGS2_UNICODE),
SMBNullField("NativeLanManager","Windows 2000 LAN Manager", utf16=lambda x:x.underlayer.Flags2 & SMB_FLAGS2_UNICODE),
SMBNullField("NativeOS","Windows 7 Professional 7600", utf16=lambda x:x.underlayer.Flags2 & SMB_FLAGS2_UNICODE),
SMBNullField("NativeLanManager","Windows 7 Professional 6.1", utf16=lambda x:x.underlayer.Flags2 & SMB_FLAGS2_UNICODE),
# SMBNullField("NativeOS","Windows 5.1", utf16=lambda x:x.underlayer.Flags2 & SMB_FLAGS2_UNICODE),
# SMBNullField("NativeLanManager","Windows 2000 LAN Manager", utf16=lambda x:x.underlayer.Flags2 & SMB_FLAGS2_UNICODE),
SMBNullField("PrimaryDomain","WORKGROUP", utf16=lambda x:x.underlayer.Flags2 & SMB_FLAGS2_UNICODE),
]

@@ -1190,6 +1192,14 @@ class SMB_Trans_Response(Packet):
ByteField("Reserved2",0),
]

class SMB_Trans_Response_Simple(Packet):
name = "SMB Trans Response Simple"
smb_cmd = SMB_COM_TRANSACTION #0x25
fields_desc = [
ByteField("WordCount",0),
LEShortField("ByteCount",0),
]

# page 45
class SMB_Trans2_Request(Packet):
name = "SMB Trans2 Request"
@@ -1256,6 +1266,54 @@ class SMB_Trans2_Response(Packet):
LEShortField("ByteCount",0),
]

class SMB_Trans2_Secondary_Request(Packet):
name = "SMB Trans2 Secondary Request"
smb_cmd = SMB_COM_TRANSACTION2_SECONDARY # 0x33
fields_desc = [
ByteField("WordCount",0),
LEShortField("TotalParamCount",0),
LEShortField("TotalDataCount",0),
LEShortField("MaxParamCount",0),
LEShortField("MaxDataCount",0),
ByteField("MaxSetupCount",0),
ByteField("Reserved",0),
XLEShortField("Flags",0),
LEIntField("Timeout",0),
ShortField("Reserved2",0),
FieldLenField("ParamCount", 0, fmt='<H', count_of="Data"),
StrFixedLenField("Data", "", length_from=lambda pkt: pkt.ParamCount),
]

class SMB_NT_Trans_Request(Packet):
name = "SMB NT Trans Request"
smb_cmd = SMB_COM_NT_TRANSACT #0xa0
fields_desc = [
ByteField("WordCount",0),
ByteField("MaxSetupCount",0),
ShortField("Reserved",0),
LEIntField("TotalParamCount",0),
LEIntField("TotalDataCount",0),
LEIntField("MaxParamCount",0),
LEIntField("MaxDataCount",0),
FieldLenField("ParamCount", 0, fmt='<I', count_of="Params"),
LEIntField("ParamOffset",0),
LEIntField("DataCount",0),
LEIntField("DataOffset",0),
FieldLenField("SetupCount", 0, fmt='B', count_of="Setup"),
ShortField("Function",0),
#TODO: need more work on this part
FieldListField("Param", 0, XByteField("", 0), count_from = lambda pkt: pkt.ParamCount),
StrFixedLenField("Data", b"", length_from=lambda pkt: pkt.DataCount),
]

class SMB_NT_Trans_Response(Packet):
name = "SMB NT Trans Response"
smb_cmd = SMB_COM_NT_TRANSACT #0xa0
fields_desc = [
ByteField("WordCount",0),
LEShortField("ByteCount",0),
]

# [MS-CIFS].pdf - 2.2.5 Transaction Subcommands
# http://msdn.microsoft.com/en-us/library/ee441557%28v=PROT.13%29.aspx
TRANS_NMPIPE_SET_STATE = 0x0001
@@ -1522,6 +1580,7 @@ class RAP_Response(Packet):
bind_bottom_up(SMB_Header, SMB_NTcreate_AndX_Response, Command=lambda x: x==0xa2, Flags=lambda x: x&0x80)
bind_bottom_up(SMB_Header, SMB_Trans_Request, Command=lambda x: x==0x25, Flags=lambda x: not x&0x80)
bind_bottom_up(SMB_Header, SMB_Trans2_Request, Command=lambda x: x==0x32, Flags=lambda x: not x&0x80)
bind_bottom_up(SMB_Header, SMB_Trans2_Secondary_Request, Command=lambda x: x==0x33, Flags=lambda x: not x&0x80)

bind_bottom_up(SMB_Header, SMB_Write_AndX_Request, Command=lambda x: x==0x2f, Flags=lambda x: not x&0x80)
bind_bottom_up(SMB_Header, SMB_Write_AndX_Response, Command=lambda x: x==0x2f, Flags=lambda x: x&0x80)
@@ -1568,6 +1627,7 @@ class RAP_Response(Packet):
bind_top_down(SMB_Header, SMB_Read_AndX_Response, Command=0x2e)
bind_top_down(SMB_Header, SMB_Trans_Request, Command=0x25)
bind_top_down(SMB_Header, SMB_Trans2_Request, Command=0x32)
bind_top_down(SMB_Header, SMB_Trans2_Secondary_Request, Command=0x33)
bind_top_down(SMB_Header, SMB_Open_AndX_Request, Command=0x2d)
bind_top_down(SMB_Read_AndX_Response, SMB_Data)

@@ -34,6 +34,8 @@
import tempfile
import binascii
import os
import hashlib
from dionaea.util import xor
from uuid import UUID

from .include.smbfields import *
@@ -70,10 +72,12 @@ def __init__ (self):
'stop': False,
}
self.buf = b''
self.buf2 = b'' # ms17-010 SMB_COM_TRANSACTION2
self.outbuf = None
self.fids = {}
self.printer = b'' # spoolss file "queue"


def handle_established(self):
# self.timeouts.sustain = 120
self.timeouts.idle = 120
@@ -121,9 +125,9 @@ def handle_io_in(self,data):
r = self.process(p)
smblog.debug('packet: {0}'.format(p.summary()))

if p.haslayer(Raw):
smblog.warning('p.haslayer(Raw): {0}'.format(p.getlayer(Raw).build()))
p.show()
# if p.haslayer(Raw):
# smblog.warning('p.haslayer(Raw): {0}'.format(p.getlayer(Raw).build()))
# p.show()

# i = incident("dionaea.module.python.smb.info")
# i.con = self
@@ -305,6 +309,8 @@ def process(self, p):
if Service.startswith('\\\\'):
Service = Service[1:]
Service = Service.split('\\')[-1]
if Service[-1] == '\x00':
Service = Service[:-1]
if Service[-1] == '$':
Service = Service[:-1]
r.Service = Service + '\x00'
@@ -525,15 +531,80 @@ def process(self, p):

rdata.ByteCount = dceplen
rdata.Bytes = self.outbuf

if socket.htons(h.Setup[0]) == TRANS_NMPIPE_PEEK:
SetupCount = h.SetupCount
if SetupCount > 0:
smblog.info('MS17-010 - SMB RCE exploit scanning..')
r = SMB_Trans_Response_Simple()
# returned #STATUS_INSUFF_SERVER_RESOURCE as we not being patched
rstatus = 0xc0000205 #STATUS_INSUFF_SERVER_RESOURCES

r /= rdata
elif p.getlayer(SMB_Header).Command == SMB_COM_TRANSACTION2:
elif Command == SMB_COM_TRANSACTION2:
h = p.getlayer(SMB_Trans2_Request)
if h.Setup[0] == SMB_TRANS2_SESSION_SETUP:
smblog.info('Possible DoublePulsar connection attempts..')
# make sure the payload size not larger than 10MB
if len(self.buf2) > 10485760:
self.buf2 = ''
elif len(self.buf2) == 0 and h.DataCount == 4096:
self.buf2 = self.buf2 + h.Data
elif len(self.buf2) != 0 and h.DataCount == 4096:
self.buf2 = self.buf2 + h.Data
elif len(self.buf2) != 0 and h.DataCount < 4096:
smblog.info('DoublePulsar payload receiving..')
self.buf2 = self.buf2 + h.Data
key = bytearray([0x52,0x73,0x36,0x5E])
xor_output = xor(self.buf2, key)
hash_buf2 = hashlib.md5(self.buf2);
smblog.info('DoublePulsar payload - MD5 (before XOR decryption): %s' %(hash_buf2.hexdigest()))
hash_xor_output = hashlib.md5(xor_output);
smblog.info('DoublePulsar payload - MD5 (after XOR decryption ): %s' %(hash_xor_output.hexdigest()))

#f = tempfile.NamedTemporaryFile(delete=False, prefix="xorfull-"+hash_xor_output.hexdigest()+"-", suffix="", dir=g_dionaea.config()['downloads']['dir'])
dir=g_dionaea.config()['downloads']['dir'] + "/"
f = open(dir+hash_xor_output.hexdigest(),'wb')
f.write(xor_output)
f.close

offset = 0
for i, c in enumerate(xor_output):
if ((xor_output[i] == 0x4d and xor_output[i+1] == 0x5a) and xor_output[i+2] == 0x90):
offset = i
smblog.info('DoublePulsar payload - MZ header found...')
break

hash_xor_output_mz = hashlib.md5(xor_output[offset:]);
smblog.info('DoublePulsar payload - MD5 final: %s. Save to disk' %(hash_xor_output_mz.hexdigest()))
#f1 = tempfile.NamedTemporaryFile(delete=False, prefix=hash_xor_output_mz.hexdigest()+"-", suffix="", dir=g_dionaea.config()['downloads']['dir'])
f1 = open(dir+hash_xor_output_mz.hexdigest(),'wb')
f1.write(xor_output[offset:])
f1.close
self.buf2 = b''
xor_output = b''

icd = incident("dionaea.download.complete")
icd.path = dir+hash_xor_output_mz.hexdigest()
icd.url = self.remote.host
icd.con = self
icd.report()
r = SMB_Trans2_Response()
rstatus = 0xc0000002 #STATUS_NOT_IMPLEMENTED

elif Command == SMB_COM_DELETE:
# specific for NMAP smb-enum-shares.nse support
h = p.getlayer(SMB_Delete_Request)
if h.FileName == b'nmap-test-file\0':
r = SMB_Delete_Response()
elif Command == SMB_COM_TRANSACTION2_SECONDARY:
h = p.getlayer(SMB_Trans2_Secondary_Request)
# TODO: need some extra works
pass
elif Command == SMB_COM_NT_TRANSACT:
h = p.getlayer(SMB_NT_Trans_Request)
r = SMB_NT_Trans_Response()
rstatus = 0x00000000 #STATUS_SUCCESS
else:
smblog.critical('...unknown SMB Command. bailing out.')
p.show()
@@ -542,9 +613,18 @@ def process(self, p):
smbh = SMB_Header(Status=rstatus)
smbh.Command = r.smb_cmd
smbh.Flags2 = p.getlayer(SMB_Header).Flags2
if Command == SMB_COM_TRANSACTION:
smbh.Flags2 = p.getlayer(SMB_Header).Flags2 | SMB_FLAGS2_ERR_STATUS
smblog.info('MS17-010 - responded with legitimate SMB with #STATUS_INSUFF_SERVER_RESOURCES')
smblog.info('MS17-010 - waiting for next incoming request.. ')
# smbh.Flags2 = p.getlayer(SMB_Header).Flags2 & ~SMB_FLAGS2_EXT_SEC
smbh.MID = p.getlayer(SMB_Header).MID
smbh.PID = p.getlayer(SMB_Header).PID
# Deception for DoublePulsar, we fix the XOR key first as 0x5273365E
# WannaCry will use the XOR key to encrypt and deliver next payload, so we can decode easily later
if Command == SMB_COM_TRANSACTION2:
smbh.MID = p.getlayer(SMB_Header).MID + 16
smbh.Signature = 0x000000009cf9c567
rp = NBTSession()/smbh/r

if Command in SMB_Commands:
@@ -46,3 +46,8 @@ def hashfile(filename, digest):
fh.close()
return digest.hexdigest()

def xor(data, key):
l = len(key)
return bytearray((
(data[i] ^ key[i % l]) for i in range(0,len(data))
))

0 comments on commit d17ebf3

Please sign in to comment.