diff --git a/EA-MakeMeAdmin_ComplianceCheck.py b/EA-MakeMeAdmin_ComplianceCheck.py old mode 100644 new mode 100755 index 3884b83..1ca3650 --- a/EA-MakeMeAdmin_ComplianceCheck.py +++ b/EA-MakeMeAdmin_ComplianceCheck.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/Library/ManagedFrameworks/Python/Python3.framework/Versions/Current/bin/python3 import os, plistlib, subprocess @@ -6,12 +6,15 @@ statusFile = 'MakeMeAdmin.Status.plist' # compliancy check plist location if os.path.exists(workingDir + statusFile): - status = plistlib.readPlist(workingDir + statusFile).Status - if status == 'Compliant': - print '' + status + '' - else: - newAdm = plistlib.readPlist(workingDir + statusFile).newAdmins - orgAdm = plistlib.readPlist(workingDir + statusFile).orgAdmin - print '' + status + ' - ' + newAdm + ' - ' + orgAdm + '' + with open(workingDir + statusFile, 'rb') as fp: + d = plistlib.load(fp) + status = d["Status"] + + if status == 'Compliant': + print('' + status + '') + else: + newAdm = d["newAdmins"] + orgAdm = d["orgAdmin"] + print('' + status + ' - ' + newAdm + ' - ' + orgAdm + '') else: - print '' + 'Compliant' + '' \ No newline at end of file + print('' + 'Compliant' + '') diff --git a/EA-adminElevations24h.py b/EA-adminElevations24h.py new file mode 100755 index 0000000..0e37179 --- /dev/null +++ b/EA-adminElevations24h.py @@ -0,0 +1,32 @@ +#!/Library/ManagedFrameworks/Python/Python3.framework/Versions/Current/bin/python3 + +from datetime import date, timedelta, datetime + +workingDir = '/usr/local/jamfps/' # working directory for script +tempAdminLog = 'tempAdmin.log' # script log file + +fmt = '%Y-%m-%d %H:%M:%S.%f' + +stop = datetime.now() +start = stop - timedelta(days=1) + +elevationCount=0 + +try: + with open(workingDir + tempAdminLog, 'r') as file: + for line in file: + line = line.strip() + + try: + ts = datetime.strptime(' '.join(line.split()[:2]), fmt) + + if start <= ts <= stop: + if "Granted" in line: + elevationCount=elevationCount+1 + + except: + pass +except: + pass + +print(('' + str(elevationCount) + '')) diff --git a/grantTempAdmin.py b/grantTempAdmin.py index c97388e..f57c6af 100644 --- a/grantTempAdmin.py +++ b/grantTempAdmin.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/Library/ManagedFrameworks/Python/Python3.framework/Versions/Current/bin/python3 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # @@ -13,6 +13,7 @@ # documentation and/or other materials provided with the distribution. # * Neither the name of the Jamf nor the names of its contributors may be # used to endorse or promote products derived from this software without +# used to endorse or promote products derived from this software without # specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY JAMF SOFTWARE, LLC "AS IS" AND ANY @@ -55,6 +56,7 @@ # Updated On: July 26th, 2017 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Updated On: April 20th, 2022 - python3 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # IMPORTS @@ -83,23 +85,24 @@ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # place launchd plist to call JSS policy to remove admin rights. -print 'Creating LaunchDaemon...' +print('Creating LaunchDaemon...') launchDaemon = { 'Label':launchdLabel, 'LaunchOnlyOnce':True, 'ProgramArguments':['/usr/local/jamf/bin/jamf', 'policy', '-trigger', policyCustomTrigger], 'StartInterval':adminTimer, 'UserName':'root', } -plistlib.writePlist(launchDaemon, '/Library/LaunchDaemons/' + launchdFile) +with open('/Library/LaunchDaemons/' + launchdFile, "wb") as fp: + plistlib.dump(launchDaemon, fp) # set the permission on the file just made. userID = pwd.getpwnam("root").pw_uid groupID = grp.getgrnam("wheel").gr_gid os.chown('/Library/LaunchDaemons/' + launchdFile, userID, groupID) -os.chmod('/Library/LaunchDaemons/' + launchdFile, 0644) +os.chmod('/Library/LaunchDaemons/' + launchdFile, 0o644) -# load the removal plist timer. -print 'Loading LaunchDaemon...' +# load the removal plist timer. +print('Loading LaunchDaemon...') subprocess.call(["launchctl", "load", "-w", '/Library/LaunchDaemons/' + launchdFile]) # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # @@ -112,12 +115,13 @@ # record user that will need to have admin rights removed # record current existing admins -print 'Retrieving List of Current Admins...' +print('Retrieving List of Current Admins...') currentAdmins = grp.getgrnam('admin').gr_mem -print 'Updating Plist...' +print('Updating Plist...') plist = { 'User2Remove':userName, 'CurrentAdminUsers':currentAdmins} -plistlib.writePlist(plist, workingDir + plistFile) +with open(workingDir + plistFile, "wb") as fp: + plistlib.dump(plist, fp) # give current logged user admin rights subprocess.call(["dseditgroup", "-o", "edit", "-a", userName, "-t", "user", "admin"]) @@ -127,4 +131,4 @@ log.write("{} - MakeMeAdmin Granted Admin Rights for {}\r\n".format(datetime.now(), userName)) log.close() -print 'Granted Admin Right to ' + userName +print('Granted Admin Right to ' + userName) diff --git a/removeTempAdmin.py b/removeTempAdmin.py index 9598c88..f96c395 100644 --- a/removeTempAdmin.py +++ b/removeTempAdmin.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/Library/ManagedFrameworks/Python/Python3.framework/Versions/Current/bin/python3 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # @@ -55,6 +55,7 @@ # Updated On: July 26th, 2017 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# Updated On: April 20th, 2022 - python3 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # IMPORTS @@ -82,8 +83,8 @@ def DecryptString(inputString, salt, passphrase): '''Usage: >>> DecryptString("Encrypted String", "Salt", "Passphrase")''' - p = subprocess.Popen(['/usr/bin/openssl', 'enc', '-aes256', '-d', '-a', '-A', '-S', salt, '-k', passphrase], stdin = subprocess.PIPE, stdout = subprocess.PIPE) - return p.communicate(inputString)[0] + p = subprocess.Popen(['/usr/bin/openssl', 'enc', '-aes256', '-d', '-md', 'md5', '-a', '-A', '-S', salt, '-k', passphrase], stdin = subprocess.PIPE, stdout = subprocess.PIPE) + return p.communicate(inputString.encode())[0] # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # APPLICATION @@ -91,47 +92,51 @@ def DecryptString(inputString, salt, passphrase): if os.path.exists(workingDir + plistFile): # remove user admin rights - user2Remove = plistlib.readPlist(workingDir + plistFile).User2Remove - subprocess.call(["dseditgroup", "-o", "edit", "-d", user2Remove, "-t", "user", "admin"]) - # add log entry - log = open(workingDir + tempAdminLog, "a+") - log.write("{} - MakeMeAdmin Removed Admin Rights for {}\r\n".format(datetime.now(), user2Remove)) - log.close() - print 'Revoked Admin Rights for ' + user2Remove - # compre prior to current admin lists - print 'Checking for newly created admin accounts...' - priorAdmins = plistlib.readPlist(workingDir + plistFile).CurrentAdminUsers - currentAdmins = grp.getgrnam('admin').gr_mem - newAdmins = set(currentAdmins).difference(set(priorAdmins)) - newAdm = '' - if not newAdmins: - print ' No New Accounts Found!' - # update compliancy plist - status = { 'Status':'Compliant'} - plistlib.writePlist(status, workingDir + statusFile) - else: - print ' New Admin Accounts Found!' + with open(workingDir + plistFile, 'rb') as fp: + d = plistlib.load(fp) + user2Remove = d["User2Remove"] + subprocess.call(["dseditgroup", "-o", "edit", "-d", user2Remove, "-t", "user", "admin"]) + # add log entry log = open(workingDir + tempAdminLog, "a+") - log.write("{} - MakeMeAdmin Discovered New Admin Accounts: {}\r\n".format(datetime.now(), list(newAdmins))) + log.write("{} - MakeMeAdmin Removed Admin Rights for {}\r\n".format(datetime.now(), user2Remove)) log.close() - # update status plist - status = { 'Status':'Remediated', - 'newAdmins':'newAdmin Created', - 'orgAdmin':'orgAdmin OK'} - plistlib.writePlist(status, workingDir + statusFile) - newAdm = plistlib.readPlist(workingDir + statusFile).newAdmins - # loop through new admin accounts and remove admin rights - print ' Removing Admin Rights for New Admin Accounts...' - for user in newAdmins: - subprocess.call(["dseditgroup", "-o", "edit", "-d", user, "-t", "user", "admin"]) + print('Revoked Admin Rights for ' + user2Remove) + # compre prior to current admin lists + print('Checking for newly created admin accounts...') + priorAdmins = d["CurrentAdminUsers"] + currentAdmins = grp.getgrnam('admin').gr_mem + newAdmins = set(currentAdmins).difference(set(priorAdmins)) + newAdm = '' + if not newAdmins: + print(' No New Accounts Found!') + # update compliancy plist + status = { 'Status':'Compliant'} + with open(workingDir + statusFile, "wb") as fp2: + plistlib.dump(status, fp2) + else: + print(' New Admin Accounts Found!') + newAdm = 'newAdmin Created' log = open(workingDir + tempAdminLog, "a+") - log.write("{} - MakeMeAdmin Removed Admin Rights for: {}\r\n".format(datetime.now(), user)) + log.write("{} - MakeMeAdmin Discovered New Admin Accounts: {}\r\n".format(datetime.now(), list(newAdmins))) log.close() - print ' Removed Admin Rights for ' + user - time.sleep(1) + # update status plist + status = { 'Status':'Remediated', + 'newAdmins':newAdm, + 'orgAdmin':'orgAdmin OK'} + with open(workingDir + statusFile, "wb") as fp2: + plistlib.dump(status, fp2) + # loop through new admin accounts and remove admin rights + print(' Removing Admin Rights for New Admin Accounts...') + for user in newAdmins: + subprocess.call(["dseditgroup", "-o", "edit", "-d", user, "-t", "user", "admin"]) + log = open(workingDir + tempAdminLog, "a+") + log.write("{} - MakeMeAdmin Removed Admin Rights for: {}\r\n".format(datetime.now(), user)) + log.close() + print(' Removed Admin Rights for ' + user) + time.sleep(1) # check if organization admin(s) are valid - print 'Checking organizational admin passwords...' - for admin, admpass in orgAdmins.iteritems(): + print('Checking organizational admin passwords...') + for admin, admpass in orgAdmins.items(): # decrypt password admpassDecrypted = DecryptString(admpass, salt, passphrase) time.sleep(1) @@ -141,52 +146,56 @@ def DecryptString(inputString, salt, passphrase): log = open(workingDir + tempAdminLog, "a+") log.write("{} - orgAdmin Password is Valid \r\n".format(datetime.now())) log.close() - print 'Password for orgAdmin: ' + admin + ' is valid!' + print('Password for orgAdmin: ' + admin + ' is valid!') else: log = open(workingDir + tempAdminLog, "a+") log.write("{} - orgAdmin Password is Invalid! \r\n".format(datetime.now())) log.close() result = subprocess.call(["dscl", ".", "passwd", "/Users/" + admin, admpassDecrypted]) time.sleep(3) - print 'Password for orgAdmin: ' + admin + ' was invalid!' + print('Password for orgAdmin: ' + admin + ' was invalid!') if result == 0: log = open(workingDir + tempAdminLog, "a+") log.write("{} - orgAdmin Password Successfully Reset! \r\n".format(datetime.now())) log.close() - print 'Password Successfully Reset for ' + admin + "!" + print('Password Successfully Reset for ' + admin + "!") if not newAdm: # update status plist status = { 'Status':'Remediated', 'newAdmins':'No newAdmins', 'orgAdmin':'orgAdmin OK'} - plistlib.writePlist(status, workingDir + statusFile) + with open(workingDir + statusFile, "wb") as fp2: + plistlib.dump(status, fp2) else: # update status plist status = { 'Status':'Remediated', 'newAdmins':'newAdmin Created', 'orgAdmin':'orgAdmin OK'} - plistlib.writePlist(status, workingDir + statusFile) + with open(workingDir + statusFile, "wb") as fp2: + plistlib.dump(status, fp2) else: log = open(workingDir + tempAdminLog, "a+") log.write("{} - Error Resetting orgAdmin Password! \r\n".format(datetime.now())) log.close() - print 'Error Resetting Password for ' + admin + "!" + print('Error Resetting Password for ' + admin + "!") if not newAdm: # update status plist status = { 'Status':'Violation', 'newAdmins':'No newAdmins', 'orgAdmin':'orgAdmin ERROR'} - plistlib.writePlist(status, workingDir + statusFile) + with open(workingDir + statusFile, "wb") as fp2: + plistlib.dump(status, fp2) else: # update status plist status = { 'Status':'Violation', 'newAdmins':'newAdmin Created', 'orgAdmin':'orgAdmin ERROR'} - plistlib.writePlist(status, workingDir + statusFile) + with open(workingDir + statusFile, "wb") as fp2: + plistlib.dump(status, fp2) os.remove(workingDir + plistFile) if os.path.exists('/Library/LaunchDaemons/' + launchdFile): - print 'Removing LaunchDaemon...' + print('Removing LaunchDaemon...') os.remove('/Library/LaunchDaemons/' + launchdFile) # Submit Jamf Pro Inventory