XSS Part 4 – How XSS could be used to gain RCE (Remote Code Execution)

In my previous post we showed how XSS can be used to hit endpoints in the context of the logged in user and the damage that could be done with this.

The er great thing about security issues is that whilst they can be bad enough individually they can get really bad when combined together.

In this post I will show a theoretical example using my deliberately vulnerable application hackthecat where we’ll pair XSS with another security issue to end up running arbitrary code on the web server (Remote Code Execution or RCE).

RCE is pretty much as bad as a security issue can get for an application – especially if it’s possible without login details!

Obligatory Warning/Nag

Do not under any circumstances try any of what I’ll discuss here on applications you don’t have permission to. It’s almost certainly illegal and you could/will end up in a lot of trouble..

A much better idea with less jail/police is to use something like my deliberately vulnerable node application that you can download from https://github.com/alexmackey/hackthecat or a machine provided by a service such as https://www.hackthebox.com/.

Previous Posts

This is my 4th post on a series of posts about XSS but if you’ve missed the previous posts here’s a helpful list so you can go back and read them and hopefully they’ll assist you with preventing XSS issues within your applications:

Part 1 – https://blog.simpleisbest.co.uk/2022/02/19/xss-cross-site-scripting-part-1-what-is-xss/

Part 2 – https://blog.simpleisbest.co.uk/2022/04/02/xss-part-2-attack-and-defence/

Part 3 – https://blog.simpleisbest.co.uk/2022/04/25/xss-part-3-session-riding-csp-policies-sameparty-and-samesite/

De-serialization Vulnerability

OK but how could an XSS issue lead to running any old code we like?

We’ll get to that but first I need to introduce you to a well-known deserialization issue in a very old library that is no longer maintained called node-serialize, version 0.4 (scarily at the time of writing npm page says it had nearly 1400 downloads last week which er let’s hope is not in production systems).

Node-Serialize’s purpose in life is surprisingly enough to serialize/de-serialize objects to and from JSON.

It has an interesting feature where it can serialize functions on an object.

Unfortunately it also offers the ability to execute the serialized function during the deserialization process by making an eval call.

This only happens if the functions property name begins with the string “_$$ND_FUNC$$_”. The below screenshot shows how this works (FUNCFLAG is defined as “_$$ND_FUNC$$_” earlier in the code):


This logic means that if we can feed some malicious JSON that ends up in a node-serialize deserialize call then we should be able to get node-serialize to execute it!

Note you can checkout a simple example of this particular issue and write up at https://snyk.io/test/npm/node-serialize and https://www.exploit-db.com/exploits/50036.

Writing our exploit for HackTheCat

It just so happens that HackTheCat has an endpoint that accepts a blob of JSON (I know as I put it there!) and you guessed it uses node-serialize to deserialize it.

In our example application imagine an endpoint intended to create products from a JSON request. Providing valid JSON will then create a new product in Products table.

This is what the end point looks like:


Using XSS we can execute a call to this endpoint and hopefully run some code on the server!

But why do we need XSS to do this?
Well we might not if the endpoint is unprotected and can be called by anyone but in the real world it’s more likely an endpoint like this would require an authenticated user with higher level privileges.

An attacker might use XSS in the hope a user with higher level privileges will stumble upon and trigger this endpoint.

Keep things simple

I quickly found that when playing with stuff like this it’s a good idea to do the simplest thing possible first and then build upon this.

If we were to try something more complex first like making a connection back to the attacker machine and it fails we don’t know whether this is because our approach was wrong or maybe there are other things such as firewalls preventing the connection.

We’ll first try to create a file using the touch command (Linux command that creates/modifies/sets properties on a file – this won’t work on Windows unless you have WSL running).

Some quick notes

I’m going to use a Linux based machine for this example as both the attacking and victim machine (yes we’ll connect back to ourselves but the approach is the same on distinct machines).

Ok we want to do the following:

  • Run the code when the page has loaded so we’ll add an event listener (not strictly necessary for this but other XSS attacks may require DOM elements to exist/be loaded)
  • We need to pass a valid product object that the endpoint expects just in case there is logic that expects various properties to exist (that’s the productName, smallImageUrl bit in the code below)
  • Pass any credentials the user may have (in the real world this is the sort of endpoint which is hopefully authenticated). We’ll use the credentials “include” option in our fetch request
  • We want to know when our call has completed so we’ll also make a call to http://localhost:8000/callback when the request has been made. This would also be useful if we were scripting the whole attack

Below is some dodgy code I wrote to do this:

Now once you’ve written something similar you’ll need to do the following to trigger it:

Log into hackthecat application

Use Netcat on your attacker machine to listen to port 8000 for the callback that will occur once the script has run (nc -lvnp 8000)

Next go to the products page, add a comment section and enclosing the XSS payload within a script block so it executes (e.g. <script>code here</script>) and then submit the comment.

All being well you should then see that your callback endpoint has been hit:

You should then find a file created on the server:

Oooo its looking good but what else might an attacker do?

Reverse Shells

Whilst the goals of attackers will vary having interactive/command line access to a machine is going to open a lot of possibilities from exploring files/services on the victim machine to using the machine as a stepping stone to attack other servers on the same network so it’s likely to be many attackers end game.

Most web servers will likely have a firewall or network rules between them and the Internet (or should do) that restrict access to specific ports or traffic such as 80 and 443.

These rules however are generally a lot less restrictive the reverse direction e.g. from the web server to the internet and also certain ports will likely need to be open for the server to do anything useful.

A reverse shell connects a pipe from the server/victim to the attacker allowing the attacker to send commands of their choosing.

