|
Save the teapot fund New CSS web design for Wibble proudly provided by Kelv. Please contact the webmaster with any questions or concerns. |
Wibble > List archives > bugtraq > 1998 [Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: Verity/Search'97 Security Problems
Here is a wrapper I just wrote to clean up ResultTemplate. It's
working for us. YMMV.
j.
--
Jay Soffian <jay@xxxxxxxxxxx> UNIX Systems Administrator
404.572.1941 Cox Interactive Media
/*
* Author: Jay Soffian <jay@xxxxxxxxxxx>
*
* Idea: s97_cgi doesn't check ResultTemplate for a valid path, so it
* is possible to read arbitrary files using something like
* ResultTemplate=../../../../../../etc/passwd
* This script decodes the input (from either a GET or a POST),
* cleans up ResultTemplate, then execs s97_cgi
*
* usage: copy s97_cgi, s97r_cgi, etc to s97_cgi.orig
* compile this program and install it as s97_cgi, s97r_cgi, etc
* in the same directory as s97_cgi.orig
*
* 16 July 98
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#define verity_path_pre "/path/to/directory/with/s97_cgi"
#define verity_path_post ".orig"
int num_params = 0;
typedef struct
{
char *name;
char *val;
} param;
char method;
#define MAX_PARAMS 1000
#define GET 'G'
#define POST 'P'
param params[MAX_PARAMS];
void die(char *logmsg, char *usermsg) {
if (!usermsg) usermsg = "internal error";
printf("Content-type: text/html\n\n");
printf("<HTML><HEAD>\n"
"<TITLE>Error</TITLE>\n"
"</HEAD><BODY>\n"
"<H1>Error</H1>\n"
"Error: %s<P>\n"
"Please try your request again.<P>\n"
"</BODY></HTML>\n", usermsg);
fprintf(stderr,logmsg);
exit(0);
}
char * escape(char *s) {
register unsigned char *a, *b;
char *buffer;
b = s;
a = buffer = (char *)malloc((strlen(s)*3)+1);
if (!buffer) die ("Internal error", "Out of memory while processing request");
while (*b) {
if (*b <= '\x20' || *b >= '\x7f' || strchr("\"#%;<>?{}|\\^~`[]&", *b)) {
*a++ = '%';
sprintf(a,"%0X",*b);
a+=2;
b++;
} else {
*a++ = *b++;
}
}
*a = '\0';
return buffer;
}
void unescape(char *s)
{
register unsigned char *a, *b;
if (!*s) return;
for ((a = b = s);(*a = *b); ++a, ++b) {
switch (*b) {
case '%':
if (*(b+1) && *(b+2)) {
*b = toupper(*b);
b++; *a = *b >= 'A' ? (((*b & 0xdf) - 'A') +10) : *b - '0';
*a *= 16;
b++; *a += *b >= 'A' ? (((*b & 0xdf) - 'A') +10) : *b - '0';
}
break;
case '+':
*a = ' ';
break;
}
}
}
void cgiinit(void)
{
int
content_length = 0,
i = 0;
char
*query = NULL,
*cp = NULL,
*request_method = getenv("REQUEST_METHOD");
if (!request_method) die("No REQUEST_METHOD", NULL);
if (!strcmp(request_method,"POST")) {
method = POST;
if(getenv("CONTENT_TYPE") &&
strcmp(getenv("CONTENT_TYPE"),"application/x-www-form-urlencoded"))
die("CONTENT_TYPE not application/x-www-form-urlencoded",
"CONTENT_TYPE must be 'application/x-www-form-urlencoded'.");
if (getenv("CONTENT_LENGTH")) content_length = atoi(getenv("CONTENT_LENGTH"));
else die("No CONTENT_LENGTH", NULL);
query = (char *)malloc(sizeof(char) * content_length + 1);
if (query == NULL) die ("malloc() failed",NULL);
if (fread(query,sizeof(char),content_length,stdin) != content_length)
die("Ran out of input while processing request", NULL);
query[content_length] = '\0';
} else if (!strcmp(request_method,"GET")) {
method = GET;
if (getenv("QUERY_STRING")) query = strdup(getenv("QUERY_STRING"));
else die("No QUERY_STRING",NULL);
if (!query) die ("malloc() failed",NULL);
} else {
die ("Method not GET nor POST", "Method must be 'GET' or 'POST'.");
}
/* input is in query. let's parse it. */
if (strchr(query,'=')) {
params[i].name = strtok(query, "&");
while ((++i < MAX_PARAMS) && (params[i].name = strtok(NULL, "&"))); /* tokenize */
num_params = i;
for(i=0; i < num_params; i++) {
if ((cp = strchr(params[i].name, '='))) {
*cp = '\0';
params[i].val = cp+1;
} else {
params[i].val = "";
}
unescape(params[i].name);
unescape(params[i].val);
}
} else {
unescape(query);
params[0].name = "keywords";
params[0].val = query;
num_params = 1;
}
}
void fixpath (register char * a)
{
register char *b = a;
if (!*a) return;
if (*a == '/') b++;
while (*b)
if (*b == '.' && *(b+1) == '.' && *(b+2) == '/') b+=3;
else *a++ = *b++;
*a = '\0';
}
char * makequery(void)
{
char * buf, *cp, *name, *val;
int i, tot_len = 0, len, size = 1024;
cp = buf = (char *)malloc(size);
if (!buf) die ("malloc() failed", NULL);
for (i=0; i<num_params; i++) {
name = escape(params[i].name);
val = escape(params[i].val);
tot_len += len = strlen(name) + strlen(val) + 2;
if (tot_len > size) {
size *=2;
buf = realloc(buf, size);
if (!buf) die ("realloc() failed", NULL);
}
sprintf(cp,"%s=%s&",name,val);
cp+=len; tot_len +=len;
free(name); free(val);
}
*(cp-1) = '\0';
return buf;
}
int main (int argc, char **argv)
{
int size, i, fd[2], pid;
char *query, *path, ssize[128], *buf;
path = strrchr(argv[0],'/');
if (!path) path = argv[0];
else path++;
buf = malloc(sizeof(verity_path_pre) +
sizeof(verity_path_post) + strlen(path) + 1);
if (!buf) die("malloc() failed", NULL);
sprintf(buf,"%s%s%s",verity_path_pre, path, verity_path_post);
path = buf;
cgiinit();
for (i=0; i<num_params; i++)
if (!strcasecmp(params[i].name, "ResultTemplate"))
fixpath(params[i].val);
query = makequery();
size = strlen(query);
if (method == GET) {
buf = (char*) malloc(sizeof("QUERY_STRING=") + size + 1);
if (!buf) die("malloc() failed", NULL);
sprintf(buf,"QUERY_STRING=%s",query);
if (putenv(buf)) die ("putenv() failed", NULL);
execv(path, argv);
die("execv() failed", NULL);
} else if (method == POST) {
sprintf(ssize,"CONTENT_LENGTH=%d",size);
if (putenv(ssize)) die("putenv() failed", NULL);
if ( pipe(fd) ) die("pipe() failed", NULL);
if ((pid = fork()) < 0) die("fork() failed", NULL);
if (!pid) { /* child */
close(fd[1]);
dup2(fd[0],0);
close(fd[0]);
execv(path, argv);
die("execv() failed", NULL);
} else { /* parent */
close(fd[0]);
dup2(fd[1],1);
close(fd[1]);
fwrite(query,sizeof(char),size,stdout);
exit(0);
}
} else {
die ("Method not GET nor POST", "Method must be 'GET' or 'POST'.");
}
exit(0);
}
Attachment Converted: "d:\apps\e-mail\eudorapro\attach\veritywrap.c"
|