Metasys ADS/ADX/NAE Login Authentication Bypass

I wanted to provide a write up of my research relating to the security vulnerabilities Johnson Controls published on August 15th in order to clear up some confusion and better describe the actual attack chain. These vulns has been assigned CVE-2019-7593 and 7594. Also tracked under the DHS ICSA number ICSA-19-227-01. I recommend reading the official notification provided by Johnson Controls here also (PDF).

First, a bit of housekeeping. This research was conducted by me alone and is not in anyway associated with my employer. The conclusions, opinions and views expressed here are mine and do not reflect those of my employer or any other group. All research was conducted on equipment I had authorization to access. At no time were any systems or cloud services I did not have authorization to access involved in this research.

Second, some history. I began looking into the Metasys around November of 2018. My original goal was to investigate whether I could convince the NAE to load a modified software image. As I started looking into the process the Metasys UI and the target system interact, my attention shifted to the login procedure and how it was secured. I disclosed my findings to the Johnson Controls security team around May of 2019. My findings were accepted and a 90 day embargo was requested to put the appropriate notice together etc. I found the JCI security team to be perfectly reasonable in their requests and professional in their dealings with me.

Now on to the fun stuff. I’ll explain briefly how the Metasys login process works, followed by a description of the 7593 and 7594 vulns and finally a proof of concept of how I exploit these vulns into an attack. It’s important to be familiar with how RSA public/private key encryption works. This information is relevant for Metasys version 9 and below only. Anything newer then that, your guess is as good as mine.

Metasys Login Process

The Metasys UI is a Java application (which I’ll refer to as the Client) that is downloaded directly from either the ADX, ADS or NAE (the Server) being connected to. Whether this is done directly or through the JCI Launcher is inconsequential. When the Java app is started, there is a process of initialization and initial resource loading. During that time the Client requests the Server’s public RSA key. Once the initialization is complete, the Client prompts the user for a username and password.

getKey
HTTP Post request to Server requesting RSA public key

The password is hashed (using SHA1) and a credential package is constructed using the plaintext username and hashed password. This credential package is then encrypted using RC2. The encryption key for the RC2 payload is encrypted using the Server’s RSA public key. This forms the completed payload which is sent to the Server using an HTTP POST request.

login
Login request sent to Server

I’m assuming at this point the Server decrypts the RC2 encryption key using its RSA private key, then decrypts the username / password with the RC2 key. The Server will compare the hash and username to a security file containing a list of valid users. If the login credentials are valid, the Server will respond with a Session Token encrypted with the same RC2 encryption key.

successful
Server sending successful login response with Security Token

All subsequent requests between the Client and Server are accompanied by the same encrypted Session Token. Without a valid Session Token, requests are rejected.

Vulnerabilities

Common RSA Keys CVE-2019-7593

As described above in the login process, it’s simple to request the public RSA key from the Server using a simple POST request. Ideally, the RSA keys should be unique for each Metasys device. However I was able to test 10 NAE, NCE and ADX devices and found they all returned the same RSA public key. Therefore the RSA key pairs seem to be common among these devices. If the RSA private key is compromised on one device, it is in effect compromised on all of these devices. An analogy to this would be having all cars of the same make/model being keyed with the same ignition key. This is not ideal. However due to the next vulnerability, this turns out to be pointless anyway.

Hardcoded RC2 Encryption Key CVE-2019-7594

The Metasys UI doesn’t seem to randomly generate the RC2 encryption key used to encrypt the login credentials and other sensitive information. The key is hardcoded in the Java application, which is downloaded to the users computer. It’s very simple to decompile the Java application using something like the Java-Decompiler (which is an awesome tool) and located the hardcoded RC2 encryption key. The fact that the RC2 key is hardcoded, easily available to the user and never changes renders the use of RSA public/private key encryption useless. This is because the RSA key is used to encrypt the RC2 key only, but we already know the RC2 key so we can skip the RSA problem entirely.

decrypt login creds
Decrypting captured login credentials using fixed RC2 key

Other Vulns

