github.com/TeaOSLab/EdgeNode@v1.3.8/internal/waf/injectionutils/libinjection/src/reader.c (about) 1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <assert.h> 5 6 #include "libinjection.h" 7 #include "libinjection_sqli.h" 8 #include "libinjection_xss.h" 9 10 #ifndef TRUE 11 #define TRUE 1 12 #endif 13 #ifndef FALSE 14 #define FALSE 0 15 #endif 16 17 static int g_test_ok = 0; 18 static int g_test_fail = 0; 19 20 typedef enum { 21 MODE_SQLI, 22 MODE_XSS 23 } detect_mode_t; 24 25 static void usage(const char* program_name); 26 size_t modp_rtrim(char* str, size_t len); 27 void modp_toprint(char* str, size_t len); 28 void test_positive(FILE * fd, const char *fname, detect_mode_t mode, 29 int flag_invert, int flag_true, int flag_quiet); 30 31 int urlcharmap(char ch); 32 size_t modp_url_decode(char* dest, const char* s, size_t len); 33 34 int urlcharmap(char ch) { 35 switch (ch) { 36 case '0': return 0; 37 case '1': return 1; 38 case '2': return 2; 39 case '3': return 3; 40 case '4': return 4; 41 case '5': return 5; 42 case '6': return 6; 43 case '7': return 7; 44 case '8': return 8; 45 case '9': return 9; 46 case 'a': case 'A': return 10; 47 case 'b': case 'B': return 11; 48 case 'c': case 'C': return 12; 49 case 'd': case 'D': return 13; 50 case 'e': case 'E': return 14; 51 case 'f': case 'F': return 15; 52 default: 53 return 256; 54 } 55 } 56 57 size_t modp_url_decode(char* dest, const char* s, size_t len) 58 { 59 const char* deststart = dest; 60 61 size_t i = 0; 62 int d = 0; 63 while (i < len) { 64 switch (s[i]) { 65 case '+': 66 *dest++ = ' '; 67 i += 1; 68 break; 69 case '%': 70 if (i+2 < len) { 71 d = (urlcharmap(s[i+1]) << 4) | urlcharmap(s[i+2]); 72 if ( d < 256) { 73 *dest = (char) d; 74 dest++; 75 i += 3; /* loop will increment one time */ 76 } else { 77 *dest++ = '%'; 78 i += 1; 79 } 80 } else { 81 *dest++ = '%'; 82 i += 1; 83 } 84 break; 85 default: 86 *dest++ = s[i]; 87 i += 1; 88 } 89 } 90 *dest = '\0'; 91 return (size_t)(dest - deststart); /* compute "strlen" of dest */ 92 } 93 94 void modp_toprint(char* str, size_t len) 95 { 96 size_t i; 97 for (i = 0; i < len; ++i) { 98 if (str[i] < 32 || str[i] > 126) { 99 str[i] = '?'; 100 } 101 } 102 } 103 size_t modp_rtrim(char* str, size_t len) 104 { 105 while (len) { 106 char c = str[len -1]; 107 if (c == ' ' || c == '\n' || c == '\t' || c == '\r') { 108 str[len -1] = '\0'; 109 len -= 1; 110 } else { 111 break; 112 } 113 } 114 return len; 115 } 116 117 void test_positive(FILE * fd, const char *fname, detect_mode_t mode, 118 int flag_invert, int flag_true, int flag_quiet) 119 { 120 char linebuf[8192]; 121 int issqli = 0; 122 int linenum = 0; 123 size_t len; 124 sfilter sf; 125 126 while (fgets(linebuf, sizeof(linebuf), fd)) { 127 linenum += 1; 128 len = modp_rtrim(linebuf, strlen(linebuf)); 129 if (len == 0) { 130 continue; 131 } 132 if (linebuf[0] == '#') { 133 continue; 134 } 135 136 len = modp_url_decode(linebuf, linebuf, len); 137 switch (mode) { 138 case MODE_SQLI: { 139 libinjection_sqli_init(&sf, linebuf, len, 0); 140 issqli = libinjection_is_sqli(&sf); 141 break; 142 } 143 case MODE_XSS: { 144 issqli = libinjection_xss(linebuf, len); 145 break; 146 } 147 default: 148 assert(0); 149 } 150 151 if (issqli) { 152 g_test_ok += 1; 153 } else { 154 g_test_fail += 1; 155 } 156 157 if (!flag_quiet) { 158 if ((issqli && flag_true && ! flag_invert) || 159 (!issqli && flag_true && flag_invert) || 160 !flag_true) { 161 162 modp_toprint(linebuf, len); 163 164 switch (mode) { 165 case MODE_SQLI: { 166 /* 167 * if we didn't find a SQLi and fingerprint from 168 * sqlstats is is 'sns' or 'snsns' then redo using 169 * plain context 170 */ 171 if (!issqli && (strcmp(sf.fingerprint, "sns") == 0 || 172 strcmp(sf.fingerprint, "snsns") == 0)) { 173 libinjection_sqli_fingerprint(&sf, 0); 174 } 175 176 fprintf(stdout, "%s\t%d\t%s\t%s\t%s\n", 177 fname, linenum, 178 (issqli ? "True" : "False"), sf.fingerprint, linebuf); 179 break; 180 } 181 case MODE_XSS: { 182 fprintf(stdout, "%s\t%d\t%s\t%s\n", 183 fname, linenum, 184 (issqli ? "True" : "False"), linebuf); 185 break; 186 } 187 default: 188 assert(0); 189 } 190 } 191 } 192 } 193 } 194 195 static void usage(const char* program_name) 196 { 197 fprintf(stdout, "usage: %s [flags] [files...]\n", program_name); 198 fprintf(stdout, "%s\n", ""); 199 fprintf(stdout, "%s\n", "-q --quiet : quiet mode"); 200 fprintf(stdout, "%s\n", "-m --max-fails : number of failed cases need to fail entire test"); 201 fprintf(stdout, "%s\n", "-s INTEGER : repeat each test N time " 202 "(for performance testing)"); 203 fprintf(stdout, "%s\n", "-t : only print positive matches"); 204 fprintf(stdout, "%s\n", "-x --mode-xss : test input for XSS"); 205 fprintf(stdout, "%s\n", "-i --invert : invert test logic " 206 "(input is tested for being safe)"); 207 208 fprintf(stdout, "%s\n", ""); 209 fprintf(stdout, "%s\n", "-? -h -help --help : this page"); 210 fprintf(stdout, "%s\n", ""); 211 } 212 213 int main(int argc, const char *argv[]) 214 { 215 /* 216 * invert output, by 217 */ 218 int flag_invert = FALSE; 219 220 /* 221 * don't print anything.. useful for 222 * performance monitors, gprof. 223 */ 224 int flag_quiet = FALSE; 225 226 /* 227 * only print positive results 228 * with invert, only print negative results 229 */ 230 int flag_true = FALSE; 231 detect_mode_t mode = MODE_SQLI; 232 233 int flag_slow = 1; 234 int count = 0; 235 int max = -1; 236 237 int i, j; 238 int offset = 1; 239 240 while (offset < argc) { 241 if (strcmp(argv[offset], "-?") == 0 || 242 strcmp(argv[offset], "-h") == 0 || 243 strcmp(argv[offset], "-help") == 0 || 244 strcmp(argv[offset], "--help") == 0) { 245 usage(argv[0]); 246 exit(0); 247 } 248 249 if (strcmp(argv[offset], "-i") == 0) { 250 offset += 1; 251 flag_invert = TRUE; 252 } else if (strcmp(argv[offset], "-q") == 0 || 253 strcmp(argv[offset], "--quiet") == 0) { 254 offset += 1; 255 flag_quiet = TRUE; 256 } else if (strcmp(argv[offset], "-t") == 0) { 257 offset += 1; 258 flag_true = TRUE; 259 } else if (strcmp(argv[offset], "-s") == 0) { 260 offset += 1; 261 flag_slow = 100; 262 } else if (strcmp(argv[offset], "-m") == 0 || 263 strcmp(argv[offset], "--max-fails") == 0) { 264 offset += 1; 265 max = atoi(argv[offset]); 266 offset += 1; 267 } else if (strcmp(argv[offset], "-x") == 0 || 268 strcmp(argv[offset], "--mode-xss") == 0) { 269 mode = MODE_XSS; 270 offset += 1; 271 } else { 272 break; 273 } 274 } 275 276 if (offset == argc) { 277 test_positive(stdin, "stdin", mode, flag_invert, flag_true, flag_quiet); 278 } else { 279 for (j = 0; j < flag_slow; ++j) { 280 for (i = offset; i < argc; ++i) { 281 FILE* fd = fopen(argv[i], "r"); 282 if (fd) { 283 test_positive(fd, argv[i], mode, flag_invert, flag_true, flag_quiet); 284 fclose(fd); 285 } 286 } 287 } 288 } 289 290 if (!flag_quiet) { 291 fprintf(stdout, "%s", "\n"); 292 fprintf(stdout, "SQLI : %d\n", g_test_ok); 293 fprintf(stdout, "SAFE : %d\n", g_test_fail); 294 fprintf(stdout, "TOTAL : %d\n", g_test_ok + g_test_fail); 295 } 296 297 if (max == -1) { 298 return 0; 299 } 300 301 count = g_test_ok; 302 if (flag_invert) { 303 count = g_test_fail; 304 } 305 306 if (count > max) { 307 printf("\nThreshold is %d, got %d, failing.\n", max, count); 308 return 1; 309 } else { 310 printf("\nThreshold is %d, got %d, passing.\n", max, count); 311 return 0; 312 } 313 }