Hi, Here's a new plugin for the myServer directory traveral vulnerability. This server gives HTTP headers like "Content-Length:1234" with no space between the colon and the value. This worked ok with the old http_func.inc functions, but broke http_keepalive.inc. I've added so *s to some regexs, which seems to have fixed this. Hope this helps, Paul -- Paul Johnston Internet Security Specialist Westpoint Limited Albion Wharf, 19 Albion Street, Manchester, M1 5LN England Tel: +44 (0)161 237 1028 Fax: +44 (0)161 237 1031 email: paul@private web: www.westpoint.ltd.uk # -*- Fundamental -*- # http_keepalive.inc # (C) Renaud Deraison # $Id: http_keepalive.inc,v 1.23 2003/09/22 13:23:40 renaud Exp $ # # # The only function which should be used by an external plugin is # http_keepalive_send_recv(port, data) which returns the result # (or NULL if no connection could be established). # # Note that the file "http_func.inc" must also be included when # using this file. # __ka_socket = 0; __ka_port = 0; __ka_enabled = -1; __ka_last_request = ""; # # Based on the last headers we received, we determine if we need # to close our socket and re-open it or not # function http_keepalive_check_connection(headers) { tmp = egrep(pattern:"^Connection: *[Cc]lose", string:headers); if(tmp) { http_close_socket(__ka_socket); __ka_socket = http_open_socket(__ka_port); } } function enable_keepalive(port) { __ka_enabled = 1; __ka_port = port; __ka_socket = http_open_socket(port); } # # This function determines if the remote web server is # keep-alive-enabled or not. # function http_keepalive_enabled(port) { local_var req, soc, r, kb; kb = get_kb_item(string("www/", port, "/keepalive")); if(kb == "yes"){ enable_keepalive(port:port); return(1); } else if(kb == "no")return(0); req = string("GET / HTTP/1.1\r\n", "Connection: Keep-Alive\r\n", "Host: ", get_host_name(), "\r\n", "Pragma: no-cache\r\n", "User-Agent: Mozilla/4.75 [en] (X11, U; Nessus)\r\n\r\n"); soc = http_open_socket(port); if(!soc)return NULL; send(socket:soc, data:req); r = http_recv(socket:soc); # Apache if(egrep(pattern:"^Keep-Alive:.*", string:r)) { http_close_socket(soc); set_kb_item(name:string("www/", port, "/keepalive"), value:"yes"); enable_keepalive(port:port); return(1); } else { # IIS send(socket:soc, data:req); r = http_recv(socket:soc); http_close_socket(soc); if(strlen(r)){ set_kb_item(name:string("www/", port, "/keepalive"), value:"yes"); enable_keepalive(port:port); return(1); } } set_kb_item(name:string("www/", port, "/keepalive"), value:"no"); return(0); } # # This function is akin to http_recv() except that if the last request # was a HEAD, we bail out (whereas http_recv() will timeout). # function http_keepalive_recv(bodyonly) { local_var headers, body, length, tmp, chunked, killme; killme = 0; length = -1; headers = http_recv_headers(__ka_socket); if(strlen(headers) == 0)headers = http_recv_headers(__ka_socket); if(ereg(pattern:"^HEAD.*HTTP/.*", string:__ka_last_request)) { # HEAD does not return a body http_keepalive_check_connection(headers:headers); if(bodyonly) return(""); else return(headers); } if("Content-Length" >< headers) { tmp = egrep(string:headers, pattern:"^Content-Length: *[0-9]*"); length = int(ereg_replace(string:tmp, pattern:"^Content-Length: *([0-9]*)", replace:"\1")); } if((length < 0) && (egrep(pattern:"transfer-encoding: *chunked", string:headers, icase:TRUE))) { while(1) { tmp = recv_line(socket:__ka_socket, length:4096); length = hex2dec(xvalue:tmp); if(length > 1024*1024*10) { length = 1024*1024; killme = 1; } body = string(body, recv(socket:__ka_socket, length:length+2, min:length+2)); if(strlen(body) > 1024*1024*10)killme = 1; if(length == 0 || killme){ http_keepalive_check_connection(headers:headers); # This is expected - don't put this line before the previous if(bodyonly) return(body); else return(string(headers,"\r\n", body)); } } } if(length >= 0) { # Don't receive more than 10MB if(length > 1024*1024*10)length = 1024*1024; body = recv(socket:__ka_socket, length:length, min:length); } else { # If we don't have the length, we close the connection to make sure # the next request won't mix up the replies. #display("ERROR - Keep Alive, but no length!!!\n", __ka_last_request); body = recv(socket:__ka_socket, length:16384); http_close_socket(__ka_socket); __ka_socket = http_open_socket(__ka_port); } http_keepalive_check_connection(headers:headers); if(bodyonly) return(body); else return(string(headers,"\r\n", body)); } #----------------------------------------------------------------------# # We close our socket on exit. function on_exit() { if(__ka_socket) { http_close_socket(__ka_socket); } } #----------------------------------------------------------------------# # # This is our "public" Keep-Alive function. It sends <data> to the remote # host on port <port>, and returns the result, or NULL if no connection # could be established. # function http_keepalive_send_recv(port, data, bodyonly) { local_var id, n, ret; if("Authorization" >!< data && get_kb_item("www/" + port + "/password_protected"))return NULL; if(__ka_enabled == -1)__ka_enabled = http_keepalive_enabled(port:port); if(__ka_enabled == 0) { local_var soc, r; soc = http_open_socket(port); if(!soc)return NULL; send(socket:soc, data:data); headers = http_recv_headers(soc); if(headers) body = http_recv_body(socket:soc, headers:headers, length:0); http_close_socket(soc); if(bodyonly) return(body); else return(string(headers, "\r\n", body)); } if((port != __ka_port)||(!__ka_socket)) { if(__ka_socket)http_close_socket(__ka_socket); __ka_port = port; __ka_socket = http_open_socket(port); if(!__ka_socket)return NULL; } id = stridx(data, string("\r\n\r\n")); data = str_replace(string:data, find:"Connection: Close", replace:"Connection: Keep-Alive", count:1); __ka_last_request = data; n = send(socket:__ka_socket, data:data); if(n <= 0) { http_close_socket(__ka_socket); __ka_socket = http_open_socket(__ka_port); if(__ka_socket == 0)return NULL; send(socket:__ka_socket, data:data); } return(http_keepalive_recv(bodyonly:bodyonly)); } # # Same as check_win_dir_trav(), but with KA support # function check_win_dir_trav_ka(port, url, quickcheck) { local_var soc, req, cod, buf; #display("check_win_dir_trav(port=", port, ", url=", url, ", quickcheck=", quickcheck, ")\n"); req = http_get(item:url, port:port); buf = http_keepalive_send_recv(port:port, data:req); if (quickcheck) { if (ereg(pattern:"^HTTP/.* 200 ", string:buf)) 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); } # # # function is_cgi_installed_ka(item, port) { local_var r, no404, dir; if(item[0] != "/") { dir = cgibin(); item = string(dir, "/", item); } r = http_keepalive_send_recv(port:port, data:http_get(item:item, port:port)); if( r == NULL ) return NULL; no404 = get_kb_item(string("www/no404/", port)); if(ereg(pattern:"^HTTP.* 200 .*", string:r)) { if(no404) { if(tolower(no404) >< tolower(r))return(0); } return(1); } return(0); } # function get_http_page(port, url, redirect) { local_var r, u, v, i, l, seen_loc, n; if (isnull(redirect)) n = 32; else if (redirect <= 0) n = 1; else n = redirect + 1; u = url; for (i = 0; i < n; i ++) # Limited iterations to avoid traps { seen_loc[u] = 1; r = http_keepalive_send_recv(port: port, data: http_get(port: port, item: u)); if (isnull(r)) return NULL; if (r =~ "^HTTP/1\.[01] +30[0-9] .*") { v = eregmatch(pattern: "\r\nLocation: *([^ \t\r\n]+)[ \t]*[\r\n]+", string: r, icase: 1); if (isnull(v)) return NULL; # Big problem l = v[1]; if (seen_loc[l]) return NULL; seen_loc[l] = 1; } else if (r =~ "^HTTP/1\.[01] +200 ") { r = strstr(r, '\r\n\r\n'); r = substr(r, 4); return r; } else # Code 4xx or 5xx return NULL; } # Loop? return NULL; } *** ../plugins/http_keepalive.inc Tue Sep 23 16:30:13 2003 --- http_keepalive.inc Fri Sep 26 12:40:44 2003 *************** *** 26,32 **** # function http_keepalive_check_connection(headers) { ! tmp = egrep(pattern:"^Connection: [Cc]lose", string:headers); if(tmp) { http_close_socket(__ka_socket); --- 26,32 ---- # function http_keepalive_check_connection(headers) { ! tmp = egrep(pattern:"^Connection: *[Cc]lose", string:headers); if(tmp) { http_close_socket(__ka_socket); *************** *** 118,130 **** if("Content-Length" >< headers) { ! tmp = egrep(string:headers, pattern:"^Content-Length: [0-9]*"); ! length = int(ereg_replace(string:tmp, pattern:"^Content-Length: ([0-9]*)", replace:"\1")); } ! if((length < 0) && (egrep(pattern:"transfer-encoding: chunked", string:headers, icase:TRUE))) { while(1) { --- 118,130 ---- if("Content-Length" >< headers) { ! tmp = egrep(string:headers, pattern:"^Content-Length: *[0-9]*"); ! length = int(ereg_replace(string:tmp, pattern:"^Content-Length: *([0-9]*)", replace:"\1")); } ! if((length < 0) && (egrep(pattern:"transfer-encoding: *chunked", string:headers, icase:TRUE))) { while(1) { # # This script was written by Paul Johnston of Westpoint Ltd <paul@private> # # See the Nessus Scripts License for details # if(description) { script_id(99002); script_version ("$Revision: 1.1 $"); name["english"] = "myServer 0.4.3 Directory Traversal Vulnerability"; script_name(english:name["english"]); desc["english"] = " This web server is running myServer <= 0.4.3. This version contains a directory traversal vulnerability, that allows remote users with no authentication to read files outside the webroot. You have to create a dot-dot URL with the same number of '/./' and '/../' + 1. For example, you can use : /././.. /./././../.. /././././../../.. /./././././../../../.. etc... More information : http://www.securityfocus.com/archive/1/339145 Solution : Upgrade to myServer 0.5.0 or later Risk factor : High"; script_description(english:desc["english"]); summary["english"] = "Attempts to retrieve the path '/././..'"; script_summary(english:summary["english"]); script_category(ACT_ATTACK); script_copyright(english:"Author Paul Johnston paul@private, Copyright (C) 2003 Westpoint Ltd"); script_family(english:"CGI abuses"); script_dependencie("find_service.nes"); script_require_ports("Services/www", 80); exit(0); } include("http_func.inc"); include("http_keepalive.inc"); port = get_kb_item("Services/www"); if(!port) port = 80; if(!get_port_state(port))exit(0); req = http_get(item:"/././..", port:port); res = http_keepalive_send_recv(port:port, data:req); if(res == NULL) exit(0); if(ereg(pattern:"^HTTP/[0-9]\.[0-9] 200 ", string:res) && egrep(pattern:"Contents of folder \.\.", string:res, icase:1)) { security_hole(port); }
This archive was generated by hypermail 2b30 : Fri Sep 26 2003 - 04:49:41 PDT