Created
April 2, 2023 06:33
-
-
Save Torvin/2036687dac5376e15aec8975354e4602 to your computer and use it in GitHub Desktop.
Twitter challenge login
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# -*- coding: utf-8 -*- | |
from base64 import b64decode,b64encode | |
from urllib.parse import quote,parse_qs,urlsplit,urlparse | |
from random import randint | |
from bs4 import BeautifulSoup | |
import calendar | |
import requests | |
import hashlib | |
import base64 | |
import time | |
import hmac | |
import types | |
class Twitter(object): | |
def __init__(self): | |
self.twitter_android_key = "XXXXXXX" | |
self.twitter_android_secret = "XXXXXXX" | |
self.session = requests.Session() | |
self.access_token = None | |
self.guest_token = None | |
self.challenged = False | |
self.challenge_type = None | |
self.challenge = None | |
self.on_challenge = None | |
self.xauth = None | |
def oauth_signature(self,request,oauth_secret): | |
key = bytes(self.twitter_android_secret +"&"+ oauth_secret, 'UTF-8') | |
message = bytes(request, 'UTF-8') | |
digester = hmac.new(key, message, hashlib.sha1) | |
signature1 = digester.digest() | |
signature2 = base64.urlsafe_b64encode(signature1) | |
signature2 = str(signature2, 'UTF-8').replace("-","+").replace("_","/") | |
return quote(signature2,safe='') | |
def signature_message(self,url,params,oauth_secret,method="POST"): | |
header = method + "&" + quote(url,safe='') + "&" | |
body = bytes() | |
for key,value in params.items(): | |
body += bytes(key,"UTF-8") + b"=" + bytes(value,"UTF-8") + b"&" | |
body = body[:-1] | |
return self.oauth_signature(header + quote(body,safe=''),oauth_secret) | |
def xauth_login(self,username,password): | |
self.access_token = self.session.post("https://api.twitter.com/oauth2/token",params = {'grant_type':'client_credentials'}, | |
headers = { | |
"Accept": "application/json", | |
"Authorization": "Basic " + b64encode((self.twitter_android_key + ":" + self.twitter_android_secret).encode("utf8")).decode("utf8") | |
} | |
).json()["access_token"] | |
self.guest_token = self.session.post("https://api.twitter.com/1.1/guest/activate.json",headers={"Authorization": "Bearer " + self.access_token}).json()["guest_token"] | |
auth = self.session.post("https://api.twitter.com/auth/1/xauth_password.json",headers={ | |
"Authorization": "Bearer " + self.access_token, | |
"X-Guest-Token": self.guest_token | |
}, | |
params = { | |
"x_auth_identifier":username, | |
"x_auth_password":password, | |
"send_error_codes":"true", | |
"x_auth_login_challenge":"1", | |
"x_auth_login_verification":"1", | |
"x_auth_country_code":"US", | |
"ui_metrics":"" | |
}).json() | |
self.xauth = auth | |
if "login_verification_request_url" in auth.keys(): | |
self.challenged = True | |
self.challenge = auth | |
self.challenge_type = parse_qs(urlparse(auth["login_verification_request_url"]).query)['challenge_type'][0] | |
return auth | |
def challenge_access_token(self,user_id,request_id): | |
oauth_nonce = ''.join([str(randint(0,9)) for n in range(31)]) | |
oauth_timestamp = str(calendar.timegm(time.gmtime())) | |
return self.session.post("https://api.twitter.com/oauth/access_token",data={ | |
"x_auth_mode":"client_auth", | |
"x_auth_login_verification":"1", | |
"x_auth_login_challenge": "1", | |
"send_error_codes":"true", | |
"login_verification_user_id": user_id, | |
"login_verification_request_id": request_id | |
}, | |
headers = { | |
"Authorization":'OAuth realm="http://api.twitter.com/", oauth_version="1.0", oauth_nonce="{oauth_nonce}", oauth_timestamp="{oauth_timestamp}", oauth_signature="{oauth_signature}", oauth_consumer_key="{oauth_consumer_key}", oauth_signature_method="HMAC-SHA1"'.format( | |
oauth_nonce = oauth_nonce, | |
oauth_timestamp = oauth_timestamp, | |
oauth_consumer_key = self.twitter_android_key, | |
oauth_signature = self.signature_message(url="https://api.twitter.com/oauth/access_token",params={ | |
"login_verification_request_id": request_id, | |
"login_verification_user_id": user_id, | |
"oauth_consumer_key":self.twitter_android_key, | |
"oauth_nonce": oauth_nonce, | |
"oauth_signature_method":"HMAC-SHA1", | |
"oauth_timestamp": oauth_timestamp, | |
"oauth_version":"1.0", | |
"send_error_codes":"true", | |
"x_auth_login_challenge":"1", | |
"x_auth_login_verification":"1", | |
"x_auth_mode":"client_auth", | |
},oauth_secret="") | |
), | |
"Content-Type": "application/x-www-form-urlencoded", | |
"Accept": "application/json", | |
}).json() | |
def solve_challenge(self,challenge): | |
self.has_challenge = True | |
challenge_url = challenge["login_verification_request_url"] | |
request_id = challenge["login_verification_request_id"] | |
response = self.session.get(challenge_url) | |
soup = BeautifulSoup(response.content, "lxml") | |
authenticity_token = soup.select_one("input[name=authenticity_token]")["value"] | |
challenge_id = soup.select_one("input[name=challenge_id]")["value"] | |
user_id = soup.select_one("input[name=user_id]")["value"] | |
self.challenge_type = soup.select_one("input[name=challenge_type]")["value"] | |
print(response.content) | |
answer = input("code:").strip() | |
data = { | |
'authenticity_token':authenticity_token, | |
'challenge_id':challenge_id, | |
'user_id':user_id, | |
'challenge_type':self.challenge_type, | |
'platform':'mobile', | |
'redirect_after_login':'', | |
'remember_me':'true', | |
'challenge_response':answer, | |
} | |
self.session.post("https://twitter.com/account/login_challenge",data=data) | |
twitter_session = self.challenge_access_token(user_id, request_id) | |
self.xauth = twitter_session | |
print(twitter_session) | |
return twitter_session | |
def auth_headers(self,oauth_nonce,oauth_timestamp,oauth_signature,skip_token=False): | |
return { | |
"Authorization": 'OAuth realm="http://api.twitter.com/", oauth_version="1.0", oauth_token="{oauth_token}", oauth_nonce="{oauth_nonce}", oauth_timestamp="{oauth_timestamp}", oauth_signature="{oauth_signature}", oauth_consumer_key="{oauth_consumer_key}", oauth_signature_method="{oauth_signature_method}"'.format( | |
oauth_token = self.xauth["oauth_token"] if not skip_token else "", | |
oauth_nonce = oauth_nonce, | |
oauth_timestamp = oauth_timestamp, | |
oauth_signature = oauth_signature, | |
oauth_consumer_key = self.twitter_android_key, | |
oauth_signature_method = "HMAC-SHA1" | |
), | |
"User-Agent": "TwitterAndroid/8.40.0-release.02 (18400002-r-2) Nexus 7/7.0 (asus;Nexus 7;google;nakasi;0;;0;2012)", | |
"X-Twitter-Active-User": "yes", | |
"X-Twitter-API-Version": "5", | |
"X-Twitter-Client": "TwitterAndroid", | |
"X-Twitter-Client-Language": "en-US", | |
"Accept": "application/json", | |
} | |
def tweet(self, text): | |
api_statuses = "https://api.twitter.com/1.1/statuses/update.json" | |
oauth_nonce = ''.join([str(randint(0,9)) for n in range(31)]) | |
oauth_timestamp = str(calendar.timegm(time.gmtime())) | |
params = { | |
"batch_mode":"off", | |
"cards_platform":"Android-12", | |
"earned_read":"true", | |
"enable_dm_commands":"false", | |
"ext":"mediaRestrictions%2CaltText%2CmediaStats%2CmediaColor%2Cinfo360%2CcameraMoment%2ChighlightedLabel%2Cmaster_playlist_only", | |
"include_blocked_by":"true", | |
"include_blocking":"true", | |
"include_cards":"true", | |
"include_entities":"true", | |
"include_media_features":"true", | |
"include_reply_count":"true", | |
"oauth_consumer_key":self.twitter_android_key, | |
"oauth_nonce": oauth_nonce, | |
"oauth_signature_method":"HMAC-SHA1", | |
"oauth_timestamp":oauth_timestamp, | |
"oauth_token": self.xauth["oauth_token"], | |
"oauth_version":"1.0", | |
"send_error_codes":"true", | |
"status": quote(text,safe=''), | |
"tweet_mode":"extended" | |
} | |
headers = self.auth_headers( | |
oauth_nonce= oauth_nonce, | |
oauth_timestamp= oauth_timestamp, | |
oauth_signature= self.signature_message( | |
url= api_statuses, | |
params= params, | |
oauth_secret= self.xauth['oauth_token_secret'] | |
) | |
) | |
headers["Content-Type"] = "application/x-www-form-urlencoded" | |
post_params = '&'.join([k + u"=" + v for k,v in params.items()]) | |
return self.session.post(api_statuses,headers=headers,data=post_params.encode('utf-8'),verify=False).json() | |
api = Twitter() | |
username = input('username: ').strip() | |
password = input('password: ').strip() | |
result = api.xauth_login(username, password) | |
print(result) | |
if api.challenged: | |
api.solve_challenge(result) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://api.twitter.com/auth/1/xauth_password.json get {'errors': [{'code': 34, 'message': 'Sorry, that page does not exist.'}]}