Visit our newest sister site!
Hundreds of free aircraft flight manuals
Civilian • Historical • Military • Declassified • FREE!

TUCoPS :: Unix :: Various Flavours :: misc5713.htm

Remote system compromise in WASD OpenVMS http server

27th Sep 2002 [SBWID-5713]

	Remote system compromise in WASD OpenVMS http server


	WASD 7.1, 7.2 (up to 7.2.3), 8.0, and possibly earlier versions.


	Thanks to Jean-loup Gailly [] advisory,  this  document
	is available at [] :

	WASD VMS Hypertext  Services  is  a  popular  http  server  for  OpenVMS
	released  under  the  GNU  GPL.  See   The
	default installation of the WASD server allows:

	  - universal directory traversal

	  - instant access to the entire web server tree

	  - trivial bypassing of access control rules

	  - getting the location of the document root

	  - read access to the whole web server configuration

	  - read access to all web server logs

	  - disclosure of directories supposed to be hidden

	  - getting the list of all cgi scripts

	  - getting the sources of all cgi scripts

	  - read access to OpenVMS system files

	  - user home directories might be readable

	  - one very serious flaw in a cgi script enabled by default

	  - some problems with other cgi-scripts enabled by default




	 1.1 The builtin "tree" script


	     By default the entire directory tree of the web server can be

	     seen with http://webserver/tree/




	   .1.2 "/*.*" directory traversal


	     Universal directory traversal is builtin with

	     http://webserver/dirname/*.* even if there is a page /dirname/index.html



	   .1.3 The builtin "upd" script


	     A nice graphical interface for directory traversal is builtin with

	     http://webserver/upd/dirname/ even if there is a page /dirname/index.html



	   .1.4 The builtin search 


	     All documents can be searched by default.



	   .1.5 Most of the server root is accessible by default


	     The document root is the main server root, which includes everything

	     (configuration files, scripts, executables, etc...). Directory traversal

	     is enabled on most of the directories and access to the other

	     directories is possible anyway (see later).


	   The WASD documentation states that the liberal option was on purpose:


	     "The default configuration is fairly liberal, providing information

	      of use in a technical environment, but that may be superfluous or

	      less-than-desirable in other, possibly commercial environments."


	   OpenVMS has a reputation of being a very secure operating system.  This may

	   explain why VMS system administrators may have a false sense of security

	   when installing the WASD web server and leave the default configuration

	   almost untouched.


	   The default configuration in WASD 8.1 will be much more restrictive.



	   2 The access control rules can be trivially bypassed


	   All the liberal features described above can be used to bypass

	   the few restrictions set by the web server.


	   .2.1 Bypassing access restrictions set by the web server


	     The configuration file httpd$map.conf contains rules such as:


		pass /ht_root/wwwroot*

		fail /ht_root/*

		fail /-/*


	      In this example, the server root is ht_root and the document root is

	      wwwroot. The "fail" rules attempt to restrict access to the server

	      root but can be trivially bypassed with:




	     (note: "-" is the VMS equivalent of ".."). So the only real protection

	     comes from the directory protections and ACLs (access control lists)

	     imposed by the operating system. (See section "Solutions" below.)


	   .2.2 The location of the document root can easily be obtained


	     The location of the document root can easily be obtained with the "where"

	     builtin script.



	     Even if the "where" script is not enabled, the "404 not found" message

	     gives away the document root.  On a server where the document root was

	     (correctly) not the entire web server root (logical name HT_ROOT), the

	     real document root could still be obtained with

	     http://theserver/notfound which gives "Document not found ...

	     /ht_root/wwwroot/notfound" This allows getting the entire web server

	     root with http://theserver/ht_root/wwwroot/-/*.* as described above.


	     The full physical path may also be given hidden as a comment in the html

	     returned in the "404 not found" message:


	         <!-- sts: %X00018292 "$1$DUA2:[HT_ROOT.][WWWROOT]NOTFOUND" -->


	   .2.3 The full web server configuration can easily be obtained


	     The web server configuration file in ht_root/local/httpd$map.conf

	     is generally supposed to be protected by a fail rule:


	        fail /ht_root/local/*


	     However this can often be trivially bypassed as shown above:




	      On one of the machines tested, there was even no "fail" rule so the

	      configuration could be obtained directly as




	      The configuration file httpd$map.conf gives a lot of information to

	      intruders, in particular all the access control rules, all the script

	      directories, all the virtual domains handled, all the accessible

	      directories not under ht_root, etc...


	   .2.4 All the web server logs can easily be obtained


	      This is just a variation on the above. There is generally a rule


	         fail /ht_root/log/*


	      but all the logs can generally be obtained with


	      unless they are protected with adequate ACLs.


	      If the logs are protected by ACLs but you have a user account on

	      the machine hosting the web server, then some of the logs may still

	      be obtained because the last request may be available in the

	      logical name (environment variable) HTTPD80$REQUEST :


	      $ show log HTTPD80$REQUEST

	      "HTTPD80$REQUEST" = "08 11:56:42.200.430.5287.0.9000.http://theserver:

	       80.ip.address.of.caller.GET /filename"


	      The logical name is dynamically updated at each request. However this

	      was observed on only one system with an old version of WASD so the

	      problem may be fixed in 8.0.


	    .2.5 The "tree" builtin script shows directories supposed to be hidden


	      The server logs are actually in a subdirectory /ht_root/log/server/

	      Since there is generally a fail rule for /ht_root/log/*

	      the subdirectory server is supposed to be hidden, but the "tree"

	      builtin script happily shows it:




	    .2.6 Directory protection can be bypassed anyway


	      Some directories are better protected and are not even visible with

	      the "tree" builtin scripts. On one tested site, the directory

	      /ht_root/script_local/ exists but cannot be seen with

	      /ht_root/script_local/*.* or with /tree/. This site has probably used

	      the following configuration described in


	        [DirAccess] - Make "disabled" to completely remove the ability

	        to generate directory listings under any circumstances.


	      However the search feature comes to rescue, and the directory

	      (together will all its scripts, see next section) can still be seen

	      with http://theserver/.../*.com?search=$


	      If even the standard search feature has been disabled, one can also

	      try the default glist script, which is supposed to give only a list

	      of images but also gives all subdirectories:




	      In any case, on this particular server the directory script_local

	      is given in /robots.txt so it is not difficult to see that it exists.


	    .2.7 The list of cgi scripts can easily be obtained


	      It is not possible to see the list of cgi scripts with the url

	      http://theserver/cgi-bin/*.* however the scripts are generally in

	      ht_root/script/ or ht_root/script_local.  If a configuration rule is

	      supposed to block access to these directories (either because the

	      document root is correctly separated from the server root, or because

	      there is an explicit rule blocking script/*), it is generally possible

	      to get the list of scripts and their sources with an url such as:




	      For cgi scripts of users, which can be run with url




	      it is a bit less trivial to obtain the list of scripts because

	      the obvious attempts fail:




	      but the following generally works:




	      where xxx doesn't have to be an existing directory.


	      If it doesn't work, then the search feature can generally be used:




	      (note: on OpenVMS "..." indicates directory recursion).  This searches

	      all the *.com scripts for the character $ which always starts a command

	      on OpenVMS, and so gives as a result the full list of all .com scripts

	      under all subdirectories of the home directory. It is even possible to

	      search *.* instead of *.com.


	    .2.8 The sources of cgi scripts can easily be obtained


	      After the list of scripts has been obtained as above, it is trivial

	      to get the sources of the scripts by clicking on a link. For general

	      server scripts the link can be of the form:




	      For user scripts obtained by the search feature, the link is:




	      Here "extract" is a script provided by default by WASD. It allows

	      getting the source of a script instead of executing it, even if the

	      directory containing the script is named cgi-bin.


	    .2.9 OpenVMS system files can generally be read


	       On several tested sites, a configuration rule is supposed to

	       give access to only a selected portion of system files:


	         pass /sys$common/syslib/* /sys$common/syslib/*


	       However other system files can easily be read, for example



	     .2.10 User home directories might be readable


	       It is common practice to map url http://theserver/~username/ to 

	       a subdirectory /user_disk/username/web/ of the home directory

	       /user_disk/username/. But if the OpenVMS protections and ACLs on

	       the home directory are not set correctly, it is possible to traverse

	       it with: 




	       Actually this often returns an error because of a strange mapping rule:


	         pass /*/-/* /ht_root/runtime/*/*


	       but it is easy to work around this rule with:




	       where x doesn't have to be the name of an existing directory,

	       and "--" represents for VMS the equivalent of "../.."


	       In one of the sites tested, there was even no mapping to a subdirectory

	       so the whole user home directory was available with





	   3  CGI scripts are run by default under the identity of the main server


	     By default the server runs the image httpd.exe (or httpd_ssl.exe)

	     under the identity of user http$server. CGI scripts are also run by

	     default under the same identity. Thus a flaw in one CGI script can affect

	     the entire server.


	     On Unix, the main server is typically run as root but CGI scripts are

	     typically run under user "nobody". Thus a bad script cannot affect the

	     entire server.


	     The WASD server allows running CGI scripts as a user other than

	     http$server. This will be the default in WASD 8.1.



	   4 Problems with some cgi scripts enabled by default


	     I have not studied all scripts provided in a default installation

	     of WASD. But at least one is very dangerous and there are some bugs

	     in others.


	     .4.1 Write to an arbitrary file on the web server


	       One script enabled by default allows writing contents of the attacker's

	       choice to an arbitrary file on the server, as long as the VMS ACLs

	       allows it. This flaw can be exploited to get a remote SYSTEM (root)



	       Given the severity of this flaw, no details are given here. See the

	       "Solutions" section below for temporary workarounds.


	     .4.2 Severe leakage of information in


	       Running http://theserver/cgi-bin/cgi_process gives a *lot* of useful

	       information for an intruder. In particular it gives all the privileges

	       owned by the script while running. (For Unix users: a script run with

	       privileges is somewhat equivalent to a setuid or setgid program, but

	       with much finer control on the actions allowed for the program.)


	       On one system, the script could be run with the SETPRV privilege, which

	       is equivalent to setuid root on Unix. This tells an intruder that

	       efforts should be concentrated on this particularly vulnerable server.


	     .4.3 Format string bug in



	       for a description of this script and its sources. It contains

	       in particular:


		   printf ("$name=\"$ENV{$name}\"\n");


	       The variable $name comes from the user and is not filtered, so a

	       classic format string attack is possible. For example:


	       (where %25 is the hex encoding of the character '%') gives:




		  REQUEST_URI="/plrte/PerlRTE_example1/   0   0   0"


	       where the number of zeroes is the number of %x format indicators.

	       This bug is probably not exploitable, but this should be checked.


	       This script also gives away a lot of potentially useful information

	       for an intruder (all logical names).


	     .4.4 Potential denial of service in


	       The cgi script allows printing a file on the server

	       from a remote location. This script is enabled by default. The source

	       is available at

	       This script attempts to restrict the IP addresses allowed to print:


	         $ HPRINTS_ALLOWED = "131.185.250.*"


	       Anyone in this IP range can force the printer to run out of paper.

	       Anyway, it should be fairly easy to spoof the source IP address.








	WASD 8.1, and the update versions 8.0.1 and 7.2.4, will  fix  the  known




	Use a separate document root, not the whole web server root

	    Put the document root in /ht_root/wwwroot, not /ht_root, with mapping

	    rules such as:


	       pass /* /ht_root/wwwroot/*

	       fail /ht_root/*


	    You can add a rule such as


	       fail /-/*


	    but unfortunately it will not be very effective because it can be

	    trivially bypassed with all versions of the WASD server up to 8.0.


	Use a subdirectory for a user document root, not the home directory

	    Use rules such as:


	      user /~*/*    /user_disk/*/web/*

	      redirect /~*  /~*/


	Set file protections and ACLs correctly

	    Since the WASD access restrictions can be bypassed, the only effective

	    protection is that provided by the system itself, OpenVMS. The web server

	    runs by default as user http$server, so make sure that directories

	    supposed to be protected are not readable by this user. Take at least

	    the following minimum precautions:


	    . Make sure that all directories under ht_root are owned by user

	      SYSTEM, not by user HTTP$SERVER. Add specific ACLs for directories

	      and files which must be readable or writable by HTTP$SERVER, but only



	       $ set file /owner=system /prot=(s:rwed,o:rwed,g,w) -

	           ht_root:[000000]local.dir, ht_root:[local...]*.*;* , -

	           ht_root:[000000]http$server.dir, ht_root:[http$server...]*.*;*


	       $ set security /acl=((ident=http$server,access=e) /delete=all -


	       $ set security /acl=((ident=http$server,access=r+e) /delete=all -


	       $ set security /acl=((ident=http$server,access=r+e) /delete=all -



	      Be particularly careful about ACLs on files in directory [local].

	      Only the .com files there should be readable by http$server; the

	      rest contains very sensitive information.


	    . To prevent all the different ways of reading scripts, set protection

	      Execute only instead of Read+Execute on all essential scripts

	      (and delete all other scripts as described below). Check at least

	      the directories /script, /script_local, /vax and /axp, plus any other

	      directories mentioned in the logical name CGI-BIN.


	       $ set file /owner=system /prot=(s:rwed,o:rwed,g,w) -

	           ht_root:[000000]script*.dir, ht_root:[script*...]*.*;* , -

	           ht_root:[000000]axp.dir, ht_root:[axp...]*.*;* , -

	           ht_root:[000000]vax.dir, ht_root:[vax...]*.*;*


	       $ set security /acl=((ident=http$server,access=e) /delete=all -


	       $ set security /acl=((ident=http$server,access=e) /delete=all -


	       $ set security /acl=((ident=http$server,access=e) /delete=all -

	           ht_root:[000000]axp.dir ! or vax.dir depending on architecture

	       $ set security /acl=((ident=http$server,access=e) /delete=all -

	           ht_root:[axp]*.*;* ! or [vax]*.*;* depending on architecture


	    . To prevent reading the web server logs, set ACLs to allow write-only

	      access for user http$server on directory [log] and its subdirectories.


	    . To prevent all the forms of directory traversal, set protection

	      Execute only instead of Read+Execute for directories which must

	      be protected from traversal. You can also add rules in httpd$map.conf


		fail /tree/

		fail /tree/*

		fail /upd/*

		fail /where/*

		fail /query/*

		fail /extract/*


	      but do not rely only on these rules, set ACLs correctly first.


	Remove all unused cgi programs

	    This is a basic principle, but unfortunately it was not followed in

	    any of the tested sites: remove *all* unused cgi scripts and executables.

	    Some of the programs provided by default with the WASD server are

	    very dangerous. So check at least the directories script, script_local,

	    axp and vax (all under ht_root) and move anything which is unused

	    somewhere outside ht_root, with very strict ACLs.


	    Let me insist again: at least one of the programs provided by default

	    with the WASD server is extremely dangerous. I will not name it to avoid

	    helping too much the script kiddies, so in doubt remove everything

	    unless you know that you absolutely need it.


	    If the machine hosting the web server has some untrusted users with

	    local accounts on the machine, then forbid execution of arbitrary cgi

	    scripts in ~untrusted/cgi-bin with a rule such as:


	       fail /~untrusted/cgi-bin/*


	    put _before_ the rule


	       exec /~*/cgi-bin/* /user_disk/*/cgi-bin/*


	    or better, block cgi access to all local users.


	Never run cgi scripts under the account of a privileged user

	    If you really need privileges in your cgi script, then force the

	    https protocol and force user authentication. Read the WASD documents

	    Never do user authentication without SSL (the https protocol).


	    Do not run cgi scripts as user http$server. Strictly speaking, this

	    account is not privileged, but since it is also used to run the main

	    server, faulty cgi scripts can cause more harm than totally

	    unprivileged users.


	    If the machine hosting the web servers has untrusted local

	    users with a ~username/cgi-bin directory, then it is preferable to

	    either remove the ability to run scripts there, or at least run the

	    scripts as the user. Running those scripts as user http$server

	    lets the untrusted users do many things to the web server, such

	    as reading the server logs if ACLs are not set correctly, or killing

	    the main server process; it would be the equivalent of giving

	    the additional right [http$server] to the untrusted users.





	  Thanks to Mark Daniel, author of the WASD server, for making it free

	  software, for quickly answering to my initial report, and for working

	  insane hours to fix all the problems I reported.


	  Thanks to Beave and Doc Cypher for providing free accounts on their

	  respective OpenVMS servers, for testing the proposed solutions and

	  suggesting improvements.


	  Thanks to Jeremy Begg for hosting the WASD demonstration server.

TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2014 AOH