immunio 0.15.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (157) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +234 -0
  3. data/README.md +147 -0
  4. data/bin/immunio +5 -0
  5. data/lib/immunio.rb +29 -0
  6. data/lib/immunio/agent.rb +260 -0
  7. data/lib/immunio/authentication.rb +96 -0
  8. data/lib/immunio/blocked_app.rb +38 -0
  9. data/lib/immunio/channel.rb +432 -0
  10. data/lib/immunio/cli.rb +39 -0
  11. data/lib/immunio/context.rb +114 -0
  12. data/lib/immunio/errors.rb +43 -0
  13. data/lib/immunio/immunio_ca.crt +45 -0
  14. data/lib/immunio/logger.rb +87 -0
  15. data/lib/immunio/plugins/action_dispatch.rb +45 -0
  16. data/lib/immunio/plugins/action_view.rb +431 -0
  17. data/lib/immunio/plugins/active_record.rb +707 -0
  18. data/lib/immunio/plugins/active_record_relation.rb +370 -0
  19. data/lib/immunio/plugins/authlogic.rb +80 -0
  20. data/lib/immunio/plugins/csrf.rb +24 -0
  21. data/lib/immunio/plugins/devise.rb +40 -0
  22. data/lib/immunio/plugins/environment_reporter.rb +69 -0
  23. data/lib/immunio/plugins/eval.rb +51 -0
  24. data/lib/immunio/plugins/exception_handler.rb +55 -0
  25. data/lib/immunio/plugins/gems_tracker.rb +5 -0
  26. data/lib/immunio/plugins/haml.rb +36 -0
  27. data/lib/immunio/plugins/http_finisher.rb +50 -0
  28. data/lib/immunio/plugins/http_tracker.rb +203 -0
  29. data/lib/immunio/plugins/io.rb +96 -0
  30. data/lib/immunio/plugins/redirect.rb +42 -0
  31. data/lib/immunio/plugins/warden.rb +66 -0
  32. data/lib/immunio/processor.rb +234 -0
  33. data/lib/immunio/rails.rb +26 -0
  34. data/lib/immunio/request.rb +139 -0
  35. data/lib/immunio/rufus_lua_ext/ref.rb +27 -0
  36. data/lib/immunio/rufus_lua_ext/state.rb +157 -0
  37. data/lib/immunio/rufus_lua_ext/table.rb +137 -0
  38. data/lib/immunio/rufus_lua_ext/utils.rb +13 -0
  39. data/lib/immunio/version.rb +5 -0
  40. data/lib/immunio/vm.rb +291 -0
  41. data/lua-hooks/ext/all.c +78 -0
  42. data/lua-hooks/ext/bitop/README +22 -0
  43. data/lua-hooks/ext/bitop/bit.c +189 -0
  44. data/lua-hooks/ext/extconf.rb +38 -0
  45. data/lua-hooks/ext/libinjection/COPYING +37 -0
  46. data/lua-hooks/ext/libinjection/libinjection.h +65 -0
  47. data/lua-hooks/ext/libinjection/libinjection_html5.c +847 -0
  48. data/lua-hooks/ext/libinjection/libinjection_html5.h +54 -0
  49. data/lua-hooks/ext/libinjection/libinjection_sqli.c +2301 -0
  50. data/lua-hooks/ext/libinjection/libinjection_sqli.h +295 -0
  51. data/lua-hooks/ext/libinjection/libinjection_sqli_data.h +9349 -0
  52. data/lua-hooks/ext/libinjection/libinjection_xss.c +531 -0
  53. data/lua-hooks/ext/libinjection/libinjection_xss.h +21 -0
  54. data/lua-hooks/ext/libinjection/lualib.c +109 -0
  55. data/lua-hooks/ext/lpeg/HISTORY +90 -0
  56. data/lua-hooks/ext/lpeg/lpcap.c +537 -0
  57. data/lua-hooks/ext/lpeg/lpcap.h +43 -0
  58. data/lua-hooks/ext/lpeg/lpcode.c +986 -0
  59. data/lua-hooks/ext/lpeg/lpcode.h +34 -0
  60. data/lua-hooks/ext/lpeg/lpeg-128.gif +0 -0
  61. data/lua-hooks/ext/lpeg/lpeg.html +1429 -0
  62. data/lua-hooks/ext/lpeg/lpprint.c +244 -0
  63. data/lua-hooks/ext/lpeg/lpprint.h +35 -0
  64. data/lua-hooks/ext/lpeg/lptree.c +1238 -0
  65. data/lua-hooks/ext/lpeg/lptree.h +77 -0
  66. data/lua-hooks/ext/lpeg/lptypes.h +149 -0
  67. data/lua-hooks/ext/lpeg/lpvm.c +355 -0
  68. data/lua-hooks/ext/lpeg/lpvm.h +58 -0
  69. data/lua-hooks/ext/lpeg/makefile +55 -0
  70. data/lua-hooks/ext/lpeg/re.html +498 -0
  71. data/lua-hooks/ext/lpeg/test.lua +1409 -0
  72. data/lua-hooks/ext/lua-cmsgpack/CMakeLists.txt +45 -0
  73. data/lua-hooks/ext/lua-cmsgpack/README.md +115 -0
  74. data/lua-hooks/ext/lua-cmsgpack/lua_cmsgpack.c +957 -0
  75. data/lua-hooks/ext/lua-cmsgpack/test.lua +570 -0
  76. data/lua-hooks/ext/lua-snapshot/LICENSE +7 -0
  77. data/lua-hooks/ext/lua-snapshot/Makefile +12 -0
  78. data/lua-hooks/ext/lua-snapshot/README.md +18 -0
  79. data/lua-hooks/ext/lua-snapshot/dump.lua +15 -0
  80. data/lua-hooks/ext/lua-snapshot/snapshot.c +455 -0
  81. data/lua-hooks/ext/lua/COPYRIGHT +34 -0
  82. data/lua-hooks/ext/lua/lapi.c +1087 -0
  83. data/lua-hooks/ext/lua/lapi.h +16 -0
  84. data/lua-hooks/ext/lua/lauxlib.c +652 -0
  85. data/lua-hooks/ext/lua/lauxlib.h +174 -0
  86. data/lua-hooks/ext/lua/lbaselib.c +659 -0
  87. data/lua-hooks/ext/lua/lcode.c +831 -0
  88. data/lua-hooks/ext/lua/lcode.h +76 -0
  89. data/lua-hooks/ext/lua/ldblib.c +398 -0
  90. data/lua-hooks/ext/lua/ldebug.c +638 -0
  91. data/lua-hooks/ext/lua/ldebug.h +33 -0
  92. data/lua-hooks/ext/lua/ldo.c +519 -0
  93. data/lua-hooks/ext/lua/ldo.h +57 -0
  94. data/lua-hooks/ext/lua/ldump.c +164 -0
  95. data/lua-hooks/ext/lua/lfunc.c +174 -0
  96. data/lua-hooks/ext/lua/lfunc.h +34 -0
  97. data/lua-hooks/ext/lua/lgc.c +710 -0
  98. data/lua-hooks/ext/lua/lgc.h +110 -0
  99. data/lua-hooks/ext/lua/linit.c +38 -0
  100. data/lua-hooks/ext/lua/liolib.c +556 -0
  101. data/lua-hooks/ext/lua/llex.c +463 -0
  102. data/lua-hooks/ext/lua/llex.h +81 -0
  103. data/lua-hooks/ext/lua/llimits.h +128 -0
  104. data/lua-hooks/ext/lua/lmathlib.c +263 -0
  105. data/lua-hooks/ext/lua/lmem.c +86 -0
  106. data/lua-hooks/ext/lua/lmem.h +49 -0
  107. data/lua-hooks/ext/lua/loadlib.c +705 -0
  108. data/lua-hooks/ext/lua/loadlib_rel.c +760 -0
  109. data/lua-hooks/ext/lua/lobject.c +214 -0
  110. data/lua-hooks/ext/lua/lobject.h +381 -0
  111. data/lua-hooks/ext/lua/lopcodes.c +102 -0
  112. data/lua-hooks/ext/lua/lopcodes.h +268 -0
  113. data/lua-hooks/ext/lua/loslib.c +243 -0
  114. data/lua-hooks/ext/lua/lparser.c +1339 -0
  115. data/lua-hooks/ext/lua/lparser.h +82 -0
  116. data/lua-hooks/ext/lua/lstate.c +214 -0
  117. data/lua-hooks/ext/lua/lstate.h +169 -0
  118. data/lua-hooks/ext/lua/lstring.c +111 -0
  119. data/lua-hooks/ext/lua/lstring.h +31 -0
  120. data/lua-hooks/ext/lua/lstrlib.c +871 -0
  121. data/lua-hooks/ext/lua/ltable.c +588 -0
  122. data/lua-hooks/ext/lua/ltable.h +40 -0
  123. data/lua-hooks/ext/lua/ltablib.c +287 -0
  124. data/lua-hooks/ext/lua/ltm.c +75 -0
  125. data/lua-hooks/ext/lua/ltm.h +54 -0
  126. data/lua-hooks/ext/lua/lua.c +392 -0
  127. data/lua-hooks/ext/lua/lua.def +131 -0
  128. data/lua-hooks/ext/lua/lua.h +388 -0
  129. data/lua-hooks/ext/lua/lua.rc +28 -0
  130. data/lua-hooks/ext/lua/lua_dll.rc +26 -0
  131. data/lua-hooks/ext/lua/luac.c +200 -0
  132. data/lua-hooks/ext/lua/luac.rc +1 -0
  133. data/lua-hooks/ext/lua/luaconf.h +763 -0
  134. data/lua-hooks/ext/lua/luaconf.h.in +724 -0
  135. data/lua-hooks/ext/lua/luaconf.h.orig +763 -0
  136. data/lua-hooks/ext/lua/lualib.h +53 -0
  137. data/lua-hooks/ext/lua/lundump.c +227 -0
  138. data/lua-hooks/ext/lua/lundump.h +36 -0
  139. data/lua-hooks/ext/lua/lvm.c +767 -0
  140. data/lua-hooks/ext/lua/lvm.h +36 -0
  141. data/lua-hooks/ext/lua/lzio.c +82 -0
  142. data/lua-hooks/ext/lua/lzio.h +67 -0
  143. data/lua-hooks/ext/lua/print.c +227 -0
  144. data/lua-hooks/ext/luautf8/README.md +152 -0
  145. data/lua-hooks/ext/luautf8/lutf8lib.c +1274 -0
  146. data/lua-hooks/ext/luautf8/unidata.h +3064 -0
  147. data/lua-hooks/lib/boot.lua +254 -0
  148. data/lua-hooks/lib/encode.lua +4 -0
  149. data/lua-hooks/lib/lexers/LICENSE +21 -0
  150. data/lua-hooks/lib/lexers/bash.lua +134 -0
  151. data/lua-hooks/lib/lexers/bash_dqstr.lua +62 -0
  152. data/lua-hooks/lib/lexers/css.lua +216 -0
  153. data/lua-hooks/lib/lexers/html.lua +106 -0
  154. data/lua-hooks/lib/lexers/javascript.lua +68 -0
  155. data/lua-hooks/lib/lexers/lexer.lua +1575 -0
  156. data/lua-hooks/lib/lexers/markers.lua +33 -0
  157. metadata +308 -0
