You may be wondering why this post had a password lock on it. That was for the purposes of responsible disclosure to certain people I know at Jamf Software.
TL;DR : 1) Encrypted Strings is not as secure as most people think and a false sense of security is quite high. 2) There are other ways that should be investigated on a product front. These have already been suggested to Jamf.
I’ve been mulling on this topic for some time. A combination of my forthcoming talk at London Apple Admins on April 12th plus my recent experiences on the Jamf 400 course and other work that I did a year ago have made me realise it’s time to address encryption practice on macOS.
Let’s start with some Collins English Dictionary definitions first, just so we’re all on the same page.
Obfuscation is the act or an instance of making something obscure, dark, or difficult to understand.
Encryption is the conversion of data into a form that cannot be easily understood by an unauthorized person, and is important to make electronic transactions secure.
Now with the definitions out of the way, let’s provide some background to what i’m on about.
Back in 1995, I got my first real taste of the internet as-was. I was lucky enough to be part of a school exchange to Pace Academy in Atlanta, Georgia. There were many firsts on that trip: first visit to the USA (threw “tea” in Boston Harbour from the ship), first taste of life abroad, first encounter with encryption.
You see back then, the US Government considered strong crypto to be a “munition” and covered under ITAR rules. 40bit keys were considered good enough for the rest of the world, and occasionally you saw 128bit keys used. That was until Philip Zimmerman in 1991 wrote Pretty Good Privacy or PGP as it became better known. Strong crypto for everyone. Big legal problems for him, thankfully resolved after several years. I was able with my first ever real internet access to get access to the PGP sources.
(btw that’s all I got access to. I eventually got the international version of PGP a year or so later and quit trying to use it around ’97)
The part that stuck with me was this section I’ve paraphrased and shortened from PGPDOC1.TXT included in the v2.6.3 zip file. Mr. Zimmerman talks about crypto and implementation.
Anyone who thinks they have devised an unbreakable encryption scheme either is an incredibly rare genius or is naive and inexperienced …
I remember a conversation with Brian Snow, a highly placed senior cryptographer with the NSA. He said he would never trust an encryption algorithm designed by someone who had not “earned their bones” by first spending a lot of time cracking codes. That did make a lot of sense. I observed that practically no one in the commercial world of cryptography qualified under this criterion. “Yes”, he said with a self assured smile, “And that makes our job at NSA so much easier.”A chilling thought. I didn’t qualify either.
Trust me, neither do I and thus we get to the meat of this post.
https://github.com/jamf/Encrypted-Script-Parameters
This thing is now part of the Jamf 400 course … and it annoys me that it is because this is obfuscation NOT encryption! It’s use is also mandatory …
Now let me explain why. (and yes that also means I have issue with the project name too)
When you command Jamf Pro to run a script, the following items happen (very simplified):
- The jamf binary checks into the JPS server and receives tasks.
- The script is downloaded to the target Mac into Jamf Downloads folder
- Jamf binary then runs the script with any parameters that need to be passed to it
- Upon completion, the script is then deleted from the Downloads folder.
- Jamf binary reports back to JPS at the conclusion of the task(s).
As as administrator, you can pass information to the script you’re calling from inside the GUI. Jamf reserves the first three parameters for information you might want, but the rest is user defined. The result is that the jamf binary is running the script like this:
/Library/Application Support/Jamf/Downloads/script.sh "/" "computer name" "username" "parameter4"
Now Jamf’s own git states that “Without access to both the policy and the script, the strings cannot be decrypted and used”. The issue is it’s not too difficult to do.
You can list all running processes in a Unix terminal window with the “ps” command. Using ps -ax we can see all processes for all users in all sessions. Doing so while the jamf binary is executing a command, you’ll get something like this:
38250 ttys001 0:00.00 /bin/bash ./script.sh / computername richardpurves jamfsuperadmin jamf1234
BTW: This is an EXCELLENT reason for NOT putting raw passwords in the GUI parameter fields!
So you’re probably thinking what’s wrong with the Encrypted Parameters github?
Encrypted Parameters is based on three elements: A passphrase, a salt and an encrypted string. It’s beyond the scope of this article to explain what these three all are but the end result is that you feed all three into a function and you get plain text at the other end.
Jamf’s recommended practice (that I’m aware of) is that two of the three elements should be supplied to the script via parameters, with the third item being contained within the script itself. “Without access to both the policy and the script, the strings cannot be decrypted and used.”
More background: circa 2017 when I was doing large security type things for a high security organisation, I was investigating Encrypted Parameters as a way of protecting Jamf Pro API credentials. I wasn’t happy with the amount of maintenance it was going to require to deal with regular service account password changes across multiple scripts, so I thought about baking in some/all of these details into a config profile. Change the password, change the profile, it auto pushes to all devices.
The problem was that the more I investigated, the more I realised the entire concept is a delaying action and nothing more. Any determined attacker will be collecting all the info they can get. You’ve slowed them down, and if you know a bit about Jamf’s workings then you’ve slowed yourself down more than the attacker.
Here’s the concept to break Encrypted Parameters as I have zero intent to actually build it.
- Create a LaunchDaemon to WatchPath the Jamf downloads folder
- The LaunchDaemon needs to run a script as soon as any change occurs
- The script needs to copy any script it finds out of that folder to somewhere more secure
- At the same time, it needs to capture the output of “ps -ax” to a file for later analysis.
You now have all the pieces to the puzzle as the decryption code will be inside the script alongside the three elements!
So to reaffirm earlier, a determined attacker will only be slowed down by utilising Encrypted Parameters but they WILL NOT be stopped. You could bake the credentials into the script but a simple capture will give those up. Passing credentials via parameters shows it all in plain text to anyone looking at running process list.
There is another way but requires some effort from Jamf on redoing the way they execute scripts. I’ll be discussing this in more depth at the April 12th 2019 London Apple Admins meetup. Tickets still available, live stream probably available.
Unix implemented an early form of IPC (internal process communication) called a “named pipe” , also known as a FIFO “First In First Out” and it’s something I’ve used for other reasons. Usually cocoaDialog.
Here’s what the Jamf binary “could” be doing instead:
- The jamf binary checks into the JPS server and receives tasks.
- The script is downloaded to the target Mac into Jamf Downloads folder
- Jamf binary sets up a named pipe specific to the script.
- The parameters are then passed to the pipe.
- The downloaded script is then called using a redirection from the named pipe
- Upon completion, the script is then deleted from the Downloads folder.
- The named pipe file is then also deleted.
- Jamf binary reports back to JPS at the conclusion of the task(s).
“Named Pipes” have the advantage that while they look like data is passing through a file on the filesystem, they are not. The data is actually passing though a custom unix stream similar to STDIN / STDOUT / STDERR and as a result is not cached on the OS or even stored on the filesystem.
Want to know more? Well http://www.tldp.org/LDP/lpg/node15.html is a good place to start. My presentation at LAA will also be useful too.
On an unrelated note, WordPress 5 has now completely broken my ability to put inline code into this blog due to it’s incredibly annoying habit of inserting HTML code right where it isn’t wanted. Until I rectify this (or more likely dump WordPress), I’ll not be able to include code samples from this point on. I’m also incredibly unhappy at what the code block actually does and the amount of whitespace it leaves.