CLIEN

본문 바로가기 메뉴 바로가기 보기설정 테마설정
톺아보기 공감글
커뮤니티 커뮤니티전체 C 모두의광장 F 모두의공원 I 사진게시판 Q 아무거나질문 D 정보와자료 N 새로운소식 T 유용한사이트 P 자료실 E 강좌/사용기 L 팁과강좌 U 사용기 · 체험단사용기 W 사고팔고 J 알뜰구매 S 회원중고장터 B 직접홍보 · 보험상담실 H 클리앙홈
소모임 소모임전체 ·굴러간당 ·주식한당 ·아이포니앙 ·MaClien ·방탄소년당 ·일본산당 ·자전거당 ·개발한당 ·이륜차당 ·소시당 ·패스오브엑자일당 ·AI당 ·안드로메당 ·나스당 ·걸그룹당 ·바다건너당 ·사과시계당 ·클다방 ·물고기당 ·노키앙 ·전기자전거당 ·노젓는당 ·축구당 ·윈폰이당 ·IoT당 ·창업한당 ·가상화폐당 ·여행을떠난당 ·곰돌이당 ·키보드당 ·리눅서당 ·골프당 ·콘솔한당 ·3D메이킹 ·X세대당 ·ADHD당 ·AI그림당 ·날아간당 ·육아당 ·배드민턴당 ·야구당 ·농구당 ·블랙베리당 ·비어있당 ·FM당구당 ·블록체인당 ·보드게임당 ·활자중독당 ·볼링친당 ·캠핑간당 ·냐옹이당 ·문명하셨당 ·클래시앙 ·요리한당 ·쿠키런당 ·대구당 ·DANGER당 ·뚝딱뚝당 ·디아블로당 ·개판이당 ·동숲한당 ·날아올랑 ·e북본당 ·갖고다닌당 ·이브한당 ·패셔니앙 ·도시어부당 ·FM한당 ·맛있겠당 ·포뮬러당 ·젬워한당 ·안경쓴당 ·차턴당 ·총쏜당 ·땀흘린당 ·하스스톤한당 ·히어로즈한당 ·인스타한당 ·KARA당 ·꼬들한당 ·덕질한당 ·어학당 ·가죽당 ·레고당 ·LOLien ·Mabinogien ·임시소모임 ·미드당 ·밀리터리당 ·땅판당 ·헌팅한당 ·오른당 ·영화본당 ·MTG한당 ·소리당 ·적는당 ·방송한당 ·PC튜닝한당 ·찰칵찍당 ·그림그린당 ·소풍간당 ·심는당 ·라즈베리파이당 ·품앱이당 ·리듬탄당 ·달린당 ·Sea마당 ·SimSim하당 ·심야식당 ·윈태블릿당 ·미끄러진당 ·나혼자산당 ·스타한당 ·스팀한당 ·파도탄당 ·퐁당퐁당 ·테니스친당 ·테스트당 ·빨콩이당 ·공대시계당 ·터치패드당 ·트윗당 ·VR당 ·시계찬당 ·WebOs당 ·소셜게임한당 ·위스키당 ·와인마신당 ·WOW당
임시소모임
고객지원
  • 게시물 삭제 요청
  • 불법촬영물등 신고
  • 쪽지 신고
  • 닉네임 신고
  • 제보 및 기타 제안
© CLIEN.NET
공지[점검] 잠시후 서비스 점검을 위해 약 30분간 접속이 차단됩니다. (금일 18:15 ~ 18:45)

가상화폐당

강좌와팁 해킹된 지갑에서 NFT 구출하기 15

5
2022-10-12 00:14:26 180.♡.34.40
fei228

제 미디움에서 가져온 글이라 반말체인점 양해 부탁드립니다ㅠㅠ




얼마 전, 아는 사람이 지갑이 해킹된 것 같다고 호소해왔다.


“지갑에 BNB를 넣으니까 자꾸 바로 다른 지갑으로 자동이체된 것처럼 빠져나가고 있다.”


이건 Wallet Sweeping이라는 해킹의 종류인데, 인터넷에서 누군가 관심사가 비슷하다며 자신의 작품이라는 파일을 보내왔고, 이걸 열어본 지인의 컴퓨터에 일종의 원격 악성코드(?)가 심어지게 된 것이 아닌가 강력하게 의심되었다.


빠져나간 BNB야 어쩔 수 없지만, 문제는 지갑 안에 들어있던 NFT였다. 아무래도 자동화된 스크립트가 지갑에 들어있는 BNB를 지속적으로 빼오도록 트랜잭션을 생성했지만, NFT를 빼오지는 안았던 모양이다.