The acute reader will notice the hashing algorithm used for the password is problematic. SHA1 is known to be a cryptographically weak algorithm that is routinely broken. I have made liberal use of Crackstation in the past, which has proven very effective against SHA1 password hashes. However as I’ll show in the attack chain below, you don’t need to decode the SHA1 hash. Also, these hashes are not salted.

Cracking the base64 decoded password from above.

Exploit

The exploit I used in this case is essentially a replay attack. Valid encrypted login credentials are captured using your favorite method and then used to login to the BAS system. Normally you cant login using a hash and would need to decode the password. However I can show below that you can replay the hash and login without being able to decode the password.

Capture Login Package

Capturing the valid login session takes a simple Man-In-The-Middle attack. This can be done a number of ways. Compromised router, public wifi, compromising the users computer etc. To simulate a MITM attack I used the fabulous and fantastic Lan Turtle from Hak5. This is a great tool that deserves it’s own post. So without going into detail, the Lan Turtle is acting as a MITM, specifically looking for the login packet and sending the details out to my Command and Control server.

With the encrypted login request in hand, we can use the hardcoded RC2 key to decrypt and recover the plaintext username and hashed password. If the password can be cracked using something like Crackstation, then the job is done. If the password is complex and cant be cracked, there’s one more step to finish the replay attack

Proxy Replay

Obviously you cannot just type the password hash into the login screen and presumably the password is complex enough to resists hash cracking.

My solution to this was to create a proxy relay server that I used to connect to to Metasys. This proxy would relay all traffic between the Client and Server, but would inspect the requests for the login request. When the login request is seen, the Proxy would replace the username/password I entered with the stolen username/password hash. This would be considered valid by the Server and I would be logged in under the stolen user account.

In this example, the Server is at 192.168.1.10, the Client is at 192.168.3.218 and the proxy relay at both 192.168.3.60 & 192.168.10.229.

Proxy Relay Example

The Proxy Relay listens for an incoming connection and relays traffic to the target Server, searching for the login request

Proxy Server replacing login request with captured credentials

In the Wireshark capture below you can see traffic flowing from the Client through the Proxy to the server. Notice the highlighted packets showing the incoming login request and the login request being sent to the Server. Notice the encrypted strings are different, despite using the same encryption keys. This is because the login credentials entered have been replaced by the captured credentials, resulting in a successful login under the compromised user account.

Login credentials being replaced with compromised account

Conclusion

There are few occasions where hardcoded passwords/keys/secrets are a good idea. This is not one of those occasions. It should have been relatively easy for the Java application to randomly generate a new RC2 encryption key with each transmission (sending the key protected by the RSA encryption). Also, I don’t see why the RSA keys have to be common to each device. The RSA keys could be generated when the system is installed, or even on system reboot. These vulnerabilities go to show how important it is to lock down network access to a BAS system, drawing the ring of trust as tight as possible.

Hope this was helpful to anyone reading. If you have questions or would like more information, feel free to contact me.

Note: You’ll notice I’ve neglected to include any actual plaintext keys. This is intentional.

Organizing Memories

So many memories we’ve forgotten

When was the last time you had pictures printed? How many pictures do you have on your phone or tablet? Do you even remember what pictures you have anymore or where they’re from?

My wife’s grandmother passed away 2 years ago. Her grandfather, John, and his wife were prolific picture takers and frequent vacationers. Over their last 5 years or so they had amassed several thousand pictures on various devices. Most of these were on two iPad’s, the balance being spread across a few CDs and usb flash drives.

So the problem was presented by the family to me. We have all these pictures, we don’t know what is a duplicate of what, we don’t know what’s on these drives or the ipads but we need it all organized in a single folder on a new laptop. The intent was for John to be able to view and curate these pictures on a laptop (that I would purchase and set ip), which was something he was struggling with on the ipad.

In a very rare act of taking the high road, I’ll skip my usual hate rant for Apple products, their apparent hatred for their user base, and their obvious goal to frustrate those of use who serve as the family tech support.  Suffice to say that I managed to invoke the right magic, spoke the correct incantations and beckoned the  appropriate powers to get all the pictures off of both ipads and safely onto my machine. We’ll skip the pain and move on.

All told, I now had around 2600 pictures to work with and I had two objectives in mind.

  1. Eliminate any duplicates in this collection of pictures
  2. Sort this collection of pictures in to a folder structure for the years and months the pictures were taken.

