-
Notifications
You must be signed in to change notification settings - Fork 29
/
JamfExplorer.py
executable file
·147 lines (113 loc) · 4.51 KB
/
JamfExplorer.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
import argparse
import string
import sys
import subprocess
import plistlib
import os
import hashlib
from os.path import join, isdir
from threading import Thread
class bcolors:
HEADER = '\033[95m'
OKBLUE = '\033[94m'
OKGREEN = '\033[92m'
WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
parser = argparse.ArgumentParser(description="Listen for new Jamf policy processes to determine insecure credential storage.")
parser.add_argument('--output', nargs='?', default="explorer_output", help='Folder to output results')
args = parser.parse_args()
if not isdir("/Library/Application Support/JAMF"):
print("[!] Jamf Application Support folder not found... are you sure Jamf is installed?")
sys.exit()
try:
with open("/Library/Preferences/com.jamfsoftware.jamf.plist", "rb") as f:
jss_prefs = plistlib.load(f)
except Exception as e:
print("[!] Jamf Preferences PLIST not found. Is Jamf enrolled correctly?")
print(e)
sys.exit()
print("[*] Determining privilege to the Jamf temp/download directories.")
if os.access("/Library/Application Support/JAMF/tmp", os.R_OK):
print("[*] We have access! Listening for scripts, packages and EAs.")
privileged_access = True
else:
print("[*] Access denied. That's okay... listening for process arguments only")
privileged_access = False
def tmp_listener():
known = []
known_filenames = []
try:
os.mkdir(args.output)
except:
pass
while True:
for file in os.listdir("/Library/Application Support/JAMF/tmp"):
try:
with open(join("/Library/Application Support/JAMF/tmp", file), "rb") as in_f:
file_data = in_f.read()
except FileNotFoundError:
continue
hash = hashlib.md5(file_data).hexdigest()
if hash not in known:
path = join(args.output, file)
with open(path, "wb") as out_f:
out_f.write(file_data)
os.chmod(path, 0o777)
known.append(hash)
if file not in known_filenames:
print("[*] New File: %s (%s)" % (file, hash))
known_filenames.append(file)
else:
print("[*] File Updated: %s (%s)" % (file, hash))
for file in os.listdir("/Library/Application Support/JAMF/Downloads"):
try:
with open(join("/Library/Application Support/JAMF/Downloads", file), "rb") as in_f:
file_data = in_f.read()
except FileNotFoundError:
continue
hash = hashlib.md5(file_data).hexdigest()
if hash not in known:
path = join(args.output, file)
with open(path, "wb") as out_f:
out_f.write(file_data)
os.chmod(path, 0o777)
known.append(hash)
if file not in known_filenames:
print("[*] New File: %s (%s)" % (file, hash))
known_filenames.append(file)
else:
print("[*] File Updated: %s (%s)" % (file, hash))
def args_listener():
known = []
while True:
p = subprocess.Popen(["ps", "-ax", "-o", "command,"], stdout=subprocess.PIPE)
results = p.stdout.read().splitlines()[1:]
for res in results:
cmd = res.decode('utf-8')
if "jamf" in cmd.lower() and not cmd.startswith("(") and not cmd.endswith(")"):
if cmd.startswith("sh -c PATH=$PATH:/usr/local/jamf/bin;"):
hash = hashlib.md5(res).hexdigest()
if hash not in known:
args = cmd.split(";")[1].strip().split("'")[1::2]
if args[0] == "/bin/sh":
args = args[1:]
print("[*] New Process: %s" % args[0])
print(" - Mount Point: %s" % args[1])
print(" - Computer Name: %s" % args[2])
print(" - Username: %s" % args[3])
print(" - Parameters:")
for i, arg in enumerate(args[4:13]):
print(" %i: %s" % (i+4, arg))
known.append(hash)
threads = []
if privileged_access:
threads.append(Thread(target=tmp_listener))
threads.append(Thread(target=args_listener))
for t in threads:
t.start()
# Spin
while True:
pass