OpenVAS Libraries  9.0.3
www_funcs.c
Go to the documentation of this file.
1 /* Copyright (C) 1998 - 2003 Renaud Deraison
2  * Portions (C) 2002 - 2003 Michel Arboi
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2,
6  * as published by the Free Software Foundation
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16  *
17  */
18 
19 #include <stdlib.h>
20 #include <string.h>
21 #include <stdio.h>
22 #include <ctype.h>
23 #include <arpa/inet.h>
24 
25 #include "../base/kb.h"
26 #include "plugutils.h"
27 #include "support.h"
28 
29 /*
30  * This function implements "whisker like" IDS evasion tactics plus a couple
31  * of other methods.
32  * Read http://www.wiretrip.net/rfp/pages/whitepapers/whiskerids.html
33  *
34  * Note: RFP is not responsible for the bugs here. I (Michel Arboi) wrote it!
35  *
36  * 2002-02-26: added Pavel kankovsky's "absolute URI"
37  * 2002-03-06: added "CGI.pm parameters" by Noam Rathaus from securiteam.com
38  * Partial support: we should changed & to ; in the "posted" data.
39  * 2002-05-29: added "protocol string". See Alla Bezroutchko's message on
40  * VULN-DEV (Date: 15 Feb 2002; From: <alla@scanit.be>;
41  * Subject: Possible IDS-evasion technique
42  * Message-ID: <3C6D434B.4377034A@scanit.be>)
43  */
44 
45 /* TBD
46  * Pollute Apache logs with this:
47 
48 To make a request and to make it seem like it came from NO IP ADDRESS at
49 all, the request should be made as this :
50 
51 GET / HTTP/1.0 \r\r\n
52 
53 In this case APACHE will print in the log file the carriage return
54 character. So when we try to tail the access_log file it will be shown in
55 the screen as :
56 
57 " 414 3461.251 - - [24/Oct/2001:18:58:18 +0100] "GET / HTTP/1.0
58 
59 A normal line would be :
60 
61 127.0.0.1 - - [24/Oct/2001:19:00:32 +0100] "GET / HTTP/1.0" 200 164
62 
63 The normal line output will help us to understand that what happens is cat
64 made a carriage return after the HTTP/1.0 and printed the rest of the log
65 over the Ip Address field.
66 We can also make it look like the request came from another Ip address, and
67 this is preferable because like this the SysAdmin will see no apparent
68 strange behaviour in the logfile. Just be careful with the timestamp !!
69 So the request should be :
70 
71 GET / HTTP/1.0 \r10.0.0.1 - - [24/Oct/2001:19:00:32 +0100] "GET /
72 HTTP/1.0\r\n
73 
74 And the logfile will appear like this :
75 
76 10.0.0.1 - - [24/Oct/2001:19:00:32 +0100] "GET / HTTP/1.0" 200 164
77 
78 This is a perfect log entry and nobody can suspect on it :-)
79 
80 */
81 
82 char *
83 build_encode_URL (struct arglist *data, char *method, char *path, char *name,
84  char *httpver)
85 {
86  int i, l = 0, n_slash = 0, n_backslash = 0, start_with_slash = 0;
87  char *ret, *ret2;
88  /* NIDS evasion options */
89  char *s, *s2;
90  int double_slash, reverse_traversal, self_ref_dir;
91  int prem_req_end, param_hiding, cgipm_param;
92  int dos_win_syntax, null_method, tab_sep, http09;
93  char *abs_URI_type, *abs_URI_host;
94  char sep_c;
95 #define URL_CODE_NONE 0
96 #define URL_CODE_HEX 1
97 #define URL_CODE_UTF16 2
98 #define URL_CODE_UTF16MS 3
99 #define URL_CODE_UTF8BAD 4
100  int url_encoding;
101  char gizmo[32];
102  kb_t kb = plug_get_kb (data);
103 
104  /* Basically, we need to store the path, a slash, and the name.
105  * Encoding will expand this
106  * We'll add the method in front of all this and the HTTP version
107  * at the end when all is done. That's not optimized, but that's simpler.
108  */
109  l = path != NULL ? strlen (path) : 0;
110  l += strlen (name) + (path != NULL);
111 
113  ret = g_malloc0 (l + 1);
114  if (path == NULL)
115  strcpy (ret, name);
116  else
117  sprintf (ret, "%s/%s", path, name);
118 
119 #ifdef URL_DEBUG
120  log_legacy_write ("Request => %s\n", ret);
121 #endif
122 
123  for (s = ret; *s != '\0'; s++)
124  if (*s == '/')
125  n_slash++;
126  else if (*s == '\\')
127  n_backslash++;
128 
129  if (kb_item_get_int (kb, "NIDS/HTTP/enabled") != 1)
130  {
131  ret2 = g_strdup_printf ("%s %s %s", method, ret, httpver);
132  g_free (ret);
133  return ret2;
134  }
135 
136  start_with_slash = (*ret == '/');
137 
138  s = kb_item_get_str (kb, "NIDS/HTTP/CGIpm_param");
139  cgipm_param = (s != NULL && strcmp (s, "yes") == 0);
140  if (cgipm_param)
141  {
142 #ifdef URL_DEBUG
143  i = 0;
144 #endif
145  for (s = ret; *s != '\0' && *s != '?'; s++)
146  ;
147  if (*s == '?')
148  for (; *s != '\0'; s++)
149  if (*s == '&')
150  {
151  *s = ';';
152 #ifdef URL_DEBUG
153  i++;
154 #endif
155  }
156 #ifdef URL_DEBUG
157  if (i > 0)
158  log_legacy_write ("Request = %s\n", ret);
159 #endif
160  }
161 
162  s = kb_item_get_str (kb, "NIDS/HTTP/self_ref_dir");
163  self_ref_dir = (s != NULL && strcmp (s, "yes") == 0);
164  if (self_ref_dir)
165  {
166  l += 2 * n_slash;
167  ret2 = g_malloc0 (l + 1);
168  for (s = ret, s2 = ret2; *s != '\0' && *s != '?'; s++)
169  if (*s != '/')
170  *s2++ = *s;
171  else
172  {
173  strncpy (s2, "/./", l);
174  s2 += 3;
175  }
176  while (*s != '\0')
177  *s2++ = *s++;
178  *s2 = '\0';
179  g_free (ret);
180  ret = ret2;
181  n_slash *= 2;
182 #ifdef URL_DEBUG
183  log_legacy_write ("Request = %s\n", ret);
184 #endif
185  }
186 
187  s = kb_item_get_str (kb, "NIDS/HTTP/reverse_traversal");
188  reverse_traversal = (s == NULL ? 0 : atoi (s));
189 
190  if (reverse_traversal > 0)
191  {
192  l += (reverse_traversal + 4) * n_slash;
193  ret2 = g_malloc0 (l + 1);
194 
195  for (s = ret, s2 = ret2; *s != '\0' && *s != '?'; s++)
196  if (*s != '/')
197  *s2++ = *s;
198  else
199  {
200  *s2++ = '/';
201  for (i = reverse_traversal; i > 0; i--)
202  *s2++ = lrand48 () % 26 + 'a';
203  strncpy (s2, "/../", l);
204  s2 += 4;
205  }
206  while (*s != '\0')
207  *s2++ = *s++;
208  *s2 = '\0';
209  g_free (ret);
210  ret = ret2;
211  n_slash *= 3;
212 #ifdef URL_DEBUG
213  log_legacy_write ("Request = %s\n", ret);
214 #endif
215  }
216 
217  s = kb_item_get_str (kb, "NIDS/HTTP/premature_request_ending");
218  prem_req_end = (s != NULL && strcmp (s, "yes") == 0);
219  if (prem_req_end)
220  {
221  l += 36;
222  ret2 = g_malloc0 (l + 1);
223  n_slash += 4;
224 
225  s = gizmo;
226  *s++ = lrand48 () % 26 + 'A';
227  for (i = 1; i < 8; i++)
228  *s++ = lrand48 () % 26 + 'a';
229  *s++ = '\0';
230  snprintf (ret2, l, "/%%20HTTP/1.0%%0d%%0a%s:%%20/../..%s", gizmo, ret);
231  g_free (ret);
232  ret = ret2;
233 #ifdef URL_DEBUG
234  log_legacy_write ("Request = %s\n", ret);
235 #endif
236  }
237 
238  s = kb_item_get_str (kb, "NIDS/HTTP/param_hiding");
239  param_hiding = (s != NULL && strcmp (s, "yes") == 0);
240  if (param_hiding)
241  {
242  l += 25;
243  ret2 = g_malloc0 (l + 1);
244  n_slash += 2;
245 
246  s = gizmo;
247  for (i = 0; i < 8; i++)
248  *s++ = lrand48 () % 26 + 'a';
249  *s++ = '\0';
250  snprintf (ret2, l, "/index.htm%%3f%s=/..%s", gizmo, ret);
251  g_free (ret);
252  ret = ret2;
253 #ifdef URL_DEBUG
254  log_legacy_write ("Request = %s\n", ret);
255 #endif
256  }
257 
258  s = kb_item_get_str (kb, "NIDS/HTTP/double_slash");
259  double_slash = (s != NULL && strcmp (s, "yes") == 0);
260  if (double_slash)
261  {
262  l += n_slash;
263 
264  ret2 = g_malloc0 (l + 1);
265  for (s = ret, s2 = ret2; *s != '\0' && *s != '?'; s++)
266  if (*s != '/')
267  *s2++ = *s;
268  else
269  {
270  *s2++ = '/';
271  *s2++ = '/';
272  }
273  while (*s != '\0')
274  *s2++ = *s++;
275  *s2 = '\0';
276  g_free (ret);
277  ret = ret2;
278  n_slash *= 2;
279 #ifdef URL_DEBUG
280  log_legacy_write ("Request = %s\n", ret);
281 #endif
282  }
283 
284  s = kb_item_get_str (kb, "NIDS/HTTP/dos_win_syntax");
285  dos_win_syntax = (s != NULL && strcmp (s, "yes") == 0);
286  if (dos_win_syntax)
287  {
288  for (s = ret + 1; *s != '\0' && *s != '?'; s++)
289  if (*s == '/')
290  {
291  *s = '\\';
292  n_backslash++;
293  }
294 #ifdef URL_DEBUG
295  log_legacy_write ("Request = %s\n", ret);
296 #endif
297  }
298 
299  s = kb_item_get_str (kb, "NIDS/HTTP/URL_encoding");
300  url_encoding = URL_CODE_NONE;
301  if (s != NULL)
302  {
303  if (strcmp (s, "Hex") == 0)
304  url_encoding = URL_CODE_HEX;
305  else if (strcmp (s, "UTF-16 (double byte)") == 0)
306  url_encoding = URL_CODE_UTF16;
307  else if (strcmp (s, "UTF-16 (MS %u)") == 0)
308  url_encoding = URL_CODE_UTF16MS;
309  else if (strcmp (s, "Incorrect UTF-8") == 0)
310  url_encoding = URL_CODE_UTF8BAD;
311  }
312 
313 
314  switch (url_encoding)
315  {
316  case URL_CODE_UTF16:
317  case URL_CODE_UTF16MS:
318  case URL_CODE_UTF8BAD:
319  /* Let's try first without encoding [back]slashes */
320  l = (l - n_slash - n_backslash) * 6 + n_slash + n_backslash;
321  break;
322  case URL_CODE_HEX:
323  /* We do not encode slashes, as this does not work against Apache,
324  * at least apache-1.3.22-2 from redhat */
325  l = (l - n_slash) * 3 + n_slash;
326  break;
327  }
328 
329  if (url_encoding != URL_CODE_NONE)
330  {
331  ret2 = g_malloc0 (l + 1);
332 
333  for (s = ret, s2 = ret2; *s != '\0'; s++)
334  if (*s == '/'
335  ||
336  ((url_encoding == URL_CODE_UTF8BAD || url_encoding == URL_CODE_UTF16
337  || url_encoding == URL_CODE_UTF16MS) && *s == '\\'))
338  *s2++ = *s;
339  else if (s[0] == '%' && isxdigit (s[1]) && isxdigit (s[2]))
340  {
341  /* Already % encoded. Do not change it! */
342  *s2++ = *s++;
343  *s2++ = *s++;
344  *s2++ = *s;
345  }
346  else if (s[0] == '%' && tolower (s[1]) == 'u' && isxdigit (s[2])
347  && isxdigit (s[3]) && isxdigit (s[4]) && isxdigit (s[5]))
348  {
349  /* Already %u encoded. Do not change it! */
350  *s2++ = *s++;
351  *s2++ = *s++;
352  *s2++ = *s++;
353  *s2++ = *s++;
354  *s2++ = *s;
355  }
356  else if (url_encoding == URL_CODE_UTF16MS)
357  {
358  sprintf (s2, "%%u00%02x", *(unsigned char *) s);
359  /* The argument MUST be "unsigned char" */
360  s2 += 6;
361  }
362  else if (url_encoding == URL_CODE_UTF16)
363  {
364  sprintf (s2, "%%00%%%02x", *(unsigned char *) s);
365  /* The argument MUST be "unsigned char" */
366  s2 += 6;
367  }
368  else if (url_encoding == URL_CODE_UTF8BAD)
369  {
370  unsigned char c = *(unsigned char *) s;
371  sprintf (s2, "%%%02x%%%02x", 0xC0 | (c >> 6), 0x80 | (c & 0x3F));
372  s2 += 6;
373  /* Note: we could also use the raw unencoded characters */
374  }
375  else
376  {
377  sprintf (s2, "%%%02x", *(unsigned char *) s);
378  /* The argument MUST be "unsigned char", so that it stays between
379  * 0 and 255. Otherwise, we might get something like %FFFFFF42 */
380  s2 += 3;
381  if (*s == '\\')
382  n_backslash--;
383  }
384  *s2 = '\0';
385  g_free (ret);
386  ret = ret2;
387 #ifdef URL_DEBUG
388  log_legacy_write ("Request = %s\n", ret);
389 #endif
390  }
391 
392  abs_URI_type = kb_item_get_str (kb, "NIDS/HTTP/absolute_URI/type");
393  if (start_with_slash && abs_URI_type != NULL
394  && strcmp (abs_URI_type, "none") != 0)
395  {
396 #ifndef MAXHOSTNAMELEN
397 # define MAXHOSTNAMELEN 64
398 #endif
399  char h[MAXHOSTNAMELEN];
400 
401  abs_URI_host = kb_item_get_str (kb, "NIDS/HTTP/absolute_URI/host");
402  h[0] = '\0';
403  if (abs_URI_host != NULL)
404  {
405  if (strcmp (abs_URI_host, "host name") == 0)
406  {
407  if ((s = (char *) plug_get_hostname (data)) != NULL)
408  strncpy (h, s, sizeof (h));
409  h[sizeof (h) - 1] = '\0';
410  }
411  else if (strcmp (abs_URI_host, "host IP") == 0)
412  {
413  struct in6_addr *ptr;
414 
415  if ((ptr = plug_get_host_ip (data)) != NULL)
416  {
417  char *asc = addr6_as_str (ptr);
418  strncpy (h, asc, sizeof (h));
419  g_free (asc);
420  }
421  h[sizeof (h) - 1] = '\0';
422  }
423  else if (strcmp (abs_URI_host, "random name") == 0)
424  {
425  for (s2 = h, i = 0; i < 16; i++)
426  *s2++ = lrand48 () % 26 + 'a';
427  *s2++ = '\0';
428  }
429  else if (strcmp (abs_URI_host, "random IP") == 0)
430  sprintf (h, "%d.%d.%d.%d", rand () % 256, rand () % 256,
431  rand () % 256, rand () % 256);
432  }
433 
434  l += strlen (h) + strlen (abs_URI_type) + 3;
435  ret2 = g_malloc0 (l + 1);
436 
437  snprintf (ret2, l, "%s://%s%s", abs_URI_type, h, ret);
438  g_free (ret);
439  ret = ret2;
440 #ifdef URL_DEBUG
441  log_legacy_write ("Request = %s\n", ret);
442 #endif
443  }
444 
445 
446  s = kb_item_get_str (kb, "NIDS/HTTP/null_method");
447  null_method = (s != NULL && strcmp (s, "yes") == 0);
448  if (null_method)
449  {
450  l += 3;
451  ret2 = g_malloc0 (l + 1);
452  strncpy (ret2, "%00", l);
453  strncpy (ret2 + 3, ret, (l - 3));
454  g_free (ret);
455  ret = ret2;
456  }
457 
458  l += strlen (method) + 1;
459 
460  s = kb_item_get_str (kb, "NIDS/HTTP/http09");
461  http09 = (s != NULL && strcmp (s, "yes") == 0);
462  if (!http09)
463  {
464  s = kb_item_get_str (kb, "NIDS/HTTP/protocol_string");
465  if (s != NULL && *s != '\0')
466  httpver = s;
467  l += strlen (httpver) + 2;
468  }
469 
470 
471  s = kb_item_get_str (kb, "NIDS/HTTP/tab_separator");
472  tab_sep = (s != NULL && strcmp (s, "yes") == 0);
473  sep_c = (tab_sep ? '\t' : ' ');
474 
475  ret2 = g_malloc0 (l + 1);
476  if (http09)
477  snprintf (ret2, l, "%s%c%s", method, sep_c, ret);
478  else
479  snprintf (ret2, l, "%s%c%s%c%s", method, sep_c, ret, sep_c, httpver);
480  g_free (ret);
481  ret = ret2;
482 
483 #ifdef URL_DEBUG
484  log_legacy_write ("Request <= %s\n", ret);
485 #endif
486  return ret;
487 }
#define URL_CODE_NONE
#define URL_CODE_UTF16
void log_legacy_write(const char *format,...)
Legacy function to write a log message.
#define URL_CODE_HEX
kb_t plug_get_kb(struct arglist *args)
Definition: plugutils.c:710
#define MAXHOSTNAMELEN
Top-level KB. This is to be inherited by KB implementations.
Definition: kb.h:102
#define URL_CODE_UTF8BAD
char * addr6_as_str(const struct in6_addr *addr6)
struct in6_addr * plug_get_host_ip(struct arglist *desc)
Definition: plugutils.c:216
const char * name
Definition: nasl_init.c:524
char * build_encode_URL(struct arglist *data, char *method, char *path, char *name, char *httpver)
Definition: www_funcs.c:83
const char * plug_get_hostname(struct arglist *desc)
Definition: plugutils.c:190
#define URL_CODE_UTF16MS