Welcome back to Linux Command Line Hackery, yes this is Part 2 and today we are going to learn some new skills. Let's rock
Let us first recap what we did in Part 1, if you are not sure what the following commands do then you should read Part 1. mkdirmyfiles # make a directory (folder) with myfiles as name cdmyfiles # navigate to myfiles folder touchfile1file2file3 # create three empty files file1, file2, file3 ls-l # view contents of current directory echo This is file1 > file1 # write a line of text to file1 catfile1 # display contents of file1 echo This is another line in file1 >> file1 # append another line of text to file1 catfile1 # display the modified content of file1 Command: cp Syntax: cpsource1 [source2 ...] destination Function: cp stands for copy. cp is used to copy a file from source to destination. Some important flags are mentioned below Flags: -r copy directories recursively -f if an existing destination file cannot be opened, remove it and try again Let us make a copy of file1 using the new cp command: cpfile1file1.bak what this command is going to do is simply copy file1 to another file named file1.bak. You can name the destination file anything you want. Say, you have to copy file1 to a different folder maybe to home directory how can we do that? well we can do that like this: cpfile /home/user/ I've used the absolute path here you can use whatever you like.
[Trick:~has a special meaning, it stands for logged in user's directory. You could have written previous command simply as cpfile1~/ and it would have done the same thing.]
Now you want to create a new directory in myfiles directory with the name backup and store all files of myfiles directory in the backup directory. Let's try it: mkdirbackup cpfile1file2file3backup/ this command will copy file1file2file3 to backup directory. We can copy multiple files using cp by specifying the directory to which files must be copied at the end. We can also copy whole directory and all files and sub-directories in a directory using cp. In order to make a backup copy of myfiles directory and all of it's contents we will type: cd.. # navigate to previous directory cp -r myfiles myfiles.bak # recursively copy all contents of myfiles directory to myfiles.bak directory This command will copy myfiles directory to myfiles.bak directory including all files and sub-directories Command: mv Syntax: mvsource1 [source2 ...] destination Function: mv stands for move. It is used for moving files from one place to another (cut/paste in GUI) and also for renaming the files. If we want to rename our file1 to file1.old in our myfiles folder we'll do the follow: cdmyfiles # navigate first to myfiles folder mvfile1file1.old this command will rename the file1 to file1.old (it really has got so old now). Now say we want to create a new file1 file in our myfiles folder and move the file1.old file to our backup folder: mvfile1.old backup/ # move (cut/paste) the file1.old file to backup directory touchfile1 # create a new file called file1 echo New file1 here > file1 # echo some content into file1 Command: rmdir Syntax: rmdir directory_name Function: rmdir stands for remove directory. It is used for removing empty directories. Let's create an empty directory in our myfiles directory called 'garbage' and then remove it using rmdir: mkdir garbage rmdirgarbage Good practice keep it doing. (*_*) But wait a second, I said empty directory! does it mean I cannot delete a directory which has contents in it (files and sub-directories) with rmdir? Yes!, you cannot do that with rmdir. So how am I gonna do that, well keep reading... Command: rm Syntax: rmFILE... Function: rm stands for remove. It is used to remove files and directories. Some of it's important flags are enlisted below. Flags: -r remove directories and their contents recursively -f ignore nonexistent files and arguments, never prompt Now let's say we want to delete the file file1.old in backup folder. Here is how we will do that: rmbackup/file1.old # using relative path here Boom! the file is gone. Keep in mind one thing when using rm "IT IS DESTRUCTIVE!". No I'm not yelling at you, I'm just warning you that when you use rm to delete a file it doesn't go to Trash (or Recycle Bin). Rather it is deleted and you cannot get it back (unless you use some special tools quickly). So don't try this at home. I'm just kidding but yes try it cautiously otherwise you are going to loose something important. Did You said that we can delete directory as well with rm? Yes!, I did. You can delete a directory and all of it's contents with rm by just typing: rm-rdirectory_name Maybe we want to delete backup directory from our myfiles directory, just do this: rm-rbackup And it is gone now. Remember what I said about rm, use it with cautious and use rm-r more cautiously (believe me it costs a lot). -r flag will remove not just the files in directory it will also remove any sub-directories in that directory and there respective contents as well. That is it for this article. I've said that I'll make each article short so that It can be learned quickly and remembered for longer time. I don't wanna bore you.
Some of you likely recall the talk back in 2016 or so of updating the OWASP Foundation website to not appear so much like a...well, a wiki. That talk was carried forward into 2017 and 2018 and, with each year, the proposal got pushed ahead as there were other, deeper projects to tackle. With the arrival of 2019 and a firm project plan under the guidance of Mike McCamon, Executive Director, we are finally moving toward a functioning, modern website that will be a whole lot less...wiki-like. The journey has been circuitous and, while we are not anywhere near complete, we have a set plan in place to bring it to fruition within the calendar year (second quarter of the year, actually).
TLDR: How Can You Help?
There are certainly ways in which you can get involved now. For instance, we are looking for a clean way to get wiki pages into GitHub markdown format for archival. I have done some work here but there are parsing issues with some of the tools. Do you know a good tool or have you done similar work? Also, are you or do you know a good designer, someone familiar with GitHub pages that can provide some useful help and feedback along the way? A Jekyll expert to help code a theme with a handful of templates would be a great addition. In addition, we could use website server admins who could help with assigning redirects to maintain search integrity. Finally, there will be a great many pages to move that we will also eventually need community involvement in.
So, What Have We Done?
Thus far we have researched various ideas for standing up a new site, including modifying the current wiki, spinning up our own web server, contracting a third party to host and build a new site, and also using existing infrastructure with our own content to launch a new face for OWASP. Our discussions led us to a familiar place, one that nearly every developer in the OWASP space is familiar with: GitHub.
In our conversations with GitHub, it became readily apparent that using the platform would be a win for the Foundation as well as GitHub. Nearly everyone who runs a project at OWASP (documentation or otherwise) uses GitHub. Because our target audience is also mostly developers we know that they are also very comfortable with the platform. And while GitHub has a number of high profile companies using their GitHub Pages, the use of the platform as the basis for the entire website of the number one non-profit foundation in the application security sector is a big draw.
We have run with that GitHub Pages idea and have spent internal manpower on a proof of concept. This proof of concept is less about the UX of the site than the functionality, the ability to utilize the authentication systems, and the ability to utilize automation to push out changes quickly.
Where Are We Now?
We are doing the final stages of website architecture. We are also planning what needs to be in the site, how the pieces will integrate with current projects and chapters, and how we might utilize the community to integrate the pieces so that we have a visually and functionally cohesive website that spans across multiple repositories.
What Is Next?
We will soon be looking for a modern website design that is responsive and clean. We will begin using the knowledge gained from our proof of concept to build out the internals of the website and then we will start implementing the highest traffic pages and administrative areas into the new platform. Once we have the big-ticket items moved we will start looking at what is left and moving over those pieces. The eventual goal would be to have a new, modern website for the future of OWASP while keeping the wiki as an archive of really useful information.
We hope you are as excited as we are about the future of the OWASP Foundation website and will join us as we move toward a modern web presence. If you have any questions or would like to volunteer your time, experience or knowledge, please contact me at harold.blankenship@owasp.com
Often while writing smart contracts we will want to call functions within other contracts either to leverage functionality within the other contract or for upgradability reasons. We can do this by leveraging libraries with Delegate Calls. There are various reasons to do this, including code re-use cost savings avoiding re-deploying large libraries. We will take a look at this while reviewing the technical details of the Parity Wallet hack at the end of this chapter. But first let's discuss some other aspects and nuances of the delegate call so we are comfortable with how they work and how we can use them in attacks.
We have seen multiple ways to interact with external contracts for example using the ABI of a contract with Web3 calls. We have also created interfaces to a contract when creating our malicious attacking contracts. Now we will expand on this using low level delegate calls to external contracts.
In this section we will show how to interact with other contracts using lower level functions such as, call and delegate call. We will show how the code can leverage the functionality of another contract using delegate calls within Solidity. Beware, that as usual whenever you use lower level functions within solidity, bad bad things can and will happen.
Firstly, let's just define some terms so that I don't confuse myself and I don't confuse the readers because this can get a bit confusing if we don't know which contract, we are discussing. So, I am going to label the following two terms upfront so we can distinguish which contact we are discussing and how they are interacting. If we don't do this, we are going to end up confused. This particular vulnerability and how it works took me a minute to wrap my head around. I actually had to deploy contracts and play with code interactions before it made sense. I hope to save you the trouble, since there were no good resources when I started learning this.
We will define two contracts as the following for the purposes of the code examples we are analyzing.
üCalling contract: The calling contract we are interacting with through our DApp
üLogic Contract: The library contract holding some kind of business logic we call with delegate call or call
With that out of the way let's get back to confusing myself along with you.
We often see delegate calls used when we don't have an ABI interface and as an upgradability pattern within solidity. In order to explain delegate call we are going to first talk about the differences between a regular call and a delegate call and what the results are with each of these call types.
Delegate calls are used to call the functionality of the logic contract but have the changes reflected in the context of the calling contract. It essentially behaves as if you imported the functionality of the logic contract into the calling contract and the changes are reflected in the context of the calling contract. This behaves much like importing libraries when you are coding large projects and using that functionality as if it were part of your project.
Vs
The regular call acts more like a remote API where we are making changes on the remote logic contract rather than our calling contract. When using a regular call, we are calling the logic contract but the effects of that are retained within the logic contract. Rather than in the context of the calling contract.
I know I know, I just confused you so let's look at a simple example and talk about the outcomes of each instance depending on if we are using call or delegate call:
The best way to start to understand delegate calls are to actually play with them. Deploy the above contract within Remix and play around with it for a few minutes before reading the code walkthrough.
Also note you can review the video walkthroughs to see this in action. But make sure that you have the contract open in Remix and you are following along, this is essential to your learning and retention of these concepts.
Note that the above code comprises of two contracts within one Solidity file, which will deploy without any issues in Remix and provide you with both the logic contract and the calling contract. The calling contract will have the functionality that you will be interacting with. So just paste it into Remix, compile and deploy it.
I have also supplied a bit of code that automatically grabs the Logic contract address via a call on line 14 since they are both in the same file. Automatically grabbing the second contracts address is useful when you're debugging so you don't have to deploy the first contract and manually add it every time you change the code and redeploy.
Things to try on your own before continuing:
üDeploy the above code as a single Solidity file in Remix and review the address of CallingContract.
üClick the print_my_delegate button and review the output in the logs section of the transaction.
üClick the print_my_call button and review the output in the logs section of the transaction.
Now that you have interacted with this code a bit within Remix, let's break it down piece by piece talk through some of the code, then do a walkthrough and explain the results.
6.function print_address() public returns(address){
7. returnedAddress = address(this);
8. emit contractAddress(returnedAddress);
9. }
10. }
The logic contract is pretty simple. We create an address variable named returnedAddress on line 3 which holds the value of the returned address from the print_address function. On line 7 we get the current address of the contract with the this keyword. This is kind of like self in python which says give me the variable value associated with the current instance of the object, in this case the address of the current contract based on context in which it has been called. In order to view this variable, we issue an Event on line 8 simply printing out the current value of the contract address.
In order to make use of the logic contract we have the CallingContract which is shown below:
First thing to notice on line 2 is the use of the exact same returnedAddress variable from the LogicContract. This is important when using delegate calls as the call will modify that variable locally on the calling contract from the Logic contracts remote functionality. If this variable does not exist it cannot be set, you should always have the same variables in each contract and have them in the correct order when using delegate call. We will talk more about variables and their behavior with delegate calls shortly when manipulating memory elements.
Next you will notice two functions, one function that is using a call on line 9 and one that is using a delegatecall on line 6.
We will see the differences with using each of these call types. Both of these functions are calling the same print_address function from the LogicContract using the logic_pointer address variable created on line 3. The logic_pointer variable is simply the address of the logic contract so our calls know where they are directed to. These two calls look very similar but that is where the similarities end as we will see in the following walkthrough.
Note: You will also notice some strange syntax wrapping our call to print_address using abi.encodeWithSignature. This is just simply an encoding mechanism before sending our data with our calls. Similar to encoding web calls with base64 except that delegate call only accepts a single un-padded bytes argument. It's nothing special, it's just the way we need to encode the data on these types of calls.
Deploying our Simple Example:
Actions to take:
üDeploy the contract in remix
üClick the print_my_call_address button
üClick the print_my_delegate_address button
The deployed contract should look similar to the following showing the contract address for CallingContract and the two functions available to us:
After you deploy the contract you will want to take note of the address of the CallingContract. In this example above the buttons you will see the calling contract address starts with the values 0x75A. Write the address of your contract down, as this contract address will be important when reviewing the output of the two functions print_my_call_address and print_my_delegate_address.
First let's review the output of using a regular call to the logic contract. When we click the print_my_call_address button you will see a new transaction post in the transaction window below the code.
Click the down arrow to view the transaction details and you should see output similar to the following under the logs section.
The output shows the event that emitted when the logic contract code was called with the returned address parameter coming from this. Notice that this is not the same address as our calling contract. This is the address of our LogicContract.
Next click the button for print_my_delegate_address. Again, check out the transaction window and click the down arrow to view the details. Within the logs section of the transaction you will see a similar event action: ___________________________________________________________________________________
This time note that the address returned is your CallingContract address that starts with 0x75. This is because with delegate call the code was run as if it was imported into the CallingContract using the context of the CallingContract for the returnedAddress variable posted to the event.
Now let's quickly go over how variables work within delegate calls and the importance of properly aligning these variables so they do not overwrite the wrong memory locations. In our example above we saw that we can execute code from the logic contract in the context of the caller. This is also true for the storage in the contract. Both the code and the storage are based on the context of the caller.
So, what does this mean? It means that when we change the value of a variable using our logic contract it will change the value of the variable within our calling contract if a delegatecall is used. This can be quite dangerous and lead to disastrous results as you will see in our Case Study of the Parity Wallet attack walkthrough at the end of this chapter.
For now, let's go over a simple example of what happens in memory when variables are incorrectly handled with delegatecall.
This example follows the same structure as the previous contract of having both the logic and calling contract in the same solidity file and retrieving the logic contracts address automatically for convenience.
Things to note:
üThere is only a single functionality between these contracts that sets the value of "a".
üThree variables are set in the calling contract "a", "b" and "logic_pointer"
üOne Variable is set in the logic contract "a"
üA delegate call is used in the calling contract to set the value of "a" using the set function from the logic contract.
Action Steps:
üTake note of the ordering of the variables between the two contracts.
üType out this code into remix and then deploy the CallingContract
üClick the b and a button and review their values
üNow click the setA button and review the values again
In the action steps above you would have noticed that when you set the value of "a" the value of "b" was the value that changed. Why is this?
So, we have to start thinking in which context we are using when calling the contract. The image below should help to clear this up. Take a look at that image for a minute and try to think about what happened.
So, in the calling contract we have "b", "a" and "Logic_Pointer". Then we have the variable "a" in the logic contract. When using a delegatecall we are executing the set function in the logic contract under the context of the calling contract which has those 3 variables with "b" being the first variable. You see where I am going with this? Essentially the logic contract only knows about the "a" variable and sets the first element in the memory to that value. However, we are in the context of the calling contract, and the calling contracts first memory slot is the variable "b".
So, what happens is when we initially deploy the contract, we have the following where both "a" and "b" equal 5.
Then we click the setA button to execute the delegatecall into the set function in the logic contract and this results in "a" remaining at the value of 5 but "b" is updated to the value placed in the setA function. In this case I used the value of 3.
The b value is overwritten because it is the first slot defined in the memory of the calling contract and the logic contract only knows about a single variable "a" in its own contract thus overwriting the value in the first slot of memory. Since we used delegate call we are not writing the memory in the logic contract but instead the calling contract.
Take a minute to let that all sink in. Review the picture from above with the memory slots. Think about the previous example of what context you are in when using delegate call. Then come back to this and check out the case study of this in action for a multi-million dollar theft in real life.
When it comes to attacks against misconfigured smart contracts with delegate calls the most famous of the attacks was the Parity Wallet hack which resulted in a multi-million-dollar losses. I will briefly but with detail discuss what one of the parity attacks entailed. This should bring together when you learned into a real-world example.
The vulnerable Parity contract we are referencing is located at the following address:
Essentially the parity wallet was a multi-signature wallet which was extremely lightweight and relied on functionality from a main library contract. Using libraries is a way of saving costs as wallets will be deployed multiple times on the blockchain and the fee to deploy contracts is based on the size of the instructions used in the contract. Less instructions on a smaller lightweight wallet equals less overall transaction payments. By deploying the main functionality within a callable library, the code only incurred a onetime fee for the larger codebase. Each additional deployed contract comes at a much smaller cost due to its reduced size of instructions. This is fantastic from both a cost savings and upgradeability perspective, depending how you deploy the functionality and how you handle access to libraries.
But the Parity wallet had a few shortcomings due to a combination of public initialization functions that lacked a usage state and authorization issues. Authorization issues allowed direct calls after initial contract deployment and delegate calls allowed attackers to interact with initialization functions in the context of the calling contract.
Parity Issues that allowed an Attack:
üAn attack Vector into the library via the wallet (DelegateCall in a Fallback function)
üInitialization functions that didn't check a wallets current initialization state
In this attack an attacker could gain control of the library via a public initialization function. Once the attacker gained control of the library via the initialization function, he was able to send two transactions. The first transaction was to take ownership of the contract found at the following link:
Browse to the above URL and click the "click to see more" link to review the live data from the output also showed and described in detail below. The transaction Input data shown made a call to the initWallet function. This call overwrote the owners of the contract with the attacker's address at [4] within the input data section.
Let's go into a little detail as to what the transaction values above are and how they were derived. This will help in understanding what is going on with this attack.
The data in the transaction can be broken down as the following
üA 4byte MethodID
üFive 32-byte values
The 4-byte MethodID which precedes the function parameters is the first 4 bytes of a sha3 hash of the initWallet method declaration. We can derive the sha3 value from the transaction by using the web3 utility functions and a substring of the sha3 output. You can try this out with the following commands.
The 5 parameters following the MethodID are defined as follows:
ü[0] Offset to the Owners Array length value: 60Hex or 96 bytes (3x32 = 96bytes to the Array length held at [3])
ü[1] How many owners are needed (Zero)
ü[2] Daily spending limit of the contract (A Large Number)
ü[3] Owners Array Length of 1 owner
ü[4] Attackers address value as the only address in the owner's array
A second transaction shown below, was then sent which transferred _value at [1] to the supplied _to address at [0] within the data section of the following transaction
Within the parity wallet there was a default payable function also known as a fallback function which used a delegate call into the wallet library. Fallback functions are called when a call is made to a contract and no function is specified while sending value to a contract. Using this functionality an attacker was able to access the fallback function and leverage the delegate call by calling the contract and NOT specifying a function but specifying msg.data with the target and values shown in the above exploit.
Fallback functions are often used as a catchall within contracts. I kind of think of them as the default from a switch statement or the else clause in a block of logic. You will see fallback functions aid us in many attacks for example tx.origin and reentrancy attacks. You also saw the usage of fallback functions in our chapter on reentrancy, when we used the functionality of a fallback function to loop through the contract calls and siphon value from the contract.
Taking a look at line 431 of the source code from the above link, this fallback function exposes all public functions of the wallet library to anyone with the fallback functions ability to send data into the wallet library via a delegatecall in the context of the calling contract on line 436. No worries, will explain context in a minute in our how delegate calls work section.
Notice that on line 435, the code logic states that if there is data within the transaction greater than 0 a delegate call is made which calls the wallet library in the context of the calling contract. We showed this above with the actual transaction data. But from a higher level the attacker used this logic to pass data to the wallet contract to perform the following to actions:
1.First calling the initWallet function as in the first transaction data we showed.
2.Followed by the execute function to both take ownership of a wallet via the wallet's fallback functionality and then transfer out the wallet's funds.
In order to perform this attack, all the attacker needs to do is:
üMake a transaction call to the wallet address
üNot specify a function in the in the wallet in order to invoke the fallback function
üSend msg.data with the values we saw in the attack transactions above
The fallback function will capture this transaction and forward it to the wallet library for us via a delegate call.
This attack resulted in millions of dollars of losses for users of the Parity wallet. I wanted to show an example of a real-world attack so you could see how it was constructed and know how serious this issue is. Millions of dollars can be lost with a relatively simple attack, in this case 31 million.