하지만 NFT를 빼오려고 해도, 지갑에 수수료인 BNB를 넣고나면 곧바로 출금이 되어버리니…그리고 BSC 체인의 NFT는 딱히 오픈씨처럼 GUI로 된 전송방식이 없다는 듯 싶었다. 나도 BSC는 이번 기회에 처음 다루게 되었다.


아무튼 나에게 NFT를 구조(?)해달라는 요청이 있어 조금 더 조사해보니, 꽤나 악질적이고 여러 곳에서 피해사례들이 올라와있는 것을 확인할 수 있었다.


혹시 관련 사례와 해결법이 있는지 검색해보니, 다행히도 무려 화이트햇 그룹이 있어 NFT를 구조해주고 있었다. 아래에 링크를 남긴다.

(물론 나는 화이트햇의 도움을 받진 않았다.)


https://discord.gg/r2hpCKpAxa


위 디스코드에 접속해 whitehat 채널에 가서 제공하는 폼을 작성하고 넘기면 시작된다.

좋은 일 하시는데, 무려 1,000달러+ 가스비…

다만, NFT를 구출해오는데 최소 가격이 1천불부터 시작되니까, 내 NFT가 그보다 저렴하다면 굳이 구해올 필요는 없겠지만…


문제는 이 NFT의 가격이 구입가 기준 10,000불이 넘어간다는 거다.


일단 화이트햇은 최후의 보류로 두고, 나는 두 가지 방법을 고려했다.

1. 수수료 대납(Fee delegation) 컨트랙트를 만들어 트랜잭션을 대신 생성해 보낸다.


직접 web3.js나 기타 web3 라이브러리를 사용해보면 이해가 가겠지만, 보통 트랜잭션을 보내기 위해서는 대략적으로 다음과 같은 방식을 거친다.


  1. web3의 월렛 인스턴스를 만들어 내 지갑을 추가한다.
  2. 트랜잭션의 형태(보내는사람, 보낼사람, 데이터 등등)을 만들어 서명한다(sign).
  3. 트랜잭션을 보낸다(Send).


이 3가지의 과정을 똑같이 수행하는데, 일단 2번까지만 수행한 다음, 이 트랜잭션을 덩어리로 묶어서 Proxy Contract로 보내면, 해당 컨트랙트가 이 트랜잭션을 대신 쏘게 되고, 수수료도 컨트랙트나 컨트랙트의 owner가 지불하게 되는 것이다.

이 방식을 사용하면 NFT를 해킹당한 지갑 입장에서는 수수료를 내지 않고 NFT를 옮길 수 있으니, 아래에서 소개할 두번째 방법보다는 훨씬 좋아보였다.


하지만 이 방식은 애초에 불가능하다.


간단히 말하자면, approve를 Proxy Contract가 받아낼 수 없기 때문이다. approve 자체도 수수료가 들어가거든…

하…오픈씨에 들어가서 내 NFT를 다른 사람에게 보내거나, 판매 리스트에 올린다고 생각해보자.

오픈씨가 보유한 컨트랙트는 이용자의 지갑주소에서 “우리가 너 대신에 NFT를 전송할 권한을 줘”라며 approve를 요청한다.

그러니 아무리 Transaction을 묶어서 Proxy Contract로 보내더라도, 승인 권한을 받지 못한 Proxy Contract는 이 NFT 전송 트랜잭션을 보내도 거절당하게 된다.


또한, 승인권한을 Proxy Contract로 주기 위한 SetApprovalForAll 메소드를 실행시키기 위해서도 가스비가 발생하기에, 결국 이 방법은 사용되지 못했다.


다만!


이 방법은 Wallet Sweeping을 예방할 수 있는 좋은 방법이다. 만약 내가 아주 많은 NFT를 보유한 지갑이 있다면, 미리 Proxy Contract를 만들고 승인을 해두면, 이후에 Sweeping을 당하더라도 Proxy Contract를 이용해 NFT를 빼내올 수 있으니 말이다. 그래서 일단 Proxy Contract를 공개해둔다.


(다만, 이 컨트랙트는 단순 샘플이니 보안을 신경쓴다면 조치를 더 취해야 할 것이다.)

pragma solidity ^0.8.0;

import “@openzeppelin/contracts/utils/cryptography/ECDSA.sol”;

