分析了一段时间的CGI接口,感觉各种WEB服务器对一些变量好象不是很统一,也没明白一些安全要求,所以造成一些安全上的漏洞,在此作一简要分析。因为是根据个人的一些理解分析,所以错误在所难免,还望大家批评指正。
主要问题是几个变量PATH_INFO、PATH_TRANSLATED、SCRIPT_NAME的处理不统一。下面是MSDN的关于这几个变量的说明,为了清楚,也把相关两个一起列出,另两个变量这两种WEB服务器应该说都是正确处理。
PATH_INFO Additional path information, as given by the client. This comprises the trailing part of the URL after the script name but before the query string (if any).
PATH_TRANSLATED This is the value of PATH_INFO, but with any virtual path name expanded into a directory specification.
QUERY_STRING The information which follows the ? in the URL that referenced this script.
REQUEST_METHOD The HTTP request method.
SCRIPT_NAME The name of the script program being executed.
为了方便说清楚,也好让大家有个印象,举一个具体实例,看看这几个变量到底是指的什么吧。比如有映射.php,那么请求:
“GET /test.php/aaa/bbb?cgivartest HTTP/1.1”,REQUEST_METHOD=GET;QUERY_STRING=cgivartest;这是不容质疑的,那另三个变量是什么呢?个人觉得MSDN里面的定义还比较准确,就是上面那几个定义。照那么说来应该SCRIPT_NAME=test.php,这是那个要执行(也可能是被别的程序解释执行)的程序,PATH_INFO=/aaa/bbb,“script name”之后“query string”之前,假如WEB主目录是“d:\inetpub\wwwroot”,那么PATH_TRANSLATED=d:\inetpub\wwwroot\aaa\bbb。
但实际情况是如何的呢,让我们来看看。用常用的两种WEB服务器建立两个环境,以做对比,看看这两种WEB服务器的处理。
环境:
1、win2000+apache1.3.14+php4;
2、win2000+iis5.0+php4;
具体配置我就不说了,相信大家都是配置高手,不用我在此多费口舌。
在每个WEB服务里面建立一个文件test.php,文件内容如下:
<?
phpinfo();
?>
大家一看就知道是干什么,简单建立这么一个文件,方便我们查看一些WEB变量。
1、apache下直接用php.exe加载;
http://192.168.8.48/php/php.exe/abcde.php/aa/..%5c../test.php?cgivartest
得到:
Environment
Variable Value
SCRIPT_FILENAME d:/php4/php.exe
GATEWAY_INTERFACE CGI/1.1
SERVER_PROTOCOL HTTP/1.1
REQUEST_METHOD GET
QUERY_STRING cgivartest
REQUEST_URI /php/php.exe/abcde.php/aa/..%5c../test.php?cgivartest
SCRIPT_NAME /php/php.exe/abcde.php/aa/..\..
PATH_INFO /abcde.php/aa/../../test.php
PATH_TRANSLATED d:\program files\apache group\apache\htdocs\test.php
2、apache下用映射加载:
http://192.168.8.48/AB.PHP/AA/..%5C../test.php?cgivartest
得到:
Environment
Variable Value
SCRIPT_FILENAME d:/php4/php.exe
GATEWAY_INTERFACE CGI/1.1
SERVER_PROTOCOL HTTP/1.1
REQUEST_METHOD GET
QUERY_STRING cgivartest
REQUEST_URI /AB.PHP/AA/..%5C../test.php?cgivartest
SCRIPT_NAME /php/php.exe/AB.PHP/AA/..\..
PATH_INFO /AB.PHP/AA/../../test.php
PATH_TRANSLATED d:\program files\apache group\apache\htdocs\test.php
3、iis下cgi接口加载:
http://192.168.8.48:81/abc.php/aa/..%c1%1c../test.php?cgivartest
得到:
Environment
Variable Value
GATEWAY_INTERFACE CGI/1.1
PATH_INFO /abc.php/aa/..\../test.php
PATH_TRANSLATED d:\inetpub\wwwroot\abc.php\aa\..\..\test.php
QUERY_STRING cgivartest
REQUEST_METHOD GET
SCRIPT_NAME /abc.php
SERVER_PROTOCOL HTTP/1.1
4、iis下isapi接口加载:(映射.php4)
http://192.168.8.48:81/abc.php4/aa/..%c1%1c../test.php?cgivartest
得到:
ISAPI
Server Variable Value
PATH_INFO /abc.php4/aa/..\../test.php
PATH_TRANSLATED d:\inetpub\wwwroot\abc.php4\aa\..\..\test.php
QUERY_STRING cgivartest
REQUEST_METHOD GET
SCRIPT_NAME /abc.php4
SERVER_PROTOCOL HTTP/1.1
URL /abc.php4
大家看看,apache、iis两者都不是执行的 SCRIPT_NAME,而是执行的PATH_TRANSLATED。个人理解PATH_INFO从其名字来看只是一个路径信息,而不是一个文件。而WEB服务本身应该说带有chroot性质,所以说变量PATH_INFO应该限制rfc的“/../”,这点iis是做到了,用%5c这种rfc里面的编码要求是不行的,%c1%1c的解码是因为另一个漏洞。而apache呢,直接用%5c就可以,这显然应该说是一个漏洞。假设要执行的是PATH_TRANSLATED,那么大家试试把test.php换成别的名,比如另一种映射的名test.pl,这4种情况同样照php执行了。那意思是什么呢,就是说我可以任意以一种解释程序去执行一种影射文件,那显然与这种映射所要求的安全不符合,也就很容易导致源代码泄露漏洞。如果限制了PATH_INFO里面的“/../”,那么是不能返回上级目录,这样就不能用任意解释程序去解释一种映射文件。但想想如果这样SCRIPT_NAME、PATH_INFO、PATH_TRANSLATED几个变量是不是就有变量根本就没什么意思呢?个人理解应该是执行的是SCRIPT_NAME程序,PATH_INFO变量只是再提供给SCRIPT_NAME的一个附加的路径信息,比如用于在这路径下读取一些配置文件等。你看apache的SCRIPT_NAME变量就去掉了后面的文件名。
我们总结得到:
1、PATH_INFO应该限制rfc编码要求内的“/../”。这点apache有漏洞。这点可能导致源代码泄露,甚至导致可以访问任意文件。
2、PATH_TRANSLATED、PATH_INFO、SCRIPT_NAME不清楚,执行文件不清楚。这点apache、iis两者都有漏洞。这点很容易导致源代码泄露。实际上发现的有很漏洞与这脱离不了关系。可能过一段时间就会有IIS的泄露源代码漏洞补丁了,同样方法在apache上面也可以,虽然此漏洞根本原因不是因为这,但这为那漏洞提供了表现机会。那攻击主要是利用了这个漏洞加上windows文件操作的文件名末尾半个汉字截断处理漏洞,可以查看一些asp、php等源代码,过一段时间大家就可以看到了。
有兴趣的可以照着这实验自己做试验,看看各种环境对这些变量的处理,理解理解,很可能你自己就很容易的找到一些新漏洞呢。
附1:MSDN关于CGI、ISAPI的接口文档资料。
EXTENSION_CONTROL_BLOCK Structure
The EXTENSION_CONTROL_BLOCK structure has the following form:
typedef struct _EXTENSION_CONTROL_BLOCK {
DWORD cbSize;//IN
DWORD dwVersion//IN
HCONN ConnID;//IN
DWORD dwHttpStatusCode; //OUT
CHARlpszLogData[HSE_LOG_BUFFER_LEN];//OUT
LPSTR lpszMethod;//IN
LPSTR lpszQueryString; //IN
LPSTR lpszPathInfo;//IN
LPSTR lpszPathTranslated;//IN
DWORD cbTotalBytes;//IN
DWORD cbAvailable; //IN
LPBYTElpbData; //IN
LPSTR lpszContentType; //IN
BOOL ( WINAPI * GetServerVariable )
( HCONN hConn,
LPSTR lpszVariableName,
LPVOIDlpvBuffer,
LPDWORD lpdwSize );
BOOL ( WINAPI * WriteClient )
( HCONNConnID,
LPVOID Buffer,
LPDWORDlpdwBytes,
DWORDdwReserved );
BOOL ( WINAPI * ReadClient )
( HCONNConnID,
LPVOID lpvBuffer,
LPDWORDlpdwSize );
BOOL ( WINAPI * ServerSupportFunction )
( HCONNhConn,
DWORDdwHSERRequest,
LPVOID lpvBuffer,
LPDWORDlpdwSize,
LPDWORDlpdwDataType );
} EXTENSION_CONTROL_BLOCK, *LPEXTENSION_CONTROL_BLOCK;
The server communicates with the ISA via the EXTENSION_CONTROL_BLOCK.
The references to IN and OUT above indicates whether the member applies to messages to the extension (IN) or from the extension (OUT).
Members
The EXTENSION_CONTROL_BLOCK structure contains the following fields:
cbSize
The size of this structure.
dwVersion
The version information ofHTTP_FILTER_REVISION. The HIWORD has the major version number and the LOWORD has the minor version number.
ConnID
A unique number assigned by the HTTP server. It must not be modified.
dwHttpStatusCode
The status of the current transaction when the request is completed. Can be one of the following:
HTTP_STATUS_BAD_REQUEST
HTTP_STATUS_AUTH_REQUIRED
HTTP_STATUS_FORBIDDEN
HTTP_STATUS_NOT_FOUND
HTTP_STATUS_SERVER_ERROR
HTTP_STATUS_NOT_IMPLEMENTED
lpszLogData
Buffer of size HSE_LOG_BUFFER_LEN. Contains a null-terminated log information string, specific to the ISA, of the current transaction. This log information will be entered in the HTTP server log. Maintaining a single log file with both HTTP server and ISA transactions is very useful for administration purposes.
lpszMethod
The method with which the request was made. This is equivalent to the CGI variable REQUEST_METHOD.
lpszQueryString
Null-terminated string containing the query information. This is equivalent to the CGI variable QUERY_STRING.
lpszPathInfo
Null-terminated string containing extra path information given by the client. This is equivalent to the CGI variable PATH_INFO.
lpszPathTranslated
Null-terminated string containing the translated path. This is equivalent to the CGI variable PATH_TRANSLATED.
cbTotalBytes
The total number of bytes to be received from the client. This is equivalent to the CGI variable CONTENT_LENGTH. If this value is 0xffffffff, then there are four gigabytes or more of available data.In this case, CHttpServerContext::ReadClient should be called until no more data is returned.
cbAvailable
The available number of bytes (out of a total of cbTotalBytes) in the buffer pointed to by lpbData. If cbTotalBytes is the same as cbAvailable the variable lpbData will point to a buffer which contains all the data sent by the client. Otherwise cbTotalBytes will contain the total number of bytes of data received. The ISA will then need to use the callback function CHttpServerContext::ReadClient to read the rest of the data (starting from an offset of cbAvailable).
lpbData
Points to a buffer of size cbAvailable that has the data sent by the client.
lpszContentType
Null-terminated string containing the content type of the data sent by the client. This is equivalent to the CGI variable CONTENT_TYPE.
GetServerVariable
This function copies information (including CGI variables) relating to an HTTP connection, or to the server itself, into a buffer. GetServerVariable takes the following parameters:
hConn A handle to a connection.
lpszVariableName Null-terminated string indicating which variable is being requested. Variable names are:Variable Name Description
ALL_HTTP All HTTP headers that were not already parsed into one of the above variables. These variables are of the form HTTP_<header field name>.
AUTH_PASS This will retrieve the password corresponding to REMOTE_USER as supplied by the client. It will be a null-terminated string.
AUTH_TYPE Contains the type of authentication used.For example, if Basic authentication is used, the string will be "Basic". For Windows NT Challenge-response, it will be "NTLM". Other authentication schemes will have other strings. Because new authentication types can be added to Internet Server, it is not possible to list all possible strings. If the string is empty then no authentication is used.
CONTENT_LENGTH The number of bytes which the script can expect to receive from the client.
CONTENT_TYPE The content type of the information supplied in the body of a POST requ