Home page logo
/

fulldisclosure logo Full Disclosure mailing list archives

multiple remote root vulns in Rosiello rFTPD and RPF
From: Slotto Corleone <slotto () gmail com>
Date: Mon, 20 Dec 2004 06:03:44 -0800

- --------------------------------------------------------------------------
De_aap security advisory 1
December 20th, 2004
- --------------------------------------------------------------------------

Package        : rftpd 2 and rpf 1.2.2
Vulnerability  : buffer overflows, race conditions, integer overflows,
logic bugs and much much more
Problem-Type   : local and remote
CVE ID         : No CVE ID's are assigned 
Bugs found by  : most by de_aap, some found by Slotto Corleone and
percy, vlad902

Previous remote root vulnerabilities in software from Rosiello.org
"security research team"
(http://lists.netsys.com/pipermail/full-disclosure/2004-April/020690.html)

1.) Gaping security holes in rftpd 2:

some background info from their site (rave.swehack.se):
*******************************************************

"Do you know that many ftp daemons are released with NULL support?
rFTPD is not like that at all, your experience will build the software!"
  Except that some of the bugs presented in this advisory have been
disclosed to the
  rftpd development team months ago, still no fix !!
...
rFTPD offers:
    * Download at high speed // yea right 
    * Fantastic logging // hellyea, and it also offers 'pre-auth' remote root 
    * Unique signal handling // can you say signal race condition ?
oh, and you can't catch SIGKILL you dummy
    * Restore your download after the client disconnection
    * Very easy configuration
    * Multiple languages are available such as English, dutch,
norwegian, swedish, italian. // all with crappy spelling
    * EPRT/EPASV full working
...
"But why?, well we are already better faster and more secure then a
lot other comercial products that are around a long time now."
  more secure ? excuse me ? we found more security holes in rftpd then
there are in wu-ftpd for fucks sake !
  It's not fast either, ever heard of a syscall named sendfile() ? 
...
Current release (rftpd-secprec2-linux.tar.gz):

    * Some features may not be included yet. // like actually
authenticating someone :)
    * Waiting for tkn people to rate the software.
...
"If you plan to use the ftpd for hosting purposes, remind to contact
us and tell about your experience with the daemon, please. This
could be crucial for the existance of the server daemon because your
knowledge is our concern."
  please contact us aswell, we'd love to own you. 
...
If you think you can do anything for this project such as:
    ...
    * Reporting bugs // will do
    ...
Contact us by:
irc.rosiello.net #rosiello
rftpd () rosiello org


from their forum (on source forge) : 
************************************

"By: Nobody/Anonymous - nobody
RE: Compliments  
2004-10-29 13:33
it's a great ftp and i use it for all my customers. they all like it
and we havent had any remote root exploits since then! very secure
and fast"
  verry funny, and almost at leet time :)


The gaping security holes:
**************************

1.) injection terminal escape codes into the terminal. 

rFTPd is ran by root, and by default doesn't fork in the background. 
This is done so that root can see all sorts of debug messages. 

When processing the following commands (there are probably more) it 
doesn't filter any characters, allowing a potential attacker to inject 
any terminal escape codes. Because this also affects the USER command 
this can be seen as a pre-auth remote root bug. 

commands: 
USER, STOR, NLST, LIST, APPE, PASV, MLST, MLSD, MKD, RMD, DELE, RNFR, RNTO


2.) Authentication screwup. 

The authentication routine is close to empty. Only validating usernames. 
This means that if a correct username is given an attacker can just log in. 
No matter what password he enters. 

There is some default protection. the root user is not allowed to login 
by default. This check is not sufficiant however. as it checks for the user 
'root'. and not for uid 0. If another uid 0 account is present on the box
(let's say toor) then one is allowed to login with that user. 
Therefor we can say that this is a pre-auth remote root bug. and that 
everything else described below can be considered semi pre-auth remote root
because all an attacker needs is a valid login.


3.) Info leak

Due to the way arguments are treated when the command itself get's translated
in all uppercase characters there exists an info leak. This was tested 
with the MKD and USER command. If the second parameter is big enough (> 128)
it is possible to leak memory from. In some cases it is even possible to
crash the current session with this. We haven't look at this any further
but is is likely that an attacker can get a rootshell from this. 
(The crash was triggered only with the USER command) 


4.) buffer overflow in debug routines

Most commands log debug messages by default. There exists a bufferoverflow in
the debug routine: 

#define MAX_LOG    225

 void Log_debug ( int preority,  char *fmt, ...) {
 va_list args;
 char buffer[MAX_LOG];
 char *ptr;
 fs_zero(buffer,MAX_LOG);
 va_start ( args,fmt);   
 ptr = buffer;
 vsprintf(ptr,fmt,args);
 ... 
 }

