Overview of http_func.inc

Public Variable Summary

Public variables are intended to be accessed by the code that imports this library.

Name Summary
OPENVAS_HTTP_USER_AGENT

Public Function Summary

Public functions are intended to be called by the code that imports this library.

Name Summary
can_host_asp
can_host_php
cgi_dirs
check_win_dir_trav
do_check_win_dir_trav
get_http_banner
get_http_port
headers_split
hex2dec
http_40x
http_gunzip
http_host_name
http_is_dead
http_recv
http_recv_body
http_recv_headers2
http_recv_length
http_send_recv
make_list_unique
php_ver_match

Private Function Summary

Private functions are not intended to be called by the code that imports this library. There is no functional difference between private and public functions, only convention, and they may be called as normal.

Name Summary
__hex_value

Public Variable Details

OPENVAS_HTTP_USER_AGENT

top

Public Function Details

can_host_asp

Named Parameters

port

Code

function can_host_asp( port ) {

  local_var banner, sig, files;

  if( ! port ) set_kb_item( name: "nvt_debug_empty/" + get_script_oid(), value:get_script_oid() + "#-#port#-#can_host_asp" );

  banner = get_http_banner( port:port );
  if( ! banner ) {
    return 0;
  } else {
    if( egrep( pattern:"^Server:.*IIS", string:banner, icase:TRUE ) ) {
      #display( get_host_ip(), " may host ASP\n" );
      return 1;
    }
  }

  if( tolower( banner ) =~ 'powered.*asp' || tolower( banner ) =~  "server.*asp.*" ) return TRUE;

  #TBD: Move before the banner check?
  files = get_kb_list( "www/" + port + "/content/extensions/asp" );
  if( ! isnull( files ) ) {
    #display( get_host_ip(), " hosts ASP - ", files[0], "\n" );
    return 1; # Hosting .asp files
  }

  sig = banner;
  if( ! sig ) { #TBD: This looks wrong...
    #display( get_host_ip(), " has no sig\n" ); 
    # Could not fingerprint it, even though we know that IIS fingerprint
    # is quite reliable 
    if( egrep( pattern:"^Server:.*", string:banner, icase:TRUE ) ) {
      return 0;
    } else {
      return 1; # Unknown web server - might be able to host a ASP website
    }
  }

  if( egrep( pattern:"iis", string:sig, icase:TRUE ) ) {
    #display( get_host_ip(), " may be ASP site (sig)\n" );
    return 1;
  } else {
    #display( get_host_ip(), " is definitely NOT a ASP site (sig) - ", sig, "\n" );
    return 0;
  }
}

