summaryrefslogtreecommitdiffstats
path: root/iv/orodja/napad/exploit.sh
blob: 9e2cafb72a677a29ac2db9a1c7d2ab2d22eaa4ce (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#!/bin/sh
if [ x$1 = x ]
then
cat >&2 <<EOF
No command. Usage: $0 <subcommand> [args ...] Subcommands:
	once <service> <exploit> [team=$GAME_NOP_TEAM] # runs exploit once
	loop <service> <exploit> # once per team per round, waits for next round
<exploit> is an executable file. Flags, grepped from stdout, are submitted.
It is called for every target with the following environment variables:
	TARGET_IP: target IP address (uses game_target_ip from config)
	TARGET_EXTRA: Flag IDs JSON object (uses game_flag_ids_url in config)
	FLAG_ID_<key>: Every JSON value from flag IDs individually
Example environment is therefore:
	TARGET_IP=1.1.1.1 TARGET_EXTRA='{"a": "1", "b": "2"}' FLAG_ID_a=1 FLAG_ID_b=2
In loop mode, exploit is first exec'd rapidly for still valid old rounds.
Max execution time is $EXPLOIT_TIMEOUT seconds (EXPLOIT_TIMEOUT in config)
Exploits are not run in parallel.
Make sure that your system time is set CORRECTLY TO THE SECOND, it's used
	to get the current round id. Check this on http://time.is
Configuration values are also available in environment of exploits.
<service> is the name of the service (used for getting flag IDs)
Set the following environment variables to alter behaviour:
	EXPLOIT_STDOUT=1: stdout of exploit will be printed to stderr/terminal
	EXPLOIT_LOOP_ONCE=1: exit after executing for all valid rounds instead of
		waiting for the next round. Only valid for loop subcommand.
	EXPLOIT_VERBOSE=1: print _every_ line executed by $0 (set -x)
	EXPLOIT_NOTPARALLEL=1: disable parallel even if parallel is available
$EXPLOIT_ADDITIONAL_HELP_TEXT
EOF
	exit 1
fi
[ ${EXPLOIT_VERBOSE:-false} = false ] || set -x
set -euo pipefail
current_round_id()
{ # BREAKS WHEN THERE ARE LEAP SECONDS DURING GAME
	startunix=`date +%s --utc --date $GAME_START`
	current=`date +%s --utc`
	echo $((($current-$startunix)/$ROUND_DURATION))
}
if [ ${ROUND_ID:-x} = x ]
then
	export ROUND_ID=`current_round_id`
fi
subcommand=$1
service=$2
exploit=$3
# tees stdout, collects flags, puts stdout to stderr, prints counts
# args: team
exploit_pipe()
{
	stdoutwhere=/dev/null
	[ ! ${EXPLOIT_STDOUT:-false} = false ] && stdoutwhere=/dev/stderr
	tee $stdoutwhere | { grep -Eo "$FLAG_REGEX_SEARCH" || :; } | while read -r line
	do
		echo $line $1 $ROUND_ID $service $exploit `whoami`@`hostname``pwd`
	done | { nc -N $SUBMISSION_HOST $SUBMISSION_PORT || return $((200+$?)); } | cut -d\  -f1,2 | sort | uniq -c | tr $'\n' ' ' | cat <(printf "team=%-2d round=%d: " $1 $ROUND_ID) /dev/stdin <(echo) >&2
}
# args: team round
get_flag_ids()
{
	set +e
	output_flagids=$(curl --fail-with-body --no-progress-meter "`game_flag_ids_url "$service" $1 $2`")
	curl_exit_code=$?
	set -e
	echo $output_flagids
	if [ ! $curl_exit_code -eq 0 ]
	then
		send_error $1 "round=$round failed to get flag ids: $output_flagids" >&2
		return 99
	fi
}
# args: team message
send_error()
{
	echo [$0] ERROR: team=$1: $2
	exploit_error_handler "$service" $1 `pwd` `whoami`@`hostname` $2
}
case $subcommand in
	once)
		target_team=$GAME_NOP_TEAM
		if [ $# -ge 4 ]
		then
			target_team=$4
		fi
		export TARGET_IP=`game_target_ip $target_team`
		export TARGET_EXTRA="`get_flag_ids $target_team $ROUND_ID`"
		source <(echo "$TARGET_EXTRA" | jq -r 'to_entries|map("export FLAG_ID_\(.key|sub("'"'"'";""))='"'"'\(.value|tostring|sub("'"'"'";"'"'\\\"'\\\"'"'"))'"'"'")|.[]')
		set +e
		timeout $EXPLOIT_TIMEOUT $exploit | exploit_pipe $target_team
		exit_code=$?
		set -e
		if [ $exit_code -gt 200 ]
		then
			send_error $target_team "submission netcat failed with $(($exit_code-200))"
			exit $exit_code
		fi
		if [ ! $exit_code -eq 0 ] && [ ! $exit_code -eq 124 ]
		then
			send_error $target_team "$exploit exited with $exit_code"
		fi
		if [ $exit_code -eq 124 ]
		then
			echo [$0] team=$target_team $exploit timed out >&2
		fi
		exit $exit_code
		;;
	loop)
		if parallel --version > /dev/null && [ ${EXPLOIT_NOTPARALLEL:-false} = false ]
		then
			commands_evaluator="parallel --color-failed"
			commands_output="/dev/stdout"
			have_parallel=true
			echo "[$0] using parallel executions (:" >&2
		else
			commands_evaluator="cat /dev/stdin"
			commands_output="/dev/null"
			have_parallel=false
			echo "[$0] parallel not found or disabled! zaporedno izvajanje ):" >&2
		fi
		round=$(($ROUND_ID-$GAME_VALID_ROUNDS))
		while :
		do
			for target_team in $GAME_TEAMS
			do
				cmd2exec="ROUND_ID=$round $0 once '$service' $exploit $target_team"
				if $have_parallel
				then
					echo $cmd2exec
				else
					eval $cmd2exec
				fi
			done | $commands_evaluator > $commands_output
			round=$(($round+1))
			we_slept=false
			while [ `current_round_id` -lt $round ]
			do # oh no we pollin thats ugly af, who cares we have
				if [ ! ${EXPLOIT_LOOP_ONCE:-false} = false ]
				then
					echo [$0] breaking due to EXPLOIT_LOOP_ONCE
					break
				fi
				we_slept=true
				sleep 1 # INFINITE CPU POWAH!
			done
			if $we_slept
			then # execute exploit at random time instead of at start
				sleep $(($RANDOM%$ROUND_DURATION/2))
			fi
		done
		;;
esac