CryoPod
3 minutes to read
We are given a Smart Contract called CryoPod.sol
:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/**
* @title CryoPod
* @dev A smart contract that allows each user to create and store a personal pod with a piece of
information.
* The information is stored permanently on the blockchain, and an event is emitted upon each
storage action.
*/
contract CryoPod {
mapping(address => string) private pods;
event PodStored(address indexed user, string data);
/**
* @dev Stores or updates the caller's pod with the provided data.
* @param _data The information to be stored in the user's pod.
*/
function storePod(string memory _data) external {
pods[msg.sender] = _data;
emit PodStored(msg.sender, _data);
}
}
And another Smart Contract called Setup.sol
:
pragma solidity ^0.8.0;
import { CryoPod } from "./CryoPod.sol";
contract Setup {
CryoPod public immutable TARGET;
bytes32 public flagHash = 0x0;
event DeployedTarget(address at);
constructor() payable {
TARGET = new CryoPod();
emit DeployedTarget(address(TARGET));
}
function isSolved(string calldata flag) public view returns (bool) {
return keccak256(abi.encodePacked(flag)) == flagHash;
}
}
There is also a remote instance where we will get connection parameters to the Blockchain:
$ nc 83.136.250.185 45551
1 - Get connection informations
2 - Restart Instance
3 - Get flag
Select action (enter number): 1
[*] No running node found. Launching new node...
Player Private Key : 29297604e2a672bd0178ac2b8672c14a1419236bcc7316c99ee9888b518dd5bb
Player Address : 0xD0b65173e2984c2EF011F7A6cA406f7723A6d7b4
Target contract : 0x44B189e4bA6DB658a8207B2432c4a6FcfD2555bf
Setup contract : 0xBF037deD3881Cb3f0ccC797E00E3F34c0FF79355
Setup environment
First of all, let’s save the connection parameters as shell variables:
$ PRIVATE_KEY='0x29297604e2a672bd0178ac2b8672c14a1419236bcc7316c99ee9888b518dd5bb'
$ ADDRESS='0xD0b65173e2984c2EF011F7A6cA406f7723A6d7b4'
$ ADDRESS_TARGET='0x44B189e4bA6DB658a8207B2432c4a6FcfD2555bf'
$ ADDRESS_SETUP='0xBF037deD3881Cb3f0ccC797E00E3F34c0FF79355'
$ export ETH_RPC_URL='http://83.136.250.185:44604'
Source code analysis
Both Smart Contracts are so simple, yet there is actually nothing to do with them. Notice that CryoPod
has a single function to store string
values in a mapping
called pods
:
function storePod(string memory _data) external {
pods[msg.sender] = _data;
emit PodStored(msg.sender, _data);
}
Once the value is set, a PodStored
event is emitted showing the user and the value stored.
On the other hand, in order to solve the challenge, we need to pass isSolved
:
function isSolved(string calldata flag) public view returns (bool) {
return keccak256(abi.encodePacked(flag)) == flagHash;
}
This is weird since flagHash
is initialized to 0x0
, and we can’t find a preimage for keccak256
hash function.
Analyzing the logs
The only thing we can do is check for the events emitted by the Smart Contracts. Fortunately, we can do it with cast logs
:
$ cast logs
- address: 0xa09ab4ac0D70fEB0f7577913183D440768211C44
blockHash: 0x38d2fe8a348b61e6ce8d4f20c4c4ef3bc051e65e5c99ac3ccdad0c35b78c0d8f
blockNumber: 1
data: 0x00000000000000000000000030dd90e431771a5b2d6db874e5bd397c467b5634
logIndex: 0
removed: false
topics: [
0xc26ec5464cc58ea5f3597f1daab5d82585655e1bfd634b0a94fdd5ab63740dbf
]
transactionHash: 0x7d309a2ef9d98df82d53dfd0178c99a01dc6de9b5be9309c4a6582872bb91921
transactionIndex: 0
- address: 0x30dd90e431771a5B2D6dB874E5bD397c467B5634
blockHash: 0x6a56d5533425347ee0a3c95ce610c9e80342fac49d81b8f1f3d8deb669c6e131
blockNumber: 2
data: 0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000003d72a2a5065616e75742042757474657220616e64205069636b6c652053616e64776963682a2a3a203220736c69636573206f66206272656164202877686974652c2077686f6c652077686561742c206f7220736f7572646f756768292c2032207461626c6573706f6f6e73206f66205065616e7574204275747465722c20342d362064696c6c207069636b6c6520736c696365732c20612064617368206f6620686f742073617563652c206c6574747563652c206f7220686f6e657920286f7074696f6e616c292e205072657061726174696f6e3a203129204170706c79207065616e757420627574746572206576656e6c79206f6e206f6e652073696465206f66206561636820627265616420736c6963652e203229204c6179657220746865207069636b6c6520736c69636573206f6e206f6e65207065616e7574206275747465722d636f766572656420627265616420736c6963652e20332920416464206120737072696e6b6c65206f662073616c742c20686f742073617563652c206f72206578747261206c6179657273206c696b65206c6574747563652e20342920506c61636520746865207365636f6e6420627265616420736c696365206f6e20746f702c207065616e757420627574746572207369646520646f776e2e2050726573732067656e746c792e2035292043757420646961676f6e616c6c7920666f72206561736965722068616e646c696e6720616e6420656e6a6f792e204465736372697074696f6e3a20456d6261726b206f6e20616e20756e65787065637465642067617374726f6e6f6d6963206a6f75726e65792077697468206f7572205065616e7574204275747465722026205069636b6c652053796d70686f6e792c2061206861726d6f6e696f757320667573696f6e206f6620636f6e7472617374696e6720666c61766f727320616e642074657874757265732074686174207265646566696e652074686520626f756e646172696573206f6620636f6e74656d706f726172792063756973696e652e2054686973206176616e742d6761726465206372656174696f6e206d6172726965732074686520726963682c2076656c76657479206e6f746573206f66206172746973616e616c20637265616d79207065616e7574206275747465722077697468207468652063726973702c2074616e6779207a657374206f662068616e642d73656c65637465642064696c6c207069636b6c65732c206d65746963756c6f75736c79206c617965726564206265747765656e20736c69636573206f662066726573686c792062616b65642c2073746f6e652d67726f756e6420736f7572646f7567682062726561642e000000000000000000
logIndex: 0
removed: false
topics: [
0x8756f21c4a2b6b179da2cf2bfd156724e3ae8c1f5fc7d3e25d9483733e5d9221
0x0000000000000000000000007687cb40c834da6f0feb151ab9636c0c0574aef0
]
transactionHash: 0x528f0c35a7b609862ecde4f1933d4369c145dffa310475f4810a9098cd9d8dc4
transactionIndex: 0
...
Here we have a lot of events. We must guess that someone is storing the flag in pods
, so we will be able to retrieve it by inspecting the logs.
Let’s take the some known characters of the flag in hexadecimal format in order to filter the events:
$ echo -n 'HTB{}' | xxd -p
4854427b7d
$ cast logs | grep 4854427b
data: 0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000184854427b68336c6c305f636834316e5f736330757433727d0000000000000000
$ cast logs | grep -oE '4854427b.*7d'
4854427b68336c6c305f636834316e5f736330757433727d
Flag
At this point, we can simply decode it and get the flag:
$ echo 4854427b68336c6c305f636834316e5f736330757433727d | xxd -r -p
HTB{h3ll0_ch41n_sc0ut3r}
There’s no need to use the isSolved
function and check it in the remote instance.