EthSecurity
5.22K subscribers
112 photos
20 files
758 links
Download Telegram
One common vulnerability with the ecrecover function in Solidity is malleability of signatures.

ecrecover is used to recover the address that signed a message from an elliptic curve signature. However, signatures in crypto systems like Ethereum are malleable.

This means it is possible to modify a signature in a way that remains valid for the same message and public key, but produces a different signature value.

A common attack involves an attacker modifying a valid signature before it is verified via ecrecover. This could allow:

Impersonating the signer by recovering their address from a maliciously modified signature.

Hiding the real signer by modifying their valid signature into one that recovers to a different address.

Tricking contracts rely on ecrecover for authentication or permissions.

To prevent this, signatures should be verified correctly against the original message and public key, rather than relying on ecrecover alone. Additionally, signature metadata like timestamp/nonce can be included in the digest to make them non-malleable. @EthSecurity1
What is the difference between an optimistic rollup and a zk-rollup?

The main differences between optimistic rollups and zk-rollups in Ethereum layer 2 scaling are:
β€’ Optimistic rollups use fraud proofs to ensure validity - transactions are assumed valid and anyone can submit a fraud proof to show invalid state transitions. Zk-rollups use zero-knowledge proofs to ensure validity - each transaction batch comes with a cryptographic proof of validity.
β€’ Optimistic rollups have longer withdrawal times (1-2 weeks) since you need to wait for the challenge period to elapse before withdrawing. Zk-rollups have faster withdrawal times (minutes to hours) since validity is already proven.
β€’ Optimistic rollups can achieve higher transaction throughput as validity does not need to be proven for each transaction. The computation costs are lower. Zk-rollups have lower throughput since each transaction must be proven valid.
β€’ Zk-rollups provide stronger security guarantees and fraud proof protection compared to optimistic rollups. However they require more computational overhead.
β€’ In summary, optimistic rollups rely on fraud proofs for validity whereas zk-rollups use zero-knowledge proofs. Zk-rollups have faster withdrawals but lower throughput while optimistic rollups have higher throughput but slower withdrawals.

How does EIP1967 pick the storage slots, how many are there, and what do they represent?

P-1967 is an Ethereum Improvement Proposal that standardizes a pattern for deploying upgradeable smart contracts.
EIP-1967 uses a proxy contract that delegates calls to the implementation contract. It defines a specific storage layout to manage this:
β€’ There are 2 storage slots used.
β€’ Slot 0 stores the address of the implementation contract. This is the logic contract that contains the actual code.
β€’ Slot 1 stores the admin address, which has permissions to upgrade the implementation contract address in slot 0.
So in summary:
β€’ 2 total storage slots.
β€’ Slot 0 stores implementation address.
β€’ Slot 1 stores admin address with upgrade permissions.
This allows the proxy contract address to stay constant while the implementation can be switched out by the admin. Users only interact with the proxy, which delegates to the implementation, enabling upgradeability via EIP-1967.
@EthSecurity1
Here are some other common uses of the delegatecall functionality besides just proxies:

Library calls - A contract can delegatecall a library to reuse shared code without duplication.

Upgrades - By delegatecalling a new implementation address, upgrading logic is possible without redeploying the entire contract.

Inheritance - Contracts can inherit behavior from parent contracts by delegatecalling base contracts from derived ones.

Sandboxing - Dangerous operations can be isolated using delegatecalls to avoid reentrancy exploits in the main contract.

Middleware - Common responsibilities like authorization, validation etc. can be externalized using delegatecalls.

Payment channels - State updates can occur off-chain via signed delegatecalls submitted simultaneously.

Oracles - Data feeds can be provided via delegatecalls to isolated oracle contracts without trusting them.

Multisig wallets - Approval proxies can require multisig authorization by delegatecalling the transaction sender.

DEX protocols - Trading pairs, pricing models etc. can flexibly be implemented via delegatecall integrations.

Under what circumstances would a smart contract that works on Etheruem not work on Polygon or Optimism? (Assume no dependencies on external contracts)


Opcode support - Layer 2s generally support the same EVM opcodes as Ethereum, but there may be some minor discrepancies in opcode behavior that could cause issues.

Chain properties - Things like block time, intrinsic gas costs, and incentive structures can differ across chains in potentially breaking ways.

Pricing models - Layer 2s often have different currency pegs, interest rates, and transaction/contract execution pricing that contracts rely on.

State storage - Polygon/Optimism have additional constraints on state storage gas costs and storage that a native Ethereum contract may violate.

Timestamps - Block times are faster on L2s, so contracts relying precisely on timestamps could malfunction.

Consensus models - Differences in consensus algorithms like finality could cause issues for contracts expecting immediate confirmation.


