DEV Community

Nelson Figueroa
Nelson Figueroa

Posted on • Originally published at nelson.cloud on

Making Life More Difficult for Bank Scammers

If you’ve been around you know I enjoy spamming phishing/scamming sites. I recently received this fake Chase email and decided to go down another phishing/scamming attempt.

Phishing Email

The email linked to a Google Drive link of a PDF.

Google Drive PDF

The PDF itself links to somewhere else. I clicked on the PDF and after some redirects I ultimately landed on a fake Chase login site. Look at the URL lol.

Fake Chase login form

Next, I opened my browser dev tools, I filled in the form and pressed “Sign In”.

A POST request goes out to https://secure005.access.chaise.com.secure-accessaccount.com/submit.php with this payload:

{"uid":"1ef25781cb3fd42f981b2bbb183d9887","ip":"138.199.35.102","uagent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:122.0) Gecko/20100101 Firefox/122.0","stp":"0","j_username":"anon","j_password":"password","securityToken":""}
Enter fullscreen mode Exit fullscreen mode

Then I was shown this page:

Error message

And of course on the frontend there’s a message about incorrect credentials. It’s one of the most common tricks these people use.

Attempting to submit new credentials does nothing. I noticed that the “reset your password” link is the only way forward so I clicked that and it took me to this page:

One-time code form

It’s asking for a one-time code. I’m not really sure how they expect people to enter a code that they normally receive after submitting correct credentials. Not only that but they don’t even know the phone number of the user. Either way, I filled in 000000 and hit “Next”.

Another POST request goes out to the same URL as before: https://secure005.access.chaise.com.secure-accessaccount.com/submit.php with this JSON:

{"uid":"1ef25781cb3fd42f981b2bbb183d9887","stp":"1","otp":"000000"}
Enter fullscreen mode Exit fullscreen mode

(I think it’s obvious now that the stp parameter that keeps showing up represents the step of the fake password recovery process. And based on the value of step, the logic of submit.php parses the JSON accordingly.)

Then I landed on this page that asks me for my card information:

credit card form

I once again filled the form with fake information and hit “Next”. Another POST request went out to the same URL as before. The main thing that changes here are the headers and the JSON payload.

{"uid":"1ef25781cb3fd42f981b2bbb183d9887","stp":"2","cnum":"6504 8764 7593 8248","expd":"03/24","cvv":"333"}
Enter fullscreen mode Exit fullscreen mode

(Also, I haven’t been showing the headers because they’re not that interesting, but I am keeping track of them for scripting purposes later.)

Next, I was shown this form. Notice how the first field says “Full Number”. I’m pretty sure they meant “Full Name” lol.

personal details form

Once again, I filled out and submitted the form.

Once again, a POST request goes out to the same URL. This time the JSON payload looks like this:

{"uid":"1ef25781cb3fd42f981b2bbb183d9887","stp":"3","fullname":"Fuck You","bdate":"01/01/1900","ssn":"123-74-6772","phone":"(827) 373-8139","address":"some st","city":"some city","state":"FU","zip":"82920","email":"nah@fu.com"}
Enter fullscreen mode Exit fullscreen mode

The fullname key in the JSON payload confirms that they meant to write “Full Name” in the field as opposed to “Full Number” lol.

After submitting the previous form I was shown yet another one, this time asking for email address and email password. They are really thorough. They also asked for my email in the previous step so that was a bit redundant.

email form

I typed in some fake credentials and submitted the form. A POST request goes out to the same URL as before with the following JSON payload:

{"uid":"1ef25781cb3fd42f981b2bbb183d9887","stp":"4","cemail":"nah@fu.com","bdate":"ajlksdasdjl"}
Enter fullscreen mode Exit fullscreen mode

Then I was redirected to the offical Chase site:

Official Chase site

Spamming Fake Information with Python

If you’ve read my previous articles about scams and phishing, you know what’s next. It’s time to write up a Python script to spam these people with fake information and hopefully make their lives harder.

