...by Daniel Szego
quote
"On a long enough timeline we will all become Satoshi Nakamoto.."
Daniel Szego
Showing posts with label security. Show all posts
Showing posts with label security. Show all posts

Friday, October 2, 2020

Ethereum solidity security tools summarized

 


Security in solidity - Ethereum has been always one of the most important topic. Some of the current most important tools are the followings:

SWC Registry /  

Smart Contract Weakness Classification and Test Cases

https://swcregistry.io/

Ethereum Smart Contract Security Best Practices 

https://consensys.github.io/smart-contract-best-practices/

MythX - a cool tool for getting information on solidity smart contract vulnerabilities 

https://mythx.io/ 

EthLint - an open source tool for analyzing Ethereum smart contracts. 

https://github.com/duaraghav8/Ethlint

Slither  - for making static code analysis on solidity contracts

https://github.com/crytic/slither

Hydra - framework for security and bug bounties

https://github.com/IC3Hydra/Hydra



Sunday, December 30, 2018

Solidity Tips and Tricks - struct at local function hack


Solidity has a lot of surprising and actually shitty characteristics. On thing is that a struct can be defined both in memory and in storage as well similarly to arrays. The problem is however that if you define your struct in a local function body, it overwrites the storage variables of the contract itself. On top unfortunately, if you create a struct in a function body without explicitly marking if it is a storage or a memory one, it is created automatically as a storage. So the following example:

contract StructHack {
    uint public myNum = 0;
    
    struct TestStruct {
        uint structNum;
    }
    
    function hackStruct() {
        TestStruct test;
        test.structNum = 22;
    }
}

Surprisingly, if you deploy the contract and call the function hackStruct, the myNum value will be initialized to 22.  

Friday, December 7, 2018

Notes on Ethereum WASM



Ethereum WASM is on the horizon, providing a more stable, flexible and faster programming environment. However introducing the technology might bring a couple of unexpected results. The problem is that with the help of WASM there will be many other languages available for Ethereum programming, apart from Solidity. The real difficulty in Blockchain programming is however not the programming language knowledge, but actually the mindset. As Ethereum smart contracts store a huge amount of money on a public blockchain and actually the deployed code is pretty much immutable, developing such a code requires special considerations. Instead of Agile or DevOps methodologies, defensive programming, formal versification and correct by construction tools should be used. For those who has actually never taken part in mission critical system development, these methodologies are new. The result will be that many software developers with WASM compatible languages will start smart contract development, which will cause again a huge amount of buggy software and a lot of hacks on the public chain. That will result that the general perception of the chain security will be again pretty low.   

Saturday, August 4, 2018

Blockchain immutability is a cryptoeconomical guarantee

Blockchain is said to be immutable, meaning that a give transaction can not be changed if it is already in the blockchain, because the whole structure is secured by crypthograhical hashes, that can not really be broken. However it is important to note that the immutability is not necessarily a pure cryptographical guarantee, it might depend on cryptoeconomical perspectives as well. Like in a proof of work system, a long range attack, meaning building up the whole blockchain from the genesis block, or from the block of the given transaction cost a lot of computational power but not impossible. Especially if we can take into account that the mining difficult might not always increase, but it might decrease as well. Similarly in a proof of stake scheme a long range attack cost a lot of money, however that is not a cryptographical guarantee. 

As a consequence blockchain immutability is not necessarily a cryptographical guarantee but it might be a cryptoeconomial one, depending on the used consensus algorithm. So instead of saying that  it  is computational impractical to change a recorded transaction, we claim something weaker, like it cryptoeconomically impractical (or not profitable) to change a recorded transaction.  

Thursday, August 2, 2018

Security of the blockchain as authenticated data structure

Blockchain is actually something as an authenticated data structure, which is a special linked list, where to create some of the hash pointers require a kind of a work to do or a kind of a monetary stake to risk. It means that we can consider the security of a given transaction which is mined in a block. This security will increase as the further blocks are minded on the top of the chain. The security is dependent on the exact consensus mechanism, but will increase somehow as follows:


Actually in a standard forking attempt, it is considered that a given transaction is secure if more than 6 blocks are mined on the top of the chain at Bitcoin and like 12-15 at the case of Ethereum. However if we an old transaction, than further added blocks increase the security further. It is certainly required at an UTXO style system, because old unspent transactions should also payed into account, however it is questionable if we really need it if we use an account based system like Ethereum.  


Monday, July 30, 2018

Cryptoeconomical attacks on Blockchain applications


It is actually a weird thing to identify attack surface for a blockchain based system. The major problem is that they are not purely software architectures, but rather complex systems containing both cryptography and software architecture components and elements based on economy. As a consequence "hacking" or "gaming" such a system is usually not purely a simple software engineering task. There can be the following types attacks:
- Classical attacks: like trying to break the cryptography, or exploiting an implementation vulnerabilities.  
- Monetary attacks: these exploit the fact that a token or several tokens are actively traded on a couple of exchanges. As an example, pump-dump scheme or perhaps even shorting against a token or cryptocurrency can be regarded as such an attack. Sometimes such an attack is not clearly monetary, but for example is combined with a negative social media campaign. 
- Certainly, there might be hybrid attacks as well, that try to exploit some system implementation errors combined with an economical "gaming". For such categories a new field of cybersecurity should be probably defined. 

Saturday, July 28, 2018

Replay attack on the Blockchain


Replay attack can be interpreted in two ways on the blockchain:

1. If there is a hard-fork on the blockchain, and the system is spited into two concurrent platforms, there is a possibility to copy one signed transaction from one chain and put this transaction to the other chain. Usually at a hard-fork there is a mechanism that explicitly avoids a replay attack, like there is a modified transaction semantics, or even just one bit on the forked blockchain, so signed transactions of the old chain will not be valid on the forked one.

2. Even without forking there is the possibility to copy an old transaction and try to replay it again on the blockchain. It is not too effective at an UTXO system, because the system will know that the old transaction output has been already spent. However if it is an account/balance based system, further algorithms must be used. One way to avoid replay attack on an account/balance based system is to implement a counter at each variable that has to be increased at each new transaction. Another way can be to create a nonce for each transaction randomly and automatically, the system has to ensure that the same nonce can not be applied two times. There might be some mixed solution as well, where quasi random nonces are used in an incremental fashion, like:

nonce_next = hash(nonce_prev)

In a multi-hash blockchain system we have most likely account/balance based systems, implying that we have to use one of the nonce or counter based solution. That means that the state of the blockchain is actually not the state of all of the balances, but the tuples of balance and nonce

state_i = <balance_i, nonce_i_j >


Sunday, May 13, 2018

Notes on highly secure software architectures


The basic architectural elements of Blockchain give the possibility for realizing highly trusted and secure computational architecture, even if they are not manifested in a decentralized peer 2 peer manner. Elements of the secure computation are the basic cryptographic elements, like public and private key infrastructures or hash functions. Services of such a highly secure architecture might be: - secure computation: for certain critical computations the requirement to sign either the computation or the result with multiply keys of multiply actors. 
- secure data structure: for the data structures to be organized in a hash structure, implying hash pointers showing to the result of other hashed data elements, providing a highly hacker resistant data structure. 
- proof of work: putting proof of work into the system implying that the security system will be more resistant against exhaustive search attacks. 
- secure architecture: combining the previous elements together to form a highly secure, highly hacker resistant software architecture. 

Wednesday, April 4, 2018

Solidity Tips and Tricks - difference between .call.value(), .send() and .transfer()


It is important to understand the difference of semantics and security implications of the different ways of sending ether to a contract:
- .call.value(ether) - sends ether to a contract by giving all the possible gas for the execution having a strong risk for reentrancy attacks. If it is succeeded true is returned if not false. 
- .send(ether) - sends ether to a contract by giving only 2300 gas for the execution making possible to do only logging and event and preventing reentrancy attacks. Similarly to the previous case if the call succeed it returns true, otherwise it returns false. 
- .transfer(ether) is tecnically the same as require(send(ether)), so if the ether sending not succeeding and error will be thrown and the transaction is reverted.  


Solidity security patterns - reentrancy


Reentrancy can happen if a smart contract calls a second one in a direct way or indirectly by transferring it ether. Typically at the code execution before the given statement terminates it called once again by another contract. Consider the following code fragments:

contract ReentrancyError {
  ...
  function withdraw(uint _amount) public{
    if(balances[msg.sender] >= _amount) {
      if(msg.sender.call.value(_amount)()) {
        balances[msg.sender] -= _amount;
      }
    }
  }
}

contract Attacker {

  function attack() public {
      target.withdraw(donated);
  }
  
  function() public payable{
      if (counter < 10) {
        counter++;
        target.withdraw(donated);
      }
  }
}

