Step into the shoes of Ash Williams or his friends from the iconic Evil Dead franchise and work together in a game loaded with over-the-top co-op and PVP multiplayer action! Play as a team of four survivors, exploring, looting, crafting, managing your fear, and finding key items to seal the breach between worlds in a game inspired by all three original Evil Dead films as well as the Starz original Ash vs Evil Dead television series.
ICONIC CHARACTERS
Play as characters from throughout the Evil Dead universe, including Ash, Scotty, Lord Arthur, Kelly Maxwell, Pablo Simon Bolivar, and more, with new dialogue performed by Bruce Campbell and others!
PLAY AS GOOD OR EVIL...
Fight for the forces of good or take control of the powerful Kandarian Demon to hunt Ash and other players while possessing Deadites, the environment, and even the survivors themselves as you seek to swallow their souls!
OVER THE TOP VISUALS
Whether you're tearing a Deadite in two with Ash's famous chainsaw hand or flying through the map as the Kandarian Demon in spirit form, the game captures the look and feel of the Evil Dead franchise in all its glory, with realistic visuals and a physics-based gore system that brings the horror to life!
THIS...IS MY BROOMSTICK!
Brandish your short barrel shotgun, chainsaw, cleavers and more to do some delightfully gruesome violence against the armies of darkness.
Evil Dead: The Game features multiplayer co-op and PvP for PC, Xbox One, Xbox X|S, PlayStation 4, PlayStation 5, and Nintendo Switch.
The DelegateCall attack or storage collision is expounded in this post.
Before you can grasp this exploit, you must first understand how Solidity saves state variables as explained here.
We start with the differences between call and delegatecall in Solidity, followed by exploiting the vulnerability of the delegatecall using the proxy contracts (mostly in smart contract upgrades), and then a solution for the attack.
Let’s start the journey!
Call VS DelegateCall
Solidity supports two low-level interfaces for interaction or sending messages to the contract functions.
These interfaces operate on addresses rather than contract instances (using this keyword). The key differences are highlighted with an example.
Call
It allows you to call the code of the callee contract from the caller with the storage context of the callee.
In order to understand this confusing sentence, let’s consider two contracts A, and CallA, with the naming convention as below:
A is the callee,
CallA is the caller
// Callee
contract A
{ uint256 public x; function foo(uint256 _x) public { x = _x; }
} // Caller
contract CallA
{ uint256 public x; function callfoo(address _a) public { (bool success,) = _a.call(abi.encodeWithSignature("foo(uint256)", 15)); require(success, "Call was not successful"); }
}
To test, deploy the contracts on Remix, and when you execute the caller (CallA -> callfoo), you can verify that foo() gets called, and the value of ‘x‘ in the callee(A ->x) is set to 15.
Note: It is also possible to send Ether and gas as part of the call using value and gas as params.
The above scenario is described in the figure as shown.
Fig: call flow
DelegateCall
It allows you to call the code of the callee contract from the caller with the storage context of the caller.
As previously mentioned, let’s consider two contracts A and DelegateCallA, with the naming convention as below:
A is the callee,
DelegateCallA is the caller
contract A
{ uint256 public x; function foo(uint256 _x) public { x = _x; }
} contract DelegateCallA
{ uint256 public x; function callfoo(address _a) public { (bool success,) = _a.delegatecall(abi.encodeWithSignature("foo(uint256)", 15)); require(success, "Delegate Call was not successful"); }
}
To test, deploy the contracts on Remix, and when you execute the caller (DelegateCallA -> ‘callfoo’), you can verify that foo() gets called and the value of ‘x‘ in the callee(A ->x) is still 0, while the value of x in the caller (DelegateCallA -> x) is 15.
Equipped with the above examples, it is evident that the delegatecall, executes in the caller’s context, while the call executes in the callee context.
A picture speaks a thousand words. The above scenario is in the below figure.
Fig: delegatecall flow
One use case of call is the transfer of Ether to a contract, and it passes all the gas to the receiving function, while the use cases of the delegatecall are when a contract invokes a library with public functions or uses a proxy contract to write smart upgradeable contracts.
Exploit with delegatecall
The most widely adopted technique to upgrade contracts is utilizing a proxy contract.
A proxy interposes the actual logical contract and the dapp interface. To update the logical contract with a new version (say V2), only the new deployed address of the logical contract is passed to the proxy.
This helps achieve minimal or no changes in the dapp/web3 interface, saving a lot of development time.
Fig: Contract upgrade with proxy
Let us write a quick and short proxy, and a logical contract (say V1). For the same, create a file DelegateCall.sol with Proxy and V1 contracts as below.
contract Proxy
{ uint256 public x; address public owner; address public logicalAddr; constructor(address _Addr) { logicalAddr = _Addr; owner = msg.sender; } function upgrade(address _newAddr) public { logicalAddr = _newAddr; } // To call any function of the logical contract fallback() external payable { (bool success, ) = logicalAddr.delegatecall(msg.data); require(success , " Error calling logical contract"); }
}
V1, This represents version 1 of the logical contract.
contract V1
{ uint256 public x; // abi.encodedWithSignature("increment_X()") = 0xeaf2926e function increment_X() public { x += 1; }
}
Compile, deploy and run the contracts in Remix with the constructor param in proxy as the address of the V1 contract.
You can observe that, when the abi.encodedWithSignature("increment_X()"))is passed as calldata to Proxy (fallback() is triggered), the function increment_X() in V1 is called.
As discussed above in delegatecall, the storage context of the caller (i.e., Proxy) is used, and the value of x in Proxy is incremented by 1.
So far, this is all good.
At some point in the future, it is decided to upgrade the V1 contract with new functionality, let’s call it V2.
Create a new contract V2
contract V2
{ uint256 public x; uint256 public y; function increment_X() public { x += 1; } // abi.encodedWithSignature("set_Y(uint256)", 10) //0x1675b4f5000000000000000000000000000000000000000000000000000000000000000a function set_Y(uint256 _y) public { y = _y; }
}
Compile and deploy V2.
Pass the address of V2, to upgrade()in Proxy as V2 is the new contract we need.
When abi.encodedWithSignature("set_Y(uint256)", 10))is passed as calldata to proxy, the function increment_Y() in V2 is called.
The value of y is 10, but wait a minute, surprise, surprise!
As there is no y in the Proxy contract, and as the storage context of Proxy is used, it has overwritten the second param in Proxy (i.e., owner) with 10 (or 0x000000000000000000000000000000000000000A).
With the owner address changed, the attacker is now in complete control of all the contracts.
How to Prevent the Attack
The delegatecall is tricky to use, and erroneous usage might have disastrous consequences.
For example, possible solutions to the above problem can be
If possible, avoid using additional storage variables or go stateless in the upgraded contract – V2.
Mirror the storage layout in V2, in other words, the contract calling delegatecall and the contract being called must have the same storage layout.
By implementing unstructured storage in proxy with the help of assembly code as in OpenZeppelins proxy and not having any storage variables in proxy apart from the logical contract address.
Outro
In this tutorial, we saw how delegatecall can lead to disastrous results with an incorrect understanding or usage.
While using delegatecall, it is vital to keep it in our minds that delegatecall keeps context intact (storage, caller, etc…).
Even though there are certain problems associated with delegatecall, it is very often used in many contracts such as OpenZeppelin, Solidity libraries, EIP2535 diamonds, and many more.
Posted by: xSicKxBot - 05-30-2022, 08:22 AM - Forum: Lounge
- No Replies
Learn Unreal Engine Game Development With This $35 Online Course Bundle
If you're a hobbyist programmer who is interested in Unreal Engine development, we have an e-learning bundle that could prove useful. The Ultimate Learn Unreal Game Development Bundle includes five courses revolving around Unreal Engine development. Through the long weekend, you can snag lifetime access to these courses for only $35 via GameSpot Deals.
The courses are taught by the experts at GameDev.tv, an experienced e-learning institution that offers online game development courses. All told, the bundle is valued at over $800, as most of the courses regularly go for close to $200, and features more than 95 hours of instruction.
Soundfall is a dungeon crawler that combines looter-shooter action with rhythm-based gameplay. Venture out solo or with up to 4 friends locally or online. Collect loot and time your actions to the beat to become all powerful. Play the Campaign Mode, Free Play 100's of songs or import your own music!
How to Overwrite the Previous Print to Stdout in Python?
Rate this post
Summary: The most straightforward way to overwrite the previous print to stdout is to set the carriage return ('\r') character within the print statement as print(string, end = "\r"). This returns the next stdout line to the beginning of the line without proceeding to the next line.
Problem Formulation
Problem Definition: How will you overwrite the previous print/output to stdout in Python?
Example: Let’s say you have the following snippet, which prints the output as shown below:
import time for i in range(10): if i % 2 == 0: print(i, end="\r") time.sleep(2)
Output:
Challenge: What we want to do is instead of printing each output in a newline, we want to replace the previous output value and overwrite it with the new output value on the same line, as shown below.
Expected Output
Method 1: Using Carriage Return (‘\r’) Character
Approach: The simplest solution to the given problem is to use the carriage return (‘\r‘) character within your print statement to return the stdout to the start of the same print line without advancing to the next line. This leads to the next print statement overwriting the previous print statement.
Note: Read here to learn more about the carriage return escape character.
Code:
import time for i in range(10): if i % 2 == 0: print(i, end="\r") time.sleep(2)
Output:
That’s easy! Isn’t it? Unfortunately, this approach is not completely foolproof. Let’s see what happens when we execute the following snippet:
import time li = ['start', 'Processing result']
for i in range(len(li)): print(li[i], end='\r') time.sleep(2)
print('Terminate')
Output:
print('Terminate') is unable to completely wipe out the previous output. Hence, the final output is erroneous.
Since we are executing each output generated by a print statement on top of the previous output, it is not possible to display an output properly on the same line if the following output has a shorter length than the output before.
FIX: To fix the above problem, instead of simply overwriting the output, we must clear the previous output before displaying the next output. This can be done with the help of the following ANSI sequence: “\x1b[2K“.
Code:
import time li = ['start', 'Processing result']
for i in range(len(li)): print(li[i], end='\r') time.sleep(2)
print(end='\x1b[2K') # ANSI sequence to clear the line where the cursor is located
print('Terminate')
Output:
Method 2: Clear Line and Print Using ANSI Escape Sequence
Approach: The idea here is to use an extra print statement instead of altering the end parameter of the print statement that is used to display the output. The extra print statement is used to move the cursor back to the previous line where the output was printed and then clear it out with the help of ANSI escape sequences.
Explanation:
Print a line that ends with a new line initially.
Just before printing the next output on the new line, perform a couple of operations with the help of ANSI escape sequences:
Move the cursor up, i.e., to the previous output line using the escape sequence: ‘\033[1A‘.
Clear the line using the escape sequence: ‘\x1b[2K‘
Print the next output.
Code:
import time UP = '\033[1A'
CLEAR = '\x1b[2K'
for i in range(10): if i % 2 == 0: print(i) time.sleep(2) print(UP, end=CLEAR)
Output:
Discussion: Though this code might look a little more complex than the previous approach, it comes with a major advantage of the neatness of output. You don’t have to worry about the length of the previous output. Also, the cursor does not visually hinder the output being displayed.
Here’s a handy guide to escape sequences with respect to cursor movements:
ESCAPE SEQUENCE
CURSOR MOVEMENT
\033[<L>;<C>H
Positions the cursor. Puts the cursor at line L and column C.
\033[<N>A
Move the cursor up by N lines.
\033[<N>B
Move the cursor down by N lines.
\033[<N>C
Move the cursor forward by N columns.
\033[<N>D
Move the cursor backward by N columns.
\033[2J
Clear the screen, move to (0,0)
\033[K
Erase the end of line.
Method 3: Using “\b” Character
Another way to overwrite the previous output line is to use the backspace character(“\b“) and write to the standard output.
Code:
import time
import sys for i in range(10): if i % 2 == 0: sys.stdout.write(str(i)) time.sleep(1) sys.stdout.write('\b') sys.stdout.flush()
Output:
Caution: Ensure that you properly flush the buffer as done in the above snippet. Otherwise, you might see that only the last result is displayed at the end of the script.
Bonus Read Ahead
What is Carriage Return (\r) in Python?
Simply put, carriage return is an escape character just like \n. Carriage return is denoted as \r and it is basically used to shift the cursor to the beginning of a line or string instead of allowing it to move on to the next line.
Whenever you use the carriage return escape character ‘\r’, the content that comes after the \r will appear on top of your line and will keep replacing the characters of the previous string one by one until it occupies all the contents left after the \r in that string.
Example:
li = ['One', 'Two', 'Three']
for i in range(len(li)): print(li[i], end='\r') # OUTPUT-->Three
Conclusion
To sum things up, the easiest way to overwrite the previous print is to use the carriage return \r character within your print statement using the end parameter. To ensure that the previous output is completely erased before printing the new output, you can use the \x1b[2K ANSI escape sequence.
I hope this tutorial helped you. Here’s another interesting read that you may find useful: Python Print One Line List
One of the most sought-after skills on Fiverr and Upwork is web scraping. Make no mistake: extracting data programmatically from websites is a critical life skill in today’s world that’s shaped by the web and remote work.
So, do you want to master the art of web scraping using Python’s BeautifulSoup?
If the answer is yes – this course will take you from beginner to expert in Web Scraping.
JDK 16.0.1, 11.0.11, 8u291, and 7u301 Have Been Released!
The Java SE 16.0.1, 11.0.11, 8u291, and 7u301 update releases are now available. You can download the latest JDK releases from the Java SE Downloads page. OpenJDK 16.0.1 is available on http://jdk.java.net/16/. New Features, Changes, and Notable Bug Fixes For information about the new features, chan...
The games are free to keep until June 2 2022 - 15:00 UTC.
Next week's freebie: mystery
We are welcoming everyone to join our discord[discord.gg]. We are more active there on finding giveaways, small or large, and there are daily raffles you can participate.