We help top organizations stay competitive, by implementing the latest disruptive technologies.

Latest Posts

Secure Your Mac with a Firmware Password

Secure Your Mac with a Firmware Password

Secure Your Mac with a Firmware Password: A Walkthrough on How to Use an Ivanti Custom Definition to Detect a Missing Firmware Password and Automatically Set If Need Be

Setting a firmware password on your Mac prevents it from starting up from any device other than the startup disk. 

Why do you care about this?

Well, a user account with its associated permissions can only protect a disk, with its associated data, when the operating system for that account is running. Therefore, a stolen Mac without a firmware password set, can be booted to an alternate boot volume (think NetBoot or NetInstall) making all of the data on that Mac is accessible (assuming the hard drive is not encrypted, which it should be, see this previous blog post).

How do you set a firmware password?

Well, there is the manual way of doing things as outlined in the Apple article I linked in the first paragraph.

But we all know if we have to physically touch every machine, the task is not going to be completed. Thankfully, detecting if a firmware password is set and even setting the firmware password can be done via some scripts.

Before we jump into the scripting aspect though, let’s go through the commands we’ll be using. To detect if a Mac has a firmware password set, run the following command in terminal:

sudo /usr/sbin/firmwarepasswd -check

So doing should spit out a response of either:

Password Enabled: Yes 
Password Enabled: No

If the answer is yes, and you’d like to validate you know the set password, run the following command:

sudo /usr/sbin/firmwarepasswd -verify

Hit enter and then provide your sudo password first, if prompted, and then the firmware password. A successful password validation prompt will return the status Correct.

If you make a mistake or want to remove the password set, run the following command:

sudo /usr/sbin/firmwarepasswd -delete 

OK, so now that you know what commands to use, we’ll begin the process to build out our detection and remediation scripts.

Detection Script

The detection script is quite simple will be a good warm up. We’ll create a variable called “check” and pass in the fimrwarepasswd -check command we used above.

We’ll then leverage a simple if / then statement to see if the output matches our expected status of FirmwareEnabled: Yes. If it does not, we’ll detect the machine as vulnerable and echo out the results the Ivanti scanner is expecting.

If you’d like more information on how to build a custom definition, and why we need the Found, Reason, Expected, Detected values, see the section Understanding the Custom Definition from my previous blog post.

For now, open up a text editor and paste in the script below and save it. You can build your custom definition later.


check=$(sudo /usr/sbin/firmwarepasswd -check)
if [[ "$check" != "Password Enabled: Yes" ]]; then    
    echo "Result: Disabled"
    echo "Found: $check."
    echo "Reason: Firmware password not set."
    echo "Expected: A firmware password to be present."
    echo "Detected: 1"
    exit 0
    echo "Result: Enabled"
    echo "Found: $check."
    echo "Reason: Firmware password set."
    echo "Expected: A firmware password to be present."
    echo "Detected: 0"
    exit 0
Remediation Script

The remediation script is a bit more complex, but shouldn’t be too bad. The first reason this script is more involved is simply due to the fact that we need to do some additional validation to see if a password is set. If it is, we need to provide the old password as well as the new password.

Secondly, we need the script to pretend like it is responding to the Terminal GUI on our behalf, so we’ll be writing the script with Expect instead of Bash. If you’re unfamiliar with Expect, Expect is an extension to the Tcl scripting language designed to automate interactions with text in Terminal. We need this to supply our passwords.

By the way, I am not the author of this script. It has been pulled from https://www.jamf.com/jamf-nation/discussions/14172/firmwarepasswd-binary with a number of different authors contributing to its final iteration.

#!/usr/bin/expect -f

spawn firmwarepasswd -check
expect {
    "Password Enabled: No" {
         spawn firmwarepasswd -setpasswd
         expect "Enter new password:"
         send "YourNewPassword\r";
         expect "Re-enter new password:"
         send "YourNewPassword\r";
         expect eof
   "Password Enabled: Yes" { #if password is set - check whether this is a known password
   spawn firmwarepasswd -verify
   expect "Enter password:"
   send "YourCurrentPassword\r"
   expect {
      "Correct" {
         #puts "Correct password identified"
         #  use this part to change a known password
         #spawn firmwarepasswd -setpasswd
         #expect "Enter password:"
         #send "YourCurrentPassword\r";
         #expect "Enter new password:"
         #send "YourNewPassword\r";
         #expect "Re-enter new password:"
         #send "YourNewPasswordd1\r";
       expect eof
      "Incorrect" {
        # puts "Password incorrect"
         exit 1
exit 0

Open a second file in your text editor and copy in the text above. In your script, make sure you replace the YourNewPassword and YourCurrentPassword values, leaving the quotes and the \r. So, for example, if my new firmware password were going to be MyCoolFirmwarePassword my send command in my script would like the following:

send “MyCoolFirmwarePassword\r”;

Save your remediation script as a .sh file when ready.

Transfer Script

Alright, by now you might be thinking you’re ready to build your custom definition. Unfortunately, you’re not quite ready. The remediation engine within Ivanti is not setup to handle a script written in Expect. So, in order to make this work, we’ll need to write a bash script that downloads the expect script, executes the expect scripts, and subsequently deletes it.

So, open a third file in your text editor and paste in the code below.


#File to copy
#change this to match your hosted path, it needs to be http

#Location to copy file to
#change this to match your destination path
destinationLocation=/Library/Application\ Support/LANDesk/sdcache

#Download command
#You shouldn't need to make any changes here
#-noinstall ensure the package does not get executed
#-package is the source url path
#-destdir is the destination url path
/Library/Application\ Support/LANDesk/bin/sdclient -noinstall -package "$filePath/""$fileName" -destdir "$destinationLocation"

#Execute Expect Script
echo "Executing script"
/usr/bin/expect "$destinationLocation"/"$fileName"

#Remove Expect Script
rm -f "$destinationLocation"/"$fileName"

You’ll obviously need to change the filePath and fileName variables, but everything else should be set. Take your expect script above that you saved as a .sh file and copy it to your http file share. Once you’ve done that, update this script with the relevant path and name.

Wrap Up

Now that you’re armed with your three scripts, you’re ready to build your content definition. You’ll want to insert your detection script into the Detect Logic > Custom Script field.

Then, insert your transfer script into the Patch Install Commands area in the Patch Information section.

Again, see the section Understanding the Custom Definition from my previous blog post if you need more details on building a custom definition.

It’s also worth mentioning, that until a reboot takes place, the firmware password will not be in place and running a -check command will still result in a no password set state.


Setting a firmware password is only supported on the following Mac models:

  • MacBook Air (Late 2010 and later)
  • MacBook Pro (Early 2011 and later)
  • MacBook Pro with Retina display (all models)
  • MacBook (Retina, 12-inch, Early 2015)
  • iMac (Mid 2011 and later)
  • Mac mini (Mid 2011 and later)
  • Mac Pro (Late 2013)
No Comments

Post A Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.