Change formatting

This commit is contained in:
Tobias Eidelpes 2022-01-15 11:22:15 +01:00
parent 51e72037f1
commit 78a592a9e5
2 changed files with 11 additions and 13 deletions

Binary file not shown.

View File

@ -173,7 +173,7 @@ is aborted.
In this challenge we were given some form of a gambling contract, which promises 10 times the ether, with which user participates. The idea is, a user submits a number along with some ether and a random number is generated with the help of a method. User's number and randomly generated number are added together and if the result is exactly 42, then user earns 10 times the ether.(if the 10 times the participant's ether value is bigger than the contract balance, then contract sends all the balance it has.) Now let's take a look at the method, which generates the random number: In this challenge we were given some form of a gambling contract, which promises 10 times the ether, with which user participates. The idea is, a user submits a number along with some ether and a random number is generated with the help of a method. User's number and randomly generated number are added together and if the result is exactly 42, then user earns 10 times the ether.(if the 10 times the participant's ether value is bigger than the contract balance, then contract sends all the balance it has.) Now let's take a look at the method, which generates the random number:
\begin{minted}[frame=lines,framesep=2mm,bgcolor=LightGray,fontsize=\footnotesize,linenos,breaklines]{solidity} \begin{minted}[frame=lines,framesep=2mm,bgcolor=LightGray,fontsize=\footnotesize,linenos,breaklines]{solidity}
function PRNG(address sender) private view returns(uint8){ function PRNG(address sender) private view returns(uint8) {
// Totally "awesome" PRNG // Totally "awesome" PRNG
//return uint8(keccak256(abi.encodePacked(sender, block.coinbase, now, big_secret))); //return uint8(keccak256(abi.encodePacked(sender, block.coinbase, now, big_secret)));
return uint8(uint(keccak256(abi.encodePacked(sender, block.coinbase, now, big_secret)))); return uint8(uint(keccak256(abi.encodePacked(sender, block.coinbase, now, big_secret))));
@ -188,26 +188,25 @@ Since blockchain is a deterministic data structure, anyone can produce the outco
\end{itemize} \end{itemize}
It seems like out of all parameters used, all of them except \textbf{big\_secret} variable can be known, because \textbf{big\_secret} is a private variable, right? It seems like out of all parameters used, all of them except \textbf{big\_secret} variable can be known, because \textbf{big\_secret} is a private variable, right?
\\ \\
What is stored on public blockchains, whether with public or private modifiers, are still accessible by anyone, because Ethereum Virtual Machine saves smart contract data in "slots" in the order of the variables declared and anyone with an access to web3 can inspect the data in these slots, if they know the address of the contract. In conclusion, using private modifier only prohibits the access of other contracts to the private variables or functions. With this knowledge, we can start the first step of our exploit, which is retrieving the value of the \textbf{big\_secret}: What is stored on public blockchains, whether with public or private modifiers, are still accessible by anyone, because Ethereum Virtual Machine saves smart contract data in "slots" in the order of the variables declared and anyone with an access to web3 can inspect the data in these slots, if they know the address of the contract. In conclusion, using private modifier only prohibits the access of other contracts to the private variables or functions. With this knowledge, we can start the first step of our exploit, which is retrieving the value of the \textbf{big\_secret}:
\\ \\ \\ \\
\begin{minted}[frame=lines,framesep=2mm,bgcolor=LightGray,fontsize=\footnotesize,linenos,breaklines]{solidity} \begin{minted}[frame=lines,framesep=2mm,bgcolor=LightGray,fontsize=\footnotesize,linenos,breaklines]{solidity}
//pragma solidity ^0.4.12; //pragma solidity ^0.4.12;
pragma solidity ^0.5.4; pragma solidity ^0.5.4;
contract SatoshiFailDice{ contract SatoshiFailDice {
// Hint: use web3.toInt() when converting bytes to soldity uint - else values may not match // Hint: use web3.toInt() when converting bytes to soldity uint - else values may not match
uint private big_secret; uint private big_secret;
address student; address student;
address private owner; address private owner;
... ...
}
\end{minted} \end{minted}
Now we can see above that the variable we are looking for is declared first, meaning that it has to be stored in the "slot 0". By using geth console we can learn what's stored in the "slot 0" of this contract: Now we can see above that the variable we are looking for is declared first, meaning that it has to be stored in the "slot 0". By using geth console we can learn what's stored in the "slot 0" of this contract:
\begin{minted}[frame=lines,framesep=2mm,bgcolor=LightGray,fontsize=\footnotesize,linenos,breaklines]{javascript} \begin{minted}[frame=lines,framesep=2mm,bgcolor=LightGray,fontsize=\footnotesize,linenos,breaklines]{javascript}
// Assume failDiceContractAddress is already initialized. // Assume failDiceContractAddress is already initialized.
eth.getStorageAt(failDiceContractAddress, 0); // Returned value is unique to every student, but let's assume the return value is "0xc0343f9c49df15c65b456c551da8926a7841ef9ad444edb606b097af9591802d" eth.getStorageAt(failDiceContractAddress, 0); // Returned value is unique to every student, but let's assume the return value is "0xc0343f9c49df15c65b456c551da8926a7841ef9ad444edb606b097af9591802d"
\end{minted} \end{minted}
After completing this step, we now know all the parameters that is used in creating a random number. Now we can write a malicious contract that can generate the same random number, which will be generated by the contract in a specific block, remove this number from 42 to find out which number to submit as our participation number: After completing this step, we now know all the parameters that is used in creating a random number. Now we can write a malicious contract that can generate the same random number, which will be generated by the contract in a specific block, remove this number from 42 to find out which number to submit as our participation number:
\begin{minted}[frame=lines,framesep=2mm,bgcolor=LightGray,fontsize=\footnotesize,linenos,breaklines]{solidity} \begin{minted}[frame=lines,framesep=2mm,bgcolor=LightGray,fontsize=\footnotesize,linenos,breaklines]{solidity}
@ -260,7 +259,6 @@ We will call the pwn function to start the exploit. This function will require a
maliciousFailDiceContractInstance.pwn({from:student, value: web3.toWei(4, 'ether')}); // call pwn function maliciousFailDiceContractInstance.pwn({from:student, value: web3.toWei(4, 'ether')}); // call pwn function
maliciousFailDiceContractInstance.withdraw({from:student}); // withdraw the malicious contract balance maliciousFailDiceContractInstance.withdraw({from:student}); // withdraw the malicious contract balance
\end{minted} \end{minted}
Conclusion is that do not use private variables for the purpose of hiding them from anyone. Private modifiers should be used for the cases where we do not want other contracts to use or access the variables or functions. Since Solidity contracts are deterministic, there is no true random number generation possible using only Solidity contract code. Though with the use of oracle services such as Chainlink, one can retrieve generate a random number outside of the blockchain and bring this data into the blockchain. Conclusion is that do not use private variables for the purpose of hiding them from anyone. Private modifiers should be used for the cases where we do not want other contracts to use or access the variables or functions. Since Solidity contracts are deterministic, there is no true random number generation possible using only Solidity contract code. Though with the use of oracle services such as Chainlink, one can retrieve generate a random number outside of the blockchain and bring this data into the blockchain.
\section{Not A Wallet} \section{Not A Wallet}
@ -270,7 +268,7 @@ In this challenge we were expected to exploit a wallet contract and drain its fu
function removeOwner(address oldowner) public rightStudent { function removeOwner(address oldowner) public rightStudent {
require(owners[msg.sender] = true); require(owners[msg.sender] = true);
owners[oldowner] = false; owners[oldowner] = false;
} }
\end{minted} \end{minted}
The writer of this contract wanted to check if the message sender is an owner, but instead of using the equals operator (==), he/she used assignment operator (=), which ends up making the sender of the message an owner by assigning true value to the sender address key in owners mapping. To exploit this contract and drain its funds, as student, its enough to first call the removeOwner method with the owner address as parameter and then withdraw function from the geth console: The writer of this contract wanted to check if the message sender is an owner, but instead of using the equals operator (==), he/she used assignment operator (=), which ends up making the sender of the message an owner by assigning true value to the sender address key in owners mapping. To exploit this contract and drain its funds, as student, its enough to first call the removeOwner method with the owner address as parameter and then withdraw function from the geth console:
@ -288,7 +286,7 @@ This bug seems to be caused by a typo and therefore could have been avoided if t
function removeOwner(address oldowner) public rightStudent { function removeOwner(address oldowner) public rightStudent {
require(owners[msg.sender] == true); require(owners[msg.sender] == true);
owners[oldowner] = false; owners[oldowner] = false;
} }
\end{minted} \end{minted}
\section*{Work distribution} \section*{Work distribution}