Purpose of this series
No,
- harm to anyone
- unethical stuff
- exfil of data
- bypassing rate limits or hardcore scraping
We try to use hacker mentality anywhere possible. Win small things in life …
Problem
EV charging is totally a cluster fuck(well at least it is in Turkey). There are tons of companies offering charging services. All have their own applications and they are not connected by any means. One needs to keep track of all applications, register to all of them, check their charging plans and find empty slots and so on. It’s frustrating, boring and time consuming.
I lived in the TRNC ( Turkish Republic of Northern Cyprus ) for some time this year. TRNC is not a developed country so there weren’t many charges on the island. There existed no DC charging infrastructure as well so AC chargers were the only option. There were 2 charging service providers on the island. Both offered free charging which was actually pretty good. There were, unfortunately, only 2 stations near to the place I lived in. Both stations had only 1 cable/slot so as you can imagine finding empty slots was painful. I had to check the apps multiple times to see if they were available or not.
I wanted to have something that automatically checks the availability for me and sends a notification.
I wanted this project to take at max 2 hours so started playing with it.
Overview
With app we can see available stations,
App doesn’t have an english translation so I will try to translate important points.
Durum
and Meşgul
translates to Availability
and Busy
so as you can see the station I wanted to charge my car at was busy.
Setting up the local environment
I downloaded the APK of the application
I set up my burp proxy to listen on all interfaces
I had already installed burp certificate on the machine so I just skipped to the proxy step.
You can follow https://notes.morph3.blog/mobile to install burp certificates and possible mobile related notes.
1
~ λ adb shell settings put global http_proxy 10.90.14.251:8080
First run,
I started seeing some requests being sent.
When I clicked on the locate me button it was sending my coordinates as 0,0. This was not good
After some investigation I noticed this error message below in the logcat.
1
2
3
11-10 21:22:54.667 2874 2950 W GoogleApiManager: The service for com.google.android.gms.internal.location.zzay is not available: ConnectionResult{statusCode=SERVICE_INVALID, resolution=null, message=null}
11-10 21:22:54.667 2874 2874 W GooglePlayServicesUtil: com.ipitex.incharge requires the Google Play Store, but it is missing.
11-10 21:22:54.696 2874 2874 W GooglePlayServicesUtil: com.ipitex.incharge requires the Google Play Store, but it is missing.
Looked like google services was not working properly.
Could it be solved ? Yes ofc. However, I have only 2 hours at max for this project so let’s just take shortcuts.
I found my location using https://www.gps-coordinates.net/my-location. I set my location and the service returned every single available charger. The service returned pretty much everything I needed so that’s all we need for now.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
"Services":[
{
"Address":"Gazimağusa \/ KKTC",
"Amenities":null,
"City":null,
"Country":null,
"CurrentlyOpen":true,
"DcAvailable":0,
"District":null,
"ImageUrl":"REDACTED",
"Lat":REDACTED,
"Lon":REDACTED,
"MerchantID":REDACTED,
"MerchantName":"CITY MALL AVM",
"NearBy":null,
"OperatorID":7,
"OperatorType":2,
"OtherOptions":null,
"PayMethods":null,
"Phone1":"REDACTED",
"Phone2":null,
"Photos":null,
"ServiceList":[
{
"Charge":null,
"ServiceID":REDACTED,
"ServiceImgUrl":"REDACTED",
"ServiceName":"Şarj",
"ServicePrice":0.0000
}
],
"StationCode":null,
"StationDescription":"AC (22kW)",
"Status":{
"ID":1,
"Value":"Kullanılabilir"
},
"TimeZone":null,
"Title":"REDACTED",
"WorkingHours":null
},
Let’s get into coding,
Sensitive information is removed.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import json
import time
import requests
def check_availability(station_name):
"""
Checks if the target is available
"""
# coordinates are removed obviously
post_data = {"ChargePointOperatorRID":7,"FromMap":True,"Lat":0,"Lon":0,"Range":100,"filters":None}
service_url = "https://SERVICE_URL"
response = requests.post(service_url, data=json.dumps(post_data), headers={"Content-Type":"application/json"})
response_json = json.loads(response.text)
# based on our location, this one will be one of the closest so we won't loop through all
for station in response_json["Result"]["Services"]:
if station["MerchantName"] == station_name:
print(f'We found the station {station["MerchantName"]}')
if station["Status"]["Value"] == "Kullanılabilir":
print(f'We found an available slot with ID: {station["Status"]["ID"]}')
return int(station["Status"]["ID"])
print("No available slots")
return 0
def notify_user(slot_id, station_name):
data = f"Found an available slot !! {station_name} : {slot_id}"
notify_url = "https://ntfy.sh/YOUR_NOTIFY_SH_SERVER"
requests.post(notify_url, data=data)
return
if __name__ == "__main__":
while True:
slot_id = check_availability("XXX")
if slot_id > 0:
notify_user(slot_id, "XXX")
time.sleep(900) # there is an empty slot so now sleep for 10 minutes
print("User notified, sleeping for 15 minutes ...")
else:
print("No available slots, sleeping for 5 minutes ...")
time.sleep(310) # sleep for 5 minutes + 10 secs, no stupid rate limits
I copied the script to my server. I run and started waiting,
1
2
3
4
╭─root at boom in /tmp
╰─○ nohup bash -c "python3 script.py" &
[1] 616237
nohup: ignoring input and appending output to 'nohup.out'
Results
Let’s charge it !
Project took actually less than an hour. (Writing this blogpost took more lol). Now, I don’t need to check the app anymore my server does it for me.