Last October I dived into the world of Jira Software (version 8.4.1) in the hope of discovering new vulnerabilities. Initially, I came across a few Cross-Site Request Forgery (CSRF) weaknesses, leading me to a vulnerability that allows a user to instruct the Jira server to initiate connections to other hosts of my choice. This CSRF vulnerability (CVE-2019-20099) affects Atlassian Jira Server and Data Center versions 8.2.4 prior to 8.7.0 and can be leveraged to perform a host discovery scan of networks visible to an affected Jira server.
This blog details the discovery of this issue and includes a host discovery proof of concept.
Jira defenses for Cross-Site Request Forgeries
CSRF attacks can target vulnerable websites by reusing cookies stored in the browser of a legitimate logged-in user to impersonate their identity and perform some malicious actions without their knowledge.
The above is an example of a POST request that sets an issue’s type to bug. The CSRF cookie and the CSRF parameter are named Atlassian.xsrf.token and atl_token. The Referer header gets validated by checking if its value commences with the Jira Server’s IP address and port number.
While testing various requests, I discovered that Jira doesn’t always validate these values.
Setting up an outgoing POP3 mail server in Jira requires a system administrator to complete and submit a form with the relevant mail server details, such as the server name, host address, port number, user credentials and so forth. At the bottom of the form there are two buttons, one for requesting to set up a new mail server and the other for testing the mail server connection.
The test connection button causes the Jira Server to attempt to connect to the mail server specified on the form. The connection consists of a credential exchange with the POP3 mail server.
When looking into this request, there was neither a Referer header nor a CSRF parameter validation check implemented. Therefore, the only requirement to perform a CSRF on this request would be to reuse the cookies from a logged in system administrator.
Putting this to the test, I set up a host with a POP3 mail server to receive verification connections from the Jira server, and a web server to host a webpage with the CSRF script. The idea was to simulate a user clicking on a malicious link that would reuse the user’s session ID cookies to make requests to the Jira server for verifying mail server connections on hosts and ports of my choice.
Here is the script I used for the CSRF webpage to exploit the POP3 server connection verification:
Below is a snippet of a Wireshark capture taken while running the above script.
Here, the victim user’s browser (172.16.68.1) sends a POST request to the Jira server (172.16.68.248). Immediately after this, a POP3 connection is initiated from Jira to the specified host and port (172.16.68.229:110). There is an exchange of credentials which fail to authenticate and the connection terminates.
The script was able to send a request to the Jira server via a CSRF link to get the server to connect to a host and port of my choice.
The POP3 connection verification request requires a username and password to be set in the POST parameters. These parameters get sent to the specified host and port after a successful handshake and provides a mechanism through which an attacker could send messages or commands to listening hosts.
Leveraging the vulnerability to perform host discovery
XMLHttpRequest objects have a readyState property which can be used in conjunction with the onreadystatechange event handler. The readyState property holds a value between 0 and 4 representing the state of the request. The following table was taken from the w3schools.com website, describes the meaning of readyState values:
The onreadystatechange event handler gets called every time the readyState values change. So, I amended the web page script to alert me every time the XMLHttpRequest changed state. I wanted to see if there were any differences in the state transitions as I made requests to connect to different host IPs and port numbers.
I added the following lines to the script to keep track of state transitions:
When the Jira server attempted to connect to an IP address for which there was no corresponding host assigned, the request state transition from state 1 to 4 took about 3 seconds to complete.
The server was returning a response to the POST request only after it had terminated the connection with the specified host. Therefore, if the IP address didn’t correspond to a running host, it would take about 3 seconds for the connection to timeout and terminate.
Proof of Concept (PoC)
I created a PoC script that exploits this vulnerability to perform a host discovery scan from the Jira server. The script makes several requests to the Jira server via CSRFs for verifying mail servers across a range of IP addresses on an arbitrary port (the PoC uses port 110 but this can be changed to any other port). The time taken to complete each request is measured and posted on a text area of the web page.
After running the PoC against the Jira server, the text area in the web page was filled with scanned IP addresses together with the corresponding time taken to get a response.
To validate the results I ran an Nmap host discovery scan from the Jira server.
These results from the Nmap scans are consistent with the results from the PoC scan.
The following snippet of a Wireshark capture shows that the PoC caused JIRA to initiate a POP connection to an arbitrary host and port, and demonstrates how the username field can be used for sending messages to hosts.
The CSRF vulnerability found in Jira’s POP3 test connection component was leveraged to perform a host discovery scan from the Jira server via a CSRF script which caused Jira to initiate test connections for a range of IP addresses. The time taken to complete each request was measured to determine if a host was present at the corresponding IP address. The results proved to be consistent with those from an Nmap host discovery scan.
This vulnerability has been disclosed to Atlassian through Tenable’s coordinated disclosure process and the issue has been fixed in Atlassian Jira Server and Data Center version 8.7.0.
For further information on this vulnerability refer to Tenable’s research advisory which outlines the disclosure timeline and provides a link to Jira’s release notes.