Skip to content

Instantly share code, notes, and snippets.

@itsnebulalol
Last active November 16, 2024 03:18
Show Gist options
  • Save itsnebulalol/99c71f23e462f9c08424417716dc49f2 to your computer and use it in GitHub Desktop.
Save itsnebulalol/99c71f23e462f9c08424417716dc49f2 to your computer and use it in GitHub Desktop.
Reverse engineered Verizon API

Verizon API

  • Reversed using Firefox Network Inspector
  • Python POC to see usage data is attached

secure.verizon.com

POST /signin/vzapps/api/v1/getentrypoint Prepares authentication?
Payload
name data type description
entryType string N/A
clientId string N/A
authFlowType string N/A
tSessionId string N/A
gotoUrl string N/A
encuid string N/A
im bool N/A
username string verizon username/phone number
Responses
http code responses
200 username
200 statusCode, typeCode, vzMyBizCustomerInd, n, username, isUniversalProfile, isB2BorPrepay, universalID, incplt
POST /signin/vzapps/api/v1/authenticate Authenticates
Payload
name data type description
username string username/phone number
password string verizon password
deviceFP object huge fingerprinting object
- screenWidth int N/A
- screenHeight int N/A
- screenColourDepth int N/A
- timezone int N/A
- installedPlugins string N/A
- installedFonts string N/A
- userAgent string N/A
- appName string N/A
- appCodeName string N/A
- appVersion string N/A
- platform string N/A
- product string N/A
- productSub string N/A
- vendor string N/A
- language string N/A
clientId string N/A
gotoUrl string N/A
authFlowType string N/A
tSessionId bool N/A
dfpStatus string N/A
sourceURL string N/A
intent string N/A
im bool N/A
Responses
http code responses
200 gotoUrl, flowMessage, isB2BorPrepay, flowCode
POST /signin/vzapps/api/v1/initiatecvs Initiate 2fa session
Payload
name data type description
rbStatus string N/A
tSessionId string N/A
im string true/false
Responses
http code responses
200 flowMessage, allowCQA, maskedMDN, flowCode, responseCode, data {listOfDevices [{deviceType, deviceID}]}, responseMessage, requestID, transactionID
POST /signin/vzapps/api/v1/stepupcomplete Finishes 2fa
Payload
name data type description
dfpStatus string N/A
tSessionId string N/A
sourceURL string N/A
Responses
http code responses
200 nonce, username, gotoUrl, scope, flowMessage, stepUpType, flowCode, acr_values

login.verizonwireless.com

OPTIONS /accessmanager/public/adaptiveauth/2fa/polling ?
Responses
http code responses
200 Empty response
? A client error occurred
POST /accessmanager/public/adaptiveauth/2fa/polling Polls for 2fa
Payload
name data type description
deviceID string required on first run, this is what sends the 2fa notif
requestType string 2FA_INITALIZE (first run), 2FA_UPDATE
transactionID string N/A
Responses
http code responses
200 responseCode, data {legalMessage2, legalMessage, legalMessage3, legalMessage4, legalMessage5, title, component}, responseMessage, eventTime, requestID, transactionID

POST /digital/nsa/secure/gw/myusage/usagMtnDetails Usage details
Payload
name data type description
allLineFlag string true/false
Responses

Extremely confusing. Seems to return the web page itself but in JSON. Listed is some common values.

value json path
phone number body.sectionTemplates.0.sections.0.contents.0.items.3.itemValue
plan body.sectionTemplates.0.sections.0.contents.0.items.8.itemValue
4G data body.sectionTemplates.0.sections.1.data.primaryDataCategoryList.0.dataUsed
4G data limit body.sectionTemplates.0.sections.1.data.primaryDataCategoryList.0.totalDataLimit
4G data units body.sectionTemplates.0.sections.1.data.primaryDataCategoryList.0.dataUnits
hotspot data body.sectionTemplates.0.sections.1.data.primaryDataCategoryList.1.dataUsed
hotspot data limit body.sectionTemplates.0.sections.1.data.primaryDataCategoryList.1.totalDataLimit
hotspot data units body.sectionTemplates.0.sections.1.data.primaryDataCategoryList.1.dataUnits
sms body.sectionTemplates.0.sections.5.contents.0.items.3.itemValue
minutes body.sectionTemplates.0.sections.5.contents.0.items.2.itemValue
GET /digital/nsa/secure/gw/devices/deviceDetail Device details
Parameters

None

Responses

Much less confusing than usagMtnDetails. Seems to return the web page itself but in JSON. Listed is some common values.

value json path
device info body.sections.0.sections.0.data.0
- model productDisplayName
- simid simId
- imei deviceId
- formatted number displayMtn
- is eSIM eSimActive
- is pSIM pSimActive
- plan planUsageInfo.planName
payment info object body.sections.0.sections.0.data.0.paymentInfo
- has balance hasPayOffBalance
- loan amount loanAmount
- loan amount paid loanAmountPaid
- remaining balance remainingBalance
- loan start loanStartDate
- loan end loanEndDate
- pending payments pendingNumberOfInstallments
- paid payments numberOfInstallmentsBilled
plan info object body.sections.0.sections.0.data.0.accountPlan
- data dataUsed
- data limit dataPlan
- data units unitOfMeasureCDForData
- sms messageUsed
- minutes minutesUsed

