freyta / 7Eleven-Python

A python script to check fuel prices and also lock them in
GNU General Public License v3.0
128 stars 63 forks source link

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

Open showdownhero opened 4 years ago

showdownhero commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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

alvinnguyen commented 4 years ago

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

micyew commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

@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 commented 4 years ago

@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 commented 4 years ago

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

freyta commented 4 years ago

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.

yifanfu commented 4 years ago

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

Motordom commented 4 years ago

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 commented 4 years ago

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

SongGithub commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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

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

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 commented 4 years ago

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 commented 4 years ago

@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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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

freyta commented 4 years ago

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 commented 4 years ago

@ryleyangus How do I generate the OAuth refresh token?

PinkyJie commented 4 years ago

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:

hirani89 commented 4 years ago

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 commented 4 years ago

@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 commented 4 years ago

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 commented 4 years ago

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

zipalign -v 4 au.com.fuel7eleven.apk au.com.fuel7eleven-aligned.apk
PinkyJie commented 4 years ago

@amcgavin thanks, same issue to me even after zipalign šŸ¤•

amcgavin commented 4 years ago

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

PinkyJie commented 4 years ago

@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 commented 4 years ago

@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 commented 4 years ago

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

gyrex commented 4 years ago

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 commented 3 years ago

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 commented 3 years ago

@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 commented 3 years ago

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