commit
12f9c9bb93
22 changed files with 497 additions and 0 deletions
@ -0,0 +1,2 @@ |
||||
.*.swp |
||||
.*.swo |
@ -0,0 +1,55 @@ |
||||
FROM debian:buster |
||||
|
||||
ARG USERNAME |
||||
ARG HOST_IP |
||||
ARG SLBR_PORT |
||||
ARG INFO_PORT |
||||
ARG LOG_PORT |
||||
ARG SSHD_PORT |
||||
|
||||
RUN (test -n "$USERNAME" || (echo "USERNAME not set" && false)) \ |
||||
&& (test -n "$SLBR_PORT" || (echo "SLBR_PORT not set" && false)) \ |
||||
&& (test -n "$INFO_PORT" || (echo "INFO_PORT not set" && false)) \ |
||||
&& (test -n "$LOG_PORT" || (echo "LOG_PORT not set" && false)) \ |
||||
&& (test -n "$HOST_IP" || (echo "HOST_IP not set" && false)) |
||||
|
||||
COPY --chown=root ./suicidebash.bashrc /etc/bash.bashrc |
||||
COPY --chown=root ./slbr.env /etc |
||||
COPY --chown=root ./package.list /package.list |
||||
COPY --chown=root ./insults.txt /insults.txt |
||||
|
||||
COPY ./bin/progress /usr/local/bin/ |
||||
COPY ./bin/submit /usr/local/bin/ |
||||
COPY ./banner /etc/motd |
||||
COPY ./pubkey /pubkey |
||||
|
||||
RUN apt remove bash-completion \ |
||||
&& rm -rf /usr/share/bash-completion |
||||
|
||||
RUN apt update \ |
||||
&& apt install -y $(cat /package.list) \ |
||||
&& rm /package.list |
||||
|
||||
RUN sed -i "s/{{ HOST_IP }}/$HOST_IP/g" /etc/bash.bashrc /usr/local/bin/progress /usr/local/bin/submit \ |
||||
&& sed -i "s/{{ SLBR_PORT }}/$SLBR_PORT/g" /etc/bash.bashrc /usr/local/bin/progress /usr/local/bin/submit \ |
||||
&& sed -i "s/{{ INFO_PORT }}/$INFO_PORT/g" /etc/bash.bashrc /usr/local/bin/progress /usr/local/bin/submit \ |
||||
&& sed -i "s/{{ LOG_PORT }}/$LOG_PORT/g" /etc/bash.bashrc /usr/local/bin/progress /usr/local/bin/submit \ |
||||
&& mkdir /home/$USERNAME \ |
||||
&& mkdir /run/sshd \ |
||||
&& mkdir /home/$USERNAME/.ssh \ |
||||
&& cat /pubkey > /home/$USERNAME/.ssh/authorized_keys \ |
||||
&& rm /pubkey \ |
||||
&& echo "PasswordAuthentication no" >> /etc/ssh/sshd_config \ |
||||
&& echo "Port $SSHD_PORT" >> /etc/ssh/sshd_config |
||||
|
||||
COPY ./clues /home/$USERNAME |
||||
COPY ./rules.md /home/$USERNAME |
||||
|
||||
RUN useradd $USERNAME -d /home/$USERNAME \ |
||||
&& chown -R $USERNAME:$USERNAME /home/$USERNAME \ |
||||
&& chmod -R +x /usr/local/bin/ \ |
||||
&& chsh $USERNAME -s /bin/bash |
||||
|
||||
#USER $USERNAME |
||||
|
||||
CMD ["/usr/sbin/sshd", "-D"] |
@ -0,0 +1,13 @@ |
||||
Welcome to: |
||||
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ |
||||
░█▀▀░█░█░▀█▀░█▀▀░▀█▀░█▀▄░█▀▀░░░█░░░▀█▀░█▀█░█░█░█░█░░ |
||||
░▀▀█░█░█░░█░░█░░░░█░░█░█░█▀▀░░░█░░░░█░░█░█░█░█░▄▀▄░░ |
||||
░▀▀▀░▀▀▀░▀▀▀░▀▀▀░▀▀▀░▀▀░░▀▀▀░░░▀▀▀░▀▀▀░▀░▀░▀▀▀░▀░▀░░ |
||||
░█▀▄░█▀█░▀█▀░▀█▀░█░░░█▀▀░░░█▀▄░█▀█░█░█░█▀█░█░░░█▀▀░░ |
||||
░█▀▄░█▀█░░█░░░█░░█░░░█▀▀░░░█▀▄░█░█░░█░░█▀█░█░░░█▀▀░░ |
||||
░▀▀░░▀░▀░░▀░░░▀░░▀▀▀░▀▀▀░░░▀░▀░▀▀▀░░▀░░▀░▀░▀▀▀░▀▀▀░░ |
||||
░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ |
||||
|
||||
For rules, `cat ~/rules.md` |
||||
To submit your solution for a challenge, run `submit <solution number> "<your solution>"` |
||||
To see your current progress, run `progress` |
@ -0,0 +1,20 @@ |
||||
#!/bin/bash |
||||
scoreboard="$(nc -q0 -d {{ HOST_IP }} {{ INFO_PORT }})" |
||||
my_ip="$(ip addr | grep 'scope global eth0' | cut -f6 -d ' ')" |
||||
total_challenges="$(echo "$scoreboard" | head -n1)" |
||||
completed_challenges="$( |
||||
echo "$scoreboard" \ |
||||
| grep "$my_ip" \ |
||||
| cut -f2- -d ' ' \ |
||||
| tr -d ' ' \ |
||||
| tr ',' '\n' \ |
||||
| sort \ |
||||
| tr '\n' ',' \ |
||||
| sed 's/,/, /g' \ |
||||
| sed 's/^, //' \ |
||||
| sed 's/, $//' |
||||
)" |
||||
num_completed="$(echo $completed_challenges | grep -oE '[0-9]' | wc -l)" |
||||
echo "There are $total_challenges total challenges" |
||||
echo "You have completed the following challenges: $completed_challenges" |
||||
echo "You have completed $num_completed of the $total_challenges total challenges" |
@ -0,0 +1,58 @@ |
||||
#!/bin/bash |
||||
|
||||
help_text=" |
||||
submit.sh - submit an slbr solution to be verified |
||||
usage: ./submit <challenge number> <solution> |
||||
for example: ./submit 3 \"this is the solution for challenge 3\" |
||||
" |
||||
|
||||
challenge_no="$1" |
||||
submitted_solution="$2" |
||||
|
||||
[ -z "$submitted_solution" ] && echo "$help_text" && exit |
||||
|
||||
echo "Submitting \"$submitted_solution\" as the solution to challenge #$challenge_no..." |
||||
|
||||
my_ip="$(ip addr | grep 'scope global eth0' | cut -f6 -d ' ')" |
||||
|
||||
scoreboard="$(nc -q0 -d {{ HOST_IP }} {{ INFO_PORT }})" |
||||
prev_score="$( |
||||
echo "$scoreboard" \ |
||||
| grep "$my_ip" |
||||
)" |
||||
max_score="$(echo "$scoreboard" | head -n1)" |
||||
current_score="" |
||||
|
||||
echo "SOLUTION $challenge_no $submitted_solution" \ |
||||
| nc -q0 {{ HOST_IP }} {{ SLBR_PORT }} |
||||
|
||||
# give the server ample time to process the request |
||||
echo "Verifying..." |
||||
sleep 5 |
||||
|
||||
# we need to request the scoreboard twice here for the score to properly update |
||||
nc -q0 -d {{ HOST_IP }} {{ INFO_PORT }} > /dev/null |
||||
current_score="$( |
||||
nc -q0 -d {{ HOST_IP }} {{ INFO_PORT }} \ |
||||
| grep "$my_ip" |
||||
)" |
||||
|
||||
if [ "$prev_score" != "$current_score" ] |
||||
then |
||||
echo "w00t! You got the right answer!!!" |
||||
num_correct="$( |
||||
echo $current_score \ |
||||
| grep -oE '[0-9],' \ |
||||
| wc -l |
||||
)" |
||||
echo "$num_correct correct answers so far" |
||||
if [ "$num_correct" = "$max_score" ] |
||||
then |
||||
printf "\e[0;92]" |
||||
echo "Hey! thats all $max_score! that means YOU WIN!" |
||||
echo "!!!!!!!CONGRATULATIONS!!!!!!!" |
||||
printf "\e[0;91m THIS CONTAINER WILL NOW SELF DESTRUCT\e[0m\n" |
||||
fi |
||||
else |
||||
echo "|X_x| Your answer was rejected!!!." |
||||
fi |
@ -0,0 +1 @@ |
||||
ubj qb lbh fcryy ahzoref? |
@ -0,0 +1,12 @@ |
||||
Oops, looks like you misspelt something >:) |
||||
Where did you learn to type? |
||||
Are you on drugs? |
||||
My pet ferret can type better than you! |
||||
You type like i drive. |
||||
Do you think like you type? |
||||
stty: unknown mode: doofus |
||||
Maybe if you used more than just two fingers... |
||||
Have you considered trying to match wits with a rutabaga? |
||||
I've seen penguins that can type better than that. |
||||
Game over, man, game over. |
||||
https://ddg.gg/?q=free+online+typing+lessons |
@ -0,0 +1,9 @@ |
||||
netcat-openbsd |
||||
emacs-nox |
||||
curl |
||||
nano |
||||
vim |
||||
tmux |
||||
man |
||||
xxd |
||||
openssh-server |
@ -0,0 +1,33 @@ |
||||
# PLAYING THE GAME |
||||
- Each game has a series of challenges to complete, users are provided with a |
||||
bash shell and a folder of clues. |
||||
- The challenges are numbered 1-X. |
||||
- Users must submit the solutions to each challenge to the admin, the first |
||||
user to submit correct solutions to each challenge will win the game. |
||||
- If at any point the user enters an invalid shell command, they will be |
||||
eliminated from the game. |
||||
- If you think you have the solution for a challenge, submit your answer using |
||||
the `submit` command in the format `submit <challenge #> <solution>` |
||||
- For example, you would run `submit 3 "the color pink"` to submit "the color |
||||
pink" as your solution for challenge #3 (quotes would not be included, and |
||||
are subject to normal bash escaping rules) |
||||
- At any time, you can run the `progress` command to see your progress in |
||||
completing the challenges |
||||
|
||||
# DA RULES |
||||
- You may use the internet |
||||
- You may write scripts |
||||
- You may not use sh, you must use bash |
||||
- You may not install more packages |
||||
- You may not attempt to obtain root access |
||||
- You may not communicate with other players |
||||
- You may not interact or tamper with the containers or environments of other |
||||
users |
||||
- You may not interact or tamper with your own container |
||||
- You may not break out of your container and/or access the host system in any |
||||
way |
||||
- You may not nullify or remove the "Suicide Linux" mechanic in any way |
||||
- You may use any package already installed on the system provided its use does |
||||
not break any of the other rules |
||||
- For the love of god don't build a bot that just brute forces random strings |
||||
to try and get a correct answer |
@ -0,0 +1,13 @@ |
||||
handler_command='command_not_found_handle is a function |
||||
command_not_found_handle () |
||||
{ |
||||
echo "DEAD" | nc illegaldrugs.net 1337 & printf "\e[0;94m%s\e[0m\n" "$(shuf -n1 /insults.txt)"; |
||||
printf "\e[0;91m\e[1mYOU HAVE BEEN ELIMINATED!\e[0m\n" |
||||
}' |
||||
# we can use the output format of `type` to determine if we are in a bash shell |
||||
# or not, as well an ensuring the instant death mechanic is enabled |
||||
if [ "$(type command_not_found_handle)" != "$handler_command" ] |
||||
then |
||||
echo "no." |
||||
exit |
||||
fi |
@ -0,0 +1,24 @@ |
||||
# If not running interactively, don't do anything |
||||
[ -z "$PS1" ] && return |
||||
|
||||
# set a fancy prompt (non-color, overwrite the one in /etc/profile) |
||||
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ ' |
||||
|
||||
# SLBR modifications |
||||
|
||||
bind -u complete |
||||
|
||||
function command_not_found_handle { |
||||
echo "DEAD" | nc {{ HOST_IP }} {{ SLBR_PORT }} & |
||||
printf "\e[0;94m%s\e[0m\n" "$(shuf -n1 /insults.txt)" |
||||
printf "\e[0;91m\e[1mYOU HAVE BEEN ELIMINATED!\e[0m\n" |
||||
} |
||||
|
||||
function log_command { |
||||
echo "$(history 1)" | nc -q0 {{ HOST_IP }} {{ LOG_PORT }} |
||||
} |
||||
|
||||
readonly -f command_not_found_handle |
||||
readonly -f log_command |
||||
readonly PROMPT_COMMAND=log_command |
||||
readonly ENV="/etc/slbr.env"; export ENV |
@ -0,0 +1,59 @@ |
||||
username="$1" |
||||
pubkey_path="$2" |
||||
slbr_port="1337" |
||||
info_port="1338" |
||||
log_port="1339" |
||||
user_sshd_port="5000" |
||||
container_id="" |
||||
container_ip="" |
||||
host_ip="" |
||||
|
||||
[ -z "$1" ] && echo "please provide a username." && exit |
||||
[ -z "$2" ] && echo "please provide a pubkey file." && exit |
||||
|
||||
get_user_sshd_port() { |
||||
listening_ports="$(ss -tuln \ |
||||
| awk '{print $5}' \ |
||||
| rev \ |
||||
| cut -f1 -d ":" \ |
||||
| rev |
||||
)" |
||||
if echo "$listening_ports" | grep -q "$user_sshd_port" |
||||
then |
||||
user_sshd_port="$(( user_sshd_port + 1 ))" |
||||
get_user_sshd_port |
||||
else |
||||
echo "$user_sshd_port" |
||||
fi |
||||
|
||||
} |
||||
get_user_sshd_port |
||||
|
||||
cp "$pubkey_path" image/pubkey |
||||
host_ip="$( |
||||
ip -br -4 addr \ |
||||
| grep eth0 \ |
||||
| awk '{print $3}' \ |
||||
| cut -f 1 -d '/' |
||||
)" |
||||
|
||||
docker build \ |
||||
-t slbr:$username \ |
||||
--build-arg USERNAME=$username \ |
||||
--build-arg HOST_IP=$host_ip \ |
||||
--build-arg SLBR_PORT=$slbr_port \ |
||||
--build-arg INFO_PORT=$info_port \ |
||||
--build-arg LOG_PORT=$log_port \ |
||||
--build-arg SSHD_PORT=$user_sshd_port \ |
||||
--label "SLBR User Container" \ |
||||
./image |
||||
|
||||
rm image/pubkey |
||||
echo "Starting container..." |
||||
container_id="$(docker run -p $user_sshd_port:$user_sshd_port -h slbr -d "slbr:$username")" |
||||
container_ip="$( |
||||
docker container inspect "$container_id" \ |
||||
| jq '.[0].NetworkSettings.Networks.bridge.IPAddress' |
||||
)" |
||||
echo "Done!" |
||||
echo "connect using: ssh $username@$host_ip -p $user_sshd_port" |
@ -0,0 +1,51 @@ |
||||
# SUICIDE LINUX BATTLE ROYALE |
||||
It's back, baby |
||||
|
||||
coming soon! check #slbr on irc for updates! |
||||
|
||||
typo? you're out. |
||||
|
||||
when you play, you'll be dropped in a fresh vm. on the way to your goal, any |
||||
mistyped command will delete your vm and you'll be eliminated. |
||||
|
||||
contact ~ben or sose on tilde.chat (in the #slbr channel) to sign up. |
||||
|
||||
## How it works |
||||
- Each game has a series of challenges to complete, users are provided with a |
||||
bash shell and a folder of clues. |
||||
- The challenges are numbered 1-X. |
||||
- Users must submit the solutions to each challenge to the admin, the first |
||||
user to submit correct solutions to each challenge will win the game. |
||||
- If at any point the user enters an invalid shell command, they will be |
||||
eliminated from the game. |
||||
|
||||
## Configuration |
||||
- Configuring a new set of challenges is as simple as editing the |
||||
`solutions.txt` file with their solutions, and providing new clues in the |
||||
`./image/clues` folder. |
||||
- In the `solutions.txt` file, the line number of each solution corresponds to |
||||
the challenge it is the solution for. Solutions may not take up multiple lines. |
||||
|
||||
## Prerequisites |
||||
- docker |
||||
- pslist |
||||
- BSD style netcat (`netcat-openbsd` on debian) |
||||
|
||||
## Setup |
||||
- Make sure your ports 1337, 1338 and 1339 are not exposed to the internet, as |
||||
SLBR will use them internally |
||||
- `mkdir /home/slbr-admin` |
||||
- `useradd slbr-admin -d /home/slbr-admin` |
||||
- `usermod -a -G docker slbr-admin` |
||||
- `sudo su slbr-admin` |
||||
- `newgrp docker` |
||||
- `cd` |
||||
- `git clone https://tildegit.org/tildeverse/SLBR` |
||||
- `cd SLBR` |
||||
- You are now ready to manage an slbr game |
||||
|
||||
## Running the game |
||||
- run `./start.sh` to start the listeners for various game events |
||||
- run `./new_image.sh <user name> </path/to/pubkey>` to create a new user |
||||
- All game events and user commands will be logged to log.txt |
||||
- You can `./reset.sh` to cleanup after a game has finished |
@ -0,0 +1,16 @@ |
||||
#!/bin/sh |
||||
num_challenges="$( |
||||
wc -l solutions.txt \ |
||||
| cut -f1 -d ' ' |
||||
)" |
||||
docker ps \ |
||||
-f label="SLBR User Container" \ |
||||
--format "{{.ID}}" \ |
||||
| xargs docker rm -f |
||||
docker images -a \ |
||||
| grep ^slbr \ |
||||
| awk '{print $3}' \ |
||||
| xargs docker rmi -f |
||||
|
||||
printf "$num_challenges\n" > scoreboard.txt |
||||
printf "" > log.txt |
@ -0,0 +1 @@ |
||||
5 |
@ -0,0 +1,86 @@ |
||||
#!/bin/sh |
||||
# we will need the suicide bashrc to continuously write DEAD to the nc socket |
||||
# in case two messages are sent at the same time. |
||||
|
||||
# this will not work if your slbr admin is not in the "docker" group |
||||
|
||||
PORT="$1" |
||||
LOG="log.txt" |
||||
|
||||
[ -z "$1" ] && echo "port?" && exit |
||||
|
||||
docker_subnet_mask="$( |
||||
docker network inspect bridge \ |
||||
| jq '.[0].IPAM.Config[0].Subnet' \ |
||||
| tr -d '"' \ |
||||
| cut -f2 -d '/' |
||||
)" |
||||
|
||||
handle_packet() { |
||||
packet="$1" |
||||
message="$(echo $packet | cut -f3 -d '|')" |
||||
|
||||
address="$( |
||||
echo "$packet" \ |
||||
| cut -f2 -d '|' \ |
||||
| cut -f3 -d ' ' |
||||
)" |
||||
address="$address/$docker_subnet_mask" |
||||
if [ "$message" = "DEAD" ] |
||||
then |
||||
echo "Killing user with ip $address" >> $LOG |
||||
container_name="$( |
||||
docker network inspect bridge \ |
||||
| jq \ |
||||
'.[0].Containers |
||||
| map(select(.IPv4Address == "'"$address"'")) |
||||
| .[0].Name' \ |
||||
| tr -d '"' |
||||
)" |
||||
docker rm -f "$container_name" |
||||
echo "killed container $container_name" >> $LOG |
||||
elif [ "$(echo $message | cut -f1 -d ' ')" = "SOLUTION" ] |
||||
then |
||||
submitted_solution="$(echo $message | cut -f3- -d ' ')" |
||||
challenge_no="$(echo $message | cut -f2 -d ' ')" |
||||
correct_solution="$(sed $challenge_no'q;d' solutions.txt)" |
||||
sed_escaped_address="$(echo $address | sed 's/\./\\./g')" |
||||
|
||||
echo "$address submitted solution for challenge $challenge_no: $submitted_solution" >> $LOG |
||||
if [ "$submitted_solution" = "$correct_solution" ] |
||||
then |
||||
num_correct="" |
||||
echo "Solution was correct!" >> $LOG |
||||
|
||||
grep -qE "^$address" scoreboard.txt \ |
||||
|| echo "$address" >> scoreboard.txt |
||||
|
||||
grep -qE "^$address .*$challenge_no," scoreboard.txt \ |
||||
|| sed -i "s|$sed_escaped_address|$address $challenge_no,|" scoreboard.txt |
||||
|
||||
num_correct="$( |
||||
grep -m1 -E "^$address" scoreboard.txt \ |
||||
| grep -oE '[0-9],' \ |
||||
| wc -l |
||||
)" |
||||
total_solutions="$(cat solutions.txt | wc -l)" |
||||
if [ $num_correct = $total_solutions ] |
||||
then |
||||
echo "$address HAS WON THE GAME!!!" >> $LOG |
||||
sleep 5 |
||||
echo "Killing all continers..." >> $LOG |
||||
docker ps -aq --filter label="SLBR User Container" | xargs docker rm -f |
||||
exit |
||||
fi |
||||
|
||||
echo "$num_correct correct answers so far" >> $LOG |
||||
fi |
||||
fi |
||||
} |
||||
|
||||
echo "game server listening on $PORT" |
||||
while true |
||||
do |
||||
packet=$(nc -w 1 -W 1 -vlp $PORT 2>&1) |
||||
handle_packet "$(echo "$packet" | head -n 3 | tr '\n' '|')" & |
||||
done |
@ -0,0 +1,6 @@ |
||||
#!/bin/sh |
||||
PORT="$1" |
||||
LOG="log.txt" |
||||
[ -z "$1" ] && echo "port?" && exit |
||||
echo "log server listening on $PORT" >> $LOG |
||||
nc -w1 -W1 -vlkp $PORT >> $LOG 2>&1 |
@ -0,0 +1,10 @@ |
||||
#!/bin/sh |
||||
PORT="$1" |
||||
[ -z "$1" ] && echo "port?" && exit |
||||
echo "scoreboard server listening on $PORT" |
||||
while true |
||||
do |
||||
cat scoreboard.txt \ |
||||
| nc -w 1 -W 1 -lp "$PORT" |
||||
echo "Got scoreboard request." |
||||
done |
@ -0,0 +1,5 @@ |
||||
one |
||||
two |
||||
three |
||||
four |
||||
five |
@ -0,0 +1,22 @@ |
||||
#!/bin/sh |
||||
LOG="log.txt" |
||||
death_pid="" |
||||
score_pid="" |
||||
log_pid="" |
||||
|
||||
cleanup() { |
||||
rkill $death_pid >/dev/null 2>&1 |
||||
rkill $score_pid >/dev/null 2>&1 |
||||
rkill $log_pid >/dev/null 2>&1 |
||||
} |
||||
trap 'cleanup' 1 2 3 9 |
||||
|
||||
servers/deathlistener.sh 1337 & death_pid="$!" |
||||
echo "death listener pid: $death_pid" >> "$LOG" |
||||
servers/scoreboard.sh 1338 & score_pid="$!" |
||||
echo "scoreboard server pid: $score_pid" >> "$LOG" |
||||
servers/gamelog.sh 1339 & log_pid="$!" |
||||
echo "log server pid: $log_pid" >> "$LOG" |
||||
|
||||
printf "\e[0;91mReading log, exit to stop game\e[0m\n" |
||||
tail -f "$LOG" |
Loading…
Reference in new issue