-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #8 from paterva/oauth
Added support for decrypting the oauth token sent from the Maltego client for transforms using OAuth.
- Loading branch information
Showing
8 changed files
with
248 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,4 +3,5 @@ build/ | |
dist/ | ||
*.pyc | ||
__pycache__ | ||
maltego_trx.egg-info | ||
maltego_trx.egg-info | ||
.pytest_cache |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,10 @@ | ||
import sys | ||
import transforms | ||
|
||
from maltego_trx.registry import register_transform_function, register_transform_classes | ||
from maltego_trx.server import app, application | ||
from maltego_trx.registry import register_transform_classes | ||
from maltego_trx.server import app | ||
from maltego_trx.handler import handle_run | ||
|
||
# register_transform_function(transform_func) | ||
register_transform_classes(transforms) | ||
|
||
handle_run(__name__, sys.argv, app) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
VERSION = "1.3.6" | ||
VERSION = "1.3.7" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
"""Maltego OAuth Crypto Helper""" | ||
import base64 | ||
from Crypto import Random | ||
from Crypto.Cipher import PKCS1_v1_5, AES | ||
from Crypto.Hash import SHA | ||
from Crypto.PublicKey import RSA | ||
from requests.auth import AuthBase | ||
|
||
|
||
class MaltegoOauth: | ||
""" | ||
A Crypto Helper for Maltego OAuth Secrets received from the Transform Distribution Server | ||
The TDS will send back an encrypted combination of the following : | ||
1. Token | ||
2. Token Secret | ||
3. Refresh Token | ||
4. Expires In | ||
Contains 1 Methods: | ||
1. decrypt_secrets(private_key_path="pem file", ciphertext="request.getTransformSetting('name from TDS')") | ||
""" | ||
|
||
@staticmethod | ||
def _rsa_decrypt(private_key_path=None, ciphertext=None): | ||
""" | ||
RSA Decryption function, returns decrypted plaintext in b64 encoding | ||
""" | ||
dsize = SHA.digest_size | ||
sentinel = Random.new().read(20 + dsize) | ||
ciphertext = base64.b64decode(ciphertext) | ||
private_key = RSA.import_key(open(private_key_path).read()) | ||
cipher = PKCS1_v1_5.new(private_key) | ||
plaintext = cipher.decrypt(ciphertext, sentinel).decode('utf8') | ||
return plaintext | ||
|
||
@staticmethod | ||
def _aes_decrypt(key=None, ciphertext=None): | ||
""" | ||
AES Decryption function, returns decrypted plaintext value | ||
""" | ||
unpad = lambda s: s[:-ord(s[len(s) - 1:])] | ||
key = base64.b64decode(key) | ||
ciphertext = base64.b64decode(ciphertext) | ||
cipher = AES.new(key, AES.MODE_ECB) | ||
plaintext = unpad(cipher.decrypt(ciphertext)).decode('utf8') | ||
return plaintext | ||
|
||
@classmethod | ||
def decrypt_secrets(cls, private_key_path=None, encoded_ciphertext=None): | ||
""" | ||
The TDS will send back an encrypted combination of the following : | ||
1. Token | ||
2. Token Secret | ||
3. Refresh Token | ||
4. Expires In | ||
This function decodes the combinations and decrypts as required and returns a dictionary with the following keys | ||
{"token":"", | ||
"token_secret": "", | ||
"refresh_token": "", | ||
"expires_in": ""} | ||
""" | ||
|
||
encrypted_fields = encoded_ciphertext.split("$") | ||
|
||
if len(encrypted_fields) == 1: | ||
token = cls._rsa_decrypt(private_key_path, encrypted_fields[0]) | ||
token_fields = { | ||
"token": token | ||
} | ||
|
||
elif len(encrypted_fields) == 2: | ||
token = cls._rsa_decrypt(private_key_path, encrypted_fields[0]) | ||
token_secret = cls._rsa_decrypt(private_key_path, encrypted_fields[1]) | ||
token_fields = { | ||
"token": token, | ||
"token_secret": token_secret | ||
} | ||
|
||
elif len(encrypted_fields) == 3: | ||
aes_key = cls._rsa_decrypt(private_key_path, encrypted_fields[2]) | ||
token = cls._aes_decrypt(aes_key, encrypted_fields[0]) | ||
token_secret = cls._aes_decrypt(aes_key, encrypted_fields[1]) | ||
token_fields = { | ||
"token": token, | ||
"token_secret": token_secret | ||
} | ||
elif len(encrypted_fields) == 4: | ||
token = cls._rsa_decrypt(private_key_path, encrypted_fields[0]) | ||
token_secret = cls._rsa_decrypt(private_key_path, encrypted_fields[1]) | ||
refresh_token = cls._rsa_decrypt(private_key_path, encrypted_fields[2]) | ||
expires_in = cls._rsa_decrypt(private_key_path, encrypted_fields[3]) | ||
token_fields = { | ||
"token": token, | ||
"token_secret": token_secret, | ||
"refresh_token": refresh_token, | ||
"expires_in": expires_in | ||
} | ||
elif len(encrypted_fields) == 5: | ||
aes_key = cls._rsa_decrypt(private_key_path, encrypted_fields[4]) | ||
token = cls._aes_decrypt(aes_key, encrypted_fields[0]) | ||
token_secret = cls._aes_decrypt(aes_key, encrypted_fields[1]) | ||
refresh_token = cls._aes_decrypt(aes_key, encrypted_fields[2]) | ||
expires_in = cls._aes_decrypt(aes_key, encrypted_fields[3]) | ||
token_fields = { | ||
"token": token, | ||
"token_secret": token_secret, | ||
"refresh_token": refresh_token, | ||
"expires_in": expires_in | ||
} | ||
else: | ||
token_fields = { | ||
"token": "", | ||
"token_secret": "", | ||
"refresh_token": "", | ||
"expires_in": "" | ||
} | ||
|
||
return token_fields | ||
|
||
|
||
class OAuth2BearerToken(AuthBase): | ||
"""Implements OAuth2 Bearer access token authentication. | ||
Pass this object via the `auth` parameter to a request or a | ||
session object in order to authenticate your requests. | ||
Example usage, once you have the `access_token`: | ||
class GreetPerson(DiscoverableTransform): | ||
@classmethod | ||
def create_entities(cls, request, response): | ||
person_name = request.Value | ||
private_key_path = "private_key.pem" | ||
encrypted_secrets = request.getTransformSetting('maltego.web.api.key.linkedin') | ||
token_fields = MaltegoCrypto.decrypt_secrets(private_key_path,encrypted_secrets) | ||
api_url = ("https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))") | ||
auth = OAuth2BearerToken(token_fields['token']) | ||
result = requests.get(api_url,auth=auth) | ||
response.addEntity(Phrase, result.text) | ||
""" | ||
|
||
def __init__(self, access_token): | ||
self.access_token = access_token | ||
|
||
def __call__(self, request): | ||
request.headers['Authorization'] = 'Bearer {}'.format( | ||
self.access_token | ||
) | ||
return request |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
from maltego_trx.oauth import MaltegoOauth | ||
|
||
okta_ciphertoken = "pZ598ZEZ7EwpBQSOJSvCZJKkcWhtbX95K7Q0f0hwbk93O+xaUB4/NegK3r54PH1NReis/Jgt4UbGc5oCuU+R7UDM1icoDUmyCmV1U78iqjHElPdDBHlxPrl2zoXBwcU1iFbukDNy49Xghy3cwwqhmEXg/FKnYUlBQl6jdf06kE1pwfHiRgF5NrJISAD7eCmUybqiAVRDW4lbLeMGk/uSrrCpDQBxd2Em/sYKBzqO87pQRPLll23G9KNxyVinHQksGgc+dI0OPYv9EQcUs7g1JFraUKUeFjHAf/OyGGrp6WH84nGqG35afkH9xsDmySBb5DZWRjef8DzSd7oRagoGq3wKBHDh700mMKf/YkR8L9cK4l1w4yNh7EfIVlCWD5yWJUx4a1lN9CvJmFs7N9A903spVVGeP8avz50raWFb5g/4XhtIpei4ylVFi49dDeVjgb0BR0I4vuU7VDmcwFweAtSfclPb5Xfp98zI9yXnr8DB31gmzf3DIkVFIIFLxZe0gG+BSIEmC7/z0L7J+YvIqoGDq8jC0Ehe9IVXYfK1yluWAsbwj62rNAzkPVSe5l+FMQFrQRXpxZFBMXzphqRAhyYKfGNX/tocoMJoLFp8O3PBRC0kIHjTNaSX8KpftNYWreEdZx6wjk2n2eeOXM5nVeSOx4uoIifRe4NUV7VYzbGm3FSRc0k1HZIGHwn1WTvn95U3crvwFN86N3k41JU+0kzSpsLxy+Y63VfPxYTbRUET/wIOf0NTfG96QCPtVKkdVh9aTqnhaN0TpGoaZQEjUqpURxbj+8mT3g6MI4vOC9Qr6vw2wIkvzehr/yKxh6vsnfUUw8UJ1YtlZI7exPsHyFLUr2J3VvpDsaemRcn1KY/uHJZ3MMHK9GNciLA6Skw8SL38mw1tJJZ1h1bMMk1IYgBZLe2ZSXXyv7JaDPq/WJmHWDaIalmXE1cKMA56qMgYGdHxs3Pai5nwEtzIGVS1OcuMnBF6sOMMBTKSFAJmlcYo8NGwjKqe/yy1cVJZe7Ucv/jy/IS3AdE1my8cDya92jDsxifsaONQMm6YIs54SIA=$f7TU33wTTxYFtbVnwJeGGw==$c64l75qukq+980EkB1tQZKEicryt6HBB0IOjeMSRQmLOYCQpTcaXlPRJ3QdS+DfRocor7OL36wLAooRqz1IaN4QQ5+6Wx5reEXFVgKtaDX777I046DM5QU3Jf+iibSbm3mXYMw0z+OknbXyGLnc7ceSaPTJdP1LkCGQ75fLMXHCLWSpqwOKHOBhqyQGwrYlj2WxPzmOfAMaIkjKZIQWzoGjrYRzwkNCQbxykJcwD5TVuVDwAHyp84zcvW0WWoUZ+rrrooJwuJJQEdiTwLZsseqklXRNso4e5eFQwH49T9IDPHkKfVusu6rLiMNgFyc18rFR1d/BYLXBu7uzMAuvQ8wZdcOtJYx+JLJmOaPI65ymGNFTpwTHYnDBTXmpW0qX2dtEglAERw1nrdl94fwsa+I/iw3H7VIivqRF3pAchfvdNF75MIEm6XH2UXY/sZD7zjMdxxwKQiaEg2bpLd2mEtqsLc0mTq/zd03ZLEUnzXsXlp8brCfDgjoVsZAJH+ElQ6wr3dxzRMlDIxWWBYFcv8LnGVQk/Vciqtee780Yh/lgttv06kyXz81dIWjumz8TqV2eV9ZpP/YxTnNzAa91fleGNah/IKhMOV8PsGy2uOnHRiUL218p1T6+Cm9B2kmL1C/2MM3080NjJVWIfqYsyTGPbR+hURK0RB/oteG5QWPs=" | ||
private_key_path = "test_private_key.pem" | ||
|
||
|
||
def testOktaDecrypt(): | ||
decrypted_linkedIn_token = MaltegoOauth.decrypt_secrets(private_key_path, okta_ciphertoken)['token'] | ||
expected_token = "eyJraWQiOiJ4ZzEyMmNZMXQ0NU5GM2l5YlUzUF9tWGluYkxEXzVrRHFwMkQ0VEl2RGd3IiwiYWxnIjoiUlMyNTYifQ.eyJ2ZXIiOjEsImp0aSI6IkFULklldnVNcXNJNDFqMURldEdPU1N2Q2VoNlI5eUxEQ0EydFBJdl9FZ3hDU3ciLCJpc3MiOiJodHRwczovL2Rldi02MTcyNDUub2t0YS5jb20vb2F1dGgyL2RlZmF1bHQiLCJhdWQiOiJhcGk6Ly9kZWZhdWx0IiwiaWF0IjoxNTg5NzgzNjU0LCJleHAiOjE1ODk3ODcyNTQsImNpZCI6IjBvYTR1YTZ1YlJIeFRDTGg4NHg2IiwidWlkIjoiMDB1NHU0ZzA4SDFqYXQwVnA0eDYiLCJzY3AiOlsib3BlbmlkIl0sInN1YiI6InRtQG1hbHRlZ28uY29tIn0.dAZrIZ9NCIqIx3fr8_0EexYCzarj8CC4CvWpVgZQCvfhtV08tGnMdWN8yuzADYvJUSzDz_meqIMMUCaVOpYZ5vzepr3LZfT-Xn00KoaaRcHGLPowphvsEPkpimvJqgnRmWw0e0VTH5Pfg9eyl3o2UUUsDofM-RkJNjxB4Uf0D6IyZaCyl0s_KhcXGZuh7hDGoR76UcKaCqRXqmqnOZs_GoMPIoDS5NHIze0MOK6sgKr8uiLikIhdh481n8PyWzPX2XZLUNcjogqX280so6Ki24VBloyxt5VgAJ1gV-e9SDj-9QSdQohQNDDSHbgiO4s1TUlhFKIm5UQWUImdhSuv1w" | ||
assert decrypted_linkedIn_token == expected_token | ||
|
||
|
||
def testReadKey(): | ||
private_key = open(private_key_path).read() | ||
assert private_key.__sizeof__() == 3292 | ||
|
||
|
||
def testCipherSplit(): | ||
encrypted_fields = okta_ciphertoken.split("$") | ||
assert len(encrypted_fields) == 3 | ||
|
||
|
||
def testToken_Field_Creation(): | ||
encrypted_fields = okta_ciphertoken.split("$") | ||
aes_key = MaltegoOauth._rsa_decrypt(private_key_path, encrypted_fields[2]) | ||
token = MaltegoOauth._aes_decrypt(aes_key, encrypted_fields[0]) | ||
token_secret = MaltegoOauth._aes_decrypt(aes_key, encrypted_fields[1]) | ||
token_fields = { | ||
"token": token, | ||
"token_secret": token_secret | ||
} | ||
decrypted_azure_token_dict = MaltegoOauth.decrypt_secrets(private_key_path, okta_ciphertoken) | ||
assert token_fields == decrypted_azure_token_dict |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
-----BEGIN PRIVATE KEY----- | ||
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 | ||
e+tSC0NMYgwe0MkkVArhPdYdAbQS | ||
-----END PRIVATE KEY----- |