bool is_string_sqli(sfilter * sql_state, const char *s, size_t slen, const char delim) { sfilter_reset(sql_state, s, slen); sql_state->delim = delim; bool all_done = false; int tlen = 0; while (tlen < MAX_TOKENS) { all_done = filter_fold(sql_state, &(sql_state->tokenvec[tlen])); if (!all_done) { break; } sql_state->pat[tlen] = sql_state->tokenvec[tlen].type; //printf("i = %d, char = %c, %s\n", tlen, sql_state->pat[tlen], // sql_state->tokenvec[tlen].val); tlen += 1; } sql_state->pat[tlen] = CHAR_NULL; //assert(strlen(sql_state->pat) <= 5); //printf("PAT = %s\n", sql_state->pat); // check to make sure we don't have a dangling // function without a "(" (then it's not a function) // (and then not a SQLi). This is the only reason // we need the 6th token. It might be possible to // skip the parsing if token 5 is NOT a function type if (tlen == MAX_TOKENS && !all_done && sql_state->pat[MAX_TOKENS - 1] == 'f') { stoken_t tmp; all_done = filter_fold(sql_state, &tmp); if (!all_done && tmp.type != '(') { sql_state->reason = __LINE__; return false; } } // loss of 10% due to bsearch bool patmatch = is_sqli_pattern(sql_state->pat); //bool patmatch = false; if (!patmatch) { sql_state->reason = __LINE__; return false; } switch (tlen) { case 3:{ if (streq(sql_state->pat, "sos") && (st_is_arith_op(&sql_state->tokenvec[1]) || st_is_english_op(&sql_state->tokenvec[1]) || sql_state->delim == CHAR_NULL)) { sql_state->reason = __LINE__; return false; } else { return true; } } break; case 5:{ if (sql_state->pat[1] == 'o' && sql_state->pat[3] == 'o') { if (sql_state->pat[2] == 'v') { return true; } else if (streq(sql_state->pat, "sono1") && st_equals_cstr(&sql_state->tokenvec[1], 'o', "&") && st_equals_cstr(&sql_state->tokenvec[3], 'o', "=")) { // query string fragment ...foo"&page=2 sql_state->reason = __LINE__; return false; } else if (sql_state->delim == CHAR_NULL && streq(sql_state->pat, "sosos")) { // "foo" and "bar" and "dingbat" // likely search term sql_state->reason = __LINE__; return false; } else if (!st_is_arith_op(&sql_state->tokenvec[3]) && strcmp(sql_state->tokenvec[1].val, sql_state->tokenvec[3].val)) { return true; } else if (streq(sql_state->tokenvec[1].val, sql_state->tokenvec[3].val)) { sql_state->reason = __LINE__; return false; } else { sql_state->reason = __LINE__; //printf("False: %s not slqi\n", sql_state->pat); return false; } } } break; } /* end switch */ //printf("i = %d, PAT = %s\n", i, sql_state->pat); return true; }
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; }