lots and lots of squashed stuff!!

This commit is contained in:
JJTech0130 2023-05-02 08:39:11 -04:00
parent 8b5bcf2461
commit d66e3e0adf
No known key found for this signature in database
GPG key ID: 23C92EBCCF8F93D6
3 changed files with 150 additions and 156 deletions

95
demo.py Normal file
View file

@ -0,0 +1,95 @@
from ids import *
import ids
import getpass
import json
# Open config
try:
with open("config.json", "r") as f:
config = json.load(f)
except FileNotFoundError:
config = {}
# If no username is set, prompt for it
if "username" not in config:
config["username"] = input("Enter iCloud username: ")
# If no password is set, prompt for it
if "password" not in config:
config["password"] = getpass.getpass("Enter iCloud password: ")
# If grandslam authentication is not set, prompt for it
if "use_gsa" not in config:
config["use_gsa"] = input("Use grandslam authentication? [y/N] ").lower() == "y"
def factor_gen():
return input("Enter iCloud 2FA code: ")
user_id, token = ids._get_auth_token(
config["username"], config["password"], config["use_gsa"], factor_gen=factor_gen
)
config["user_id"] = user_id
config["token"] = token
key, cert = ids._get_auth_cert(user_id, token)
config["key"] = key
config["cert"] = cert
conn1 = apns.APNSConnection()
conn1.connect()
conn1.filter(["com.apple.madrid"])
info = {
"uri": "mailto:" + config["username"],
"user_id": user_id,
}
resp = None
try:
if "validation_data" in config:
resp = ids._register_request(
b64encode(conn1.token),
info,
cert,
key,
conn1.cert,
conn1.private_key,
config["validation_data"],
)
except Exception as e:
print(e)
resp = None
if resp is None:
print(
"Note: Validation data can be obtained from @JJTech, or intercepted using a HTTP proxy."
)
validation_data = (
input_multiline("Enter validation data: ")
.replace("\n", "")
.replace(" ", "")
)
resp = ids._register_request(
b64encode(conn1.token),
info,
cert,
key,
conn1.cert,
conn1.private_key,
validation_data,
)
config["validation_data"] = validation_data
madrid_cert = x509.load_der_x509_certificate(
resp["services"][0]["users"][0]["cert"]
)
madrid_cert = (
madrid_cert.public_bytes(serialization.Encoding.PEM).decode("utf-8").strip()
)
config["madrid_cert"] = madrid_cert
# Save config
with open("config.json", "w") as f:
json.dump(config, f, indent=4)

30
gsa.py
View file

@ -18,7 +18,8 @@ import getpass
DEBUG = True # Allows using a proxy for debugging (disables SSL verification)
# Server to use for anisette generation
#ANISETTE = "https://sign.rheaa.xyz/"
ANISETTE = 'http://45.132.246.138:6969/'
#ANISETTE = 'http://45.132.246.138:6969/'
ANISETTE = False
# ANISETTE = 'https://sideloadly.io/anisette/irGb3Quww8zrhgqnzmrx'
# ANISETTE = "http://jkcoxson.com:2052/"
@ -33,15 +34,34 @@ urllib3.disable_warnings()
def generate_anisette() -> dict:
r = requests.get(ANISETTE, verify=False if DEBUG else True, timeout=5)
r = json.loads(r.text)
return r
import objc
from Foundation import NSBundle, NSClassFromString #type: ignore
AOSKitBundle = NSBundle.bundleWithPath_('/System/Library/PrivateFrameworks/AOSKit.framework')
objc.loadBundleFunctions(AOSKitBundle, globals(), [("retrieveOTPHeadersForDSID", b'')]) #type: ignore
util = NSClassFromString('AOSUtilities')
h = util.retrieveOTPHeadersForDSID_("-2")
o = {
"X-Apple-I-MD": str(h["X-Apple-MD"]),
"X-Apple-I-MD-M": str(h["X-Apple-MD-M"]),
}
#h["X-Apple-I-MD"] = str(h["X-Apple-MD"])
#h["X-Apple-I-MD-M"] = str(h["X-Apple-MD-M"])
#print(o)
return o
#r = requests.get(ANISETTE, verify=False if DEBUG else True, timeout=5)
#r = json.loads(r.text)
#return r
class Anisette:
@staticmethod
def _fetch(url: str) -> dict:
"""Fetches anisette data that we cannot calculate from a remote server"""
if url == False:
return generate_anisette()
r = requests.get(url, verify=False if DEBUG else True, timeout=5)
r = json.loads(r.text)
return r
@ -507,5 +527,5 @@ def authenticate(username, password, anisette: Anisette):
print(f"Unknown auth value {r['Status']['au']}")
return
else:
print("Assuming 2FA is not required")
#print("Assuming 2FA is not required")
return spd

