Open julio03451 opened 6 months ago
As rsyccd said, you should avoid using the chain that is provided in chains.json. Get the chain from your device and use it instead. However, this chain is working for the moment.
Also when you get the chain from your device you can update osPatchLevel, vendorPatchLevel and bootPatchLevel to the current ones.
Sorry, can you explain how to get the 'privateAttestationKey', please?
Sorry, can you explain how to get the 'privateAttestationKey', please?
It's ec_private_key that comes from Chain.py
Hi all, the @julio03451 solution its working only on Android? What would be the difference with iOS?
Hi all, the @julio03451 solution its working only on Android? What would be the difference with iOS?|
It should work. Amz poorly validate this chain.
Is it possible to create unique chains from an emulator using getCertificateChain() ? or does it have to be a physical android device running
Is it possible to create unique chains from an emulator using getCertificateChain() ? or does it have to be a physical android device running
that is what we all trying to understand
The most interesting thing is that when commercial bots raised their prices to $200/month, they argued that they needed some impressive computing power to solve 420 error. And that now it is not just python code, but something more complex haha. I wonder what else they are lying us about
I think it was the greedy signature providers that caused the price hikes.
Could you give an example of these signature services? Im not sure what you are referencing.
The most interesting thing is that when commercial bots raised their prices to $200/month, they argued that they needed some impressive computing power to solve 420 error. And that now it is not just python code, but something more complex haha. I wonder what else they are lying us about
I think it was the greedy signature providers that caused the price hikes.
Could you give an example of these signature services? Im not sure what you are referencing.
The most interesting thing is that when commercial bots raised their prices to $200/month, they argued that they needed some impressive computing power to solve 420 error. And that now it is not just python code, but something more complex haha. I wonder what else they are lying us about
I think it was the greedy signature providers that caused the price hikes.
Could you give an example of these signature services? Im not sure what you are referencing.
aghh ok thank you for the quick response. I want to also say thanks to all of you that worked on this, I think it's very impressive that you all come together to figure something out like this and not be gatekeepers.
Is it possible to create unique chains from an emulator using getCertificateChain() ? or does it have to be a physical android device running
There is nothing special about certificate chains, you don't even need an emulator to do it, you can just create the whole chain yourself and self-sign the root.
But key attestation requires root cert validation, which is done by verifying the public key and attesting that the root cert is trustworthy and its issuing authority is Google, which emulators & VMs can't do - keystores on physical devices are set up at the factory, isolated from the OS.
Now it's entirely possible Amazon's validation logic doesn't even attest the root and they just look for a valid chain, worth giving it a go if you wish. But then again, a non-Google-issued root key is undeniable proof of botting if Amazon ever comes looking.
To add: @MY20-PHEV you don't need an android device running, you're not pulling these certs every time you generate the signature - the root and intermediate certs never change, so you just pull them one time then hardcode them into your codebase.
Has anyone written an Android app to getCerificate chain?
Has anyone written an Android app to getCerificate chain?
I am trying to just generate certs myself using openssl. but no luck yet
Has anyone written an Android app to getCerificate chain?
I am trying to just generate certs myself using openssl. but no luck yet
I don't think it's the right way. Right now, as I understand it, they're busy with captcha. But sooner or later a manager will come and they will fix their outrage.
My point is that it's not worth wasting time generating a root certificate
Has anyone written an Android app to getCerificate chain?
I am trying to just generate certs myself using openssl. but no luck yet
I don't think it's the right way. Right now, as I understand it, they're busy with captcha. But sooner or later a manager will come and they will fix their outrage.
My point is that it's not worth wasting time generating a root certificate
What do you exactly mean by "they're busy with captcha" ?
@julio03451 I am able to generate accept signatures but how to generate validatechallenge signatures ??
def sign_accept_headers(self): signature_headers = self.sign_request("/AcceptOffer")
should I just change the "AcceptOffer" to "ValidateChallenge"???
@julio03451 Can I please connect with you offline? I need some help with code. My mail id is in bio.
@julio03451 I am able to generate accept signatures but how to generate validatechallenge signatures ??
def sign_accept_headers(self): signature_headers = self.sign_request("/AcceptOffer")
should I just change the "AcceptOffer" to "ValidateChallenge"???
it is same signature just change url segment to ValidateChallenge
I managed to decode 1.3.6.1.4.1.11129.2.1.17. It wasn't too hard, if you google "1.3.6.1.4.1.11129.2.1.17" you will find all the necessary information.
Here's the information inside this extension:
KeyDescription: attestationVersion=200 attestationSecurityLevel=Software keymasterVersion=200 keymasterSecurityLevel=Software attestationChallenge=ozSGSaxdQrh1VsOyXikrzk== uniqueId= softwareEnforced=AuthorizationList: purpose=SetOf: 2 algorithm=3 keySize=256 digest=SetOf: 4 6 ecCurve=1 noAuthRequired= creationDateTime=1710255346877 origin=0 rootOfTrust=RootOfTrust: verifiedBootKey=0x0000000000000000000000000000000000000000000000000000000000000000 deviceLocked=False verifiedBootState=Unverified verifiedBootHash=0x0000000000000000000000000000000000000000000000000000000000000000 osVersion=130000 osPatchLevel=202211 attestationApplicationId=0x3041311b30190411636f6d2e616d617a6f6e2e72616262697402041248d6f2312204202f19adeb284eb36f7f07786152b9a1d14b21653203ad0b04ebbf9c73ab6d7625 vendorPatchLevel=0 bootPatchLevel=20221101 teeEnforced=AuthorizationList:
Hi there! I was wondering, how did you get to decode this?
Hi there! I was wondering, how did you get to decode this?
All you need is chatgpt and ASN.1 schema: https://developer.android.com/privacy-and-security/security-key-attestation#key_attestation_ext_schema
from pyasn1.codec.der.decoder import decode
from pyasn1.type import univ, namedtype, namedval, tag, char
import base64
from cryptography import x509
from cryptography.hazmat.backends import default_backend
# Define the ASN.1 schema based on the provided structure
class SecurityLevel(univ.Enumerated):
namedValues = namedval.NamedValues(
('Software', 0),
('TrustedEnvironment', 1),
('StrongBox', 2)
)
class VerifiedBootState(univ.Enumerated):
namedValues = namedval.NamedValues(
('Verified', 0),
('SelfSigned', 1),
('Unverified', 2),
('Failed', 3)
)
class RootOfTrust(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('verifiedBootKey', univ.OctetString()),
namedtype.NamedType('deviceLocked', univ.Boolean()),
namedtype.NamedType('verifiedBootState', VerifiedBootState()),
namedtype.OptionalNamedType('verifiedBootHash', univ.OctetString())
)
class AuthorizationList(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.OptionalNamedType('purpose', univ.SetOf(componentType=univ.Integer()).subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 1))),
namedtype.OptionalNamedType('algorithm', univ.Integer().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 2))),
namedtype.OptionalNamedType('keySize', univ.Integer().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 3))),
namedtype.OptionalNamedType('digest', univ.SetOf(componentType=univ.Integer()).subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 5))),
namedtype.OptionalNamedType('padding', univ.SetOf(componentType=univ.Integer()).subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 6))),
namedtype.OptionalNamedType('ecCurve', univ.Integer().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 10))),
namedtype.OptionalNamedType('rsaPublicExponent', univ.Integer().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 200))),
namedtype.OptionalNamedType('rollbackResistance', univ.Null().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 303))),
namedtype.OptionalNamedType('activeDateTime', univ.Integer().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 400))),
namedtype.OptionalNamedType('originationExpireDateTime', univ.Integer().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 401))),
namedtype.OptionalNamedType('usageExpireDateTime', univ.Integer().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 402))),
namedtype.OptionalNamedType('noAuthRequired', univ.Null().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 503))),
namedtype.OptionalNamedType('userAuthType', univ.Integer().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 504))),
namedtype.OptionalNamedType('authTimeout', univ.Integer().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 505))),
namedtype.OptionalNamedType('allowWhileOnBody', univ.Null().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 506))),
namedtype.OptionalNamedType('trustedUserPresenceRequired', univ.Null().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 507))),
namedtype.OptionalNamedType('trustedConfirmationRequired', univ.Null().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 508))),
namedtype.OptionalNamedType('unlockedDeviceRequired', univ.Null().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 509))),
namedtype.OptionalNamedType('allApplications', univ.Null().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 600))),
namedtype.OptionalNamedType('applicationId', univ.OctetString().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 601))),
namedtype.OptionalNamedType('creationDateTime', univ.Integer().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 701))),
namedtype.OptionalNamedType('origin', univ.Integer().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 702))),
namedtype.OptionalNamedType('rootOfTrust', RootOfTrust().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 704))),
namedtype.OptionalNamedType('osVersion', univ.Integer().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 705))),
namedtype.OptionalNamedType('osPatchLevel', univ.Integer().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 706))),
namedtype.OptionalNamedType('attestationApplicationId', univ.OctetString().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 709))),
namedtype.OptionalNamedType('attestationIdBrand', univ.OctetString().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 710))),
namedtype.OptionalNamedType('attestationIdDevice', univ.OctetString().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 711))),
namedtype.OptionalNamedType('attestationIdProduct', univ.OctetString().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 712))),
namedtype.OptionalNamedType('attestationIdSerial', univ.OctetString().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 713))),
namedtype.OptionalNamedType('attestationIdImei', univ.OctetString().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 714))),
namedtype.OptionalNamedType('attestationIdMeid', univ.OctetString().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 715))),
namedtype.OptionalNamedType('attestationIdManufacturer', univ.OctetString().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 716))),
namedtype.OptionalNamedType('attestationIdModel', univ.OctetString().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 717))),
namedtype.OptionalNamedType('vendorPatchLevel', univ.Integer().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 718))),
namedtype.OptionalNamedType('bootPatchLevel', univ.Integer().subtype(
explicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatSimple, 719)))
)
class KeyDescription(univ.Sequence):
componentType = namedtype.NamedTypes(
namedtype.NamedType('attestationVersion', univ.Integer()),
namedtype.NamedType('attestationSecurityLevel', SecurityLevel()),
namedtype.NamedType('keymasterVersion', univ.Integer()),
namedtype.NamedType('keymasterSecurityLevel', SecurityLevel()),
namedtype.NamedType('attestationChallenge', univ.OctetString()),
namedtype.NamedType('uniqueId', univ.OctetString()),
namedtype.NamedType('softwareEnforced', AuthorizationList()),
namedtype.NamedType('teeEnforced', AuthorizationList())
)
# Load the certificate
pem_data = """
-----BEGIN CERTIFICATE-----
Put your certificate here
-----END CERTIFICATE-----
"""
der_data = base64.b64decode("".join(pem_data.strip().splitlines()[1:-1]))
certificate = x509.load_der_x509_certificate(der_data, default_backend())
# Find and decode the extension
oid = '1.3.6.1.4.1.11129.2.1.17'
extension = certificate.extensions.get_extension_for_oid(x509.ObjectIdentifier(oid))
extn_value = extension.value.value
parsed_data, _ = decode(extn_value, asn1Spec=KeyDescription())
# Display the parsed data
print(parsed_data.prettyPrint())
This doesn't work for me. Is it because my marketplace is not US? Do I need to change something in the code to make it work?
All you need is chatgpt and ASN.1 schema: https://developer.android.com/privacy-and-security/security-key-attestation#key_attestation_ext_schema
Sweet =)
This doesn't work for me. Is it because my marketplace is not US? Do I need to change something in the code to make it work?
What exactly doesn't work?
This doesn't work for me. Is it because my marketplace is not US? Do I need to change something in the code to make it work?
What exactly doesn't work?
I'm getting 420 error
This doesn't work for me. Is it because my marketplace is not US? Do I need to change something in the code to make it work?
What exactly doesn't work?
I'm getting 420 error
How about keyId?
This doesn't work for me. Is it because my marketplace is not US? Do I need to change something in the code to make it work?
What exactly doesn't work?
I'm getting 420 error
How about keyId?
KeyId is getting generated, I can even generate signatures but when signatures are used to accept offer, I get 420
This doesn't work for me. Is it because my marketplace is not US? Do I need to change something in the code to make it work?
What exactly doesn't work?
I'm getting 420 error
How about keyId?
KeyId is getting generated, I can even generate signatures but when signatures are used to accept offer, I get 420
Did you change routes to the current routes in your region?
routes = {
"GetOffers": "",
"AcceptOffer": "",
.
.
.
}
This doesn't work for me. Is it because my marketplace is not US? Do I need to change something in the code to make it work?
What exactly doesn't work?
I'm getting 420 error
How about keyId?
KeyId is getting generated, I can even generate signatures but when signatures are used to accept offer, I get 420
Did you change routes to the current routes in your region?
routes = { "GetOffers": "", "AcceptOffer": "", . . . }
Yes I have :-(
Is somebody using this outside US? Please ping me on telegram (link in bio).
This doesn't work for me. Is it because my marketplace is not US? Do I need to change something in the code to make it work?
What exactly doesn't work?
I'm getting 420 error
How about keyId?
KeyId is getting generated, I can even generate signatures but when signatures are used to accept offer, I get 420
Did you change routes to the current routes in your region?
routes = { "GetOffers": "", "AcceptOffer": "", . . . }
Any way to contact you?
Okay, here's my solution: https://github.com/julio03451/AmazonFlexUnlimited420
As rsyccd said, you should avoid using the chain that is provided in chains.json. Get the chain from your device and use it instead. However, this chain is working for the moment.
Also when you get the chain from your device you can update osPatchLevel, vendorPatchLevel and bootPatchLevel to the current ones.
Great job on chain.py very clever 👍
@julio03451 hi. Thx for your time!
can you pls write steps for start your code? If i need real android device for parse some certificates? Or all generation inside your version code?
@julio03451 hi. Thx for your time!
can you pls write steps for start your code? If i need real android device for parse some certificates? Or all generation inside your version code?
Just run python app.py
in a terminal and follow the instructions. Nothing special is needed
@fullsendai I'm not a fan of adding features more than just grabbing blocks. All these I arrived, IO, photo bypass functions are just too much for me. So I didn't even try to look that way
By the way, lumo93 added gui to my fork. If anyone is interested, I created a branch with this gui version: https://github.com/julio03451/AmazonFlexUnlimited420/tree/GUI-version
I got this error at acceptOffer () function if request.status_code == 420: self.register_attestation() TypeError: FlexUnlimited.register_attestation() missing 1 required positional argument: 'cert_chain'
Any help will be apireciated. Thank you
I got this error at acceptOffer () function if request.status_code == 420: self.register_attestation() TypeError: FlexUnlimited.register_attestation() missing 1 required positional argument: 'cert_chain'
Any help will be apireciated. Thank you
Did this solution work before for you?
I got this error at acceptOffer () function if request.status_code == 420: self.register_attestation() TypeError: FlexUnlimited.register_attestation() missing 1 required positional argument: 'cert_chain' Any help will be apireciated. Thank you
Did this solution work before for you?
Thank you. No, It didn't work. When I tried to accept an offer the error raised because of missing argument in the function acceotOffer() if request.status_code == 420: self.register_attestation(missed argument )
I understand why you got this:
TypeError: FlexUnlimited.register_attestation() missing 1 required positional argument: 'cert_chain'
I will fix this soon, its not a problem.
But I don't understand why you can't accept an offer. I just checked and it works for me fine
I understand why you got this:
TypeError: FlexUnlimited.register_attestation() missing 1 required positional argument: 'cert_chain'
I will fix this soon, its not a problem. But I don't understand why you can't accept an offer. I just checked and it works for me fine
Thank you so much, I don't know why I get 420 code. I will try again when you fix it and see what's wrong.
I understand why you got this:
TypeError: FlexUnlimited.register_attestation() missing 1 required positional argument: 'cert_chain'
I will fix this soon, its not a problem. But I don't understand why you can't accept an offer. I just checked and it works for me fineThank you so much, I don't know why I get 420 code. I will try again when you fix it and see what's wrong.
Try now
I understand why you got this:
TypeError: FlexUnlimited.register_attestation() missing 1 required positional argument: 'cert_chain'
I will fix this soon, its not a problem. But I don't understand why you can't accept an offer. I just checked and it works for me fineThank you so much, I don't know why I get 420 code. I will try again when you fix it and see what's wrong.
Try now
I think is working now. There is no offers available now in my area but I got the message "OFFER already taken"
Also when you g
How do you extract the chains? or how do they work?
I understand why you got this:
TypeError: FlexUnlimited.register_attestation() missing 1 required positional argument: 'cert_chain'
I will fix this soon, its not a problem. But I don't understand why you can't accept an offer. I just checked and it works for me fineThank you so much, I don't know why I get 420 code. I will try again when you fix it and see what's wrong.
Try now
Julio03451 great thinking - nice work and thank you.
it seems @julio03451 solution stopped working today... now I'm getting {'code': 201, 'message': 'Invalid attestation object '}
Yes. I also got the issue: {'code': 201, 'message': 'Invalid attestation object '} 403. @julio03451 , Thank your work. Do you have a solution?
anyone has a clue how to fix this "code":201,"message":"Invalid attestation object"}' ???
Why you don't understand is that everything that is published in public will be corrected by amazon!!!! This is the 3rd such situation and you don't learn anything from it...!
based on what i read from start of this discussion we needed new chain for each program right?
so maybe this issue is happening because everyone used the chain already provided inside the code?
if it is that, how can we generate our own chain !
Hi guys, I don't own a commercial bot so a classic situation like with mdesilva, sdubzz or lumo93 happened - I found a full time job. 😄 So I can't dedicate enough time to finding a solution now. However, I don't have magic, so if Amazon guys implemented real key attestation as written in google's best practices, this should be the end.
But I still believe there are interested people at Amazon who will always leave a backdoor.
Let's find the solution here