injection_projection code
Mark Bucciarelli
mark at gaiahost.coop
Wed Jul 19 23:13:51 UTC 2006
Following up on the C CGI thread, I settled on the old cgiemail
program from MIT, deleted all the printf and html- and
url-encoding crap, and added code to protect against email header
injection.
If you see any holes in the injection_protection code, please let
me know--it turned out to be harder than I thought, mainly
because of hex encoding. Once I get a git repository up, this
will available as Free Software.
This only runs for the template variables that are replaced in
the email headers. I identify the headers by looking for two
linefeeds (or carriage returns, or carriage return+linefeeds) in
a row in the template.
As a little background, cgiemail lets you define a template and
with field names escaped in square brackets. Then you define the
form vars that match the field names and set the form action to
/cgi-bin/cgiemail/template.txt. It's another issue, but I don't
like that cgiemail uses PATH_TRANSLATED to lookup the template
file. PATH_TRANSLATED = DOCUMENT_ROOT + PATH_INFO, so you have
to put the template files in a place that is readable via a web
browser. Seems like the templates are better off in a cgi-bin
dir that is outside the document root.
/**
* Sanitize string to protect against email header injection.
*
* From my testing, a line feed encoded as "\%6e" is still a line feed
* according to sendmail. Get rid of hex encodeing before looking for
* nasties.
*
* This routine modifies the string passed in.
*/
void injection_protection( char *s )
{
char *injections[] = {
"\\n",
"\\r",
"\n",
"\r",
"content-type:",
"bcc:",
"to:",
"cc:"
};
char *cleaned;
char *p;
int i;
hex2char( s );
// If we find any injection text, drop whatever comes after it.
for ( i = 0; i < sizeof(injections)/sizeof(char*); i++ )
{
// s = "abcde\n"
// 0123456
// p = "\n"
// p - s = 5
p = strcasestr( s, injections[i] );
if ( p )
{
// MKB: TODO: log injection attempt.
if ( p - s > 0 )
strlcpy( s, s, p - s + 1 );
else
*s = '\0';
}
}
}
/**
* Convert all hex entries to char's in the given string.
*
* If hex code resolves to a non-printable character, just drop
* it.
*
* Return new string in the arg passed in.
*
*/
void hex2char( char * s )
{
char *cleaned;
char *p;
char *q;
char hex_string[3];
unsigned int hex_int;
cleaned = (char*) calloc(strlen(s) + 1, sizeof(char));
// Replace hex values with characters. If hex code references a
// non-printable character, drop it and continue with rest of string.
hex_string[2] = '\0';
p = s;
q = cleaned;
while ( *p )
{
if ( *p != '%' )
{
*q++ = *p++;
}
else
{
p++;
if ( *p )
{
hex_string[0] = *p++;
if ( *p )
hex_string[1] = *p++;
else
hex_string[1] = '\0';
sscanf(hex_string, "%x", &hex_int);
if( isprint(hex_int) )
{
*q++ = (char)hex_int;
}
if ( *p == '\0' )
*q = '\0';
}
else
{
// value terminates in a percentage sign.
*q++ = '%';
*q = '\0';
}
}
}
strcpy( s, cleaned );
free( cleaned );
}
More information about the freebsd-isp
mailing list