These guys were thorough so I’ll need to dynamically create 5 different payloads and send them to the url. Thankfully it’s the same endpoint for all of these payloads.

I want to dynamically generate headers and payloads that seem as realstic as possible. These scammers were thorough so I want to be thorough in making their lives more difficult (also I’m unemployed right now so I have a lot of free time. Someone please hire me 🥺)

This is the Python script I came up with:

from faker import Faker
import requests
import uuid
import random
import string

fake = Faker()
url = "https://secure005.access.chaise.com.secure-accessaccount.com/submit.php"

# headers that are consistent among every request
base_headers = {
    "Host": "secure005.access.chaise.com.secure-accessaccount.com",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:122.0) Gecko/20100101 Firefox/122.0",
    "Accept": "*/*",
    "Accept-Language": "en-US,en;q=0.5",
    "Accept-Encoding": "gzip, deflate, br",
    "Content-Type": "application/x-www-form-urlencoded",
    "Origin": "https://secure005.access.chaise.com.secure-accessaccount.com",
    "DNT": "1",
    "Sec-GPC": "1",
    "Connection": "keep-alive",
    "Referer": "https://secure005.access.chaise.com.secure-accessaccount.com/",
    "Sec-Fetch-Dest": "empty",
    "Sec-Fetch-Mode": "cors",
    "Sec-Fetch-Site": "same-origin",
    "Pragma": "no-cache",
    "Cache-Control": "no-cache",
}

step_0_cookie = None
step_1_cookie = None
step_2_cookie = None
step_3_cookie = None
step_4_cookie = None

step_0_payload = None
step_1_payload = None
step_2_payload = None
step_3_payload = None
step_4_payload = None


def generate_headers_and_payloads():
    # telling Python to modify the variables on a global scope
    global step_0_cookie, step_1_cookie, step_2_cookie, step_3_cookie, step_4_cookie, step_0_payload, step_1_payload, step_2_payload, step_3_payload, step_4_payload

    fake_phpsessid = "".join(random.choices(string.ascii_letters + string.digits, k=26))

    step_0_cookie = {
        "Cookie": f"PHPSESSID={fake_phpsessid}; stp=0; ppath=web%2Fauth%2Fdashboard%23%2Fdashboard%2Findex%2Findex"
    }
    step_1_cookie = {
        "Cookie": f"PHPSESSID={fake_phpsessid}; stp=1; ppath=oamo/identity/help/passwordhelp/"
    }
    step_2_cookie = {
        "Cookie": f"PHPSESSID={fake_phpsessid}; stp=2; ppath=oamo/identity/help/passwordhelp/"
    }
    step_3_cookie = {
        "Cookie": f"PHPSESSID={fake_phpsessid}; stp=3; ppath=oamo/identity/help/passwordhelp/"
    }
    step_4_cookie = {
        "Cookie": f"PHPSESSID={fake_phpsessid}; stp=4; ppath=oamo/identity/help/passwordhelp/"
    }

    uid = uuid.uuid4().hex

    step_0_payload = {
        "uid": uid,
        "ip": fake.ipv4(),
        "uagent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:122.0) Gecko/20100101 Firefox/122.0",
        "stp": "0",
        "j_username": fake.simple_profile()["username"],
        "j_password": fake.password(length=12),
        "securityToken": "",
    }

    step_1_payload = {
        "uid": uid,
        "stp": "1",
        "otp": fake.random_int(min=100000, max=999999),
    }

    # the credit card in the payload has spaces in between every 4 digits, so I am replicating this
    credit_card_number = fake.credit_card_number("mastercard")
    # adding spaces in between every 4 digits
    credit_card_number = " ".join(
        [credit_card_number[i : i + 4] for i in range(0, len(credit_card_number), 4)]
    )

    step_2_payload = {
        "uid": uid,
        "stp": "2",
        "cnum": credit_card_number,
        "expd": fake.credit_card_expire(),
        "cvv": fake.credit_card_security_code(),
    }

    step_3_payload = {
        "uid": uid,
        "stp": "3",
        "fullname": fake.name(),
        "bdate": fake.date_of_birth(minimum_age=18).strftime("%m/%d/%Y"),
        "ssn": fake.ssn(),
        "phone": fake.phone_number(),
        "address": fake.street_address(),
        "city": fake.city(),
        "state": fake.state_abbr(),
        "zip": fake.postcode(),
        "email": fake.simple_profile()["mail"],
    }

    step_4_payload = {
        "uid": uid,
        "stp": "4",
        "cemail": fake.simple_profile()["mail"],
        "bdate": fake.password(
            length=12
        ),  # the parameter is bdate but in the frontend it asked for password
    }


