Updates the libinjection
This commit is contained in:
Родитель
2c07a17fa3
Коммит
a4724dfdab
2
CHANGES
2
CHANGES
|
@ -1,6 +1,8 @@
|
|||
DD MMM YYYY - 2.9.2 - To be released
|
||||
------------------------------------
|
||||
|
||||
* Updates libinjection to: da027ab52f9cf14401dd92e34e6683d183bdb3b4
|
||||
[ModSecurity team]
|
||||
* {dis|en}able-handler-logging: Option to disable logging of Apache handler
|
||||
in audit log
|
||||
[Issue #1070, #1381 - Marc Stern]
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2012, 2013 Nick Galbreath
|
||||
* Copyright 2012-2016 Nick Galbreath
|
||||
* nickg@client9.com
|
||||
* BSD License -- see COPYING.txt for details
|
||||
*
|
||||
|
@ -7,8 +7,8 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#ifndef _LIBINJECTION_H
|
||||
#define _LIBINJECTION_H
|
||||
#ifndef LIBINJECTION_H
|
||||
#define LIBINJECTION_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
# define LIBINJECTION_BEGIN_DECLS extern "C" {
|
||||
|
@ -49,9 +49,9 @@ const char* libinjection_version(void);
|
|||
*/
|
||||
int libinjection_sqli(const char* s, size_t slen, char fingerprint[]);
|
||||
|
||||
/** ALPHA version of xss detector.
|
||||
/** ALPHA version of xss detector.
|
||||
*
|
||||
* NOT DONE.
|
||||
* NOT DONE.
|
||||
*
|
||||
* \param[in] s input string, may contain nulls, does not need to be null-terminated
|
||||
* \param[in] slen input string length
|
||||
|
@ -62,4 +62,4 @@ int libinjection_xss(const char* s, size_t slen);
|
|||
|
||||
LIBINJECTION_END_DECLS
|
||||
|
||||
#endif /* _LIBINJECTION_H */
|
||||
#endif /* LIBINJECTION_H */
|
||||
|
|
|
@ -71,20 +71,20 @@ void libinjection_h5_init(h5_state_t* hs, const char* s, size_t len, enum html5_
|
|||
|
||||
switch (flags) {
|
||||
case DATA_STATE:
|
||||
hs->state = h5_state_data;
|
||||
break;
|
||||
hs->state = h5_state_data;
|
||||
break;
|
||||
case VALUE_NO_QUOTE:
|
||||
hs->state = h5_state_before_attribute_name;
|
||||
break;
|
||||
hs->state = h5_state_before_attribute_name;
|
||||
break;
|
||||
case VALUE_SINGLE_QUOTE:
|
||||
hs->state = h5_state_attribute_value_single_quote;
|
||||
break;
|
||||
hs->state = h5_state_attribute_value_single_quote;
|
||||
break;
|
||||
case VALUE_DOUBLE_QUOTE:
|
||||
hs->state = h5_state_attribute_value_double_quote;
|
||||
break;
|
||||
hs->state = h5_state_attribute_value_double_quote;
|
||||
break;
|
||||
case VALUE_BACK_QUOTE:
|
||||
hs->state = h5_state_attribute_value_back_quote;
|
||||
break;
|
||||
hs->state = h5_state_attribute_value_back_quote;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,10 +100,18 @@ int libinjection_h5_next(h5_state_t* hs)
|
|||
/**
|
||||
* Everything below here is private
|
||||
*
|
||||
*/
|
||||
*/
|
||||
|
||||
|
||||
static int h5_is_white(char ch)
|
||||
{
|
||||
/*
|
||||
* \t = horizontal tab = 0x09
|
||||
* \n = newline = 0x0A
|
||||
* \v = vertical tab = 0x0B
|
||||
* \f = form feed = 0x0C
|
||||
* \r = cr = 0x0D
|
||||
*/
|
||||
return strchr(" \t\n\v\f\r", ch) != NULL;
|
||||
}
|
||||
|
||||
|
@ -112,19 +120,19 @@ static int h5_skip_white(h5_state_t* hs)
|
|||
char ch;
|
||||
while (hs->pos < hs->len) {
|
||||
ch = hs->s[hs->pos];
|
||||
switch (ch) {
|
||||
case 0x00: /* IE only */
|
||||
case 0x20:
|
||||
case 0x09:
|
||||
case 0x0A:
|
||||
case 0x0B: /* IE only */
|
||||
case 0x0C:
|
||||
switch (ch) {
|
||||
case 0x00: /* IE only */
|
||||
case 0x20:
|
||||
case 0x09:
|
||||
case 0x0A:
|
||||
case 0x0B: /* IE only */
|
||||
case 0x0C:
|
||||
case 0x0D: /* IE only */
|
||||
hs->pos += 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
default:
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
return CHAR_EOF;
|
||||
}
|
||||
|
@ -259,12 +267,12 @@ static int h5_state_tag_name(h5_state_t* hs)
|
|||
pos = hs->pos;
|
||||
while (pos < hs->len) {
|
||||
ch = hs->s[pos];
|
||||
if (ch == 0) {
|
||||
/* special non-standard case */
|
||||
/* allow nulls in tag name */
|
||||
/* some old browsers apparently allow and ignore them */
|
||||
pos += 1;
|
||||
} else if (h5_is_white(ch)) {
|
||||
if (ch == 0) {
|
||||
/* special non-standard case */
|
||||
/* allow nulls in tag name */
|
||||
/* some old browsers apparently allow and ignore them */
|
||||
pos += 1;
|
||||
} else if (h5_is_white(ch)) {
|
||||
hs->token_start = hs->s + hs->pos;
|
||||
hs->token_len = pos - hs->pos;
|
||||
hs->token_type = TAG_NAME_OPEN;
|
||||
|
@ -332,7 +340,7 @@ static int h5_state_before_attribute_name(h5_state_t* hs)
|
|||
default: {
|
||||
return h5_state_attribute_name(hs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int h5_state_attribute_name(h5_state_t* hs)
|
||||
|
@ -450,12 +458,12 @@ static int h5_state_attribute_value_quote(h5_state_t* hs, char qchar)
|
|||
TRACE();
|
||||
|
||||
/* skip initial quote in normal case.
|
||||
* dont do this is pos == 0 since it means we have started
|
||||
* don't do this "if (pos == 0)" since it means we have started
|
||||
* in a non-data state. given an input of '><foo
|
||||
* we want to make 0-length attribute name
|
||||
*/
|
||||
if (hs->pos > 0) {
|
||||
hs->pos += 1;
|
||||
hs->pos += 1;
|
||||
}
|
||||
|
||||
|
||||
|
@ -705,10 +713,13 @@ static int h5_state_comment(h5_state_t* hs)
|
|||
char ch;
|
||||
const char* idx;
|
||||
size_t pos;
|
||||
size_t offset;
|
||||
const char* end = hs->s + hs->len;
|
||||
|
||||
TRACE();
|
||||
pos = hs->pos;
|
||||
while (1) {
|
||||
|
||||
idx = (const char*) memchr(hs->s + pos, CHAR_DASH, hs->len - pos);
|
||||
|
||||
/* did not find anything or has less than 3 chars left */
|
||||
|
@ -719,21 +730,62 @@ static int h5_state_comment(h5_state_t* hs)
|
|||
hs->token_type = TAG_COMMENT;
|
||||
return 1;
|
||||
}
|
||||
ch = *(idx + 1);
|
||||
offset = 1;
|
||||
|
||||
/* skip all nulls */
|
||||
while (idx + offset < end && *(idx + offset) == 0) {
|
||||
offset += 1;
|
||||
}
|
||||
if (idx + offset == end) {
|
||||
hs->state = h5_state_eof;
|
||||
hs->token_start = hs->s + hs->pos;
|
||||
hs->token_len = hs->len - hs->pos;
|
||||
hs->token_type = TAG_COMMENT;
|
||||
return 1;
|
||||
}
|
||||
|
||||
ch = *(idx + offset);
|
||||
if (ch != CHAR_DASH && ch != CHAR_BANG) {
|
||||
pos = (size_t)(idx - hs->s) + 1;
|
||||
continue;
|
||||
}
|
||||
ch = *(idx + 2);
|
||||
|
||||
/* need to test */
|
||||
#if 0
|
||||
/* skip all nulls */
|
||||
while (idx + offset < end && *(idx + offset) == 0) {
|
||||
offset += 1;
|
||||
}
|
||||
if (idx + offset == end) {
|
||||
hs->state = h5_state_eof;
|
||||
hs->token_start = hs->s + hs->pos;
|
||||
hs->token_len = hs->len - hs->pos;
|
||||
hs->token_type = TAG_COMMENT;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
offset += 1;
|
||||
if (idx + offset == end) {
|
||||
hs->state = h5_state_eof;
|
||||
hs->token_start = hs->s + hs->pos;
|
||||
hs->token_len = hs->len - hs->pos;
|
||||
hs->token_type = TAG_COMMENT;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
ch = *(idx + offset);
|
||||
if (ch != CHAR_GT) {
|
||||
pos = (size_t)(idx - hs->s) + 1;
|
||||
continue;
|
||||
}
|
||||
offset += 1;
|
||||
|
||||
/* ends in --> or -!> */
|
||||
hs->token_start = hs->s + hs->pos;
|
||||
hs->token_len = (size_t)(idx - hs->s) - hs->pos;
|
||||
hs->pos = (size_t)(idx - hs->s) + 3;
|
||||
hs->pos = (size_t)(idx + offset - hs->s);
|
||||
hs->state = h5_state_data;
|
||||
hs->token_type = TAG_COMMENT;
|
||||
return 1;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/**
|
||||
* Copyright 2012,2013 Nick Galbreath
|
||||
* Copyright 2012,2016 Nick Galbreath
|
||||
* nickg@client9.com
|
||||
* BSD License -- see COPYING.txt for details
|
||||
*
|
||||
|
@ -112,15 +112,11 @@ memchr2(const char *haystack, size_t haystack_len, char c0, char c1)
|
|||
}
|
||||
|
||||
while (cur < last) {
|
||||
if (cur[0] == c0) {
|
||||
if (cur[1] == c1) {
|
||||
return cur;
|
||||
} else {
|
||||
cur += 2; /* (c0 == c1) ? 1 : 2; */
|
||||
}
|
||||
} else {
|
||||
cur += 1;
|
||||
/* safe since cur < len - 1 always */
|
||||
if (cur[0] == c0 && cur[1] == c1) {
|
||||
return cur;
|
||||
}
|
||||
cur += 1;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
@ -191,11 +187,11 @@ static int char_is_white(char ch) {
|
|||
/* ' ' space is 0x32
|
||||
'\t 0x09 \011 horizontal tab
|
||||
'\n' 0x0a \012 new line
|
||||
'\v' 0x0b \013 verical tab
|
||||
'\v' 0x0b \013 vertical tab
|
||||
'\f' 0x0c \014 new page
|
||||
'\r' 0x0d \015 carriage return
|
||||
0x00 \000 null (oracle)
|
||||
0xa0 \240 is latin1
|
||||
0xa0 \240 is Latin-1
|
||||
*/
|
||||
return strchr(" \t\n\v\f\r\240\000", ch) != NULL;
|
||||
}
|
||||
|
@ -294,7 +290,7 @@ static void st_clear(stoken_t * st)
|
|||
static void st_assign_char(stoken_t * st, const char stype, size_t pos, size_t len,
|
||||
const char value)
|
||||
{
|
||||
/* done to elimiate unused warning */
|
||||
/* done to eliminate unused warning */
|
||||
(void)len;
|
||||
st->type = (char) stype;
|
||||
st->pos = pos;
|
||||
|
@ -402,7 +398,7 @@ static size_t parse_eol_comment(struct libinjection_sqli_state * sf)
|
|||
}
|
||||
}
|
||||
|
||||
/** In Ansi mode, hash is an operator
|
||||
/** In ANSI mode, hash is an operator
|
||||
* In MYSQL mode, it's a EOL comment like '--'
|
||||
*/
|
||||
static size_t parse_hash(struct libinjection_sqli_state * sf)
|
||||
|
@ -842,7 +838,7 @@ static size_t parse_bstring(struct libinjection_sqli_state *sf)
|
|||
|
||||
/*
|
||||
* hex literal string
|
||||
* re: [XX]'[0123456789abcdefABCDEF]*'
|
||||
* re: [xX]'[0123456789abcdefABCDEF]*'
|
||||
* mysql has requirement of having EVEN number of chars,
|
||||
* but pgsql does not
|
||||
*/
|
||||
|
@ -1072,7 +1068,7 @@ static size_t parse_money(struct libinjection_sqli_state *sf)
|
|||
/* we have $foobar$ ... find it again */
|
||||
strend = my_memmem(cs+xlen+2, slen - (pos+xlen+2), cs + pos, xlen+2);
|
||||
|
||||
if (strend == NULL) {
|
||||
if (strend == NULL || ((size_t)(strend - cs) < (pos+xlen+2))) {
|
||||
/* fell off edge */
|
||||
st_assign(sf->current, TYPE_STRING, pos+xlen+2, slen - pos - xlen - 2, cs+pos+xlen+2);
|
||||
sf->current->str_open = '$';
|
||||
|
@ -1104,7 +1100,6 @@ static size_t parse_number(struct libinjection_sqli_state * sf)
|
|||
const char *cs = sf->s;
|
||||
const size_t slen = sf->slen;
|
||||
size_t pos = sf->pos;
|
||||
int have_dot = 0;
|
||||
int have_e = 0;
|
||||
int have_exp = 0;
|
||||
|
||||
|
@ -1136,7 +1131,6 @@ static size_t parse_number(struct libinjection_sqli_state * sf)
|
|||
}
|
||||
|
||||
if (pos < slen && cs[pos] == '.') {
|
||||
have_dot = 1;
|
||||
pos += 1;
|
||||
while (pos < slen && ISDIGIT(cs[pos])) {
|
||||
pos += 1;
|
||||
|
@ -1185,7 +1179,7 @@ static size_t parse_number(struct libinjection_sqli_state * sf)
|
|||
}
|
||||
}
|
||||
|
||||
if (have_dot == 1 && have_e == 1 && have_exp == 0) {
|
||||
if (have_e == 1 && have_exp == 0) {
|
||||
/* very special form of
|
||||
* "1234.e"
|
||||
* "10.10E"
|
||||
|
@ -1242,29 +1236,13 @@ int libinjection_sqli_tokenize(struct libinjection_sqli_state * sf)
|
|||
const unsigned char ch = (unsigned char) (s[*pos]);
|
||||
|
||||
/*
|
||||
* if not ascii, then continue...
|
||||
* actually probably need to just assuming
|
||||
* it's a string
|
||||
* look up the parser, and call it
|
||||
*
|
||||
* Porting Note: this is mapping of char to function
|
||||
* charparsers[ch]()
|
||||
*/
|
||||
if (ch > 127) {
|
||||
fnptr = char_parse_map[ch];
|
||||
|
||||
/* 160 or 0xA0 or octal 240 is "latin1 non-breaking space"
|
||||
* but is treated as a space in mysql.
|
||||
*/
|
||||
if (ch == 160) {
|
||||
fnptr = parse_white;
|
||||
} else {
|
||||
fnptr = parse_word;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* look up the parser, and call it
|
||||
*
|
||||
* Porting Note: this is mapping of char to function
|
||||
* charparsers[ch]()
|
||||
*/
|
||||
fnptr = char_parse_map[ch];
|
||||
}
|
||||
*pos = (*fnptr) (sf);
|
||||
|
||||
/*
|
||||
|
@ -1349,16 +1327,22 @@ static int syntax_merge_words(struct libinjection_sqli_state * sf,stoken_t * a,
|
|||
a->type == TYPE_UNION ||
|
||||
a->type == TYPE_FUNCTION ||
|
||||
a->type == TYPE_EXPRESSION ||
|
||||
a->type == TYPE_TSQL ||
|
||||
a->type == TYPE_SQLTYPE)) {
|
||||
return CHAR_NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (b->type != TYPE_KEYWORD && b->type != TYPE_BAREWORD &&
|
||||
b->type != TYPE_OPERATOR && b->type != TYPE_SQLTYPE &&
|
||||
b->type != TYPE_LOGIC_OPERATOR &&
|
||||
b->type != TYPE_FUNCTION &&
|
||||
b->type != TYPE_UNION && b->type != TYPE_EXPRESSION) {
|
||||
return CHAR_NULL;
|
||||
if (!
|
||||
(b->type == TYPE_KEYWORD ||
|
||||
b->type == TYPE_BAREWORD ||
|
||||
b->type == TYPE_OPERATOR ||
|
||||
b->type == TYPE_UNION ||
|
||||
b->type == TYPE_FUNCTION ||
|
||||
b->type == TYPE_EXPRESSION ||
|
||||
b->type == TYPE_TSQL ||
|
||||
b->type == TYPE_SQLTYPE ||
|
||||
b->type == TYPE_LOGIC_OPERATOR)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sz1 = a->len;
|
||||
|
@ -1374,7 +1358,6 @@ static int syntax_merge_words(struct libinjection_sqli_state * sf,stoken_t * a,
|
|||
tmp[sz1] = ' ';
|
||||
memcpy(tmp + sz1 + 1, b->val, sz2);
|
||||
tmp[sz3] = CHAR_NULL;
|
||||
|
||||
ch = sf->lookup(sf, LOOKUP_WORD, tmp, sz3);
|
||||
|
||||
if (ch != CHAR_NULL) {
|
||||
|
@ -1450,6 +1433,13 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf)
|
|||
sf->tokenvec[2].type == TYPE_COMMA &&
|
||||
sf->tokenvec[3].type == TYPE_LEFTPARENS &&
|
||||
sf->tokenvec[4].type == TYPE_NUMBER
|
||||
) ||
|
||||
(
|
||||
sf->tokenvec[0].type == TYPE_BAREWORD &&
|
||||
sf->tokenvec[1].type == TYPE_RIGHTPARENS &&
|
||||
sf->tokenvec[2].type == TYPE_OPERATOR &&
|
||||
sf->tokenvec[3].type == TYPE_LEFTPARENS &&
|
||||
sf->tokenvec[4].type == TYPE_BAREWORD
|
||||
)
|
||||
)
|
||||
{
|
||||
|
@ -1541,7 +1531,7 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf)
|
|||
continue;
|
||||
} else if ((sf->tokenvec[left].type == TYPE_BAREWORD || sf->tokenvec[left].type == TYPE_VARIABLE) &&
|
||||
sf->tokenvec[left+1].type == TYPE_LEFTPARENS && (
|
||||
/* TSQL functions but common enough to be collumn names */
|
||||
/* TSQL functions but common enough to be column names */
|
||||
cstrcasecmp("USER_ID", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 ||
|
||||
cstrcasecmp("USER_NAME", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0 ||
|
||||
|
||||
|
@ -1564,7 +1554,7 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf)
|
|||
|
||||
/* pos is the same
|
||||
* other conversions need to go here... for instance
|
||||
* password CAN be a function, coalese CAN be a function
|
||||
* password CAN be a function, coalesce CAN be a function
|
||||
*/
|
||||
sf->tokenvec[left].type = TYPE_FUNCTION;
|
||||
continue;
|
||||
|
@ -1828,7 +1818,7 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf)
|
|||
* 1,-sin(1) --> 1 (1)
|
||||
* Here, just do
|
||||
* 1,-sin(1) --> 1,sin(1)
|
||||
* just remove unary opartor
|
||||
* just remove unary operator
|
||||
*/
|
||||
st_copy(&sf->tokenvec[left+1], &sf->tokenvec[left+2]);
|
||||
pos -= 1;
|
||||
|
@ -1852,9 +1842,21 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sf)
|
|||
pos -= 1;
|
||||
left = 0;
|
||||
continue;
|
||||
} else if ((sf->tokenvec[left].type == TYPE_FUNCTION) &&
|
||||
(sf->tokenvec[left+1].type == TYPE_LEFTPARENS) &&
|
||||
(sf->tokenvec[left+2].type != TYPE_RIGHTPARENS)) {
|
||||
/*
|
||||
* whats going on here
|
||||
* Some SQL functions like USER() have 0 args
|
||||
* if we get User(foo), then User is not a function
|
||||
* This should be expanded since it eliminated a lot of false
|
||||
* positives.
|
||||
*/
|
||||
if (cstrcasecmp("USER", sf->tokenvec[left].val, sf->tokenvec[left].len) == 0) {
|
||||
sf->tokenvec[left].type = TYPE_BAREWORD;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* no folding -- assume left-most token is
|
||||
is good, now use the existing 2 tokens --
|
||||
do not get another
|
||||
|
@ -2019,7 +2021,7 @@ int libinjection_sqli_blacklist(struct libinjection_sqli_state* sql_state)
|
|||
}
|
||||
|
||||
/*
|
||||
* return TRUE if sqli, false is benign
|
||||
* return TRUE if SQLi, false is benign
|
||||
*/
|
||||
int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state)
|
||||
{
|
||||
|
@ -2033,10 +2035,10 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state)
|
|||
|
||||
if (tlen > 1 && sql_state->fingerprint[tlen-1] == TYPE_COMMENT) {
|
||||
/*
|
||||
* if ending comment is contains 'sp_password' then it's sqli!
|
||||
* if ending comment is contains 'sp_password' then it's SQLi!
|
||||
* MS Audit log apparently ignores anything with
|
||||
* 'sp_password' in it. Unable to find primary refernece to
|
||||
* this "feature" of SQL Server but seems to be known sqli
|
||||
* 'sp_password' in it. Unable to find primary reference to
|
||||
* this "feature" of SQL Server but seems to be known SQLi
|
||||
* technique
|
||||
*/
|
||||
if (my_memmem(sql_state->s, sql_state->slen,
|
||||
|
@ -2055,7 +2057,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state)
|
|||
|
||||
if (sql_state->fingerprint[1] == TYPE_UNION) {
|
||||
if (sql_state->stats_tokens == 2) {
|
||||
/* not sure why but 1U comes up in Sqli attack
|
||||
/* not sure why but 1U comes up in SQLi attack
|
||||
* likely part of parameter splitting/etc.
|
||||
* lots of reasons why "1 union" might be normal
|
||||
* input, so beep only if other SQLi things are present
|
||||
|
@ -2080,7 +2082,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state)
|
|||
|
||||
/*
|
||||
* for fingerprint like 'nc', only comments of /x are treated
|
||||
* as SQL... ending comments of "--" and "#" are not sqli
|
||||
* as SQL... ending comments of "--" and "#" are not SQLi
|
||||
*/
|
||||
if (sql_state->tokenvec[0].type == TYPE_BAREWORD &&
|
||||
sql_state->tokenvec[1].type == TYPE_COMMENT &&
|
||||
|
@ -2090,7 +2092,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state)
|
|||
}
|
||||
|
||||
/*
|
||||
* if '1c' ends with '/x' then it's sqli
|
||||
* if '1c' ends with '/x' then it's SQLi
|
||||
*/
|
||||
if (sql_state->tokenvec[0].type == TYPE_NUMBER &&
|
||||
sql_state->tokenvec[1].type == TYPE_COMMENT &&
|
||||
|
@ -2113,13 +2115,13 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state)
|
|||
if (sql_state->tokenvec[0].type == TYPE_NUMBER &&
|
||||
sql_state->tokenvec[1].type == TYPE_COMMENT) {
|
||||
if (sql_state->stats_tokens > 2) {
|
||||
/* we have some folding going on, highly likely sqli */
|
||||
/* we have some folding going on, highly likely SQLi */
|
||||
sql_state->reason = __LINE__;
|
||||
return TRUE;
|
||||
}
|
||||
/*
|
||||
* we check that next character after the number is either whitespace,
|
||||
* or '/' or a '-' ==> sqli.
|
||||
* or '/' or a '-' ==> SQLi.
|
||||
*/
|
||||
ch = sql_state->s[sql_state->tokenvec[0].len];
|
||||
if ( ch <= 32 ) {
|
||||
|
@ -2141,7 +2143,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state)
|
|||
}
|
||||
|
||||
/*
|
||||
* detect obvious sqli scans.. many people put '--' in plain text
|
||||
* detect obvious SQLi scans.. many people put '--' in plain text
|
||||
* so only detect if input ends with '--', e.g. 1-- but not 1-- foo
|
||||
*/
|
||||
if ((sql_state->tokenvec[1].len > 2)
|
||||
|
@ -2177,7 +2179,7 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state)
|
|||
}
|
||||
|
||||
/*
|
||||
* not sqli
|
||||
* not SQLi
|
||||
*/
|
||||
sql_state->reason = __LINE__;
|
||||
return FALSE;
|
||||
|
@ -2186,8 +2188,8 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state* sql_state)
|
|||
streq(sql_state->fingerprint, "1&1") ||
|
||||
streq(sql_state->fingerprint, "1&v") ||
|
||||
streq(sql_state->fingerprint, "1&s")) {
|
||||
/* 'sexy and 17' not sqli
|
||||
* 'sexy and 17<18' sqli
|
||||
/* 'sexy and 17' not SQLi
|
||||
* 'sexy and 17<18' SQLi
|
||||
*/
|
||||
if (sql_state->stats_tokens == 3) {
|
||||
sql_state->reason = __LINE__;
|
||||
|
@ -2243,7 +2245,7 @@ int libinjection_is_sqli(struct libinjection_sqli_state * sql_state)
|
|||
size_t slen = sql_state->slen;
|
||||
|
||||
/*
|
||||
* no input? not sqli
|
||||
* no input? not SQLi
|
||||
*/
|
||||
if (slen == 0) {
|
||||
return FALSE;
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
/**
|
||||
* Copyright 2012, 2013 Nick Galbreath
|
||||
* Copyright 2012-2016 Nick Galbreath
|
||||
* nickg@client9.com
|
||||
* BSD License -- see COPYING.txt for details
|
||||
* BSD License -- see `COPYING.txt` for details
|
||||
*
|
||||
* https://libinjection.client9.com/
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LIBINJECTION_SQLI_H
|
||||
#define _LIBINJECTION_SQLI_H
|
||||
#ifndef LIBINJECTION_SQLI_H
|
||||
#define LIBINJECTION_SQLI_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -53,7 +53,7 @@ struct libinjection_sqli_token {
|
|||
|
||||
/* count:
|
||||
* in type 'v', used for number of opening '@'
|
||||
* but maybe unsed in other contexts
|
||||
* but maybe used in other contexts
|
||||
*/
|
||||
int count;
|
||||
|
||||
|
@ -63,7 +63,7 @@ struct libinjection_sqli_token {
|
|||
typedef struct libinjection_sqli_token stoken_t;
|
||||
|
||||
/**
|
||||
* Pointer to function, takes cstr input,
|
||||
* Pointer to function, takes c-string input,
|
||||
* returns '\0' for no match, else a char
|
||||
*/
|
||||
struct libinjection_sqli_state;
|
||||
|
@ -97,7 +97,7 @@ struct libinjection_sqli_state {
|
|||
int flags;
|
||||
|
||||
/*
|
||||
* pos is index in string we are at when tokenizing
|
||||
* pos is the index in the string during tokenization
|
||||
*/
|
||||
size_t pos;
|
||||
|
||||
|
@ -118,7 +118,7 @@ struct libinjection_sqli_state {
|
|||
/*
|
||||
* fingerprint pattern c-string
|
||||
* +1 for ending null
|
||||
* Mimimum of 8 bytes to add gcc's -fstack-protector to work
|
||||
* Minimum of 8 bytes to add gcc's -fstack-protector to work
|
||||
*/
|
||||
char fingerprint[8];
|
||||
|
||||
|
@ -156,7 +156,7 @@ struct libinjection_sqli_state {
|
|||
*/
|
||||
int stats_comment_c;
|
||||
|
||||
/* '#' operators or mysql EOL comments found
|
||||
/* '#' operators or MySQL EOL comments found
|
||||
*
|
||||
*/
|
||||
int stats_comment_hash;
|
||||
|
@ -208,8 +208,8 @@ void libinjection_sqli_init(struct libinjection_sqli_state* sql_state,
|
|||
*/
|
||||
int libinjection_is_sqli(struct libinjection_sqli_state* sql_state);
|
||||
|
||||
/* FOR H@CKERS ONLY
|
||||
*
|
||||
/* FOR HACKERS ONLY
|
||||
* provides deep hooks into the decision making process
|
||||
*/
|
||||
void libinjection_sqli_callback(struct libinjection_sqli_state* sql_state,
|
||||
ptr_lookup_fn fn,
|
||||
|
@ -269,7 +269,7 @@ int libinjection_sqli_fold(struct libinjection_sqli_state * sql_state);
|
|||
* two functions. With this, you over-ride one part or the other.
|
||||
*
|
||||
* return libinjection_sqli_blacklist(sql_state) &&
|
||||
* libinject_sqli_not_whitelist(sql_state);
|
||||
* libinjection_sqli_not_whitelist(sql_state);
|
||||
*
|
||||
* \param sql_state should be filled out after libinjection_sqli_fingerprint is called
|
||||
*/
|
||||
|
@ -284,7 +284,7 @@ int libinjection_sqli_blacklist(struct libinjection_sqli_state* sql_state);
|
|||
/* Given a positive match for a pattern (i.e. pattern is SQLi), this function
|
||||
* does additional analysis to reduce false positives.
|
||||
*
|
||||
* \return TRUE if sqli, false otherwise
|
||||
* \return TRUE if SQLi, false otherwise
|
||||
*/
|
||||
int libinjection_sqli_not_whitelist(struct libinjection_sqli_state * sql_state);
|
||||
|
||||
|
@ -292,4 +292,4 @@ int libinjection_sqli_not_whitelist(struct libinjection_sqli_state * sql_state);
|
|||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBINJECTION_SQLI_H */
|
||||
#endif /* LIBINJECTION_SQLI_H */
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -6,13 +6,6 @@
|
|||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef DEBUG
|
||||
#include <stdio.h>
|
||||
#define TRACE() printf("%s:%d\n", __FUNCTION__, __LINE__)
|
||||
#else
|
||||
#define TRACE()
|
||||
#endif
|
||||
|
||||
typedef enum attribute {
|
||||
TYPE_NONE
|
||||
, TYPE_BLACK /* ban always */
|
||||
|
@ -37,109 +30,109 @@ typedef struct stringtype {
|
|||
|
||||
|
||||
static const int gsHexDecodeMap[256] = {
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 256, 256,
|
||||
256, 256, 256, 256, 256, 10, 11, 12, 13, 14, 15, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 10, 11, 12, 13, 14, 15, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 256, 256,
|
||||
256, 256, 256, 256, 256, 10, 11, 12, 13, 14, 15, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 10, 11, 12, 13, 14, 15, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
|
||||
256, 256, 256, 256
|
||||
};
|
||||
|
||||
static int html_decode_char_at(const char* src, size_t len, size_t* consumed)
|
||||
{
|
||||
int val = 0;
|
||||
size_t i;
|
||||
int ch;
|
||||
int val = 0;
|
||||
size_t i;
|
||||
int ch;
|
||||
|
||||
if (len == 0 || src == NULL) {
|
||||
*consumed = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*consumed = 1;
|
||||
if (*src != '&' || len < 2) {
|
||||
return (unsigned char)(*src);
|
||||
}
|
||||
|
||||
|
||||
if (*(src+1) != '#') {
|
||||
/* normally this would be for named entities
|
||||
* but for this case we don't actually care
|
||||
*/
|
||||
return '&';
|
||||
}
|
||||
|
||||
if (*(src+2) == 'x' || *(src+2) == 'X') {
|
||||
ch = (unsigned char) (*(src+3));
|
||||
ch = gsHexDecodeMap[ch];
|
||||
if (ch == 256) {
|
||||
/* degenerate case '&#[?]' */
|
||||
return '&';
|
||||
if (len == 0 || src == NULL) {
|
||||
*consumed = 0;
|
||||
return -1;
|
||||
}
|
||||
val = ch;
|
||||
i = 4;
|
||||
while (i < len) {
|
||||
ch = (unsigned char) src[i];
|
||||
if (ch == ';') {
|
||||
*consumed = i + 1;
|
||||
return val;
|
||||
}
|
||||
ch = gsHexDecodeMap[ch];
|
||||
if (ch == 256) {
|
||||
*consumed = i;
|
||||
return val;
|
||||
}
|
||||
val = (val * 16) + ch;
|
||||
if (val > 0x1000FF) {
|
||||
return '&';
|
||||
}
|
||||
++i;
|
||||
|
||||
*consumed = 1;
|
||||
if (*src != '&' || len < 2) {
|
||||
return (unsigned char)(*src);
|
||||
}
|
||||
*consumed = i;
|
||||
return val;
|
||||
} else {
|
||||
i = 2;
|
||||
ch = (unsigned char) src[i];
|
||||
if (ch < '0' || ch > '9') {
|
||||
return '&';
|
||||
|
||||
|
||||
if (*(src+1) != '#') {
|
||||
/* normally this would be for named entities
|
||||
* but for this case we don't actually care
|
||||
*/
|
||||
return '&';
|
||||
}
|
||||
val = ch - '0';
|
||||
i += 1;
|
||||
while (i < len) {
|
||||
ch = (unsigned char) src[i];
|
||||
if (ch == ';') {
|
||||
*consumed = i + 1;
|
||||
return val;
|
||||
}
|
||||
if (ch < '0' || ch > '9') {
|
||||
*consumed = i;
|
||||
return val;
|
||||
}
|
||||
val = (val * 10) + (ch - '0');
|
||||
if (val > 0x1000FF) {
|
||||
return '&';
|
||||
}
|
||||
++i;
|
||||
|
||||
if (*(src+2) == 'x' || *(src+2) == 'X') {
|
||||
ch = (unsigned char) (*(src+3));
|
||||
ch = gsHexDecodeMap[ch];
|
||||
if (ch == 256) {
|
||||
/* degenerate case '&#[?]' */
|
||||
return '&';
|
||||
}
|
||||
val = ch;
|
||||
i = 4;
|
||||
while (i < len) {
|
||||
ch = (unsigned char) src[i];
|
||||
if (ch == ';') {
|
||||
*consumed = i + 1;
|
||||
return val;
|
||||
}
|
||||
ch = gsHexDecodeMap[ch];
|
||||
if (ch == 256) {
|
||||
*consumed = i;
|
||||
return val;
|
||||
}
|
||||
val = (val * 16) + ch;
|
||||
if (val > 0x1000FF) {
|
||||
return '&';
|
||||
}
|
||||
++i;
|
||||
}
|
||||
*consumed = i;
|
||||
return val;
|
||||
} else {
|
||||
i = 2;
|
||||
ch = (unsigned char) src[i];
|
||||
if (ch < '0' || ch > '9') {
|
||||
return '&';
|
||||
}
|
||||
val = ch - '0';
|
||||
i += 1;
|
||||
while (i < len) {
|
||||
ch = (unsigned char) src[i];
|
||||
if (ch == ';') {
|
||||
*consumed = i + 1;
|
||||
return val;
|
||||
}
|
||||
if (ch < '0' || ch > '9') {
|
||||
*consumed = i;
|
||||
return val;
|
||||
}
|
||||
val = (val * 10) + (ch - '0');
|
||||
if (val > 0x1000FF) {
|
||||
return '&';
|
||||
}
|
||||
++i;
|
||||
}
|
||||
*consumed = i;
|
||||
return val;
|
||||
}
|
||||
*consumed = i;
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -157,7 +150,7 @@ static stringtype_t BLACKATTR[] = {
|
|||
, { "DATASRC", TYPE_BLACK } /* IE */
|
||||
, { "DYNSRC", TYPE_ATTR_URL } /* Obsolete img attribute */
|
||||
, { "FILTER", TYPE_STYLE } /* Opera, SVG inline style */
|
||||
, { "FORMACTION", TYPE_ATTR_URL } /* HTML5 */
|
||||
, { "FORMACTION", TYPE_ATTR_URL } /* HTML 5 */
|
||||
, { "FOLDER", TYPE_ATTR_URL } /* Only on A tags, IE-only */
|
||||
, { "FROM", TYPE_ATTR_URL } /* SVG */
|
||||
, { "HANDLER", TYPE_ATTR_URL } /* SVG Tiny, Opera */
|
||||
|
@ -173,20 +166,20 @@ static stringtype_t BLACKATTR[] = {
|
|||
};
|
||||
|
||||
/* xmlns */
|
||||
/* xml-stylesheet > <eval>, <if expr=> */
|
||||
/* `xml-stylesheet` > <eval>, <if expr=> */
|
||||
|
||||
/*
|
||||
static const char* BLACKATTR[] = {
|
||||
"ATTRIBUTENAME",
|
||||
"BACKGROUND",
|
||||
"DATAFORMATAS",
|
||||
"HREF",
|
||||
"SCROLL",
|
||||
"SRC",
|
||||
"STYLE",
|
||||
"SRCDOC",
|
||||
NULL
|
||||
};
|
||||
static const char* BLACKATTR[] = {
|
||||
"ATTRIBUTENAME",
|
||||
"BACKGROUND",
|
||||
"DATAFORMATAS",
|
||||
"HREF",
|
||||
"SCROLL",
|
||||
"SRC",
|
||||
"STYLE",
|
||||
"SRCDOC",
|
||||
NULL
|
||||
};
|
||||
*/
|
||||
|
||||
static const char* BLACKTAG[] = {
|
||||
|
@ -220,36 +213,36 @@ static const char* BLACKTAG[] = {
|
|||
|
||||
static int cstrcasecmp_with_null(const char *a, const char *b, size_t n)
|
||||
{
|
||||
char ca;
|
||||
char cb;
|
||||
/* printf("Comparing to %s %.*s\n", a, (int)n, b); */
|
||||
while (n-- > 0) {
|
||||
cb = *b++;
|
||||
if (cb == '\0') continue;
|
||||
char ca;
|
||||
char cb;
|
||||
/* printf("Comparing to %s %.*s\n", a, (int)n, b); */
|
||||
while (n-- > 0) {
|
||||
cb = *b++;
|
||||
if (cb == '\0') continue;
|
||||
|
||||
ca = *a++;
|
||||
ca = *a++;
|
||||
|
||||
if (cb >= 'a' && cb <= 'z') {
|
||||
cb -= 0x20;
|
||||
if (cb >= 'a' && cb <= 'z') {
|
||||
cb -= 0x20;
|
||||
}
|
||||
/* printf("Comparing %c vs %c with %d left\n", ca, cb, (int)n); */
|
||||
if (ca != cb) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* printf("Comparing %c vs %c with %d left\n", ca, cb, (int)n); */
|
||||
if (ca != cb) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (*a == 0) {
|
||||
/* printf(" MATCH \n"); */
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
if (*a == 0) {
|
||||
/* printf(" MATCH \n"); */
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Does an HTML encoded binary string (const char*, lenght) start with
|
||||
* a all uppercase c-string (null terminated), case insenstive!
|
||||
*
|
||||
* Does an HTML encoded binary string (const char*, length) start with
|
||||
* a all uppercase c-string (null terminated), case insensitive!
|
||||
*
|
||||
* also ignore any embedded nulls in the HTML string!
|
||||
*
|
||||
* return 1 if match / starts with
|
||||
|
@ -257,47 +250,47 @@ static int cstrcasecmp_with_null(const char *a, const char *b, size_t n)
|
|||
*/
|
||||
static int htmlencode_startswith(const char *a, const char *b, size_t n)
|
||||
{
|
||||
size_t consumed;
|
||||
int cb;
|
||||
int first = 1;
|
||||
/* printf("Comparing %s with %.*s\n", a,(int)n,b); */
|
||||
size_t consumed;
|
||||
int cb;
|
||||
int first = 1;
|
||||
/* printf("Comparing %s with %.*s\n", a,(int)n,b); */
|
||||
while (n > 0) {
|
||||
if (*a == 0) {
|
||||
/* printf("Match EOL!\n"); */
|
||||
return 1;
|
||||
}
|
||||
cb = html_decode_char_at(b, n, &consumed);
|
||||
b += consumed;
|
||||
n -= consumed;
|
||||
if (*a == 0) {
|
||||
/* printf("Match EOL!\n"); */
|
||||
return 1;
|
||||
}
|
||||
cb = html_decode_char_at(b, n, &consumed);
|
||||
b += consumed;
|
||||
n -= consumed;
|
||||
|
||||
if (first && cb <= 32) {
|
||||
/* ignore all leading whitespace and control characters */
|
||||
continue;
|
||||
}
|
||||
first = 0;
|
||||
if (first && cb <= 32) {
|
||||
/* ignore all leading whitespace and control characters */
|
||||
continue;
|
||||
}
|
||||
first = 0;
|
||||
|
||||
if (cb == 0) {
|
||||
/* always ignore null characters in user input */
|
||||
continue;
|
||||
}
|
||||
/* always ignore null characters in user input */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cb == 10) {
|
||||
/* always ignore vtab characters in user input */
|
||||
/* who allows this?? */
|
||||
continue;
|
||||
}
|
||||
/* always ignore vertical tab characters in user input */
|
||||
/* who allows this?? */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cb >= 'a' && cb <= 'z') {
|
||||
/* upcase */
|
||||
/* upcase */
|
||||
cb -= 0x20;
|
||||
}
|
||||
|
||||
if (*a != (char) cb) {
|
||||
/* printf(" %c != %c\n", *a, cb); */
|
||||
/* mismatch */
|
||||
return 0;
|
||||
/* printf(" %c != %c\n", *a, cb); */
|
||||
/* mismatch */
|
||||
return 0;
|
||||
}
|
||||
a++;
|
||||
a++;
|
||||
}
|
||||
|
||||
return (*a == 0) ? 1 : 0;
|
||||
|
@ -313,8 +306,8 @@ static int is_black_tag(const char* s, size_t len)
|
|||
|
||||
black = BLACKTAG;
|
||||
while (*black != NULL) {
|
||||
if (cstrcasecmp_with_null(*black, s, len) == 0) {
|
||||
/* printf("Got black tag %s\n", *black); */
|
||||
if (cstrcasecmp_with_null(*black, s, len) == 0) {
|
||||
/* printf("Got black tag %s\n", *black); */
|
||||
return 1;
|
||||
}
|
||||
black += 1;
|
||||
|
@ -324,7 +317,7 @@ static int is_black_tag(const char* s, size_t len)
|
|||
if ((s[0] == 's' || s[0] == 'S') &&
|
||||
(s[1] == 'v' || s[1] == 'V') &&
|
||||
(s[2] == 'g' || s[2] == 'G')) {
|
||||
/* printf("Got SVG tag \n"); */
|
||||
/* printf("Got SVG tag \n"); */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -332,7 +325,7 @@ static int is_black_tag(const char* s, size_t len)
|
|||
if ((s[0] == 'x' || s[0] == 'X') &&
|
||||
(s[1] == 's' || s[1] == 'S') &&
|
||||
(s[2] == 'l' || s[2] == 'L')) {
|
||||
/* printf("Got XSL tag\n"); */
|
||||
/* printf("Got XSL tag\n"); */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -347,9 +340,9 @@ static attribute_t is_black_attr(const char* s, size_t len)
|
|||
return TYPE_NONE;
|
||||
}
|
||||
|
||||
/* javascript on.* */
|
||||
/* JavaScript on.* */
|
||||
if ((s[0] == 'o' || s[0] == 'O') && (s[1] == 'n' || s[1] == 'N')) {
|
||||
/* printf("Got javascript on- attribute name\n"); */
|
||||
/* printf("Got JavaScript on- attribute name\n"); */
|
||||
return TYPE_BLACK;
|
||||
}
|
||||
|
||||
|
@ -357,7 +350,7 @@ static attribute_t is_black_attr(const char* s, size_t len)
|
|||
if (len >= 5) {
|
||||
/* XMLNS can be used to create arbitrary tags */
|
||||
if (cstrcasecmp_with_null("XMLNS", s, 5) == 0 || cstrcasecmp_with_null("XLINK", s, 5) == 0) {
|
||||
/* printf("Got XMLNS and XLINK tags\n"); */
|
||||
/* printf("Got XMLNS and XLINK tags\n"); */
|
||||
return TYPE_BLACK;
|
||||
}
|
||||
}
|
||||
|
@ -365,7 +358,7 @@ static attribute_t is_black_attr(const char* s, size_t len)
|
|||
black = BLACKATTR;
|
||||
while (black->name != NULL) {
|
||||
if (cstrcasecmp_with_null(black->name, s, len) == 0) {
|
||||
/* printf("Got banned attribute name %s\n", black->name); */
|
||||
/* printf("Got banned attribute name %s\n", black->name); */
|
||||
return black->atype;
|
||||
}
|
||||
black += 1;
|
||||
|
@ -387,20 +380,18 @@ static int is_black_url(const char* s, size_t len)
|
|||
static const char* javascript_url = "JAVA";
|
||||
|
||||
/* skip whitespace */
|
||||
while (len > 0) {
|
||||
while (len > 0 && (*s <= 32 || *s >= 127)) {
|
||||
/*
|
||||
* HEY: this is a signed character.
|
||||
* We are intentionally skipping high-bit characters too
|
||||
* since they are not ascii, and Opera sometimes uses UTF8 whitespace
|
||||
* since they are not ASCII, and Opera sometimes uses UTF-8 whitespace.
|
||||
*
|
||||
* Also in EUC-JP some of the high bytes are just ignored.
|
||||
*/
|
||||
if (*s <= 32) {
|
||||
++s;
|
||||
--len;
|
||||
}
|
||||
break;
|
||||
++s;
|
||||
--len;
|
||||
}
|
||||
|
||||
|
||||
if (htmlencode_startswith(data_url, s, len)) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -442,16 +433,16 @@ int libinjection_is_xss(const char* s, size_t len, int flags)
|
|||
/*
|
||||
* IE6,7,8 parsing works a bit differently so
|
||||
* a whole <script> or other black tag might be hiding
|
||||
* inside an attribute value under HTML5 parsing
|
||||
* inside an attribute value under HTML 5 parsing
|
||||
* See http://html5sec.org/#102
|
||||
* to avoid doing a full reparse of the value, just
|
||||
* look for "<". This probably need adjusting to
|
||||
* handle escaped characters
|
||||
*/
|
||||
/*
|
||||
if (memchr(h5.token_start, '<', h5.token_len) != NULL) {
|
||||
return 1;
|
||||
}
|
||||
if (memchr(h5.token_start, '<', h5.token_len) != NULL) {
|
||||
return 1;
|
||||
}
|
||||
*/
|
||||
|
||||
switch (attr) {
|
||||
|
@ -473,13 +464,13 @@ int libinjection_is_xss(const char* s, size_t len, int flags)
|
|||
}
|
||||
break;
|
||||
/*
|
||||
default:
|
||||
assert(0);
|
||||
default:
|
||||
assert(0);
|
||||
*/
|
||||
}
|
||||
attr = TYPE_NONE;
|
||||
} else if (h5.token_type == TAG_COMMENT) {
|
||||
/* IE uses a "`" as a tag ending char */
|
||||
/* IE uses a "`" as a tag ending char */
|
||||
if (memchr(h5.token_start, '`', h5.token_len) != NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -491,7 +482,7 @@ int libinjection_is_xss(const char* s, size_t len, int flags)
|
|||
(h5.token_start[2] == 'f' || h5.token_start[2] == 'F')) {
|
||||
return 1;
|
||||
}
|
||||
if ((h5.token_start[0] == 'x' || h5.token_start[1] == 'X') &&
|
||||
if ((h5.token_start[0] == 'x' || h5.token_start[0] == 'X') &&
|
||||
(h5.token_start[1] == 'm' || h5.token_start[1] == 'M') &&
|
||||
(h5.token_start[2] == 'l' || h5.token_start[2] == 'L')) {
|
||||
return 1;
|
||||
|
@ -499,7 +490,7 @@ int libinjection_is_xss(const char* s, size_t len, int flags)
|
|||
}
|
||||
|
||||
if (h5.token_len > 5) {
|
||||
/* IE <?import pseudo-tag */
|
||||
/* IE <?import pseudo-tag */
|
||||
if (cstrcasecmp_with_null("IMPORT", h5.token_start, 6) == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
@ -519,22 +510,22 @@ int libinjection_is_xss(const char* s, size_t len, int flags)
|
|||
* wrapper
|
||||
*/
|
||||
int libinjection_xss(const char* s, size_t len)
|
||||
{
|
||||
if (libinjection_is_xss(s, len, DATA_STATE)) {
|
||||
return 1;
|
||||
}
|
||||
if (libinjection_is_xss(s, len, VALUE_NO_QUOTE)) {
|
||||
return 1;
|
||||
}
|
||||
if (libinjection_is_xss(s, len, VALUE_SINGLE_QUOTE)) {
|
||||
return 1;
|
||||
}
|
||||
if (libinjection_is_xss(s, len, VALUE_DOUBLE_QUOTE)) {
|
||||
return 1;
|
||||
}
|
||||
if (libinjection_is_xss(s, len, VALUE_BACK_QUOTE)) {
|
||||
return 1;
|
||||
}
|
||||
{
|
||||
if (libinjection_is_xss(s, len, DATA_STATE)) {
|
||||
return 1;
|
||||
}
|
||||
if (libinjection_is_xss(s, len, VALUE_NO_QUOTE)) {
|
||||
return 1;
|
||||
}
|
||||
if (libinjection_is_xss(s, len, VALUE_SINGLE_QUOTE)) {
|
||||
return 1;
|
||||
}
|
||||
if (libinjection_is_xss(s, len, VALUE_DOUBLE_QUOTE)) {
|
||||
return 1;
|
||||
}
|
||||
if (libinjection_is_xss(s, len, VALUE_BACK_QUOTE)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче