[EOS 해킹 Issue 분석] EOSBet 2차 해킹 Part 2

OZ
EOS Chrome
Published in
7 min readNov 26, 2018

--

안녕하세요 여러분~ OZ입니다! 오랜만에 뵙습니다 :) EOSBet 2차 해킹 마지막 파트를 남겨두고 너무 오랜시간 제 자리를 공석으로 둔 것 같아 얼른 달려왔습니다!

저번 포스팅에서 말씀드렸던 바와 같이, 요번 포스팅에서는 EOSBet 해킹의 조금 더 기술적인, 개발자 분들께 도움이 될 만한 분석글을 작성해 보았어요. 물론 비개발자 분들도 이해하시기 쉽도록 열심히 노력해서 써 보았으니 한번 꼼꼼히 읽어봐 주시면 감사하겠습니다! 적극적인 소통 언제나 환영하고 있으니 혹시 의문점이나 이견을 갖고 계신 분들은 댓글 남겨주시면 정말정말 좋을것 같네요 :)!!

지난 포스팅이 궁금하신 분들은 아래의 링크를 참고해주세요!:
EOSBet 2차 해킹 Part 1

[EOSBet이 공개한 해킹에 대한 기술적인 설명]

eosio.token의 핵심 코드는 들어오는(incoming) EOS 토큰이 있을 경우 그 토큰의 수신인과 발신인 모두에게 ‘공지’를 하도록 설계되어 있다.

EOSBet의 다이스 컨트랙트도 마찬가지로 이 공지 기능을 탑재하고 있다. 다이스 컨트랙트의 경우 스마트 토큰 컨트랙트를 시행할 시 제일 처음으로 본인들이 EOS 토큰의 발신인인지에 관해 확인한다. 이 때, EOSBet이 발신인인 것이 확인 되면 컨트랙트는 별다른 변수 없이 작성된 코드 그대로 진행되는 것이 예상된 행동이다 (왜냐하면 EOSBet이 승자에게 상금을 지급중에 있는 발신인이 맞으므로).

만일 EOS 토큰의 발신인이 EOSBet이 아닌 경우는 두가지로 나뉠 수 있는데 1. EOSBet이 수신인인 경우 와 2. EOSBet이 발신인, 수신인도 아닌 다른 유저들이 발신인인 경우이다. 그러나 EOSBet은 이 과정에서 치명적인 컨트랙트상 실수를 범한다 — 2번의 경우를 간과하고 1번의 경우에 해당하는 컨트랙트만을 작성했기 때문이다.

그들이 작성한 코드대로 스마트 컨트랙트가 진행될 시, 다이스 컨트랙트는 EOSBet이 발신인이 아닌 모든 토큰들은 자신의 컨트랙트 내로 보내진다고 가정한다 (EOSBet이 전송되는 모든 토큰들의 수신인). 즉, 완전히 별개의 두 유저 A와 B가 서로 토큰을 전송하고 전송받을 시에도 다이스 컨트랙트에게로 토큰 전송이 진행되고 있다고 ‘공지’가 갈 수 있게 되는 것이다.

이번 해킹 사례에서 해커들은 EOSBet이 간과한 이 ‘뜻밖의 인터랙션’을 이용해 컨트랙트의 취약성을 악용한 것이라 보여진다.

예를 들어, 해커 A와 B가 EOSBet 유저라는 전제 하에 해커 A가 B에게 100 EOS를 전송한다고 가정해보자. 이 때, 실상 다이스 컨트랙트 내로 보내진 EOS 토큰은 아무것도 없으나 다이스 컨트랙트의 결함으로 인해 EOSBet은 자신의 컨트랙트로 100 EOS가 들어왔다고 ‘공지’를 받는다.

이 공지에 따라 다이스 컨트랙트는 상금을 지급하게 되는데, 지급할 시에는 EOSBet의 Operational Wallet으로부터 실효성이 있는 EOS 토큰을 지급하게 된다. 이런 식으로 해커들은 자기들끼리 반복적으로 트랜잭션을 만들며 EOSBet의 자금을 빼돌린 것이다.