This speaks louder then words. Exploitation is trivial. We made a proof of 
concept exploit at our lab to prove exploitability. We are however not 
going to release our exploit. This can be considered a semi pre-auth remote 
root bug. 


5.) NULL pointer dereference 

There exists a NULL pointer dereference in the NLST command, when used 
with no argument. This can be used to crash the current session. 


6.) Buffer overflow in filter_port()

Filter port is a procedure called from do_port() which is the procedure that 
gets called when the port command is given. The most funny part about this 
overflow is that there is a comment stating that one should watch out for
bufferoverflows: 

int filter_port(const char *portcommand,const char *ip_addr, const void *prt)
{
int pos[10] = { 0 , 0 , 0 ,0 ,0 };
int inc;
int i;
char tmp[128];
int left;
int right;
char port[1];
long port_c;

 /* Always fear buffer underruns/overflows and Check length */
if ((strlen(portcommand)) <= 3) return -1;
if ( !portcommand[0] && ((portcommand[strlen(portcommand)-2]) != 0xd) &&
((portcommand[strlen(portcommand)-2]) != 0xd)) return -1;

strcpy(tmp,portcommand); <--- THIS IS WHERE IT ALL HAPPENS ! 

Exploitation is trivial and this can be considered a semi pre-auth remote root 
bug. 


7.) Another bufferoverflow in filter_port

If the argument given to filter_port isn't long enough to 
trigger the first bufferoverflow, and contains more then 10 ','s then 
one can overflow the pos array: 

...
for (i= 0; i < strlen(portcommand); ++i)
if (((char)portcommand[i]) == ',') { pos[inc] = i; inc++ ; }
...

Exploitation is not so easy. We at de_aap security research believe that this 
can be exploited, given an attacker that is clever enough. 


8.) Third bufferoverflow in filter_port

When filter_port is called at do_port it's second argument is a local character
array of size 128. This can be overflowed later in filter_port: 

int do_port ( void ) {
 char ip[128];
 ...
 filter_port(u_com,ip,&con->usr_rel.req_port);
 ...
}

int filter_port(const char *portcommand,const char *ip_addr, const void *prt) {
 ... 
 char tmp[128];
 ...
 strcpy((char *)ip_addr,tmp);
 ...
}

Exploitation is trivial and is also considered a semi pre-auth remote root. 
Also note the wrong usage of 'const' in filter_port. 


9.) Bufferoverflow in motd parsing

When parsing the motd file a bufferoverflow can happen if there are more then 
MAX_READ + 3 characters on a single line: 

#define MAX_READ    255
void do_welcome ( int socket )  {
 char message[MAX_READ+3];
 ...
 FILE *fp;
 ...
 if ( config ->motdfile  ) {
  fp = fopen(config->motdfile, "r");
  if ( !fp) {  send_data(MSG_WELCOME,socket); return ;}
  while((feof(fp)) == 0){
   fgets(message,500,fp);
   ...
  }
  ...
 }
 ...
}

Exploitation is only usefull when an attacker controls the motd file. 
When this is the case exploitation is trivial. 


10.) do_list info leak. 

There exists a potential information leak in do_list due to not 0terminating 
a string after strncpy(): 

void do_list ( void ) {
 char dir[MAX_PATH+3];
 ...
 if (!dir[0]) strncpy(dir,con->usr_rel.PWD,MAX_PATH);
 ...
}


11.) do_nlst info leak. 

An info leak very simular as the one described in 10 is present in do_nlst: 

void do_nlst ( void ) {
 char dir[MAX_PATH+3];
 ...
 if (!dir[0]) strncpy(dir,con->usr_rel.PWD,MAX_PATH);
 ...
}


12.) bufferoverflow in PAD

There is a potential overflow in the PAD procedure: 

char padstring[512];
static char *PAD(char *string,size_t size) {
 fs_zero (padstring,sizeof(padstring));
 if ((size >= sizeof(padstring)) || (sizeof(string) >= size) ) return
(char *)string;
 memset (padstring,0x20,size);
 memcpy(padstring,string,strlen(string));
 return (char *)padstring;
}

The problem occurs because sizeof() was used on a pointer.
Exploitation is somewhat difficult, depending on the compiler used. This is 
because an attacker can only overflow a buffer on the .bss. 


13.) Potential buffer overflow in do_ascii 

