CVE-2016-8747
21 Mar 2017 | categories noteshttp://svn.apache.org/viewvc/tomcat/tc8.5.x/trunk/java/org/apache/coyote/http11/Http11InputBuffer.java?r1=1774166&r2=1774165&pathrev=1774166&diff_format=f
--- a/java/org/apache/coyote/http11/Http11InputBuffer.java
+++ b/java/org/apache/coyote/http11/Http11InputBuffer.java
@@ -296,12 +296,16 @@ public class Http11InputBuffer implements InputBuffer, ApplicationBufferHandler
void nextRequest() {
request.recycle();
- // Copy leftover bytes to the beginning of the buffer
- if (byteBuffer.remaining() > 0 && byteBuffer.position() > 0) {
- byteBuffer.compact();
+ if (byteBuffer.position() > 0) {
+ if (byteBuffer.remaining() > 0) {
+ // Copy leftover bytes to the beginning of the buffer
+ byteBuffer.compact();
+ byteBuffer.flip();
+ } else {
+ // Reset position and limit to 0
+ byteBuffer.position(0).limit(0);
+ }
}
- // Always reset pos to zero
- byteBuffer.limit(byteBuffer.limit() - byteBuffer.position()).position(0);
发送如下请求:
GET / HTTP/1.1
Host: 127.0.0.1:8890
User-Agent: curl/7.51.0
GET /abc HTTP/1.1
Host: 127.0.0.1:8890
c=AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
将导致c参数的值不仅仅是A,还会包含上一个请求(可能是别人的请求)的内容。
p position
l limit
c capacity
byteBuffer的内存布局
|______|__________|____________________|
0 p l c
我们构造一个请求,0-p为一个正常的请求。p-l为上面AAAA...那个请求。两个请求放在一个socket里发送。
当Tomcat处理完第一个请求的时候,将执行compact操作
public ByteBuffer compact() {
System.arraycopy(hb, ix(position()), hb, ix(0), remaining());
position(remaining());
limit(capacity());
discardMark();
return this;
}
内存布局变成
|__________|______|____________________|
0 p1 l l1,c
p1=(l-p), l1=c
注意这里,0--(l-p)之间变成了原本p--l的内容,而l1--l之间的内容为buffer的缓存内容,可能是上一个请求的内容。
然后执行`byteBuffer.limit(byteBuffer.limit() - byteBuffer.position()).position(0);`
内存布局变成
|__________|______|__________|__________|
p2 p1 l l2 c
p2=0, l2=l1-p1
这样,Tomcat继续处理一个socket里的下一个请求。但是这时,limit是不正确的,正确的limit应该是p1。由于limit不正确,因此请求错误的包含了l--l2之间的内容,而该部分内容,是buffer中缓存的内容。将导致恶意构造的请求可以读取到别人发送的内容。
补丁正确的处理了这个问题。
类似这样的问题,有可能发生的很不隐蔽。比如这个。只在8.5.7-8.5.9中存在。因为这个错误将导致一个socket中包含两个http请求时,后一个请求会出现异常,因此很快就能得到反馈,发现问题。如果情况再特殊一点,后一个请求不抛出异常的话,那么比较可能导致一个潜伏的漏洞。
服务器为了性能,重复利用buffer,也是一个安全隐患。