EOSBet 측에 따르면, 그들은 자신의 컨트랙트가 토큰의 수신인 이라는 것을 확실하게 검토하지 않았기 때문에 이러한 사태가 일어나게 된 것이라 주장한다.

따라서 이러한 이슈로부터 공격받지 않기 위해 EOSBet은 다음의 라인을 토큰 트랜스퍼에 관련되는 펑션에 추가할 것을 권유한다:

eosio_assert(transfer_data.from == _self || transfer_data.to == _self, “Must be incoming or outgoing transfer”);

만일 토큰을 전송’받기’만을 원하고 (incoming) 전혀 보내지 않을 것이라면 아래의 라인만 추가하면 된다:

eosio_assert(transfer_data.to == _self, “Must be incoming transfer);

EOSBet은 다른 dApp들이 같은 피해를 입지 않게 하기 위해 EOSBet측은 해킹에 쓰인 코드를 공개하지 않기로 했다. 하지만 EOS 스마트 컨트랙트 개발자들에게 악성 컨트랙트가 EOS 컨트랙트 어플라이 펑션에 “코드” 패러미터를 전달할 수 있음을 반드시 알아둬야 한다고 전했다. 따라서 require_recipient() handler를 통해 액션 아규먼트에 명확한 검토가 필요하다고 강조했다.

참조:https://medium.com/@eosbetcasino/eosbet-statement-on-hack-and-1st-dividend-distribution-a5c9aa617eaf

[취약점 패치]

EOSBet이 2차 해킹 피해를 겪은 후 EOS BP중 하나인 EOS Cafe Block은 EOS 컨트랙트 상 ‘알림’을 사용하는 컨트랙트 들의 취약성을 발견해 그에 대한 대응 방법을 공유했다. 그에 따르면, 이 알림으로 부터 오는 모든 패러미터들이 명확하게 체크되어야 하며 컨트랙트 네임과 액션 네임만을 체킹하는 것은 불충분하다고 전했다.

따라서 EOS Cafe Block은 트랜스퍼 알림 기능을 사용하는 모든 컨트랙트에 다음과 같은 체크 구문을 추가할 것을 권유한다:

if (transfer.to != _self) return;

만일 들어오는(incoming) 트랜스퍼에 관해서만 로직을 적용하되, 이 트랜스퍼 액션을 들어오고 나가는 트랜스퍼 둘 다에 재사용하기 위해서는 다음의 구문을 이용하면 된다:

if (transfer.from == _self || transfer.to != _self ) return;

EOS Cafe Block은 이는 컨트랙트상 취약점이고 시스템의 취약점이 아님을 명시했으며 이 취약점 패치를 적용한 많은 컨트랙트들 외에 아직 인지하지 못한 다른 개발자 들에게도 이 패치를 공유할 것을 당부했다.

[마치며…]

2차 해킹이 발생한지 약 한달 전, 첫 해킹이 있기 며칠 앞서서 EOSBet은 본인이 겜블링 dApp중 가장 안전한 게임이라 자부하며 공공연하게 선언했었다. 뿐만 아니라 사건이 있은 후에도 EOSBet은 자체 개발팀과 여러 제3의 기관들을 통해 강도 높게 회계 감사를 해오고 있으며 따라서 보안성이 한층 더 강화되었다고 주장했었다.

그러나 불과 한달만에 또 다른 취약성을 공격한 해킹이 발생하게 되었다. 이는 유저들 사이에 EOS 스마트 컨트랙트가 아직까지 얼마나 치명적인 버그들을 갖고 있는지 경각심을 일깨워주는 계기로 작용했다. 뿐만 아니라 반복되는 기술적 결함과 미숙하고 안일한 게임 운영 정책들 때문에 많은 유저들이 EOSBet에게 등을 돌리고 있으며 반대로 그의 짝퉁이라 여겨져온 Betdice의 승승장구가 이어지고 있는 상황이다. https://steemit.com/kr/@twinbraid/eetdice-eosbet

긴 글 읽어주셔서 감사합니다! 오늘 분석 포스팅이 블록체인 생태계 참여자 모두에게 큰 도움이 되어서 앞으로도 블록체인이 승승장구 했으면 좋겠네요! 이로써 EOSBet 해킹 분석 글을 마치겠습니다. 감사합니다!!

--

--