I just built Python wheels for the latest version of SQLAlchemy (1.05 at the time I wrote this). This should make it a whole lot easier to install on Windows since no compiling is required. They’re only available for the latest versions of Python (2.7.10 and 2.6.6) since it appears to be impossible to make multiple minor versions of Python coexist. I did manage to install both 32 and 64 bit versions though. On Cygwin, only Python 2.7.10 is available (I don’t think it’s possible to install Python 2.6 there, at least not using the package manager), but at least I could produce builds for 32 and 64 bits as well.
I skipped Python 2.5 entirely since pip doesn’t work there, so I assume it’s not meant to be possible. If you happen to know how to make Python wheels work on it, let me know!
I also skipped Python 3.x, but that’s just because I hate it. I don’t even know if SQLAlchemy works there and quite frankly I don’t care. 
Enjoy! 
The WinAppDbg python module allows developers to quickly code instrumentation scripts in Python under a Windows environment.
It uses ctypes to wrap many Win32 API calls related to debugging, and provides an object-oriented abstraction layer to manipulate threads, libraries and processes, attach your script as a debugger, trace execution, hook API calls, handle events in your debugee and set breakpoints of different kinds (code, hardware and memory). Additionally it has no native code at all, making it easier to maintain or modify than other debuggers on Windows.
The intended audience are QA engineers and software security auditors wishing to test / fuzz Windows applications with quickly coded Python scripts. Several ready to use utilities are shipped and can be used for this purposes.
Current features also include disassembling x86/x64 native code, debugging multiple processes simultaneously and produce a detailed log of application crashes, useful for fuzzing and automated testing.
In a nutshell…
should work on other servers too (let me know if it doesn’t!)
Project homepage:
Download links:
Documentation:
Online
Windows Help
HTML format (offline)
PDF format (suitable for printing)
Acknowledgements go to Arthur Gerkis, Chris Dietrich, Felipe Manzano, Francisco Falcon, @Ivanlef0u, Jean Sigwald, John Hernandez, Jun Koi, Michael Hale Ligh, Nahuel Riva, Peter Van Eeckhoutte, Randall Walls, Thierry Franzetti, Thomas Caplin, and many others I’m probably forgetting, who helped find and fix bugs in the almost eternal beta of WinAppDbg 1.5! 
Enjoy! 
Edited 6-May-2013: updated Impacket to version 0.9.10
Edited 18-Feb-2014: updated Impacket to version 0.9.11
Anyway. After a conversation on Twitter about how it’s becoming increasingly harder to find the venerable WIN32.HLP file – and how it was becoming ever more outdated, I came to realize I didn’t know of any OllyDbg plugin to use the more modern and up to date MSDN documentation. I asked around and no one else seems to have written such a plugin, so I wrote my own.
It’s sort of a dirty hack – in general there’s no easy way of overriding existing features in Olly, the plugin API is rather meant to add new functionality. So after messing about with it for a while I came up with an easy hack – the plugin just hooks the WinHelp() API call to detect when WIN32.HLP is about to be opened, and launches the default web browser instead. Any other help file is launched normally.
The next step would be to search the MSDN looking for the API call the user requested. Then again, a quick hack came to the rescue
since instead of figuring out how to perform MSDN searches it was much easier to just use a Google search with the “I Feel Lucky” button. You can find out more here about the unofficial Google Search API.
The plugin is also compatible with the newer Immunity Debugger which is based in OllyDbg, and was tested on both.
To install, just copy the DLL file in the plugins folder (by default is the same where the main EXE lives). You do need to have set the win32.hlp file in the configuration at some point (so Olly actually tries to open it, otherwise the plugin never finds out). It doesn’t need to be the real file though, any file named “win32.hlp” will do the trick, even if it’s 0 bytes long.
Enjoy!
Enjoy!
Update: Just added another disassembler package, Pymsasid.
Update: Added precompiled Windows binaries for PyDasm on Python 2.6 and 2.7.
Update: My installers were added to the Python Arsenal for RE. 
Update: The Pymsasid package was updated with a small change, so the importation works just the same as loading the .py files from the current directory (it’s just an “import *” in __init__.py)
Update: Added a simple setup script for Libdisassemble 2.0. Since I had to put the sources inside a package the import statement in your scripts will have to be adjusted if using this version. With a simple try/except block you can make scripts compatible with both versions as well, if you need to.
Now, I never get tired of saying how great VTrace is. It’s written in Python, supports multiple platforms and quite comfortable to develop with. But alas, I tend to prefer my own debugger (call me biased if you wish!). So today I went ahead and added WinAppDbg support to Heappie!. When WinAppDbg is installed, it’s chosen automatically as the backend. If not found, it falls back to VTrace. That way we don’t lose support for other platforms, since WinAppDbg naturally only works on Windows.
This patch also adds support for 64 bit versions of Windows, in case you were thinking this was just an exercise in self indulgence. Well, it is that, but not just that. Ahem.
Just download the file above, go to AnΓbal’s blog to learn how to use it, and exploit all the bugs! 
The WinAppDbg python module allows developers to quickly code instrumentation scripts in Python under a Windows environment.
It uses ctypes to wrap many Win32 API calls related to debugging, and provides an object-oriented abstraction layer to manipulate threads, libraries and processes, attach your script as a debugger, trace execution, hook API calls, handle events in your debugee and set breakpoints of different kinds (code, hardware and memory). Additionally it has no native code at all, making it easier to maintain or modify than other debuggers on Windows.
The intended audience are QA engineers and software security auditors wishing to test / fuzz Windows applications with quickly coded Python scripts. Several ready to use utilities are shipped and can be used for this purposes.
Current features also include disassembling x86 native code (using the open source diStorm project, see http://ragestorm.net/distorm/), debugging multiple processes simultaneously and produce a detailed log of application crashes, useful for fuzzing and automated testing.
In a nutshell…
Entire changelog for all versions (slow!):
This security update resolves one publicly disclosed vulnerability and one privately reported vulnerability in Microsoft Exchange and Windows SMTP Service. The more severe of these vulnerabilities could allow denial of service if an attacker sent a specially crafted DNS response to a computer running the SMTP service.
However, researcher NicolΓ‘s Economou found an interesting surprise in this patch: two additional, undisclosed vulnerabilities had also been patched… and they were far more severe than the ones reported! From the Core Security advisory:
Nicolas found that the Windows SMTP Service does its own DNS resolution of MX records rather that use the DNS resolver from the operating system while investigating CVE-2010-0024.
Furthermore, he found that the patch referenced in MS10-024 fixed two severe bugs that were not disclosed as such in the bulletin and had no CVE identifiers assigned to them. Basic analysis of the vulnerabilities disclosed in this advisory indicates that the threat of DNS spoofing attacks against Windows SMTP service and Microsoft Exchange or of exploitation of CVE-2010-0024 was underestimated in MS10-024.
An attacker may leverage the two previously undisclosed vulnerabilities fixed by MS10-014 to spoof responses to any DNS query sent by the Windows SMTP service trivially. DNS response spoofing and cache poisoning attacks are well known to have a variety of security implications with impact beyond just Denial of Service and Information Disclosure as originally stated in MS10-024.
In fact, the two “new” vulnerabilities were quite crass. Both Exchange and the SMTP service were doing their own manually crafted DNS queries using incremental transaction IDs, which is a big no-no when implementing DNS because it makes it real easy for attackers to guess the transaction ID and spoof replies, as is a well known fact for… say… the last 16 years or so? But as it turns out, attackers didn’t even need to guess the transaction IDs… because they weren’t even being used when parsing the DNS responses! 
This omission may be easily attributed to the “embarrasment factor”
but it’s still a terrible idea to patch vulnerabilities silently: IT administrators, unaware of the real danger of the problem, may give the patch a lower priority. A denial of service just means having the mail server down for a while until it restarts, so the patch can wait – it’d be worse if the server didn’t work at all because patching went wrong. On the other hand, a DNS poison vulnerability means having an attacker browse through everyone’s emails and taking over all other services you may have on the same machine – patching becomes much more worth the risk.
Of course, this isn’t the first time this happens. Practically every vendor did this at one time or another. A quick Google search for “silently patched vulnerability” shows some 1.400.000 hits at the time I’m writing this, showing this is neither new or uncommon – and that even small software vendors may easily get caught. Especially thanks to the rise of binary diffing tools that can pinpoint precisely where and how the code was patched.
Thanks Alfredo Ortega for pointing out this advisory and providing such a cool sounding title. 
From the CORE Security webpage:
What is Impacket?
Impacket is a collection of Python classes focused on providing access to network packets. Impacket allows Python developers to craft and decode network packets in simple and consistent manner. It includes support for low-level protocols such as IP, UDP and TCP, as well as higher-level protocols such as NMB and SMB. Impacket is highly effective when used in conjunction with a packet capture utility or package such as Pcapy. Packets can be constructed from scratch, as well as parsed from raw data. Furthermore, the object oriented API makes it simple to work with deep protocol hierarchies.
What is Pcapy?
Pcapy is a Python extension module that interfaces with the libpcap packet capture library. Pcapy enables python scripts to capture packets on the network. Pcapy is highly effective when used in conjunction with a packet-handling package such as Impacket, which is a collection of Python classes for constructing and dissecting network packets.
There is a problem though – Pcapy hasn’t been updated in quite a while, so there is no MSI installer for Python 2.6. I’ve built it myself and hosted in here in the blog, so you don’t have to.
I’ve also built an EXE installer for Impacket, it’s not really needed since it’s a pure Python module, but why not?
So this is the list of files we’ll be needing:
Installation is now pretty much straight forward. After running all the installers, let’s try it out with this example script to dump all connection attempts by sniffing SYN packets:
C:\Documents and Settings\Mario Vilas\Desktop>python connections.py
Available network interfaces:
1 - \Device\NPF_GenericDialupAdapter
2 - \Device\NPF_{5BE055D9-461D-4F51-99DD-188224D1A6D0}
3 - \Device\NPF_{9B7DC2FB-7660-4E68-B4EC-DB9682C76E40}
4 - \Device\NPF_{166A618C-4230-42E7-93AD-298D1145F5BC}
5 - \Device\NPF_{BE987C8D-D523-49B8-8B95-DDDBAA46EB3F}
Choose an interface [0 to quit]: 2
Listening on: \Device\NPF_{5BE055D9-461D-4F51-99DD-188224D1A6D0}
Connection attempt 10.0.2.15 -> 192.168.254.254
Connection attempt 10.0.2.15 -> 192.168.254.254
Connection attempt 10.0.2.15 -> 192.168.254.254
Connection attempt 10.0.2.15 -> 192.168.254.254
Connection attempt 10.0.2.15 -> 192.168.254.254
Connection attempt 10.0.2.15 -> 209.85.227.106
Connection attempt 10.0.2.15 -> 209.85.227.104
Connection attempt 10.0.2.15 -> 209.85.227.104
Connection attempt 10.0.2.15 -> 209.85.227.104
Connection attempt 10.0.2.15 -> 209.85.227.100
^C
Below is the source code to the script. Enjoy! 
#!/usr/bin/env python
# Copyright (c) 2009-2010, Mario Vilas
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice,this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
from pcapy import findalldevs, open_live
from impacket import ImpactDecoder, ImpactPacket
def get_interface():
# Get the list of interfaces we can listen on
ifs = findalldevs()
# No interfaces found
if len(ifs) == 0:
raise RuntimeError, "Error: no available network interfaces, or you don't have enough permissions on this system."
# A single interface was found
if len(ifs) == 1:
interface = ifs[0]
# Multiple interfaces found
else:
print "Available network interfaces:"
for i in xrange(len(ifs)):
print '\t%i - %s' % (i + 1, ifs[i])
print
while 1:
choice = raw_input("Choose an interface [0 to quit]: ")
try:
i = int(choice)
if i == 0:
interface = None
break
interface = ifs[i-1]
break
except Exception:
pass
# Return the selected interface
return interface
def sniff(interface):
print "Listening on: %s" % interface
# Open a live capture
reader = open_live(interface, 1500, 0, 100)
# Set a filter to be notified only for TCP packets
reader.setfilter('ip proto \\tcp')
# Run the packet capture loop
reader.loop(0, callback)
def callback(hdr, data):
# Parse the Ethernet packet
decoder = ImpactDecoder.EthDecoder()
ether = decoder.decode(data)
# Parse the IP packet inside the Ethernet packet
iphdr = ether.child()
# Parse the TCP packet inside the IP packet
tcphdr = iphdr.child()
# Only process SYN packets
if tcphdr.get_SYN() and not tcphdr.get_ACK():
# Get the source and destination IP addresses
src_ip = iphdr.get_ip_src()
dst_ip = iphdr.get_ip_dst()
# Print the results
print "Connection attempt %s -> %s" % (src_ip, dst_ip)
def main():
interface = get_interface()
if interface:
sniff(interface)
if __name__ == "__main__":
main()
]]>Given that Windows NT 4 was relased in ~1996 this vulnerability has been
present for ~14 years. If it is confirmed this vulnerablity is also
present in older systems such as Windows NT 3.1, released in ~1993,
Windows NTLMv1 authentication mechanism could have been vulnerable for
~17+ years.
Whoa. That’s kind of scary.
Kudos to Hernan Ochoa and Agustin Azubel for this great find! 
Below is the complete text of the advisory, except for the source code to the scripts, which were removed for brevity. The original advisory can be downloaded from: http://www.hexale.org/advisories/OCHOA-2010-0209.txt.
Update: Hernan Ochoa has also written an article regarding the risk assesment for this vulnerability.
Windows SMB NTLM Authentication Weak Nonce Vulnerability
Security Advisory
Hernan Ochoa ([email protected]) - Agustin Azubel ([email protected])
Title: Windows SMB NTLM Authentication Weak Nonce Vulnerablity
Advisory ID: OCHOA-2010-0209
Advisory URL: http://www.hexale.org/advisories/OCHOA-2010-0209.txt
Date published: 2010-02-09
Vendors contacted: Microsoft
Release mode: Coordinated release
Last Updated: 2010-02-09
Index
-----
1.Vulnerablity information
2.Vulnerablity description
3.Vulnerable systems
4.Vendor Information, solutions and workarounds
5.Credits
6.Technical description
6.1.NTLMv1 authentication protocol
6.2.The Flaws
6.3.Detecting if the SMB service generates duplicate 8-byte challenges
6.4.Exploiting duplicate challenges
6.4.1.Proof-of-Concept Exploit
6.5.Predicting challenges
6.5.1.SMB service: challenge generation process
6.5.2.Proof-of-Concept Exploit
7.References
8.Disclaimer
1.Vulnerability information
---------------------------
Impact: An unauthenticated remote attacker without any kind of
credentials can access the SMB service under the credentials of an
authorized user. Depending on the privileges of the authorized user, and
the configuration of the remote system, an attacker can gain read/write
access to the remote file system and execute arbitrary code by using
DCE/RPC over SMB.
Remotely Exploitable: Yes
Bugtraq Id:
CVE: CVE-2010-0231
2.Vulnerability description
---------------------------
Microsoft Server Message Block (SMB) Protocol is a Microsoft network
file sharing protocol also used for sharing printers, communications
abstractions such as named pipes and mailslots, and performing Remote
Procedure Calls (DCE/RPC over SMB) [1].
NTLM (NT Lan Manager) is a challenge-response authentication protocol
used by the SMB protocol [2].
Windows systems commonly use the SMB protocol with NTLM authentication
for network file/printer sharing and remote administration via DCE/RPC.
Flaws in Microsoft's implementation of the NTLM challenge-response
authentication protocol causing the server to generate duplicate
challenges/nonces and an information leak allow an unauthenticated
remote attacker without any kind of credentials to access the SMB
service of the target system under the credentials of an authorized
user. Depending on the privileges of the user, the attacker will be able
to obtain and modify files on the target system and execute arbitrary code.
3.Vulnerable Systems
--------------------
This vulnerability was verified by the authors on the following platforms:
Windows NT4 SP1
Windows Server 2003 SP2
Windows XP SP3
Windows Vista x32
Windows 7 x32 RC
However, all versions of Windows implementing NTLMv1 are suspected to be
affected.
Microsoft, in their "Microsoft Security Bulletin Advance Notification
for February 2010" [3], list the following platforms as affected:
Windows 2000 SP4
Windows XP SP2 and SP3
Windows XP Professional x64 Edition SP2
Windows Server 2003 SP2
Windows Server 2003 x64 Edition SP2
Windows Server 2003 SP2 for Itanium-based systems
Windows Vista
Windows Vista SP1
Windows Vista SP2
Windows Vista x64 Edition
Windows Vista x64 Edition SP1
Windows Vista x64 Edition SP2
Windows Server 2008 x32
Windows Server 2008 x32 SP2
Windows Server 2008 x64 SP2
Windows Server 2008 x64 SP2
Windows Server 2008 for Itanium-based systems
Windows Server 2008 for Itanium-based systems SP2
Windows 7 x32
See [3] for more details.
Given that Windows NT 4 was relased in ~1996 this vulnerability has been
present for ~14 years. If it is confirmed this vulnerablity is also
present in older systems such as Windows NT 3.1, released in ~1993,
Windows NTLMv1 authentication mechanism could have been vulnerable for
~17+ years.
4.Vendor Information, Solutions and Workarounds
-----------------------------------------------
SMB NTLM Authentication Lack of Entropy Vulnerability - CVE-2010-0231
http://www.microsoft.com/technet/security/bulletin/ms10-012.mspx
5.Credits
---------
This vulnerability was discovered by Hernan Ochoa (Independent
Information Security Consultant and Researcher) and it was researched by
Hernan Ochoa and Agustin Azubel (Independent Information Security
Consultant and Researcher).
6.Technical description
------------------------
Microsoft Server Message Block (SMB) Protocol is a Microsoft network
file sharing protocol also used for sharing printers, communications
abstractions such as named pipes and mailslots, and performing Remote
Procedure Calls (DCE/RPC over SMB) [1].
NTLM (NT Lan Manager) is a challenge-response authentication protocol
used by the SMB protocol [2].
Windows systems commonly use the SMB protocol with NTLM authentication
for network file/printer sharing and remote administration via DCE/RPC.
Flaws in Microsoft's implementation of the NTLM challenge-response
authentication protocol causing the server to generate duplicate
challenges/nonces and an information leak allow an unauthenticated
remote attacker without any kind of credentials to access the SMB
service of the target system under the credentials of an authorized
user. Depending on the privileges of the user, the attacker will be able
to obtain and modify files on the target system and execute arbitrary code.
6.1.NTLMv1 authentication protocol
----------------------------------
The NTLMv1 authentication protocol is a challenge-response protocol that
consists of the following messages:
1. The client sends to the server a message containing a set of flags of
features supported/requested to perform authentication.
2. The server responds with a message containing a set of flags
supported/required by the server enabling both ends to agree on the
authentication parameters and, more importantly, an 8-byte random
challenge/nonce.
3. The client uses the random challenge/nonce and the user's
credentials to calculate the response (24 bytes) and sends it to the server.
4. The server determines if the response is correct and allows or
disallows access to the client.
The randomness of the 8-byte challenge/nonce returned by the server
tries to ensure that every challenge-response sequence is unique helping
protect against replay attacks.
6.2.The Flaws
----------------
Several flaws were found leading to attacks such as generation of
duplicate challenges/nonces and challenge/nonce prediction.
The randomness of the 8-byte challenges generated by the SMB server in
response to an specific packet requesting authentication is bad enabling
attackers to perform replay attacks. The SMB server easily generates
duplicate 8-byte challenges.
The challenge/nonce prediction attack is feasible due to several factors
including that the protocol leaks information that can be used by an
attacker to calculate the internal state of the PRNG used to generate
challenges.
6.3.Detecting if the SMB service generates duplicate 8-byte challenges
-----------------------------------------------------------------------
Detecting the generation of duplicate challenges can be verified
remotely by repeatedly sending 'SMB Negotiate Protocol Request' packets
to a Windows system with the 'Flags2' field set to 0xc001 (disabling
security signatures, extended attributes and extended security
negotiation) recording the 8-byte challenges obtained from the server
and waiting for duplicates.
The following Ruby script can be used to test for the presence of this
vulnerability:
6.4.Exploiting duplicate challenges
--------------------------------------
There are different ways to exploit duplicate challenges, including:
(i) An attacker A can eavesdrop network traffic looking for NTLM
authentication messages exchanged between client C and server S ('SMB
Negotiate Protocol Requests' packets and 'SMB Negotiate Protocol
Responses' packets), storing challenges and their corresponding
responses. The attacker A can then perform several authentication
requests to server S until S returns a previously observed challenge (a
duplicate).At that point attacker A will send the corresponding and
previously recorded response.
We did not find so far any current Windows version (XP,Vista,7,etc)
that by default or using some specific configuration, when acting as an
SMB client, would generate the necessary 'SMB Negotiate Protocol
Request' packets with the correct values in the 'Flags2' field to
trigger the vulnerability when accessing a remote SMB service. Hence we
were unable to collect duplicate challenges only by network sniffing.
Tests were performed with the third-party SMB client 'smbclient' from
the SAMBA project with the same negative results (tests were not
exhaustive).
Since this problem was also found on Windows versions as old as Windows
NT4, this scenario might still be possible.
(ii) An attacker A connects to system S and sends mutiple 'SMB
Negotiate Protocol Request' packets with the 'Flags2' field set to
0xc001 to obtain several challenges, and stores them. The attacker A
then forces a user U on system S to connect to his own specially crafted
SMB server, for example by sending an email with multiple
tags
with UNC links (e.g.:
) or a link to
web server with similar
tags. Upon receiving the connections from
system S,the attacker's SMB server will respond with the previously
obtained challenges and will store the corresponding responses returned
by the remote system. Attacker A has now a set of responses which are
the challenges encrypted with user's U credentials.
Finally, the attacker A will perform several authentication requests to
system S until it returns one of the challenges obtained at the
beginning of this attack, and at that point he will replay the
corresponding and previously obtained response to gain access to system
S as user U.
If user U has, for example, local administrator privileges on system S
(not uncommon for Windows XP users, for example), remote code execution
is possible via DCE/RPC over SMB. Even if user U has no administrator
privileges attacker A can still access, for example, file shares
accessible by user U and read/modify information.
Tests performed showed that challenges and responses obtained from a
system S can be reused multiple times against that same system and other
remote systems. We observed that challenges obtained from a system S
were also returned by other remote systems. This means that attacker A
only needs, in the best case scenario, to force user U to connect to his
own specially crafted SMB server once. Of course, user U must have
access (his credentials must be valid) to the other systems attacked.
This attack needs the victim to have port 445/tcp open and the attacker
to be able to access that port. The victim also needs to be able to
access port 445/tcp on the attacker's server (only once, to record
responses. Subsequent attacks do not need the victim to access the
attacker's system).
This simple attack using a 'brute-force' approach to find duplicate
challenges proved to be acceptably effective.
6.4.1.Proof-of-Concept Exploit
--------------------------------
The exploit implementation is twofolded:
(i) setup_smb_weak_nonce.rb
This standalone Ruby script performs several connections to the victim
sending 'SMB Negotiate Protocol Request' packets to obtain 8000
challenges (the number of challenges to be obtained can be changed).
After collecting 8000 challenges, it will listen on port 445/tcp for
incoming SMB connections originated by the victim. For every connection
received, it will send to the victim one of the previously obtained
challenges and will store the corresponding response obtained.
As a simple example of a method to force the victim to connect to the
attacker, the file 'conn.html' is provided. This is a very simple HTML
file with javascript code that will generate 1000
tags with an UNC
link to different image files.
The challenges and responses obtained are saved to the file
'fullcreds.log'.
(ii) msf_smb_weak_nonce.rb
This metasploit module will perform connections to the victim until
the server responds with one of the duplicate challenges stored in
'fullcreds.log'. The module will then send the corresponding response to
gain access to the victim's SMB service.
Finally, after successful exploitation, the module will create the
file 'owned.txt' in the ADMIN$ share (c:\windows) with the following
text: "Windows SMB NTLM Authentication weak nonce vulnerability
successfully exploited!".
This module can be easily modified to execute code on the remote
system (given the target user has enough privileges).
To exploit the vulnerability repeat the following steps:
1. copy msf_smb_weak_nonce.rb to
/modules/exploits/windows/smb
2. Run setup_smb_weak_nonce.rb specifying the IP of the victim (e.g.:
ruby setup_smb_weak_nonce.rb 192.168.10.1). After collecting the nonces
the script will listen on port 445 for incoming SMB connections.
3. Run Internet Explorer and load 'conn.html'. This will produce 1000+
connections to the SMB server implemented by setup_smb_weak_noce.rb.
(Note 1: setup_smb_weak_nonce.rb needs to be run as root to be able to
listen on port 445/tcp)
(Note 2: If you load 'conn.html' with Internet Explorer and
'conn.html' is stored on a local drive (e.g.:c:\conn.html) it is
possible Internet Explorer will prompt you to allow execution of the
javascript code within 'conn.html'. This is not a limitation of the
attack, it is just an extra protection implemented by Internet Explorer,
the 'conn.html' does not even need to contain javascript code, it uses
it just because it is convenient, you could just as easily 'hard-code'
all
tags. Also, loading the html file from the a local disk is not
a real attack scenario, all of this is for demonstration purposes).
4.After 1000 connections are received by setup_smb_weak_nonce.rb the
script will terminate. The file 'fullcreds.log' will be generated. Copy
'fullcreds.log' to /tmp.
5. run metasploit (msfconsole) and execute the following commands:
-use windows/smb/msf_smb_weak_nonce
-set RHOST
for example: set RHOST 192.168.10.1
-set payload windows/shell/bind_tcp
-exploit
The metasploit module looks for 'fullcreds.log' in '/tmp' by default.
You can specify the location of the 'fullcreds.log' file using the
following command:
-set CREDSFILE
for example:
-set CREDSFILE /mydir/fullcreds.log
6.the metasploit module will start performing connections to the
victim until receiving a duplicate challenge for which there's a
response in the 'fullcreds.log' file. After successfully authenticating
to the victim, the script will create the file 'owned.txt' in c:\windows
via the ADMIN$ share (given the user exploited has enough privileges).
Please remember that this proof-of-concept exploit requires the targer
user to have enough privileges (e.g.: local administrator) to access the
ADMIN$ share remotely. However, the target user does need to have this
privilege level in order for the attacker to exploit the vulnerability.
For example: if the target user only has regular user privileges, an
attacker can access the file shares that user has access to. Also,
exploiting the vulnerabiliy and the level of access obtained are two
different things.
This is just a proof-of-concept exploit, it can be improved and optimized.
Next are all the previously mentioned files part of the proof-of-concept
exploit:
6.5.Predicting challenges
The challenge/nonce prediction attack is feasible due to several
factors including that the protocol leaks information that can be used
by an attacker to calculate the internal state of the PRNG used to
generate challenges.
In order to explain the attack implemented next we begin by explaining
the method used by the Windows SMB service to generate challenges.
6.5.1.SMB service: challenge generation process
(Note: during this explanation we are going to use the code for the
Windows XP version of all modules mentioned. The code is the same in all
platforms with some minor differences for some platforms but these
differences do not produce a different behaviour).
The function that generates the challenges returned in 'SMB Negotiate
Protocol Response' packets is srv.sys!GetEncryptionKey():
It takes the current time, and adds to the low part of the current time
the value of the
global variable _EncryptionKeyCount.
00040735 lea eax, [ebp+CurrentTime]
00040738 push eax
00040739 call ds:__imp__KeQuerySystemTime@4
0004073F mov eax, _EncryptionKeyCount
00040744 add dword ptr [ebp+CurrentTime], eax
Increments _EncryptionKeyCount by 0x100 and makes some 'calculations'
with the (current time.lowpart + _EncryptionKeyCount) resulting in a
DWORD value with the
following 'pattern':
where CT = (current time.lowpart + _EncryptionKeyCount)
seed = CT[1], CT[2]-1, CT[2], CT[1]+1;
00040747 movzx ecx, byte ptr [ebp+CurrentTime+1]
0004074B movzx eax, byte ptr [ebp+CurrentTime+2]
0004074F add _EncryptionKeyCount, 100h
00040759 mov edx, ecx
0004075B shl edx, 8
0004075E lea esi, [eax-1]
00040761 or edx, esi
00040763 mov esi, ds:__imp__RtlRandom@4
00040769 shl edx, 8
0004076C or edx, eax
0004076E shl edx, 8
00040771 inc ecx
00040772 lea eax, [ebp+Seed]
00040775 or edx, ecx
Then it calls the ntoskrnl.exe!RtlRandom(&seed) function three times, using
as a 'seed' the value with the pattern shown above. Each call to
ntosrnkl.exe!RtlRandom(&seed)
returns in 'seed' a different value (meaning each call does not use the
same value as a 'seed').
00040777 push eax
00040778 mov [ebp+Seed], edx
0004077B call esi ; RtlRandom(x)
0004077D mov [ebp+var_18], eax
00040780 lea eax, [ebp+Seed]
00040783 push eax
00040784 call esi ; RtlRandom(x)
00040786 mov ebx, eax
00040788 lea eax, [ebp+Seed]
0004078B push eax ; Seed
0004078C call esi ; RtlRandom(x)
The calls to ntoskrnl.exe!RtlRandom(&seed) generate 3 'random' numbers.
Based on the value of random_number3, random_number1 and random_number2 are
modified:
0004078E test al, 1
00040790 mov ecx, 80000000h
00040795 jz short loc_4079A
00040797 or [ebp+var_18], ecx
0004079A
0004079A loc_4079A:
0004079A test al, 2
0004079C jz short loc_407A0
0004079E or ebx, ecx
000407A0
000407A0 loc_407A0:
Finally, the code returns the challenge in the form
bytes(random_number1, random_number2)
000407A0 mov eax, [ebp+var_18]
000407A3 mov ecx, [ebp+var_4]
000407A6 mov [edi+4], ebx
000407A9 mov [edi], eax
000407AB pop edi
000407AC pop esi
000407AD pop ebx
000407AE call @__security_check_cookie@4
000407B3 leave
000407B4 retn 4
Next is pseudo-code for the function srv.sys!GetEncryptionKey():
// Global Variable
DWORD _EncryptionKeyCount = 0;
srv.sys!GetEncryptionKey(byte OUT *pChallenge)
{
LARGE_INTEGER currentTime;
DWORD seed;
DWORD random_number1, random_number2, random_number3;
KeQuerySystemTime(&CurrentTime);
CurrentTime.LowPart += _EncryptionKeyCount;
_EncryptionKeyCount += 0x100;
CT = CurrentTime.LowPart;
seed = CT[1], CT[2]-1, CT[2], CT[1]+1;
random_number1 = ntoskrnl.exe!RtlRandom(&seed);
random_number2 = ntoskrnl.exe!RtlRnadom(&seed);
random_number3 = ntoskrnl.exe!RtlRandom(&seed);
if ( (random_number3 & 1) == 1) {
random_number1 |= 0x80000000
}
if( (random_number3 & 2) == 2 ) {
random_number2 |= 0x80000000
}
*pChallenge = bytes(random_number1, random_number2);
}
The code for ntoskrnl.exe!RtlRandom(&seed) is the following:
It receives the seed and performs the following calculations:
X0 = *seed;
X1 = (a*X0 + b ) mod m
where:
a = 0x7FFFFFED
b = 0x7FFFFFC3
m = 0x7FFFFFFF
004B5B75 mov edi, edi
004B5B77 push ebp
004B5B78 mov ebp, esp
004B5B7A push ebx
004B5B7B push esi
004B5B7C mov esi, [ebp+Seed]
004B5B7F mov eax, [esi]
004B5B81 imul eax, 7FFFFFEDh
004B5B87 push edi
004B5B88 mov ecx, 7FFFFFC3h
004B5B8D add eax, ecx
004B5B8F mov edi, 7FFFFFFFh
004B5B94 xor edx, edx
004B5B96 mov ebx, edi
004B5B98 div ebx
With the X1 value performs similar calculations:
X2 = (a*X1 + b) mod m
004B5B9A mov ebx, edx
004B5B9C mov eax, edx
004B5B9E imul eax, 7FFFFFEDh
004B5BA4 add eax, ecx
004B5BA6 xor edx, edx
004B5BA8 div edi
It sets the value of seed to X2
004B5BAA pop edi
004B5BAB mov [esi], edx
it calculates (X2 & 0x7F) to generate an index for the
_RtlpRandomConstantVector
004B5BAD and edx, 7Fh
004B5BB0 lea ecx, _RtlpRandomConstantVector[edx*4]
and finally fetches the value found at the previously calculated index,
and also
stores the value of X1 in that position.
004B5BB7 mov eax, [ecx]
004B5BB9 pop esi
004B5BBA mov [ecx], ebx
Next is pseudo-code for the function ntoskrnl.exe!RtlRandom:
// Global variable
DWORD ntoskrnl.exe!RtlpRandomConstantVector [128] = {...}
DWORD ntoskrnl.exe!RtlRandom(DWORD *pseed)
{
DWORD a = 0x7FFFFFED;
DWORD b = 0x7FFFFFC3;
DWORD m = 0x7FFFFFFF;
DWORD X0, X1, X2;
X0 = *pseed;
X1 = ( a*X0 + b ) mod m
X2 = ( a*X1 + b ) mod m
*pseed = X2;
ndx = X2 & 0x7F;
n = RtlpRandomConstantVector[ndx];
RtlpRandomConstantVector[ndx] = X1;
return n;
}
In Summary,
The srv.sys!GetEncryptionKey() does the following:
- Gets current time, takes the low part (4 bytes) and adds the value
of _EncryptionKeyCount (4-bytes)
- Increments _EncryptionKeyCount by 0x100
- Takes the two 'middle' bytes of CT=(current time.lowpart +
_EncryptionKeyCount) and creates
a seed with the form CT[1], CT[2]-1, CT[2], CT[1]+1.
- Calls ntoskrnl.exe!RtlRandom three times and obtains three random
numbers (random1,random2,random3)
- Depending on the value of random3, makes some modifications to
random1 and random2
- creates the challenge by creating an array of bytes in the form
random1, random2
The ntoskrnl.exe!RtlRandom function appears to be a Maclaren-Marsaglia
PRNG algorithm using two LCGs (linear congruential generators) [4] with
a vector of 128 bytes.
We know the following facts:
- _EncryptionKeyCount starts with a value of 0
- _EncryptionKeyCount is only modified by srv.sys!GetEncryptionKey.
The code that calls srv.sys!GetEncryptionKey() is not regularly
triggered, but only when the SMB service receives a packet like the one
we use with the 'flags2' field set to 0xc001
- We have not observed 'modern' Windows systems (Windows XP SP3,
Vista, 7, etc) generate these kind of packets
- This allows us to expect that before start conducting an attack
against any 'modern' Windows system, _EncryptionKeyCount will always be
0; by keeping count of the number of packets we send, we can also
calculate the value of _EncryptionKeyCount for further connections
- Interestingly enough, in our tests, the value of Current Time used
by srv.sys!GetEncryptionKey to generate the seed was the same value
returned by the SMB service to the client in the field 'System Time' of
an 'SMB Negotiate Protocol Response' packet
- The initial state of the vector used by ntoskrnl.exe!RtlRandom is
hard-coded, but it is modified every time the function is called and it
is called every time a new process is created (modifications might not
be that many).
Based on these facts we implemented the following attack to predict
challenges:
- We set the vector used by ntoskrnl.exe!RtlRandom to a 'known state'
-To do this we send multiple 'SMB Negotiate Protocol Request' packets
with the 'flags2' field set to 0xc001 to trigger
srv.sys!GetEncryptionKey which in turns calls ntoskrnl.exe!RtlRandom
modifying its internal vector (~300 packets)
-Since we know the seed used by the server to perform the previous
actions, because it is in the 'System Time' field of the 'SMB Negotiate
Protocol Response' packet we receive, and we also know all the other
variables including the value of _EncryptionKeyCount, we can do the same
calculations updating our own vector
-We repeat this process until all 128 values of our vector are
calculated. At this point we know the state of the table on the remote
system, we know all of its values and their position within the vector.
- We calculate all possible challenges that can be generated with that
'known state' next time srv.sys!GetEncryptionKey is called
- We force the victim to connect to our specially crafted SMB server
to get all those challenges encrypted with the credentials of the victim
(an average of ~16000 to ~48000 possible challenges)
- At this point we know that if we send another authentication request
to the victim the challenge returned will be one of the pre-calculated
challenges. We make the connection, get the challenge, look for the
corresponding response we obtained from the victim, and authenticate to
the SMB service.
6.5.2.Proof-of-Concept Exploit
------------------------------
Next are the necessary steps to perform the attack:
- Run predictor.rb against the victim. E.g.: ruby predictor.rb
192.168.1.110
This script will show the progress of 'setting' the values of the
victims RtlRandom's internal vector.
It will display something like this:
(0x00-0x04) 0x00000000 0x00000000 0x00000000 0x2948d15b
(0x04-0x08) 0x72f4dda5 0x00000000 0x14dbf86f 0x00000000
(0x08-0x0c) 0x00000000 0x62d2c31e 0x00000000 0x7ef9db03
(0x0c-0x10) 0x00000000 0x0dfdee4d 0x00000000 0x0ecd0d97
(0x10-0x14) 0x00000000 0x04d986e1 0x00000000 0x00000000
(0x14-0x18) 0x00000000 0x35fdf275 0x00000000 0x00000000
(0x18-0x1c) 0x00000000 0x47b6b289 0x00000000 0x00000000
(0x1c-0x20) 0x5b9a7eb8 0x00000000 0x00000000 0x3b150ecc
(0x20-0x24) 0x146909b1 0x7a3022b1 0x00000000 0x00000000
(0x24-0x28) 0x23bfb6e0 0x00000000 0x00000000 0x0e5c7c0f
(0x28-0x2c) 0x3f027a59 0x00000000 0x00000000 0x00000000
(0x2c-0x30) 0x00000000 0x00000000 0x6a3158d2 0x00000000
(0x30-0x34) 0x69d97001 0x2cd5c5e6 0x00000000 0x2cdcb5b0
(0x34-0x38) 0x00000000 0x00000000 0x00000000 0x00000000
(0x38-0x3c) 0x00000000 0x00000000 0x00000000 0x00000000
(0x3c-0x40) 0x08deca3d 0x4954003d 0x00000000 0x00f5b207
(0x40-0x44) 0x4de0efd1 0x00000000 0x00000000 0x56bf3780
(0x44-0x48) 0x25210c65 0x00000000 0x00000000 0x00000000
(0x48-0x4c) 0x00000000 0x00000000 0x00000000 0x00000000
(0x4c-0x50) 0x00000000 0x00000000 0x00000000 0x00000000
(0x50-0x54) 0x00000000 0x397415a1 0x34aa91eb 0x00000000
(0x54-0x58) 0x231aeb35 0x00000000 0x00000000 0x00000000
(0x58-0x5c) 0x00000000 0x04223749 0x00000000 0x1b4c91f8
(0x5c-0x60) 0x00000000 0x00000000 0x00000000 0x71ad9da7
(0x60-0x64) 0x00000000 0x00000000 0x00000000 0x046696bb
(0x64-0x68) 0x00000000 0x00000000 0x193b264f 0x439ef5b4
(0x68-0x6c) 0x5bdd2f34 0x00000000 0x00000000 0x481eaee3
(0x6c-0x70) 0x00000000 0x00000000 0x50b1e1f7 0x2a8d71dc
(0x70-0x74) 0x00000000 0x02240f41 0x0ae7948b 0x37af3d8b
(0x74-0x78) 0x00000000 0x00000000 0x77130a3a 0x640bf49f
(0x78-0x7c) 0x31665169 0x20a1c769 0x00000000 0x00000000
(0x7c-0x80) 0x6958e618 0x00000000 0x00000000 0x00000000
known values: 48/128
- When predictor.rb finishes, it writes the values of the vector to
'x_values.log' (it also generates a file 't_values.log' containing the
'current times' observed in the 'SMB Negotiate Protocol Response' packets).
- Run generate_challenges.rb, it will generate the file
'challenges.log' with all the possible challenges based on 'x_values.log'.
- Run savecreds.rb, it will wait for incoming connections on port 445/tcp
- On the victim, use 'predict.html' with Internet Explorer to perform
SMB connections to savecreds.rb's server
You will need to change the IP address of the server where savecreds.rb
is running in 'predict.html', and
also the number of connections to perform (look for the line: 'if (id
== 50000) {' and change accordingly).
The number of connections that need to be performed is shown by
savecreds.rb.
- When savecreds.rb is finished, a file 'fullcreds.log' will be created
- Now use the metasploit module msf_smb_weak_nonce.rb as explained
before with the recently generated 'fullcreds.log' against the victim
- You should be able to authenticate with the victim at the ~first attempt
Sometimes the challenge is correctly 'guessed' at the first attempt,
but the attack fails because of some SMB error. If this happens please
note that the challenge was indeed correctly predicted.
Also note that since the internal vector is not completely modified
after just one connection, the exploit will actually be able to predict
more challenges (you might be able to run the metasploit exploit
multiple times before performing the whole attack all over again).
The predictor.rb assumes the EncryptionKeyCount is 0. If you want to
run the attack multiple times you
just need to modify its value in predictor.rb. The value of
EncryptionKeyCount after the attack is displayed by predictor.rb when it
terminates (you need to use the value displayed + 0x100).
After generate_challenges.rb is executed, if the number of possible
challenges is 'too big' (~48000 or more) you
might want to run predictor.rb again. The size of the set of possible
challenges vary according to the values in the vector. Remember to
adjust EncryptionKeyCount before running predictor.rb. We recommend
peforming the attack when EncryptionKeyCount is 0 specially if this is
the first time this proof-of-concept is used.
This is just a proof-of-concept exploit, it can be improved and optimized.
7.References
------------
[1] Microsoft SMB Protocol and CIFS Protocol Overview
http://msdn.microsoft.com/en-us/library/aa365233(VS.85).aspx
[2] Microsoft NTLM
http://msdn.microsoft.com/en-us/library/aa378749(VS.85).aspx
[3] Microsoft Security Bulletin Advance Notification for February 2010
http://www.microsoft.com/technet/security/Bulletin/ms10-feb.mspx
[4] Bruce Schneier, Applied Cryptography (Second Edition), 1996.
Chapter 16, pp 369.
8.Disclaimer
------------
The contents of this advisory are copyright (c) 2010 Hernan Ochoa, and
may be distributed freely provided that no fee is charged for
distribution and proper credit is given.
]]>