Script to fill a phisher's database with thousands of fake credentials

avatar
(Edited)

Friday night.. beer & bots time!   =]

A new PHISHING campaign hit Hive in the past couple of days.. 👇

@louis88, @guiltyparties and @phage93 were immediately on it and started spreading awareness (NO DATABASE WAS HACKED, IT'S JUST PHISHING!!).

I was busy at work today (crazy release day) and then immediately after I went out for dinner so I was not aware of it happening.


Guiltyparties updated his github with his list of known phishing links so, since my bot already consumes it, it would start automatically fighting against the new phishing wave.

The new url was added though only after the attacker managed to put out most of his messages already:

image.png

I therefore decided to (run the bot against old messages and) make the attacker's life more difficult in case someone indeed fell for it. I filled his database with thousands of fake credentials! :evil_laugh:

I would like to see his/her face when they first see the amount of credentials they think they stole just to then realize that they are all not working. Priceless.   =]

After I wrote the script to fill their database with crap, I left it running for about 2 hours by now and I will leave it running for the next couple of days changing a bit the rules as well in order to create different types of fake credentials.

You can find below my nodeJs code in case someone wants to use this in the future. I will for sure after other attacks since it's usually quite trivial to figure out how to write bad data into their DB - my script can easily be adjusted for that.

For example, in the case of the PHISHING DOMAIN steemconnect.xyz, it was just a matter of figuring out how the request to store the stolen credentials looked like and start sending fake ones:

( The target phishing site running in my VM )

Without further ado.. HERE IS THE CODE:

const dhive = require('@hiveio/dhive');
const crypto = require('crypto');
const fetch = require('node-fetch');
const btoa = require('btoa');
const flatten = require('lodash/flattenDeep');

const targetTagsForNewAutors = [
  'hive', 'photography', 'blockchain', 'travel', 'actifit', 'crytpocurrency',
];

const nap = ms => new Promise(res => setTimeout(res, ms));

const generatePwd = (author = '') => {
  if (Math.random() > 0.85) {
    // Fake Password
    let fakePwd = btoa(author.slice(-2)).replace(/=/g, '')
      + author.split('').reverse().join('').replace('b', '').replace('c', '_').replace('i', ' '); // eslint-disable-line newline-per-chained-call
    fakePwd += Math.random > 0.5 ? btoa(author.slice(0, 3)).replace(/=/g, '') : `${Math.random()}`.slice(-5);
    return fakePwd;
  }
  // Fake owner or active key
  const array = crypto.randomBytes(10);
  const keyFromSeed = dhive.PrivateKey.fromSeed(array).toString();
  const privateKey = `${Math.random() > 0.5 ? 'P' : ''}${keyFromSeed}`;
  return privateKey;
};

// Get list of authors that just posted for the given tag
const getExistingAuthors = tag => new Promise((resolve) => {
  fetch('https://api.hive.blog/', {
    method: 'POST',
    headers: {
      accept: 'application/json',
      'cache-control': 'no-cache',
      'content-type': 'application/json',
      'sec-fetch-dest': 'empty',
      'sec-fetch-mode': 'cors',
      'sec-fetch-site': 'same-site',
    },
    referrer: 'https://hive.blog/',
    referrerPolicy: 'strict-origin-when-cross-origin',
    body: `{"id":1,"jsonrpc":"2.0","method":"bridge.get_ranked_posts","params":{"sort":"created","tag":"${tag}","observer":null}}`,
    mode: 'cors',
    credentials: 'omit',
  })
    .then(resp => resp.json())
    .then(({ result }) => resolve(result.map(entry => entry.author)));
});

const stuffing = (credentials = []) => new Promise(async (resolve) => {
  for (let id = 0; id < credentials.length; id++) {
    const { author, pwd } = credentials[id];
    fetch('https://steemconnect.xyz/insert.php', {
      headers: {
        accept: 'application/json, text/javascript, */*; q=0.01',
        'accept-language': 'en-US,en;q=0.9',
        'cache-control': 'no-cache',
        'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
        pragma: 'no-cache',
        'sec-fetch-dest': 'empty',
        'sec-fetch-mode': 'cors',
        'sec-fetch-site': 'same-origin',
        'x-requested-with': 'XMLHttpRequest',
      },
      referrer: 'https://steemconnect.xyz/',
      referrerPolicy: 'strict-origin-when-cross-origin',
      body: `username=${author}&password=${pwd}`,
      method: 'POST',
      mode: 'cors',
      credentials: 'include',
    })
      .then(resp => ({ status: resp.status, text: resp.text() }))
      .then(data => console.log(`Sent: ${author} / ${pwd} --> Response: ${data.status}`));
    await nap(100);
  }
  await nap(3 * 1000);
  resolve();
});

const spamDb = () => new Promise((resolve) => {
  console.log('> Fetching real hive users');
  const promises = targetTagsForNewAutors.map(tag => getExistingAuthors(tag));
  Promise.all(promises)
    .then(async (results) => {
      const authorsSet = new Set(flatten(results)); // merged array of unique authors
      const authors = Array.from(authorsSet);
      const credentials = authors.map(author => ({ author, pwd: generatePwd(author) }));
      console.log('> Spamming DB with entries:', credentials.length);
      await stuffing(credentials);
      resolve();
    });
});

const start = async () => {
  while (true) { // eslint-disable-line no-constant-condition
    console.log('-----------');
    await spamDb();
    const napDuration = (Math.random() * 30 * 1000).toFixed(0);
    console.log('> napping for ms', napDuration);
    await nap(napDuration);
  }
};
start();


HERE ARE SOME LOGS THAT SHOW ITS OUTPUT:

image.png




It currently runs on batches of about 100 writes every about 20 seconds with sligth randomizations of the wait time between one batch and the other in order to make the detection of fake data patterns more difficult to spot.

Good luck phisher! LOL


I am now currently finishing
working on...

  • Allowing (top 50?) witnesses and other selected users to immediately blacklist a domain for @keys-defender simply sending it a wallet memo. This list will initially include: @guiltyparties, @louis88, @phage93, @jlsplatts (thanks for the delegation by the way!), @enforcer48 - and others will be added in the next few days.

  • Allowing a domain to be blacklisted if 10 users report it in a short window of time (24 hours?).


I will post an update here tomorrow(-ish) with my development progress.

Take care,
@keys-defender / @gaottantacinque



0
0
0.000
8 comments
avatar

You are the third person I know doing this. Everyone hates scammers.

0
0
0.000
avatar

Fucking BRILLIANT!!!! Now we are talking, offense!!

0
0
0.000
avatar

Ha...that's funny.

Wonder if they've caught on.

0
0
0.000
avatar

Their phishing campaign ended after the first batch so maybe they did!   =]

0
0
0.000