void do_ascii ( char *msg,const char *target,size_t max) {
int o;
char *ptr;
ptr = (char *)target;
o=0;
while ( o <= (size_t) strnlen(msg,max) ) {
 if (msg[o] == '\n' ) *ptr ++ = '\r';
 *ptr ++= msg[o];
 o++;
}

It is obious that if msg < target and target contains enough '\n' characters 
that an overflow occurs. The bug in question can however not be exploited due 
to the programmer not calling his own procedure the way he intended to. 


14.) Funny logic bug in s_rename

There exists a logic bug in s_rename. A very strange condition in an 
if statement that can never be true: 

int s_rename (const char *src,const char *org_name,char *newname) {
 int i;
 if ( (strlen( src) < 5) && (strlen (src) > 128) ) return -1;
 ...
}

because something cannot be smaller then 5 AND bigger then 128 this 
is a void statement. Later bufferoverflows are possible. 


15.) Off-by-one underflow in do_append: 

There exists an off-by-one underflow in the appending of files if an 
unexpected error is returned by read(): 

do_append (char *filename) {
 ...
 do
 {
  numbytes +=strlen((char *)strip_nl(buffer));
  buffer[inc]='\0';   
  write (fin,buffer,inc);  
  memset (buffer,'\0',MAX_READ);
 } while ( (inc = read((int)con->usr_rel.req_sock,buffer,MAX_READ))  !=0 );
 ...
}


16.) Endless loop in get_data

char buffer[MAX_READ+3];
char *get_data(struct connection *conn){
int numbytes=0;
fs_zero(buffer,MAX_READ);
while ( numbytes=read (conn->fd,buffer,MAX_READ) <= 0 )
  buffer[numbytes]='\0';
return (char *)buffer;
}

This while loop here can cause an endless loop when disconnecting 
while reading. 


17.) Deleting and creating  any file or directory  on the system. 

The DELE, XMKD and XRMD commands do not check wether a certain user 
is allowed to delete or create  a file or directory. 

This unfortunate bug caused one of our researcher to loose some of his 
research data. 


18.) Potential information leak in do_eprt

int do_eprt ( void ){
 char ip[20];
 F_EPRT(u_com,ip,&port,&protocol,20);
 ...
}

int F_EPRT(const char *src, char *ip, long *port, int *protocol,int MAX_IP) {
 char **ok;
 int pos;

 if ((strlen(src)) <= 5) return -1;
 src += 5;
 ...
 ok = splitcmd ( src, '|' );
 if (calc_argc (ok)  !=2) return -1;
 ...
 strncpy(ip,ok[1],MAX_IP);
}

since strncpy() might not 0terminate it is possible to cause an
information leak
in do_eprt. 


19.) Logic bug in do_mlst

void do_mlst ( char *filename, int soc, int type) {
  ...
  if ( (filename[0]=='\0') && (strlen(filename) > 128) ) { send_data (
MSG_NO_SUCH_FD,soc); return ; }
  ...
}

The logic bug is located in the if-statement. If the first byte is a 0byte then 
strlen() cannot return anything else BUT 0. Hence this is a void statement.  


20.) Buffer overflow in do_mlst due to a logic bug

void do_mlst ( char *filename, int soc, int type) {
 struct stat status;
 struct utsname buf;
 int ret;
 char complete[512];
 ...
 sprintf( complete,
"type=%s;sized=%d;modify=%s;%s.mode=%o;%s.uid=%d;%s.gid=%d %s \r\n",
   S_ISDIR( status.st_mode ) ? "dir" : "file",
   status.st_size,
   mytime ( time((time_t *)status.st_mtime) , FORMAT_MDTM ),
   me,
   status.st_mode,
   me,
   status.st_uid,
   me,
   status.st_gid,
   filename);
 ...
}

Due do the logic bug described earlier the length of filename is
allowed to be longer
then 128. This might cause a bufferoverflow. 


21.) Integer overflows in dirlist

dirlist is a procedure inside ls.c it is indeed used to list whatever
is in directories.
The procedure itself has a few integer values used to hold information
about the directory
it's supposed to list: 

int bytes=0;
int files=0;
int folders=0;
int onefile=0;
int total=0;

Due to no checks whatsoover on any operations on these they can
overflow, or become negative
(since they are signed). This can cause more mischief later on. 


22.) Error in priviledge dropping

After logging in the rftpd daemon is supposed to drop all priviledges. 
This is done with seteuid() instead of setuid(). Hence only the
effective userid
gets dropped and can be regained with some of the vulnerabilities described 
earlier. 


some more funny things about rftpd and it's programmer:
*******************************************************

ftpd_core.c:322:
time_t start, finish;;
  dumbass, you dont need 2 semi-colons for 2 variables