@@ -0,0 +1,531 @@
1
+
2
+ #include "libinjection.h"
3
+ #include "libinjection_xss.h"
4
+ #include "libinjection_html5.h"
5
+
6
+ #include <assert.h>
7
+ #include <stdio.h>
8
+
9
+ typedef enum attribute {
10
+ TYPE_NONE
11
+ , TYPE_BLACK /* ban always */
12
+ , TYPE_ATTR_URL /* attribute value takes a URL-like object */
13
+ , TYPE_STYLE
14
+ , TYPE_ATTR_INDIRECT /* attribute *name* is given in *value* */
15
+ } attribute_t;
16
+
17
+
18
+ static attribute_t is_black_attr(const char* s, size_t len);
19
+ static int is_black_tag(const char* s, size_t len);
20
+ static int is_black_url(const char* s, size_t len);
21
+ static int cstrcasecmp_with_null(const char *a, const char *b, size_t n);
22
+ static int html_decode_char_at(const char* src, size_t len, size_t* consumed);
23
+ static int htmlencode_startswith(const char* prefix, const char *src, size_t n);
24
+
25
+
26
+ typedef struct stringtype {
27
+ const char* name;
28
+ attribute_t atype;
29
+ } stringtype_t;
30
+
31
+
32
+ static const int gsHexDecodeMap[256] = {
33
+ 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
34
+ 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
35
+ 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
36
+ 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
37
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 256, 256,
38
+ 256, 256, 256, 256, 256, 10, 11, 12, 13, 14, 15, 256,
39
+ 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
40
+ 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
41
+ 256, 10, 11, 12, 13, 14, 15, 256, 256, 256, 256, 256,
42
+ 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
43
+ 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
44
+ 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
45
+ 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
46
+ 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
47
+ 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
48
+ 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
49
+ 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
50
+ 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
51
+ 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
52
+ 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
53
+ 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
54
+ 256, 256, 256, 256
55
+ };
56
+
57
+ static int html_decode_char_at(const char* src, size_t len, size_t* consumed)
58
+ {
59
+ int val = 0;
60
+ size_t i;
61
+ int ch;
62
+
63
+ if (len == 0 || src == NULL) {
64
+ *consumed = 0;
65
+ return -1;
66
+ }
67
+
68
+ *consumed = 1;
69
+ if (*src != '&' || len < 2) {
70
+ return (unsigned char)(*src);
71
+ }
72
+
73
+
74
+ if (*(src+1) != '#') {
75
+ /* normally this would be for named entities
76
+ * but for this case we don't actually care
77
+ */
78
+ return '&';
79
+ }
80
+
81
+ if (*(src+2) == 'x' || *(src+2) == 'X') {
82
+ ch = (unsigned char) (*(src+3));
83
+ ch = gsHexDecodeMap[ch];
84
+ if (ch == 256) {
85
+ /* degenerate case '&#[?]' */
86
+ return '&';
87
+ }
88
+ val = ch;
89
+ i = 4;
90
+ while (i < len) {
91
+ ch = (unsigned char) src[i];
92
+ if (ch == ';') {
93
+ *consumed = i + 1;
94
+ return val;
95
+ }
96
+ ch = gsHexDecodeMap[ch];
97
+ if (ch == 256) {
98
+ *consumed = i;
99
+ return val;
100
+ }
101
+ val = (val * 16) + ch;
102
+ if (val > 0x1000FF) {
103
+ return '&';
104
+ }
105
+ ++i;
106
+ }
107
+ *consumed = i;
108
+ return val;
109
+ } else {
110
+ i = 2;
111
+ ch = (unsigned char) src[i];
112
+ if (ch < '0' || ch > '9') {
113
+ return '&';
114
+ }
115
+ val = ch - '0';
116
+ i += 1;
117
+ while (i < len) {
118
+ ch = (unsigned char) src[i];
119
+ if (ch == ';') {
120
+ *consumed = i + 1;
121
+ return val;
122
+ }
123
+ if (ch < '0' || ch > '9') {
124
+ *consumed = i;
125
+ return val;
126
+ }
127
+ val = (val * 10) + (ch - '0');
128
+ if (val > 0x1000FF) {
129
+ return '&';
130
+ }
131
+ ++i;
132
+ }
133
+ *consumed = i;
134
+ return val;
135
+ }
136
+ }
137
+
138
+
139
+ /*
140
+ * view-source:
141
+ * data:
142
+ * javascript:
143
+ */
144
+ static stringtype_t BLACKATTR[] = {
145
+ { "ACTION", TYPE_ATTR_URL } /* form */
146
+ , { "ATTRIBUTENAME", TYPE_ATTR_INDIRECT } /* SVG allow indirection of attribute names */
147
+ , { "BY", TYPE_ATTR_URL } /* SVG */
148
+ , { "BACKGROUND", TYPE_ATTR_URL } /* IE6, O11 */
149
+ , { "DATAFORMATAS", TYPE_BLACK } /* IE */
150
+ , { "DATASRC", TYPE_BLACK } /* IE */
151
+ , { "DYNSRC", TYPE_ATTR_URL } /* Obsolete img attribute */
152
+ , { "FILTER", TYPE_STYLE } /* Opera, SVG inline style */
153
+ , { "FORMACTION", TYPE_ATTR_URL } /* HTML5 */
154
+ , { "FOLDER", TYPE_ATTR_URL } /* Only on A tags, IE-only */
155
+ , { "FROM", TYPE_ATTR_URL } /* SVG */
156
+ , { "HANDLER", TYPE_ATTR_URL } /* SVG Tiny, Opera */
157
+ , { "HREF", TYPE_ATTR_URL }
158
+ , { "LOWSRC", TYPE_ATTR_URL } /* Obsolete img attribute */
159
+ , { "POSTER", TYPE_ATTR_URL } /* Opera 10,11 */
160
+ , { "SRC", TYPE_ATTR_URL }
161
+ , { "STYLE", TYPE_STYLE }
162
+ , { "TO", TYPE_ATTR_URL } /* SVG */
163
+ , { "VALUES", TYPE_ATTR_URL } /* SVG */
164
+ , { "XLINK:HREF", TYPE_ATTR_URL }
165
+ , { NULL, TYPE_NONE }
166
+ };
167
+
168
+ /* xmlns */
169
+ /* xml-stylesheet > <eval>, <if expr=> */
170
+
171
+ /*
172
+ static const char* BLACKATTR[] = {
173
+ "ATTRIBUTENAME",
174
+ "BACKGROUND",
175
+ "DATAFORMATAS",
176
+ "HREF",
177
+ "SCROLL",
178
+ "SRC",
179
+ "STYLE",
180
+ "SRCDOC",
181
+ NULL
182
+ };
183
+ */
184
+
185
+ static const char* BLACKTAG[] = {
186
+ "APPLET"
187
+ /* , "AUDIO" */
188
+ , "BASE"
189
+ , "COMMENT" /* IE http://html5sec.org/#38 */
190
+ , "EMBED"
191
+ /* , "FORM" */
192
+ , "FRAME"
193
+ , "FRAMESET"
194
+ , "HANDLER" /* Opera SVG, effectively a script tag */
195
+ , "IFRAME"
196
+ , "IMPORT"
197
+ , "ISINDEX"
198
+ , "LINK"
199
+ , "LISTENER"
200
+ /* , "MARQUEE" */
201
+ , "META"
202
+ , "NOSCRIPT"
203
+ , "OBJECT"
204
+ , "SCRIPT"
205
+ , "STYLE"
206
+ /* , "VIDEO" */
207
+ , "VMLFRAME"
208
+ , "XML"
209
+ , "XSS"
210
+ , NULL
211
+ };
212
+
213
+
214
+ static int cstrcasecmp_with_null(const char *a, const char *b, size_t n)
215
+ {
216
+ char ca;
217
+ char cb;
218
+ /* printf("Comparing to %s %.*s\n", a, (int)n, b); */
219
+ while (n-- > 0) {
220
+ cb = *b++;
221
+ if (cb == '\0') continue;
222
+
223
+ ca = *a++;
224
+
225
+ if (cb >= 'a' && cb <= 'z') {
226
+ cb -= 0x20;
227
+ }
228
+ /* printf("Comparing %c vs %c with %d left\n", ca, cb, (int)n); */
229
+ if (ca != cb) {
230
+ return 1;
231
+ }
232
+ }
233
+
234
+ if (*a == 0) {
235
+ /* printf(" MATCH \n"); */
236
+ return 0;
237
+ } else {
238
+ return 1;
239
+ }
240
+ }
241
+
242
+ /*
243
+ * Does an HTML encoded binary string (const char*, lenght) start with
244
+ * a all uppercase c-string (null terminated), case insenstive!
245
+ *
246
+ * also ignore any embedded nulls in the HTML string!
247
+ *
248
+ * return 1 if match / starts with
249
+ * return 0 if not
250
+ */
251
+ static int htmlencode_startswith(const char *a, const char *b, size_t n)
252
+ {
253
+ size_t consumed;
254
+ int cb;
255
+ int first = 1;
256
+ /* printf("Comparing %s with %.*s\n", a,(int)n,b); */
257
+ while (n > 0) {
258
+ if (*a == 0) {
259
+ /* printf("Match EOL!\n"); */
260
+ return 1;
261
+ }
262
+ cb = html_decode_char_at(b, n, &consumed);
263
+ b += consumed;
264
+ n -= consumed;
265
+
266
+ if (first && cb <= 32) {
267
+ /* ignore all leading whitespace and control characters */
268
+ continue;
269
+ }
270
+ first = 0;
271
+
272
+ if (cb == 0) {
273
+ /* always ignore null characters in user input */
274
+ continue;
275
+ }
276
+
277
+ if (cb == 10) {
278
+ /* always ignore vtab characters in user input */
279
+ /* who allows this?? */
280
+ continue;
281
+ }
282
+
283
+ if (cb >= 'a' && cb <= 'z') {
284
+ /* upcase */
285
+ cb -= 0x20;
286
+ }
287
+
288
+ if (*a != (char) cb) {
289
+ /* printf(" %c != %c\n", *a, cb); */
290
+ /* mismatch */
291
+ return 0;
292
+ }
293
+ a++;
294
+ }
295
+
296
+ return (*a == 0) ? 1 : 0;
297
+ }
298
+
299
+ static int is_black_tag(const char* s, size_t len)
300
+ {
301
+ const char** black;
302
+
303
+ if (len < 3) {
304
+ return 0;
305
+ }
306
+
307
+ black = BLACKTAG;
308
+ while (*black != NULL) {
309
+ if (cstrcasecmp_with_null(*black, s, len) == 0) {
310
+ /* printf("Got black tag %s\n", *black); */
311
+ return 1;
312
+ }
313
+ black += 1;
314
+ }
315
+
316
+ /* anything SVG related */
317
+ if ((s[0] == 's' || s[0] == 'S') &&
318
+ (s[1] == 'v' || s[1] == 'V') &&
319
+ (s[2] == 'g' || s[2] == 'G')) {
320
+ /* printf("Got SVG tag \n"); */
321
+ return 1;
322
+ }
323
+
324
+ /* Anything XSL(t) related */
325
+ if ((s[0] == 'x' || s[0] == 'X') &&
326
+ (s[1] == 's' || s[1] == 'S') &&
327
+ (s[2] == 'l' || s[2] == 'L')) {
328
+ /* printf("Got XSL tag\n"); */
329
+ return 1;
330
+ }
331
+
332
+ return 0;
333
+ }
334
+
335
+ static attribute_t is_black_attr(const char* s, size_t len)
336
+ {
337
+ stringtype_t* black;
338
+
339
+ if (len < 2) {
340
+ return TYPE_NONE;
341
+ }
342
+
343
+ /* javascript on.* */
344
+ if ((s[0] == 'o' || s[0] == 'O') && (s[1] == 'n' || s[1] == 'N')) {
345
+ /* printf("Got javascript on- attribute name\n"); */
346
+ return TYPE_BLACK;
347
+ }
348
+
349
+
350
+ if (len >= 5) {
351
+ /* XMLNS can be used to create arbitrary tags */
352
+ if (cstrcasecmp_with_null("XMLNS", s, 5) == 0 || cstrcasecmp_with_null("XLINK", s, 5) == 0) {
353
+ /* printf("Got XMLNS and XLINK tags\n"); */
354
+ return TYPE_BLACK;
355
+ }
356
+ }
357
+
358
+ black = BLACKATTR;
359
+ while (black->name != NULL) {
360
+ if (cstrcasecmp_with_null(black->name, s, len) == 0) {
361
+ /* printf("Got banned attribute name %s\n", black->name); */
362
+ return black->atype;
363
+ }
364
+ black += 1;
365
+ }
366
+
367
+ return TYPE_NONE;
368
+ }
369
+
370
+ static int is_black_url(const char* s, size_t len)
371
+ {
372
+
373
+ static const char* data_url = "DATA";
374
+ static const char* viewsource_url = "VIEW-SOURCE";
375
+
376
+ /* obsolete but interesting signal */
377
+ static const char* vbscript_url = "VBSCRIPT";
378
+
379
+ /* covers JAVA, JAVASCRIPT, + colon */
380
+ static const char* javascript_url = "JAVA";
381
+
382
+ /* skip whitespace */
383
+ while (len > 0 && (*s <= 32 || *s >= 127)) {
384
+ /*
385
+ * HEY: this is a signed character.
386
+ * We are intentionally skipping high-bit characters too
387
+ * since they are not ascii, and Opera sometimes uses UTF8 whitespace.
388
+ *
389
+ * Also in EUC-JP some of the high bytes are just ignored.
390
+ */
391
+ ++s;
392
+ --len;
393
+ }
394
+
395
+ if (htmlencode_startswith(data_url, s, len)) {
396
+ return 1;
397
+ }
398
+
399
+ if (htmlencode_startswith(viewsource_url, s, len)) {
400
+ return 1;
401
+ }
402
+
403
+ if (htmlencode_startswith(javascript_url, s, len)) {
404
+ return 1;
405
+ }
406
+
407
+ if (htmlencode_startswith(vbscript_url, s, len)) {
408
+ return 1;
409
+ }
410
+ return 0;
411
+ }
412
+
413
+ int libinjection_is_xss(const char* s, size_t len, int flags)
414
+ {
415
+ h5_state_t h5;
416
+ attribute_t attr = TYPE_NONE;
417
+
418
+ libinjection_h5_init(&h5, s, len, (enum html5_flags) flags);
419
+ while (libinjection_h5_next(&h5)) {
420
+ if (h5.token_type != ATTR_VALUE) {
421
+ attr = TYPE_NONE;
422
+ }
423
+
424
+ if (h5.token_type == DOCTYPE) {
425
+ return 1;
426
+ } else if (h5.token_type == TAG_NAME_OPEN) {
427
+ if (is_black_tag(h5.token_start, h5.token_len)) {
428
+ return 1;
429
+ }
430
+ } else if (h5.token_type == ATTR_NAME) {
431
+ attr = is_black_attr(h5.token_start, h5.token_len);
432
+ } else if (h5.token_type == ATTR_VALUE) {
433
+ /*
434
+ * IE6,7,8 parsing works a bit differently so
435
+ * a whole <script> or other black tag might be hiding
436
+ * inside an attribute value under HTML5 parsing
437
+ * See http://html5sec.org/#102
438
+ * to avoid doing a full reparse of the value, just
439
+ * look for "<". This probably need adjusting to
440
+ * handle escaped characters
441
+ */
442
+ /*
443
+ if (memchr(h5.token_start, '<', h5.token_len) != NULL) {
444
+ return 1;
445
+ }
446
+ */
447
+
448
+ switch (attr) {
449
+ case TYPE_NONE:
450
+ break;
451
+ case TYPE_BLACK:
452
+ return 1;
453
+ case TYPE_ATTR_URL:
454
+ if (is_black_url(h5.token_start, h5.token_len)) {
455
+ return 1;
456
+ }
457
+ break;
458
+ case TYPE_STYLE:
459
+ return 1;
460
+ case TYPE_ATTR_INDIRECT:
461
+ /* an attribute name is specified in a _value_ */
462
+ if (is_black_attr(h5.token_start, h5.token_len)) {
463
+ return 1;
464
+ }
465
+ break;
466
+ /*
467
+ default:
468
+ assert(0);
469
+ */
470
+ }
471
+ attr = TYPE_NONE;
472
+ } else if (h5.token_type == TAG_COMMENT) {
473
+ /* IE uses a "`" as a tag ending char */
474
+ if (memchr(h5.token_start, '`', h5.token_len) != NULL) {
475
+ return 1;
476
+ }
477
+
478
+ /* IE conditional comment */
479
+ if (h5.token_len > 3) {
480
+ if (h5.token_start[0] == '[' &&
481
+ (h5.token_start[1] == 'i' || h5.token_start[1] == 'I') &&
482
+ (h5.token_start[2] == 'f' || h5.token_start[2] == 'F')) {
483
+ return 1;
484
+ }
485
+ if ((h5.token_start[0] == 'x' || h5.token_start[1] == 'X') &&
486
+ (h5.token_start[1] == 'm' || h5.token_start[1] == 'M') &&
487
+ (h5.token_start[2] == 'l' || h5.token_start[2] == 'L')) {
488
+ return 1;
489
+ }
490
+ }
491
+
492
+ if (h5.token_len > 5) {
493
+ /* IE <?import pseudo-tag */
494
+ if (cstrcasecmp_with_null("IMPORT", h5.token_start, 6) == 0) {
495
+ return 1;
496
+ }
497
+
498
+ /* XML Entity definition */
499
+ if (cstrcasecmp_with_null("ENTITY", h5.token_start, 6) == 0) {
500
+ return 1;
501
+ }
502
+ }
503
+ }
504
+ }
505
+ return 0;
506
+ }
507
+
508
+
509
+ /*
510
+ * wrapper
511
+ */
512
+ int libinjection_xss(const char* s, size_t len)
513
+ {
514
+ if (libinjection_is_xss(s, len, DATA_STATE)) {
515
+ return 1;
516
+ }
517
+ if (libinjection_is_xss(s, len, VALUE_NO_QUOTE)) {
518
+ return 1;
519
+ }
520
+ if (libinjection_is_xss(s, len, VALUE_SINGLE_QUOTE)) {
521
+ return 1;
522
+ }
523
+ if (libinjection_is_xss(s, len, VALUE_DOUBLE_QUOTE)) {
524
+ return 1;
525
+ }
526
+ if (libinjection_is_xss(s, len, VALUE_BACK_QUOTE)) {
527
+ return 1;
528
+ }
529
+
530
+ return 0;
531
+ }