Free Parking for Life

Ron Reiter
4 min readJan 9, 2019

Disclaimer: I am not responsible for anything you do with this information.

This post was originally published in 2017.

As I entered the parking lot, I took out my parking ticket and put a sticker on it to validate my parking. My company buys stickers for parking validation which cost around $10 each. Looking a bit more at the stickers, I realized that if I knew how to generate those stickers, I could just park for free.

Those stickers had a simple “Interleaved 2 of 5” 1D barcode on them. I went home and took a picture of those barcodes, and uploaded them to an online barcode scanner which identified the barcodes automatically and printed out the digits on them. I had a lot of them since we bought those stickers in batches for our guests.

Those were the numbers I got:

03001909 0788
03001910 0956
03001919 0642
03001946 0642
03001920 0810
03001921 0664
03001922 0518
03001923 0372
03001932 0372
03001933 0226
03001934 0080
03001935 0934
03001947 0496

To generate an additional barcode, you would need two things:

1) Know the next probable valid serial number you could use.
2) Know how to generate a valid barcode.

In our case, it is easy to see that the first 8 digits are the serial number, and the last 4 digits are sort of a validation mechanism. Doing #1 is easy, we just need to keep on counting to the next one and we would be likely able to generate a barcode in the correct series. However, #2 is a bit tricker.

I had to start investigating the last 4 digits and their connection to the first 8. Two pairs of barcodes did help me to figure that out. The first one is this:

03001923 0372
03001932 0372

As you can see, the last 4 digits here are the same, whereas the first 8 digits have the same digits. We can probably assume that the algorithm for generating the last 4 digits is “commutative” in nature, meaning that the order of the objects does not change the calculation. Addition and binary gate operations are two examples of such operations. Another thing we can understand is that the calculation is probably done on a per-digit basis.

The second pair which caught my eyes was this one:

03001919 0642
03001946 0642

This time, the connection is not immediately trivial, but one might ask how come 1 and 9 together are the same as 4 and 6 together? You guessed it, the operation is addition. When adding up the digits we get the same number. In this case, 3+1+9+1+9 = 23.

OK, great. So now we know that f(23) = 0642, but we have no idea what the function f is. It might as well be some sort of salted SHA1 hash which we would never be able to guess. But I was assuming it would be a bit easier.

The column of zeroes made me think a bit, and I realized that the ones who planned it had to cut some digits in order to get those numbers in the range of 0 to 999. Cutting digits is done by using the modulus operator, and in this case, they even misused it a bit. They could have cut the digits using modulus 10,000, but instead, they only used 1,000. Well, at least that was my assumption.

So, assuming they used the modulus operator to cut the digits, we can probably guess that there’s some sort of operation done on the sum of digits. The most trivial way to create such hashes would be to multiply the number (which is how CRC works). Ideally, you’d want to multiply using a large prime number which is larger than the size of the number field.

Therefore, I’m guessing that f(x) translates to:

f(x) = (x * secret) % 1000

We already know that f(23) = 642, so:

642 = (23 * secret) % 1000

If 23 * secret would be less than 1000, then to find secret, we would just need to divide the equation by 23:

secret = 642/23 = 27.913043478

Well, obviously, that’s not it. If it’s not 642, then it might be 1,642, or 2,642, and so forth.

I’m sure there’s a bit more elegant way to find the missing thousand component, but for me, it would be just quicker to do a bit of brute-forcing:

1642/23 = 71.391304348
2642/23 = 114.869565217

18642/23 = 810.52173913
19642/23 = 854

Bingo. A number which the sum divides without any remainder. And it’s not even prime nor larger than the number field. So now our function is:

f(x) = (x * 854) % 1000

Let’s see if we were right. If we were right, we can generate the last 4 digits of the following barcode just by using the first 8.

03001935 0934

So sum = 3+1+9+3+5 = 21. f(21) = (21 * 854) % 1000 = 17934 % 1000 = 934.

Nice. So what're the next steps?

1) Buy some stickers
2) Write a simple HTML page that generates barcodes according to the requested series.
3) Print them on the stickers

And we have free parking for life :)

However, there’s one caveat. The parking lot does track the license plate of the car and the barcode numbers used to exit the parking lot. So if they check the database, they can link the cars to the generated numbers, and assuming they are fake, they can probably send your license plate to the police and get you in jail. So I wouldn’t try it at home if I were you :)

--

--