Skip to content
This repository has been archived by the owner on Jan 4, 2021. It is now read-only.

7-Eleven Fuel App set to be relaunched as My 7 Eleven #79

Open
showdownhero opened this issue Jun 16, 2020 · 36 comments
Open

7-Eleven Fuel App set to be relaunched as My 7 Eleven #79

showdownhero opened this issue Jun 16, 2020 · 36 comments

Comments

@showdownhero
Copy link

Obviously the fuel app is down at the moment. Based on their comment on this Facebook post they will be creating a new app called my 7 eleven.

https://www.facebook.com/132945996743236/posts/3034321299939010/?d=n

Just thought I’d give everyone a heads up

@micyew
Copy link

micyew commented Jun 16, 2020

The new My 7 Eleven is up...

Obviously we can't lock fuel now....I try to change the APP_VERSION in settings.py to "2.0.0.10867". I was able to login and lock the fuel..But the fuel docket didn't show up in my iphone new My7Eleven app...

@micyew
Copy link

micyew commented Jun 16, 2020

I think they tie the fuel docket/offers to the 711 card rather than the account as in previous version....

@alvinnguyen
Copy link

@micyew, does the Fuel Price Lock tab in the app show the locked price? If yes then I think it's still working?

@micyew
Copy link

micyew commented Jun 17, 2020

Nope....Previous version have this button "Show Voucher". Now no more. I can lock the price with this app.py after changing the version in settings.py. Everything good. But it just shows nothing in the new My7Eleven app. Something must have change in the backend. Maybe different database..?

@LynnAU
Copy link

LynnAU commented Jun 17, 2020

has anybody gone through the app with wireshark running? i'd imagine some of the api endpoints or the host itself may have changed

@PinkyJie
Copy link
Contributor

