首页 -> 安全研究

安全研究

绿盟月刊
绿盟安全月刊->第16期->技术专题
期刊号: 类型: 关键词:
WEB服务CGI接口漏洞分析

作者:yuange < yuange@nsfocus.com >
主页:http://www.nsfocus.com
日期:2000-12-14

分析了一段时间的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
    CHAR      lpszLogData[HSE_LOG_BUFFER_LEN];    //OUT
    LPSTR     lpszMethod;                          //IN
    LPSTR     lpszQueryString;                     //IN
    LPSTR     lpszPathInfo;                        //IN
    LPSTR     lpszPathTranslated;                  //IN
    DWORD     cbTotalBytes;                        //IN
    DWORD     cbAvailable;                         //IN
    LPBYTE    lpbData;                             //IN
    LPSTR     lpszContentType;                     //IN

    BOOL ( WINAPI * GetServerVariable )
       ( HCONN       hConn,
        LPSTR       lpszVariableName,
        LPVOID      lpvBuffer,
        LPDWORD     lpdwSize );

    BOOL ( WINAPI * WriteClient )
       ( HCONN      ConnID,
       LPVOID     Buffer,
       LPDWORD    lpdwBytes,
       DWORD      dwReserved );

    BOOL ( WINAPI * ReadClient )
       ( HCONN      ConnID,
       LPVOID     lpvBuffer,
       LPDWORD    lpdwSize );

    BOOL ( WINAPI * ServerSupportFunction )
       ( HCONN      hConn,
       DWORD      dwHSERRequest,
       LPVOID     lpvBuffer,
       LPDWORD    lpdwSize,
       LPDWORD    lpdwDataType );

} 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 of  HTTP_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 request.
GATEWAY_INTERFACE The revision of the CGI specification to which this server complies. The current version is CGI/1.1.
HTTP_ACCEPT Special case HTTP header. Values of the Accept: fields are concatenated, separated by ", ". For example, if the following lines are part of the HTTP header:
accept: */*; q=0.1
accept: text/html
accept: image/jpeg
then the HTTP_ACCEPT variable will have a value of:

*/*; q=0.1, text/html, image/jpeg

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.
REMOTE_ADDR The IP address of the client.
REMOTE_HOST The hostname of the client.
REMOTE_USER This contains the username supplied by the client and authenticated by the server.
REQUEST_METHOD The HTTP request method.
SCRIPT_NAME The name of the script program being executed.
SERVER_NAME The server's hostname (or IP address) as it should appear in self-referencing URLs.
SERVER_PORT The TCP/IP port on which the request was received.
SERVER_PROTOCOL The name and version of the information retrieval protocol relating to this request. Normally HTTP/1.0.
SERVER_SOFTWARE The name and version of the web server under which the CGI program is running.


lpvBuffer   Pointer to buffer to receive the requested information.


lpdwSize   Pointer to DWORD indicating the number of bytes available in the buffer. On successful completion the DWORD contains the number of bytes transferred into the buffer (including the null terminating byte).
WriteClient

Sends information to the client from the indicated buffer. WriteClient takes the following parameters:

ConnID   A unique connection number assigned by the HTTP server.


Buffer   Pointer to the buffer where the data is to be written.


lpdwBytes   Pointer to the data to be written.


dwReserved   Reserved for future use.
ReadClient

Reads information from the body of the Web client's HTTP request into the buffer supplied by the caller. ReadClient takes the following parameters:

ConnID   A unique connection number assigned by the HTTP server.


lpvBuffer   Pointer to the buffer area to receive the requested information.


lpdwSize   Pointer to DWORD indicating the number of bytes available in the buffer. On return *lpdwSize will contain the number of bytes actually transferred into the buffer.
ServerSupportFunction

Provide the ISAs with some general-purpose functions as well as functions that are specific to HTTP server implementation. ServerSupportFunction takes the following parameters:

hConn   A handle to a connection.


dwHSERRequest   An HTTP Server Extension value. See CHttpServerContext::ServerSupportFunction for a list of possible values and related parameters.


lpvBuffer   When used with HSE_REQ_SEND_RESPONSE_HEADER, it points to a null-terminated optional status string (i.e., "401 Access Denied"). If this buffer is null, a default response of "200 Ok" will be sent by this function. When used with HSE_REQ_DONE_WITH_SESSION, it points to a DWORD indicating the status code of the request.


lpdwSize   When used with HSE_REQ_SEND_RESPONSE_HEADER, it points to the size of the buffer lpdwDataType.


lpdwDataType   A null-terminated string pointing to optional headers or data to be appended and sent with the header. If  NULL, the header will be terminated by a “\r\n” pair.
Comments

A server identifies files with the extensions  .EXE and .BAT as CGI (Common Gateway Interface) executables. In addition, a server will identify a file with a DLL extension as a script to execute.

When the server loads the DLL, it calls the DLL at the entry point CHttpServer::GetExtensionVersion to get the version number of the  HTTP_FILTER_REVISION the ISA is based on and a short text description for server administrators. For every client request, the CHttpServer::HttpExtensionProc entry point is called. The extension receives the commonly-needed information such as the query string, path info, method name, and the translated path.

See Also   CHttpServerContext::ReadClient, CHttpServer::GetExtensionVersion, CHttpServer::HttpExtensionProc
版权所有,未经许可,不得转载