Finding Duplicates

This was an interesting problem to solve. I am very sure this wasn’t the most efficient way to solve the issue but it was rather interesting to me. My approach was to read through the various folders for the picture files. For each file, I load the filename, extension and path into a database. I also take an md5 hash of the picture as well as the date the picture was taken as reported in the exif data. These additional data points are also loaded into the database.

For those unaware, an md5 hash is a unique fingerprint of the data within the file, which for my purposes is enough to uniquely identify the file based on its content and not on its file name. Also, exif data is data saved inside a picture file the identifies several properties of the picture such as the camera it was taken on, the camera settings and the date the picture was taken.

From here, weeding out the duplicate pictures was a trivial SQL query to select the unique md5 hashes. Now I thought that was pretty neat. See the code for this first stage below. You can see that I am using exiftool to pull out the exif data. Its a great tool written by Phil Harvey.  Also below is the end result of this script

if [ $1 -z ];
then
echo "Need to include the root directory containing pictures"
exit
fi
if [ $1 = '-h' ];
then
echo "   [-d]:to create duplicate database "
exit
fi</code>

search_dir=$1
#echo $search_dir
first=0
find $search_dir -iname '*' -print0 | while IFS= read -r -d '' entry
do
if [ $first -gt 0 ];
then
filename=$(basename "$entry")
extension="${filename##*.}"
path=$(dirname "$entry")
md5hashString=$(md5sum "$entry")
md5hash=($md5hashString)

imageDate="$(exiftool "$entry" |
grep -m 1 "Date/Time Original" |
sed "s|Date/Time Original : ||g" |
sed "s|:|-|g")"

if [ -z "$imageDate" ];
then imageDate="$(exiftool "$entry" |
grep -m 1 "File Modification Date/Time : " |
sed "s|File Modification Date/Time : ||g" |
sed "s|:|-|g")";
fi;
if [ -z "$imageDate" ];
then
imageDate="1980-01-01"
else
imageDate=($imageDate)
fi

sql="INSERT INTO Pictures (Path,File,Extension,Hash,Date) VALUES ('$path', '$filename', '$extension','${md5hash[0]}','$imageDate')"
mysql -D GGPics -e "$sql"
fi
first=1
done

Picture hashes

Organizing the Final Product

Once I had everything in the database, I made a new table of distinct hashes, essentially weeding out the duplicate files. Next was the organizational step which was rather trivial. For this, I wrote a small python script (again probably not as efficient as it could be) to accomplish the organization. The script reads through the unique table, determines if a folder exists already for the year the picture was take, and the month the picture was taken. It creates the folders as needed and then copies the image into the new structure. Code and results below

oldPath = result[1]
oldFilename = result[2]
oldDate = result[3].strftime(‘%Y-%m-%d’)
oldFile = open(oldPath + "/" + oldFilename, "r")

#see if year folder exists
if not os.path.exists(newLocation + "/" +oldDate.split("-")[0]):
os.makedirs(newLocation + "/" + oldDate.split("-")[0])
month = calendar.month_name[int(oldDate.split("-")[1])]
#see if month file exists
if not os.path.exists(newLocation + "/" + oldDate.split("-")[0] + "/" + month):
os.makedirs(newLocation + "/" + oldDate.split("-")[0] + "/" + month)
if((oldDate.split("-")[0] == "1980") or (oldDate.split("-")[0] == "1900")):
newPath = newLocation + "/" + "UnknownDate" + "/"
filecount = len(os.listdir(newPath))
newFile = open(newPath + str(filecount+1) + ".jpg","w")
else:
newPath = newLocation + "/" + oldDate.split("-")[0] + "/" + month + "/"
if os.path.isfile(newPath + oldDate + ".jpg"):
filecount = len(os.listdir(newPath))
newFile = open(newPath + oldDate + "_" + str(filecount+1) + ".jpg","w")
else:
newFile = open(newPath + oldDate + ".jpg","w")
newFile.write(oldFile.read())
newFile.close()
oldFile.close()
lastID = lastID+1
print newFile.name
print str(lastID) + " of " + str(totalFiles) + " done"
curs.execute("UPDATE DistHash SET Processed=1 WHERE ID=" + str(result[0]))
conn.commit()

