Files
2026-02-16 15:05:15 +01:00

141 lines
4.7 KiB
Python
Executable File

# -*- coding: utf-8 -*-
"""
Keysword is a utility for extracting Filevault2 keys from JAMF JSS
~~~~~~~~~~~~
This module implements the Requests API.
:copyright: (c) 2019 by Mike Mackintosh.
:license: Apache2, see LICENSE for more details.
"""
import requests
import cookielib
import argparse
from os import getenv
from xml.dom.minidom import parseString
__VERSION__ = "1.0"
JAMF_HOST = getenv("JAMF_HOST")
JAMF_USERNAME = getenv("JAMF_USERNAME")
JAMF_PASSWORD = getenv("JAMF_PASSWORD")
"""
getComputerID
-------------
Converts a computer name to a computer ID using the JAMF API
:param name string
:return id string
"""
def getComputerID(name):
auth = requests.auth.HTTPBasicAuth(JAMF_USERNAME, JAMF_PASSWORD)
headers = {"Accept": "application/json"}
resp = requests.get("{}/JSSResource/computers/name/{}".format(JAMF_HOST, name), auth=auth, headers=headers)
# TODO: add error checking here
return resp.json()["computer"]["general"]["id"]
"""
getSessionToken
-------------
Gets a session token from the legacy pages to get access to the ajax API
:param s requests.Session
:param jar cookie jar
:return token string
"""
def getSessionToken(s, jar, id):
resp = s.post('{}/?failover'.format(JAMF_HOST), cookies=jar, data={'username':JAMF_USERNAME, 'password':JAMF_PASSWORD, 'resetUsername':''})
if resp.status_code != 200:
print "Looks like you failed to authenticate"
exit(1)
params = {"id": id, "o": "r", "v": "management"}
resp = s.get('{}/legacy/computers.html'.format(JAMF_HOST), params=params, cookies=jar)
session_token = ""
# TODO: add error checking here
for line in resp.content.splitlines():
if "session-token" in line:
return line.encode('utf-8').translate(None, '<>"').split('=')[-1]
print "Unable to find session token"
"""
main
-------------
Connects to the JAMF JSS API and extracts a filevault key for the provided device ID
:param id string
:param name string
"""
def main(id, name):
""" Create the cookie jar and session for requests """
jar = cookielib.CookieJar()
s = requests.Session()
s.cookies = jar
""" Get the computer id if a hostname was provided """
if len(name) > 0:
id = getComputerID(name)
""" Get the session token """
session_token = getSessionToken(s, jar, id)
if len(session_token) == 0:
print "Unable to find session token"
exit()
""" Make the request against the computers.ajax endpoint """
data = "&ajaxAction=AJAX_ACTION_READ_FILE_VAULT_2_KEY&session-token={}".format(session_token)
resp = s.post('{}/computers.ajax?id={}&o=r&v=management'.format(JAMF_HOST, id), data="{}".format(data), cookies=jar, headers={
"X-Requested-With": "XMLHttpRequest",
"Origin": JAMF_HOST,
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"Accept": "*/*",
"Content-Length": "{}".format(len(data)),
"Accept-Encoding": "gzip, deflate, br",
"Accept-Language": "en-US,en;q=0.9",
"Connection": "keep-alive",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36",
"Referer": "{}/legacy/computers.html?id={}&o=r&v=management".format(JAMF_HOST, id)
})
# TODO: add error checking here
e = parseString(resp.content)
if len(e.getElementsByTagName("individualKey")) > 0:
for n in e.getElementsByTagName("individualKey")[0].childNodes:
if n.nodeType == n.TEXT_NODE:
print n.data
return
""" If we couldn't find the key, print """"
print "Unable to find filevault key"
""" main """
if __name__ == "__main__":
""" Create Argparser """
parser = argparse.ArgumentParser(prog='keysword')
parser.add_argument('-id', action="store", default="", dest="id")
parser.add_argument('-name', action="store", default="", dest="name")
parser.add_argument('--version', action='version', version='%(prog)s {}'.format(__VERSION__))
results = parser.parse_args()
""" Quick validation of arguments """
if len(results.id) == 0 and len(results.name) == 0:
print "Please provide a computer id with -id or computer name with -name"
exit()
elif len(results.id) != 0 and len(results.name) != 0:
print "Please provide only one computer id with -id or with -name, but not both"
exit()
if len(getenv("JAMF_USERNAME")) == 0 \
or len(getenv("JAMF_USERNAME")) == 0 \
or len(getenv("JAMF_HOST")) == 0:
print "Please set your environment variables appropriately"
exit()
""" run main """
main(results.id, results.name)