2007年5月24日星期四

[Tips]Tomcat URI Stack Overflow

by axis
2007-03-06

ZDI 发布了一个针对Tomcat的公告,tomcat在uri超长时会造成一个栈溢出,我们看细节

原来的漏洞公告,转载自ZDI

ZDI-07-008: Apache Tomcat JK Web Server Connector Long URL Stack
            Overflow Vulnerability
http://www.zerodayinitiative.com/advisories/ZDI-07-008.html
March  2, 2007

-- CVE ID:
CVE-2007-0774

-- Affected Vendor:
Apache

-- Affected Products:
Tomcat JK Web Server Connector 1.2.19
Tomcat JK Web Server Connector 1.2.20
Tomcat 4.1.34
Tomcat 5.5.20

-- TippingPoint(TM) IPS Customer Protection:
TippingPoint IPS customers have been protected against this vulnerability
since February 26, 2007 by Digital Vaccine protection filter ID 5152. For
further product information on the TippingPoint IPS:

    http://www.tippingpoint.com 
<http://www.tippingpoint.com/>  

-- Vulnerability Details:
This vulnerability allows remote attackers to execute arbitrary code on
vulnerable installations of Apache Tomcat JK Web Server Connector.
Authentication is not required to exploit this vulnerability.

The specific flaw exists in the URI handler for the mod_jk.so library,
map_uri_to_worker(), defined in native/common/jk_uri_worker_map.c. When
parsing a long URL request, the URI worker map routine performs an unsafe
memory copy. This results in a stack overflow condition which can be
leveraged to execute arbitrary code.

-- Vendor Response:
Apache has issued an update to correct this vulnerability. More details can
be found at:

http://tomcat.apache.org/connectors-doc/miscellaneous/changelog.html

-- Disclosure Timeline:
2007.02.16 - Vulnerability reported to vendor
2007.02.26 - Digital Vaccine released to TippingPoint customers
2007.03.02 - Coordinated public release of advisory

-- Credit:
This vulnerability was discovered by an anonymous researcher.

-- About the Zero Day Initiative (ZDI):
Established by TippingPoint, a division of 3Com, The Zero Day Initiative
(ZDI) represents a best-of-breed model for rewarding security researchers
for responsibly disclosing discovered vulnerabilities.

Researchers interested in getting paid for their security research through
the ZDI can find more information and sign-up at:

    http://www.zerodayinitiative.com 
<http://www.zerodayinitiative.com/>

The ZDI is unique in how the acquired vulnerability information is used.
3Com does not re-sell the vulnerability details or any exploit code.
Instead, upon notifying the affected product vendor, 3Com provides its
customers with zero day protection through its intrusion prevention
technology. Explicit details regarding the specifics of the vulnerability
are not exposed to any parties until an official vendor patch is publicly
available. Furthermore, with the altruistic aim of helping to secure a
broader user base, 3Com provides this vulnerability information
confidentially to security vendors (including competitors) who have a
vulnerability protection or mitigation product. 


细节其实说的很清楚了,我们看代码,这里以Tomcat 5.5.20为例
const char *map_uri_to_worker(jk_uri_worker_map_t *uw_map,
                              
const char *uri, jk_logger_t *l)
{
    unsigned 
int i;
    
char *url_rewrite;
    
const char *rv = NULL;
    
char  url[JK_MAX_URI_LEN+1];            //  这里定义

    JK_TRACE_ENTER(l);

    
if (!uw_map || !uri) {
        JK_LOG_NULL_PARAMS(l);
        JK_TRACE_EXIT(l);
        
return NULL;
    }
    
if (*uri != '/') {
        jk_log(l, JK_LOG_WARNING,
                
"Uri %s is invalid. Uri must start with /", uri);
        JK_TRACE_EXIT(l);
        
return NULL;
    }
    
for (i = 0; i < strlen(uri); i++)               //  这里开始拷贝,溢出了
        if (uri[i] == ';')
            
break;
        
else
            url[i] 
= uri[i];
    url[i] 
= '\0';


在jk_uri_worker_map.h 中有定义
#define JK_MAX_URI_LEN 4095


所以超过4096个字节的url长度传递过去,就造成了栈溢出。






2007-03-07更新:
看了补丁,加了个判断

 /* Make the copy of the provided uri and strip
     * everything after the first ';' char.
     
*/
    
for (i = 0; i < strlen(uri); i++) {
        
if (i == JK_MAX_URI_LEN) {
            jk_log(l, JK_LOG_WARNING,
                   
"Uri %s is invalid. Uri must be smaller then %d chars",
                   uri, JK_MAX_URI_LEN);
            JK_TRACE_EXIT(l);
            
return NULL;
        }
        
if (uri[i] == ';')
            
break;
        
else
            url[i] 
= uri[i];
    }
    url[i] 
= '\0';