Setting up security features
Keychain
#!/bin/bash #Author : Arun Patwardhan #Date : 14th January 2020 #Contact : arun@amaranthine.co.in #Website : https://www.amaranthine.in #Scope : This script populates the keychain with some predefined secrets #Arguments : This script does not take any arguments #NOTE : This script must be run as sudo. #DISCLAIMER : The author of this script provides it on an as is basis. The author is not repsonsible for any damages, loss of data or any other issue that may occur with # the use of this script. The user of this script must take due care to validate the script before use. #WARNING : Use caution while running scripts as root. #################################################################################################### #################################################################################################### # SAMPLE USAGE # ./exploreKeychain.sh #################################################################################################### #################################################################################################### #Variables #This variable get us access to the last keychain in the list. It assumes that only the default keychain exists. KEYCHAINNAME=`security list-keychains | awk '{print $1}' | sort -n | tail -1` #4. Add an internet item to the keychain security add-internet-password -a student@mail.com -s www.mail.com -w studentPassword $KEYCHAINNAME #5. Find an internet password security find-internet-password -a student@mail.com -s www.mail.com -g #6. Export all keychain items security export -k $KEYCHAINNAME -P passcode -f pkcs12 -o ~/Desktop/secFile.p12 #View other scripts for security related changes.
FileVault
There are 2 ways to do this.
- Use the defer method and provide a plist to hold the recovery key
- Use an institutional key
Option 1: Use the defer method and provide a plist to hold the recovery key
#!/bin/sh #!/usr/bin/expect -f #Author : Arun Patwardhan #Date : 14th January 2020 #Contact : arun@amaranthine.co.in #Website : https://www.amaranthine.in #Scope : This script creates comfigures and updates record for FileVault on macOS. #Arguments #argument 1 : user Name #argument 2 : password #NOTE : This script must be run as sudo. #DISCLAIMER : The author of this script provides it on an as is basis. The author is not repsonsible for any damages, loss of data or any other issue that may occur with # the use of this script. The user of this script must take due care to validate the script before use. #WARNING : Use caution while running scripts as root. #################################################################################################### #################################################################################################### # VALUE FORMAT FOR THE ARGUMENTS # USERNAME : All lower case, one word # PASSWORD : Should be a single word. This is the new password value # # SAMPLE USAGE # sudo sh ./configureFileVault.sh <USERNAME> <PASSWORD> # sudo sh ./configureFileVault.sh ladmin ladminpwd #################################################################################################### #################################################################################################### #Variables USERNAME="" PASSWORD="" FDECONFIGLOG="/Users/Shared/.fdeConfig/fdeCongif.log" FDECONFIGPATH="/Users/Shared/.fdeConfig/" TURNONFILEVAULT="FALSE" FDECONFIGFILE="/Users/Shared/.fdeConfig/FDEConfigSettings.plist" #1. Check to see if the script is being run as root if [[ $EUID -ne 0 ]]; then echo "The script must be run as root." exit 1 fi #2. Assign values to variables USERNAME=$1 PASSWORD=$2 #3. Check to see if all the arguments are passed if [[ $USERNAME == "" || $PASSWORD == "" ]]; then echo "ERROR: Incorrect use of command. Please make sure all the arguments are passed in." echo "sudo sh ./configureFileVault.sh <USERNAME> <NEW PASSWORD>" echo "For Example" echo "sudo sh ./configureFileVault.sh ladmin ladminpwd" exit 1 fi #4. Before turning on FileVault we must to check to see if the user we need exists. if [[ $USERNAME != $(dscl . -list /Users UniqueID | awk '{print $1}' | grep -w "$USERNAME") ]]; then echo "The User does not exist. Please check username" exit 0 fi #5. Check to see if a temp folder to hold the recovery key can be created if [[ -d /.fdeConfig ]]; then echo "$(date "+DATE: %Y-%m-%d% TIME: %H:%M:%S") Folder exists" >> $FDECONFIGLOG else cd /Users/Shared/ mkdir .fdeConfig echo "$(date "+DATE: %Y-%m-%d% TIME: %H:%M:%S") Creating folder" >> $FDECONFIGLOG fi cd $FDECONFIGPATH #6. Check to see if FileVault is already enabled ISACTIVE=$(fdesetup isactive) echo "$ISACTIVE" if [[ $ISACTIVE == "false" ]]; then echo "$(date "+DATE: %Y-%m-%d% TIME: %H:%M:%S") FileVault not on" >> $FDECONFIGLOG echo "$(date "+DATE: %Y-%m-%d% TIME: %H:%M:%S") Turning on FileVault" >> $FDECONFIGLOG TURNONFILEVAULT="TRUE" fi #---------------------------------------------------------------------------------------------------- ##OPTION 1 - Defer enablement for later #7. Check to see if the file is there or not if [[ -f $FDECONFIGFILE ]]; then echo "$(date "+DATE: %Y-%m-%d% TIME: %H:%M:%S") Config File exists" >> $FDECONFIGLOG else touch $FDECONFIGFILE echo "$(date "+DATE: %Y-%m-%d% TIME: %H:%M:%S") Creaitng Config File" >> $FDECONFIGLOG fi #8. Turn on filevault if [[ $TURNONFILEVAULT == "TRUE" ]]; then fdesetup enable -defer $FDECONFIGPATH/FDEConfigSettings.plist fi echo "$(date "+DATE: %Y-%m-%d% TIME: %H:%M:%S")" >> $FDECONFIGLOG fdesetup status >> $FDECONFIGLOG
Option 2: Use an institutional key
#!/bin/sh #!/usr/bin/expect -f #Author : Arun Patwardhan #Date : 14th January 2020 #Contact : arun@amaranthine.co.in #Website : https://www.amaranthine.in #Scope : This script creates comfigures and updates record for FileVault on macOS. #Arguments #argument 1 : user Name #argument 2 : password #NOTE : This script must be run as sudo. #DISCLAIMER : The author of this script provides it on an as is basis. The author is not repsonsible for any damages, loss of data or any other issue that may occur with # the use of this script. The user of this script must take due care to validate the script before use. #WARNING : Use caution while running scripts as root. #################################################################################################### #################################################################################################### # VALUE FORMAT FOR THE ARGUMENTS # USERNAME : All lower case, one word # PASSWORD : Should be a single word. This is the new password value # # SAMPLE USAGE # sudo sh ./configureFileVault.sh <USERNAME> <PASSWORD> # sudo sh ./configureFileVault.sh ladmin ladminpwd #################################################################################################### #################################################################################################### #Variables USERNAME="" PASSWORD="" FDECONFIGLOG="/Users/Shared/.fdeConfig/fdeCongif.log" FDECONFIGPATH="/Users/Shared/.fdeConfig/" TURNONFILEVAULT="FALSE" #1. Check to see if the script is being run as root if [[ $EUID -ne 0 ]]; then echo "The script must be run as root." exit 1 fi #2. Assign values to variables USERNAME=$1 PASSWORD=$2 #3. Check to see if all the arguments are passed if [[ $USERNAME == "" || $PASSWORD == "" ]]; then echo "ERROR: Incorrect use of command. Please make sure all the arguments are passed in." echo "sudo sh ./configureFileVault.sh <USERNAME> <NEW PASSWORD>" echo "For Example" echo "sudo sh ./configureFileVault.sh ladmin ladminpwd" exit 1 fi #4. Before turning on FileVault we must to check to see if the user we need exists. if [[ $USERNAME != $(dscl . -list /Users UniqueID | awk '{print $1}' | grep -w "$USERNAME") ]]; then echo "The User does not exist. Please check username" exit 0 fi #5. Check to see if a temp folder to hold the recovery key can be created if [[ -d /.fdeConfig ]]; then echo "$(date "+DATE: %Y-%m-%d% TIME: %H:%M:%S") Folder exists" >> $FDECONFIGLOG else cd /Users/Shared/ mkdir .fdeConfig echo "$(date "+DATE: %Y-%m-%d% TIME: %H:%M:%S") Creating folder" >> $FDECONFIGLOG fi cd $FDECONFIGPATH #6. Check to see if FileVault is already enabled ISACTIVE=$(fdesetup isactive) echo "$ISACTIVE" if [[ $ISACTIVE == "false" ]]; then echo "$(date "+DATE: %Y-%m-%d% TIME: %H:%M:%S") FileVault not on" >> $FDECONFIGLOG echo "$(date "+DATE: %Y-%m-%d% TIME: %H:%M:%S") Turning on FileVault" >> $FDECONFIGLOG TURNONFILEVAULT="TRUE" fi #---------------------------------------------------------------------------------------------------- #OPTION 2 - Use institutional deployment #7. Export the variables for use in Expect script export USERNAME export PASSWORD export FDERECOVERKEYPATH #8. Change the permissions for the FileVault Master Key cp ~/Desktop/FileVaultMaster.keychain /Library/Keychains/ chown root:wheel /Library/Keychains/FileVaultMaster.keychain chmod 644 /Library/Keychains/FileVaultMaster.keychain #9. If we are turning on FileVault for the first time, then turn it on using the Master Key. Else change the receovery key method to Institutional. if [[ $TURNONFILEVAULT == "TRUE" ]]; then /usr/bin/expect -c ' set myUserName $env(USERNAME); set myPassword $env(PASSWORD); spawn fdesetup enable -keychain -norecoverykey expect "Enter the user name:" { send "$myUserName\r"} expect "Enter the password for user ?" { send "$myPassword\r"} expect eof' echo "$(date "+DATE: %Y-%m-%d% TIME: %H:%M:%S") Turning on FileVault" >> $FDECONFIGLOG else fdesetup changerecovery -institutional -keychain /Library/Keychains/FileVaultMaster.keychain echo "$(date "+DATE: %Y-%m-%d% TIME: %H:%M:%S") Since FileVault is already tunred on, only changing the recovery key to institutional" >> $FDECONFIGLOG fi echo "$(date "+DATE: %Y-%m-%d% TIME: %H:%M:%S")" >> $FDECONFIGLOG fdesetup status >> $FDECONFIGLOG
Security Reports
This script generates a system report on the security settings/status on macOS. The one change here is that I have used Swift Programming Language to handle the parsing. This could have been done using Shell or other languages too.
#!/bin/bash #Author : Arun Patwardhan #Date : 13th January 2020 #Contact : arun@amaranthine.co.in #Website : https://www.amaranthine.in #Scope : This script examines the different security settings and prepares a report for the same. #Arguments #argument 1 : Username #argument 2 : Password #NOTE : This script must be run as sudo. #DISCLAIMER : The author of this script provides it on an as is basis. The author is not repsonsible for any damages, loss of data or any other issue that may occur with # the use of this script. The user of this script must take due care to validate the script before use. #WARNING : Use caution while running scripts as root. #################################################################################################### #################################################################################################### # VALUE FORMAT FOR THE ARGUMENTS # USERNAME : All lower case, one word # PASSWORD : Should be a single word # ACCOUNT TYPE : One Word, "admin", "standard" # REAL NAME : Can be more than one word. If it is more than one word then it should be in quotes. # PRIMARY GROUP ID : Just a number. (80 -> admin, 20 -? user) # # SAMPLE USAGE # ./generateSecurityReport.sh <USERNAME> <PASSWORD> # ./generateSecurityReport.sh ladmin ladminpwd #################################################################################################### #################################################################################################### #Variables USERNAME="" PASSWORD="" REPORTNAME="/Users/Shared/Report/in.amaranthine.SECURITYREPORT.plist" REPORTPATH="/Users/Shared/Report" REPORTLOG="/Users/Shared/Report/report.log" #1. Check to see if the script is being run as root if [[ $EUID -ne 0 ]]; then echo "The script must be run as root." exit 1 fi #2. Assign values to variables USERNAME=$1 PASSWORD=$2 #3. Check to see if all the arguments are passed if [[ $USERNAME == "" || $PASSWORD == "" ]]; then echo "ERROR: Incorrect use of command. Please make sure all the arguments are passed in." echo "sudo ./generateSecurityReport.sh <USERNAME> <PASSWORD>" echo "For Example" echo "sudo ./generateSecurityReport.sh ladmin ladminpwd" exit 1 fi echo $USERNAME $PASSWORD #4. Check to see if the folder exists if [[ -d $REPORTPATH ]] then echo "$(date "+DATE: %Y-%m-%d%TIME: %H:%M:%S") Folder exists" >> $REPORTLOG else cd /Users/Shared/ mkdir Report cd Report touch report.log echo "$(date "+DATE: %Y-%m-%d%TIME: %H:%M:%S") Created Folder" >> $REPORTLOG fi #SIP STATUS ---------------------------------------------------------------------------------------- SIPSTAT=$(csrutil status) defaults write $REPORTNAME SIP "$SIPSTAT" #GATEKEEPER STATUS --------------------------------------------------------------------------------- GATEKEEPERSTAT=$(spctl --status) defaults write $REPORTNAME GateKeeper "$GATEKEEPERSTAT" #FIREWALL ------------------------------------------------------------------------------------------ FIREWALLSTAT=$(defaults read /Library/Preferences/com.apple.alf.plist) defaults write $REPORTNAME Firewall "$FIREWALLSTAT" ##UAKEL STATUS -------------------------------------------------------------------------------------- /usr/bin/expect -c ' spawn sqlite3 /var/db/SystemPolicyConfiguration/KextPolicy expect "sqlite>" { send ".mode csv\r"} expect "sqlite>" { send ".output /Users/Shared/Report/macOSKextWhitelist.csv\r"} expect "sqlite>" { send "SELECT * FROM kext_policy;\r"} expect "sqlite>" { send ".output stdout\r"} expect "sqlite>" { send ".quit\r"} expect eof' #transform to _ delimited cat /Users/Shared/Report/macOSKextWhitelist.csv| tr "," "_" >> ~/Desktop/transformedFile.txt #parse the file using builtin parser ~/Desktop/csvparser --file ~/Desktop/transformedFile.txt --delimiter _ --keylist ~/Desktop/keys.txt --plist $REPORTNAME #cleanup rm ~/Desktop/transformedFile.txt rm /Users/Shared/Report/macOSKextWhitelist.csv #SECURE TOKEN STATUS ------------------------------------------------------------------------------- #4. Get list of users USERS=$(dscl . -list /Users | grep -v '_') SECURETOKENENABLEDUSERS=() for person in $USERS do sysadminctl -secureTokenStatus $person 2> $REPORTPATH/TOKENSTAT.log STR=$(grep -w "ENABLED" $REPORTPATH/TOKENSTAT.log) if [[ $STR != "" ]] then SECURETOKENENABLEDUSERS+=($person) fi done COMMAND="(" for human in ${SECURETOKENENABLEDUSERS[@]} do if [[ $COMMAND == "(" ]] then COMMAND=$(echo "$COMMAND $human") else COMMAND=$(echo "$COMMAND, $human") fi done COMMAND=$(echo "$COMMAND )") #write to report defaults write $REPORTNAME SecureTokenEnabledUsers -array "$COMMAND" #cleanup rm $REPORTPATH/TOKENSTAT.log #FILEVAULT STATUS ---------------------------------------------------------------------------------- FVISON=$(echo ""$(fdesetup isactive)"") FVSTATUS=$(echo ""$(fdesetup status)"") FVKEYTYPE=" " ISACTIVE=$(fdesetup isactive) FVPERSONALKEY="" FVINSTITKEY="" if [[ $ISACTIVE == "true" ]]; then FVPERSONALKEY=$(fdesetup haspersonalrecoverykey) FVINSTITKEY=$(fdesetup hasinstitutionalrecoverykey) if [[ $FVPERSONALKEY == "true" ]]; then FVKEYTYPE="Personal" elif [[ $FVINSTITKEY == "true" ]]; then FVKEYTYPE="Institutional" fi fi echo $FVSTATUS #write to report defaults write $REPORTNAME FileVaultInfo -dict-add IsActive "$FVISON" defaults write $REPORTNAME FileVaultInfo -dict-add Status "$FVSTATUS" defaults write $REPORTNAME FileVaultInfo -dict-add FileVaultKeyType "$FVKEYTYPE"
The swift file which contains the parsing logic. This can also be downloaded from the GitHub link shared earlier. I will be sharing the project for the same.
import Foundation //MARK: - Variables var fileToParse : String = "" var delimiter : String = "" var lines : [String] = [String]() var parsedResult : [Dictionary<String, String>] = [Dictionary<String,String>]() var keys : [String] = [String]() var keyFile : String = "" var plistFile : String = "" var captureFileName : Bool = false var captureDelimiter : Bool = false var captureKeyList : Bool = false var capturePlist : Bool = false //MARK: - Argument Processing //Make sure that the arguments are passed in if CommandLine.arguments.count == 0 { print("Please provide arguments in the following sequence") print("csvparser --file <FILENAME> --delimiter <DELIMITER> --keylist <KEYLIST> --plist <PLISTFILE>") print("FOR EXAMPLE:") print("csvparser --file ~/Desktop/input.csv --delimiter , --keylist keys.txt -- plist com.company.name.plist") } //Populate the variables based on the data from the arguments for argument in CommandLine.arguments { if captureFileName { fileToParse = argument captureFileName = false } if captureDelimiter { delimiter = argument captureDelimiter = false } if captureKeyList { keyFile = argument captureKeyList = false } if capturePlist { plistFile = argument capturePlist = false } switch argument { case "--file": captureFileName = true case "--delimiter": captureDelimiter = true case "--keylist": captureKeyList = true case "--plist": capturePlist = true default: continue } } //MARK: - Parsing //Read the contents of the file and split it into lines. func splitIntoLines(contentsOf fileName : String) -> [String] { do { let data = try String(contentsOfFile: fileName, encoding: .ascii) let myStrings = data.components(separatedBy: .newlines) return myStrings } catch { return [] } } //Split the document into an array of lines lines = splitIntoLines(contentsOf: fileToParse) keys = splitIntoLines(contentsOf: keyFile) //Clean out the array let cleanLines = lines.filter({(input : String) -> Bool in return !input.isEmpty }) //Parse out the line and populate into the dictionary for line in cleanLines { let lineParts = line.components(separatedBy: delimiter) var tempDictionary : Dictionary<String,String> = Dictionary<String,String>() var partCount : Int = 0 for item in lineParts { var newStr : String = "" if item.contains("\"") { for element in item { if element != "\"" { newStr.append(element) } } } else { newStr = item } tempDictionary["\(keys[partCount])"] = newStr partCount += 1 } parsedResult.append(tempDictionary) } //MARK: - Writing to plist var dict : NSMutableDictionary = NSMutableDictionary(contentsOfFile: plistFile)! var entryCount : Int = 0 dict.setValue(parsedResult, forKey: "Kext List") dict.write(toFile: plistFile, atomically: false)
Configuring Login
#!/bin/bash #Author : Arun Patwardhan #Date : 24th January 2020 #Contact : arun@amaranthine.co.in #Website : https://www.amaranthine.in #Scope : This script configures the login settings for a Mac. #Arguments #argument 1 : Username #argument 2 : Password #argument 3 : Message to be displayed on login screen #argument 4 : User whose autologin is to be disabled #NOTE : This script must be run as sudo. #DISCLAIMER : The author of this script provides it on an as is basis. The author is not repsonsible for any damages, loss of data or any other issue that may occur with # the use of this script. The user of this script must take due care to validate the script before use. #WARNING : Use caution while running scripts as root. #################################################################################################### #################################################################################################### # VALUE FORMAT FOR THE ARGUMENTS # USERNAME : All lower case, one word. This is the administrator user account username. # PASSWORD : Should be a single word. This is the administrator user account password. # MESSAGE : Can contain multiple words in a single line within quotes. For example, "This Mac belongs to Admin." # USER NAME : All lower case, one word. This is the username of the user account whose auto login is to be disabled. # # SAMPLE USAGE # sudo ./configureLogin.sh <USERNAME> <PASSWORD> <MESSAGE> <USER> # sudo ./configureLogin.sh ladmin ladminpwd "This is a login window message" student #################################################################################################### #################################################################################################### #Variables USERNAME="" PASSWORD="" LOGFILE="/Users/Shared/configureLogin.log" MESSAGE="" USERTODISABLE="" #1. Check to see if the script is being run as root if [[ $EUID -ne 0 ]]; then echo "The script must be run as root." exit 1 fi #2. Assign values to variables USERNAME=$1 PASSWORD=$2 MESSAGE=$3 USERTODISABLE=$4 #3. Check to see if all the arguments are passed if [[ $USERNAME == "" || $PASSWORD == "" || $MESSAGE == "" || $USERTODISABLE == "" ]]; then echo "ERROR: Incorrect use of command. Please make sure all the arguments are passed in." echo "sudo ./configureLogin.sh <USERNAME> <PASSWORD> <MESSAGE> <USER>" echo "For Example" echo "sudo ./configureLogin.sh ladmin ladminpwd \"This is a login window message\" student" echo "Warning: Please make sure that the login window message is less than 3 lines." exit 1 fi #4. Check to see if the log file exists if [[ -f $LOGFILE ]] then echo "$(date "+DATE: %Y-%m-%d%TIME: %H:%M:%S") File exists" >> $LOGFILE else cd /Users/Shared/ touch configureLogin.log echo "$(date "+DATE: %Y-%m-%d%TIME: %H:%M:%S") Created Folder" >> $LOGFILE fi #LOGIN WINDOW MESSAGE --------------------------------------------- defaults write /Library/Preferences/com.apple.loginwindow LoginwindowText $MESSAGE #DISABLE AUTOLOGIN ------------------------------------------------- #Check to see if the user exists if [[ $USERTODISABLE != `dscl . -list /Users UniqueID | awk '{print $1}' | grep -w $USERNAME` ]]; then echo "The User does not exist. Please check the username" exit 0 fi #check to see if there is any autologin configured for a given user PRECONFIGUREDUSER=$(defaults read /Library/Preferences/com.apple.loginwindow autoLoginUser) if [[ $PRECONFIGUREDUSER != "" && $PRECONFIGUREDUSER == $USERTODISABLE ]]; then defaults delete /Library/Preferences/com.apple.loginwindow autoLoginUser $USERTODISABLE echo "$(date "+DATE: %Y-%m-%d%TIME: %H:%M:%S") $USERTODISABLE autoLogin disabled" >> $LOGFILE else echo "$(date "+DATE: %Y-%m-%d%TIME: %H:%M:%S") Auto login not configured or configured for another user." >> $LOGFILE" fi #SHOW MORE DETAILS ------------------------------------------------ #To view the values in the login window simply click on the clock in the upper right hand corner to cycle through the values below. defaults write /Library/Preferences/com.apple.loginwindow.plist AdminHostInfo SystemVersion defaults write /Library/Preferences/com.apple.loginwindow.plist AdminHostInfo SystemBuild defaults write /Library/Preferences/com.apple.loginwindow.plist AdminHostInfo SerialNumber defaults write /Library/Preferences/com.apple.loginwindow.plist AdminHostInfo DSStatus #DISABLE SHUTDOWN, SLEEP, & RESTART BUTTONS defaults write /Library/Preferences/com.apple.loginwindow ShutDownDisabled -bool true defaults write /Library/Preferences/com.apple.loginwindow RestartDisabled -bool true defaults write /Library/Preferences/com.apple.loginwindow SleepDisabled -bool true
Pingback: List of macOS Terminal commands | Arun Patwardhan's Blog
Here is another article for your reference: https://arunpatwardhan.com/2020/07/29/list-of-macos-terminal-commands/