@LynnAU It seems the new app uses SSL Pinning, I used another proxy tool (https://github.com/alibaba/anyproxy) trying to inspect the requests, failed... It appears it only respected the SSL certificate issued by themselves.

@LynnAU
Copy link

LynnAU commented Jun 17, 2020

@PinkyJie that's going to be annoying, we'll have to pull the cert out from the app (if it even includes it that is). i'll take a look at it tonight and see if we can decompile the apk or something

@micyew
Copy link

micyew commented Jun 17, 2020

Getting more and more difficult to crack.....

@freyta
Copy link
Owner

freyta commented Jun 17, 2020

Just a quick snoop of a fuel lock request, it loads this URL https://app.api.7eleven.com.au/api/Stores/NearbyFuel?fuel=PULP98&lat=-37.782531&lon=144.943449 and these are the headers:
x-device-os: Android
x-device-os-version: Android: 9 - P (SDK 28)
x-device-build-version: 2.0.0
x-device-identifier: A0001
x-device-uuid: 6f4ba054-****-****-****-************
x-tz-offset: 36000
Date: Wed, 17 Jun 2020 05:28:15 GMT
x-attestation-token:
Authorization: Bearer *snipsnip*
signature: *removed*

And then with that json response it has a list of your 5 closest stores, a hash & timestamp to send on (UTC time it looks like), and your fuel type. For example (store details removed):
{"stores":{["storeId":"1001",
"name":"7-Eleven Oakleigh",
"coordinates":{},
"location":[],
"address":{},
"phone":"",
"openingHoursList":[],
"specialOpeningHours":[],
"allHours":true,
"isActive":true,
"isFuelStore":true,
"hasKiosk":false,
"features":[],
"fuelOptions":[],
"atm":true}],
"fuel":"PULP98",
"time":"2020-01-01T00:00:00.0000000Z",
"hash":"HMrd******************************/ZVRUsYrs"}

And then it uses the stores list, the timestamp, hash and the fuel type redirects to https://app.api.7eleven.com.au/api/Fuel/BestPrice?fuel=PULP98&stores=1001,1002,1003,1004,1005&time=2020-01-01T00:00:00.0000000Z&hash=HMrd******************************/ZVRUsYrs which then responds with:

{"storeId":"1336","storeName":"Wantirna","storeLatitude":-37.903332,"storeLongitude":145.085953,"ean":"56","fuelType":"PULP98","updated":"2020-06-16T19:33:00Z","price":1419,"time":"2020-01-01T00:00:00.0000000Z","hash":"IdlLV/******************************/U"}


That's all I'm gonna do for now. I've removed some identifying things.

@freyta freyta pinned this issue Jun 17, 2020
@yifanfu
Copy link

yifanfu commented Jun 21, 2020

@freyta Out of curiosity, how did you get the response contents with SSL pinning enabled?

@Motordom
Copy link
Contributor

There's a few ways to bypass, I use ssl-kill-switch2 on iOS, there's similar for Android I presume (not sure what Freyta used)

@peter-kerr1
Copy link

How much work would it be to update the python script to interact with the new app?

@SongGithub
Copy link

Just a quick snoop of a fuel lock request, it loads this URL https://app.api.7eleven.com.au/api/Stores/NearbyFuel?fuel=PULP98&lat=-37.782531&lon=144.943449

I think as long as coordinate (lat) can be overridden with a "desirable" one this app is feeding in, the app will be working correctly with new API.

not sure if there is any TLS comm issue with the new API though.

@gyrex
Copy link

gyrex commented Jun 26, 2020

Firstly, I just want to thank @freyta for this wonderful project. I was just wondering if there's been any progress with getting this working with the new app/process?

@amcgavin
Copy link

Hate to be the bearer of bad news.

I've spent some time looking through the Android app and found the source of these headers:

x-attestation-token

  • required on the /api/Fuel/Lock call (is left blank on the other preparing calls)
  • protects API calls from unverified sources
  • comes from SafetyNet

SafetyNet has been proven to be difficult to circumvent.
It's not feasible to generate this token outside an app context (i.e., in a web script).
It's also not possible to repackage the app with the ability to set the GPS location on non-rooted devices.

signature

  • protects API calls from tampering (e.g., changing latitude and longitude)
  • comes from libapikey.so
  • compiled module, difficult to decompile

Previously, the signature was generated in Java which was trivial to decompile and re-implement (all parameters were visible, along with the algorithms used).
It's still possible to use this new module as it will still accept arguments and return a signature but it's difficult to create an interface.

Early signs point to a script like this existing one is not feasible due to SafetyNet.
However, using emulators is a viable, albeit less convenient solution.

@yifanfu not sure how freyta did it, but I recompiled the app with a different security config which allows user certificates (and removes the pinning):

diff --git a/res/xml/network_security_config.xml b/res/xml/network_security_config.xml
index df1194a..3e2d64c 100644
--- a/res/xml/network_security_config.xml
+++ b/res/xml/network_security_config.xml
@@ -5,16 +5,9 @@
             <certificates src="@raw/rapidsslrsa2018" />
             <certificates src="@raw/digicertglobalrootca" />
             <certificates src="system" />
+            <certificates src="user" />
         </trust-anchors>
     </base-config>
-    <domain-config cleartextTrafficPermitted="false">
-        <domain includeSubdomains="true">*.7eleven.com.au</domain>
-        <trust-anchors>
-            <certificates src="@raw/isrgx4" />
-            <certificates src="@raw/isrgx3" />
-            <certificates src="@raw/isrgrootx1" />
-        </trust-anchors>
-    </domain-config>
     <debug-overrides>
         <trust-anchors>
             <certificates src="system" />

@k0rtina
Copy link

k0rtina commented Jun 28, 2020

Hate to be the bearer of bad news.

I've spent some time looking through the Android app and found the source of these headers:

x-attestation-token

  • required on the /api/Fuel/Lock call (is left blank on the other preparing calls)
  • protects API calls from unverified sources
  • comes from SafetyNet

SafetyNet has been proven to be difficult to circumvent.
It's not feasible to generate this token outside an app context (i.e., in a web script).
It's also not possible to repackage the app with the ability to set the GPS location on non-rooted devices.

signature

  • protects API calls from tampering (e.g., changing latitude and longitude)
  • comes from libapikey.so
  • compiled module, difficult to decompile

Previously, the signature was generated in Java which was trivial to decompile and re-implement (all parameters were visible, along with the algorithms used).
It's still possible to use this new module as it will still accept arguments and return a signature but it's difficult to create an interface.

Early signs point to a script like this existing one is not feasible due to SafetyNet.
However, using emulators is a viable, albeit less convenient solution.

@yifanfu not sure how freyta did it, but I recompiled the app with a different security config which allows user certificates (and removes the pinning):

diff --git a/res/xml/network_security_config.xml b/res/xml/network_security_config.xml
index df1194a..3e2d64c 100644
--- a/res/xml/network_security_config.xml
+++ b/res/xml/network_security_config.xml
@@ -5,16 +5,9 @@
             <certificates src="@raw/rapidsslrsa2018" />
             <certificates src="@raw/digicertglobalrootca" />
             <certificates src="system" />
+            <certificates src="user" />
         </trust-anchors>
     </base-config>
-    <domain-config cleartextTrafficPermitted="false">
-        <domain includeSubdomains="true">*.7eleven.com.au</domain>
-        <trust-anchors>
-            <certificates src="@raw/isrgx4" />
-            <certificates src="@raw/isrgx3" />
-            <certificates src="@raw/isrgrootx1" />
-        </trust-anchors>
-    </domain-config>
     <debug-overrides>
         <trust-anchors>
             <certificates src="system" />

Any recommendations on emulator and APK to use? PS thanks @freyta for the usage of your app, used it about 30-40 times.

@amcgavin
Copy link

@k0rtina To be honest with you I haven't looked into it. On the ozbargain thread PokemonGo methods (https://www.reddit.com/r/PokemonGoSpoofing/) are mentioned.

@ryleyangus
Copy link

If anyone is interested, I wrote up a quick and nasty Python script which implements the current signature generation requirements. Querying nearby stores and fuel prices requires an OAuth token (not supplied), but the signature generation can be validated with the health check and "appconfig" requests. I haven't locked in fuel recently, but for what its worth I haven't come across the "x-attestation-token" on iOS yet.

Link

@amcgavin
Copy link

Nice work!
Have you managed to complete the last step of the lock in?
iOS will require(?) the x-device-check-token to be set.

@ryleyangus
Copy link

I haven't tried that yet, but I'll keep it in mind and post any further notes here.

@freyta
Copy link
Owner

freyta commented Jun 29, 2020

Definitely interested in seeing it. 🙃

Just an FYI, you can't use the Android signature with iPhone headers, it produces a "signature mismatch" error

@hirani89
Copy link

@ryleyangus How do I generate the OAuth refresh token?

@PinkyJie
Copy link
Contributor

PinkyJie commented Jul 5, 2020

Hey guys, I spent some time on hacking the login page and realised it's implemented by Azure AD D2C OAuth flow, with the help of the Azure document, I finally figured out the flow to get access token/refresh token.

Here is the snippet written in Node.js to get the access/refresh token: https://runkit.com/wenbo/7-eleven-api-test

@hirani89 Hope this can help answer your question.

Note:

  • there's a login/password inside, it's just a random account I registered for testing purpose, I feel it's okay to make it public, please don't modify the password 🤦
  • I haven't tried the token with the APIs posted by @ryleyangus above, gonna do it later to check if the token is working or not. Full API call example updated (nearby stores API provided by @ryleyangus 👍 )

@hirani89
Copy link

hirani89 commented Jul 5, 2020

If anyone is interested, I wrote up a quick and nasty Python script which implements the current signature generation requirements. Querying nearby stores and fuel prices requires an OAuth token (not supplied), but the signature generation can be validated with the health check and "appconfig" requests. I haven't locked in fuel recently, but for what its worth I haven't come across the "x-attestation-token" on iOS yet.

Link

I tried running this python script using the refresh token generated by the js code. I get Hash mismatch

@PinkyJie
Copy link
Contributor

PinkyJie commented Jul 5, 2020

@hirani89 I updated my script to include a "nearby stores" API call (with the example provided in the python script), could you try again to see if it works?Just use the same link above https://runkit.com/wenbo/7-eleven-api-test (make sure you are on v1.0.3).

@PinkyJie
Copy link
Contributor

PinkyJie commented Jul 7, 2020

Hey @amcgavin , I was trying to remove SSL pinning with your solution, but the recompiled apk can't be opened, I checked the log with adb logcat, it says libapikey.so is missing...

AndroidRuntime: java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/au.com.fuel7eleven-MJ9OaVTWjkE7Y23n2u69FA==/base.apk"],nativeLibraryDirectories=[/data/app/au.com.fuel7eleven-MJ9OaVTWjkE7Y23n2u69FA==/lib/arm64, /system/lib64, /system/product/lib64]]] couldn't find "libapikey.so"

any ideas? The steps I was following are:

  1. decompile the apk apktool d au.com.fuel7eleven.apk
  2. edit the config file res/xml/network_security_config.xml
  3. recompile the apk apktool b --use-aapt2 au.com.fuel7eleven (it throws error without --use-aapt2)
  4. generate a key for signing keytool -genkey -v -keystore my-release-key.keystore -alias alias_name -keyalg RSA -keysize 2048 -validity 10000
  5. sign the apk jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore my-release-key.keystore au.com.fuel7eleven.apk alias_name

@amcgavin
Copy link

amcgavin commented Jul 8, 2020

@PinkyJie you'll need to zipalign after you sign.

zipalign -v 4 au.com.fuel7eleven.apk au.com.fuel7eleven-aligned.apk

@PinkyJie
Copy link
Contributor

PinkyJie commented Jul 8, 2020

@amcgavin thanks, same issue to me even after zipalign 🤕

@amcgavin
Copy link

amcgavin commented Jul 9, 2020

Hmm, if you re-decompile your built one, are the libraries present?

@PinkyJie
Copy link
Contributor

@amcgavin not sure how to find the libraries 🤦 not android developer. Did you find the spec for API api/fuel/lock? Correct me if I'm wrong, I'm thinking we already know how to get the access token, if we know the spec of lock API, we can lock now, right? Or we still require some specific key from libapikey.so? From the python script provided above, it seems we don't need any other info if we know both the API spec and access token.

@ryleyangus
Copy link

@PinkyJie As amcgavin posted earlier, the issue preventing price locking independently of the My 7-Eleven app is generating a valid x-attestation-token (Android) or x-device-check-token (iOS). You also need the customer "loyaltyId", but this can be retrieved from "https://app.api.7eleven.com.au/api/profile" by generating a signature using the general method I described. I have a workaround for the x-device-check-token requirement, but its not a long-term solution (7-Eleven could very easily patch it). I'm happy to look into generating a proper x-device-check-token, but this might not be practical / might take a long time to achieve.

BTW Thanks for your work on describing and implementing the Azure authentication process.

@PinkyJie
Copy link
Contributor

@ryleyangus I see, thanks for explanation, hope you guys can bring us good news soon. 👍

@gyrex
Copy link

gyrex commented Oct 10, 2020

Hi guys, just seeing if there's been any progress on this? Is it likely we'll be able to use this in the future or have 7 eleven locked this down for good?

@LynnAU
Copy link

LynnAU commented Nov 23, 2020

In case anyone is still holding out for any news/updates on this. I've been looking into the SafetyNet api that google uses this past week or so. Google basically scraps data from the device, and checks on its servers if it's genuine/untampered, sends those results back to the app which passes them onto 7/11's backend where they verify them. The payload is signed by google so the api will have the information required to decrypt it and read the contents.

There is no spoofing this/generating it in a web script. I can't think of anything at least to fool the api into thinking the request came from a genuine device (unless the developers got lazy and skipped some verification steps).

I've managed to root a spare galaxy s7 and can gps spoof to get cheap fuel again.

@ryleyangus
Copy link

@LynnAU Up until a few weeks ago it was possible to use any single character as the "x-device-check-token" header value. About the same time 7-Eleven fixed this oversight, they also blocked the ability to easily overwrite an existing fuel lock with a better fuel lock. There might still be some low-hanging validation bugs, but I've changed my process to using iOS DeviceCheck tokens.

@barrett50
Copy link

@LynnAU @ryleyangus
That's good work! Do either of you have anything working to share please? I'd love to learn more.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests