 engineering the Albertine app for fun and profit. Let's first introduce myself. I am Nick Vars. I work as a knock engineer at Speakup. They do voiceover IP things like was presented. And by night, I'm a hacker, thinker, and a hosting provider. I do some hosting provider work for small businesses in and around NSW. So let's get started. Why did I choose the Albertine to reverse engineer? Well, they're close by to me. And they give benefits to people that use a bonus card. And the bonus card is meant to be linked to you as a person. And that gives you all kinds of discounts. And another reason was that, I mean, other supermarkets also have an extensive API. So maybe you'll find some inspiration from this. And reverse engineer, for example, the YAML app or the app in another country. So let's explore the API. We have an app, and this is a very simple screenshot of how the app can look. This is some discounts and some products that were lost last month. And what happens in the background when you open this page is that your app does a get request to this URL. And how can we find this out? How can we see what the app is doing in the background? Well, it's very easy. There are these tools. There are other tools as well. But these are Charles and Burp Suite. And what you can do with these is man in the middle your own phone. That can be very interesting. What you need to do is install a certificate authority on your phone. It needs to be trusted. And once you do that, the app hasn't been secured against this because the most bank apps will be and other apps as well. But the Albertine app is not. So when we install our own CA certificates, we can listen to the traffic. If you have a Mac with a M1 processor or M2, you can make this easier because, well, iPhone and iPad apps can run on your laptop. And that makes it so you don't have to install certificate authorities on your phone. Charles can do that for you. Once you open Charles, all traffic flows through that. And that makes it a lot easier to reverse engineer. So here's an example of something you might want to do in the app or data you want to get from the app. They have these loyalty programs where you can save up for, in this case, towels. And every time you get a full card with eight stamps, you get towels for three or four euros. So what if you want to track your progress in this? Say you visit the Albertine very much and you want to see how you progress alone. Well, you just do an API request to this URL here. And what you get back is a JSON response. It's very handy. This is how the app works in the background. Your app is just a front end for their API. They've built an API, then built a front end, and that is how the app works. So we have the balance right there. It's very handy. And you can track that over time in pretty Grafana dashboards. I'm a great fan of that. I promised you for profit. So here's why it's for profit. Albertine is a thing called the bonus box. What you need to do every week is go in there and pick out what kind of discounts you want. And as you guessed, there's an API call for that too. You just do a request to that URL there. Give the start date. You get back a JSON response with other products that will be discounted for you and you only. And we can also activate those products. You send a few parameters. And then the offer is activated. And you have discounts that you wouldn't have if you weren't going to go into the app every week and manually activate those offers. So there's a little bit of profit. I did exactly that. I wrote a script. And it goes down all the things that I can activate. And that makes it that I have cheaper groceries. I mean, Albertine is not the cheapest. If you're from the Netherlands, you'd know that. But there can be if you have the right offers. Here's the thing, though. Albertine made it pretty annoying to work with this API. It used to be that you can just send a login request via posts. And then you would be able to log in, get a token, and do all these API requests. What they did a short while ago is enable CAPTCHA on that login process. And there is no other way to get an authentication token. So what you need to do is, oh, sorry. What you need to do is man in the middle, either with a Mac that can run iOS apps, or you need to install a CA certificate on your phone, listen to the request it makes. And then you will see that it does a request for a refresh token. And that refresh token gives you, you can submit a request with that request token. And it gives you a new authentication token and a request token. So if you do that, let's say every half hour, you put that refresh token in a database. That gives you quite a long time of playing with the API. So what if you want to play around with this API for yourself? So some of you might have already seen this, but I flashed it a couple of seconds ago. This is a Swagger page. Everyone that works with APIs will know what this is. And this is basically some documentation for the Albertine API. And because I want all of you to play around with this, I have released this Swagger page as well as the open API specification. So you can scan this QR code. And well, go ahead for yourself. It's on GitHub, too. So if you figure out more API requests from the app, please submit a pull request. I really appreciate that. And I know scanning QR codes is scary. At the end, I will give you some ways to contact me. Like I said, the Albertine is not unique in these. A lot of apps work this way. This is an example for the YAMBO. When I click on the plus to add this delicious hamburgers a la minutes, it just sends a pull request to this URL. And the funny thing is, I'm not even authenticated here. I just downloaded the app and clicked the plus button. And I saw this in the app. So that means that YAMBO is still tracking users that haven't created an account yet. It's quite interesting. So that's enough about the API. I've given you some examples of how I use it. And I've given you a way to play with it yourself. And I'd now like to talk about the brief story of Random Bonus Cards.nl. And some people started laughing. RandomBonusCards.nl is exactly what you think it does. Once you go there, you'll be presented with a bonus card. That means that Albertine can track your purchases. Because Albertine uses the bonus card to track you and in return, you get discounts. But most people don't want to be tracked. So here is RandomBonusCards.nl. It's meant to be used on your phone. And it works really well. A lot of people use it. How do I know a lot of people use it? I can track website visitors. I have a Motomo install on this website, so I can track that. But I want to know how many people actually go to the Albertine and scan that code. There are others as well. I'm not the only one who does this. Here are three examples. BonusCard.nl, WellBonusGeneData.nl, and BonusCard.nl. And these do exactly the same, although I don't know if these actually generate random BonusCards or if these are doing a similar thing to me. Because, well, I thought one day, what if I put my own BonusCard on there? What if I only put my own BonusCard on there? So I put several on them on there. You might think, well, that breaks the promise of a random BonusCard. It's not random anymore. That's true. But the reason you like to use a random BonusCard is to have anonymity while you're shopping. And once there are enough users on the same BonusCard, the profile gets so contaminated that the data isn't of use anymore to the Albertine. So I did that. And here is a map of all the Albertines that people did groceries with my BonusCard. And this is only June. Because the Albertine app gives you an API call to track receipts. And that receipts has data of the address to store. So once you get that address, and you put that through a location API, you get the latitude and longitude. And then you store it in a database, and you get this. I have more statistics as well. Here is how many people used my website. It's 1,305. And this is just in June. Here you can track the amount of times it was used per day. So it was quite a busy day there on the 18th. Not sure what's up with that. Of course, Albertine isn't the only app that has a private API in Jumbo, isn't as well. There are others. And has anyone here heard of Go Scooters? OK, a couple of people. Go Scooters are a rental service where you can download an app and unlock a scooter that's on the street. People don't often treat them lightly. They say, don't be gentle. It's a rental a bit too far, if you ask me. If you download the app, you get this pretty map. And you can see all the vehicles that are around you. So let me zoom out here, and I'll go to Almere. And you can see how far assumed out I am and how many dots you can see. So that means that the data must be coming from somewhere, right? Oh, yep. And I'd actually like to do this with a live demo. So OK, let's see if I can drag my terminal over to the next screen. Yep, there we go. And can I maximize this and then make the text a little bigger? All right. So once you do an API request to this URL here, user.api.gourban.services, what do you think will happen? Well, I'm going to spoil this for you. I'm just going to press Enter and get a huge JSON request back, the JSON response back, with a lot of data, actually, and more data than I expected. Some of these coordinates are pretty precise, and you can also see the license plate and the state of charge of these vehicles. Not sure if this is meant to be this way. I'm guessing there can be some optimizations made here. I'd like to go back to this statistic here. There's a reason I showed June instead of July. And that is my scraper runs every 30 minutes. And when it does that, it asks the obtain API, hey, can you give me all four receipts on my account? And there's no way to limit that request. So what started happening was that script started spewing out error messages. And those error messages were 504 timeouts, gateway timeouts. So what happened was that the request got so big that the underlying servers weren't able to handle my request in time. Because my scraper runs every 10 minutes, or every 30 minutes, I put it down a little bit. There's less strain on their databases. But I think some engineer at Albatyn noticed because they limited the results I got back. I got curious, how big is that response? It's about 20,000 lines of JSON. So I can understand why someone did something about that. The only problem is they didn't limit it on the last receipts. So when I go into the app now and I check my latest receipts, the latest one is from October last year. So no more pretty stats for me. The discard looks quite empty for today and the rest of the month, July as well. What can you do? We talked about the Go sharing, and we've checked out the Go Urban API. So what's the moral of the story? Just open up your APIs. I mean, you've already built it. And once you do that, you give other people the possibility to create amazing things. One example I heard was someone that created a scanner app where you can scan a barcode, and it will automatically add that to your shopping list. It's beneficial to Albatyn because it creates convenience. And once it's on your Albatyn shopping list, well, then you're most likely to go to the Albatyn to buy that product. And you've already built it again. So why not release it? I mean, you can't release it the way it is right now. You have to do some tweaks, mostly with authentication. And the past can be cleaned up as well. But I don't care if Albatyn releases this the way it is. And I really hope they do. Another point, by the way, is data freedom. You can track your own groceries if you decide not to use randombonuscard.nl, which I highly, highly recommend. So what can you do? Does anyone know what these are? Awesome. I'm going to explain them anyway. These are Amazon Dash buttons. The idea is that you order Amazon Dash buttons. And once you push that button, one of these items will be added to your shopping cart on amazon.nl or wherever you're from. And it will also place the order for you if you want. You could make your own one of these. You can track the Albatyn delivery time slots. And you can also just place an order for delivery through the Albatyn app, which is what I did, of course, to try it out. Because once the courier comes, you pay at the door. So that makes it possible to place an order like that. So I'd like to thank you all for attending my talk. And if you want to contact me, that's how you can do that. Thank you. Thank you so much, Nick. That was amazing. And thanks, dear, dear audience, for applauding a live demo. I think that is a very cool thing to do. Thank you. I didn't even bring an offer to the demo gods. Are there any questions? And if you have a question, please move over to the microphone and ask a question there. So the people in the live stream also can hear your question. Thank you so much. The person in the back was first, so you can go first. I apologize if I missed this, but are you actually able to generate a random barcode for the bonus cards? Is there an algorithm to that, or is there just like any random unique ID would be valid? Yeah, the bonus card is just a AOM-13 barcode. And there's a certain range of card numbers. And what you can do is generate your own and ask the Albertine API if that is a valid bonus card or not. And that is actually how randombonuscard.nl worked in the beginning. It just, once you load the page, it generated one. And if it was valid, it will show that to you. I changed it up a bit for, well, statistics reasons. But yeah, there is a way to actually generate random bonus cards, random bonus cards. Yeah. Thank you for your question. Next one up, go ahead. Superman. Thanks. Thanks for the interesting talk. I saw you had 272 of the Handuk Segel things. How did you get those? And was that the random bonus card account? Yep. Yep, that's exactly it. Well done, well done. If you need some, by the way, just come talk to me and I'll transfer some to you. It's no problem. Thank you so much. Go ahead. So apart from transaction costs and interesting location data, do you have any other interesting data that you got via the not-so-random bonus card? I'm mainly thinking of interesting personal data. Right. No. It's very hard to, and I didn't actually try, but it's very hard to track individual users that use the website. I can see that the same person that used the bonus card in Almere also used it in Amsterdam a week later. I can't see that. And I don't even want to know that either. That's good to know. The promise is anonymity, and I want to keep it that way. I was wondering, do you have any tips because you were currently discussing how to reverse engineer REST APIs? Yep. I was wondering, do we have also have any tips to reverse engineer GQL APIs or WebSockets or other types of infrastructures? The same method I used for this REST API also works for GraphQL apps or WebSockets. Once you man in the middle, you can see all the traffic that the app generates, and you can also see the responses from the server. I meant more like, do you know any civic tooling or any? Yeah, the same tooling I showed you, so WebSuite and Charles can also see that kind of traffic. And the way I documented this API was with a postman collection. So what I did is copy the request as curl from Charles, in this case, and then paste that into postman because postman can understand curl commands. Yeah, of course. But postman isn't able to understand WebSockets, right? Sorry? A postman doesn't understand WebSockets. Yeah, that's true. So you need another tool for that. I don't have experience with WebSockets. Sorry. Go ahead. I was wondering if you racked up that many Handoek Seegels. How many AirMiles did you rack up? And what did you buy with that? No comment. Another one, please go ahead. Oh, yeah. Another question in the for-profit part. This likely also means that you can get all the product details in pricing and do nice comparisons with that. Exactly, yeah. That's one way you could use this API. Just grab the same product and the price and see how that develops over time. Yeah, do you have anything available for that, or is that something that? The Swagger I released and the OpenHPI specifications have some calls for listing products in certain categories or searching for products. So that should help you with that endeavor. You could also do the same thing as I did and listen to the traffic that it generates and see what it does when you tap a certain product. You most likely get a product ID and can query that for the price details. OK, thank you. This is maybe more of an Albert Hein question than a reverse engineering question. Sure. But would it be possible for someone to take one of the random bonus cards and sign up in the Albert Hein app, as though it was their bonus card, enroll in the Cope Zagels program, and then harvest the Cope Zagels from inattentive people at checkout that weren't noticing that they were purchasing some extra coupons? To clarify, by the way, I didn't enable the Cope Zagels on random bonus cards I don't know. I want to keep you as a user. But no, it's not possible to claim this account to a different account because it's already linked to mine. So once you try that, it will say this bonus card has already been linked to an account and you cannot link it to another one. You had the Pursión Liga bonus, which changes every week. But I noticed in the API call that there's a start date and an end date. Can you also query the bonus that you get next week or next month? You can query the bonus you get next week from Thursday of the previous week. So once it is Thursday, you can do that request with the start date. And the start date should be Monday. And that gives you back the results. If you do that before then, you will get back an error message. So unfortunately, no. Go ahead. Yeah, so I myself use just an unactivated bonus card. I grabbed from near the till, which also works. Random bonus card is a lot better. So thanks for that. Is there any chance that it generates a random one which you then register, as you just said, which then collides and maybe steals away my bonus card? Like I said before, the way it used to work was that it generated a random number and checked that against the API and then showed you that code or not. If that code was already linked to a different Albertine account, I'd actually not show it, but generate a new one because, well, someone can enable corp tables and that would encode costs on the users. And I don't want that. OK, so it is possible that my unactivated bonus card was randomly generated by the app and you've registered it? That is, in theory, possible. Yes. OK. How large is the key space around the button? I don't know off the top of my head. I can look that up for you. Cheers. Thanks. Thank you very much. I have one question from the internet, from Turim. He was wondering on the random bonus card if you automatically enabled all bonuses on it. Yep, that's a service from me to you. If you use that website, I showed you a screenshot of the script. On the screen, yes. Yeah, thank you. Sorry. How it is. Where is my screenshots? Here it is. It does this every week for all the bonus cards that are on randombonuscard.nl. And what it does is it enables Albertine Premium for reasons I'm not going to comment on. You can figure that one out. But it also gives me 10 offers to choose from instead of five. What you could do is bring in some more logic. For example, if you're a fan of a certain type of food, you could do some pattern matching and see when that is in your bonus box and then use that to activate that offer every week. What this does is just activates the first 10. So pretty simple, but yeah, it works. Thank you. I see another question. Oh, sorry. I think that was it then. Thank you. Now we have time for one more. Because I was interested. You told me something about the Albertine hasn't reached out to you yet, right? No, no. I'd really like to hear from them. I want to know. So if anyone has any connections, I mean, oh, here we have the awesome. Come talk to me after. Awesome. Thank you. Thank you. Thank you again, Nick. I think I'll put my contact details on there again. So you know. Can we get it? Oh, yeah, here. If you want to contact Nick, his contacts are on the sheets. You have been an amazing crowd. Give him the last big round of applause because I think you did a great job. Thank you.