Skip to content

Commit

Permalink
Merge pull request #432 from commjoen/challenge2627
Browse files Browse the repository at this point in the history
Challenge 26 & 27
  • Loading branch information
commjoen authored Sep 29, 2022

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
2 parents 9e8e6ab + c619408 commit e8db22d
Showing 12 changed files with 272 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package org.owasp.wrongsecrets.challenges.docker;


import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.util.encoders.Base64;
import org.owasp.wrongsecrets.RuntimeEnvironment;
import org.owasp.wrongsecrets.ScoreCard;
import org.owasp.wrongsecrets.challenges.Challenge;
import org.owasp.wrongsecrets.challenges.ChallengeTechnology;
import org.owasp.wrongsecrets.challenges.Spoiler;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Value;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.spec.AlgorithmParameterSpec;
import java.util.List;

@Slf4j
@Component
@Order(26)
public class Challenge26 extends Challenge {
private final String cipherText;

public Challenge26(ScoreCard scoreCard, @Value("${challenge26ciphertext}") String cipherText) {
super(scoreCard);
this.cipherText = cipherText;
}

@Override
public boolean canRunInCTFMode() {
return true;
}

@Override
public Spoiler spoiler() {
return new Spoiler(quickDecrypt(cipherText));
}

@Override
public boolean answerCorrect(String answer) {
String correctString = quickDecrypt(cipherText);
return answer.equals(correctString);
}

@Override
public List<RuntimeEnvironment.Environment> supportedRuntimeEnvironments() {
return List.of(RuntimeEnvironment.Environment.DOCKER);
}

@Override
public int difficulty() {
return 2;
}

@Override
public String getTech() {
return ChallengeTechnology.Tech.WEB3.id;
}

@Override
public boolean isLimittedWhenOnlineHosted() {
return false;
}

private String quickDecrypt(String cipherText) {
try {
final Cipher decryptor = Cipher.getInstance("AES/GCM/NoPadding");
SecretKey decryptKey = new SecretKeySpec("thiszthekeytoday".getBytes(StandardCharsets.UTF_8), "AES");
AlgorithmParameterSpec gcmIv = new GCMParameterSpec(128, Base64.decode(cipherText), 0, 12);
decryptor.init(Cipher.DECRYPT_MODE, decryptKey, gcmIv);
return new String(decryptor.doFinal(Base64.decode(cipherText), 12, Base64.decode(cipherText).length - 12));
} catch (Exception e) {
log.warn("Exception with Challenge 26", e);
return "";
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package org.owasp.wrongsecrets.challenges.docker;


import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.util.encoders.Base64;
import org.owasp.wrongsecrets.RuntimeEnvironment;
import org.owasp.wrongsecrets.ScoreCard;
import org.owasp.wrongsecrets.challenges.Challenge;
import org.owasp.wrongsecrets.challenges.ChallengeTechnology;
import org.owasp.wrongsecrets.challenges.Spoiler;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Value;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.spec.AlgorithmParameterSpec;
import java.util.List;

@Slf4j
@Component
@Order(26)
public class Challenge27 extends Challenge {
private final String cipherText;

public Challenge27(ScoreCard scoreCard, @Value("${challenge27ciphertext}") String cipherText) {
super(scoreCard);
this.cipherText = cipherText;
}

@Override
public boolean canRunInCTFMode() {
return true;
}

@Override
public Spoiler spoiler() {
return new Spoiler(quickDecrypt(cipherText));
}

@Override
public boolean answerCorrect(String answer) {
String correctString = quickDecrypt(cipherText);
return answer.equals(correctString);
}

@Override
public List<RuntimeEnvironment.Environment> supportedRuntimeEnvironments() {
return List.of(RuntimeEnvironment.Environment.DOCKER);
}

@Override
public int difficulty() {
return 2;
}

@Override
public String getTech() {
return ChallengeTechnology.Tech.WEB3.id;
}

@Override
public boolean isLimittedWhenOnlineHosted() {
return false;
}

private String quickDecrypt(String cipherText) {
try {
final Cipher decryptor = Cipher.getInstance("AES/GCM/NoPadding");
SecretKey decryptKey = new SecretKeySpec("thiszthekeytoday".getBytes(StandardCharsets.UTF_8), "AES");
AlgorithmParameterSpec gcmIv = new GCMParameterSpec(128, Base64.decode(cipherText), 0, 12);
decryptor.init(Cipher.DECRYPT_MODE, decryptKey, gcmIv);
return new String(decryptor.doFinal(Base64.decode(cipherText), 12, Base64.decode(cipherText).length - 12));
} catch (Exception e) {
log.warn("Exception with Challenge 27", e);
return "";
}
}
}
2 changes: 2 additions & 0 deletions src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -45,6 +45,8 @@ keepasspath=/var/tmp/helpers/alibabacreds.kdbx
canarytokenURLs=http://canarytokens.com/terms/about/s7cfbdakys13246ewd8ivuvku/post.jsp,http://canarytokens.com/terms/about/y0all60b627gzp19ahqh7rl6j/post.jsp
challenge15ciphertext=qcyRgfXSh0HUKsW/Xb5LnuWt9DgU8tQJfluR66UDDlmMgVWCGEwk1qxKCi4ZvzDwM38xP3nRFqO4SZEgqp8Ul8Ej/lNDbQCgBuszSILVSV6D9eojOMl6zTcNgzUmjW2K3dJKN9LqXOLYezEpEN2gUaYqPu2nVqmUptKTmXGwAnmQH1TIl2MUueRuXpRKe72IMzKenxZHKRsNFp+ebQebS3qzP+Q=
challenge25ciphertext=dQMhBe8oLxIdGLcxPanDLS++srED/x05P+Ph9PFZKlL2K42vXi7Vtbh3/N90sGT087W7ARURZg==
challenge26ciphertext=gbU5thfgy8nwzF/qc1Pq59PrJzLB+bfAdTOrx969JZx1CKeG4Sq7v1uUpzyCH/Fo8W8ghdBJJrQORw==
challenge27ciphertext=gYPQPfb0TUgWK630tHCWGwwME6IWtPWA51eU0Qpb9H7/lMlZPdLGZWmYE83YmEDmaEvFr2hX
management.endpoint.health.probes.enabled=true
management.health.livenessState.enabled=true
management.health.readinessState.enabled=true
27 changes: 14 additions & 13 deletions src/main/resources/explanations/challenge25_hint.adoc
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
You can solve this challenge by the following steps:

Option 1:
1. Look under the contract creation transaction on https://goerli.etherscan.io/tx/0x497b71a1fd4c57509bfecc2114ec649387fe669c23a3a7e97961f389444d9561[Etherscan]
2. Go to state and look at storage.
1. Look at the storage in Etherscan:
- Look under the contract creation transaction on https://goerli.etherscan.io/tx/0x497b71a1fd4c57509bfecc2114ec649387fe669c23a3a7e97961f389444d9561[Etherscan]
- Go to state and look at storage.
Option 2:
1. Look under the contract creation transaction on https://goerli.etherscan.io/tx/0x497b71a1fd4c57509bfecc2114ec649387fe669c23a3a7e97961f389444d9561[Etherscan]
2. Have a look at the input data.
2. Look at the input data in Etherscan:
- Look under the contract creation transaction on https://goerli.etherscan.io/tx/0x497b71a1fd4c57509bfecc2114ec649387fe669c23a3a7e97961f389444d9561[Etherscan]
- Have a look at the input data.
Option 3:
1. Create an Infura key at https://infura.io/[Infura].
2. Write a simple script with web3js to call the view function on the public string "secret"
3. Use Infura with web3js at Infura:
- Create an Infura key at https://infura.io/[Infura].
- Write a simple script with web3js to call the view function on the public string "secret"
Option 2:
1. Create an Infura key at https://infura.io/[Infura].
2. Read the storage at position 0 for the contract like:
curl https://goerli.infura.io/v3/${<your-infura-key>} \
4. Do a storage request at Infura:
- Create an Infura key at https://infura.io/[Infura].
- Read the storage at position 0 for the contract like:
curl https://goerli.infura.io/v3/${<your-infura-key>} \
-X POST \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0", "method": "eth_getStorageAt", "params": ["0x8b72f7cbAD50620c46219ad676Ad9d3a5A273587", "0x0", "latest"], "id": 1}'
5 changes: 5 additions & 0 deletions src/main/resources/explanations/challenge26.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
=== Secrets in smart contracts part 2

Our smart contract developer realized he wrote a secret to the chain and went back and wrote over it.

In this challenge, you need to read the variable named secret from the contract `0xCe793D588cd1Ee091290b4A1aE1D586B2a748eB4` on the Goerli EVM Testnet as it was before it got changed.
14 changes: 14 additions & 0 deletions src/main/resources/explanations/challenge26_hint.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
You can find the previous state one of two ways.

1. Find the previous block via a request to https://infura.io/[Infura]:
- Find the block number for any block after the contract was created and before it was updated.
- Search for the storage state of the contract for that block. The below command is an example vs the infura API:
curl https://goerli.infura.io/v3/${your-infura-key} \
-X POST \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0", "method": "eth_getStorageAt", "params": ["${contract address}", "0x0", "${blocknumber}"], "id": 1}'
2. Look at the contract creation on https://etherscan.io/[Etherscan]:
- Look under the contract creation transaction on etherscan
- Go to state and look at storage
5 changes: 5 additions & 0 deletions src/main/resources/explanations/challenge26_reason.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
*Why overwriting secrets on the blockchain does not get rid of them*

The state of the chain can be verified for any point in time by executing the state updates up until a certain block.

Updating the state of the chain does not remove previous changes to state.
5 changes: 5 additions & 0 deletions src/main/resources/explanations/challenge27.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
=== Secrets in smart contracts part 3

Our smart contract developer got somewhat smarter and only stored a hashed secret in his contract. He then checks a input data vs that hash to validate whether or not a transaction returns true or false. He is sure that since the secret is never stored in the internal state of the contract, that it can't be found.

In this challenge, you need to find the correct secret that has the guess method from the contract `0x8318d477f4BCae5a80BEA22E3c040cf8BaaFFe8B` on the Goerli EVM Testnet return true.
7 changes: 7 additions & 0 deletions src/main/resources/explanations/challenge27_hint.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
You can find the correct input to the guess method by:

1. Comparing hashes:
- Look up the contract on the https://etherscan.io/[Etherscan] explorer.
- Pull the hash from the contract storage.
- Go through the transactions and then opening the inputs tab and decoding them as UTF-8.
- Compare the hashes of the inputs from the transactions with the stored hash value.
4 changes: 4 additions & 0 deletions src/main/resources/explanations/challenge27_reason.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*Why sending secrets as inputs to smart contracts is a bad idea even if they aren't stored*

Inputs to all transactions to contracts, like the state of internal storage of contracts on the chain are stored forever and are easy to query.
Inputs to transactions are even visible before those transactions are accepted. This can lead to front-running by a 3rd party who has access to the pool of transactions and can send a transaction (with higher gas) that benefits from the known transaction running after it.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.owasp.wrongsecrets.challenges.docker;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.owasp.wrongsecrets.ScoreCard;

@ExtendWith(MockitoExtension.class)
class Challenge26Test {

@Mock
private ScoreCard scoreCard;

@Test
void rightAnswerShouldSolveChallenge() {
var challenge = new Challenge26(scoreCard, "gbU5thfgy8nwzF/qc1Pq59PrJzLB+bfAdTOrx969JZx1CKeG4Sq7v1uUpzyCH/Fo8W8ghdBJJrQORw==");
Assertions.assertThat(challenge.solved(challenge.spoiler().solution())).isTrue();
Mockito.verify(scoreCard).completeChallenge(challenge);
}



}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.owasp.wrongsecrets.challenges.docker;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.owasp.wrongsecrets.ScoreCard;

@ExtendWith(MockitoExtension.class)
class Challenge27Test {

@Mock
private ScoreCard scoreCard;

@Test
void rightAnswerShouldSolveChallenge() {
var challenge = new Challenge27(scoreCard, "gYPQPfb0TUgWK630tHCWGwwME6IWtPWA51eU0Qpb9H7/lMlZPdLGZWmYE83YmEDmaEvFr2hX");
Assertions.assertThat(challenge.solved(challenge.spoiler().solution())).isTrue();
Mockito.verify(scoreCard).completeChallenge(challenge);
}



}

0 comments on commit e8db22d

Please sign in to comment.