Contourner à nouveau les restrictions de l'API pour le plaisir et le profit

Mar 26 2023
Dans mon blog précédent, je parle de la façon dont j'ai écrit un script pour contourner les restrictions de l'API. Je recommanderais à tout le monde de parcourir le blog précédent pour comprendre les nuances et les défis de le contourner avant d'aller de l'avant.
Crédits image : https://blog.open-xchange.com/ox-bug-bounty-programs-two-years-in/

Dans mon blog précédent , je parle de la façon dont j'ai écrit un script pour contourner les restrictions de l'API. Je recommanderais à tout le monde de parcourir le blog précédent pour comprendre les nuances et les défis de le contourner avant d'aller de l'avant. Récemment, l'application a été mise à jour et le champ X-Api-Token n'est plus codé en dur dans l'application, il change plutôt tous les jours. Cela devient assez problématique car je devais maintenant trouver un moyen de récupérer dynamiquement le jeton pour que le contournement fonctionne. Après quelques reconnaissances, j'ai trouvé deux façons de résoudre le problème du jeton API. Regardons les deux façons et mettons à jour le script.

La reconnaissance

J'ai ouvert rot et intercepté la demande lors de l'ouverture de l'URL du tableau de bord. Alors que de nombreuses URL ont été interceptées, une requête m'a particulièrement intéressé :

GET /server/status
Host: redacted.com
Content-Length: 3144
Sec-Ch-Ua: “Chromium”;v=”109", “Not_A Brand”;v=”99"
Sec-Ch-Ua-Platform: “macOS”
X-Api-Token: "$api_token"
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.5414.120 Safari/537.36
Content-Type: application/json
Accept: */*
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://redacted.com/
Accept-Encoding: gzip, deflate
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Connection: close

Utilisation du sélénium

Selenium est un outil d'automatisation du navigateur. J'écrirai un blog séparé sur l'utilisation de Selenium car j'en utilise beaucoup pour mon travail d'automatisation. Ici, j'ai utilisé Selenium pour ouvrir le tableau de bord des URL et capturer toutes les requêtes passant par le navigateur Selenium. Le code ci-dessous m'a aidé à y parvenir:

from seleniumwire import webdriver  # Import from seleniumwire
import time
from selenium.webdriver.common.by import By
# Create a new instance of the Chrome driver
driver = webdriver.Chrome(executable_path= "/usr/local/bin/chromedriver")

# Go to the dashboard home page
driver.get('https://redacted.com/')
time.sleep(4)
# Access requests via the `requests` attribute
for request in driver.requests:
    if request.url == "https://redacted.com/server/status":
        if request.response:
            x_api_token=request.headers['X-Api-Token']
        break

En ajoutant le code ci-dessus, le code mis à jour est devenu :

from seleniumwire import webdriver  # Import from seleniumwire
import time
from selenium.webdriver.common.by import By
import requests
import json
#Credentials needed to automate session
username= "admin"
password= "admin"
# Create a new instance of the Chrome driver
driver = webdriver.Chrome(executable_path= "/usr/local/bin/chromedriver")

# Go to the dashboard home page
driver.get('https://redacted.com/')
time.sleep(4)
# Access requests via the `requests` attribute
for request in driver.requests:
    if request.url == "https://redacted.com/server/status":
        if request.response:
            x_api_token=request.headers['X-Api-Token']
        break

#Function to generate headers for Login
def headers_data(request_data,if_login,token=0):
    data_len= str(len(request_data))
    headers_request = {
    'Content-Length': data_len,
    'Content-Type': 'application/json',
    'X-API-Token': x_api_token
    }    
    if if_login:
        return headers_request
    else:
        headers_request['X-Cookie']= 'token='+token
    return headers_request 

#Login to application and store token
login_data= '{"username":' + '"' + username + '"'+',"password":' + '"' + password + '"'+'}'
login_headers = headers_data(login_data,True)
try:
    login_tokens = requests.post('https://redacted.com/session', headers=login_headers, data=login_data, verify=False)
    token= login_tokens.json().get('token')
    print("Login Successful !")
except:
    raise Exception("Login Automation failed") 

#Post request to stop endpoint.
payload_data= { "Some json data to be posted to stop transaction"}
update_ip_headers = headers_data(payload_data,False,token)
stop_transaction_response= requests.put('https://redacted.com/stop/transaction', headers=update_ip_headers, data=payload_data, verify=False)
print("Transaction stopped via API")

Après quelques recherches, un fichier JS a été découvert dans la source de la page URL du tableau de bord. Le X-Api-Token était présent dans le fichier JS. Désormais, l'automatisation peut être réalisée facilement via le module de requêtes. Le code ci-dessous a aidé à récupérer le jeton :

import re
import requests

js_response = requests.get('https://redacted.com/redacted.js', verify=False)
token =re.findall('(?<=key:"Token",value:function\(\){return").*?(?="}},{key:"Headers")', js_response.text) #Regex in the file to fecth the token
x_api_token= token[0]


import requests
import json
import re
#Credentials needed to automate session
username= "admin"
password= "admin"
js_response = requests.get('https://redacted.com/redacted.js', verify=False)
token =re.findall('(?<=key:"Token",value:function\(\){return").*?(?="}},{key:"Headers")', js_response.text) #Regex in the file to fecth the token
x_api_token= token[0]

#Function to generate headers for Login
def headers_data(request_data,if_login,token=0):
    data_len= str(len(request_data))
    headers_request = {
    'Content-Length': data_len,
    'Content-Type': 'application/json',
    'X-API-Token': x_api_token
    }    
    if if_login:
        return headers_request
    else:
        headers_request['X-Cookie']= 'token='+token
    return headers_request 

#Login to application and store token
login_data= '{"username":' + '"' + username + '"'+',"password":' + '"' + password + '"'+'}'
login_headers = headers_data(login_data,True)
try:
    login_tokens = requests.post('https://redacted.com/session', headers=login_headers, data=login_data, verify=False)
    token= login_tokens.json().get('token')
    print("Login Successful !")
except:
    raise Exception("Login Automation failed") 

#Post request to stop endpoint.
payload_data= { "Some json data to be posted to stop transaction"}
update_ip_headers = headers_data(payload_data,False,token)
stop_transaction_response= requests.put('https://redacted.com/stop/transaction', headers=update_ip_headers, data=payload_data, verify=False)
print("Transaction stopped via API")