function http_40x( port, code ) {

		
top

can_host_php

Named Parameters

port

Code

function can_host_php( port ) {

  local_var banner, sig, files;

  if( ! port ) set_kb_item( name: "nvt_debug_empty/" + get_script_oid(), value:get_script_oid() + "#-#port#-#can_host_php" );

  if( get_kb_item( "www/"+port+"/PHP" ) ) return TRUE;

  banner = get_http_banner( port:port );

  if( ! banner ) {
    return 0;
  } else {

    if( tolower( banner ) =~ 'powered.*php' || tolower( banner ) =~ "server.*php.*" ) return TRUE; 

    if( egrep( pattern:"^Server:.*IceWarp", string:banner, icase:TRUE ) ) {
      return 1;
    }

    if( egrep( pattern:"^Server:.*apache|nginx|thttpd|aolserver|pi3web|zeus|iis", string:banner, icase:TRUE ) ) {
      #display( get_host_ip(), " may host PHP\n" );
      return 1;
    }
  }

  #TBD: Move before the banner check?
  files = get_kb_list( "www/" + port + "/content/extensions/php*" );
  if( ! isnull( files ) ) {
    #display( get_host_ip(), " hosts PHP - ", files[0], "\n" );
    return 1; # Hosting .php+ files
  }

  sig = banner;
  if( ! sig ) { 
    return 1; # Unknown web server - might be able to host a PHP website
  }

  if( egrep( pattern:"apache|thttpd|aolserver|pi3web|zeus|iis", string:sig, icase:TRUE ) ) {
    #display( get_host_ip(), " may be PHP site (sig)\n" );
    return 1;
  } else {
    #display( get_host_ip(), " is definitely NOT a PHP site (sig) - ", sig, "\n" );
    return 0;
  }
}

function can_host_asp( port ) {

		
top

cgi_dirs

Named Parameters

port

Code

function cgi_dirs( port ) {

  local_var kb;

  if( get_kb_item( "Settings/disable_cgi_scanning" ) ) return NULL;

  if( port ) {
    kb = get_kb_list( "www/" + port + "/content/directories" );
  } else {
    kb = get_kb_list( "www/*/content/directories" );
  }

  usercgis = get_kb_list( "/user/cgis" );
  if( isnull( usercgis ) ) usercgis = "/";
  if( isnull( kb ) ) {
    kb = make_list( usercgis, "/cgi-bin", "/scripts", "/" );
  } else {
    kb = make_list( usercgis, kb, "/" );
  }

  return( make_list_unique( kb ) );
}

function can_host_php( port ) {

		
top

check_win_dir_trav

Named Parameters

port
quickcheck
url

Code

function check_win_dir_trav( port, url, quickcheck ) {
  if( do_check_win_dir_trav( port:port, url:url + rand(), quickcheck:quickcheck ) )
    return NULL;
  else
    return do_check_win_dir_trav( port:port, url:url, quickcheck:quickcheck );
}

function http_recv_headers2( socket ) {

		
top

do_check_win_dir_trav

Named Parameters

port
quickcheck
url

Code

function do_check_win_dir_trav( port, url, quickcheck ) {

  local_var soc, req, cod, buf;

  if( ! port ) set_kb_item( name: "nvt_debug_empty/" + get_script_oid(), value:get_script_oid() + "#-#port#-#do_check_win_dir_trav" );
  if( ! url ) set_kb_item( name: "nvt_debug_empty/" + get_script_oid(), value:get_script_oid() + "#-#url#-#do_check_win_dir_trav" );

  #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, code:cod );

  if( "content-encoding: gzip" >< tolower( buf ) )
    buf = http_gunzip( buf:buf );

  http_close_socket( soc );

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

  if( "; for 16-bit app support" >< buf || "[boot loader]" >< buf ) {
    return( 1 );
  }
  return( 0 );
}

function check_win_dir_trav( port, url, quickcheck ) {

		
top

get_http_banner

Named Parameters

file
port

Code

function get_http_banner( port, file ) {

  local_var soc, sb, banner, req, body;

  if( ! port ) set_kb_item( name: "nvt_debug_empty/" + get_script_oid(), value:get_script_oid() + "#-#port#-#get_http_banner" );

  if( ! file ) file = "/";

  if( get_kb_item( "Services/www/" + port + "/broken" ) ) return NULL;

  if( ! get_port_state( port ) ) return (0);

  sb = strcat( "www/real_banner/", port, file );
  banner = get_kb_item( sb );
  if( banner ) return( banner );

  sb = strcat( "www/banner/", port, file );
  banner = get_kb_item( sb );
  if( banner ) return( banner );

  soc = http_open_socket( port );
  if( ! soc ) return( NULL );
  req = http_get( item:file, port:port );
  send( socket:soc, data:req );
  banner = http_recv_headers2( socket:soc );
  #body = http_recv_body( socket:soc, headers:banner );
  http_close_socket( soc );
  if( banner ) replace_kb_item( name:sb, value:banner );
  return( banner );
}

# Submitted by Georges Dagousset

		
top

get_http_port

Named Parameters

default

Code

function get_http_port( default ) {

  local_var default, port, p;

  if( ! default ) set_kb_item( name: "nvt_debug_empty/" + get_script_oid(), value:get_script_oid() + "#-#default#-#get_http_port" );

  port = get_kb_item( "Services/www" );
  if( port ) default = port;

  p = get_kb_item( "Services/www/" + default + "/broken" );
  if( p ) exit( 0 );

  p = get_kb_item( "Services/www/" + default + "/working" );
  if( p ) return default;

  if( ! get_port_state( default ) ) exit( 0 );

  return default;
}

# (C) Georges Dagousset

		
top

headers_split

Named Parameters

h

Code

function headers_split( h ) {

  local_var ret, array, item, subarray, end;

  if( ! h ) set_kb_item( name: "nvt_debug_empty/" + get_script_oid(), value:get_script_oid() + "#-#h#-#headers_split" );

  end = strstr( h, '\r\n\r\n' );
  if( end ) h -= end;

  array = split( h, keep:FALSE );
  foreach item( array ) {
    subarray = split( item, sep:':', keep:FALSE );
    ret[tolower( subarray[0] )] = ereg_replace( pattern:"^ *", replace:"", string:subarray[1] );
  }
  return ret;
}

#

		
top

hex2dec

Named Parameters

xvalue

Code

function hex2dec( xvalue ) {

  local_var ret, l, i, n, m;

  if( ! xvalue ) {
    set_kb_item( name: "nvt_debug_empty/" + get_script_oid(), value:get_script_oid() + "#-#xvalue#-#hex2dec" );
    return(0);
  }

  xvalue = tolower( xvalue );
  if( '\r\n' >< xvalue ) {
    l = strlen( xvalue ) - 2;
  } else if( '\n' >< xvalue ) {
    l = strlen( xvalue ) - 1;
  } else {
    l = strlen( xvalue );
  }

  ret = 0;
  m = 1;
  if( l == 0 ) return 0;

  # Remove the trailing spaces
  while( xvalue[l - 1] == " " && l > 0 ) l--;

  for( i = l; i > 0; i-- ) {
    n = __hex_value( num:xvalue[i - 1] ) * m;
    ret = ret + n;
    m = m * 16;
  }
  return int( ret );
}

function get_http_banner( port, file ) {

		
top

http_40x

Named Parameters

code
port

Code

function http_40x( port, code ) {

  local_var no404;

  if( ! port ) set_kb_item( name: "nvt_debug_empty/" + get_script_oid(), value:get_script_oid() + "#-#port#-#http_40x" );
  if( ! code ) set_kb_item( name: "nvt_debug_empty/" + get_script_oid(), value:get_script_oid() + "#-#code#-#http_40x" );

  if( ereg( string:code, pattern:"^HTTP/1\.[01] +40[0-9]" ) )
    return TRUE;

  no404 = get_kb_item( "www/no404/" + port );
  if( no404 && no404 >< code )
    return TRUE;
  return FALSE;
}

function http_gunzip( buf, onlybody ) {

		
top

http_gunzip

Named Parameters

buf
onlybody

Code

function http_gunzip( buf, onlybody ) {

  local_var onlybody, lines, line, sep, header, body, h, tmpdir, tmpfile, tmpfile_gz, res;

  if( ! buf ) {
    set_kb_item( name: "nvt_debug_empty/" + get_script_oid(), value:get_script_oid() + "#-#buf#-#http_gunzip" );
    return FALSE;
  }

  if( "##**##UNZIPPED##**##" >< buf ) return buf; 

  if( "content-encoding: gzip" >!< tolower( buf ) && ! onlybody ) return buf;

  if( ! onlybody ) {

    lines = split( buf, keep:FALSE );

    foreach line( lines ) {

      if( ! sep && line !~ "^$" )
        header += line + '\n';

      if( line =~ "^$" && ! body ) {
        sep = TRUE;
        continue;
      }

      if( sep )
        body += line + '\n';
    }
  } else {
    body = buf;
  }

  if( ! body ) return buf;

  if( defined_func( "gunzip" ) ) {

    if( body = gunzip( data:body ) ) {

      if( onlybody ) return body + '\n\n\n##**##UNZIPPED##**##';

      h = ereg_replace( string:header, pattern:'(content-encoding:[^\r\n]+[\r\n]+)', replace:"", icase:TRUE );
      return( h + '\r\n\r\n' + body + '\n\n\n##**##UNZIPPED##**##' );
    } 
    return buf;
  } else {

    if( ! find_in_path( "gunzip" ) ) return buf;

    tmpdir = get_tmp_dir();
    if( ! tmpdir ) return buf;

    file = "openvas_" + rand();
    tmpfile = tmpdir + file;
    tmpfile_gz = tmpfile + '.gz';

    if( ! fwrite( data:body + '\r\n', file:tmpfile_gz ) ) return buf;

    argv[i++] ="gunzip";
    argv[i++] = tmpfile_gz;

    res = pread( cmd:"gunzip", argv:argv, cd:0 );

    if( file_stat( tmpfile_gz ) ) unlink( tmpfile_gz );

    if( file_stat( tmpfile ) ) {

      res = fread( tmpfile );
      unlink( tmpfile );

      if( ! res ) return buf;

      if( onlybody ) return res + '\n\n\n##**##UNZIPPED##**##';

      h = ereg_replace( string:header, pattern:'(content-encoding:[^\r\n]+[\r\n]+)', replace:"", icase:TRUE );
      return h + '\r\n\r\n' + res  + '\n\n\n##**##UNZIPPED##**##';
    }
  }   
  return buf;
}

function http_host_name( port ) {

		
top

http_host_name

Named Parameters

port

Code

function http_host_name( port ) {

  if( ! port ) set_kb_item( name: "nvt_debug_empty/" + get_script_oid(), value:get_script_oid() + "#-#port#-#http_host_name" );

  host = get_host_name();
  if( port ) {
    if( port != 80 && port != 443 )
      host += ':' + port;
  }
  return host;
}

function make_list_unique( ) {

		
top

http_is_dead

Named Parameters

port
retry

Code

function http_is_dead( port, retry ) {

  local_var soc, url, req, code, h, h2, b, i;

  if( ! port ) set_kb_item( name: "nvt_debug_empty/" + get_script_oid(), value:get_script_oid() + "#-#port#-#http_is_dead" );

  if( ! retry ) retry = 2;

  i = 0;
  soc = http_open_socket( port );
  while( ! soc && i++ < retry ) {
    sleep( 1 ); # Should we use sleep(i) ?
    soc = http_open_socket( port );
    #display("i = ", i, "\n");
  }
  if( ! soc ) return( 1 );
  # NB: http_head does not work against SWAT & VNC (& probably others...)
  url = strcat( "/OpenVASTest", rand(), ".html" );
  req = http_get( item:url, port:port );

  send( socket:soc, data:req );
  code = recv_line( socket:soc, length:1024 );
  if( code ) {
    h = http_recv_headers2( socket:soc );
    h2 = strcat( code, h );
    b = http_recv_body( socket:soc, headers:h2 );
  }
  http_close_socket( soc );
  if( ! code ) return( 1 );
  # 500: internal server error
  # 501: not implemented = unsupported method...
  # 502: Bad gateway = upstream server sends an invalid response
  # 503: service unavailable = temporary overloading...
  # 504: gateway timeout = no timely response from upstream server
  if( ereg( pattern:"^HTTP/1\.[01] +50[234]", string:code ) ) return( 1 );
  return( 0 );
}

# This function was originally written by SecurITeam in 

		
top

http_recv

Named Parameters

code
socket

Code

function http_recv( socket, code ) {

  local_var h, b, l;

  if( ! socket ) set_kb_item( name: "nvt_debug_empty/" + get_script_oid(), value:get_script_oid() + "#-#socket#-#http_recv" );

  if( code ) {
    h = strcat( code ); # Convert to string, just in case
    repeat
    {
      l = recv_line( socket:socket, length:2048 );
      h = h + l;
    }
    until( ! l || l =~ '^[\r\n]+$' ); # EOF or empty line
    if( ! l ) return h;
  } else {
    h = http_recv_headers2( socket:socket );
    if( ! h ) return( NULL );
    else if( ! ereg( pattern:"^HTTP/.* [0-9]*", string:h ) ) return h;
    h = strcat( h, '\r\n' );
  }
  b = http_recv_body( socket:socket, headers:h, length:0 );
  return strcat( h, b );
}

function http_recv_length( socket, bodylength ) {

		
top

http_recv_body

Named Parameters

headers
length
socket

Code

function http_recv_body( socket, headers, length ) {

  local_var h, cl, l, min, max, x, n, to, gzip;

  if( ! socket ) set_kb_item( name: "nvt_debug_empty/" + get_script_oid(), value:get_script_oid() + "#-#socket#-#http_recv_body" );

  if( ! headers ) {
    h = http_recv_headers2( socket:socket );
  } else {
    h = headers;
  }

  l = -1;
  cl = egrep( pattern:"^Content-length: *[0-9]+", string:h, icase:TRUE );
  if( "content-encoding: gzip" >< tolower( h ) ) gzip = TRUE;

  if( cl ) {
    l = int( ereg_replace( pattern:"Content-length: *([0-9]+).*", replace:"\1", string:cl, icase:TRUE ) );
  }
  # "l" = Content-Length or -1 now

  max = -1;
  min = -1;

  if( l < 0 && egrep( pattern:"^transfer-encoding: chunked", string:h, icase:TRUE ) ) {

    local_var tmp, body;
    body = "";
 
    while( 1 ) {
      tmp = recv_line( socket:socket, length:4096 );
      l = hex2dec( xvalue:tmp );
      body = strcat( body, recv( socket:socket, length:l, min:l ) );
      # "\r\n"
      recv( socket:socket, length:2, min:2 );
      if( l == 0 ) {
        return( body ); # This is expected - don't put this line before the previous
      }
    }
  }

  if( length ) max = length;
  if( l >= 0 ) min = int( l );
  if( l >= max || min >= max ) max = l;
  if( max < 0 ) {
    #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 > 0 ) {
    x = recv( socket:socket, length:max, min:min );
  } else {
    n = recv( socket:socket, min:max, length:max );
    x = n;
    while( strlen( n ) >= max && max != 0 ) {
      n = recv( socket:socket, length:max );
      x += n;
      if( strlen( x ) > 1048576 ) {
        display( "http_recv_body: read stopped after 1 MB!\n" );
        break;
      }
    }
  }

  if( gzip ) return http_gunzip( buf:x, onlybody:FALSE );

  return( x );
}

# This function reads everything

		
top

http_recv_headers2

Named Parameters

socket

Code

function http_recv_headers2( socket ) {

  local_var buf, line, counter;

  if( ! socket ) set_kb_item( name: "nvt_debug_empty/" + get_script_oid(), value:get_script_oid() + "#-#socket#-#http_recv_headers2" );

  while( TRUE ) {
    counter ++;
    line = recv_line( socket:socket, length:4096 );
    buf += line;
    if( line == '\r\n' ) break;
    if( ! strlen( line ) ) break;
    if( counter > 1024 ) break;
  }

  return buf;
}

# This function does not return the headers!

		
top

http_recv_length

Named Parameters

bodylength
socket

Code

function http_recv_length( socket, bodylength ) {

  local_var h, b;

  if( ! socket ) set_kb_item( name: "nvt_debug_empty/" + get_script_oid(), value:get_script_oid() + "#-#socket#-#http_recv_length" );
  if( ! bodylength ) set_kb_item( name: "nvt_debug_empty/" + get_script_oid(), value:get_script_oid() + "#-#bodylength#-#http_recv_length" );

  h = http_recv_headers2( socket:socket );
  b = http_recv_body( socket:socket, headers:h, length:bodylength );
  return strcat( h, '\r\n', b );
}

function http_send_recv( port, data ) {

		
top

http_send_recv

Named Parameters

data
port

Code

function http_send_recv( port, data ) {

  local_var s, r;

  if( ! port ) set_kb_item( name: "nvt_debug_empty/" + get_script_oid(), value:get_script_oid() + "#-#port#-#http_send_recv" );
  if( ! data ) set_kb_item( name: "nvt_debug_empty/" + get_script_oid(), value:get_script_oid() + "#-#data#-#http_send_recv" );

  s = http_open_socket( port );
  if( ! s ) return;
  send( socket:s, data:data );
  while( x = http_recv( socket:s ) ) {
    if( "content-length:" >< tolower( x ) && "206 Partial" >!< x ) {
      cl = eregmatch( pattern:"Content-Length: ([0-9]+)", string:x, icase:TRUE );
      if( ! isnull( cl[1] ) ) conlen = int( cl[1] );
    }

    r += x;
    if( ( conlen  && conlen > 0 ) && strlen( r ) >= conlen ) break;

  }

  http_close_socket( s );

  if( "content-encoding: gzip" >< tolower( r ) )
    return http_gunzip( buf:r );

  return r;

}

function cgi_dirs( port ) {

		
top

make_list_unique

Named Parameters

Code

function make_list_unique( ) {

  local_var ret, args, x, z, a, e;

  ret = make_list();
  args = make_list();

  foreach x( _FCT_ANON_ARGS ) {
    if( typeof( x ) == "array" ) { # e.g. return value from cgi_dirs()
      foreach z( x )
        args = make_list( args, z );
    } else {
      args = make_list( args, x );
    }
  }

  foreach a( args ) {

    e = FALSE;
    foreach r ( ret ) {
      if( a == r ) {
        e = TRUE; # entry already exist
        break;
      }
    }

    if( ! e ) ret = make_list( ret, a ); # entry didn't exist, add entry...
  }
  return ret;
}


		
top

php_ver_match

Named Parameters

banner
pattern

Code

function php_ver_match( banner, pattern ) {

  local_var line;

  if( ! banner ) set_kb_item( name: "nvt_debug_empty/" + get_script_oid(), value:get_script_oid() + "#-#banner#-#php_ver_match" );
  if( ! pattern ) set_kb_item( name: "nvt_debug_empty/" + get_script_oid(), value:get_script_oid() + "#-#pattern#-#php_ver_match" );

  line = egrep( pattern:"^Server:.*", string:banner, icase:TRUE );

  if( ereg( pattern:pattern, string:line, icase:TRUE ) ) {
    return( 1 );
  } else {
    line = egrep( pattern:"^X-Powered-By:.*", string:banner, icase:TRUE );
    if( ereg( pattern:pattern, string:line, icase:TRUE ) ) {
      return( 1 );
    }
  }
  return( 0 );
}

function http_is_dead( port, retry ) {

		
top

Private Function Details

__hex_value

Named Parameters

num

Code

function __hex_value( num ) {

  if( num == "a") return( 10 );
  if( num == "b") return( 11 );
  if( num == "c") return( 12 );
  if( num == "d") return( 13 );
  if( num == "e") return( 14 );
  if( num == "f") return( 15 );
  return( int( num ) );
}

function hex2dec( xvalue ) {

		
top