contract Proxy {

using ECDSA for bytes32;

// verify the data and execute the data at the target address

function forward(address _to, bytes calldata _data, bytes memory _signature) external returns (bytes memory _result) {

bool success;

verifySignature(_to, _data, _signature);

(success, _result) = _to.call(_data);

if (!success) {

// solhint-disable-next-line no-inline-assembly

assembly {

returndatacopy(0, 0, returndatasize())

revert(0, returndatasize())

}

}

}

// Recover signer public key and verify that it’s a whitelisted signer.

function verifySignature(address _to, bytes calldata _data, bytes memory signature) private view {

require(_to != address(0), “invalid target address”);

bytes memory payload = abi.encode(_to, _data);

address signerAddress = keccak256(payload).toEthSignedMessageHash().recover(signature);

}

}

그래서 어쨋든 두번째 방법으로 넘어갔다.


2. 가스비를 속사포처럼 쏘면서 NFT 트랜스퍼 트랜잭션도 계속 보낸다.


굉장히 훌륭하지만, 무식한;;; 방법이다.

이 방법을 거의 처음 생각해내고 실행해낸 사람의 글이 있어서 소개한다.


https://medium.com/mycrypto/operation-cryptokitty-rescue-93fd8e00e4f8


무려 크립토키티;;;를 빼내온 사람의 얘기다.

방법은 단순하다.


  1. 해킹당한 지갑에 지속적으로 BNB를 보낸다.
  2. BNB를 계속 보내는 동안, NFT의 전송 트랜잭션도 계속 보낸다.
  3. 지갑에 BNB가 들어오고, 나가기 전에 NFT 전송 트랜잭션이 들어가면 NFT가 무사히 구조된다.


절대! 이 방법을 다 손으로 할 생각은 절대 금물이다!

위는 실제로 이 해킹사건의 피해지갑의 트랜잭션을 조회한 것이다.


왼쪽에서 볼 수 있듯이, 지갑에 일단 BNB가 전송되면, 단 두 블록만에 BNB가 전부 빠져나간다.


2 블록이면 대략 6초이지만, 실제로는 지갑에 들어온 BNB를 캐치하고 곧바로 빼내오는 트랜잭션을 전송했을 것으로 생각되니 틈이 나는 시간은 3초 이내라는 거다. 이걸 손으로 일단 BNB 지갑에서 전송하고, 해킹당한 지갑으로 가서 NFT를 다시 전송하고…를 할 수는 없다.


나는 web3.js 라이브러리로 다음과 같은 두 코드를 돌렸다.

let web3;

var contract;

let nftAddress;

let nftABI;

