How I Hacked TicketMaster Barcodes
I recently bought concert tickets from TicketMaster. If they had sent me a regular printable PDF ticket that I could save offline on my phone, this article would never have existed. But it's 2024: everything done online is no longer easy.
After completing the purchase, TicketMaster informed me that I would not be able to print tickets for the event. The site issues tickets using the Mobile Entry system, aka SafeTix. They come in the form of an updatable barcode displayed in the TicketMaster web app or Android/iOS app.
“Screenshots Won't Let You Pass,” But Chrome Developer Tools Will
Maybe I'm getting old, but I still remember the days when printed tickets were everywhere. You could print out your tickets after purchasing them online or even at the box office (wow!) and bring those paper tickets to the entrance of the event. They could be saved as PDFs and viewed on almost any device. PDF tickets can be used even when your phone doesn't have an internet connection. Paper tickets can be used even when you don't have a phone. If I bought a ticket from an official company that sells them (and not from a shady middleman), I knew for sure that it was real. There was no risk of being denied entry with it. You could safely send them to friends via WhatsApp, iMessage, Signal, email, or even hand-deliver printed tickets.
And these updatable barcodes are far from perfect. I personally encountered this last year when I went to very popular concert that used a similar system with tickets based on updatable QR codes. Many people, including me and my friends, got stuck at the turnstile due to a bunch of problems with broken barcodes. The main problem:
The phone does not have an internet connection, so the QR code does not load.
The event was so crowded that cell towers and WiFi were overloaded. Internet access was spotty and intermittent.
Apparently the company that created this ticketing nightmare (I can't remember the name) didn't have a helpline, and even if they did, it probably wouldn't work. There was nothing the event staff could do. All we could do was wave our phones in the air and hope that the ticketing app would update sooner or later.
In the end, I luckily managed to “catch” a mobile operator and download the QR codes for the tickets. We left a bunch of other ticket holders waving their phones at the turnstiles. I have no idea if they managed to get in.
I paid three hundred dollars for the experience of using this high-tech system.
Marketing
TicketMaster advertises its SafeTix technology as a panacea for scammers and scalpers.
SafeTix™ uses a new unique barcode that automatically updates every few seconds to ensure it cannot be stolen or copied, keeping your tickets secure and safe.
Ticketmaster SafeTix uses a new, unique barcode system that automatically updates every 15 seconds, greatly reducing the risk of fraud with stolen or counterfeit tickets.
Our secure ticketing technology reduces the risk of ticket fraud by eliminating theft and counterfeiting. When you buy mobile tickets from Ticketmaster, you can rest assured that you will get the seats you paid for.
And there is also this masterpiece:
If you look closely at the ticket, you will notice that it has a moving strip, making it in some sense alive. This is the same technology that works every second to protect you.
Oh, don't push it, TicketMaster. It's just CSS animation, have some sense.
This is what made me wary:
The barcode on the mobile ticket includes security technology, meaning that screenshots and printouts of the ticket cannot be scanned.
It gave me flashbacks to last year's concert, and I imagined myself waving my phone around even more frantically, praying for a cell connection more than Saul Goodman in the desert.
But TicketMaster was ready to allay my worries:
Worried about cellular coverage at an event? A ticket will solve that problem. If you view it in the app, the ticket will be automatically saved and always ready.
Great, if I trust the app and it doesn't break on the day of the concert, then everything will be fine. Unfortunately, I don't trust it, and I don't want to install this spyware on my phone.
Motivation
The reasons for TicketMaster to promote this technology are quite obvious:
- SafeTix makes it difficult to resell tickets outside of its closed, high-margin resale marketplace, where the company can buy cheap and sell high to people with no alternative.
- It forces users to install TicketMaster's proprietary, closed-source app, which gives the company more information about users' devices and behavior.
- Buyers cannot save or transfer tickets outside of Ticketmaster. This forces ticket holders to share friends' contact information with TicketMaster, which can be used to create social graphs and reduce privacy.
TicketMaster would never admit to such a motivation, but these consequences certainly occur even if the company had no such intentions; and all of this pleases TicketMaster's co-owners, but not its customers.
Contradiction
If you have experience with computers and software, you may have the same question I had after reading TicketMaster's marketing statements.
How can tickets be saved offline if they cannot be transferred outside the TicketMaster system?
The ticket is digital. Saving data offline is similar to copying it to a hard drive. If the data can be copied, then it can be transferred. And if it can be transferred, then you can also sell it/
This contradicts TicketMaster's claims. You can't create reliable DRM for tickets if those tickets can be viewed offline.
So what does TicketMaster actually do to create these updatable barcodes?
The first thing I had to do was study the barcodes themselves to see what I could glean from them. Their format is fairly simple. These are barcodes
encoding text in
. As mentioned above, that blue stripe floating across the barcode is simply useless.
: it doesn't actually interfere with scanning barcode screenshots because PDF417 has built-in error correction properties.
It looks like some older barcodes encoded other text formats, but the barcodes in my TicketMaster web app generated data like this embed
:
B4cq2BdFCpFl90TDuYD3pWfRDSO6eQ3bR0YQqsDnyfciuVFkKp+m0zI+a2lgfonY::140013::481994::1707070843
Note: The data is not taken from a real SafeTix barcode. I do not want TicketMaster to be able to identify and track me.
It looks like four blocks of data separated by colons. First comes some data, encoded Base64followed by two six-digit numbers, and at the end is indicated Unix timestamp.
When the barcode changes every 15 seconds, its contents change slightly. The base64 data remains static, only the six-digit numbers and the timestamp change.
B4cq2BdFCpFl90TDuYD3pWfRDSO6eQ3bR0YQqsDnyfciuVFkKp+m0zI+a2lgfonY::358190::038184::1707070859
These six-digit numbers behave in many ways like
Time-based One-Time Password (TOTP)
used in 2FA applications such as
And
. These are rolling six-digit numbers that can be generated from a shared secret and a timestamp.
My gut feeling was that the first two numbers would indeed be TOTP, generated from different secrets based on a Unix timestamp appended to the end of the barcode data. This makes sense: TicketMaster wouldn't want to reinvent the wheel with this system, so they used a cryptographic tool as part of it.
The base64 data was still a mystery. After decoding the data into its 48 bytes, I couldn't discern any meaningful data structures from it. It looked more or less like random data, and since it didn't change when the barcode was updated, it was probably some random bearer token identifying the ticket owner and the ticket itself.
When a ticket is scanned at the turnstile, TicketMaster (or perhaps the event organizer) looks for ticket metadata using that bearer token, and then validates the two OTPs with two secrets stored in its database. If both steps are successful, the ticket is authentic and security can let you through.
Little secret
TOTP can be flexibly configured, but in general the software industry has chosen a certain set of parameters to standardize TOTP. Two parts are sufficient to generate TOTP:
- Shared secret (just a byte array)
- Working hours
If you have both, you can generate any amount of TOTP while you are
completely offline
.
There are two TOTPs in the barcode data, so I probably need to find two shared secrets. If I have both, plus the bearer token, I can generate any number of valid barcodes.
That is, my task became much clearer: I need to find out where these tokens and secrets come from.
Debugging a web application
I turned on my Android phone and connected its Chrome browser to Chrome DevTools on my desktop. This gave me access to the TicketMaster API and source code.
Recording network requests While loading the TicketMaster barcode viewer, I came across one particularly curious query:
POST /api/render-ticket/secure-barcode?time=1707071877481&amid=XXXXXXXXXXXXXXX&_format=json
The response data to it:
{
"deviceId": "8f651107-acad-42a4-b3a6-019aaac41960",
"deviceType": "WEB",
"deviceOs": "ANDROID",
"userAgent": "Mozilla/5.0 (Linux; Android 10; K) XXXXXXXXXXXXXXX",
"nfcCapableDevice": true,
"tickets": [
{
"eventId": "myevent.50.38991943985838B9",
"section": "3",
"row": "A",
"seat": "1",
"barcode": "481848590102K",
"addedValue": false,
"generalAdmission": false,
"fan": null,
"token": "eyJiIjoiNDgxODQ4NTkwMTAySyIsInQiOiJUR1JMWUNxQWYyQ1MvQmxILzh5dThZdkhoV055TW8xUW9CYTI5UTVqVkN4V2xBcE5NbnczSlJkeU9UcFVVWUFDIiwiY2siOiJiOTg0MzJlZDIzYjhmMmJkYTgyMzQ4MjE2MjI5ZjRkMjdjZTlkMDYzIiwiZWsiOiJiMzUxOTM2NGUwYzc5MTRjMWY5ZDU5ZDM1NjUyYTA0MDY3ZDJmNjQ3IiwicnQiOiJyb3RhdGluZ19zeW1ib2xvZ3kifQ==",
"renderType": "rotating_symbology",
"passData": {
"android": {
"jwt": "eyJhbGciOiJSUzI1NiJ9.XXXXXXXXXXXXXXXXXX.YYYYYYYYYYYYYYYYYYYYYYYYYY"
}
},
"bindingRequired": true,
"deviceKeyBindingRequired": false,
"deviceSignatureRequired": false,
"segmentType": "NFC_ROTATING_SYMBOLOGY",
"ticketId": "50.3.A.1"
}
],
"globalUserId": "k39Fj4lNfOS4Zq481bxIWg"
}
Note: I have scrambled identifying information to avoid punishment.
Please note the property token
object in array tickets
. I decoded it from base64 and found that it was another JSON object:
{
"b": "481848590102K",
"t": "TGRLYCqAf2CS/BlH/8yu8YvHhWNyMo1QoBa29Q5jVCxWlApNMnw3JRdyOTpUUYAC",
"ck": "b98432ed23b8f2bda82348216229f4d27ce9d063",
"ek": "b3519364e0c7914c1f9d59d35652a04067d2f647",
"rt": "rotating_symbology"
}
- It seems to be a property
b
coincides with the propertybarcode
tickets object. - Property
rt
coincides with the propertyrenderType
tickets object. - Property
t
— is a base64 encoded byte array of length 48 bytes. - Properties
ck
Andek
— these are arrays of bytes in hexadecimal encoding, each 20 bytes long.
I scanned the last barcode displayed in the TicketMaster web app again:
TGRLYCqAf2CS/BlH/8yu8YvHhWNyMo1QoBa29Q5jVCxWlApNMnw3JRdyOTpUUYAC::492436::240860::1707074879
Excellent. That is to say.
t
— it is a static bearer token. I wonder if there will be
ck
And
ek
those TOTP secrets I'm looking for?
Upon further examination of the minified source code of the TicketMaster website, I found in the file presence-secure-entry.js
function generateSignedToken
which the web application uses to generate barcode data.
key: "generateSignedToken",
value: function
var e = arguments.length > 1 && void 0 !== arguments[1] && arguments[1];
if (this.displayType === l.ROTATING) {
var n = [this.eventKey, this.customerKey]
, a = t;
if (this.eventKey) {
var u = new Date(a);
a = u instanceof Date && "Invalid Date" !== "".concat(u) ? u : new Date
}
var A = n.reduce((function(t, n) {
if (n) {
var u;
try {
u = i.b32encode(o.a.hexToByteString(n))
} catch
u = ""
}
var A = r.a(u, 15).now(a, e);
t.push(A)
}
return t
}
), [this.rawToken]);
if (this.eventKey) {
var s = Math.floor(a.getTime() / 1e3);
A.push(s)
}
return A.join("::")
}
return this.barcode
}
Minification makes the code harder to read, but it seems that
ek
And
ck
are deciphered as
eventKey
And
customerKey
and the bearer token
t
is called in the code above
rawToken
.
The two TOTPs appear to be generated in 15 second increments, but are otherwise created in the same way as the industry standard SHA-1 TOTPs found in any mobile 2FA app. The first is generated using eventKey
and the second one – with the help of customerKey
. Next, the Unix timestamp used to generate both TOTPs is added to the end to help with server-side verification.
To test my interpretation, I installed a command line tool for working with TOTP oathtool
Then I substituted ck
, ek
and the Unix timestamp into the TOTP SHA-1 generator with an interval of 15 seconds:
$ sudo apt install oathtool -y
...
$ date=$(python3 -c 'import datetime; print(datetime.datetime.fromtimestamp(1707074879).isoformat())')
$ oathtool --totp --time-step-size 15s -N "$date" b3519364e0c7914c1f9d59d35652a04067d2f647
492436
$ oathtool --totp --time-step-size 15s -N "$date" b98432ed23b8f2bda82348216229f4d27ce9d063
240860
Excellent! This matches the two TOTPs in the barcode:
TGRLYCqAf2CS/BlH/8yu8YvHhWNyMo1QoBa29Q5jVCxWlApNMnw3JRdyOTpUUYAC::492436::240860::1707074879
Probably,
eventKey
unique to the specific event for which tickets are purchased, and
customerKey
probably unique to the ticket holder. They don't seem to change at all, unlike
rawToken
which is updated every time the TicketMaster web application is updated. However, if you leave the page alone for a few hours,
rawToken
will not change, meaning it should presumably remain valid even after the web application is closed.
What about the field? passData.android.jwt
? Does it do anything? I'll save you some time: it turns out it's not needed to verify the ticket at all; it's probably just an authentication token used to store the ticket in Google Wallet user. I don't use Google Wallet because I care a lot about privacy and try to stay as far away from Google services as possible.
Pirate tickets
Now I know everything I need to duplicate TicketMaster barcodes in my own app or even resell a ticket outside of TicketMaster's fenced marketplace. All I need to do is extract the base64 encrypted property
token
from API endpoint
/api/render-ticket/secure-barcode
or develop a way to dynamically obtain this token using TicketMaster session credentials.
This line token
in base64 encoding and there is ticket, at least for the guards at the entrance. If you have valid rawToken
, eventKey
And customerKey
then you can generate valid PDF417 barcodesindistinguishable from the barcodes from the official TicketMaster application. Without the ability to check a document with a photo at the entrance, the employees of the organizing company will not be able to understand whether the person at the turnstile is the same as the person to whom the ticket is registered in TicketMaster.
The funny thing is that TicketMaster itself has simplified the process of extracting tokens: when a barcode renderer component is placed on a web page, token
is automatically output to the browser console.
r.a.log(
"'render' called on '".concat(
"pseview-".concat(J.get(this)),
"' with token '", this.token, "'"
)
)
This means that in order to obtain
token
we don't even have to bother with injecting our own custom scripts into the page. Simply open the SafeTix barcode in the TicketMaster web app,
connect chrome instance on phone to chrome devtools on laptop
and open the console. It will display
token
. You can copy it and use it however you like.
Lifespans
The only unknown factor here is lifespan.
rawToken
. It is difficult to know exactly how TicketMaster's backend server uses
rawToken
to search for a ticket. Probably new
rawToken
generated every time a client accesses an endpoint
/api/render-ticket/secure-barcode
.
I have no idea how long rawToken
remains valid. It is possible that only one TicketMaster account can be valid at a time. rawToken
. TicketMaster developers could have designed the system in such a way as to prevent multiple valid tickets from being retrieved at the same time.
If a set is simultaneously valid token
then one person could buy dozens of tickets, extract the amount he needs token
and resell them “under the counter”. It would be great if TicketMaster didn't think about this, because then I could extract token
tickets for friends and distribute them without having to communicate with TicketMaster's data collection pipeline.
The only authoritative source I could find on this topic is mysterious document on TicketMaster Developer API Documentation website.
Partners must refresh the token 20 hours before the event and every time the ticket is displayed in the app.
FAQ
- How often should the token be refreshed? You need to refresh the token every time a viewer opens and views a ticket in your app, and 20 hours before the event. If we can't refresh the token when the viewer opens the ticket at the turnstile, the SDK will try to use the token that was refreshed 20 hours before. The token should still be valid. You don't need to refresh the token every 20 hours.
Based on this, it would be reasonable to assume that
rawToken
is only valid for 20 hours, which should mean you need to get
rawToken
no later than 20 hours before the event to resell or transfer it without TicketMaster's permission. However, if you just want to keep the ticket offline, then this is more than an adequate solution. I even collected on
a small application that I called
; if you pass it on to him
token
it renders SafeTix barcodes.
I want to test it when my concert date comes.
Conclusion
I think we all agree with the motto
. I hope its worthless product managers and senior management read this and freak out. I hope its developers read it and feel ashamed. I rarely feel genuine hostility toward other developers, but to the designers of this system, I say:
“Shame on you”
.
Shame on you for wasting your skills on limiting the opportunities of people who do not have modern technologies.
Shame on you for allowing the marketing team use this dark pattern as a protective measure.
Shame on you for supporting a company with such vicious business practices.
Software developers are the wizards and shamans of the modern era. We must use our powers with the care and responsibility that these powers imply. And you use these powers to keep people out of entertainment.
Good luck with refactoring your ticket verification system.