United Kingdom Vehicle Registration Search

I recently got introduced to how vehicles are registered in the UK. I learned a lot while looking into this topic. This blog post will be a mix of two topics: a summary of how the plates are registered and a script to brute-force unknown vehicle registration numbers.

Vehicle Registration

I will be summarizing mostly from the "Vehicle registration numbers and number plates" (INF104 Vehicle Services) PDF by the government of U.K. (Source #1)

The "registration numbers" (which also include the letter values) are a way to identify vehicles that are owned by the Secretary of State. According to the government of U.K., "The registration number is given to the vehicle, not the registered keeper. It will stay with the vehicle (until the vehicle is broken up, destroyed or exported permanently out of the country) unless the registered keeper applies to take it off and put it on another vehicle or on to a retention certificate (V778)". The current format was introduced on September 1, 2001. It consists of:

  • 2 letter memory tag (these refer to the region in the country where a vehicle is first registered)

    • "I" (capital "i"), "Q", and "Z" are not used in local memory tags

  • 2 numbers (these tell you when it was issued)

  • a space and 3 letters chosen at random

    • "Z" can be used as a random letter

The memory tags can tell us what region the vehicle was first registered in. Using the example above, "BD" would tell us the vehicle was registered in Birmingham. For the age, "51" would tell us it was registered between Sept 2001 and Feb 2002. The last three values are just random letters. The PDF listed in the Sources section below has a great cheat-sheet for all of the regions where this is applicable. With this information about a vehicle, as an OSINT Analyst, we can make assumptions about where an individual lives based on their vehicle registration. However, there is the possibility of a person buying a vehicle registered in another region.

From an OSINT perspective, there will be times when information is limited or redacted, and we must make an assumption or educated guess to move the investigation further. For example, using the registration number above, imagine if we were given only the first six values: BD51 SM. We do not know the last value. Based on our research, we can assume it is an alphabetical letter between A and Z, but we cannot say which one for sure. Using code to automate this process, we can quickly generate all 26 possible values for the registration number and check those with the U.K. Driver & Vehicle Licensing Agency's database. There is a website that I had found that does this well: https://www.partialnumberplate.co.uk/. However, I did not find many other websites like this, so I decided to write my own code to automate this process.

The code I had written works, but it definitely is not beginner-friendly. I will show the code first, then describe what it does.

There are two functions that print out the registration numbers: full and license_print. The full function is disabled by default, but outputs all possible values for the registration numbers. It takes a while to output all. I kept it there as a proof of concept of how to get all of the values. license_print is there to output the registration numbers based on wildcards. In the code, I use "$" for a numerical wildcard, and a "@" for an alphabetical wildcard. The code will not work as expected until you put in an API key at the top. I requested an API key from the DVLA (currently located at: https://register-for-ves.driver-vehicle-licensing.api.gov.uk/) and got the key overnight. Keep in mind, the more alphabetical wildcards there are, the more output there will be. The code currently is set up to query the test API, so un-comment the regular API to query actual data. You will then have to comment out the test API line. Below is output I got from the test API. I know the value of "AA19AAA" would give me a result, so I made the position of the "9" to be the wildcard: AA1$AAA. This wildcard would go from AA11AAA to AA19AAA. We can see this in the following output of the code:

If you want to use jq to make the output look much cleaner, you can remove the print statements. There are a lot of guardrails I contemplated on including in this code. If I was to include the guardrails for the positions of the wildcards to be correct and making dictionaries for all combinations of the first two letters, that would end up taking a lot of lines of code. I do have that at the back of mind, and might consider it, if time and interest permits.

Code Limitations

The code is limited to 3 wildcards. I felt like any more than 3 wildcards, and you are just brute-forcing a government portal without any actual direction of what you are looking for. My code is a bit on the greedier side. It outputs more than is needed. In instances where a wildcard is one of the first 2 letters, it would print out all letters from A-Z, without excluding the letters not used: "I", "Q", "Z". If I ever do a revisit to this code, or a redo, I plan on making it exclude those values and be able to be more precise in the output. My goal was to make a code that just works. I was not able to find many resources that did just this, so I decided to make code that .... well, just works.

Updated Code

To run the code, simply run python3 licenseV2.py "license_plate", where you replace the string with the partial plate with the wildcard ?. An example of this would be python3 licenseV2.py "AA1?AAA" on Linux. This would output all possibilites for the 4th value. If you have an API key and would like to use it, use the --api argument and provide the key in quotes after that, such as: python3 licenseV2.py "AA1?AAA" --api "ThisIsMyAPIKey". If the key is provided, the DVLA API will be queried. If not, the plates will be printed out.

Here are the following changes updated in this version of the code:

  • Replacing the wildcard from $ and @ to just ?

  • Command line arguments for the registration number and the API key

  • Adding --help information to guide users

  • Changing the code from the ground up

Source

Last updated