Hacking Solidity For fun and profit


After a long period of silence I am now going to write a post for hacking Solidity smart contracts for dummies (like me). The easiest way to pen-test Solidity smart contracts is through REMIX!!!!! This post provides an introduction to the world of smart contract security for people with a background in traditional cyber security and little knowledge of crypto and blockchain tech. While other smart contract platforms exist, we will be focusing on Ethereum, which is currently the most widely adopted platform. 

The Landscape In Smart Contracts

When you will start hacking smart contracts, you will instantly understand that there is NO DOCUMENTATION or NOOOOOO TUTORIALS or NO NOTHING. Do not get depressed, Elusive Thoughts is here to help you!!!. 

First go through Mastering Ethereum, then you are good to go.

Web Apps Versus DApps

On my quest to Solidity hacking, I found this awesome info on arvanaghi (see references below) so enjoy. When your browser interacts with a regular web application, the web app might speak to other internal servers, databases, or a cloud. 

In the end, the interaction is simple:

In a DApp, most interactions are the same. But there’s a third element: the smart contract, which is publicly accessible. Some interactions with the web application will lead to either a read or a write to one or multiple smart contracts on the Ethereum blockchain.

Because smart contracts are publicly accessible, we can interact with them directly, unimpeded by the web server logic that might limit what transactions we can issue.

So far, we have a two-pronged approach to our hacking quest:
  • A standard web application we can hack by simply exploiting, authentication, access controls, and session management etc.
  • A DApp application has a Web Component and the smart contract audit element.
Note: In other words, we check for logical and input validation errors in both the web application and the smart contract logic.

Below we can visualize the flows described:

Note: In order to interact with the chain directly, you can use a wallet such as Metamask.

Hacking DApps

When you create a Smart Contract, some kind of message is sent to the Blockchain. This message allows you to access your contract. So that no one else but the creator of the Smart Contract can change anything (become a super user!!). We essentially create a new variable of type address called “owner”. In Solidity language we use modifiers to expand the mentioned concept by altering function execution flow.

In Solidity, modifiers express what actions are occurring in a declarative and readable manner. They are similar to the decorator pattern used in Object Oriented Programming. In Solidity functions are tagged with the label modifier to control access, or put in other words, modifiers are used to modify the behavior of a function. For example you can add a prerequisite to a function, in order to execute.

