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.phpthatshell_execis used to run thesanta_mon.shscript. Our input in thecommandURL parameter is then appended to/santa_mon.shso 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.shprogram. Importantly, Thesanitizefunction is called on our input, which removes spaces using thes+regular expression. -
We can see the source code of the
santa_mon.shprogram inconfig/santa_mon.shin 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.shshows that theups_statusandrestart_upscommands 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_statusandrestart_upscommands, but it also has a/get_flagendpoint 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_flagand 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 theIFSvariable, 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.shscript. For instance, if our command injection iscurl${IFS}http://localhost:3000/get_flagthen 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.shscript will seecurlas the first argument and will runcurlwithout 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.shscript 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}