There are lots of different ways of creating a reverse shell depending on the operating system, framework used, CPU architecture etc but in our example we know we’re working with a Node application and can execute node code so we’ll use a node reverse shell (I found this particular one by googling “node reverse shell” but there’s a great list here: https://book.hacktricks.xyz/shells/shells).

You can read more about reverse shell’s here: https://www.acunetix.com/blog/web-security-zone/what-is-reverse-shell/

Getting a reverse shell via hackthecat

Before we tell the victim machine to connect to us we’ll need something for it to connect to so let’s use Netcat to listen in on port 9000 for a connection (if you are trying this on two separate machines remember to check any firewall settings and allow access to the listening port from the victim machine):

Next we’ll use the same code we used in our example above but instead of using the touch command we’ll run a node reverse shell to port 9000:

If you then follow the same process as above example you should find you get a connection back! (yes I’m aware I’ve connected to myself but didn’t want to setup another machine – change these details as per your own setup..)

This is interactive so you can run various commands – lets run pwd & id (note you’ll want to upgrade this to a full shell but that’s another topic entirely):


We’ve shown how an attacker could use an XSS issue, combine it with a deserialization issue to end up running code on the host of the application and even get an interactive session on it!

This is also a realistic issue – here’s the first real world example I found from a quick Google: https://blog.sonarsource.com/magento-rce-via-xss

Well hopefully by now I’ve convinced you that XSS can be really bad but what should we do to prevent this?

  • Always encode output then the XSS attack would not have worked in the first place
  • Ok this is not XSS but we couldnt have done the RCE without this – monitor the third-party components you use – npm flags that node-serialize has a known security issue and third-party solutions such as Synk and Whitesource will too
  • Validate and filter input from untrusted sources – do you need to be able to accept HTML/JS from a comments textbox – probably not but note its pretty hard to do this as we’ll see shortly
  • Define CSP policies that allow just the minimum functionality necessary for a page – if an attacker found a way round our encoding/filtering this could prevent or limit what they can do
  • Use HTTPOnly and secure option on session cookies to make the attackers life harder and prevent session hijacking/interception
  • Transmit scripts and cookies over secure connection
  • Have a firewall/network restrictions between your server and internet (duh)
  • Restrict outbound connections from the server to just what is needed – more advanced firewalls that can inspect traffic may have prevented suspicious connections like our reverse shell
  • Don’t run web applications as root/high privileges – if in our example the hackthecat application was running as root when we’d performed this attack then attacker has free reign on the machine. If they were able to perform this attack as a lower privileged user they are going to have to find a way to elevate their privileges if they want to do much
  • The script we used was actually quite long and having field length restrictions/validation would have made the attackers job harder

Next Post

Some folks believe that they can filter out XSS attacks with simple string replacement approaches taking out script tags and event handlers.

In my next post we’ll look at some of the literally millions of ways of creating XSS attacks and explore some weird corners of HTML and JavaScript.

XSS Part 3 – Session Riding, CSP policies, SameParty and SameSite

In my previous post XSS Part 2 Attack and Defence we looked at how an attacker can use XSS to steal a users session token from a cookie and then hijack it.

We then enabled the HTTPOnly option on our session cookie preventing malicious JavaScript from accessing the cookie value and sending it to the attacker.

Whilst HTTPOnly option will prevent this scenario unfortunately there is a another we need to address.

Obligatory Warning

Before we go any further obligatory disclaimer/warning/nag – do not perform any of the attacks we’ll discuss on sites you do not have permission to otherwise you could get into a lot of trouble or even jail.

A much better option to explore this topic is to use something like my deliberately vulnerable application https://github.com/alexmackey/hackthecat or HackTheBox.

Back to the content..

Ok where we?

Ah yes so the big issue we need to address occurs because if an attacker can execute code on a web page then it will operate as if it was legitimate code written by the site author with the same access to cookies, local and session storage.

Now browsers under most circumstances will automatically send cookies set by the site the user is browsing with any requests made via XHR & fetch requests (note that fetch requests require this to be explicitly enabled).

This can be a big issue when an XSS problem exists as because if a cookie value is used to identify a user (like in our example) and an attacker can get code to run on a page then they can call any API endpoint in the context of the logged in user!

Uh oh..

An attacker could then use this to:

  • Hit an API to change the user’s password to a known value (we’ll do this in a minute!)
  • Perform any valid action the user can – maybe this is transferring money in a banking application or purchasing products and sending them to the attacker or maybe exploiting some dumb Web3 NFT thing..
  • Perform additional XSS attacks but as the user themselves e.g. messaging other users XSS nastyness
  • ..and a thousand other horrendous things!

So how does this work?

Creating this attack is trivial and any web developer will have written similar (but probably better) code for completely legitimate purposes.

Below is an example of code that in the hackthecat application will change the password of the logged in user.

If we can get this to run in a page the user viewing it will have their password changed!

var formData = new FormData();
formData.append("username", "user");
formData.append("newPassword", "changed!"); 
formData.append("confirmNewPassword", "changed!"); 
var request = new XMLHttpRequest();
request.open("POST", "/user/change-password");

You can of course write this using fetch as well just remember you’ll need to use the credentials option set to “include” or “same-origin” otherwise fetch wont send credentials/cookies.

To see this in action yourself simply log into the hack the cat application (user and pass will do), go to a product and add a review with the above code.

When this runs you’ll then find this has changed the users password – here’s an exciting before and after mysql query screenshot – note how the password is “changed!” in the second query:

Local/Session Storage and Session Tokens

Some sites use local or session storage to save a users session token and then append it to requests rather than storing tokens in a cookie.

I think generally as the XSS code is executing in the context of the user this approach is unlikely to provide any additional protection. In fact it could make things worse.

I’m of two minds about storing session tokens in local storage. Whilst you are arguably in trouble if an XSS issue exists (due to the attack type we are currently discussing) you lose the benefit of how cookies work and expire and additional protection such as HttpOnly or SameSite options that are baked into modern browsers.

CSRF (Cross Site Request Forgery) Tokens

Some of you might be thinking oh this is where CRSF tokens come in – they’ll save me!

CSRF tokens are intended for preventing a different issue (you can read more about them here: https://portswigger.net/web-security/csrf/tokens).

CSRF tokens are likely implemented as a special value stored in a hidden form field that is sent with any requests and compared server side.

To circumvent this protection will require the attacker to read a value of a hidden form field which er really isn’t too tricky so in respect to this attack doesn’t really provide any protection (except against some very lazy attackers).

You should still however use CSRF tokens as they will of course offer protection against CSRF attacks – exactly what they were intended for.

What can we do to prevent this attack?

Apart from preventing XSS issues in the first place probably the most effective protection against this particular attack is to ensure that critical actions such as changing a password enforce the user to provide their original password first as hopefully the attacker and script will not have access to this.

I guess you could also implement a CAPTCHA but no-one wants to count how many Volvo’s are in a crappy picture displayed in a 16×16 grid – no they really don’t – do better.

We are however going to make the attackers life a lot harder by using Content Security Policy (CSP to its friends).

CSP headers (Content Security Policy)

CSP policies allow the client application fine grained control of what should and should not be running on a page and from where.

CSP policies are supported in every major browser and in a limited form in IE10+ (which hopefully you don’t have to support).

CSP policies can be set either in HTTP headers or meta tags and look something like this:

Content-Security-Policy: script-src https://simpleisbest.co.uk/

The above policy says scripts can only run from simpleisbest.co.uk and some other behaviours I’ll discuss shortly.

Below is the meta tag equivalent:

<meta http-equiv=”Content-Security-Policy” content=”script-src https://simpleisbest.co.uk‘ ‘self’;”>

What can you do with CSP policies?

Let’s say we have set the following CSP header on my site simpleisbest.co.uk:

Content-Security-Policy: script-src https://simpleisbest.co.uk/

Adding this header to HTTP requests will do the following:

  • Any inline scripts will be blocked (unless explicitly enabled with ‘unsafe-inline’ option) – this would prevent the XSS attack we have been discussing!
  • Inline event handlers e.g. onclick=”doSomething()” will be blocked preventing another attack vector
  • If the attacker tried to load a script from anywhere but simpleisbest.co.uk it’s going to be blocked
  • Several script execution methods such as eval(), Function, setTimeout, setInterval, setImmediate are blocked unless specifically enabled with unsafe-eval option
  • It prevents an attacker sending data to another server with html forms

Now the chances are when you first implement CSP policies especially on a site that has been around for a while some of these settings will break the site – you’ll find all sorts of dubious approaches in your code and perhaps third-party libraries doing some weird stuff!

Whilst you are first implementing CSP policies I suggest instead of using “Content-Security-Policy” I suggest you use “Content-Security-Policy-Report-Only” – you’ll see stuff that CSP would have stopped in the browser console instead of it being blocked making it easier to fix it up.

Enabling specific inline scripts

If for some reason you wanted to enable specific inline scripts (really?) but benefit from the protections CSP offers you can do this by adding a nonce to your inline script and then specifying the nonce to be expected like so:

Content-Security-Policy: script-src 'nonce-test'
<script nonce="test">

Ensure only specific scripts can be loaded

CSP policies allow us to ensure that only specific versions of scripts can be loaded by specifying an expected hash of the script like below (remember to include script tags, whitespace and that this is all case sensitive):

Content-Security-Policy: script-src 'sha256-yourSha256hashhere'

This is probably a good idea if you are referencing any scripts especially those on third party servers. This way you can be sure what your users will get is exactly as expected!

The downside of course is that its going to require some maintenance when scripts and assets are updated but it’s a small price to pay.

Which policies should I use?

CSP policies offer a huge number of settings to tweak.

Ideally, you want to only allow the minimum necessary for your site to function – this will reduce the surface attack area of your site and make the attackers life really hard if you can limit what options they have to utilise.

OWASP list the following CSP policy on their cheat sheet page (https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html)

Content-Security-Policy: default-src 'none'; script-src 'self'; connect-src 'self'; img-src 'self'; style-src 'self'; frame-ancestors 'self'; form-action 'self';

This will do the following:

  • All resources must be in same domain as document
  • No inline script, evals for script and style
  • No need for other sites to frame
  • No form submissions to external sites
  • Prevents loading of non ajax and CSS resources

This seems a pretty good base to start from and adapt to your purposes.

Adding a CSP Policy to HackTheCat

Ok let’s add a simple CSP policy to hackthecat site so we can see the impact.

We’ll do this directly in homeRoutes.js.

Add the following line before the res.render call in homeRoutes.js:

res.set("Content-Security-Policy-Report-Only", "default-src 'self'");

Note really you want this header to apply to every response so this isn’t the best way to do this as it will only apply to this endpoint. Also note that there are some third party express libraries to do this.

Once you’ve added this, restart the app, navigate to the page and you will then see something like the following in the browser console showing the inline script has been blocked:

Changing this to “Content-Security-Policy” mode will also display information about the referenced stylesheet hosted on fonts.googleapis.com being blocked as we haven’t said this is OK in our policy:

Deprecated approaches

You may come across a reference to various other XSS protection headers/options such as

  • X-XSS-Protection
  • X-Content-Security-Policy
  • X-Webkit-CSP
  • X-FrameOptions

These are all now deprecated and superseded by CSP Policies (for X-FrameOptions you can use frame-ancestors to provide protection against frame based evilness).

Using these legacy approaches can even cause security issues so don’t use them.

SameSite and SameParty

Before we wrap up this post I just wanted to tie up a loose end from the last post on SameSite and SameParty cookie options that you may have seen in the browser dev tools:

SameParty is a proposal designed to deal with the issue that modern sites are often served over multiple domains owned by the same entity. The intention is to allow developers more control over the privacy boundaries of where cookies are shared.

As this is still a proposal I’m not going to worry too much about it at this stage but its an interesting idea. You can read more about this proposal here: https://chromestatus.com/feature/5280634094223360.

SameSite however is ready to use now and supported in all major browsers apart from our old friend IE11.

Same-site is designed to protect against CSRF and potential information leakage by allowing developers to control that it should only be sent from requests initiated by the domain it was created in.

This is different to the default cookie behaviour where cookies are automatically sent to the same domains that they were set in.

Same site has 4 main options:

  • Strict
  • Lax
  • None
  • Unspecified (behaves the same as lax)

What do these SameSite options do?

Let’s assume a scenario where:

The user has a cookie set by my domain simpleisbest.co.uk

The user is on an external blog site hosted at wordpress.com

If the cookie had SameSite set to strict then the following will occur:

  • If the blog site references an image on simpleisbest.co.uk then no cookies would be sent to simpleisbest.co.uk from this request
  • If the user were to follow a link from wordpress to simpleisbest.co.uk then on the first request they make no cookies will not be sent offering protection against CSRF attacks that rely on the user being logged in and clicking a malicious link
  • Once the user is on the site e.g. they click a link on simpleisbest.co.uk then cookies will be sent as they are now in a first-party context (e.g. on the site that set the cookie).

When SameSite is set to lax then:

  • If the blog site was referencing an image and requested an image from simpleIsBest.co.uk then no cookies would be sent as per strict mode above
  • Unlike strict mode however if the user follows a link to simpleIsBest.co.uk then cookies will be sent.


When SameSite is set to None:

  • If the blog site was referencing an image on simpleIsBest.co.uk then cookies would be sent with the request
  • If the user follows a link from another site to the site that set the cookie (simpleIsBest.co.uk) then cookies will be sent
  • Note you must set the secure attribute on cookies when using None


Unspecified now behaves the same as Lax (recent change).

Ok let’s wrap things up – in this post we looked at how XSS can without further protections in place allow us to execute actions in the context of the user such as change their password or call arbitrary endpoints via XHR or fetch.

We then looked at how CSP policies provide fine grained control of what functionality can run in a page and can prevent or at least make an attackers life a lot harder then finally we looked at SameSite and SameParty cookie options.

In my next post I’ll show how an XSS issue can be exploited to run arbitrary code on a webserver which is pretty much as bad as things can get!

AzureB2C and User Flows – Unable to retrieve document from: ‘[PII of type ‘System.String’ is hidden

I was playing with AzureB2C & user flows this weekend (yes what better way to spend your weekend!) and encountered a few issues I suspect will bite other people.

Microsoft documentation has improved massively over recent years but whenever I touch AzureB2C/ASP.NET Core Auth stuff I’m always frustrated by the out of date documentation and examples available.

Today was no exception an after an hour or two of playing, swearing, feeling stupid and upgrading examples to .NET 6 I had the basics working and could sign-in to my AzureB2C instance.

I now wanted to add a custom user flow so I followed through the tutorials to set this up and all looked good.

However when I tried to sign in I was greeted with the following error:

IOException: IDX20807: Unable to retrieve document from: '[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'. HttpResponseMessage: '[PII of type 'System.Net.Http.HttpResponseMessage' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]', HttpResponseMessage.Content: '[PII of type 'System.String' is hidden. For more details, see https://aka.ms/IdentityModel/PII.]'.

Here’s a lovely screenshot of it:

This confused me as I’d followed tutorials step by step and this error message really is not very helpful.

The first step to resolving this is to turn off the PII protection in Identity model so you can see what’s going on.

To do this add the below line to startup.cs/program.cs and you will have more info:

IdentityModelEventSource.ShowPII = true;

In my case I could see the problem was the app was trying to download OpenID configuration from a URL that was not accessible any more:


I assume Microsoft have retired/repurposed login.microsoftonline.com as a way of referencing user flows – perhaps they could have provided some kind of feedback around this if you hit the URL?

But what should the correct URL be?

AzureB2C allows you to test your user flows with a “Run user flow” option. I knew my flow was working as I’d tried this already:

Note if you find when you try to run your user flow that all the options are disabled/greyed out this is because when you created your application registration you didn’t select the third option in Supported account types (ask me how I know):

Silly you!

Of course this clumsy error you made is immediately obvious from the complete lack of information here the Azure Portal will give you here but er moving on..

Anyway on the run user flow section I could see that the config for the user flow was actually located at:

https://<AzureB2C name>.b2clogin.com/<AzureB2C name>.onmicrosoft.com/v2.0/.well-known/openid-configuration?p=B2C_1_SignUpAndSignIn

Anyway at when you Run your user flow you’ll see the URL where this config lives at the top of the pane:

You can go to this URL and you’ll see some lovely JSON with your setup details in – a bit of it looks like this:

I’m configuring my app via appsettings.json so the fix was simply in the AzureB2C configuration section to change the instance property from:

"Instance": "https://login.microsoftonline.com/"


"Instance": "https://<Azure B2C name>.b2clogin.com/"

XSS Part 2 – Attack! (and defence)

In my first post we looked at what XSS is, the different types and summarised some of the potential impacts it could have.

In my next few post’s we’re going to explore common XSS attacks and how we can prevent or mitigate them.

As always don’t try this stuff on sites you don’t have permission to as its almost certainly illegal and you could get into a lot of trouble..

A much better idea is to use something like my deliberately vulnerable node application that you can download from https://github.com/alexmackey/hackthecat and that’s exactly what we’ll be using in this post.

We’ll start off with some basic stuff and build upon it over the coming posts.

Finding XSS Issues

First of all, an attacker will need to locate an XSS issue in your application.

XSS issue can occur under the following conditions:

  • There is input controllable by an attacker
  • The input appears somewhere on a page that will be processed by a browser (or something browser like that will execute HTML/JS)
  • The input is not adequately validated/sanitised allowing tags such as <script> (note there’s many options here so do not think XSS is confined to just the script element)
  • When the input is eventually output to the page it is not encoded
  • Other protections such as CSP are not in place. We’ll talk more about CSP in future but for now know that CSP can prevent or mitigate some XSS attacks

Finding all the places XSS can occur in a large application can be time consuming and difficult so there are many different commercial and free engines that automate this process. These range from the freely available tools such as OWASP ZAP to affordable options such as Burp Professional up to tools costing thousands of dollars (and more).

A tool likely wont find everything and some XSS issues will require multiple steps to occur for it to manifest.

An example would be an XSS issue existing in a user registration form where everything is done right however elsewhere the application outputs the username in an unencoded form leaving an opportunity for XSS to occur if an attacker were to enter a malicious username.

However I digress and in our example we don’t need any of these automated scanners and we’ll find the issues manually by trying to add some HTML and see if it is output encoded.

Browsing around the HackTheCat site we are running locally we come across a page that allows users to add a review to a product.

This page is probably a good candidate to test as we can control the review text and its likely to be output to this page:

We wont know however whether this page is vulnerable to XSS until we try entering some values. It may be that the text we’ll enter has been encoded properly or sanitised on the back-end which will put a stop to our evil plans 😦

To see if the review text is encoded we could add some simple styled HTML or a script block to write to the console or that old classic the native JavaScript alert box aw yeah.

I guess a real attacker would probably try something subtle first to avoid alerting the team looking after the site.

In our HackTheCat cat bicycle shop example we’ll add some simple HTML in our review text:

<h3>Cats suck! Dogs Rule!</h3>

We’ll add this text and sure enough we see some larger formatted text so it’s likely this is not be encoded properly – we’ve found our XSS!

At this point we’ve added some HTML which whilst has possibilities around defacing the site, mis-information to promote dogs to our feline readers is not as useful or convenient as being able to run some JavaScript directly so let’s see if we can add a script block too.

We’ll do this by adding a message to write to the console like below:

Now if we press F12 to bring up the developer tools we can see we have a message that has been written to the console:

Some sites may allow some HTML tags to format input but filter out more risky things like <script> and JavaScript so you’ll probably want to play with both.

Back to our example – as we can see via output in the console we’re in business to do much more devious stuff now which we’ll get onto shortly.

Before we get onto this let’s see how this issue occurs in the first place as its key to understanding XSS.

XSS issues can occur when we accept input from the user, do not sanitise it, don’t encode it and output it somewhere where it will be executed

If we do a View Source on the page we’ll see something like the below:

This looks just like we’d written this script block ourselves in the applications code – and it will run in the same way as if we had!

In our HackTheCat application the page responsible for displaying user reviews is detail.ejs:

HackTheCat uses a templating engine called EJS (https://ejs.co/) which stands for Embedded JavaScript templating.

In this instance there’s no problem with EJS engine – the problem is in the choice of methods used to output the product review.

Here I’ve deliberately used the wrong output method to demonstrate this issue.

EJS offers two main ways of outputting content <%- (outputs raw, un-encoded output) and <%= (encoded output).

Why would you need raw output?

We’ll for the most part you probably don’t but it could be needed for certain scenarios for example the EJS documentation mentions using it to avoid double encoding output or where you can be sure the content you are outputting is not malicious.

For most circumstances however when using EJS you’ll want <%= to avoid XSS issues.

So does using a framework encoding method like this mean you can avoid XSS?

Most of the time.

However there’s certainly been issues in templating engines, frameworks and browsers and likely will again. Just last week Chromium had a parser issue and there’s been several XSS/client side template issues in frameworks such as Angular.

I dont think we’ve seen the last of these either and as per defence in depth you probably want to consider sanitising input too.

In a later post we’ll look at what frameworks and templating engines are actually doing underneath the cover and the native DOM methods performing this work.

Anyway let’s change the code to use <%= and see the difference in behaviour and output:

If you are using the containerised version of HackTheCat remember to rebuild with the –build flag to get this change:

When you have made this change navigating to this page should now show something like the following and no message in the console:

If we view the source we’ll see it looks a bit different too as the special characters have now been encoded properly:

Compare this with the unencoded version:

Ok this seems pretty straight forward.

There’s certainly been (and will continue to be) issues like this but XSS is can be more subtle than this.

XSS can often occur in less obvious places with values being passed into dialogue boxes or perhaps from other locations such as a user registration form.

Before we move on lets change back the output method so our comment is unencoded as I want to show you some more issues and how we can mitigate them:

Cookie Stealing/Session Hijack

Another XSS attack you should be aware of is that if an XSS issue exists then it can be used to try and steal cookies and ultimately a users session (assuming user sessions are session cookie based).

There’s a lot of different ways & libraries to manage sessions but in our HackTheCat example I’m using express-sessions to manage a users session within the application and sessions are maintained using a cookie.

We can see this in action by logging into the application (by default credentials are username “user” and password “pass” or “admin” and “pass”).

If we bring up the dev tools (F12), select the application tab and look at cookies we’ll see something like the following:

Here we can see that express-sessions has set a cookie called connect.sid containing a random ID. This will be used to identify a user.

Now if we were to copy the value of this cookie and set a cookie with the same name on another machine (and no additional checks/protections were in place and the session had not expired) then as far as the web application is concerned we will be the same logged in user – try it using incognito mode if you want.

This means if an attacker can steal a cookie then they can act as the logged in user.

What’s even worse is if the user had higher privileges e.g. an admin user was browsing the site then the attacker could have access to administrative functions that could be very damaging.

This scenario can occur with XSS using a simple script (or we could just use an img element directly) like the following:

If you look in the browser network tools you’ll then see this session cookie float off to the attackers server where they can gleefully pick it up and pretend to be various users:

Now we can prevent this by making use of some settings on the cookie.

If you open up app.js you’ll see the following:

I’ve deliberately used some bad, unsecure options to demonstrate these concepts.

Luckily many frameworks have some good default options out the box to help keep your applications safe but dont assume, check!

The key option here to prevent this particular attack is that HttpOnly flag.

HttpOnly flag (first implemented in 2002 by Internet Explorer team in IE 6 SP1!) tells the browser that the cookie can only be access from HTTP and not by JavaScript on the page.

We can see this flag wasn’t set in the browser tools when we look at the cookie:

Lets set this option now by updating the session configuration in app.js:

In the real world you’d probably want to set that secure flag too to ensure the cookie is only sent over a secure HTTPS connection so it cant be easily intercepted but lets ignore this for now.

Once you’ve made this change if you now look at this cookie we’ll see a nice HTTP Only tick:

And if we then look at the page source we’ll see there is no cookie present:

Trying to access the cookie properties in the browser console will return nothing:

OK so we’ve prevented that attack and you may think you are out the woods by adding these additional protections but as I’ll demonstrate in my next post you certainly are not.

In my next post we’ll talk about SameSite and SameParty flags, the other bad stuff an attacker could do despite HttpOnly flag and then show how this can be chained with another issue to get RCE or remote code execution but for now that’s all folks!

Advanced Web Attacks and Exploitation (AWAE/OWSE) Course Review

I recently took Offensive Security’s Advanced Web Attacks and Exploitation (AWAE) course and attempted the OWSE exam.

I successfully completed Offsec’s better known OSCP course last year which introduces you to penetration testing and offensive security techniques however with the AWAE course the focus is very much on web applications and the code behind them (which is er kind of explained in the title).

Having a development background, I wanted to know a bit more about what to look for when making and reviewing changes in code bases from a security perspective.

I’m not aware of much training being available in this space (pls add in the comments if you have come across anything good!) so decided to give it a go.

AWAE Course

AWAE structure is very different to OSCP.

AWAE teaches you key concepts by walking through several cases studies of issues in real world applications.

One of the key takeaways I took from the course was how various smaller issues could be chained together to ultimately result in remote code execution (RCE).

You’ll be taught to script these exploits yourself with simple Python examples provided – sometimes in an incomplete state for you to finish off as a learning exercise.

A variety of applications and issues are covered in several languages and platforms including .NET, Java, PHP, Node and Python.

At the end of the course there are two (White-box) and 1 (Black-box) machines with no instructions/solutions to give you a taste of what’s to come in the exam (given the code focus of the course I’m not sure why the Blackbox machine was thrown in there but hey its there if you want to play with it).

I liked how the course taught key concepts with real world examples although some of the examples felt a bit dated. Having said that the concepts are still very relevant so guess it’s ok just might have been nice to see something newer and maybe a bit less PHP (yes you can certainly have two much of that IMHO).

Its worth noting that I understand there’s been a recent update to the course with additional content around server-side request forgery and some other items added (I had the version prior to this).

The Exam

The exam is 48 hrs to review and bypass authentication mechanisms and then obtain RCE on applications you haven’t seen before – oh and you also have to script your attack end to end and write a report about it (you get another day for the report bit).

For writing the exploits you can use any language but you’ll probably end up using Python. I have a .NET/C# background but Python is so easy to pickup, use and has a heap of great libraries it’s a no brainer in my opinion.

The exam is tough and stressful.

To give you an idea of how tough this exam is (or possibly where I am skill-wise currently) I began the exam at 09:00 and finally found one of the authentication bypasses 13 hrs later at around 22:00. Annoyingly I’d actually spotted this earlier too..

I had RCE on the box midnight and the whole attack scripted about 00:30 before going to bed around 01:30 after I’d written the process up.

The second day I didn’t find anything useful at all and unfortunately, I couldn’t complete the other items I needed which meant I didn’t pass the exam this time – I’m still wondering what I missed.. 😦

My learnings:

  • The most challenging part by far is finding the damn authentication bypass/initial foothold!
  • It took me too long to find the issues and i’d have a much better chance at passing if could improve my methodology/spot these issues quicker – I suspect you need to train yourself to spot these
  • Once you find the issues things can turn around very quickly so don’t get disheartened if you haven’t found anything for a long time
  • Reading code in unfamiliar languages and frameworks whilst tired really ramps up the difficulty!
  • For those with a dev background coding the exploits was straight forward (probably the easiest bit for me) and I practised various approaches with my own https://github.com/alexmackey/hackthecat node app which gave me some good templates to use
  • If you don’t pass it’s hard to know what to do to improve – I think probably the best thing is to go over the course notes again, complete exercises you missed and look at other real world issues and code
  • I’d benefit from more real world security code review experience whether in day job or reviewing open source projects before tackling this again

I don’t like leaving things incomplete and not that I take a heap of certifications/exams but I think this is probably the first exam I haven’t passed (although my sociology grade wasn’t great going back to high school!).

For AWAE i’m of two minds whether I’ll retake it as:

  • It’s 3 days long! For those with work and family commitments 3 days uninterrupted by kids etc is a fair amount of time and investment for something with no guarantee you’ll pass
  • Seriously 3 days for an exam?! Reviewing code when really tired seems unnecessary, stressful and an unrealistic situation and you’ll feel smashed for a couple of days after (yes book at least 1 day off as you’ll need it)
  • There’s a fair amount of investment needed in stuff that may not be that relevant to you. E.g. I think I would have been a lot quicker to find the issues with being more familiar with weaker languages or frameworks I don’t use
  • I’m not sure how well known this certification is compared to say OSCP

I don’t have a heap of free time so I suspect I may now get more bang for my buck by working through some of Portswiggers great (and free!) workshops which whilst they dont focus on the code aspects are relevant and then see how I feel in a few months – at least when I’ve forgotten what a horrible experience that 48hrs was and want the challenge again!


This course is really good at:

  • Demonstrating real world issues
  • Showing how issues are chained end to end
  • Improving your python and exploit writing skills

You’ll end up developing some kind of methodology/approach from the examples and challenges but I think this is an area the course could do better in and provide more guidance.

I guess locating the issues really is the hard bit in this field and it must be a tricky thing to teach but there is a massive difference from being taken through an example to finding a problem yourself – the course only provides two machines to practice this end to end on (I enjoyed and completed them both).

This will be a challenging course for those without a development background to understand the code and some offensive security knowledge/techniques are assumed (I was fine after learning these aspects in OSCP).

Those with a development background will find the code aspects for the most part trivial but will also likely pickup some interesting items e.g. I learnt some things you could do with debugging symbols in .NET I wasn’t aware of and some weirdness about PHP variable handling – that second bit isnt that relevant for me but it was interesting!

I completed the course and many of the exercises within 2 months with a full time job and family commitments so this should be do-able for most with other commitments unlike OSCP which will take over your life for a bit.

In summary I really enjoyed AWAE and learnt a lot from it. I would recommend it to other developers who want to know more about how attackers will exploit issues in code and what to look for however be aware this course has a bit of a gap when it comes to teaching methodologies to locate these issues.

HackTheCat – Deliberately Vulnerable Node Express App for teaching/learning AppSec

The last few months I’ve been working on creating a deliberately vulnerable web application to teach and learn AppSec and also use as practice for scripting exploits in preparation for Offensive Security’s AWAE course exam.

AppSec is generally not taught well (if at all) and we can write better, more secure applications if we understand the approaches and techniques attackers will use to exploit solutions – Better Defence through Learning Offence!

The result of this is HackTheCat – a deliberately and deeply flawed Node/Express & MySQL App ready for you to hack and harden!

The application contains a heap of security issues for you to exploit and harden.

In future I plan on creating some step by step guides to teach some basics like avoiding XSS etc.

Obviously do not put this on a machine exposed directly to the internet or on a sensitive network as this application is designed to be easily compromised – you have been warned..

You can download the code from https://github.com/alexmackey/HackTheCat/ and there’s a docker version too so its ready to go with no effort.

Read on if you want to know more about the issues contained in the application and if you’d rather find them yourself stop here as spoilers ahead 🙂

Issues (Warning Spoilers Ahead!)

The app contains a heap of security issues including:

  • XSS (stored and reflected)
  • Various different SQL Injection issues
  • Weak session cookie options
  • Weak encoding options
  • LFI (Local File Inclusion)/RFI (Remote File Inclusion)
  • RCE via vulnerable version of node-serialize (0.4)
  • RCE via Side Template Injection (SSTI) in vulnerable version of pug template engine (2.0.4)
  • Unrestricted file upload
  • Left over mock credentials file discoverable via brute force
  • IDOR (Indirect object reference)
  • Poor and inconsistently implemented authentication approach
  • Some crappy CSS/HTML hacks to a template I made..

Hope some of you find it useful!

XSS (Cross Site Scripting) Part 1 – What is XSS?

I’ve been interviewing web developers recently and was surprised that the majority did not know what XSS (Cross Site Scripting) is.

Perhaps part of this is that many web developers will begin their development career using a framework such as React or Angular that abstracts what’s actually going on.

Many frameworks will now also provide sensible defaults that can help prevent many XSS issues and you have to go out of your way to get round these for example React warns you that you are probably about to do something potentially silly with its wonderfully named dangerouslySetInnerHTML method.

However its still very possible despite some of these protections and defaults to have XSS issues so if you are developing for the web it’s important you understand what XSS is and how to prevent it.

XSS is a surprisingly big topic (and I certainly learnt stuff putting this series of blog posts together) and we’ll be going deep into this topic so I’m going to split this up into what’s hopefully a series of more digestible articles rather than a 30,000 word mega post.

In this series of posts, I will:

  • Introduce XSS and talk about its different types
  • Talk about what an attacker could do with XSS
  • Show an example using my demo app of how XSS could lead to compromised accounts and even RCE (Remote Code Execution) when combined with other issues
  • Look at ways to mitigate or prevent XSS
  • Review some of the thousands of ways XSS can occur and how attackers circumvent various protective measures and what to do about it


As with any offensive security topics its important you do not use these methods and techniques on sites you do not own or have permission to test on.

Trying some of the techniques we’ll discuss on sites you don’t have permission to is almost certainly illegal and you could end up in a lot of trouble or even jail.

There’s plenty of great labs to explore security topics such as hackthebox, tryhackme or bug bounty programs where you can learn and help make stuff safer which makes the world a better place.

These are all much better options than a criminal record/jail time..

Hack The Cat (vulnerable Node/Express application for learning/teaching appsec)

I wanted an application to play, learn and teach some of these issues so I’ve been developing a deliberately vulnerable Node/Express application called Hack The Cat that contains many different security issues (below):

Whilst early in its development I’ve added various common security issues including:

  • Various XSS vulnerabilities
  • SQL Injection
  • Serialization issue
  • File upload with naïve filter

My plan is to expand upon this and also add the following:

  • SSTI (Server Side Template Injection)
  • More advanced XSS filters
  • LFI & RFI (Local/remote File Inclusion)
  • OS command injection
  • JWT issues

Anyway i’ll release this shortly with a MIT license so its free for all but let’s talk about XSS.

What exactly is XSS?

XSS or Cross Site Scripting is one of the most common web security issues and occurs when a website accepts malicious client-side code or HTML and then executes it in the context of the user who is visiting the site.

A simple example of XSS would be a shopping site that allows users to post reviews of products and then renders the reviews submitted.

If an attacker can submit a comment containing a script block like say below..

<script>alert('hello you have XSS issue you'll need to fix up')</script>

..and the browser renders it without encoding this then you’ll be greeted with an annoying smug alert box.

In fact if right click/view page source on this blog post and search for “hello” in the source code you’ll see something like below:

Here, WordPress has thankfully properly encoded this code block – if they didn’t you’d all be seeing an alert box as it would run as if the original site developer had added it.

If you want to see just how common XSS issues are and how they can be used go to https://www.exploit-db.com/ (a site that contains a massive index of security issues and code for utilizing them) and search for “xss” – wow quite a few issues..

XSS was apparently “discovered” by the Microsoft Security Response Centre and the IE Security team who heard about attacks where script and image tags were injected into web pages. In 2000 they published a report in conjunction with CERT where the term Cross Site Scripting was first used.

Whilst popping up an alert box and taking your users back to early 2000’s web/common current debugging techniques is certainly annoying an attacker could do much worse and this can be used to devastating affect.

For this we need to get into cookies and sessions.

Cookies and Sessions

XSS can become especially destructive due to how web site sessions & cookies work.

Cookies are pretty important and one way of holding state about a visitor. Cookies are one of the main mechanisms websites use to identify individual user on a website and understand if a user is logged in.

When I log into many sites the site will issue me a cookie to identify me and that I should be able to access the site.

Now the thing about cookies is that they are sent with any request made from a site or “origin” (there are a few exceptions such as using fetch which doesnt send cookies by default and certain configurations we’ll talk about later).

Now this can be a big issue as if an attacker can get code to run on a site as we know that cookies are being used to identify users then the site may think the request is from a legitimate user!

Same-origin policy

Before we move on I just wanted to mention same-origin policy as this relates to cookies and will also prevent or make harder some types of attack.

This can get quite complex so here’s an overly simplified version.

Same-origin policy places restrictions on what a document or script can do when a page is loaded from one origin and interacting with another.

A site is considered as having the same origin if the following match:

  • Its protocol (http/https)
  • Port (if specified – note weirdly IE ignores the port bit because er IE)
  • host (the address bit – it’s more complex than this but anyway)

The following for example would be considered to have the same origin:



Now this is important as if an attacker is running a script on another server (origin) then they wont be able to do certain things (at least directly) like steal cookies. This is a good thing.

Ok enough theory lets talk about different types of XSS.

Different Types of XSS

XSS comes in several different and overlapping ugly flavours you should be aware of:

  • Stored XSS
  • Blind XSS
  • Reflected XSS
  • DOM Based XSS

Persistent/Stored XSS

In Stored XSS the attacker manages to save their horrible XSS payload somewhere (most likely a database as they are good for this kind of thing unlike er blockchain which really isnt very good at anything).

The bad news with Persistent/Stored XSS is that once malicious code is stored it could potentially be executed for thousands of users who don’t have to do anything but visit your site where the code is rendered which can give it a massive reach.

I guess you’d also have to clean up the stored malicious content at some point in your database which could be really annoying if an attacker automated the creation of thousands of comments.

Blind XSS

Blind XSS is a form of Persistent/Stored XSS but has the difference that the attacker is not sure when the code will actually execute and if at all.

Er what?

Imagine an application that allows the sending of a contact form message to admin users.

When an admin user views this message then the malicious code will then execute in the context of the admin user. This malicious code could then be used potentially to perform administrative functions, steal the admin’s session cookie etc as its executing in the context of the admin user.

In Blind XSS the attacker may not have access to the code base/application so they cant be sure their code will ever actually execute.

An attacker might send code that will “ping” a remote server or endpoint by perhaps requested an image and then monitor to see if a blind xss attack was successful. They could then perhaps send more information about the page its executing on.

Reflected XSS

Reflected XSS occurs when the XSS payload is not actually stored but is “reflected” back to the user.

A site may have a search function that allows users to search for products and then sends the search values unencoded in the query string e.g. simpleisbest.co.uk?search=<script>something bad</script>

Attackers could potentially send users links like the above that are pointing at a legitimate site that then executes their malicious code.

An attacker would likely take care to obscure their payload more carefully than the above example and this could be obscured with various methods e.g. JavaScript’s String.fromCharCode method and a hellish number of different encoding schemes that most browsers support.

It’s important to note that reflected XSS requires a user to perform an action (e.g. click the link) and may be avoided by more knowledgeable users or automated systems that scan emails for malicious content.

Reflected XSS attacks are likely to have limited reach compared to persistent/stored XSS.

DOM (Document Object Model) based XSS

In DOM based XSS the attacker finds a way to inject a payload into the pages DOM without modifying the HTML directly.

A site may after login put the users name in a query string to display a welcome message that is then output on a page e.g. simpleisbest.co.uk?username=Alex

If the receiving code doesn’t encode the output properly then an attacker could supply a malicious bit of code in the username parameter that would then be output and executed on a page.

DOM based XSS can be harder to find/scan for as the attacks never reach the server itself.

So what’s the big deal about XSS?

Whilst using XSS to pop up an alert box or maliciously redirecting users to Michael Buble’s site could be very annoying XSS can be devastating when chained with other attacks.

Depending on other protections & configuration in place we’ll talk about in the future XSS can be used to do pretty much anything a user on that page could do as code will execute in the context of that users browser.

This means of course that the code can:

  • Transverse and manipulate the pages DOM
  • Read users cookies, local and session storage (depending on other protections in place)
  • Send requests to backend APIs in the context of the current user even if not used on the current page
  • Redirect the user to other sites/applications
  • Modern APIs have access to the camera, geolocation, microphone and certain files (these will require user to grant permission if they haven’t already)

And any other endless possibilities – basically anything you could do with client side code in the context of the current user

This means an attacker could:

  • Harvest and steal session cookies (depending on other protections in place) allowing them to act as if they are the user logged in until the cookie/token expires or is revoked
  • Perform actions in the context of the current user as the browser will send cookies with any requests made e.g. change their password to something known
  • Transverse & manipulate the DOM to pull out sensitive information
  • Manipulate the DOM and trick users into performing certain actions or reading wrong information
  • Redirect the user to other sites e.g. a site hosting malware or Michael Buble’s music
  • Defacing a site and replacing it with other content (hopefully not Mr Buble’s music)

Ok so hopefully I’ve convinced you XSS can be a pretty big deal.

In the next post i’ll show an example with my demo application of how it could be used to gain control of an admin account and even an entire server and then we’ll look at how we can fix this up.

Further reading




Should Team Lead and Dev Managers code?

TLDR – Yes but choose the right things to work on

Over the last few years I have been mulling over how much hands on coding I should be doing in various technical leadership roles.

The Pendulum

Charity Majors some years back wrote an article I really like titled the Engineer/Manager pendulum.

One of the things Charity proposes is that some of the best managers are never more than 2-3 years from individually contributing and vice versa.

This makes sense to me as:

  • I think its an unavoidable truth that in software development over a short time your technical skills will atrophy, you’ll get rusty and whilst you might read some articles you came across on Twitter about some new way of doing things in React that seems overly complex its really not the same as getting your hands dirty with some good old development and breaking some stuff
  • Software doesn’t exist in a vacuum and understanding how to get things done and the constraints and challenges a wider organisation faces will change how you approach development (honestly every dev should probably try it at some point you’ll be better dev for it)

Whilst it’s almost impossible to be a very good manager and amazing developer at the same time (i’ll discuss why shortly) I want to discuss why if you are in a software development leadership role of some description I think its important that you remain hands on to an extent and explore some ways you can do this.


Before I get into my er mind dump/rant that i’ve re-written several times I want to note that I have never done a CTO or head of engineering role so can’t comment on what’s required here. I’m writing primarily for the perspective of Team Leads and Dev Managers and whilst I suspect some of what I will talk about still applies for more senior roles it seems likely that coding may not be the best use of a very senior leaders time.

I have worked in various development roles including various levels of Developer, Practice Lead, Team/Technical Lead & Principal consultant for organisations of various sizes. I have led small and large teams and been responsible/supported up to 7 concurrent teams/projects (would not recommend).

In my current role I have a mix of responsibilities but spend probably just under half my time coding with the rest of time made up of a mix of people lead and non-coding project tasks.

Technical Role “Progression”

So most organisations tend to organise development roles around some variation of the following structure:

Junior/Grad -> Developer -> Senior Developer -> Team/Tech Lead -> Dev Manager -> Group lead

At some point you will be promoted/encouraged/pushed/ into some kind of technical leadership role (some with considerable effort have managed to avoid this and seem very happy with this decision which is awesome).

As the roles get more senior you probably (whether you like it or not) have some additional responsibilities or even an entire change in focus.

You likely get paid more for taking on additional responsibilities or responsibilities for others (whether things should be this way is another discussion).

You’ve shifted from being paid to write code to helping others build stuff.

At times this is going to feel like you have made a deal with the devil.

Additional responsibilities in no particular order could include but are not limited to:

  • Working out what you are building and which items to prioritise (surprisingly time consuming)
  • Working with team members to make sure they understand what you should be building (who’d ideally be engaged in the working out stuff but frequently are not). This is also surprisingly time consuming
  • Supporting/advising/mentoring your team
  • Actually doing some dev work and building something (although you feel as if you have less and less time to do this due to the various other items..)
  • Attending various status & update meetings
  • Catch-ups and People Leadership with your team (surprisingly time consuming despite the 20-30 min per person your HR department pretends will be sufficient)
  • Quarterly/Annual Reviews
  • Interviewing new candidates/contributing to recruitment
  • Various other company initiatives
  • Working on proposals/contracts
  • Architecture discussions
  • And there’s probably a heap of other items..

All of this means that you of course have a lot less time to code.

Oh and did I mention the context switching you’ll have to do?

One minute you may be trying to work out why John just cant get on with Sandra and the next you may be interviewing a new front-end developer candidate who’s turned up late.. but wait Functional Dean wants to talk to you about why everything should be written in Haskell (this would be cool but there’s more important stuff and only Dean knows Haskell).


Adding additional responsibilities can result in a lot of a context switching which as we know makes coding really hard and I think its fair to say that Management and Software Development are opposed in many ways.

So er should you be doing coding anyway?

You may be advised by some well-meaning colleagues and perhaps your boss to stop coding altogether so you can spend more time doing what you “should be doing” – uplifting, enabling etc etc.

I’m almost certain they are wrong.

Let me explain – there is a reasonable perspective that if you are in some form of technical leadership role your focus is the team rather than as an individual contributor.

The thinking is that you should be enabling and uplifting your team and that you need to see the big picture rather than be in the detail about why say the project shouldn’t be upgraded to .NET 6 yet.

Additionally, if you are doing all the coding yourself then this can mean you are not giving the opportunity for your team to learn how to resolve problems themselves (I had a manager who did all the interesting work then left us to fix the numerous bugs and it was very annoying).

Long term this will also have long term repercussions for your organisation if you were to leave and the team cannot work alone.

However this ignores some big items:

Tech changes rapidly

You no longer understand how the solution works which makes it hard to assist the team

Over time you wont speak the same language as the team

Like most things in life however there is a balance to be had here and as a warning it is not easy to find.

Why you should remain coding

Whilst your hands on coding time will (and should) reduce in a leadership role I do think its important you remain coding/hands on.


  • It will be less than when you were an individual contributor
  • It will feel uncomfortable as you’ll likely no longer be the most technical person and up to date with the latest library features/changes
  • You’ll need to ask for help and advice from the team at times – they are working with this stuff every day and you will benefit from their input

I believe the advantages of remaining hands on outweigh the small-time commitment this can take:

  • You’ll understand better how the systems you and your teams are responsible for actually work – reading documentation/your orgs confluence pages can help but really isn’t the same as getting your hands dirty and getting first hand experience of a deployment pipeline that fails at random points
  • You will understand the issues your team are dealing with. I loved that a previous manager pulled down the solution code and worked through the setup himself. At the time it was challenging to get the solution going. This manager now had first hand experience of this pane and could advocate why this needed to be fixed up asap
  • You will know better how to empower your teams and help resolve issues when they occur
  • Software and practices move quickly and your skills and knowledge will certainly atrophy over time and this is unescapable
  • At times management/leadership can feel very lonely and empty. You’ll get a lot of satisfaction combining both enabling others and making small contributions/refinements (we’ll discuss this in a minute)

I’ve got too much stuff to do already how do I fit some dev in?

But I hear you ask how do you do this when you have thousand things to do?

First of all no one is going to say to you “hey Alex make sure you are making time to do some coding ” (especially if your name is not Alex) so you’ll have to do it yourself.

If you are worried about using company time then think how much time is wasted by various other activities that you er “have to do”. Yep that’s right your company can spare a few hours and if they wont then find another company (seriously).

Hopefully however you can work this out so let’s talk about what you should be working on.

What should I work on?

Remember that now you are in a lead role your focus is your team and organisation.

You do need to be interruptible and flexible at times if your team need your guidance or help which means that there are some items that are very much more suitable for you to work on when you are in a leadership role.

As a general rule you don’t want to be taking on any critical, core or very large items as:

  • You’ll get in the way of your team(s)
  • It will stress you out as you’ll know you need to complete these other items but have a heap of other work as well and John and Sandra are still arguing over something that really doesn’t seem that big a deal and Dean as we speak is converting everything to Haskell when there’s more important stuff he should be doing..
  • You take away an opportunity for a team member to learn

Some suggestions on how to do this

  • Find some stuff to work on – good candidates for items to work on include:
    • Smaller tasks such as bug fixes or small features
    • Documentation updates (you know this hasn’t been done in a while)
    • Build, deployment and process improvements
    • Security and performance improvements
  • Book regular time to think, read-up and do some dev and train your organisation/teams that you are not available during this time. You will need blocks of at least 30 minutes and you really want at least 2-4 hours a week and more depending on your role
  • Select an area or initiative that you are passionate about and see what you can do to drive it within your organisation. I’m enjoying learning about security the last few years so have focussed on this but maybe for you its Devops, Observability or database tuning – what can you do around this for your organisation?
  • Depending on your circumstances you might enjoy small fun projects/open source in your own time. This isn’t for everyone and family responsibilities etc can leave little time or energy for this. Something fun however doesn’t feel like work and can be relaxing
  • Consider being hands on for a longer stint to get your skills up to date again (a smaller pendulum?)

In conclusion whilst it can be hard to find the time to code in technical leadership roles I propose the benefits will outweigh a small time commitment.

Further Reading

I really like Charity Majors article the engineer-manager pendulum – check it out at


Managing Humans is a great book that has several discussions around this area:

Attacking (and defending) username/password based systems – Part 2

In my previous post we looked at how an attacker might circumvent username/password based systems and saw there were several possibilities for attacking these.

In this article I want to look at this scenario from the perspective of the defender and look at what we can put in place to circumvent some of these attack methods.

Do you really want to implement this stuff yourself?

Before we look at implementing this ourselves I want to start off by saying that in many circumstances you are going to be much better off using an existing identity service such as Auth0 or Azure B2C (and there are many other options) rather than handling this yourself.

Companies such as Auth0 and Microsoft put a heap of work into creating very secure and feature rich implementations that have been tried and tested.

Additionally, most of these solutions will come with support for various other features such as MFA (Multi-Factor-Authentication), password reset flows, logging, alerts etc all of which would take a long time to build yourself (and some important features like logging and alerts tend to get forgotten).

These solutions are also pretty cheap at least until you get into having high numbers of users where you can probably afford to pay for them anyway.

However, let’s say for whatever reason you cant use one of these options how can we make our login system as secure as possible?

Multi Factor Authentication

You probably are not going to be too surprised to find this as the number one item.

We can divide the types of authentication into:

  • Something we know such as a password or PIN
  • Something we have e.g. a Yubikey, RSA token or smart phone MFA App
  • Something we are and that is unique like a finger print, retina etc

MFA based authentication simply means using more than one of these items.

Its highly unlikely (or at least very much harder) that an attacker will posses multiple of these items at once.

MFA will likely prevent (or make much harder)

  • Brute force/password spray/credential stuffing attacks
  • Could alert a user that someone’s trying to log in as them e.g. with an authentication prompt on a mobile device
  • Even if an attacker can capture (keylogger) or sniff a login over the network they still will need something else to get in

There are however downsides to consider:

  • Additional friction for login – but friction that’s almost certainly worth it for the benefits it provides
  • Can be complex for some users and require use of a modern mobile device which may make it unsuitable for some classes of users
  • Its hard to implement yourself and you’ll likely end up using a third party service which will incur a cost
  • You’ll need a way of resetting this when users lose/forget however you are implementing this

There’s a great blog post by Microsoft’s Alex Wienert (Director of Identity Security) who examines some of the attacks they see on Azure Active directory.

Alex says “based on our studies, your account is more than 99.9% less likely to be compromised if you use MFA.”

Alex also notes that most attackers tried between 10 & 50 passwords before moving on.

Microsoft put together a good paper on advice for password handling that you can read for free.

Some MFA systems can also be configured to block weird behaviour e.g. multiple login attempts from a different location or a login attempt from a location the other side of the world providing additional security protections.

There’s been some discussion around the security of SMS based MFA solutions over the years. Part of this is due to some really rather dumb and trusting processes by telecoms companies to authenticate callers before they port a mobile number (e.g. asking for easily discoverable information). Whilst other non SMS methods are probably more secure most users will have a phone and this means they dont have to install additional software. This makes SMS a pretty good option for some cases.

Disable account after series of invalid logins

Automatically disabling an account after a set number of invalid logins is easy to implement and will almost certainly prevent an attacker brute forcing an account.

Where this gets trickier is that this can become a denial of service vector and allow an attacker to prevent a user accessing their own account!

There’s a few ways you could handle this but probably the easiest is to disable the account for a short period of time and provide a way to enable it again e.g. by time limited email link.

Ensure secure connection

Ensure connections to your login page (and subsequent pages as these will contain authentication related cookies/tokens too!) are made over a secure connection.

Its trivial for an attacker using a tool such as Wireshark or Tcpdump to sniff information being sent over a network such as login details but a secure connection will prevent this.

A certificate will also provide reassurance the user is logging into the correct site – although I’ve seen many organisations use some entirely different domain addresses to their main site which is a bit confusing.

Ensure Passwords are complex but er not too complex

Ensure users set passwords with sufficient complexity to avoid easy brute force attempts.

Perhaps you could even use one of the smaller lists at https://github.com/danielmiessler/SecLists to check the password is not in a top 1000 password list for example.

There’s a balance to having sufficient complexity requirements to make a password hard to guess/brute force crack and encouraging users to find (insecure) ways to remember it!

Forcing rotation of passwords also needs to be balanced against this as most users will just increment a number on the end or something similar.

Don’t restrict characters, length or truncate passwords

Restricting characters, length or truncating a password reduces its complexity and there’s really no good reason (maybe integration with something really old that cant be changed?) to do this.

Store passwords securely

OWASP provide detailed advice on the best way to do this – at the time of writing they suggest the hashing function Argon2id (I hadnt heard of this either) with 2 iterations and 1 degree of parallelism. Note that Argon2id also salts the password to make it harder to crack.

Don’t give anything away with your invalid login messages

Provide the same response for valid/invalid usernames and passwords and if an account is locked out to prevent an attacker using this as an enumeration method. Even subtle changes in rendered HTML like an extra whitespace character could be used to give away details of whether a username is valid or if an account is now locked out.

Logging & Alerts

Whilst there will always be some perfectly legitimate invalid logins where users have forgotten their password or made a typo you’ll probably want to know if there are 100 or 1000 of attempts on an account or a heap of attempts from the same IP address (be aware applications and scripts that will rotate through servers or proxies to avoid this).

Having some form of an alert system can allow you to take a decision on how you want to handle this such as blocking the IP address/network or disabling the account.

Logging is really important as allows you to understand what has happened, where the issues may be and potentially could be important if an attacker gains access to further systems. You may even need it for legal action.

Obviously don’t store your logs in the same place as your solution as guess where an attackers going first if they are successful getting onto your system..

Ensure Users Keep their details up to date

You’ve probably seen that annoying prompt every so often from sites where they check your contact details. Whilst some are probably doing this to spam you it is important these details are up to date so they can contact you and potentially have a way for you to re-enable your account if it is blocked.

Require the user to enter their password to perform a sensitive functions

Privileged operations such as change of email address or password should require additional authentication to prevent say an attacker changing a password or transferring money if a machine has been unlocked or perhaps a CSRF attack.

Make your solution Password Manager friendly

Password managers are a great solution to the problem of having to remember a heap of logins. Some sites disable features such as paste into login boxes or prevent the use of certain characters which can stop password managers working so well. Don’t make your users lives harder these tools make it easy to use complex passwords across sites.

Be wary about using the same authentication systems externally and internally

Whilst it may be very convenient to have an externally facing web application you have developed use your internal networks active directory (and there’s some benefits of centralisation or legitimate use cases) this could very much weaken your network security by providing another (and likely very much weaker point) to attack. E.g. if there’s an issue in your application that it could be potentially used to gain wider access depending on how this is implemented.

Don’t use/allow highly privileged accounts to login in remotely

This is probably veering off the appsec side of things which is where I want to focus but you probably should not connect remotely using highly privileged accounts as this could provide an opportunity for an attacker. Instead have separate privileged accounts that are just used when required.

Be aware of language specific issues

Some languages and frameworks provide special functions to compare password hashes. Note that some languages/frameworks e.g. PHP have some issues you should be aware of such as Magic hashes.

Geographical and time restrictions

Are you users only located in one country?

If so restricting to requests to a specific country could prevent evil bots that crawl the internet discovering your service and make it slightly harder for attackers.

Obviously, there are a heap of ways around this such as VPNs, use servers in another country etc so this should only be used in conjunction with some of the other methods we’ve discussed.


In summary:

  • Don’t build this stuff yourself unless you have to
  • Use industry standard protocols such as OAuth
  • Use MFA
  • Disable accounts after a number of invalid login attempts
  • Enforce balanced complexity requirements
  • Ensure you have alerting and logging in place

Further Reading

OWASP have a great cheat sheet to implementing authentication:


Attacking (and defending) username/password based systems – Part 1

As part of my current focus on Appsec I wanted to explore various security areas that either had common issues or I found interesting to research and write about.

I thought I would start with your everyday Username and Password functionality as:

  • Almost every application or service has some form of this. Even my young kids know how this system works as they attempt to shoulder surf my iPad password and gain access to unlimited Peppa Pig access
  • It’s arguably the weakest point of a system (excluding some form of manipulation/social engineering) and also the one that can provide the most value to an attacker
  • There’s some easy to implement defences that can make an attackers job much, much harder

Where did usernames and passwords come from?

It seems very likely that some form of secret phrase or sign has been used since ancient times as a form of authentication and there’s records of various code systems reliant on a passphrase or secret knowledge being used in ancient times.

The computer based username/password system we’re all familiar with was invented in the early 1960’s by Dr Corbato at MIT who was developing an operating system called the Compatible Time Sharing System or CTSS to its friends.

At the time computers supported just a single concurrent user and the good doctor was developing a way to divide up the processing power of a computer allowing more people to make use of its resources.

Usernames/Passwords were introduced as a solution to hide away files and folders from other users accessing the same machine. You can read more about this on the BBC’s site.

The problem(s) with Username & Passwords

Whilst a Username and Password system is a (mostly) convenient approach to authenticating a user and straight forward to implement* it has 3 big flaws:

  • It requires a human to remember something – and er the vast majority of humans are not very good at this and there’s certainly a limit to the number of things that we can all remember
  • A username/password generally requires a secret to be transmitted from one machine to another over a network which of course leaves opportunity for someone to intercept these communications
  • Username and passwords can be very annoying to regularly enter leading folks to find easier (and less secure) ways to make this easier such as short, easy to enter passwords

* There’s certainly some traps waiting to catch you out as we’ll see

So how might an attacker approach the humble login?

Whilst you are probably familiar with some techniques we’ll discuss such as brute forcing a login let’s put ourselves in the position of an attacker and consider all the ways we could go about attacking an application or solution.

This is a good exercise to carry out with your own solutions (threat modelling) and various frameworks such as STRIDE assist with this.

Of course not all applications are equal and a system designed to hold confidential info or deal with financial transactions is likely to attract more malicious interest than your cat’s fan page (if your cat is of interest to nation state actors then I wish you the best of luck).

Having said this poorly secured applications can (and have) provided a stepping stone for an attacker to gain entry into a network or system. Over the years I’ve seen many dev focussed solutions or systems that perform some highly privileged functions (e.g. talking to databases/copying code/allowing file upload/transfer) that are poorly protected, not maintained or forgotten about and could just provide the entry point someone malicious is looking for..

Obligatory Warning – don’t do illegal stuff and get fired/sued/go to Jail etc

Before we talk about approaches it should go without saying that you should never try any of these methods or tools on services you don’t own or have written permission to.

Attempting to gain unauthorised access is illegal and using some of the techniques we’ll discuss against stuff you don’t have permission to could see you ending up in jail.

If you want to learn how to use some of the tools and techniques there’s plenty of great services that offer VM’s you can legitimately target to develop your skills such as TryHackMe, HackTheBox or deliberately vulnerable applications such as the OWASP juice shop.

We’ll also be developing our own sample application shortly to attack and then implement defences for.

Attacking Approaches

Username and Password functionality initially seems to offer limited attacking options given its simplicity.

Well, there’s actually rather a lot of options and below is a list of things I could come up with in a short time and I’m sure there are more that more experienced folks could think of.

Default logins

It is unfortunately rather common for folks to leave default login credentials on services. Hardware devices such as routers are particularly bad for this and indeed you’ve probably seen this yourself in organisations you work in or with.

A quick google with the name of a service or device will soon locate a default login for a device or application if one exists and given the low effort to do this I suspect this would be one of the first things an attacker might try.

The other pretty common approach is to have a login that’s the same as the product name due to lack of imagination e.g. “payroll”, ” payroll”.

Guessing common logins

It’s pretty common for folks to create dumb passwords many of which should know better. Combinations of strings such as “admin”, “root”, “administrator” or “password” & “password123” will likely be tried given how common this is and the ease of which it can be done.

It is also pretty common for organisations to append the month, season or year on common terms e.g. winter2021 or <companyname>winter2021 so this approach may be tried too.

Guessing credentials with a bit of research/OSINT

If you know some of the users of a system (say via a LinkedIn search or even just a look on company website’s staff page) a bit of research may yield likely passwords candidates.

Maybe one of the potential users is blogging/tweeting about a particular sports team or hobby this could yield potential password options.

Another option an attacker could take might be to find out a supplier or partner that possesses login details and utilise these.

Credential Stuffing

Credential stuffing is where attackers use a list of credentials from other systems in the hope that users have reused them. There are many password dumps around and paid services to make them easy to search.

My favourite example of this was in Darknet Diary episode about the LinkedIn breach and Donald Trump. Can you guess what Trump’s Twitter password was in ~2013 when he was the host of a popular TV show?

Using a list of passwords

There are many lists of common and real passwords compiled from login dumps at sites such as https://github.com/danielmiessler/SecLists/tree/master/Passwords.

Attackers can make use of tools such as Hydra and Burp that make it easy to utilise these lists and test for valid logins. These tools send a large amount of requests and then responses can be compared to check for signs of a successful login e.g. specific text such as “Logged in successfully”, different HTTP status codes or content length. With a fast connection and machine hundreds of thousands of passwords can be tried very quickly.

Trying every possible combination of characters, numbers and symbols

Whilst this will likely take a while and is very noisy this approach it will eventually yield results especially if there are no complexity requirements on your passwords.

This could also crash a poorly written application resulting in a Denial of Service.

Buffer Overflow

A buffer overflow in a login function is probably one of the most critical issues an application could have due to its ability to be exploited remotely. This very issue occurred in SLmail 5.5 and is now often for teaching buffer overflow concepts.

Username Enumeration

You might be thinking ok I can see how you can try various passwords from lists etc but how will an attacker know the username?

There’s several options an attacker could take to find out a username such as:

  • Some systems may leak details of usernames (e.g. a blog that shows the username on posts)
  • Maybe it’s a popular system that most folks will use and their email/username can be found elsewhere
  • An easy to guess system is used such as an incrementing number
  • It may be possible to setup a user yourself to work out the format
  • Forgotten password functionality could expose valid/invalid usernames (we’ll go back to this)
  • Valid usernames could be enumerated by sending a large amount of requests and examining timing differences that may occur when a valid username is supplied. Some older versions of SSL in a certain configuration suffer from this and there is even a metasploit module to check/exploit this.


If somethings been transmitted over a network then there is the potential for it to be intercepted unless its transmitted using secure protocols.

Of course, some attackers (e.g. government agencies) almost certainly possess the resources to read even encrypted communications.

Certificate based attacks and SSL stripping

Whilst communications can be sent over SSL if an attacker can redirect them to an unsecured connection or somehow obtain the certificate key or compromise the certificate issuing authority then communications could be intercepted.

Tricking users into using a fake login page

If an attacker can somehow trick users into using what appears to be a legitimate login page maybe via phishing or social engineering they could then pickup their credentials and forward them onto the real site and the user be non the wiser.

There’s some scary real world examples of this such as Tunisia, Facebook incident back in 2011.


If a user is already logged into an application and CRSF defences are not utilised it may be possible with approaches such as phishing emails to access privileged functionality especially if it doesn’t require login details to be re-entered.

User manipulation/Coercion

Whilst I think most folks are becoming aware that they shouldn’t share their login credentials or hand them over the phone its likely there are many folks that could be tricked into handing over credentials. Think a phone call from “IT Support” that just need your credentials to do..

Some users could be enticed/bribed, blackmailed or threatened into revealing important details.

Denial of service

It might be possible for an attacker to create a high load on a system by bombarding it with login requests and prevent anyone else from using it.

Looking for unsecured areas of the application & poorly implemented session handling

Whilst not strictly a login issue there may be unsecured components in an application that don’t even need valid login details that could be found by directory busting using tools such as gobuster.

If you can guess a users session identifier you could potentially take it over.

Using credentials of inactive users or staff that have left

Many organisations have a huge number of systems that their staff will use and it can pretty hard without centralised authentication to ensure that access is disabled.

We all know how good most companies are at making sure all access is disabled.. (not very).

SQL Injection

Hopefully not so common now but authenticating against a database is pretty common and it may be a poor implementation vulnerable to SQL injection. I should note this issue seems to crop up fairly regularly in training environments/CTF machines so worth checking for.

Insecure implementations of Remember Me functionality

Some applications will supply a cookie to the users so they can avoid having to login to an application again. Poor implementations may store a user id in a form that can be easily modified to elevate access.

Insecure Password Reset

Going to a password reset page may allow an attacker to determine if a username is valid or not. For example the attacker could enter a username to test and the application may indicate whether the login was valid or not with a message such as “invalid username” or even tiny differences in the HTML returned.

Sometimes password reset functionality may ask questions to authenticate a user. Unfortunately some of these questions can be pretty easy to find out such as a persons date of birth (quite likely on social media), school etc. See Sarah Palin hack for an example of where attackers used this approach.

Keystroke logging

An attacker could add a malicious program or device to log users keystrokes. I’ve seen some financial applications implement a keypad that appears at random positions to try and mitigate this. Whilst this probably raises the bar if someone has a keylogger on your machine they could grab screen images too..

Physical changes on a device

This is more relevant for physical security devices such as a keypad entry system that due to physical characteristics may reveal the login detail. I remember seeing a keypad recently where 3 keys were very visibly more used than others. Guess which 3 keys are likely to be used in the entry code..


As you can see there are many potential options – can you think of any others?

Join me in Part 2 where we’ll begin to implement a .NET Core application for playing with Offensive and Defensive techniques and look at how we can defend against most of these methods we’ve discussed above.

Further reading