313 lines
8.0 KiB
C
313 lines
8.0 KiB
C
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <glob.h>
|
|
#include "libinjection.h"
|
|
#include "libinjection_sqli.h"
|
|
#include "libinjection_html5.h"
|
|
#include "libinjection_xss.h"
|
|
|
|
static char g_test[8096];
|
|
static char g_input[8096];
|
|
static char g_expected[8096];
|
|
|
|
size_t modp_rtrim(char* str, size_t len);
|
|
size_t print_string(char* buf, size_t len, stoken_t* t);
|
|
size_t print_var(char* buf, size_t len, stoken_t* t);
|
|
size_t print_token(char* buf, size_t len, stoken_t *t);
|
|
int read_file(const char* fname, int flags, int testtype);
|
|
const char* h5_type_to_string(enum html5_type x);
|
|
size_t print_html5_token(char* buf, size_t len, h5_state_t* hs);
|
|
|
|
size_t modp_rtrim(char* str, size_t len)
|
|
{
|
|
while (len) {
|
|
char c = str[len -1];
|
|
if (c == ' ' || c == '\n' || c == '\t' || c == '\r') {
|
|
str[len -1] = '\0';
|
|
len -= 1;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
return len;
|
|
}
|
|
|
|
size_t print_string(char* buf, size_t len, stoken_t* t)
|
|
{
|
|
int slen = 0;
|
|
|
|
/* print opening quote */
|
|
if (t->str_open != '\0') {
|
|
slen = sprintf(buf + len, "%c", t->str_open);
|
|
assert(slen >= 0);
|
|
len += (size_t) slen;
|
|
}
|
|
|
|
/* print content */
|
|
slen = sprintf(buf + len, "%s", t->val);
|
|
assert(slen >= 0);
|
|
len += (size_t) slen;
|
|
|
|
/* print closing quote */
|
|
if (t->str_close != '\0') {
|
|
slen = sprintf(buf + len, "%c", t->str_close);
|
|
assert(slen >= 0);
|
|
len += (size_t) slen;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
size_t print_var(char* buf, size_t len, stoken_t* t)
|
|
{
|
|
int slen = 0;
|
|
if (t->count >= 1) {
|
|
slen = sprintf(buf + len, "%c", '@');
|
|
assert(slen >= 0);
|
|
len += (size_t) slen;
|
|
}
|
|
if (t->count == 2) {
|
|
slen = sprintf(buf + len, "%c", '@');
|
|
assert(slen >= 0);
|
|
len += (size_t) slen;
|
|
}
|
|
return print_string(buf, len, t);
|
|
}
|
|
|
|
const char* h5_type_to_string(enum html5_type x)
|
|
{
|
|
switch (x) {
|
|
case DATA_TEXT: return "DATA_TEXT";
|
|
case TAG_NAME_OPEN: return "TAG_NAME_OPEN";
|
|
case TAG_NAME_CLOSE: return "TAG_NAME_CLOSE";
|
|
case TAG_NAME_SELFCLOSE: return "TAG_NAME_SELFCLOSE";
|
|
case TAG_DATA: return "TAG_DATA";
|
|
case TAG_CLOSE: return "TAG_CLOSE";
|
|
case ATTR_NAME: return "ATTR_NAME";
|
|
case ATTR_VALUE: return "ATTR_VALUE";
|
|
case TAG_COMMENT: return "TAG_COMMENT";
|
|
case DOCTYPE: return "DOCTYPE";
|
|
default:
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
size_t print_html5_token(char* buf, size_t len, h5_state_t* hs)
|
|
{
|
|
int slen;
|
|
char* tmp = (char*) malloc(hs->token_len + 1);
|
|
memcpy(tmp, hs->token_start, hs->token_len);
|
|
/* TODO.. encode to be printable */
|
|
tmp[hs->token_len] = '\0';
|
|
|
|
slen = sprintf(buf + len, "%s,%d,%s\n",
|
|
h5_type_to_string(hs->token_type),
|
|
(int) hs->token_len,
|
|
tmp);
|
|
len += (size_t) slen;
|
|
free(tmp);
|
|
return len;
|
|
}
|
|
|
|
size_t print_token(char* buf, size_t len, stoken_t *t)
|
|
{
|
|
int slen;
|
|
|
|
slen = sprintf(buf + len, "%c ", t->type);
|
|
assert(slen >= 0);
|
|
len += (size_t) slen;
|
|
switch (t->type) {
|
|
case 's':
|
|
len = print_string(buf, len, t);
|
|
break;
|
|
case 'v':
|
|
len = print_var(buf, len, t);
|
|
break;
|
|
default:
|
|
slen = sprintf(buf + len, "%s", t->val);
|
|
assert(slen >= 0);
|
|
len += (size_t) slen;
|
|
}
|
|
slen = sprintf(buf + len, "%c", '\n');
|
|
assert(slen >= 0);
|
|
len += (size_t) slen;
|
|
return len;
|
|
}
|
|
|
|
int read_file(const char* fname, int flags, int testtype)
|
|
{
|
|
int count = 0;
|
|
FILE *fp = NULL;
|
|
char linebuf[8192];
|
|
char g_actual[8192];
|
|
char* bufptr = NULL;
|
|
size_t slen;
|
|
char* copy;
|
|
sfilter sf;
|
|
int ok = 1;
|
|
int num_tokens;
|
|
int issqli;
|
|
int i;
|
|
|
|
g_test[0] = '\0';
|
|
g_input[0] = '\0';
|
|
g_expected[0] = '\0';
|
|
|
|
fp = fopen(fname, "r");
|
|
while(fgets(linebuf, sizeof(linebuf), fp) != NULL) {
|
|
if (count == 0 && strcmp(linebuf, "--TEST--\n") == 0) {
|
|
bufptr = g_test;
|
|
count = 1;
|
|
} else if (count == 1 && strcmp(linebuf, "--INPUT--\n") == 0) {
|
|
bufptr = g_input;
|
|
count = 2;
|
|
} else if (count == 2 && strcmp(linebuf, "--EXPECTED--\n") == 0) {
|
|
bufptr = g_expected;
|
|
count = 3;
|
|
} else {
|
|
assert(bufptr != NULL);
|
|
strcat(bufptr, linebuf);
|
|
}
|
|
}
|
|
fclose(fp);
|
|
if (count != 3) {
|
|
return 1;
|
|
}
|
|
|
|
g_expected[modp_rtrim(g_expected, strlen(g_expected))] = '\0';
|
|
g_input[modp_rtrim(g_input, strlen(g_input))] = '\0';
|
|
|
|
|
|
slen = strlen(g_input);
|
|
copy = (char* ) malloc(slen);
|
|
memcpy(copy, g_input, slen);
|
|
|
|
g_actual[0] = '\0';
|
|
if (testtype == 0) {
|
|
/*
|
|
* print sqli tokenization only
|
|
*/
|
|
libinjection_sqli_init(&sf, copy, slen, flags);
|
|
libinjection_sqli_callback(&sf, NULL, NULL);
|
|
slen =0;
|
|
while (libinjection_sqli_tokenize(&sf) == 1) {
|
|
slen = print_token(g_actual, slen, sf.current);
|
|
}
|
|
} else if (testtype == 1) {
|
|
/*
|
|
* testing tokenization + folding
|
|
*/
|
|
libinjection_sqli_init(&sf, copy, slen, flags);
|
|
libinjection_sqli_callback(&sf, NULL, NULL);
|
|
slen =0;
|
|
num_tokens = libinjection_sqli_fold(&sf);
|
|
for (i = 0; i < num_tokens; ++i) {
|
|
slen = print_token(g_actual, slen, libinjection_sqli_get_token(&sf, i));
|
|
}
|
|
} else if (testtype == 2) {
|
|
/**
|
|
* test sqli detection
|
|
*/
|
|
char buf[100];
|
|
issqli = libinjection_sqli(copy, slen, buf);
|
|
if (issqli) {
|
|
sprintf(g_actual, "%s", buf);
|
|
}
|
|
} else if (testtype == 3) {
|
|
/*
|
|
* test html5 tokenization only
|
|
*/
|
|
|
|
h5_state_t hs;
|
|
libinjection_h5_init(&hs, copy, slen, DATA_STATE);
|
|
slen = 0;
|
|
while (libinjection_h5_next(&hs)) {
|
|
slen = print_html5_token(g_actual, slen, &hs);
|
|
}
|
|
} else if (testtype == 4) {
|
|
/*
|
|
* test XSS detection
|
|
*/
|
|
sprintf(g_actual, "%d", libinjection_xss(copy, slen));
|
|
} else {
|
|
fprintf(stderr, "Got stange testtype value of %d\n", testtype);
|
|
assert(0);
|
|
}
|
|
|
|
g_actual[modp_rtrim(g_actual, strlen(g_actual))] = '\0';
|
|
|
|
if (strcmp(g_expected, g_actual) != 0) {
|
|
printf("INPUT: \n%s\n==\n", g_input);
|
|
printf("EXPECTED: \n%s\n==\n", g_expected);
|
|
printf("GOT: \n%s\n==\n", g_actual);
|
|
ok = 0;
|
|
}
|
|
|
|
free(copy);
|
|
return ok;
|
|
}
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
int offset = 1;
|
|
int i;
|
|
int ok;
|
|
int count = 0;
|
|
int count_fail = 0;
|
|
int flags = 0;
|
|
int testtype = 0;
|
|
int quiet = 0;
|
|
|
|
const char* fname;
|
|
while (1) {
|
|
if (strcmp(argv[offset], "-q") == 0 || strcmp(argv[offset], "--quiet") == 0) {
|
|
quiet = 1;
|
|
offset += 1;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
printf("%s\n", libinjection_version());
|
|
|
|
for (i = offset; i < argc; ++i) {
|
|
fname = argv[i];
|
|
count += 1;
|
|
if (strstr(fname, "test-tokens-")) {
|
|
flags = FLAG_QUOTE_NONE | FLAG_SQL_ANSI;
|
|
testtype = 0;
|
|
} else if (strstr(fname, "test-folding-")) {
|
|
flags = FLAG_QUOTE_NONE | FLAG_SQL_ANSI;
|
|
testtype = 1;
|
|
} else if (strstr(fname, "test-sqli-")) {
|
|
flags = FLAG_NONE;
|
|
testtype = 2;
|
|
} else if (strstr(fname, "test-html5-")) {
|
|
flags = FLAG_NONE;
|
|
testtype = 3;
|
|
} else if (strstr(fname, "test-xss-")) {
|
|
flags = FLAG_NONE;
|
|
testtype = 4;
|
|
} else {
|
|
fprintf(stderr, "Unknown test type: %s, failing\n", fname);
|
|
count_fail += 1;
|
|
continue;
|
|
}
|
|
|
|
ok = read_file(fname, flags, testtype);
|
|
if (ok) {
|
|
if (! quiet) {
|
|
fprintf(stderr, "%s: ok\n", fname);
|
|
}
|
|
} else {
|
|
count_fail += 1;
|
|
if (! quiet) {
|
|
fprintf(stderr, "%s: fail\n", fname);
|
|
}
|
|
}
|
|
}
|
|
return count > 0 && count_fail > 0;
|
|
}
|