Skip to content

Instantly share code, notes, and snippets.

@zhil
Created April 28, 2016 06:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zhil/53d77f7c120b5ed4eef51ed5c8d2a363 to your computer and use it in GitHub Desktop.
Save zhil/53d77f7c120b5ed4eef51ed5c8d2a363 to your computer and use it in GitHub Desktop.
Atlassian security check (python 2.7.6-2.7.8)
import sys
import xml.etree.ElementTree as Tree
import urllib2
import ssl
import json
from collections import namedtuple
#_DEFAULT_TEST_URL = 'https://anspedite-3.atlassian.net'
_DEFAULT_TEST_URL = 'http://pc1:2990/jira'
# noinspection PyProtectedMember
def _set_secret(descriptor_url, product_url, secret):
path = product_url + '/plugins/servlet/oauth/consumer-info'
ids = Tree.fromstring(urllib2.urlopen(path).read())
client_key = ids.find('key').text
public_key = ids.find('publicKey').text
description = ids.find('description').text
descriptor = json.loads(urllib2.urlopen(descriptor_url).read())
install_payload = {
'baseUrl': product_url,
'clientKey': client_key,
'description': description,
'eventType': 'installed',
'key': descriptor['key'],
'pluginsVersion': '1.2.0',
'productType': client_key.split(':')[0],
'publicKey': public_key,
'serverVersion': '73000',
'sharedSecret': secret
}
installed_callback_url = descriptor['baseUrl'] + descriptor['lifecycle']['installed']
data = json.dumps(install_payload)
content_length = len(data)
headers = {'Content-Type': 'application/json', 'Content-length': content_length}
request = urllib2.Request(installed_callback_url, data, headers)
try:
response = urllib2.urlopen(request)
except urllib2.HTTPError as e:
return e.code, e.read()
return response.getcode(), response.read()
_TestResult = namedtuple('_TestResult', ['result', 'message', 'status_code', 'body'])
def _product_to_url(product):
if product.lower() in ('jira', 'both'):
return _DEFAULT_TEST_URL
if product.lower() == 'confluence':
return _DEFAULT_TEST_URL + '/wiki'
if product.lower().startswith('https://'):
return product
raise Exception('Please specify "jira" ,"confluence" or "both" as the supported product')
def test_vulnerability(descriptor_url,
product='jira',
secret='aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'):
try:
product_url = _product_to_url(product)
status_code, body = _set_secret(descriptor_url, product_url, secret)
if status_code < 300:
result = _TestResult('vulnerable',
'Your add-on appears to be VULNERABLE '
'(it returned a status code of {}).'.format(status_code),
status_code, body)
elif 300 <= status_code < 400:
result = _TestResult('invalid',
'Your add-on sent a redirect of some kind (status code was {}). '.format(status_code) +
'Could not determine if it is vulnerable',
status_code, body)
elif 400 <= status_code < 500:
result = _TestResult('safe',
'Your add-on appears to be SAFE '
'(it blocked the request with status code {}).'.format(status_code),
status_code, body)
else:
result = _TestResult('invalid',
'Your add-on returned an error status of {}'.format(status_code) +
'. Could not determine whether it is safe.',
status_code, body)
except Exception as e:
result = _TestResult('invalid', 'There was an exception while testing your add-on for a vulnerability. ' +
'Could not determine whether it is safe.', -1, e)
return result
if __name__ == "__main__":
if '-h' in sys.argv or len(sys.argv) < 2 or len(sys.argv) > 4:
print('')
print('USAGE: python secret_overwrite_test.py add-on-descriptor-url [jira|confluence|both]')
print('')
print('add-on-descriptor-url: The https:// url to your atlassian-connect.json '
'(the marketplace-hosted one or the one hosted by your service will both work)')
print('jira|confluence|both: whether your add-on is for jira, confluence, or both (defaults to jira)')
print('')
print('EXAMPLE 1: '
'python secret_overwrite_test.py https://jira-addon.example.com/atlassian-connect.json')
print('')
print('EXAMPLE 2: '
'python secret_overwrite_test.py https://confluence-addon.example.com/atlassian-connect.json confluence')
print('')
else:
test_result = test_vulnerability(*sys.argv[1:])
print(test_result.message)
if test_result.result == 'vulnerable':
print('Your add-on should respond with 401 (unauthorized) to '
're-installation requests that don\'t have a valid JWT signed with the old secret')
elif test_result.status_code == -1:
print(test_result.body)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment