Tag Archives: Security

Contactless Check-In: A Security Nightmare

IT security is always a big deal. We’ve heard of a lot of data breaches, and all sorts of different attacks (e.g. phishing, ransomware, etc) over the years. A security incident can cost a company its reputation and threaten its survival. But how much worse is it when IT security puts the very safety of your home at risk?

Contactless Check-In: Intro

Over the past year or so, I’ve stayed at some apartments and hotels in the DACH region that were “contactless”. They had no reception; they send you a code and you let yourself in. I’m not sure whether this practice was popularised by the COVID19 pandemic or was already well in force earlier, but I do understand the appeal:

  • It minimises the risk of catching contagious virus for both staff and guests
  • It reduces expenses for the company by not needing to pay reception staff

However, it also has some serious flaws:

  • If there’s any problem with the accommodation, it’s a huge hassle to get someone to fix it.
  • Even worse, if the entry code doesn’t work for whatever reason, you’re basically screwed.
  • Still worse, having an entry code sitting in your mailbox is a security accident waiting to happen.

Let’s talk a bit more about that third point.

Don’t Send Passwords via Email

If you work in IT or have at least a basic understanding of the internet, it should be common knowledge at this point that sending passwords via email is a bad idea. Email is not a secure channel; each email message can go through a number of devices and servers, unencrypted by default, and can be compromised at any point during that journey.

That’s why every bank seems to invent its own secure messaging mechanism. They have to deal with enough fraud and security incidents already, and email is a relatively easy attack vector. And yet, I’ve written about cases of passwords being sent by email in the past, e.g. “The Shameful Web of April 2017 (Part 1)“, “The Pitiful State of the Web in May 2017 (Part 2)“.

Beyond the danger of being intercepted in transit, a bigger problem with email is that it can stick around for a long time. So if you have an email that contains a password, someone could obtain illegal access to your email on a server or on one of your own devices at some point in the future and, unless you’ve been diligently changing your passwords regularly, would still be able to use that password nefariously.

Nowadays, when you sign up for a new account, the best practice is for the service to send you a limited-time activation link that then lets you choose your own password via their web interface (securely over HTTPS, of course). It’s still risky, but there is a limited time window so an attacker would have to gain access to that email in the short time before the link either is consumed or expires. Using multi-factor authentication further reduces the risk considerably.

Contactless Check-In: Codes

If it’s so risky to send a password via email, how much worse is it to send a code that gives access to your hotel room or apartment?

There are a couple of places I’ve been to that send you a code for either the apartment or a key box that is valid for the first day. When you arrive, you use that code and get a key, which you then have to use for the remainder of your stay. This is similar to sending an activation link via email, so there’s a limited time window for an attacker. But I’d argue that the risk of someone getting into your room or apartment and robbing you is much higher than some prankster setting your Facebook profile picture to that of a horse, so I don’t think this approach is acceptable.

It gets worse. Vision Apartments send you a code that remains active for the duration of your stay (potentially several weeks or months), is the only way to access your ‘apartment’, and gives access to the front door of the building, your ‘apartment’, and your mailbox. That code remains active and is available to Vision’s staff as well as potentially anyone who gains access to your email during the entire duration of your stay.

  • Did you accidentally forward the email to the authorities? Oops. They technically now have access to your ‘apartment’.
  • Did you leave your home laptop or mobile phone unprotected while guests were around? Not great either.
  • Did you accidentally fall for a social engineering scam and reveal your email password?
  • Did someone brute force your email account’s password?
  • Did someone intercept the email on one of the servers it went through while it was being sent?

Some of the above cases might sound stupid, but people do fall for scams all the time, and they are subject to identity theft, fraud, and other crimes. That’s bad enough. You wouldn’t want to leave your house keys hanging where anyone can just pick them up.

Would you leave your keys outside the front door like this? (Image source)

If someone manages to get hold of that email and code, they basically have control over your living space, your physical mail, your belongings, and your life. That’s pretty scary.

Note: I’ve already mentioned in “Surviving in Canton Zurich” that I had a terrible experience with Vision Apartments. The security aspect is one of many things that bothered me, and it would take a whole long article just to explain all of them. If you’re considering staying with Vision, do yourself a favour and don’t, or at least read some reviews first.


Whatever the reason behind contactless check-in, it’s a terrible idea. It’s both bad service and bad security. In fact, it’s a security accident waiting to happen. It might also possibly be in breach of data protection laws.

It’s not worth the risk. So before you stay at an accommodation, always make sure they do actually have a reception.

Getting Started with Cartography for AWS

I have recently been working with Cartography. This tool is great for taking stock of your infrastructural and security assets, visualising them, and running security audits. However, getting it to work the first time is more painful than it needs to be. Through this article, I hope to make it less painful for other people checking out Cartography for the first time.

What is Cartography?

Cartography is a tool that can explore cloud and Software as a Service (SaaS) providers (such as AWS, Azure, GCP, GitHub, Okta and others), gather metadata about them, and store it in a Neo4j graph database. Once in Neo4j, the data can be queried using the Cypher language and the results can be visualised. This is extremely useful to understand the relationship between different infrastructural and security assets, which can sometimes reveal security flaws that need to be addressed.

Cartography is written in Python and maintained by Lyft. Sacha Faust’s “Automating Security Visibility and Democratization” 30-minute talk at BSidesSF 2019 serves as a great intro to Cartography, and also illustrates several of the early data relationships it collected.

Good to Know

Before we dive into setting up Cartography and its dependencies, I want to point out some issues I ran into, in order to minimise frustration.

[Update 8th July 2023: all issues in this section have by now been fixed, so you can skip this section. You can use a newer version of Neo4j now, although the rest of the article still uses Neo4j 3.5 for historical reasons.]

The biggest of these is that Cartography still requires the outdated Neo4j 3.5, which was planned to reach its end-of-life on 28th November 2021. Although a pull request for migration to Neo4j 4.4 was contributed on 30th January 2021, the Lyft team completely missed this deadline. Fortunately, support for Neo4j 3.5 was extended to 27th May 2022. Although the maintainers are planning to migrate to migrate to a newer Neo4j version by then, I’m not holding my breath.

This worries me for a number of reasons:

  1. If Neo4j 3.5 reaches end of life before Cartography have migrated to a more recent version, it means people using Cartography would need to run an unsupported version of Neo4j. This could be a security risk, which is ironic given that Cartography is a tool used for security.
  2. It gives the feeling that Cartography is not very well-maintained, if issues as important as this take well over a year to resolve.
  3. It makes it virtually impossible to run Cartography on a Mac with one of the newer Apple M1 CPUs. That’s because Neo4j 3.5 won’t run on an arm64 processor (e.g. Neo4j Docker images for this architecture started to appear only since 4.4), but also because a Python cryptography dependency needs to be upgraded.

So if you feel you need to depend on Cartography, it might make sense to fork it and maintain it yourself. Upgrading it to support Neo4j 4.4 is tedious but not extremely complicated, and mostly is a matter of updating Cypher queries to use the new parameter syntax as explained in the aforementioned pull request.

Another problem I ran into (and reported) is that Cartography gets much more EBS snapshot data than necessary. This bloats the Neo4j database with orders of magnitude of unnecessary data, and makes the already slow process of data collection take several minutes longer than it needs to.

Setting Up Neo4j

For now, we’ll have to stick with Neo4j 3.5. You can follow the Cartography Installation documentation to set up a local Neo4j instance, but it’s actually much easier to just run a Docker container. In fact, all you need is to run the following command:

sudo docker run -p 7474:7474 -p 7473:7473 -p 7687:7687 neo4j:3.5

Like this, you can avoid bloating your system with dependencies like Java, and just manage the container instead. Depending on the operating system, you use, you may need to keep or drop the sudo command. You’ll also need to mount a volume (not shown here) if you want the data to survive container restarts.

Running a Neo4j 3.5 Docker container.

