Which .NET Version is Installed?

I’ve found myself needing to know which version(s) of the .NET are installed on a server and the easiest way I’ve discovered is to browse to the directory and check the version on mscor*.dll files.

Browse to this directory which is the same on all versions of Windows currently in use.


Go into the Framework or Framework64 directories and you’ll see the overview of versions installed. For example, you might have a directory called v4.0.30319 and you would be forgiven for thinking that is the version installed. But what if you know you have .NET 4.5 or even 4.7 installed?

You can go into the directory and find the DLLs whose name begins mscor then right-click -> Properties -> Details tab and see the file version. This matches the version of .NET.

Ubuntu Static IP

Linux is a varied operating system with myriad ways of accomplishing a single task. Here is the cleanest, quickest, way I use to set a static IP for Ubuntu 16.04.3 LTS (GNU/Linux 4.4.0-96-generic x86_64).

sudo nano /etc/network/interfaces

After entering your password you will be presented with a nano session showing the current configuration of your interfaces. If this is a fresh install you’ll see something like this.

# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
auto enp0s3
iface enp0s3 inet dhcp

Note! My interface is enp0s3 but yours may have a different name.

Comment out the current configuration for the interface you want to set to a static IP and edit in the new information.

# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
#auto enp0s3
#iface enp0s3 inet dhcp
auto enp0s3
iface enp0s3 inet static

In this example I have set it to:

auto enp0s3 Automatically bring the interface online
iface enp0s3 inet static Told the interface it will use a static IP
address Set the static IP I want this VM to use
netmask Set the subnet mask
gateway Set the IP of the gateway to other networks
network Set the network address
dns-nameservers Set the DNS server to the router’s IP

The simplest way to test the configuration is to reboot the machine but you can turn the interface off and back on again if you know the commands for your specific version of Linux.


I’ve been playing Tera through Steam which is free to play and has a shop you can buy [mostly] cosmetic items from should you want to. After having played Runescape for years and become bored of the MMORPG scene I have to say Tera is nicely refreshing for the first 40 levels.

There’s a lot to learn but you don’t have to memorize information like you would with EVE or other MMOs. I downloaded it and ran the game to quickly find there was enough on-screen help to get me through. So far I’ve completed several quests, done some dungeons, and ran around fighting monsters mostly by pressing ‘F’ when near an NPC (interact key – to get quests) and carrying on clicking on monsters until either they die or I do.

Also, you can be a deranged-looking teddy bear.

Overlooking the courtyard
Sitting on a bench

If you have a HOTAS or other game controller connected you might have performance issues after 30 minutes. This is a bug in Tera that’s been around for years and still not fixed. You can resolve the problem by unplugging the controller before starting the game. Make sure to uninstall or disable any virtual controllers!

By the time you hit level 40 you’ve probably learned all the controls, the NPC attack patterns, and seen the same 3 monster models dozens of times with slightly changed names. It definitely gets samey and boring at that stage but as a free game you can certainly get a nice twist on combat in massively multiplayer online games.


I decided to move to WordPress because I wasn’t getting enough time to develop any new features for the blog software I made. Also, WordPress is a full-featured system that has a slick interface and is nice to use.

I installed it on a fresh install of Server 2012 R2 with IIS 8.5 using the Microsoft Web Platform which helpfully popped up when I opened IIS. This took care of installing PHP, MySQL, and WordPress itself by turning the whole process into little more than a wizard.

However… I later decided to move the installation to a different folder so had to change WordPress Address and Site Address under Settings within WordPress then move the files and reset the permissions.

IMPORTANT: Make sure IIS IUSRS has Read & Execute on all the WordPress folders and Write & Modify pm wp-content. You should also add IIS AppPool/ApplicationPoolName with the same permissions to each folder. Check your website’s application pool name and fill in the “ApplicationPoolName” part.

I then discovered I had to edit the C:\Program Files (x86)PHP\v5.6\php.ini file and change upload_tmp_dir to a directory where IIS IUSRS had Read, Write, Modify, and Execute. This enabled editing of images which is needed if you crop images to use as part of the theme.

One plugin I find extremely useful is Enlighter which does all sorts of syntax highlighting for code.

TLD & IP Regex

I needed to validate both a domain name and IP addresses in one regular expression (or: regex) and put this together:


It’ll match a single line to validate an IP or domain name, including any of the new TLDs at the time of writing.

Let’s Encrypt Free SSL on Windows!

Letsencrypt had been around for a while now and is supported by very big names in tech such as Facebook, Mozilla, Cisco, and a lot more. The free service is there to allow anyone to have a secure website which helps the whole web by making sure things like login details are encrypted.

The system had been designed with Linux in mind and some very kind people have offered up Windows variants to make use of it. You can see a full list of recognized bots/programs and websites under the documentation ACME Client Implementations.

I use letsencrypt-win-simple which is a project started by Bryan Livingston which is easy to use and can automatically keep the certificates up to date with a scheduled task.

The main step to remember is adding a mime type on the acme-challenge folder so the verification keys will be served by IIS when the Let’s Encrypt service tried to check your site. Verification will fail without this because IIS will present a 404 error for unknown for types.

. Text/Plain

For example, if your site is located at C:\inetpub\wwwroot you will be guided to create some directories:


NOTE: Windows prevents you from starting a directory with a dot so you can create it through Command Prompt/Powershell with mkdir. There are other ways to fiddle with it but this is the quickest and easiest.

Once that’s done you can run letsencryptwinsimple and get your free certificates! They’ll be saved to:


Get Computer Model with WMIC

Windows Management Instrumentation can be a crucial tool in day to day IT tasks. One thing I often use it for is getting the model of a server or PC because it’s quicker to type the query than go to the documentation and open the spreadsheet.

