HACK THE BOO π: Challenge Writeups
Web Challenges
Evaluation Deck π΄
Home page where the card game was being displayed. Once a card is flipped, the health bar amount is either gained or subtracted, depending on the card that is flipped [random].
When a card is flipped, I could intercept the POST request being used in order to determine three different values and their variables:
current_health
, attack_power
, & operator
. Playing around with the different variables, I noticed that the operator
value could be manipulated:Moving the attack further, I was given the python code used to generate these values and variables. Quite a ways down the code given below, the variables are defined:
from flask import Blueprint, render_template, request
from application.util import response
web = Blueprint('web', __name__)
api = Blueprint('api', __name__)
@web.route('/')
def index():
return render_template('index.html')
@api.route('/get_health', methods=['POST'])
def count():
if not request.is_json:
return response('Invalid JSON!'), 400
data = request.get_json()
current_health = data.get('current_health')
attack_power = data.get('attack_power')
operator = data.get('operator')
if not current_health or not attack_power or not operator:
return response('All fields are required!'), 400
result = {}
try:
code = compile(f'result = {int(current_health)} {operator} {int(attack_power)}', '<string>', 'exec')
exec(code, result)
return response(result.get('result'))
except:
return response('Something Went Wrong!'), 500
Something interesting is the
result
variable & the operator
variable. The operator variable is left wide open for manipulation without any definition to it. In addition to this, I can leverage the result variable in order to [hopefully] read files on the server. Messing with some options, I was able to manipulate the operator variable to receive a null
message value:Now, how do I get out of this sandbox? Viewing hacktricks methods and digging deeper into how Werkzeug works, there is a way to open and then read the contents of a file, shown here. Here is the attempt to grab the flag:
FLAG =
HTB{c0d3_1nj3ct10ns_4r3_Gr3at!!}
Web Challenges
Spookifier π»
Upon opening the website to the main page, there is an input field where you can type in string and it will re-write the string in different fonts.
Capturing the input field that re-writes the string to different fonts, we are presented with the following burp suite request and response:
Going through the steps, one-by-one, here are the results:



This is indicative that the template being used is Mako. With this knowledge, I used the
${-input command here-}
method in combination with escaping the python sandbox to retrieve the flag:FLAG =
HTB{t3mpl4t3_1nj3ct10n_1s_$p00ky!}
Web Challenges
Juggling Facts π€Ή
Right away, I am presented with a simple website with three different options: Spooky Facts, Not So Spooky Facts, & Secret Facts. Without admin access, or local access, I am unable to view the Secret Facts.
Attempting to click the
Secret Facts
button, we are presented with the Secrets can only be accessed by admin
message. Let's go ahead and capture the action of clicking on the Secret Facts
button with Burp Suite:One major thing that caught my eye is that the application is using a content type of
JSON
. This is very interesting and now makes sense as to why the title of this challenge is Juggling
facts. The reason why I say that is explained here, and can be shown in the PHP
code given in the challenge, displayed below:<?php
class IndexController extends Controller
{
public function __construct()
{
parent::__construct();
}
public function index($router)
{
$router->view('index');
}
public function getfacts($router)
{
$jsondata = json_decode(file_get_contents('php://input'), true);
if ( empty($jsondata) || !array_key_exists('type', $jsondata))
{
return $router->jsonify(['message' => 'Insufficient parameters!']);
}
if ($jsondata['type'] === 'secrets' && $_SERVER['REMOTE_ADDR'] !== '127.0.0.1')
{
return $router->jsonify(['message' => 'Currently this type can be only accessed through localhost!']);
}
switch ($jsondata['type'])
{
case 'secrets':
return $router->jsonify([
'facts' => $this->facts->get_facts('secrets')
]);
case 'spooky':
return $router->jsonify([
'facts' => $this->facts->get_facts('spooky')
]);
case 'not_spooky':
return $router->jsonify([
'facts' => $this->facts->get_facts('not_spooky')
]);
default:
return $router->jsonify([
'message' => 'Invalid type!'
]);
}
}
}
Further towards the middle-top portion of the PHP code above, there is the
json_decode()
function, which is sometimes a good indicator that the code may be susceptible to type juggling. For example, and shown above in the POST request being captured in Burp Suite, the type
is looking for a string called secrets
. If I change the string [secrets] to, let's say the boolean true
, it will most likely accept that data type. And it does, which is shown below!FLAG =
HTB{sw1tch_stat3m3nts_4r3_vuln3r4bl3!!!}
Pwn Challenges
Pumpkin Stand π
For this Pwn Challenge, I was presented with a program where you could buy either a
Shovel
for 1337 pumpcoins OR a Laser
for 9999 pumpcoins. I was given exactly 1337 pumpcoins and buying a shovel dropped my pumpcoins amount to exactly 0. After playing around with different integers, I was able to manipulate the pumpcoin value that I possess to a negative value of -20710
when I entered in a large number of just 1's. This made me realize that the program may be vulnerable to an integer overflow, therefore I could somehow get that Laser without having the correct amount. Here's the process I followed below: βββ(rootπkali)-[~/Downloads] ββ# nc 139.59.167.169 32160 ##& (#&& ##&& ,*. #%%& .*, .&@@@@#@@@&@@@@@@@@@@@@&@@&@#@@@@@@( /@@@@&@&@@@@@@@@@&&&&&&&@@@@@@@@@@@&@@@@, @@@@@@@@@@@@@&@&&&&&&&&&&&&&@&@@@@@@&@@@@@@ #&@@@@@@@@@@@@@@&&&&&&&&&&&&&&&#@@@@@@@@@@@@@@, .@@@@@#@@@@@@@@#&&&&&&&&&&&&&&&&&#@@@@@@@@@@@@@& &@@@@@@@@@@@@@@&&&&&&&&&&&&&&&&&&&@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@&&&&&&&&&&&&&&&&&&&&@@@@@@@@@&@@@@@ @@@@@@@@@@@@@@@&&&&&&&&&&&&&&&&&&&@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@&&&&&&&&&&&&&&&&&&&@@@@@@@@@@@@@@@ .@@@@@@@@@@@@@@&&&&&&&&&&&&&&&&&&&@@@@@@@@@@@@@@ (@@@@@@@@@@@@@@&&&&&&&&&&&&&&&&&@@@@@@@@@@@@@@. @@@@@@@@@@@@@@&&&&&&&&&&&&&&&@@@@@@@@@@@@@@ ,@@@@@@@@@@@@@&&&&&&&&&&&&&@@@@@@@@@@@@@ @@@@@@@@@@@@@&&&&&&&&&@@@@@@@@@@@@/ Current pumpcoins: [1337] Items: 1. Shovel (1337 p.c.) 2. Laser (9999 p.c.) >> 111111111111111111111111111111111 How many do you want? >> 1 Current pumpcoins: [-20710] [-] Not enough pumpcoins for this! Current pumpcoins: [-20710] Items: 1. Shovel (1337 p.c.) 2. Laser (9999 p.c.) >> 1111111111111111111111111111111 How many do you want? >> 1 Congratulations, here is the code to get your laser: HTB{1nt3g3R_0v3rfl0w_101_0r_0v3R_9000!}
FLAG:
HTB{1nt3g3R_0v3rfl0w_101_0r_0v3R_9000!}
Reversing Challenges
Cult Meeting π€
After downloading the file given to us for this challenge, there a shell script that could be executed, called
meeting
. After running the strings
command on this file, I could see something secretive:βββ(rootπkali)-[~/Downloads/rev_cult_meeting] ββ# strings meeting /lib64/ld-linux-x86-64.so.2 mgUa puts stdin fgets stdout system fwrite strchr __cxa_finalize setvbuf strcmp __libc_start_main libc.so.6 GLIBC_2.2.5 _ITM_deregisterTMCloneTable __gmon_start__ _ITM_registerTMCloneTable u/UH []A\A]A^A_ [3mYou knock on the door and a panel slides back [3m A hooded figure looks out at you "What is the password for this week's meeting?" sup3r_s3cr3t_p455w0rd_f0r_u! [3mThe panel slides closed and the lock clicks | | "Welcome inside..." /bin/sh \/ \| "That's not our password - call the guards!" ;*3$" GCC: (Debian 10.2.1-6) 10.2.1 20210110 crtstuff.c deregister_tm_clones __do_global_dtors_aux completed.0 __do_global_dtors_aux_fini_array_entry frame_dummy __frame_dummy_init_array_entry main.c __FRAME_END__ __init_array_end _DYNAMIC __init_array_start __GNU_EH_FRAME_HDR _GLOBAL_OFFSET_TABLE_ __libc_csu_fini _ITM_deregisterTMCloneTable stdout@GLIBC_2.2.5 puts@GLIBC_2.2.5 stdin@GLIBC_2.2.5 _edata system@GLIBC_2.2.5 strchr@GLIBC_2.2.5 __libc_start_main@GLIBC_2.2.5 fgets@GLIBC_2.2.5 __data_start strcmp@GLIBC_2.2.5 __gmon_start__ __dso_handle _IO_stdin_used __libc_csu_init __bss_start main setvbuf@GLIBC_2.2.5 fwrite@GLIBC_2.2.5 __TMC_END__ _ITM_registerTMCloneTable __cxa_finalize@GLIBC_2.2.5 .symtab .strtab .shstrtab .interp .note.gnu.build-id .note.ABI-tag .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame .init_array .fini_array .dynamic .got.plt .data .bss .comment
Towards the top of the strings output, I noticed the string
sup3r_s3cr3t_p455w0rd_f0r_u!
. Doing a little more digging, it looks like when I answer the question, What is the password for this week's meeting?
, correctly, I am given a /bin/sh
shell on wherever the file is run on. Let's connect to the docker that this challenge is using and enter that correct password when asked:βββ(rootπkali)-[~/Downloads/rev_cult_meeting] ββ# nc 139.59.167.169 31234 You knock on the door and a panel slides back |/ποΈ ποΈ \| A hooded figure looks out at you "What is the password for this week's meeting?" sup3r_s3cr3t_p455w0rd_f0r_u! sup3r_s3cr3t_p455w0rd_f0r_u! The panel slides closed and the lock clicks | | "Welcome inside..." /bin/sh: 0: can't access tty; job control turned off $ cat flag.txt cat flag.txt HTB{1nf1ltr4t1ng_4_cul7_0f_str1ng5}
After receiving the shell on the docker container hosting the challenge, I went ahead and ran the
cat
command on the flag.txt file to retrieve the flag.FLAG =
HTB{1nf1ltr4t1ng_4_cul7_0f_str1ng5}
Previous
Previous
SMB Relay to Reverse Shells: Initial Attack Vector Evading AV
Next
Next