Once Neo4j 3.5 is running, you can access the Neo4j Browser at localhost:7474:

The Neo4j Browser’s login screen.

Login with the default credentials, i.e. with “neo4j” as both username and password. You will then be prompted to change your password:

Changing password in the Neo4j Browser.

Go ahead and change the password. This is necessary because Cartography would not otherwise be able to connect to Neo4j using the default credentials.

The Neo4j Browser’s dashboard after changing password.

Setting Up a SecurityAudit User in AWS

Cartography can be used to map out several different services, but here we’ll use AWS. To retrieve AWS data, we’ll need to set up a user with a SecurityAudit policy.

Log into the AWS Console, then go into the IAM service, and finally select “Users” on the left. Click the “Add users” button on the right.

Once in IAM, select “Users” on the left, and then click “Add users” on the right.

In the next screen, enter a name for the user, and choose “Access key – Programmatic access” as the AWS credential type, then click the “Next: Permissions” button at the bottom-right.

Enter a username, then choose Programmatic access before proceeding.

In the Permissions screen, select “Attach existing policies directly” (an arguable practice, but for now it will suffice). Use the search input to quickly filter the list of policies until you can see “SecurityAudit”, then click the checkbox next to it, and finally click the “Next: Tags” button at the bottom-right to proceed.

Attach the “SecurityAudit” policy directly to the new user.

There is nothing more to do, so just click on the remaining “Next” buttons and create the user. At this point you are given the new user’s Access key ID and Secret access key. Grab hold of them and keep them in a safe place. We’ll use them shortly.

Now that we have a user with the right permissions, all we need to do us set up the necessary AWS configuration locally, so that Cartography can use that user to inspect the AWS account. This is quite simple and is covered in the AWS Configuration and credential file settings documentation.

First, create a file at ~/.aws/credentials, and then add the Access key ID and Secret access key you just obtained, as follows (replacing the placeholder values):


Then, create another file at ~/.aws/config, and add the basic configuration as follows. I’m not sure whether the region actually makes a difference, since Cartography will in fact inspect all regions for many services that can be deployed in multiple regions.


That’s it! Let’s run Cartography.

Running Cartography

Run the following command to install Cartography:

pip3 install cartography

Then, run Cartography itself:

cartography --neo4j-uri bolt://localhost:7687 --neo4j-password-prompt --neo4j-user neo4j

Enter the Neo4j password you set earlier (i.e. not the default one) when prompted.

Cartography should now run, collecting data from AWS, adding it to Neo4j, and writing output as it works. It takes a while, even for a brand new AWS account.

Querying the Graph

Once Cartography finishes running, go back to the Neo4j Browser at http://localhost:7474/browser/ . You can now write Cypher queries to analyse the data collected by Cartography.

If you haven’t used Cypher before, check out my articles “First Steps with RedisGraph” and “Family Tree with RedisGraph“, as well as my RedisConf 2020 talk “A Practical Introduction to RedisGraph“. RedisGraph is another graph database that uses the same Cypher query language, and these resources should allow you to ramp up quickly.