requests_sent = 0
while True:
    # dynamically generate fake headers and JSON payloads
    generate_headers_and_payloads()

    # handle exceptions so that the script continues even if there are connection issues
    try:
        # for each step, add in corresponding cookie and random content-length to headers
        base_headers.update(step_0_cookie)
        base_headers.update({"Content-Length": str(fake.random_int(min=80, max=215))})
        response = requests.post(url, headers=base_headers, json=step_0_payload)
        print(f"Step 0 status code: {response.status_code}")

        base_headers.update(step_1_cookie)
        base_headers.update({"Content-Length": str(fake.random_int(min=80, max=215))})
        response = requests.post(url, headers=base_headers, json=step_1_payload)
        print(f"Step 1 status code: {response.status_code}")

        base_headers.update(step_2_cookie)
        base_headers.update({"Content-Length": str(fake.random_int(min=80, max=215))})
        response = requests.post(url, headers=base_headers, json=step_2_payload)
        print(f"Step 2 status code: {response.status_code}")

        base_headers.update(step_3_cookie)
        base_headers.update({"Content-Length": str(fake.random_int(min=80, max=215))})
        response = requests.post(url, headers=base_headers, json=step_3_payload)
        print(f"Step 3 status code: {response.status_code}")

        base_headers.update(step_4_cookie)
        base_headers.update({"Content-Length": str(fake.random_int(min=80, max=215))})
        response = requests.post(url, headers=base_headers, json=step_4_payload)
        print(f"Step 4 status code: {response.status_code}")

        requests_sent = requests_sent + 5
        print(f"Requests sent: {requests_sent}")
    except requests.exceptions.RequestException as e:
        print({e})
Enter fullscreen mode Exit fullscreen mode

It’s quite lengthy but it works. I ran the script in the background and went about my day.

Terminal output after running the Python script

More Retaliation Against Scammers

If you enjoyed this, I’ve done a few other posts similar to this one:

Top comments (4)

Collapse
 
michaeltharrington profile image
Michael Tharrington

Wow, this is so freaking dope!

You are doing noble work, my friend. 💚

I'm following ya now. I love these kinda stories.

As a non-technical person, I'd like to hear a bit more about what this script is like for the scammer. I'm curious, does this just keep on sending bogus info that looks real their way?

Collapse
 
nelsonfigueroa profile image
Nelson Figueroa

I'm curious, does this just keep on sending bogus info that looks real their way?

That's exactly it! After all the fake info I sent their way they would have no way of telling what's real and what isn't. They would have to try all the banking information they saved until something worked. With the amount of data I sent their way this would take forever. It's probably easier for them to just start over.

Collapse
 
snailplissken profile image
SnailPlissken

Won’t the scammers notice an abnormal increase in “scammed people” and just throw out everything?
Or is there random time between each request to make it even harder for them to notice?

Collapse
 
nelsonfigueroa profile image
Nelson Figueroa

Yeah the scammers would notice an increase in "scammed people". Adding a random time delay between each request would have made the requests look even more real.

My goal was to make their operation unsuccessful. If they did get any legitimate information it would be buried among all the fake data I sent their way. They would have to try out all the data and see what actually works. This would be extremely time-consuming for them and it's probably easier for them to give up and start over. Given that the scammer site is no longer up, I would like to think that they actually did give up.

I'm sure they'll try again under a different domain though.