It seems that the evil elves have broken the controller gadget for the good old candy cane factory! Can you team up with the real red teamer Santa to hack back?
-
The website allows us to view some properties about a linux system. The output looks just like standard linux commands. The output of the "List Storage" command seems to be executing
df -h
. -
At this point, I guessed that this was a command injection challenge and I tried accessing
http://IP:PORT/?command=ls"
to see if I could list the contents of the current directory. Sure enough, this worked, confirming my suspicions. This is in fact a command injection challenge. -
Looking at the source code, we see in
challenge/models/MonitorModel.php
thatshell_exec
is used to run thesanta_mon.sh
script. Our input in thecommand
URL parameter is then appended to/santa_mon.sh
so that the final command looks like this:/santa_mon.sh [COMMAND PARAMETER INPUT]
. In other words, we control the first argument passed to thesanta_mon.sh
program. Importantly, Thesanitize
function is called on our input, which removes spaces using thes+
regular expression. -
We can see the source code of the
santa_mon.sh
program inconfig/santa_mon.sh
in our downloaded ZIP. We see that the buttons in the web interface do indeed run standard linux commands. At the bottom we see that if there is an argument to the program, it is executed as a command. -
config/santa_mon.sh
shows that theups_status
andrestart_ups
commands return the output from a local web server using curl. If you check the output of the "List Processes" command you will seepython3 /root/ups_manager.py
. Let's check out the source code forconfig/ups_manager.py
. This file runs an HTTP server with the two endpoints accessed by theups_status
andrestart_ups
commands, but it also has a/get_flag
endpoint that prints the flag! -
So, our approach to get the flag is to craft a command injection payload without using spaces that will run
curl http://localhost:3000/get_flag
and return the output to us through the webpage. Using a standard approach to remove spaces (such as those from the excellent guide at swisskyrepo/PayloadsAllTheThings) will not work here because our input is stripped of whitespace and then passed as an argument to another program. Thus, use can use something like theIFS
variable, since hte PHP code will not strip that out, but when it is parsed by bash it will be interpreted as a second argument to thesanta_mon.sh
script. For instance, if our command injection iscurl${IFS}http://localhost:3000/get_flag
then PHP will execute,/santa_mon.sh curl${IFS}http://localhost:3000/get_flag
, bash will interpret this as/santa_mon.sh curl http://localhost:3000/get_flag
, and then thesanta_mon.sh
script will seecurl
as the first argument and will runcurl
without any arguments. -
To solve this, we simply wrap our payload in double quotes like so:
"curl${IFS}http://localhost:3000/get_flag"
(URL encoded:%22curl${IFS}http://localhost:3000/get_flag%22
). This way, PHP will execute/santa_mon.sh "curl${IFS}http://localhost:3000/get_flag"
, bash will interpret this as/santa_mon.sh "curl http://localhost:3000/get_flag"
, then thesanta_mon.sh
script will see the string"curl http://localhost:3000/get_flag"
as the first parameter, it will run our payload, and the PHP server will return the output containing the flag. -
So, the final payload is
http://IP:PORT/?command=%22curl${IFS}http://localhost:3000/get_flag%22
.
HTB{54nt4_i5_th3_r34l_r3d_t34m3r}