# -*- Fundamental -*-
#
# (C) 2002 Michel Arboi <arboi@bigfoot.com>
# get_http_port (C) Georges Dagousset
# $Revision: 1.12.2.3 $

function get_http_banner(port)
{
  if (! get_port_state(port)) return (0);

  ___sb = string("www/banner/", port);
  ___banner = get_kb_item(___sb);
  if (___banner) return(___banner);

  ___soc = http_open_socket(port);
  if(!___soc) return (0);
  ___req = http_get(item:"/", port:port);
  send(socket:___soc, data:___req);
  ___banner = recv(socket:___soc, length:5000);
  http_close_socket(___soc);
  set_kb_item(name: ___sb, value: ___banner);
  return(___banner);
}

# Submitted by Georges Dagousset
# Usage: port = get_http_port(default:80);
function get_http_port(default)
{
  ___port = get_kb_item("Services/www");
  if(!___port)___port = default;
  ___banner = get_http_banner(port:___port);
  if (! ___banner) exit(0);
  return(___port);
}

# (C) Georges Dagousset
# Usage:
# banner = get_http_banner(port:port);
# if (php_ver_match(banner:banner, 
#     pattern:".*PHP/((3.*)|(4\.0.*)|(4\.1\.[01].*))"))
#       security_hole(port);
#
function php_ver_match(banner, pattern) 
{
  ___line = egrep(pattern:"^Server:.*", string:banner);
  if(ereg(pattern:pattern, string:___line))return(1);
  else
  {
    ___line = egrep(pattern:"^X-Powered-By:.*", string:banner);
    if(ereg(pattern:pattern, string:___line))return(1);
  }
  return(0);
}

function http_is_dead(port)
{
  ___soc = http_open_socket(port);
  if(!___soc) return (1);
  # NB: http_head does not work against SWAT & VNC (& probably others...)
  ___req = http_get(item:"/", port:port);
  
  send(socket:___soc, data:___req);
  ___banner = recv(socket:___soc, length:5000);
  http_close_socket(___soc);
  if (! ___banner) return (1);
  return (0);
}

# This function was originaly written by SecurITeam in 
# badblue_directory_traversal.nasl
# I (=MA) enhanced it.
# NB: it works with AUTOEXEC.BAT, WIN.INI and BOOT.INI
# quickcheck should be set to 0 if the server does not return clean 404 code,
# i.e., if "www/no404/"+port is defined in the KB

function check_win_dir_trav(port, url, quickcheck)
{
  #display("check_win_dir_trav(port=", port, ", url=", url, ", quickcheck=", quickcheck, ")\n");
  _soc = http_open_socket(port);
  if(! _soc)
  {
   # display("check_win_dir_trav: cannot open socket to ", port, "\n");
    return (0);
  }

  _req = http_get(item:url, port:port);
  send(socket:_soc, data:_req);
  _cod = recv_line(socket: _soc, length: 80);
  _buf = http_recv(socket:_soc);
  http_close_socket(_soc);

  if (quickcheck)
  {
    if (" 200 " >< _cod) return (1);
    return (0);
  }

  if ( ("ECHO" >< _buf)          || ("SET " >< _buf)             ||
       ("export" >< _buf)        || ("EXPORT" >< _buf)           ||
       ("mode" >< _buf)          || ("MODE" >< _buf)             || 
       ("doskey" >< _buf)        || ("DOSKEY" >< _buf)           ||
       ("[boot loader]" >< _buf) || ("[fonts]" >< _buf)          ||
       ("[extensions]" >< _buf)  || ("[mci extensions]" >< _buf) ||
       ("[files]" >< _buf)       || ("[Mail]" >< _buf)           ||
       ("[operating systems]" >< _buf)              )
  {
    return(1);
  }
  return(0);
}

# This function does not return the headers!
# So 'length' parameter does not include headers length, even if we 
# have to read them. Anyway, this parameter will be ignored if Content-length
# is set