The withdraw function of the ReentrancyError contract is meant to be called by externally owned accounts, however a tricky hacker might force to call the function from a hacked contract. If so by calling the withdraw function at the msg.sender.call.value(_amount) by transferring ether to the Attacker contract the fallback function will be called, that calls the withdraw function back again. As balance of the sender is still not modified at this stage, the attacker will succeed to transfer the amount of ether once again starting a new cycle (up to 10).

Possible solutions in this example are:
- reducing the balance before the ether transfer
- using mutex
- using require statement instead of if

Solidity security patterns - difference between call delegate call and library call


It might be a little bit tricky to distinguish between the different kind of calls in solidity. Basically library call is realized on a low-level by delegate call and it is different from a standard call. In a standard call the context of the called contract is considered as active. In a library or delegate call the calling context, meaning variables, storage, visibility remain active. In other words in a library call only the function code of the called contract will be loaded, every other parameter remain the same. The situation can be best seen by the following contract examples: 

contract CalledContract {
    event showAddressEvent(address _from);
    function test() payable public {
        showAddressEvent(this);
    }
}

contract CallingContract {
    function callDifferentContracts(address _contractAddress) public {
        require(_contractAddress.call(bytes4(keccak256("test()"))));
        require(_contractAddress.delegatecall(bytes4(keccak256("test()"))));
        testLib.calledSomeLibFun();
    }
}