At the end I end up with a structure that looks something like this. I don’t have the actual pictures anymore so its showing 0 files but you get the idea.

Picture Structure

All in all, this was a pretty fun project I intend to work on a little more and use for my own organization. My wife is a prolific picture taker and over the years I have multiple backups. So having this type of tool to quickly organize and weed out duplicates is pretty useful.

More importantly, this tool gave me the ability to give something important to John. It let me give him back his memories. So often we leave our memories locked up in our devices. I was pleased to be able to give John access to the pictures he hadn’t seen in a long long time and the memories that are attached to them. It reminded me of how precious and fragile our memories are.

“Daddy, lets build electronics!” – How a book changed my life

This is less an interesting technical blog post and more just a retrospective on my past and what it has given me today.

As long as I can remember I’ve loved electronics, since the first time I took apart a tv remote when I was 12 (much to my fathers unhappiness). Looking at the green epoxy coated circuit board, it made me think I was looking down at a green landscape, resistors and capacitors dotting the scenery like towns and villages. Then I was just an observer discovering new worlds. Eventually in highschool I began learn electronic components and design, to which I am always grateful to Mr.Langil my electronics teacher. Now I felt like a creator of landscapes, not just an observer. I was hungry for knowledge and without the easy access the internet provides us, I turned to books.

Sometime in 2000 I picked up a copy of “Engineer’s Mini Notebook: Timer, OpAmp & Optoelectronics Circuits & Projects” from Radio Shack.  This was the first I had ever seen of this book series  or its incredible author, Forrest Mims. Initially I had been interested in it because I had worked with 555 timers in the past and Op Amps were like a new magical power waiting for me. But after looking at this small book I was captivated by its hand drawn diagrams and notes. There was a romantic, real quality that I couldn’t resist. This wasn’t a text book, this was like a hand written note and treasure map directed to me. I can’t say how many hours I spent with this book or how many of these circuits I built, but this book took me from a dilettante to someone with a real passion to build.

Fast forward through highschool, two rounds through university and a decade and a half in various careers. Through the wonderfully deterministic world of digital electronics, the seductive magic of analog signals, and finally programming and embedded systems where I could finally communicate with something.  Now I spend most of my time writing code and less time building hardware but now and then will still pull out my old kits and put something together.

My 5 year old daughter spent a week this summer at a STEM camp. During that week she built a simple flasher circuit out of conductive play-dough, a battery and an LED. She loved this project and was so excited to show me, knowing her daddy is an engineer. She told me all about how it worked, how the electricity moved through the metal and the dough to make the light work. She wanted to build more and decided that we would build electronics together.

My home office is littered with containers of components, half finished projects and books. I started scrounging around for bits and pieces to put together while my daughter picked through my bookshelves. It may have been the colorful cover that drew her attention but for whatever reason she picked up this same “Engineer’s Mini Notebook” that had caught my attention so long ago. She asked if I had drawn the diagrams and pointed out to me the LED and resistor symbols she had learned.

I would be lying if I said I wasn’t a little emotional seeing her get so excited over this same book that had started me on my journey.

I picked a simple project that would appeal to her and the next day we were down at the local electronics shop to pick up the bits I was missing. An hour of breadboarding later, my daughter learning to use a multimeter to measure capacitors, and we had our first project. She loved it and wouldn’t stop playing with it. Breadboards are temporary and this was a memory I wanted to last. So the next day while she was at school I soldered it up on a prototype board. And here it is, our first Father Daughter project.

First Project

This is the Toy Organ project from page 23 of Forrest Mims’ “Timers, OpAmps & Optoelectronics” entry from the Engineer’s Mini Notebook series. And it still sits on the window sill of my daughters room. Every now and then when she’s in her room I can hear the tones from the circuit.

I can’t express how grateful I am to Mr.Mims and his book series. It played an important role in my life and is now helping me introduce my daughter to the exciting adventure of world building. We’ve already picked the next project to build, maybe one that doesn’t make so much noise this time. I look forward to many weekends spend with this book on one side, and my daughter on the other.