wmic /node:SomePC computersystem get model

Simply run that as an account that has enough privilege to do so and you’ll get the model number of the Windows machine you’re querying. You can get a lot of useful information this way including all the performance stats which could be queried programatically.

What Is My IP?

I needed a quick way to find my IP without using Telnet so I added https://mcgrane.co.uk/ip to my site. Here’s the ASP Classic  code because I was feeling nostalgic.

If Request.QueryString("debug") = "1" Then
  For Each x in Request.ServerVariables
    Response.Write(X & " = " & Request.ServerVariables(X) & vbCrLf)
  If Len(Request.ServerVariables("HTTP_X_FORWARDED_FOR")) = 0 Then
    Response.Write Request.ServerVariables("REMOTE_ADDR")
    Response.Write Request.ServerVariables("HTTP_X_FORWARDED_FOR")
  End If
End If



SQL Injection Example

For years I’ve known that SQL injection is bad and how to protect against it. In fact, I’d go so far as to say that everything except the very first classic ASP pages I wrote were safe against malicious SQL but for some reason I’d never actually tried attacking a vulnerable page to see what was really so bad about it.

We all know the XKCD comic about little Bobby Tables and yes you could simply drop the tables or database very easily on an unsecured page but what if you aren’t simply bent on destruction? As developers we spend our lives building little hand-holds into application to stop people breaking things, and that’s just for those that aren’t trying to do anything bad! What about those that want to slip in, infiltrate, and hold your organisation to ransom?

Here’s a brief example of how easy (scary) it is for one unchecked variable to be used as the gateway to read your entire database.

Some things to note:

  • The pages are classic ASP because .NET does not easily let you be so careless
    • PHP, just like Linux, will let you do what you want even if that is pure self-destruction
  • The database back-end is MSSQL Express but this doesn’t matter too much as the theory is the same for any DB backend

First, I’m greeted by a login prompt:

Simply enter a single apostrophe into either field to see if this page is vulnerable.

Awesome! Not only is the page vulnerable, it’s got error reporting turned on so I can see the exact part of the query I’m interested in! This error is saying there is “unclosed quotation mark” in the query which means the apostrophe we entered has been taken literally by the server and executed as part of the query. Simply because of one extra quotation mark the query fails because MSSQL can’t figure out where each string starts/ends.

How can this be exploited? Well, commonly a low-tech self-made login process would select a record where the username and password both exist. Now we’ve seen part of the SQL statement this website uses we can see if we can “log in” without a password, just for fun…

Jackpot. We’re technically logged in but apparently only as BasicUser which just so happens to be the first user out of the database in the very simplistic query we tried. At this point any developers should be thinking this is pretty bad and that they’d never leave any unchecked user input. Read on…

I’ve logged in but I don’t know anything about this server or its secrets. I’ve decided I want to know:

  • What user tables there are
  • What columns each table has
  • List all usernames and passwords

So, step one, I’d like to know how many tables there are so I enter this into the username part of the login prompt:

' UNION SELECT 1, count(*), '3' FROM sys.objects WHERE type='u';--


There are only two tables in this database so it shouldn’t take long to list them all, except that I can’t simply list all the tables as I’ve only got one output to work with which seems to be trying to welcome the visitor by name. I guess I’ll have to do it one-by-one:

' UNION SELECT 1, name+'+'+convert(varchar,[object_id]), '3' FROM sys.objects WHERE type='u';--


Hey look there’s a messages table, I guess these users can chat to each other. I’ve outputted the object ID because that’s what I’ll use to get the columns later. But first I want to know what the other table is so I’ll exclude Messages and do the query again:

' UNION SELECT 1, name+'+'+convert(varchar,[object_id]), '3' FROM sys.objects WHERE type='u' AND name NOT IN ('Messages');--


Now I can get the field names for each table by doing a similar query but this time looking at sys.columns:

' UNION SELECT 1,name,3 FROM sys.columns WHERE object_id = 277576027;--

Now I’ve got a column I can use “AND name NOT IN(….)” again to get them all and repeat the process for both tables. Here’s the result:

Users (ID: 245575913) Messages (ID: 277576027)
Password Message
Username Recipient


I wonder if logging in as “admin” will work, assuming the account exists. Due to how there’s completely no security on this page I could simply put ‘ OR Username = ‘admin’;– into the username field so if there is an account with that name it’ll log me in without needing the password but that’s easy, what if I want to actually know the password? Very easy, I just do the same sort of query as above:

' UNION SELECT 1,Password,3 FROM Users WHERE Username = 'admin';--


The password is ‘admin’ !! Not only is the page SQL injection vulnerable the username/password policy is ridiculous too and every good developer knows to NEVER have something like this in their code… don’t you 😉

Also, once logged in as admin it seems something else cropped up and it looks like a message from BasicUser. It’s important to note here that the messages sent to the administrator appear because the username and password are both ‘admin’ and would not have shown up otherwise. This is because the example looks for messages sent to a Username so by using the above query to get the password the application would think the password was the username and find no messages logged against it.

Now I know there is somewhere that does an iterative list to output a record set and I know what columns it will use I can get a little more creative and simply list all usernames and passwords from this database:

' UNION SELECT 1,''' UNION SELECT Id,Username,Password,Password FROM Users;--',3;--

In conclusion, I hope this shows you that the little SQL bug you have in a project which crashes whenever anyone called O’Leary turns up is absolutely worth fixing right now.

NOTE: I have omitted some details explaining exactly what each SQL query does as this post is intended to explain to a developer why SQL injection vulnerabilities are a critical security flaw, not just something that results in a few errors every now-and-then.

Proudly powered by WordPress | Theme: Baskerville 2 by Anders Noren.

Up ↑