You might not know what Cartography data to look for initially, but you can always start with a simple MATCH query, and as you type “AWS” as a node type in a partial query (e.g. “MATCH (x:AWS“), Neo4j will suggest types from the ones it knows about. You can also consult the AWS Schema documentation, as well as the aforementioned “Automating Security Visibility and Democratization” talk which illustrates some of these types and their relationships in handy diagrams.

Let’s take a look at a few simple examples around IAM to ease you in.

Example 1: Get All Principals

MATCH (u:AWSPrincipal)

In AWS, a “principal” is an umbrella term for anything that can make a request, including users, groups, roles, and the special root user. Although this is a very basic query, you’ll be surprised by what it returns, including some special internal AWS roles.

Example 2: Get Users with Policies

MATCH (u:AWSUser)-[:POLICY]->(p:AWSPolicy)

This query gets users and their policies via the POLICY relationship. Due to the nature of the query, it won’t return users that don’t have any directly attached policies. In this case all I’ve got is the cartography user I created earlier, but you can see the connection to the SecurityAudit policy.

The cartography user is linked to the SecurityAudit policy.

Example 3: Get Policy Statements for Principals

MATCH (a:AWSPrincipal)-->(p:AWSPolicy)-[:STATEMENT]->(s)
RETURN a, p, s

Cartography parses the statements in AWS policies, so if you inspect a node of type AWSPolicy, you can actually see what resources it provides access to. This query shows the relationship between principals (again, this means users, groups, etc) and the details of the policies attached directly to them.

It is possible to refine this query further to include indirectly assigned policies (e.g. to see what permissions a user has via a group it belongs to), or to look for specific permissions (e.g. whether a principal has access to iam:*).

Results of a Cypher query linking AWS principals to the policy statements that apply to them, via AWS policies.

Wrapping Up

As you can see, Cartography takes a bit of effort to set up and has some caveats, but it’s otherwise a fantastic tool to gather data about your resources into Neo4j for further analysis.

Enabling and Enforcing HTTPS on a Subdomain with cPanel

Nowadays, there’s really no excuse not to enable HTTPS on a website, even a small personal one. It’s free and simple. In fact, chances are that whatever host you’re using offers a simple option you can just turn on. In this article, we’ll see how to set this up in cPanel, which is commonly used in Linux/PHP/MySQL web hosting services.

Set up the Subdomain

Subdomains service in cPanel

If you haven’t already, create a subdomain. To do this:

  1. Locate the Subdomains service in cPanel.
  2. Enter a name for the subdomain.
  3. Enter a path to a folder to be used as the document root for the subdomain.
  4. Click the Create button.

Enable HTTPS on the Subdomain

Let’s Encrypt™ SSL service in cPanel

New subdomains will by default run on HTTP, which is insecure. Enabling HTTPS requires an SSL or TLS certificate. To set this up:

  1. Locate the Let’s Encrypt™ SSL service in cPanel.
  2. Scroll towards the bottom of the page, and page through your subdomains until you locate the new one you want to apply HTTPS to.
  3. Click on the Issue action link next to it.
  4. Leave the settings as they are and click on the Issue button.

Enforce HTTPS on the Subdomain

Domains service in cPanel

Enabling HTTPS is only half good if people can still access the site insecurely over HTTP. It’s very easy to automatically redirect people from the HTTP endpoint to HTTPS. To do this:

  1. Locate the Domains service in cPanel.
  2. Locate the new subdomain, which may be on a different page.
  3. Turn on the switch in the Force HTTPS Redirect column.
  4. A success message should confirm that it’s been enabled.

Test the Subdomain

The subdomain is secure and running on HTTPS

To make sure everything is set up correctly, use a browser to ensure that the website at your subdomain is secure.

  1. Wait a few seconds. The redirect you just enabled might not kick in right away.
  2. Use an incognito session in your browser. Otherwise, if you visited the subdomain before enabling the redirect, it’s possible that the browser might still show it as insecure.
  3. Access your domain with the URL starting with https://. Ensure that your browser displays the padlock icon and reports the connection as secure.
  4. Access your domain with the URL starting with http://. Once the page loads, ensure that you are now on https:// and that the browser displays the padlock icon and reports the connection as secure. Optionally, you can also open your browser’s dev tools, switch to the Network tab, and observe a 301 redirect request.


As you can see, it’s super easy to get HTTPS working on a subdomain in cPanel. Just enable HTTPS for the subdomain, force the HTTPS redirect, and you’re done.

Securing PowerShellGet on a Windows EC2 Instance

I’ve been doing some work with security on AWS recently, and part of that involved running security assessments using Amazon Inspector to identify vulnerabilities at network and host level.

If I launch a fresh EC2 instance right now using the Microsoft Windows Server 2019 Base AMI and run a host-level assessment, the report lists a vulnerability related to the PowerShellGet module:

Microsoft Security Response Center’s entry about this vulnerability explains a little more about it:

“A security feature bypass vulnerability exists in the PowerShellGet V2 module. An attacker who successfully exploited this vulnerability could bypass WDAC (Windows Defender Application Control) policy and execute arbitrary code on a policy locked-down machine.

“An attacker must have administrator privileges to create a configuration that includes installing PowerShellGet V2 module onto a machine from the PowerShell Gallery. The WDAC policy must be configured to allow the module to run. After this is done, PowerShell script can be injected and run fully trusted, allowing the attacker arbitrary code execution on the machine.”

— CVE-2020-16886 at MSRC

The same page says that this vulnerability was fixed in PowerShellGet v. 2.2.5. So why do we have this problem? Here’s why:

PS C:\Users\Administrator> Get-Module PowerShellGet -ListAvailable

    Directory: C:\Program Files\WindowsPowerShell\Modules

ModuleType Version    Name                                ExportedCommands
---------- -------    ----                                ----------------
Script    PowerShellGet                       {Install-Module, Find-Module, Save-Module, Upda...

PS C:\Users\Administrator>

That AMI came with PowerShellGet, but we need version 2.2.5. We can install it by running a Powershell session in Administrator mode, and running the following commands (from the Installing PowershellGet documentation) and agreeing to install the NuGet provider:

Install-Module -Name PowerShellGet -Force
Update-Module -Name PowerShellGet

This results in the new 2.2.5 version being installed alongside the older one:

A Powershell session showing how we started with PowerShellGet, installed a more recent version, and now have the new 2.2.5 version alongside the old one.

I don’t know enough to be able to say whether having that version around still poses any kind of risk, but it seems to be enough for Amazon Inspector which no longer reports any vulnerability after installing version 2.2.5:

If you’re really paranoid, check out this Stack Overflow question for ways to get rid of the old version manually. I haven’t actually tried this, so be careful.

Removing the Server Header in ASP .NET Core

There are many aspects to web security, but in this article we’ll focus on one in particular. Attackers can use any available information about a target web application to their advantage. Therefore, if your web application is sending out headers revealing the underlying infrastructure of your web application, attackers can use those details to narrow down their attack and attempt to exploit vulnerabilities in that particular software.

Let’s create a new ASP .NET Core web application to see what is returned in the headers by default:

mkdir dotnet-server-header
dotnet new web
dotnet run

This creates a “Hello world” ASP .NET Core application using the “ASP .NET Core Empty” template, and runs it. By default it runs on Kestrel on port 5000. If we access it in a browser and check the response headers (e.g. using the Network tab of the Chrome Developer Tools), we see that there’s this Server header with a value of Kestrel. If it were running under IIS, this value might have been MicrosoftIIS/10.0 instead.

Honestly, this could be worse. Older versions of ASP .NET running on the old .NET Framework used to add X-Powered-By, X-AspNet-Version and X-AspNet-MvcVersion headers with very specific information about the underlying software. While this information can be really useful for statistical purposes (e.g. to identify the most popular web servers, or to identify how prevalent different versions of ASP .NET are), they are also very useful for malicious purposes (e.g. to look for known vulnerabilities in a specific ASP .NET version).

ASP .NET Core, on the other hand, only adds the Server header, which is quite broad. However, the less information we give a potential attacker, the better for us.

There is no harm in removing the Server header, and to do this in ASP .NET Core, we can take a tip from this Stack Overflow answer:

        public static IHostBuilder CreateHostBuilder(string[] args) =>
                .ConfigureWebHostDefaults(webBuilder =>
                              .UseKestrel(options => options.AddServerHeader = false);

The highlighted line above, added to Program.cs, has the effect of getting rid of that Server header. In fact, if we dotnet run again now, we find that it is gone:

Update 27th July 2020: Just to clarify, this removes the Server header coming from Kestrel. However, if you use other software (e.g. IIS) to host your web application, you will need to take additional steps to remove it from there as well.

It is always a good idea to do a vulnerability assessment of your web application, and in doing so, remove any excess information that complete strangers do not need to know. What we have seen here is a very small change that can reduce the security risk at least by a little.