if you don't use free() then you get memory starvation. 
 
<rave> you have to admit, rftpd is more secure then sphiro
  ?? you got that shiz right ! sphiro has even more bugs (see sphiro
advisory from slotto)

<de_aap> when is the next release of rftpd comming btw ? 
<rave> not soon
<de_aap> and you know the current one has major bugs ? 
<rave> yes
<de_aap> even though people are using it right now ? 
<de_aap> just check the source forge forum 
<rave> all those ppl are told about it 
<rave> so they know 
  ?? this is the same guy that stated his ftpd is more secure then
others and who is
     in a security group that releases exploits for sudo ! (that
particular exploit also
     had a few buffer overruns, but we'll save that for another
advisory :pPpPpPpPPp)

<rave> I dont even care what you think of my code but you will see
when i release it or
       parts of it you will not find as mutch or only minior bugs then
every project of
       mine before.
  ?? rave about his next 'secure' project (an ircd) my reply "We'll see :)"

<rave> neeh im a trained security engeneer
  ?? note his misspelling of engineer

<de_aap> rftpd is total crap 
<rave> 2.0 is for sure
<rave> i told you a 10000000 times
  ?? there you have it folks, on one side it's 'more secure then most
other ftpd's out there'
     and on the other it's total crap. this doesn't make sense, does it ?

<rave> rftpd is more secure then bulletproof ftpd and raiden ftpd 
<rave> it's not as secure as ftpd's that have been there for a long
time, like wu-ftpd

