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  }