Below we can see a simple modifier example:

    modifier onlyOwner {
        require(msg.sender == owner); 
        // The message sender has to be the owner (msg.sender is an environment variable )
        // Execution body from function to alter.

Note: Here we define a modifier. 

Below we can see how modifier is used (through function tagging):

    function writeData(bytes32 data) public onlyOwner returns (bool success) {
        // will only run if owner sent transaction

Because of modifiers, though, there’s actually a third prong to our attack we can have to consider. 

Below we can see the flow of what we just described:

Because DApps deal with Ethereum accounts, they are based on public key authentication. Not password authentication is used most of the time (serious DApps use JWT tokens in conjunction with the public key authentication). Though we can interact directly with the smart contract, we can’t execute functions when modifiers like onlyOwner are properly implemented.   

This means that the server is acting as a middle man, between you and the blockchain, or put simple, the "wallet of the DApp server" has the address of the owner (not always) and the private keys and you don't. A DApp, with proper security architecture does not follow the mentioned design patterns. Meaning that if we implement proper RBAC we are good to go.  Also the majority of DApp now is still using the mentioned bad design patterns.

When dealing with a DApp, the private keys to these privileged addresses almost certainly exist on the web server. And the web application almost certainly has logic that takes user input over the web and calls a privileged function in the smart contract using one of those keys.

All this considered, we have our attack surface:
  • A standard web application assessment requires to test for typical OWASP Top 10 vulnerabilities and you are covered.
  • A smart contract audit of the source code. 
  • Attempting to forge privileged writes to the smart contract through the web interface. Can you get the web application to interact with the smart contract in a way it didn’t expect?
So to test the DApp, we would have to use a Web Proxy such as Burp and also review and test the Solidity code (perform both dynamic and static code analysis). Because I dedicated my life writing post on web app testing, I am going to skip the web testing. But what you should remember is that always check key privilege checks, when testing DApps. 

Note: Also if you try to hack legitimate DApps, without permission, you should now that it is illegal and escaping with the funds is not easy, you are going to get caught in a tornado mesh.  

Solidity Tools For Hacking

Tops tools for automating part of the Smart Contract pen-test are:
  • REMIX - Remix IDE is used for the entire journey of smart contract development by users at every knowledge level. It requires no setup, fosters a fast development cycle and has a rich set of plugins with intuitive GUIs. The IDE comes in 2 flavors (web app or desktop app) and as a VSCode extension.
  • VSCode - Visual Studio Code is a lightweight but powerful source code editor which runs on your desktop and is available for Windows, macOS and Linux. It comes with built-in support for JavaScript, TypeScript and Node.js and has a rich ecosystem of extensions for other languages and runtimes (such as C++, C#, Java, Python, PHP, Go, .NET). 
  • Slither - Slither is a Solidity static analysis framework written in Python 3. It runs a suite of vulnerability detectors, prints visual information about contract details, and provides an API to easily write custom analyses. Slither enables developers to find vulnerabilities, enhance their code comprehension, and quickly prototype custom analyses.
  • Mythril - Mythril is a security analysis tool for EVM bytecode. It detects security vulnerabilities in smart contracts built for Ethereum, Hedera, Quorum, Vechain, Roostock, Tron and other EVM-compatible blockchains. It uses symbolic execution, SMT solving and taint analysis to detect a variety of security vulnerabilities. It's also used (in combination with other tools and techniques) in the MythX security analysis platform.

Setting Up The Hacking Environment 

The biggest pain on Solidity Smart contract testing is to configure and add the libraries, so as for the project to run smoothly. Not anymore, here see an easy way to do it.

Step One: Load the project from Github to Remix :- In the top left corner clieck Clone Git Repository.

Note: Most of the time the client will give you a public git repo URL to load the code (or a private git repo URL). Now with Remix, you can load that it directly.

Note: When you upload confidential information in Remix, you better have the permission or the code is patented.

Step Two: Compile your code and troubleshoot :- 

Note:  It does worth mentioning that the Remix compiler will also generate the relevant project files. Which you can download and use on your workstation with some modifications. 

Step Three: Fixing import errors:- 

In order to resolve the issue we refer to the online tutorial REMIX guide found here. Which says more or less to replace the original path:
import "../../utils/introspection/IERC165.sol";

And then taddaaaaaa magic happens, the code is compiles!!!

Remix Debugging and Security Plugins

Remix besides an online compiler has also awesome!!!! plugins, including that of static analysis for debugging. Static code analysis is a process to debug the code by examining it and without actually executing the code. Solidity Static Analysis plugin performs static analysis on Solidity smart contracts once they are compiled. It checks for security vulnerabilities and bad development practices, among other issues. It can be activated from Remix Plugin Manager.

Another plugin you would like to also install is MythX by ConsenSys. MythX is a security analysis service and performs Static and Dynamic Security Analysis using the MythX Cloud Service. MythX offers a suite of analysis techniques that automatically detects security vulnerabilities in Ethereum smart contracts. 

Note: Mythx requires an API key to work with Remix.

Step Four: Installing the static analysis plugin. In order to install the plugin, go in the left bottom corner.

Step Five: Use the search manager to find the plugins you like to do your hacks (type static analysis).

Note: There are numerous plugins you can choose from to install. Search the ones you like. 

Below we can see the plugins to install (static analysis):

Below we can see the plugins to install (MYTHX):

Note: The plugin has dependency Solidity Compiler plugin, you need to activate in also.

The static analysis plugin checks for the following security issues:

The plugin static analysis also looks for non-security issues. Some of the issues shown below can be used to perform Gas Denial of Service attacks so pay attention!!!!!: 

The report generated  by the static analysis plugin will look like this:

 Some of the findings can be false positives, so take care. Make sure you untick the external library option if the libraries are trusted.

Interacting From Your Machine With Remix 

The next step would be, to see how we can interact with Remix, locally from our machine. For a complex project, you can't just copy paste the single sol file and let it run. To make our life easier, Remix has localhost connection which allows you to interact with your project in your local machine remotely. This is something I'm used to doing when the project has a large number of inheritant contracts. Obviously, this make our life easier than ever by just downloading the git project and do some commands.

remixd is a tool that intend to be used with Remix IDE (aka. Browser-Solidity). It allows a websocket connection between Remix IDE (the DApp) and the local computer. You can also use Burp to intercept the remixd traffic (although is not going to be easy). Practically Remix IDE makes available a folder shared by remixd. If you would like to install the tool follow the steps below (remixd needs npm and node).

yarn global add @remix-project/remixd

Note: Alternatively remixd can be used to setup a development environment that can be used with other popular frameworks like Embark, Truffle, Ganache, etc. The command above will work in most linux distributions.

Step Six: Go to WorkSpaces and click "Connect to Localhost"

Step Seven: Check the remixd version and connect.

Note: The message box pops up and you just need to read carefully and copy the command shown in the box to connect your localhost. The parameter -u in the remixd is a copy paste of the workspace you actively using (if you moved in the tab workspace).

The remixd command for my workspace is:

remixd -s localWorkspace/ -u https://remix.ethereum.org

Note: remixd provides full read and write access to the given folder for any application that can access the TCP port 65520 on your local host. To minimize the risk, Remixd can ONLY bridge between your filesystem and the Remix IDE URLS - including:
  •   https://remix.ethereum.org
  •   https://remix-alpha.ethereum.org
  •   https://remix-beta.ethereum.org
  •   package://a7df6d3c223593f3550b35e90d7b0b1f.mod
  •   package://6fd22d6fe5549ad4c4d8fd3ca0b7816b.mod
  •   https://ipfsgw.komputing.org
Note: In the terminal where remixd is running, typing ctrl-c will close the session. Remix IDE will then put up a modal saying that remixd has stopped running. If you want to kill the remixd, just run killall node from the terminal you launched the tool.

Remixd and Slither (automated security scans)

The end goal of this lengthy post is to make you able to run remotely automated scans with tools such as slither.  When remixd NPM module is installed, it also installs Slither and solc-select and latest version of solc. 

If you run the following command in your Linux box, it will work 90% of the time:

remixd -i slither

Note: The command above will take care all the dependencies.

If a project is shared through remixd and localhost workspace is loaded in Remix IDE, there will be an extra checkbox shown in Solidity Static Analysis plugin with the label:

Note: When you connect to localhost, remixd will create an empty workspace. Use it to add the sol files. Also 




Solidity Smart Contract Upgradeability


This article is going to focus on Smart Contract upgradability, why this important and how can we achieve it. When dealing with Smart Contracts we need to be able to upgrade our system code. This is because if security critical bugs appear , we should be able to remediate the bugs. We would also want to enhance the code and add more features. Smart Contract upgradability is not as simple as upgrading a normal software due to the blockchain immutability.
As already mentioned by design, smart contracts are immutable. On the other hand, software quality heavily depends on the ability to upgrade and patch source code in order to produce iterative releases. Even though blockchain based software profits significantly from the technology’s immutability, still a certain degree of mutability is needed for bug fixing and potential product improvements.

Preparing for Upgrades   

In order to properly do the upgrade we should be focusing in the following aspects of the project:
  • Have money management strategies in place
  • Create a pause functionality 
  • Have paths to upgrades
    • Switching addresses
    • Switching Oracles
    • Proxy contracts 

The mentioned functionality is mandatory in order to properly maintain and do risk management on your system. The money management strategy has to do with were and how we hold the funds and the system data. The switch address is related to the proxy contract and the rest have to do with the flow paths we designed to upgrade the smart contracts [1]. 

Proxy Contract

The basic idea is using a proxy for upgrades. The first contract is a simple wrapper or "proxy" which users interact with directly and is in charge of forwarding transactions to and from the second contract, which contains the logic. The key concept to understand is that the logic contract can be replaced while the proxy, or the access point is never changed. Both contracts are still immutable in the sense that their code cannot be changed, but the logic contract can simply be swapped by another contract. The wrapper can thus point to a different logic implementation and in doing so, the software is "upgraded"

Note: This abstract proxy contract provides a fallback function that delegates all calls to another contract using the EVM instruction delegatecall. We refer to the second contract as the implementation behind the proxy, and it has to be specified by overriding the virtual _implementation function. Additionally, delegation to the implementation can be triggered manually through the _fallback function, or to a different contract through the _delegate function. 

The most immediate problem that proxies need to solve is how the proxy exposes the entire interface of the logic contract without requiring a one to one mapping of the entire logic contract’s interface. That would be difficult to maintain, prone to errors, and would make the interface itself not upgradeable. Hence, a dynamic forwarding mechanism is required [1].

Proxy Setup

Below we can see that the contract proxy has one to one relationship with all the logic contract proxy. An this is important in order to understand that this setup kind of breaks the immutability of the blockchain.