mdesilva / AmazonFlexUnlimited

Automate the process of grabbing job blocks from Amazon Flex
168 stars 102 forks source link

420 code solution #171

Open julio03451 opened 6 months ago

julio03451 commented 6 months ago

Let's find the solution here

FlavaClover commented 5 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?

julio03451 commented 5 months ago

Sorry, can you explain how to get the 'privateAttestationKey', please?

It's ec_private_key that comes from Chain.py

hstrauch commented 5 months ago

Hi all, the @julio03451 solution its working only on Android? What would be the difference with iOS?

hoqua commented 5 months ago

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.

MY20-PHEV commented 5 months ago

Is it possible to create unique chains from an emulator using getCertificateChain() ? or does it have to be a physical android device running

hoqua commented 5 months ago

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

OpenVisionz commented 5 months ago

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.

MY20-PHEV commented 5 months ago

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.

https://t.me/flexautosign

OpenVisionz commented 5 months ago

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.

https://t.me/flexautosign

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.

rsyccd commented 5 months ago

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.

vineet4183 commented 5 months ago

Has anyone written an Android app to getCerificate chain?

hoqua commented 5 months ago

Has anyone written an Android app to getCerificate chain?

I am trying to just generate certs myself using openssl. but no luck yet

julio03451 commented 5 months ago

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

vineet4183 commented 5 months ago

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" ?

SediqiRobert commented 5 months ago

@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"???

vineet4183 commented 5 months ago

@julio03451 Can I please connect with you offline? I need some help with code. My mail id is in bio.

hoqua commented 5 months ago

@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

itsjjpp21 commented 5 months ago

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?

julio03451 commented 5 months ago

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

julio03451 commented 5 months ago
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())
vineet4183 commented 5 months ago

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?

itsjjpp21 commented 5 months ago

All you need is chatgpt and ASN.1 schema: https://developer.android.com/privacy-and-security/security-key-attestation#key_attestation_ext_schema

Sweet =)

julio03451 commented 5 months ago

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?

vineet4183 commented 5 months ago

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

julio03451 commented 5 months ago

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?

vineet4183 commented 5 months ago

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

julio03451 commented 5 months ago

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": "",
    .
    .
    .
  }
vineet4183 commented 5 months ago

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 :-(

vineet4183 commented 5 months ago

Is somebody using this outside US? Please ping me on telegram (link in bio).

Dolphet commented 5 months ago

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?

asadbek064 commented 5 months ago

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 👍

Vasa211 commented 4 months ago

@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 commented 4 months ago

@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

julio03451 commented 4 months ago

@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

julio03451 commented 4 months ago

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

nemo03 commented 4 months ago

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

julio03451 commented 4 months ago

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?

nemo03 commented 4 months ago

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 )

julio03451 commented 4 months ago

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

nemo03 commented 4 months ago

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.

julio03451 commented 4 months ago

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.

Try now

nemo03 commented 4 months ago

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.

Try now

I think is working now. There is no offers available now in my area but I got the message "OFFER already taken"

Dolphet commented 4 months ago

Also when you g

How do you extract the chains? or how do they work?

lpqssq commented 4 months ago

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.

Try now

Julio03451 great thinking - nice work and thank you.

biabock commented 3 months ago

it seems @julio03451 solution stopped working today... now I'm getting {'code': 201, 'message': 'Invalid attestation object '}

huabtc commented 3 months ago

Yes. I also got the issue: {'code': 201, 'message': 'Invalid attestation object '} 403. @julio03451 , Thank your work. Do you have a solution?

JAPP05 commented 3 months ago

anyone has a clue how to fix this "code":201,"message":"Invalid attestation object"}' ???

Vasa211 commented 3 months ago

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...!

ripinghot commented 3 months ago

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 !

julio03451 commented 3 months ago

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.