181
ids.py
View file

@ -6,19 +6,21 @@ from base64 import b64decode, b64encode
from datetime import datetime
import requests
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives.asymmetric import padding, rsa
from cryptography.x509.oid import NameOID
import apns
import bags
import gsa
USER_AGENT = "com.apple.madrid-lookup [macOS,13.2.1,22D68,MacBookPro18,3]"
#USER_AGENT = "com.apple.madrid-lookup [macOS,13.2.1,22D68,MacBookPro18,3]"
# NOTE: The push token MUST be registered with the account for self-uri!
# This is an actual valid one for my account, since you can look it up anyway.
PUSH_TOKEN = "5V7AY+ikHr4DiSfq1W2UBa71G3FLGkpUSKTrOLg81yk="
SELF_URI = "mailto:jjtech@jjtech.dev"
#PUSH_TOKEN = "5V7AY+ikHr4DiSfq1W2UBa71G3FLGkpUSKTrOLg81yk="
#SELF_URI = "mailto:jjtech@jjtech.dev"
# Nonce Format:
@ -189,13 +191,6 @@ def _get_auth_token(
return realm_user_id, auth_token
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding, rsa
from cryptography.x509.oid import NameOID
def _generate_csr(private_key: rsa.RSAPrivateKey) -> str:
csr = (
x509.CertificateSigningRequestBuilder()
@ -229,8 +224,6 @@ def _get_auth_cert(user_id, token) -> tuple[str, str]:
"realm-user-id": user_id,
}
# print(body["csr"])
body = plistlib.dumps(body)
r = requests.post(
@ -242,10 +235,7 @@ def _get_auth_cert(user_id, token) -> tuple[str, str]:
r = plistlib.loads(r.content)
if r["status"] != 0:
raise (Exception(f"Failed to get auth cert: {r}"))
# return b64encode(r["cert"]).decode()
# cert = x509.load_pem_x509_certificate(b64encode(r["cert"]).decode())
cert = x509.load_der_x509_certificate(r["cert"])
# cert = cert.public_bytes(serialization.Encoding.PEM).decode("utf-8")
return (
private_key.private_bytes(
encoding=serialization.Encoding.PEM,
@ -258,95 +248,27 @@ def _get_auth_cert(user_id, token) -> tuple[str, str]:
)
def _register_request(push_token, user_id, auth_cert, auth_key, push_cert, push_key):
# body = {'device-name': 'Test'}
def _register_request(
push_token, info, auth_cert, auth_key, push_cert, push_key, validation_data
):
body = {
"device-name": "Jamess Laptop",
"hardware-version": "MacBookPro18,3",
"language": "en-US",
"os-version": "macOS,13.2.1,22D68",
# "private-device-data": {
# "ap": "0",
# "d": "703987510.082306",
# "dt": 1,
# "gt": "0",
# "h": "1",
# "ktf": "0",
# "ktv": 54,
# "m": "0",
# "p": "0",
# "pb": "22D68",
# "pn": "macOS",
# "pv": "13.2.1",
# "s": "0",
# "t": "0",
# "u": "E451BD65-51B0-44F3-805A-A92BDD8A5000",
# "v": "1",
# },
"retry-count": 0,
"software-version": "22D68",
"services": [
{
"capabilities": [{"flags": 1, "name": "Messenger", "version": 1}],
"service": "com.apple.madrid",
# "sub-services": [
# "com.apple.private.alloy.gelato",
# "com.apple.private.alloy.gamecenter.imessage",
# "com.apple.private.alloy.sms",
# "com.apple.private.alloy.biz",
# ],
"users": [
# {
# "client-data": {
# "ec-version": 1,
# "kt-version": 5,
# "nicknames-version": 1,
# "optionally-receive-typing-indicators": True,
# "prefers-sdr": False,
# "public-message-identity-key": b"0\x81\xf6\x81C\x00A\x04\x87\x1e\xeb\xe4u\x0b\xa3\x9e\x9c\xbc\xf8rK\x1e\xfe44%f$\x1d\xe8\xbb\xc6\xbdCD\x9ckv K\xc1\x1e\xb1\xdf4\xc8S6\x0f\x92\xd0=\x1e\x84\x9c\xc5\xa5\xb6\xb7}\xdd\xec\x1e\x1e\xd8Q\xd8\xca\xdb\x07'\xc7\x82\x81\xae\x00\xac0\x81\xa9\x02\x81\xa1\x00\xa8 \xfc\x9f\xa6\xb0V2\xce\x1c\xa7\x13\x9e\x03\xd1\xd8\x97a\xbb\xdd\xac\x86\xb8\x10(\x89\x13QP\x8f\xf0+EP\xd1\xb06\xee\x94\xcd\xa8\x9e\xf1\xedp\xa4\x9726\x1e\xe9\xab\xd4\xcb\xac\x05\xd7\x8c?\xbb\xa2\xde,\xfe\r\x1a\xb9\x88W@\x99\xec\xa0]\r\x1a>dV\xb2@\xc5P\xf3m\x80y\xf5\xa0G\xae\xd8h\x92\xef\xca\x85\xcbB\xed\xa9W\x8c\x13\xd4O\xdbYI2\xdcM\x1f\xf6c\x17\x1c\xd1v\xdd\xbcc\xac,&V\xfd\x07\xa0\xc3\x9f\x00\x1f\xc6\xe4\x02u\x12p\x8f\xe2\xb0\x14\xfai\x12\xbb\xa6\x9a6Q\xa5\xde+\x9e{\xcf\xc8\x1b}\x02\x03\x01\x00\x01",
# "public-message-identity-ngm-version": 12,
# "public-message-identity-version": 2,
# "public-message-ngm-device-prekey-data-key": b"\n v\xd6=#\xb7\xde\xe9~n\xdd\x94|xw\x1c#W\xa5\xe0\xf3\x15\xed\xd1\xa0\xab\xa8\xfd\xa9\x8c\xdd\x16\xb0\x12@x\xb4\xafE\xc4\x1b\xcd\xe9\xb1\x8f\x8aI\x03\xd2&F\x95\x9b\x99R\x92\x07/\x12\xaeM\x10\xf3\xa2u\x7f5]\xd9\x19\xc3\x91\xb5\xb4\xbdO\x9c\x1f\r\xae\xa9\xf3+\x9c\x00M2\x83\x147\xb3X\xa11\x00\xaeV\xbe_\x19\x10\xafg\x19\xbf\x10\xd9A",
# "supports-ack-v1": True,
# "supports-animoji-v2": True,
# "supports-audio-messaging-v2": True,
# "supports-autoloopvideo-v1": True,
# "supports-be-v1": True,
# "supports-ca-v1": True,
# "supports-certified-delivery-v1": True,
# "supports-cross-platform-sharing": True,
# "supports-dq-nr": True,
# "supports-fsm-v1": True,
# "supports-fsm-v2": True,
# "supports-fsm-v3": True,
# "supports-hdr": True,
# "supports-heif": True,
# "supports-ii-v1": True,
# "supports-impact-v1": True,
# "supports-inline-attachments": True,
# "supports-keep-receipts": True,
# "supports-location-sharing": True,
# "supports-media-v2": True,
# "supports-original-timestamp-v1": True,
# "supports-people-request-messages": True,
# "supports-people-request-messages-v2": True,
# "supports-photos-extension-v1": True,
# "supports-photos-extension-v2": True,
# "supports-protobuf-payload-data-v2": True,
# "supports-rem": True,
# "supports-sa-v1": True,
# "supports-st-v1": True,
# "supports-update-attachments-v1": True,
# },
# #"kt-loggable-data": b'\n"\n \rl\xbe\xca\xf7\xe8\xb2\x89k\x18\x1e\xb9,d\xf8\xe2\n\xbf\x8d\xe1E\xd6\xf3T\xcb\xd9\x99d\xd1mk\xeb\x10\x0c\x18\x05"E\x08\x01\x12A\x04\x99\x16\xc3\xd8\x85\x80qPr\xbf\x0c\xdb\x9f\x1bHK\xb2:)\x01\x88\x91\xb1\x08do\xf3\x16\xc7\xaa\xd3nb\xddQF\x8f\xb2a\xb1\xbbK\xdf\xd0\xfa\x95\xa29XZ\xcaRh\xbex\xc4f\xe6G`\x1f\xf2\xf3[',
# "uris": [{"uri": "mailto:user_test2@icloud.com"}],
# "user-id": "D:20994360971",
# }
{
"uris": [{"uri": info["uri"]}],
"user-id": info["user_id"],
}
],
}
],
"software-version": "22D68",
# "validation-data": b"v\x02V`\xd8N\xf3V\xb0\xc4'=\x137+\x16-o\x1d\x00\x1c\xf53\xe0g\xd9\x83x\xe0\xderh\xa0\xc7\x00\x00\x01\xe0\x07\x00\x00\x00\x01\x00\x00\x01\x806\x81<\xb9G\xf0,(CQX\xc5\x1e\xbc\xfe}a\xf7y\xfcg\xa1j/B\xb6k\xf4\xeey\x7f=e\xe6\xea\xa3\xfd\xb2\x18\x8e.\x19\x9e'\x9eO]\xca\xe3{\x9f\x10I\x94\x1a\xe0\xef>\xce\x9dl\xb0\xb2u\x88KT\x0b\xcc\x915\x92\xd3\x86\x1b\xb3\xe5\x04\x9f\x8d\x8a\x82$\x11\xfb\xf2t\xda&\x96@U<lP\"/\xf6->\xec\x84\x13\xe7p\xffS\x02\xde\x8c\xdd\xfcqA\x14!\xa4\x07\x82\xd0\x9fm\xe9~\xc4\xcf\x96\xd6D\xa3\xf0\xb9\xa7\xa2}\xc5\x0e.\x0fvYz\x07\xc2\x9f$s:\xd4<\x13u]\x06f[\xcd\x95\xd1\xad\xe9\xb3\xb3\x9f|\nh-\xa2\xa6\xb9c\xa1\x8d\xf2gx\x84\xbe\x1d\xc4\x03}^\xbf\x9ck#\xa8\xad\xa5\x87\x04\x88D\xd0\xee>\x9f\x0f\xa63;\x7fE\x14\x89\x1c]\x8b\x13o\xbd\xf6\x84`R\xa2\xb7Z\xcc\xdf+\xc5\xe5>\xf73?\x84\xe2d\x97\xd3\x07\x10V\xb6\xb4\nB7\xfc\x8bReeA\x15t\x94\xcf\xa8\x957\x1f\x1d>\xe1\xa4\xc5X\xb0!\x81\xcah\x11.'$\xf6\x12\xb3`\xe9\xa93\x07\xe4}\x02\xee\x95hW\xb7\xfb '_\xafC.\xdd\x13\x8df\xcf(H\x06\x18\xe2\xe7\xce\x93+\xf9\xe0\xf5\x17r\xb5.g2M\x8a\xb7\x80j\xb3\x00*\xa6Z\x1f\x07\xf3\x82\xcfj\xd2R\xc1%\xcc\xbe\x10\x9c\xb4qp\x1f\xd7W\x8c\x1aL2\xfa\xeb\x01s\x01m\xa3$\x9cJ\xf8X?\x99r`pT\xa7\xa6\x80\xcc\xc0\x97\xb3|[%\xc8Usj\x1d\x00\x00\x00\x00\x00\x00\x00O\x01P\xdc\"\x98\xc3\xd9\xb5\xbaK\xdc.\xeb\x81\x87r\x8d\xa4q^\xcb\x00\x00\x006\t\x01\x92\x91\x8fI\xff\xff\xd5g\xf2\x1d\x04G\xf4_\xe4\x90dE\xc7\xb7\xcaO~V\x1e[\x7ff?e|d\xae\xb8\x92(F\xd1_\xe9\xb2\x9e\xb0\xf1\x99\x92\x07\xf8\xb2&I\xed",
"validation-data": random.randbytes(10),
"validation-data": b64decode(validation_data),
}
body = plistlib.dumps(body)
@ -363,7 +285,7 @@ def _register_request(push_token, user_id, auth_cert, auth_key, push_cert, push_
"x-auth-cert-0": auth_cert.replace("\n", "")
.replace("-----BEGIN CERTIFICATE-----", "")
.replace("-----END CERTIFICATE-----", ""),
"x-auth-user-id-0": user_id,
"x-auth-user-id-0": info["user_id"],
"x-auth-nonce-0": b64encode(auth_nonce),
"x-pr-nonce": b64encode(auth_nonce),
"x-push-token": push_token,
@ -374,68 +296,25 @@ def _register_request(push_token, user_id, auth_cert, auth_key, push_cert, push_
"x-push-nonce": b64encode(push_nonce),
}
# headers.update(gsa.Anisette().generate_headers())
r = requests.post(
"https://identity.ess.apple.com/WebObjects/TDIdentityService.woa/wa/register",
headers=headers,
data=body,
verify=False,
)
print(r.text)
r = plistlib.loads(r.content)
print(f'Response code: {r["status"]}')
if "status" in r and r["status"] == 6004:
raise Exception("Validation data expired!")
return r
def test():
import getpass
import json
# Open config as read and write
try:
with open("config.json", "r") as f:
config = json.load(f)
except FileNotFoundError:
config = {}
# If no username is set, prompt for it
if "username" not in config:
config["username"] = input("Enter iCloud username: ")
# If no password is set, prompt for it
if "password" not in config:
config["password"] = getpass.getpass("Enter iCloud password: ")
# If grandslam authentication is not set, prompt for it
if "use_gsa" not in config:
config["use_gsa"] = input("Use grandslam authentication? [y/N] ").lower() == "y"
def factor_gen():
return input("Enter iCloud 2FA code: ")
user_id, token = _get_auth_token(
config["username"], config["password"], config["use_gsa"], factor_gen=factor_gen
)
config["user_id"] = user_id
config["token"] = token
key, cert = _get_auth_cert(user_id, token)
config["key"] = key
config["cert"] = cert
# print(key, cert)
conn1 = apns.APNSConnection()
conn1.connect()
conn1.filter(["com.apple.madrid"])
_register_request(
b64encode(conn1.token), user_id, cert, key, conn1.cert, conn1.private_key
)
# Save config
with open("config.json", "w") as f:
json.dump(config, f, indent=4)
if __name__ == "__main__":
test()
def input_multiline(prompt):
print(prompt)
lines = []
while True:
line = input()
if line == "":
break
lines.append(line)
return "\n".join(lines)