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/