function http_recv_body(socket, headers, length)
{
  if (!headers)
  {
    __h = http_recv_headers(socket);
  }
  else
  {
    __h = headers;
  }

  __cl = egrep(pattern:"^Content-length: *[0-9]+", string: __h, icase: 1);
  __l = ereg_replace(pattern: "Content-length: *([0-9]+).*", replace:"\1",
		string: __cl, icase: 1);
  __max = 0;
  __min = 0;
  if (length) __max = length;
  if (__l) __min = __l;
  if (__l > __max) __max = __l;
  if (! __max)
  {
    #display("http_recv_body: bogus or no Content-length field, and no 'length' paramater set! Defaulting to 8 KB\n");
    __max = 8192;
  }
  #display("http_recv_body: min=", __min, "; max=", __max, "\n");
  if (__min)
  {
    __x = recv(socket: socket, length: __max, min: __min);
  }
  else
  {
    __x = recv(socket: socket, length: __max);
  }
  return(__x);
}

# This function reads everything
# Note that bodylength will be ignored if the Content-length field is set

function http_recv(socket)
{
  __h = http_recv_headers(socket);
  __b = http_recv_body(socket: socket, headers: __h, length:0);
  return (string(__h, "\r\n", __b));
}

function http_recv_length(socket, bodylength)
{
  __h = http_recv_headers(socket);
  __b = http_recv_body(socket: socket, headers: __h, length: bodylength);
  return (string(__h, "\r\n", __b));
}

function get_cgi_path(port)
{
 _k = string("www/cgi-path/", port);
 _p = get_kb_item(_k);
 if (_p) return (_p);

 _no404 = get_kb_item(string("www/no404/", port));

 # Mostly from DDI_Directory_Scanner (c) by HD Moore
 _i = 0;
 _c[_i] = "cgi-bin";	_i = _i+1;
 _c[_i] = "cgi-bin2";	_i = _i+1;
 _c[_i] = "scripts";	_i = _i+1;
 _c[_i] = "cgi";	_i = _i+1;
 _c[_i] = "cgis";	_i = _i+1;
 _c[_i] = "cd-cgi";	_i = _i+1;
 _c[_i] = "cfide";	_i = _i+1;
 _c[_i] = "cgi"; 	_i = _i+1;
 _c[_i] = "cgi-auth";	_i = _i+1;
 _c[_i] = "cgi-bin";	_i = _i+1;
 _c[_i] = "cgi-bin2";	_i = _i+1;
 _c[_i] = "cgi-csc";	_i = _i+1;
 _c[_i] = "cgi-lib";	_i = _i+1;
 _c[_i] = "cgi-local";	_i = _i+1;
 _c[_i] = "cgi-scripts"; _i = _i+1;
 _c[_i] = "cgi-shl";	_i = _i+1;
 _c[_i] = "cgi-shop";	_i = _i+1;
 _c[_i] = "cgi-sys";	_i = _i+1;
 _c[_i] = "cgi-weddico"; _i = _i+1;
 _c[_i] = "cgi-win";	_i = _i+1;
 _c[_i] = "cgibin";	_i = _i+1;
 _c[_i] = "cgilib";	_i = _i+1;
 _c[_i] = "cgiscripts";	_i = _i+1;
 _c[_i] = "cgiwin";	_i = _i+1;
 _c[_i] = 0;

 _p = "";
 for (_i = 0; _c[_i]; _i=_i+1)
 {
    _s = http_open_socket(port);
    if (_s)
    {
      _req = http_get(port: port, item: string("/", _c[_i], "/"));
      send(socket: _s, data: _req);
      if (_no404)
      {
        _h = http_recv(socket: _s);
        if (! (_no404 >< _h)) _p = string(_p, "/", _c[_i], ":");
      }
      else
      {
        _h = recv_line(socket: _s, length: 256);
        if (ereg(pattern: "^HTTP/1\.[01] +(200|403)", string: _h))
         _p = string(_p, "/", _c[_i], ":");
      }
      http_close_socket(_s);
    }
 }
 if (!_p) _p = "/cgi-bin:/scripts";
 set_kb_item(name: _k, value: _p);
 return (_p);
}

function locate_cgi(port, item)
{
  _p = get_cgi_path(port);
  #display("P=", _p, "\n");
  while (_p)
  {
    _p1 = ereg_replace(pattern: "^([^:]+):.*", string: _p, replace: "\1");
    #display("P1=", _p1, "\n");
    _p = _p - string(_p1, ":");
    _cp = string(_p1, "/", item);
    if (is_cgi_installed(port: port, item: _cp)) return (_cp);
  }
  return ("");
}
