https://github.com/kyrers
https://github.com/kyrers

Subscribe to kyrers

Subscribe to kyrers
Share Dialog
Share Dialog
<100 subscribers
<100 subscribers
In this post, I will share my explanations for the Account section of the Capture The Ether challenges. There are plenty of solutions around the web - my goal was to solve the challenges locally, avoiding Etherscan when possible, and writing code locally.
You can find the code here.
Let’s begin.
To solve this challenge we need successfully authenticate as "smarx". The challenge gives us the conditions we need to meet:
Have a contract that returns "smarx" when the function name is called;
That same contract must be deployed at an address that ends with badc0de.
Step 1 is pretty simple, we just need a function called name that returns bytes32("smarx"). As for step 2, the EVM now has an opcode called CREATE2 that allows us to deploy a contract to a pre-computed address, provided we give it the contract bytecode and an uint256 salt to use. This is probably not what the author had in mind, but we should take advantage of improvements to the EVM.
To achieve step 2, take a look at this repo. It allows you to deploy a factory contract that will use the CREATE2 opcode to deploy our FuzzyIdentityHelper contract to an address that ends with badc0de, provided we send the correct salt along with the FuzzyIdentityHelper bytecode. This will allow us to solve the challenge. The repository contains instructions on how it should be done.
Our FuzzyIdentityHelper contract will have our challenge contract address hardcoded, although it's entirely possible to deploy bytecode with constructor params. It's just that this way is easier and does not require you to change the factory repo code.
So, to recap, here are the steps needed:
Deploy the factory contract to the Ropsten network;
Get our FuzzyIdentityHelper contract bytecode;
Determine the salt to use to deploy it to an address ending with badc0de. When introducing the needed information in the findHash.js script, remember that the deployerAddress is the address of the factory contract you deployed on step 1, not your own;
Use the factory contract to deploy our FuzzyIdentityHelper to the address determined in step 3;
Get the FuzzyIdentityHelper contract we just deployed;
Call the FuzzyIndentityHelper authenticate function;
Win;
This challenge isn't about hacking a smart contract. It's about understanding how signatures work. So, you should read the docs before solving this.
A couple of important things to know:
Ethereum signatures use the ECDSA algorithm. They consist of two integers r,s and v which Ethereum uses as a recover identifier;
What is actually signed is the serialized transaction hash, according to the current docs;
recoverPublicKey come with a prefix, such as 0x04 which means that both r and s follow;
Now, we will actually need some help from etherscan to begin with. The challenge contract contains the owner address, but to get its public key, we need a transaction signed by said address. If you search ropsten etherscan for the address you'll find an outgoing transaction, just what we need.
So, here's what's needed to solve this challenge:
Get the challenge owner outgoing transaction hash from etherscan;
Get the transaction object;
Reconstruct both the transaction data and signature objects;
Serialize the transaction data object;
Hash it;
Recover the public key using both the transaction data hash and the signature object;
Format it;
Get the challenge contract;
Authenticate yourself.
This challenge is actually harder than the scoring suggests. It implies having knowledge about how ECDSA works and how to exploit its vulnerabilities. The math behind this is beyond the scope of this explanation and, to be honest, I am not knowledgeable enough to explain it. Here's a stackoverflow discussion that should get you started.
As a basic overview, ECDSA signatures can be exploited with the goal of recovering private keys when the same nonce is used to sign two transactions. We've determined in the previous challenge that a signature object consists of r, s, and v values. If two transactions have the same r, it means the same nonce was used.
ECDSA signatures are determined using s = k⁻¹ (z + r * privateKey) (mod p), where: - k is the nonce; - z is the transaction hash; - r is the r value of the signature object. This is what must be common between two transactions for this exploit to work; - (mod p) is a congruence modulo where p is a constant.
First, we need to determine all the possible k values. Then, we determine the private key that matches those k's and find out which one matches our account to hack address. After that, it's a matter of connecting to it using our new wallet and authenticating ourselves.
Note that everybody solving this challenge uses the same account, so if you're authenticate transaction is failing, it may be because the account has no ETH. Check on ropsten on etherscan and send it some if needed.
So, here are the steps:
Find two transactions sent by the account to hack that have the same r for the signature. This is hard to find because there are so many, so I found out which one were by searching different solutions to this challenge and kept them in the accountTakeover.js script so you don't have to;
Calculate the s and z values needed to determine our possible k's;
Determine our possible k's and the matching private keys;
Determine which private key corresponds to the address we need;
Get the challenge contract and connect to it using the hacked account wallet;
Authenticate ourselves;
Again, I advise you to research how ECDSA allows for private key recovery if the same nonce is used twice before solving this. And if you understand the math, feel free to hit me up and explain it to me :)
In this post, I will share my explanations for the Account section of the Capture The Ether challenges. There are plenty of solutions around the web - my goal was to solve the challenges locally, avoiding Etherscan when possible, and writing code locally.
You can find the code here.
Let’s begin.
To solve this challenge we need successfully authenticate as "smarx". The challenge gives us the conditions we need to meet:
Have a contract that returns "smarx" when the function name is called;
That same contract must be deployed at an address that ends with badc0de.
Step 1 is pretty simple, we just need a function called name that returns bytes32("smarx"). As for step 2, the EVM now has an opcode called CREATE2 that allows us to deploy a contract to a pre-computed address, provided we give it the contract bytecode and an uint256 salt to use. This is probably not what the author had in mind, but we should take advantage of improvements to the EVM.
To achieve step 2, take a look at this repo. It allows you to deploy a factory contract that will use the CREATE2 opcode to deploy our FuzzyIdentityHelper contract to an address that ends with badc0de, provided we send the correct salt along with the FuzzyIdentityHelper bytecode. This will allow us to solve the challenge. The repository contains instructions on how it should be done.
Our FuzzyIdentityHelper contract will have our challenge contract address hardcoded, although it's entirely possible to deploy bytecode with constructor params. It's just that this way is easier and does not require you to change the factory repo code.
So, to recap, here are the steps needed:
Deploy the factory contract to the Ropsten network;
Get our FuzzyIdentityHelper contract bytecode;
Determine the salt to use to deploy it to an address ending with badc0de. When introducing the needed information in the findHash.js script, remember that the deployerAddress is the address of the factory contract you deployed on step 1, not your own;
Use the factory contract to deploy our FuzzyIdentityHelper to the address determined in step 3;
Get the FuzzyIdentityHelper contract we just deployed;
Call the FuzzyIndentityHelper authenticate function;
Win;
This challenge isn't about hacking a smart contract. It's about understanding how signatures work. So, you should read the docs before solving this.
A couple of important things to know:
Ethereum signatures use the ECDSA algorithm. They consist of two integers r,s and v which Ethereum uses as a recover identifier;
What is actually signed is the serialized transaction hash, according to the current docs;
recoverPublicKey come with a prefix, such as 0x04 which means that both r and s follow;
Now, we will actually need some help from etherscan to begin with. The challenge contract contains the owner address, but to get its public key, we need a transaction signed by said address. If you search ropsten etherscan for the address you'll find an outgoing transaction, just what we need.
So, here's what's needed to solve this challenge:
Get the challenge owner outgoing transaction hash from etherscan;
Get the transaction object;
Reconstruct both the transaction data and signature objects;
Serialize the transaction data object;
Hash it;
Recover the public key using both the transaction data hash and the signature object;
Format it;
Get the challenge contract;
Authenticate yourself.
This challenge is actually harder than the scoring suggests. It implies having knowledge about how ECDSA works and how to exploit its vulnerabilities. The math behind this is beyond the scope of this explanation and, to be honest, I am not knowledgeable enough to explain it. Here's a stackoverflow discussion that should get you started.
As a basic overview, ECDSA signatures can be exploited with the goal of recovering private keys when the same nonce is used to sign two transactions. We've determined in the previous challenge that a signature object consists of r, s, and v values. If two transactions have the same r, it means the same nonce was used.
ECDSA signatures are determined using s = k⁻¹ (z + r * privateKey) (mod p), where: - k is the nonce; - z is the transaction hash; - r is the r value of the signature object. This is what must be common between two transactions for this exploit to work; - (mod p) is a congruence modulo where p is a constant.
First, we need to determine all the possible k values. Then, we determine the private key that matches those k's and find out which one matches our account to hack address. After that, it's a matter of connecting to it using our new wallet and authenticating ourselves.
Note that everybody solving this challenge uses the same account, so if you're authenticate transaction is failing, it may be because the account has no ETH. Check on ropsten on etherscan and send it some if needed.
So, here are the steps:
Find two transactions sent by the account to hack that have the same r for the signature. This is hard to find because there are so many, so I found out which one were by searching different solutions to this challenge and kept them in the accountTakeover.js script so you don't have to;
Calculate the s and z values needed to determine our possible k's;
Determine our possible k's and the matching private keys;
Determine which private key corresponds to the address we need;
Get the challenge contract and connect to it using the hacked account wallet;
Authenticate ourselves;
Again, I advise you to research how ECDSA allows for private key recovery if the same nonce is used twice before solving this. And if you understand the math, feel free to hit me up and explain it to me :)
No activity yet