library testLib {
    event showAddressEvent(address _from);
    function calledSomeLibFun() public {
        showAddressEvent(this);
    }

By calling the callDifferentContracts function with the address of the CalledContract, the code first reveals the address of CalledContract as it is expected by a standard call. After that it shows the address of the CallingContract both at the delegatecall and at the library call examples. 

Solidity security patterns - delegatecall and callcode


The problem is both with delegatecall and callcode that they dynamically load the code of a smart contract and call its function. Hence they do this loading in a way that the context (storage, memory etc) of the calling contract is preserved. It means that from the called contract any kind of variables (even privates !) of the calling contract can be changed. So it must be particularly paid attention that only one specific smart contract and only one specific function is to be called by callcode or delegatecall.

contract TestCallCode {

  function callDelegateFunction(address _a, string _functionName)  {
        _a.delegatecall(bytes4(keccak256(_functionName)));
 }
}

In the previous example if an attacker can call the callDelegateFunction and influence the address, he can redirect the call to any smart contract of a choice and with the functionName any function can be called. Even if there is no direct match between the _a address and _functionName the system can be sometimes tricked like with implementing malicious code into the fallback function. 

Tuesday, April 3, 2018

Solidity Tips and Tricks - delegatecall and callcode


It should be paid attention that delegatecall and callcode are pretty much similar in a lot of senses. Both delegatecall and callcode are executed in the context of the calling contract, meaning that the whole context of the calling contract is actually vulnerable for different attack possibilities. The only difference is that in callcode msg.sender and msg.value are not preserved. As in the following example, the private variable of contract D is changed by callTest even if the function was called indirectly from contract E.


contract D{
    uint private n = 0;
    
    function getN () returns (uint) {
        return n;
    }
    
    function callTest(address _e, uint _n) {
        _e.callcode(bytes4(sha3("setN(uint256)")), _n);
    }
}

contract E{
    uint public n = 0;
    
    function setN(uint _n) {
        n = _n;
    }
}

Solidity Tips and Tricks - private variable and delegatecall


Delegatecall means in solidity that the contract is executed under the context of the calling contract. Pay attention however because that means that even the private variables can be set from a different contract if you call them with delegatecall. As an example, in the following code, calling delegateCallTest will change the private variable n for contract D, even if the variable is marked as private and variable setting is executed in contract E.

contract D{
    uint private n = 0;
    
    function getN () returns (uint) {
        return n;
    }
    
    function delegateCallTest(address _e, uint _n) {
        _e.delegatecall(bytes4(sha3("setN(uint256)")), _n);
    }
}

contract E{
    uint public n = 0;
    
    function setN(uint _n) {
        n = _n;
    }
}

Solidity Tips and Tricks - delegatecall


Delegate call in solidity is somehow tricky. It is basically executed in the context of the calling contract that creates a couple of unexpected behaviors. As an example, considering the following contracts, calling setN is executed in the context of D, meaning that _n variable of D will be set and not for E! Another feature is that msg.sender and msg.value do not change values.

contract D{
    uint public n = 0;
    
    function delegateCallTest(address _e, uint _n) {
        _e.delegatecall(bytes4(sha3("setN(uint256)")), _n);
    }
    
}

contract E{
    uint public n = 0;
    
    function setN(uint _n) {
        n = _n;
    }

Friday, March 23, 2018

Solidity security patterns - forcing ether to a contract


Never use conditions or contracts that assume that the contract balance is zero. The problem is that the selfdestruct(targetaddress) command forces to send to the address contract independently how the targetaddress is defined. 

contract Balance
{
    function getBalance() view returns (uint){
        return this.balance;
    }
    
    function () payable{
        revert();
    }
}

contract ForceTransfer{
    address toTransfer;

    function getBalance() view returns (uint){
        return this.balance;
    }
    
    function payToContract() payable{
    }
    
    function ForceTransfer(address _address){
        toTransfer = _address;
    }
    
    function kill(){
        selfdestruct(toTransfer);
    }
}

Considering the previous examples, even if Balance explicitly implement a revert() in case a selfdestruct forces ether to the contract, there is no way to prevent it. As a consequence, patterns that implicitly or explicitly assume that the balance of the account is zero provide a relative huge security risk 

Solidity security patterns - uint underflow


As integer overflow is considered in solidity as one of a huge problems, in real life overflow happens rarely, actually because the values causing overflows are pretty big. However, if you use uint variables underflow is a much more critical problem that can happen frequently. 

contract testContract
{
    uint public integer = 0;
    uint public sub;
    
    function minusOne() returns (uint){
        return integer -1;
    }
    
    function checkSub(uint balance, uint amount2) returns (uint){
        sub = balance - amount2;
        require (sub > 0);
        return sub;
    } 
}

In the previous example calling minusOne() does not throw an error message, instead it returns with the biggest possible uint value: uint256: 115792089237316195423570985008687907853269984665640564039457584007913129639935

Similarly in the checkSub() function if you the amount2 is bigger than the balance variable, sub variable will underflow resulting a very huge integer number which will not trigger the require condition. 

Monday, February 12, 2018

Ethereum and smart contract security tools summarized


Some of the most important tools for testing ensuring or improving the security for your smart contract are the followings. Even if some of them are pretty much in a beta phase, it is practical to list them:

- OpenZeppelin: Solidity library for writing secure smart contracts:

- Oyente: analysis tool for smart contracts:

- SolCover: Solidity testing code coverage

- SolGraph: visualizing structure and control flow of solidity contracts

- Vyper: new experimental and more secure programming language for Ethereum smart contracts

- Securify: formal verification initiative for solidity smart contracts
https://securify.ch/

- SmartCheck: another verification tool for looking for wrongly implemented patterns
https://tool.smartdec.net/

- Ganache: more UI and user friendly testrpc



Tuesday, November 28, 2017

Notes on hash turing machines


Hash functions are basic building blocks of every blockchain or distributed ledger solutions. The blockchain itself is nothing more than a linked list of blocks that store transactions and the links are made photographically more secure with hash functions. There are other hash structures as well, like hash trees, called merkle trees to efficiently store the transaction in the blocks or hash tree algorithms to create a consensus mechanism from a different point of view. 

However, hash pointers should not only be considered only at data structures. Hash might be efficiently considered as a result or internal state of a computation. As an example, let we consider a Turing machine: each state change can be extended by a hash computation that computes a hash value based on the input and output states making sure that the given computation is highly secure and hacking resistance. In this sense, a result of a whole computation can be guaranteed by a hash value that is computed either by the inputs or outputs of the whole computation or by the hashes of the individual computational elements. Certainly, it is a little bit questionable what happens if a given algorithm can be implemented many different ways, implying that there might be several valid hash at the end of the computation.   

Sunday, April 9, 2017

Emerging trend: Reporting under encryption, KPI under encryption


Reporting and big-data analysis has been having a hype phase in the last couple of years, however considering a system architecture point of view a reporting systems has a pretty big security hole it is because it aggregates different kind of a data from probably the whole company or from several companies. The data is processed and presented in a way for some end-users, however in most cases there is no detail analysis about the fact who can see what. It is usually not such a huge problem as we speak of one company (although the security hole is certainly given), however it will be pretty big cross company discussion if the data is coming from several companies.

As a solution there might be possible to use one of the emerging encryption technology that aggregates the data without actually encrypting them, like with the help of zero knowledge proofs, homomorphic encryption or secure multiparty protocols. In this way not all of the data is leaked only some kind of a specific result is presented.  Let we called the field as Reporting under Encryption or KPI under encryption.

Another solutions might be to heavily use information labeling and filtering identifying who should actually be able to see that kind of data or information. In this sense, the field should be rather called secure reporting and secure KPI-s.