Chain ID - Each chain has a unique chain ID. Contracts using chain ID for randomness or permissions would fail cross-chain.


Requirements for ETH - Logic requiring ETH balances or transfers directly wouldn't work without wrapping ETH on those chains first.

Mainnet EIP changes - A contract deployed before an EIP like 1559 may not account for changes introduced and fail on current Ethereum.

Network upgrades - Hard forks, consensus changes over time could cause issues if a contract doesn't anticipate potential future upgrade incompatibilities. @EthSecurity1
πŸ‘6❀2
How can a smart contract change its bytecode without changing its address?

There are a few ways a smart contract could change its bytecode without changing its address:

Upgradeable proxies - The contract address stays the same while the implementation address it proxies to can be updated, allowing bytecode changes.

Library delegation - If a contract delegates functionality to upgradeable libraries, the libraries' bytecode can change without affecting the contract address.

State channels - Contract state could transition through different bytecode versions via signed state updates submitted off-chain without changing the on-chain address.

Eternal storage - Storing critical code/data in an immutable "storage" contract while non-critical code resides in an upgradable "proxy" contract.

Self-replacement - Contract includes logic to suicidally delete and redeploy itself at the same address with new bytecode, careful state migration required.

Data availability - Contract source and data is decoupled, allowing new implementations to reuse stored data under the same address.
How change bytecodes of deployed contract πŸ‘‰https://t.me/EthSecurity1/184
@EthSecurity1
πŸ‘3❀1
What is the relationship between variable scope and stack depth?

The relationship between variable scope and stack depth in Ethereum is:
Variables are allocated memory on the execution stack based on their scope.

Local variables declared inside a function have the smallest scope and deepest stack depth. They are allocated at the top of the stack and removed when the function ends.

outer or enclosing scopes have wider scope but shallower stack depth, as their variables are allocated lower down on the stack and persist even after inner scopes exit.

The contract's state variables declared at the top level have the widest scope across the entire contract but the shallowest/lowest stack depth, as they persist for the life of the contract.

The stack grows deeper as new scopes are entered via function calls or loops, and shrinks back as those scopes exit.

So deeper in the call stack means deeper stack depth and narrower variable scope that exists only within that run.

Shallower in the call stack equates to wider variable scope that persists outside the current run.

So in summary, narrower variable scope correlates with deeper stack allocation, while wider scope variables have more persistent but shallower storage on the stack. Scopes map directly to stack usage.

What is an access list transaction? access list transactions provide a way for senders to declaratively restrict contract storage access during tx execution for efficiency and privacy benefits. @EthSecurity1
1)If you deploy an empty Solidity contract, what bytecode will be present on the blockchain, if any?

If you deploy an empty Solidity contract with no functions or variables defined, the bytecode that will be deployed to the blockchain will be:

608060405234801561001057600080fd5b50610130806100206000396000f3fe6080604052600080fdfea264697066735822122082841ff4e4f1026f8824145257795b55a85b7b19d8689f3e455c52daa2c275e64736f6c634300060c0033

This is the default bytecode generated by the Solidity compiler for an empty contract with no code. It consists of:

608060405234801561001057600080fd5b50 - Standard EVM contract initialization code
610130806100206000396000f3fe - Empty contract creation code
6080604052600080fdfea26469706673582212... - Empty runtime bytecode 2)Rate manipulation in Balancer Boosted Pools https://medium.com/balancer-protocol/rate-manipulation-in-balancer-boosted-pools-technical-postmortem-53db4b642492
@EthSecurity1
πŸ‘7❀4🫑1
We beyond 3000 subscribers.
πŸ”₯6πŸŽ‰3⚑1❀1πŸ‘1🍾1πŸ¦„1
❌ Error: uint160(uint160 a * uint56 b)

Intermediate result of a * b can overflow uint160
When performing arithmetic operations on uint data types in Solidity, the result takes on the smallest uint type that can hold the result without overflowing.


a is of type uint160
b is of type uint56
Multiplying two uint values performs unchecked arithmetic

So when we multiply a * b:

The result could potentially be up to 160 + 56 = 216 bits wide.
βœ… Fix: uint160(uint256(uint160 a) * uint56 b)

Cast to uint256 first then multiply @EthSecurity1
❀4
TLDR: Attacker can break neutrality guarantees of Chainlink's VRF (verifiable random function). Chainlink confirmed CRITICAL severity and paid us $300K for the finding!πŸŽ‡

From the Chainlink blog: "malicious VRF subscription

Link to blog: https://blog.chain.link/smart-contract-research-case-study/
…
@EthSecurity1
πŸ”₯11
In this clip, ArthurB
points out that Optimism has not implemented fraud proofs at all https://twitter.com/Justin_Bons/status/1726395238749450722 @EthSecurity1