static ib_status_t sqli_op_execute( ib_tx_t *tx, void *instance_data, const ib_field_t *field, ib_field_t *capture, ib_num_t *result, void *cbdata ) { assert(tx != NULL); assert(field != NULL); assert(result != NULL); sfilter sf; ib_bytestr_t *bs; ib_status_t rc; const sqli_pattern_set_t *ps = (const sqli_pattern_set_t *)instance_data; *result = 0; /* Currently only bytestring types are supported. * Other types will just get passed through. */ if (field->type != IB_FTYPE_BYTESTR) { return IB_OK; } rc = ib_field_value(field, ib_ftype_bytestr_mutable_out(&bs)); if (rc != IB_OK) { return rc; } /* Run through libinjection. */ libinjection_sqli_init( &sf, (const char *)ib_bytestr_const_ptr(bs), ib_bytestr_length(bs), FLAG_NONE ); if (ps != NULL ) { libinjection_sqli_callback(&sf, sqli_lookup_word, (void *)ps); } if ( libinjection_is_sqli(&sf) ) { ib_log_debug_tx(tx, "Matched SQLi fingerprint: %s", sf.fingerprint); *result = 1; } return IB_OK; }
int read_file(const char* fname, int flags, int testtype) { int count = 0; FILE *fp = NULL; char linebuf[4096]; char g_actual[4096]; char* bufptr = NULL; 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 { 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'; size_t slen = strlen(g_input); char* copy = (char* ) malloc(slen); memcpy(copy, g_input, slen); libinjection_sqli_init(&sf, copy, slen, flags); /* just here for code coverage and cppcheck */ libinjection_sqli_callback(&sf, NULL, NULL); slen = 0; g_actual[0] = '\0'; if (testtype == 1) { issqli = libinjection_is_sqli(&sf); if (issqli) { sprintf(g_actual, "%s", sf.fingerprint); } } else if (testtype == 2) { num_tokens = libinjection_sqli_fold(&sf); for (i = 0; i < num_tokens; ++i) { slen = print_token(g_actual, slen, &(sf.tokenvec[i])); } } else { while (libinjection_sqli_tokenize(&sf) == 1) { slen = print_token(g_actual, slen, sf.current); } } 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; }
static ib_status_t sqli_normalize_tfn(ib_mpool_t *mp, const ib_field_t *field_in, const ib_field_t **field_out, void *tfn_data) { assert(mp != NULL); assert(field_in != NULL); assert(field_out != NULL); const sqli_pattern_set_t *ps = (const sqli_pattern_set_t *)tfn_data; sfilter sf; ib_bytestr_t *bs_in; ib_bytestr_t *bs_out; const char *buf_in; char *buf_in_start; size_t buf_in_len; char *buf_out; char *buf_out_end; size_t buf_out_len; size_t lead_len = 0; char prev_token_type; ib_field_t *field_new; ib_status_t rc; size_t fingerprint_len; /* Currently only bytestring types are supported. * Other types will just get passed through. */ if (field_in->type != IB_FTYPE_BYTESTR) { *field_out = field_in; return IB_OK; } /* Extract the underlying incoming value. */ rc = ib_field_value(field_in, ib_ftype_bytestr_mutable_out(&bs_in)); if (rc != IB_OK) { return rc; } /* Create a buffer big enough (double) to allow for normalization. */ buf_in = (const char *)ib_bytestr_const_ptr(bs_in); buf_out = buf_out_end = (char *)ib_mpool_calloc(mp, 2, ib_bytestr_length(bs_in)); if (buf_out == NULL) { return IB_EALLOC; } /* TODO: With the latest libinjection, we will need to do something like the * following, but more robust, instead of just calling is_sqli. This seems * to be because folding is now called, which removes some tokens. */ #if 0 /* As SQL can be injected into a string, the normalization * needs to start after the first quote character if one * exists. * * First try single quote, then double, then none. * * TODO: Handle returning multiple transformations: * 1) Straight normalization * 2) Normalization as if with single quotes (starting point * should be based on straight normalization) * 3) Normalization as if with double quotes (starting point * should be based on straight normalization) */ buf_in_start = memchr(buf_in, CHAR_SINGLE, ib_bytestr_length(bs_in)); if (buf_in_start == NULL) { buf_in_start = memchr(buf_in, CHAR_DOUBLE, ib_bytestr_length(bs_in)); } if (buf_in_start == NULL) { buf_in_start = (char *)buf_in; buf_in_len = ib_bytestr_length(bs_in); } else { ++buf_in_start; /* After the quote. */ buf_in_len = ib_bytestr_length(bs_in) - (buf_in_start - buf_in); } /* Copy the leading string if one exists. */ if (buf_in_start != buf_in) { lead_len = buf_in_start - buf_in; memcpy(buf_out, buf_in, lead_len); buf_out_end += lead_len; } #endif buf_in_start = (char *)buf_in; buf_in_len = ib_bytestr_length(bs_in); /* Copy the normalized tokens as a space separated list. Since * the tokenizer does not backtrack, and the normalized values * are always equal to or less than the original length, the * tokens are written back to the beginning of the original * buffer. */ libinjection_sqli_init(&sf,buf_in_start, buf_in_len, FLAG_NONE); libinjection_sqli_callback(&sf, sqli_lookup_word, (void *)ps); /* NOTE: We do not care if it is sqli, but just want the tokens. */ libinjection_is_sqli(&sf); if (strlen(sf.fingerprint) == 0) { *field_out = field_in; return IB_OK; } buf_out_len = 0; prev_token_type = 0; fingerprint_len = strlen(sf.fingerprint); for (size_t i = 0; i < fingerprint_len; ++i) { stoken_t current = sf.tokenvec[i]; size_t token_len = strlen(current.val); /* Add in the space if required. */ if ((buf_out_end != buf_out) && (current.type != 'o') && (prev_token_type != 'o') && (current.type != ',') && (*(buf_out_end - 1) != ',')) { *buf_out_end = ' '; buf_out_end += 1; ++buf_out_len; } /* Copy the token value. */ memcpy(buf_out_end, current.val, token_len); buf_out_end += token_len; buf_out_len += token_len; prev_token_type = current.type; } /* Create the output field wrapping bs_out. */ buf_out_len += lead_len; rc = ib_bytestr_alias_mem(&bs_out, mp, (uint8_t *)buf_out, buf_out_len); if (rc != IB_OK) { return rc; } rc = ib_field_create(&field_new, mp, field_in->name, field_in->nlen, IB_FTYPE_BYTESTR, ib_ftype_bytestr_mutable_in(bs_out)); if (rc == IB_OK) { *field_out = field_new; } return rc; }
void test_positive(FILE * fd, const char *fname, detect_mode_t mode, int flag_invert, int flag_true, int flag_quiet) { char linebuf[8192]; int issqli; int linenum = 0; size_t len; sfilter sf; while (fgets(linebuf, sizeof(linebuf), fd)) { linenum += 1; len = modp_rtrim(linebuf, strlen(linebuf)); if (len == 0) { continue; } if (linebuf[0] == '#') { continue; } len = modp_url_decode(linebuf, linebuf, len); issqli = 0; switch (mode) { case MODE_SQLI: { libinjection_sqli_init(&sf, linebuf, len, 0); issqli = libinjection_is_sqli(&sf); break; } case MODE_XSS: { issqli = libinjection_xss(linebuf, len); break; } default: assert(0); } if (issqli) { g_test_ok += 1; } else { g_test_fail += 1; } if (!flag_quiet) { if ((issqli && flag_true && ! flag_invert) || (!issqli && flag_true && flag_invert) || !flag_true) { modp_toprint(linebuf, len); switch (mode) { case MODE_SQLI: { /* * if we didn't find a SQLi and fingerprint from * sqlstats is is 'sns' or 'snsns' then redo using * plain context */ if (!issqli && (strcmp(sf.fingerprint, "sns") == 0 || strcmp(sf.fingerprint, "snsns") == 0)) { libinjection_sqli_fingerprint(&sf, 0); } fprintf(stdout, "%s\t%d\t%s\t%s\t%s\n", fname, linenum, (issqli ? "True" : "False"), sf.fingerprint, linebuf); break; } case MODE_XSS: { fprintf(stdout, "%s\t%d\t%s\t%s\n", fname, linenum, (issqli ? "True" : "False"), linebuf); break; } default: assert(0); } } } } }
int main(int argc, const char* argv[]) { int flags = 0; int fold = 0; int detect = 0; int i; int count; int offset = 1; int issqli; sfilter sf; if (argc < 2) { fprintf(stderr, "need more args\n"); return 1; } while (1) { if (strcmp(argv[offset], "-m") == 0) { flags |= FLAG_SQL_MYSQL; offset += 1; } else if (strcmp(argv[offset], "-f") == 0 || strcmp(argv[offset], "--fold") == 0) { fold = 1; offset += 1; } else if (strcmp(argv[offset], "-d") == 0 || strcmp(argv[offset], "--detect") == 0) { detect = 1; offset += 1; } else if (strcmp(argv[offset], "-ca") == 0) { flags |= FLAG_SQL_ANSI; offset += 1; } else if (strcmp(argv[offset], "-cm") == 0) { flags |= FLAG_SQL_MYSQL; offset += 1; } else if (strcmp(argv[offset], "-q0") == 0) { flags |= FLAG_QUOTE_NONE; offset += 1; } else if (strcmp(argv[offset], "-q1") == 0) { flags |= FLAG_QUOTE_SINGLE; offset += 1; } else if (strcmp(argv[offset], "-q2") == 0) { flags |= FLAG_QUOTE_DOUBLE; offset += 1; } else { break; } } /* ATTENTION: argv is a C-string, null terminated. We copy this * to it's own location, WITHOUT null byte. This way, valgrind * can see if we run past the buffer. */ size_t slen = strlen(argv[offset]); char* copy = (char* ) malloc(slen); memcpy(copy, argv[offset], slen); libinjection_sqli_init(&sf, copy, slen, flags); if (detect == 1) { issqli = libinjection_is_sqli(&sf); if (issqli) { printf("%s\n", sf.fingerprint); } } else if (fold == 1) { count = libinjection_sqli_fold(&sf); // printf("count = %d\n", count); for (i = 0; i < count; ++i) { //printf("token: %d :: ", i); print_token(&(sf.tokenvec[i])); } } else { while (libinjection_sqli_tokenize(&sf)) { print_token(sf.current); } } free(copy); return 0; }
static ib_status_t sqli_normalize_tfn(ib_engine_t *ib, ib_mpool_t *mp, void *tfn_data, const ib_field_t *field_in, const ib_field_t **field_out, ib_flags_t *pflags) { assert(ib != NULL); assert(mp != NULL); assert(field_in != NULL); assert(field_out != NULL); assert(pflags != NULL); sfilter sf; ib_bytestr_t *bs_in; ib_bytestr_t *bs_out; const char *buf_in; char *buf_in_start; size_t buf_in_len; char *buf_out; char *buf_out_end; size_t buf_out_len; size_t lead_len = 0; char prev_token_type; ib_field_t *field_new; ib_status_t rc; size_t pat_len; /* Currently only bytestring types are supported. * Other types will just get passed through. */ if (field_in->type != IB_FTYPE_BYTESTR) { *field_out = field_in; return IB_OK; } /* Extract the underlying incoming value. */ rc = ib_field_value(field_in, ib_ftype_bytestr_mutable_out(&bs_in)); if (rc != IB_OK) { return rc; } /* Create a buffer big enough (double) to allow for normalization. */ buf_in = (const char *)ib_bytestr_const_ptr(bs_in); buf_out = buf_out_end = (char *)ib_mpool_calloc(mp, 2, ib_bytestr_length(bs_in)); if (buf_out == NULL) { return IB_EALLOC; } /* As SQL can be injected into a string, the normalization * needs to start after the first quote character if one * exists. * * First try single quote, then double, then none. * * TODO: Handle returning multiple transformations: * 1) Straight normalization * 2) Normalization as if with single quotes (starting point * should be based on straight normalization) * 3) Normalization as if with double quotes (starting point * should be based on straight normalization) */ buf_in_start = memchr(buf_in, CHAR_SINGLE, ib_bytestr_length(bs_in)); if (buf_in_start == NULL) { buf_in_start = memchr(buf_in, CHAR_DOUBLE, ib_bytestr_length(bs_in)); } if (buf_in_start == NULL) { buf_in_start = (char *)buf_in; buf_in_len = ib_bytestr_length(bs_in); } else { ++buf_in_start; /* After the quote. */ buf_in_len = ib_bytestr_length(bs_in) - (buf_in_start - buf_in); } /* Copy the leading string if one exists. */ if (buf_in_start != buf_in) { lead_len = buf_in_start - buf_in; memcpy(buf_out, buf_in, lead_len); buf_out_end += lead_len; } /* Copy the normalized tokens as a space separated list. Since * the tokenizer does not backtrack, and the normalized values * are always equal to or less than the original length, the * tokens are written back to the beginning of the original * buffer. */ libinjection_is_sqli(&sf, buf_in_start, buf_in_len, NULL, NULL); buf_out_len = 0; prev_token_type = 0; pat_len = strlen(sf.pat); for (size_t i = 0; i < pat_len; ++i) { stoken_t current = sf.tokenvec[i]; size_t token_len = strlen(current.val); ib_log_debug2(ib, "SQLi TOKEN: %c \"%s\"", current.type, current.val); /* Add in the space if required. */ if ((buf_out_end != buf_out) && (current.type != 'o') && (prev_token_type != 'o') && (current.type != ',') && (*(buf_out_end - 1) != ',')) { *buf_out_end = ' '; buf_out_end += 1; ++buf_out_len; } /* Copy the token value. */ memcpy(buf_out_end, current.val, token_len); buf_out_end += token_len; buf_out_len += token_len; prev_token_type = current.type; } /* Mark as modified. */ *pflags = IB_TFN_FMODIFIED; /* Create the output field wrapping bs_out. */ buf_out_len += lead_len; rc = ib_bytestr_alias_mem(&bs_out, mp, (uint8_t *)buf_out, buf_out_len); if (rc != IB_OK) { return rc; } rc = ib_field_create(&field_new, mp, field_in->name, field_in->nlen, IB_FTYPE_BYTESTR, ib_ftype_bytestr_mutable_in(bs_out)); if (rc == IB_OK) { *field_out = field_new; } return rc; }
int main(int argc, const char* argv[]) { char comment_style = COMMENTS_ANSI; int fold = 0; int detect = 0; int i; int count; int offset = 1; sfilter sf; stoken_t current; if (argc < 2) { fprintf(stderr, "need more args\n"); return 1; } while (1) { if (strcmp(argv[offset], "-m") == 0) { comment_style = COMMENTS_MYSQL; offset += 1; } else if (strcmp(argv[offset], "-f") == 0 || strcmp(argv[offset], "--fold") == 0) { fold = 1; offset += 1; } else if (strcmp(argv[offset], "-d") == 0 || strcmp(argv[offset], "--detect") == 0) { detect = 1; offset += 1; } else { break; } } /* ATTENTION: argv is a C-string, null terminated. We copy this * to it's own location, WITHOUT null byte. This way, valgrind * can see if we run past the buffer. */ size_t slen = strlen(argv[offset]); char* copy = (char* ) malloc(slen); memcpy(copy, argv[offset], slen); libinjection_sqli_init(&sf, copy, slen, CHAR_NULL, comment_style); if (detect == 1) { detect = libinjection_is_sqli(&sf, copy, slen, CHAR_NULL, COMMENTS_ANSI); if (detect) { printf("%s\n", sf.pat); } } else if (fold == 1) { count = filter_fold(&sf); // printf("count = %d\n", count); for (i = 0; i < count; ++i) { //printf("token: %d :: ", i); print_token(&(sf.tokenvec[i])); } } else { while (libinjection_sqli_tokenize(&sf, ¤t)) { print_token(¤t); } } free(copy); return 0; }
static ib_status_t sqli_op_execute( ib_tx_t *tx, const ib_field_t *field, ib_field_t *capture, ib_num_t *result, void *instance_data, void *cbdata ) { assert(tx != NULL); assert(field != NULL); assert(result != NULL); const sqli_fingerprint_set_t *ps = (const sqli_fingerprint_set_t *)instance_data; sfilter sf; ib_bytestr_t *bs; ib_status_t rc; sqli_callback_data_t callback_data; *result = 0; /* Currently only bytestring types are supported. * Other types will just get passed through. */ if (field->type != IB_FTYPE_BYTESTR) { return IB_OK; } rc = ib_field_value(field, ib_ftype_bytestr_mutable_out(&bs)); if (rc != IB_OK) { return rc; } /* Run through libinjection. */ libinjection_sqli_init( &sf, (const char *)ib_bytestr_const_ptr(bs), ib_bytestr_length(bs), FLAG_NONE ); callback_data.confidence = 0; callback_data.fingerprint_set = NULL; if (ps != NULL) { callback_data.fingerprint_set = ps; libinjection_sqli_callback(&sf, sqli_lookup_word, (void *)&callback_data); } if (libinjection_is_sqli(&sf)) { ib_log_debug_tx(tx, "Matched SQLi fingerprint: %s", sf.fingerprint); *result = 1; } if (*result == 1 && capture != NULL) { { ib_field_t *fingerprint_field; size_t fingerprint_length = strlen(sf.fingerprint); const uint8_t *fingerprint; fingerprint = ib_mm_memdup( tx->mm, sf.fingerprint, fingerprint_length ); if (fingerprint == NULL) { return IB_EALLOC; } rc = ib_field_create_bytestr_alias( &fingerprint_field, tx->mm, IB_S2SL("fingerprint"), fingerprint, fingerprint_length ); if (rc != IB_OK) { return rc; } rc = ib_field_list_add(capture, fingerprint_field); if (rc != IB_OK) { return rc; } } { ib_field_t *confidence_field; rc = ib_field_create( &confidence_field, tx->mm, IB_S2SL("confidence"), IB_FTYPE_NUM, ib_ftype_num_in(&callback_data.confidence) ); if (rc != IB_OK) { return rc; } rc = ib_field_list_add(capture, confidence_field); if (rc != IB_OK) { return rc; } } } return IB_OK; }