if(options.network == “testnet”){

web3 = new Web3(‘https://data-seed-prebsc-1-s1.binance.org:8545/');

nftAddress = contractData.BNBProxyAddress;

nftABI = contractData.BNBProxyABI;

contract = new web3.eth.Contract(nftABI,nftAddress) ;

}else if(options.network == “mainnet”){

web3 = new Web3(‘https://bsc-dataseed.binance.org/');

nftAddress = contractData.BNBProxyAddress;

nftABI = contractData.BNBProxyABI;

contract = new web3.eth.Contract(nftABI,nftAddress) ;

}

const Address = configData.BnbTreasuryAccount;

const PrivateKey = configData.BnbPrivateKey;

const Address2 = configData.BnbTreasuryAccount2;

ret = await web3.eth.accounts.wallet.add(PrivateKey);

for(let i = 0 ; i< 10;i++){

ret = await web3.eth.sendTransaction({

from: Address,

to: Address2,

value: web3.utils.toWei(“0.006”,”ether”),

gas: ‘100000’

}).then((res) => {console.log(res);})

}

이게 1번 코드이고, 총 10번동안 0.006BNB씩 해킹당한 지갑주소에 전송한다.

그리고 저 코드를 돌리는 동안 다음 코드를 동시에 여러 터미널에서 돌린다.

let ret;

let web3;

var contract;

let nftAddress;

let nftABI;

if(options.network == “testnet”){

web3 = new Web3(‘https://data-seed-prebsc-1-s1.binance.org:8545/');

nftAddress = contractData.BNBNFTContractTestnet;

nftABI = contractData.BNBNFTABI;

contract = new web3.eth.Contract(nftABI,nftAddress) ;

}else if(options.network == “mainnet”){

web3 = new Web3(‘https://bsc-dataseed.binance.org/');

nftAddress = contractData.BNBNFTContractTestnet;

nftABI = contractData.BNBNFTABI;

contract = new web3.eth.Contract(nftABI,nftAddress) ;

}

const Address = configData.BnbTreasuryAccount;

const PrivateKey = configData.BnbPrivateKey;

const Address2 = configData.BnbTreasuryAccount2;

const PrivateKey2 = configData.BnbPrivateKey2;

ret = await web3.eth.accounts.wallet.add(PrivateKey);

ret = await web3.eth.sendTransaction({

from: Address,

to: nftAddress,

data: contract.methods.transferFrom(minterAddress,minterAddress2, tokenID).encodeABI(),

gas: ‘300000’

}).then((res) => {console.log(res);})

코드 2번은 해킹당한 지갑에서 다른 지갑으로 NFT를 전송하는 코드이다. 이 코드는 10번의 BNB 전송이 돌아가는 사이에 최대한 동시에 많이 들어가야 하기에, 일단 전송 코드를 돌리고 그 사이에 대략 5개의 터미널에서 계속해서 실행시켰다.


BAAM!!

결국 NFT는 구조되었다.

와! 구조!


지속적으로 Transaction은 insufficient fund로 뜨다가, 결국 0.3BNB정도를 소모한 끝에 구출해낼 수 있었다.


화이트햇에게 요청하는 것에 비하면 아주 저렴하게 구조했다는게 뿌듯하긴 했지만, 뭐…해킹범에게 정의구현을 한 건 아니니깐…


어쨋든 검색해보니 국외뿐만 아니라 국내에도 이런 피해를 입고, 구출해내지 못한 NFT가 있는 사람도 꽤 있는 듯 하니, 이번 글이 도움이 됐으면 좋겠다.

출처 : https://medium.com/@eklee808/%ED%95%B4%ED%82%B9%EB%90%9C-%EC%A7%80%EA%B0%91%EC%97%90%EC%84%9C-nft-%EA%B5%AC%EC%B6%9C%ED%95%98%EA%B8%B0-5e52ddaf630
fei228 님의 게시글 댓글
  • 주소복사
  • Facebook
  • X(Twitter)
댓글 • [15]
야동량대표아적심
IP 59.♡.77.78
10-12 2022-10-12 01:16:45
·
뭔지는 몰라도 엄청나군요
삭제 되었습니다.
뭉코건볼
IP 220.♡.32.207
10-12 2022-10-12 10:43:01
·
@쉐도우님 저런 경우는 보통 개인키까지 유출된 경우일껍니다. 개인키만 있으면 외부에서 트랜잭션을 만드는건 어렵지않으니까요. 해당 주소의 잔고를 모니터링하다가 입금(?)이 보이면 바로 개인키 사용해서 출금하는 트랜잭션을 만드는 봇을 돌리고 있겠죠.
삭제 되었습니다.
뭉코건볼
IP 220.♡.32.207
10-12 2022-10-12 11:50:13 / 수정일: 2022-10-12 11:50:39
·
@쉐도우님 생각해보면 아마 못 건드리는게 아니라, 안 건드리는게 아닐까 싶긴 합니다. 기술적으로는 불가능하지 않거든요.
NFT를 일일이 찾아서 빼내는게 스마트컨트랙트 호출을 해야하다보니 ETH나 BNB 전송보다 복잡하기도 하고, 거래소로 들어가면 오프체인으로 세탁이 가능한 ETH나 BNB와 달리 NFT는 오프체인 거래소가 잘 없지 않나요?(이건 제가 잘 몰라서..) 이런 요건들이 아마 ROI가 안 나온다고 생각한게 아닐까.. 개인적인 추측입니다 ㅎ
fei228
IP 180.♡.34.40
10-12 2022-10-12 14:13:04
·
@뭉코건볼님 네 저도 뭉코건볼님과 같은 의견입니다. 트랜잭션을 보내려면 NFT 컨트랙트 주소도 알아야 하고, 이것저것 알아볼게 많은데, 자기네들이 스크립트를 심었던 모든 주소를 다 뒤져보는 것도 한계가 있기 때문에 안돌린게 아닐까 생각됩니다 ㅎ
kakao
IP 121.♡.225.234
10-12 2022-10-12 07:21:23
·
제 주변에서도 이 방법으로 NFT 몇개 구출하신분들 있는데
글로 올라오는건 처음보는군요 ㅎㅎ
좋은글이네요
fei228
IP 180.♡.34.40
10-12 2022-10-12 14:14:02
·
@kakao님 감사합니다 ㅎ 아마 국내에서도 사례가 좀 있는 걸로 봐서는 포기하시는 분들도 계실 것 같은데, 한글로 된 정보가 좀 알려졌으면 하는 바람에 적어봤습니다.
Plusultra
IP 39.♡.86.8
10-12 2022-10-12 10:22:59
·
좋은글 감사드립니다
뭉코건볼
IP 220.♡.32.207
10-12 2022-10-12 10:32:45
·
재밌게 잘 봤습니다. 1번 방식에서 미리 Proxy Contract를 만들고 승인을 해두는게 Sweeping을 대비할 수는 있지만, 잘못하면 오히려 이 부분이 보안 취약점이 될 수도 있겠네요. 실제로 지갑의 토큰이 털리는 경우중에 남발된 approve가 원인인 경우도 있어서요 ^^;
fei228
IP 180.♡.34.40
10-12 2022-10-12 14:15:50
·
@뭉코건볼님 네, 그 점때문에 보안관련 사족을 달았습니다. Ownership이라던가 여러가지 설정을 좀 넣어서 보완해야겠습니다만, 아마 회사차원에서 관리하는 NFT 지갑들이 있다면 미리 이렇게 예방책을 만들어 두는게 좋을 수도 있겠다는 생각입니다. 말씀하신 대로 남발된 승인들도 많은데 개인들은 주기적으로 Revoke 해줘야 하겠죠 ㅎ
BIP39
IP 59.♡.176.126
10-12 2022-10-12 18:19:40
·
BSC 블록타임 3초내에 BNB를 전송하는 트랜잭션과 NFT를 전송하는 트랜잭션 모두 같은 블록에 넣는다면 해커 봇을 이길 수 있지 않나 싶군요.. 해커봇이 BNB 수량을 확인하고 최소 1블록 다음에 반응하는걸보면요.. 이때는 NFT 전송 트잭의 블록내 포지션을 BNB전송보다 후순위 처리하기 위해 앞 트잭에 가스가격을 더 올린다거나 먼저 브로드캐스팅한다거나... 그런 이론이 떠올랐습니다. 근데 이미 테스트넷에서 충분히 실험해보셨겠죠?
fei228
IP 180.♡.34.40
10-12 2022-10-12 19:16:33
·
@BIP39님 두 개의 트랜잭션의 전송인, 그러니까 From Address가 서로 다르기 때문에 한 블록으로 처리하기가 어렵지 않을까 생각됩니다. "BNB의 전송"은 2->1로, "NFT의 전송"은 1->2로 보내기 때문에 강제로 한 블록으로 처리할 수 있을 방법이 있는지 당장 떠오르지 않네요; 다만 실제로 수행할 때에는 BNB 가스가격은 최소로, NFT 전송은 가스가격을 충분히 올려서 수행한 것은 맞습니다:) 제가 모르는 부분일 수 있는데 혹시 말씀하신 부분의 수행은 어떻게 하면 좋을까요?
BIP39
IP 59.♡.176.126
10-12 2022-10-12 21:40:01
·
@fei228님 이더 테스트넷에서 몇가지 실험해보니 가스 문제 때문에 어렵네요..구출하신 방법이 제일 좋은것같습니다
엔젤아름
IP 211.♡.180.240
10-13 2022-10-13 23:31:20
·
아ㅜㅜ 컴맹이라 구출을 하고싶어도 따라할수가없네요ㅜㅜ
엔젤아름
IP 223.♡.150.209
10-14 2022-10-14 09:59:45
·
매틱네트워크 nft인데 구출가능할까요?ㅜㅜ
fei228
IP 180.♡.34.36
10-14 2022-10-14 12:34:14
·
@엔젤아름님 매틱도 RPC 엔드포인트만 다르고 solidity, web3를 그대로 쓸 수 있으니 같은 방법으로 구조가 가능합니다 ㅎ
새로운 댓글이 없습니다.
이미지 최대 업로드 용량 15 MB / 업로드 가능 확장자 jpg,gif,png,jpeg,webp
지나치게 큰 이미지의 크기는 조정될 수 있습니다.
목록으로
글쓰기
글쓰기
목록으로 댓글보기 이전글 다음글
아이디  ·  비밀번호 찾기 회원가입
이용규칙 운영알림판 운영소통 재검토요청 도움말 버그신고
개인정보처리방침 이용약관 책임의 한계와 법적고지 청소년 보호정책
©   •  CLIEN.NET
보안 강화를 위한 이메일 인증
안전한 서비스 이용을 위해 이메일 인증을 완료해 주세요. 현재 회원님은 이메일 인증이 완료되지 않은 상태입니다.
최근 급증하는 해킹 및 도용 시도로부터 계정을 보호하기 위해 인증 절차가 강화되었습니다.

  • 이메일 미인증 시 글쓰기, 댓글 작성 등 게시판 활동이 제한됩니다.
  • 이후 새로운 기기에서 로그인할 때마다 반드시 이메일 인증을 거쳐야 합니다.
  • 2단계 인증 사용 회원도 최초 1회는 반드시 인증하여야 합니다.
  • 개인정보에서도 이메일 인증을 할 수 있습니다.
지금 이메일 인증하기
등록된 이메일 주소를 확인하고 인증번호를 입력하여
인증을 완료해 주세요.