.. dustcloth [~dustcloth () mail bookfeel com] has joined #rosiello
... Topic (#rosiello): Rosiello Security http://www.rosiello.org | Rosiello
          Security won the InfoSecWriters contest of July | atm rftpd is being
          ported to win32 + mysql and PHP support will be added to the project
... Topic (#rosiello): set by rave at Mon Aug 30 14:43:51 2004
... [Users(#rosiello:14)]
[ dustcloth      ] [ giles_    ] [ jdag      ] [ () rave      ] [ Anix      ]
[ anthill   ] [ giles__   ] [ zeusfaber_] [ Guest     ] [ akriel    ]
[ nocturnal ] [ () angelo    ] [ anto^eof  ] [ chris     ]
... Channel #rosiello was created at Wed Aug 25 09:34:47 2004
... BitchX: Join to #rosiello was synched in 0.414 secs!!
<dustcloth> hello
<dustcloth> hello rave
<dustcloth> & angelo
<rave> hellow dust
<dustcloth> what do you mean php support?
<dustcloth> php in ftp?
<rave> we have a user nammager you can use on apache servers
<rave> as a website for admins like webmin
<dustcloth> ohhhhhhs
<dustcloth> nice
<dustcloth> secure too?
<rave> yes
<rave> sure
<angelo> hey ppl
<angelo> I'm waiting for punix to be ready
<angelo> she's getting sme phard
<angelo> :>
<angelo> hi dustcloth
<chris> dustcloth: hows xar these days
<dustcloth> i use rftpd on my webhost box to test
... SignOff giles__: #rosiello (Ping timeout)
<dustcloth> chris, he is ok
<angelo> rftpd will r0x
<dustcloth> i heard he had sex with a man at defcon though
<chris> its quite funny if you look who is logged into xar's box
<chris> theres one username which sticks out
<dustcloth> what name?
<angelo> dustcloth do u find rftpd ok?
<dustcloth> angelo, yes it's nice
<dustcloth> and secure
<chris> haha you are being bullshitted to hell
<angelo> good, I'm happy to hear it
<angelo> rave did u release the sec-pre 3 ?
<rave> no that will take a long time
<rave> i have to code getpwent wrappers
<rave> and set/get uid wrappers
<rave> and the sql code
<rave> and win32 user api`s
<rave> i need more coders
<rave> MORE MORE MORE !!!
<angelo> heh
<angelo> bro I suggest you to fix the sec-pre 2 and to release a stable one
<dustcloth> do u guys run rftpd?
<angelo> then you add new stuffs for the next releases
<rave> every one sayes yes i want to help out
<rave> but no one does shit
<dustcloth> sec-pre 2 is not stable?
<dustcloth> it hasnt crashed yet
<angelo> dustcloth it is but I mean on sf
<dustcloth> sf?
<rave> dustcloth ofcource we dont run our own stuff
<dustcloth> sorceforge?
<rave> only for testing
<dustcloth> why not run your own stuff?
<angelo> rave: release a stable version on sf
<rave> secpre 2 has a DOS
<rave> when u use a non existing user
<dustcloth> ohhh
<rave> you can crash the auth system
<dustcloth> but no remote exploits right?
<angelo> no dust
<chris> this conversation will be on FD all over again
<chris> why do you let it happen again
<rave> well the auth thing is known hehe
[msg(chris)] u not like me?
[chris(~chris () crew tkn us)] i hate liars
[msg(chris)] liars?
[msg(chris)] i not lie
[chris(~chris () crew tkn us)] k
[msg(chris)] am from france ok english not so good
[chris(~chris () crew tkn us)] it doesnt matter to me, its their loss
[chris(~chris () crew tkn us)] they are the ones being bullshitted
[msg(chris)] loldongs !!!!!!!
<rave> hahah yes sure we have milions of remote exploits ready for the server
<rave> and in time we release a bug for stupid ppl like sloth to laugh at and
          feel good
<rave> so we entertain the dogs from the drain
<rave> you ssee
<dustcloth> sloth is a nice guy :(
<rave> yeah when he dreams and keeps away from here he is
<dustcloth> you should just ban him
<rave> he is
<dustcloth> oh
<dustcloth> i wish i knew how to program c so i could help you
<dustcloth> but only i know scheme
<rave> if you buy a book you can learn C
<dustcloth> i can't read
<dustcloth> books i mean
<dustcloth> bad eyes
<rave> then read a Ebook


2.) Gaping security holes in rpf 1.2.2

Some background:
****************

rpf stands for rmp finder. According to rave (who thinks he coded it,
see log below)
It's in the mandrake packages. Our research pointed out that it is not!


Funny comments in the code: 
***************************
//      gets(command_line); Just to kill any bad idea


The gaping security holes:
**************************

1.) remotely exploitable bufferoverflow

When rpf connects to a webserver it uses a procedure web() to do the actual 
communicatio with the webserver. This procedure however contains a
bufferoverflow:

char *web(char *url, char *ip) {
char ch;
struct sockaddr_in server_addr;
 int PORT, sd, error, buffer, fd, begin;
 int register i, j;
 char get[256], memory[1024], cleaner[1024], old[1024], file[64];
 char capo = '\n';
 ...
        while(buffer != 0)
        {
                buffer = recv(sd, &ch, 1, 0);
                if(ch == '\n' || ch == ' ')
                {
                 ....
                }
                else if(ch != '\n' && ch != ' ')
                {
                                                                        
                        memory[i] = ch;
                        i++;
                }
        } 
 ...
}

Exploitation is trivial !


2.) Local file race condition. 

in that same web() procedure there is a file made to store some needed 
data: 

...
        sprintf(file, "/tmp/.rpf-%d", getuid());
        fd = open(file, O_CREAT | O_WRONLY | O_TRUNC, 0644);
...

There is however no check done if the file already exists or not. 
A symlink attack is possible allowing a potential attacker to truncate 
any file owned by the person running rpf. 


Afthermath: 
***********

There are various other overflows in rpf that are not exploitable due to 
the programmer (angelo) not free()'ing ANY memory as shown by our reseach: 
de_aap () monkeytown:~/rpf-1.2.2%grep "free *(" * -n -r | wc
      0       0       0
de_aap () monkeytown:~/rpf-1.2.2%

According to our calculations there are about one gazillion memory leaks 
in rpf. 

It also appears that the programmer (angelo) has never heard of memset and 
insists on clearing memory with ugly for loops. (note to angelo, in case you 
don't know most memset() implementations are optimized for this kind of 
stuff and it is advised that you use those.)

Some nice ircd logs about this: 
<rave> mine got on mandrake
<percy> what is in mandrake ?
<rave> percy the rpm tool
<rave> to find new updated rpm files
<percy> THATS ANGELOS TOOL YOU FAGGET
<percy> stop claiming other peoples achievements

greets: - boobys.org
        - toeters security labs
        - gobbles (personal hero !)
        - sorbo (italian maffia)
        - kokanin (woke up naked hugging his computer)
        - LOLDONGS.com
        - GeS
        - percy (doing it for the puppies since 2004)

super-secret hacker greetz:
  MRX, vect0rx, HexPhile, wormwood, t12 / tk421, MC m00, dyldo, DJ Tino,
  eating dead baby animals, chickens, kawanza, DJ Jackalope
_______________________________________________
Full-Disclosure - We believe in it.
Charter: http://lists.netsys.com/full-disclosure-charter.html


  By Date           By Thread  

Current thread:
  • multiple remote root vulns in Rosiello rFTPD and RPF Slotto Corleone (Dec 21)
[ Nmap | Sec Tools | Mailing Lists | Site News | About/Contact | Advertising | Privacy ]