---
# System prepended metadata

title: Обманчивые смартконтракты

---

# Обманчивые смартконтракты

Авторы: artur.lukianov@cyberok.ru, 

Привет, Хабр! Меня зовут Артур и я являюсь стажёром в компании CyberOK. В этой статье я поделюсь с вами интересной находкой.

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

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

## Анализ вызовов между контрактами и перевод денег

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

Один из простых и эффективных способов решения этой задачи - отслеживание вызовов между контрактами с помощью эмуляции предыдущих транзакций. А данные о вызовах контрактов позволяют быстро определить паттерны основных атак.

Реализовав данную стратегию для атак типа [reentrancy attack](https://habr.com/ru/post/655639/) мы сразу обнаружили интересный контракт

![](https://i.imgur.com/mkXJya2.png)

Рассмотрим транзакцию подробнее:
![](https://i.imgur.com/kF7vk7q.png)

Это выглядит как неудачная попытка эксплуатации reentrancy - выполнение транзакции закончилось через revert, а деньги не были пересланы на атакующий контракт. 

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

## Разбор найденных смарт-контрактов

Рассмотрим смарт-контракт, на который шла атака:
(TODO: все ссылки вынести на наш гитхаб)
Одна из функций показалась нам наиболее занимательной:

```solidity=
...
pragma solidity ^0.4.25;

contract PEOPLE_BANK
{
    function Collect(uint _am) public payable
    {
...            
        if(msg.sender.call.value(_am)())
            {
...                LogFile.AddMessage(msg.sender,_am,"Collect");
            }
...   
function PEOPLE_BANK(address log) public{
        LogFile = Log(log);
    }
}


```

Строчка `msg.sender.call.value(_am)()` - классический пример уязвимого к reentrancy кода.
На первый взгляд в исходном коде смарт-контракта ничто не мешает проведению атаки, но как вы видели выше, эксплуатация контракта приводила к отмене транзакции - revert. 
Приглядевшись повнимательнее, можно заметить что PEOPLE_BANK использует контракт Log. Исходный код Log находится в том же файле. В нём нет ничего что могло бы вызвать revert. 

Заглянем глубже в байткод контракта..

Декомпилируем контракт и обнаруживаем странное...
![](https://i.imgur.com/QAQw3cw.png)
```python=
# Palkeoramix decompiler. 

def AddMessage(address _adr, uint256 _val, string _data): # not payable
  mem[128 len _data.length] = _data[all]
  stor1 = _adr
  stor4 = block.timestamp
  stor3 = _val
  uint256(stor2[]) = Array(len=_data.length, data=_data[all])
  stor0.length++
  addr(stor0[stor0.length].field_0) = stor1
  if 31 >= stor2.length:
      stor290D[stor0.length] = stor2.length
      idx = 0
      while stor[(4 * stor0.length) + 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e564].length + 31 / 32 > idx:
          stor[idx + sha3((4 * stor0.length) + 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e564)] = 0
          idx = idx + 1
          continue 
  else:
      stor290D[stor0.length] = Mask(255, 1, (256 * not bool(stor2.length)) - 1 and stor2.length) + 1
      if not Mask(255, 1, (256 * not bool(stor2.length)) - 1 and stor2.length):
          idx = 0
          while stor[(4 * stor0.length) + 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e564].length + 31 / 32 > idx:
              stor[idx + sha3((4 * stor0.length) + 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e564)] = 0
              idx = idx + 1
              continue 
      else:
          s = 0
          idx = 0
          while stor2.length + 31 / 32 > idx:
              stor[s + sha3((4 * stor0.length) + 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e564)] = uint256(stor2[idx])
              s = s + 1
              idx = idx + 1
              continue 
          idx = stor2.length + 31 / 32
          while stor[(4 * stor0.length) + 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e564].length + 31 / 32 > idx:
              stor[idx + sha3((4 * stor0.length) + 0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e564)] = 0
              idx = idx + 1
              continue 
  stor290D[stor0.length] = stor3
  stor290D[stor0.length] = stor4
  
  # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  if caller == stor5: 
      if stor7 != _adr:
          if stor6 != tx.origin:
              require 0 < _data.length
              if 'C' == Mask(8, 248, mem[128]):
                  require _val <= 0
  # !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
```

Этой части кода вообще нет в исходнике!
Если мы выводим деньги с контракта (операция начинается с 'C' - то есть 'Collect'), то требуется чтобы выводимых средств было меньше либо равно нулю, за исключением одного адреса (который находится на storage slot 6 - "0x0a494fec232c75df8ba0a781015c2382fef5abc8"). 
Это и мешает проэксплуатировать такую простую уязвимость.

Так же важно отметить, что solidity 0.4.25, имеет интересную особоенность.
При неудачной эксплуатации, будет вызываться revert, который вызывает отмену всех вызовов через call, а криптовалюта посланная на этот контракт на нём и оставалась. 

Кроме того, контракт требует перевести на него 1 ETH для попытки эксплуатации. Таким образом, попытки эксплуатации, которые обнаружил, наш анализатор блокчейна, заканчиваются просто переводом средств с атакующего контракта, на баланс атакуемого.

Данная ситуация выглядит, как классический хонепот, кто то как специально сделал уязвимость в контракте, но при этом позаботился о том, что бы деньги терял именно атакующий.
Что бы более глубоко понять зачем так сделали, изучим детальнее переводы денег, которые связанны с этим контрактом.


## Расследование
Отследив путь этих 20 ETH, можно заметить что PEOPLE_BANK переехал на новый адрес: https://etherscan.io/address/0xe07e724a96866daae308870d1a5eb41258436b53

![](https://i.imgur.com/H4S5rTq.png)

Взглянем на цепочку транзакций, которая привела ETH на адрес этого контракта, используя утилиту от CyberOK:
![](https://i.imgur.com/OFprdzP.png)


Из  графа можно сделать следующие выводы:
- В сети существует много ханипотов, связанных друг с другом
- Существовало несколько цепочек, которые соединились некоторое время назад

Подробный анализ этих транзакций раскрывает интересный факт - смартконтракт всё время "переезжает" на новые адреса. Вероятнее всего это было сделано чтобы код контракта отображался в выдаче от etherscan (500 последних verified контрактов). Код контракта не меняется, но его имя образуется как `<случайное слово>_BANK`

![](https://i.imgur.com/LytjoDN.png)

\- Цепочка по которым криптовалюта поступила на этот смартконтракт

Кроме того, существует ещё один контракт, связанный с BANK (1), находящийся на параллельной цепочке, Game (2). Его код отличается от BANK и не имеет явных уязвимостей, но схожее поведение (именование, "переезды") и пересечение цепочек транзакций на некоторых адресах, не оставляет сомнений что эти два контракта принадлежат одному злоумышленнику.

Глубже в цепочке можно обнаружить и другие honeypot-ы:
![](https://i.imgur.com/VaI6s63.png)
Gift_for_you_1: https://etherscan.io/address/0x8bbf2d91e3c601df2c71c4ee98e87351922f8aa7#code

Время от времени на эти ханипоты попадается по несколько человек:
Попытки вывести криптовалюту с Game: https://etherscan.io/address/0xe37b75941d9b8e3139e16a774faa2d9fb1fc9f28
![](https://i.imgur.com/xA9FSTr.png)

BANK: https://etherscan.io/address/0x93d3395b08bbd0d9998ec9ed00ca9d329328964e#internaltx
![](https://i.imgur.com/srU9lny.png)

Глубже в цепочке можно найти еще больше honeypot-ов:
```
???_BANK
PreSaleFund
try_to_Play
QUIZ_GAME
For_Test
GO_GO_GO
Loan
Distributor
Multiplicator
EthMultiplicator
Conductor
Gift_???
ENIGMA
EXPERIMENTAL_ETH_AUCTION
AddressLotteryV2
```

Пример контракта Game: https://etherscan.io/address/0xe37b75941d9b8e3139e16a774faa2d9fb1fc9f28#code

Ссылка на гитхаб со сборником ханипотов: https://github.com/cyberok-org/honeypot-zoo

И ещё немного любопытной статистики:
- 

## Заключение.

Тема ханипотов не нова, и уже была давно описана: https://www.slideshare.net/PolySwarm/smart-contract-honeypots-for-profit-and-fun-bha. Удивительно что эта схема продолжает работать уже на протяжении более 3 лет.

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