# Written by Nebula
import requests
from time import sleep
from uuid import uuid4
username = ""
password = ""
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
"Content-Type": "application/json;charset=UTF-8",
"Accept": "application/json, text/plain, */*",
"Pragma": "no-cache",
"Cache-Control": "no-cache",
"Accept-Encoding": "gzip, deflate, br, zstd",
}
session = requests.Session()
## Part 1
## Get needed cookies
payload = '{"entryType":"e1","clientId":"MVO","authFlowType":"BASIC","tSessionId":"{{UUID}}","gotoUrl":"","encuid":""}'
r = session.post(
"https://secure.verizon.com/signin/vzapps/api/v1/getentrypoint",
headers=headers,
allow_redirects=False,
data=payload.replace("{{UUID}}", str(uuid4())),
)
print(r.text)
## Part 2
## Partial login
payload = '{"entryType":"e2","im":false,"clientId":"MVO","authFlowType":"BASIC","username":"{{USERNAME}}","tSessionId":"{{SESSIONID}}"}'
r = session.post(
"https://secure.verizon.com/signin/vzapps/api/v1/getentrypoint",
headers=headers,
allow_redirects=False,
data=payload.replace("{{USERNAME}}", username).replace(
"{{SESSIONID}}",
session.cookies.get_dict()["igAmSessionId"].replace("POE-D-", ""),
),
)
print(r.text)
## Part 3
## Authenticate
payload = '{"username":"{{USERNAME}}","password":"{{PASSWORD}}","deviceFP":"{\\"screenWidth\\":1440,\\"screenHeight\\":900,\\"screenColourDepth\\":30,\\"timezone\\":240,\\"installedPlugins\\":\\"internal-pdf-viewer;internal-pdf-viewer;internal-pdf-viewer;internal-pdf-viewer;internal-pdf-viewer;\\",\\"installedFonts\\":\\"cursive;monospace;serif;sans-serif;fantasy;default;Arial;Arial Black;Arial Narrow;Arial Rounded MT Bold;Comic Sans MS;Courier;Courier New;Georgia;Impact;Papyrus;Tahoma;Times;Times New Roman;Trebuchet MS;Verdana;\\",\\"userAgent\\":\\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36\\",\\"appName\\":\\"Netscape\\",\\"appCodeName\\":\\"Mozilla\\",\\"appVersion\\":\\"5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36\\",\\"platform\\":\\"MacIntel\\",\\"product\\":\\"Gecko\\",\\"productSub\\":\\"20030107\\",\\"vendor\\":\\"Google Inc.\\",\\"language\\":\\"en-US\\"}","clientId":"MVO","gotoUrl":"","authFlowType":"BASIC","tSessionId":"{{SESSIONID}}","dfpStatus":"N","sourceURL":"https://secure.verizon.com/signin","intent":"","im":false}'
r = session.post(
"https://secure.verizon.com/signin/vzapps/api/v1/authenticate",
headers=headers,
allow_redirects=False,
data=payload.replace("{{USERNAME}}", username)
.replace("{{PASSWORD}}", password)
.replace(
"{{SESSIONID}}",
session.cookies.get_dict()["igAmSessionId"].replace("POE-D-", ""),
),
)
print(r.text)
if r.json()["flowMessage"] == "VERIFY":
## Part 3.1
## Send notification for 2fa
payload = '{"rbStatus":"","tSessionId":"{{SESSIONID}}","im":"false"}'
r = session.post(
"https://secure.verizon.com/signin/vzapps/api/v1/initiatecvs",
headers=headers,
allow_redirects=False,
data=payload.replace(
"{{SESSIONID}}",
session.cookies.get_dict()["igAmSessionId"].replace("POE-D-", ""),
),
)
print(r.text)
cvs_json = r.json()
transaction_id = cvs_json["transactionID"]
device_id = cvs_json["data"]["listOfDevices"][0]["deviceID"]
## Part 3.2
## Poll for successful 2fa
poll_headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
"Content-Type": "application/json;charset=UTF-8",
"Accept": "application/json, text/plain, */*",
"Pragma": "no-cache",
"Cache-Control": "no-cache",
"Accept-Encoding": "gzip, deflate, br, zstd",
"Access-Control-Request-Method": "POST",
"Access-Control-Request-Headers": "content-type",
"Referer": "https://secure.verizon.com/",
"Origin": "https://secure.verizon.com",
}
r = session.options(
"https://login.verizonwireless.com/accessmanager/public/adaptiveauth/2fa/polling",
headers=poll_headers,
)
print(r.text)
payload = '{"deviceID":"{{DEVICEID}}","requestType":"2FA_INITIALIZE","transactionID":"{{TRANSACTIONID}}"}'
r = session.post(
"https://login.verizonwireless.com/accessmanager/public/adaptiveauth/2fa/polling",
headers=headers,
allow_redirects=False,
data=payload.replace("{{DEVICEID}}", device_id).replace(
"{{TRANSACTIONID}}",
transaction_id,
),
)
print(r.text)
sleep(3)
while True:
poll_headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36",
"Content-Type": "application/json;charset=UTF-8",
"Accept": "application/json, text/plain, */*",
"Pragma": "no-cache",
"Cache-Control": "no-cache",
"Accept-Encoding": "gzip, deflate, br, zstd",
"Access-Control-Request-Method": "POST",
"Access-Control-Request-Headers": "content-type",
"Referer": "https://secure.verizon.com/",
"Origin": "https://secure.verizon.com",
}
r = session.options(
"https://login.verizonwireless.com/accessmanager/public/adaptiveauth/2fa/polling",
headers=poll_headers,
)
print(r.text)
payload = '{"requestType":"2FA_UPDATE","transactionID":"{{TRANSACTIONID}}"}'
r = session.post(
"https://login.verizonwireless.com/accessmanager/public/adaptiveauth/2fa/polling",
headers=headers,
allow_redirects=False,
data=payload.replace(
"{{TRANSACTIONID}}",
transaction_id,
),
)
print(r.text)
if r.json()["responseMessage"] == "Completed":
break
sleep(3)
## Step 4
## Complete login
payload = '{"dfpStatus":"N","tSessionId":"{{SESSIONID}}","sourceURL":"https://secure.verizon.com/signin"}'
r = session.post(
"https://secure.verizon.com/signin/vzapps/api/v1/stepupcomplete",
headers=headers,
allow_redirects=False,
data=payload.replace(
"{{SESSIONID}}",
session.cookies.get_dict()["igAmSessionId"].replace("POE-D-", ""),
),
)
print(r.text)
## Step 5
## Get usage information
payload = '{"allLineFlag": "false"}'
r = session.post(
"https://www.verizon.com/digital/nsa/secure/gw/myusage/usagMtnDetails",
headers=headers,
allow_redirects=False,
data=payload,
)
usage = r.json()
hotspot = usage["body"]["sectionTemplates"][0]["sections"][1]["data"][
"primaryDataCategoryList"
][1]["dataUsed"]
hotspot_limit = usage["body"]["sectionTemplates"][0]["sections"][1]["data"][
"primaryDataCategoryList"
][1]["totalDataLimit"]
hotspot_units = usage["body"]["sectionTemplates"][0]["sections"][1]["data"][
"primaryDataCategoryList"
][1]["dataUnits"]
## Step 6
## Get device information
r = session.get(
"https://www.verizon.com/digital/nsa/secure/gw/devices/deviceDetail",
headers=headers,
allow_redirects=False,
)
device = r.json()
device_data = device["body"]["sections"][0]["sections"][0]["data"][0]
model = device_data["productDisplayName"]
simid = device_data["simId"]
imei = device_data["deviceId"]
number = device_data["displayMtn"]
sim_type = "eSIM" if device_data["eSimActive"] else "pSIM"
plan = device_data["planUsageInfo"]["planName"]
payment_data = device_data["paymentInfo"]
has_balance = payment_data["hasPayOffBalance"]
if has_balance:
loan_amount = payment_data["loanAmount"]
loan_amount_paid = payment_data["loanAmountPaid"]
remaining_balance = payment_data["remainingBalance"]
loan_start = payment_data["loanStartDate"]
loan_end = payment_data["loanEndDate"]
pending_payments = int(payment_data["pendingNumberOfInstallments"])
paid_payments = int(payment_data["numberOfInstallmentsBilled"])
total_payments = pending_payments + paid_payments
plan_data = device_data["accountPlan"]
data = plan_data["dataUsed"]
data_limit = plan_data["dataPlan"]
data_units = plan_data["unitOfMeasureCDForData"]
sms = plan_data["messageUsed"]
minutes = plan_data["minutesUsed"]
print()
print(f"\033[01mDevice information for {number}\033[0m")
print(f"Model: {model}")
print(f"SIM ID: {simid}")
print(f"IMEI: {imei}")
print(f"SIM Type: {sim_type}")
if has_balance:
print(f"\n\033[01mLoan information\033[0m")
print(f"${loan_amount}/${loan_amount_paid} paid (${remaining_balance} remaining)")
print(
f"{total_payments}/{paid_payments} months paid ({pending_payments} remaining)"
)
print(f"Start date: {loan_start}")
print(f"End date: {loan_end}")
print("\n\033[01mUsage information\033[0m")
print(f"Plan: {plan}")
print(f"Data: {data}/{data_limit} {data_units} used")
print(f"Hotspot data: {hotspot}/{hotspot_limit} {hotspot_units}")
print(f"SMS/MMS: {sms} used")
print(f"Minutes: {minutes} used")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment