0% found this document useful (0 votes)
16 views22 pages

Cracking SF License System

The document discusses the vulnerabilities in Cisco's Sourcefire licensing system, detailing the components of the system and the necessity of valid licenses for operation. It outlines methods for bypassing license validation, including modifying binaries and creating custom license generators. The author provides technical insights and tools for achieving these bypasses, emphasizing the implications of such actions on system functionality.

Uploaded by

Ranjit Singh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
16 views22 pages

Cracking SF License System

The document discusses the vulnerabilities in Cisco's Sourcefire licensing system, detailing the components of the system and the necessity of valid licenses for operation. It outlines methods for bypassing license validation, including modifying binaries and creating custom license generators. The author provides technical insights and tools for achieving these bypasses, emphasizing the implications of such actions on system functionality.

Uploaded by

Ranjit Singh
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 22

Cracking Cisco’s Sourcefire licensing system

Jose Gonzalez Krause


email: [email protected]
twitter: @bitsniper

February 20, 2018

1
1 The problem
Cisco’s Sourcefire system is the IDS/IPS solution offered by this company after the ac-
quisition of Sourcefire, including its network anomaly detection engine, Snort. This IPS
solution is one of the more powerful systems available on the market.
The system is composed mainly by two appliances:

• The sensor –FirePOWER–, is the IPS itself with Snort, the RNA –Real Network
Awareness– engine, nmap, the signature database and all the stuff that makes sense
on an IPS. This appliance is mainly physical but Cisco offers also a virtual appliance
option available on the customer support portal.

• The manager –FireSIGHT Management center (FSM)–, is the central administra-


tion console, one FSM can have attached multiple sensors, and all the configuration
is done here, so as policy creation, firewall rules, object setup, rule edition, etc. Once
configured or modified some policy the whole config/rule/stuff package is deployed
to the paired sensors. This element can be run as a virtual appliance available on
the Cisco customer support portal.

The main problem of Cisco’s Sourcefire system is that the hardware is completely useless
without a valid license. After buying a sensor on Ebay or scavenging one from a death
project or whatever, a license is still needed to make them to work, and yes, these licenses
are not exactly cheap...
In this writeup I’ll use the following laboratory setup:

• Virtual FSM on version 5.4.1.9

• Physical sensor 3D2000 on version 5.4.0.9

• Physical sensor 3D7110 on version 5.4.0.9

In this writeup I’ll make use of some custom tools and scripts, all this code is available
on my git —https://dev.hackercat.ninja/hcninja/sflicense— server.
At least, but not less important, the bypass techniques exposed in this paper are also
applicable to the latest versions of Sourcefire sensors and FSMs —Tested on FSM version
6—. According to Cisco, neither its ASA nor the new Firepower Threat Defense appliances
are susceptible to the demonstrated license bypass. However, I am not able to confirm or
deny this as I haven?t had the chance to test those systems.
Lets go!

2
2 The license file
The first step was to find out what a license file actually contains, fortunately I’m currently
working with multiple FireSIGHT appliances and I have access to plenty of original valid
licenses, let’s look at one:

Figure 1: Product license

This license actually looks like a PEM encoded certificate, but looking inside undoing
the base64 encoding

Figure 2: License content

3
The license is in fact a bunch of metadata regarding the license –red– and a binary
signature appended after it –green– the serial number is a integer that doesn’t seems to be
a timestamp, and the node is the MAC address of the device.
But, how do we request a new license? What data should we provide to request a
license? The request process is easy, the only thing we must do is go to the license option
in the FSM and click the option for adding a new license:

Figure 3: License content

Here we can see that the necessary data is the ”License Key”, and a PAK code given
in the documentation of the appliance –this code wouldn’t be necessary for our purposes–,
but, what is actually this code? It is a device type code ”66” in hexadecimal 0x42, do you
remember this number from the license file? And the MAC address of the FSM –in case
the license is for a FSM appliance–.
Now that we know how a license is built, let’s try to load a modified one, and yes, it
doesn’t work, the console launches a beautiful Failed [ signature ] error.
Once we know this details, let us search around to look for the process that validates
the licenses.

4
3 Checking the validation system
One of the great things about the FireSIGHT systems is that all the appliances are built
on top of a custom linux distribution, with active SSH server and root access.
Looking and greping around, points us on a Perl module, /var/sf/lib/perl/5.10.1/SF/System.pm,
this perl module contains all the stuff regarding to FireSIGHT system interactions.

Figure 4: License parsing function

The important part here seems to be the ”Run checklic” line. Looking for the $SFBINPATH
variable declaration we can locate the called program ”checklic” in the path /usr/local/sf/bin/.

5
Now let’s see what this program actually is:

# file /usr/local/sf/bin/checklic
checklic: ELF 64-bit LSB executable, x86-64, version 1 (SYSV),
dynamically linked (uses shared libs), for GNU/Linux 2.6.0, stripped

Ok, we have here a nice stripped binary executable, let’s try to execute it with the flag
-h:

Copyright Sourcefire 2013


-v version
-h this message
-f [filename]
-k [keyfile]
-q quietmode
-d dump contents of license
-F dump feature licenses

Bingo! thanks Cisco! running the version command returns:

Authentication version 1

The perl module, as seen supra, uses the flags -d and -f passing to it a license file, the
output of a valid license is:

Valid license
[model: 0x42]
[expires: forever]
[node: 00:11:22:33:44:55]
[serial_number: 123456789]
[feature_id: 0xC]
[model_info: 66E:5000:HOST,66E:5000:USER]
[66E: VirtualDC64bit]

The resulting output, is the parsed license information with a ”license status” header,
as shown in the checklic_parse function, we have six different options:

• AUTH_LICENSE_NOT_CHECKED => 0x00;

• AUTH_LICENSE_VALID => (1<<0);

• AUTH_LICENSE_DATE_INVALID => (1<<1);

• AUTH_LICENSE_SIG_INVALID => (1<<2);

6
• AUTH_LICENSE_NODE_INVALID => (1<<3);

• AUTH_LICENSE_MODEL_INVALID => (1<<4);

• AUTH_LICENSE_OTHER_INVALID => (1<<7);

This constants are defined in the perl module /var/sf/lib/perl/5.10.1/SF/Auth.pm

7
4 Bypassing the license validation
The easiest way to bypass the validation system is always returning the $AUTH_LICENSE_VALID
constant, no matters of the real checklic binary output. Ok, it works... but it’s a pretty
boring and ugly solution.

4.1 The imitation game


Another easy solution is replacing the checklic binary by one of our design, one that parses
the given license and returns a Valid license header.
As expected, after some few lines of code for the parser we accomplished our goal with
a nice license validator. The cons of this approach is that ANY license will be validated,
and this could lead to system malfunctions due to zero license sanity checks.

4.2 A nicer but not so appropriate approach


Let’s go a step further, let’s look inside the binary to check the validation flow. The first
thing to look for is the string Failed [ something ], this is the output of the license
validation failure, after digging a little around this appears:

Figure 5: Failed string

This points with a XREF to 0x402a2c and this is part of a procedure that validates
the license on address 0x4029da

8
Figure 6: License validation procedure

After a fast inspection of the flow, it’s easy to deduct that changing the instruction
on address 0x402a05 from 0x0 to 0x1 will jump directly over the validation, avoiding the
failed status and move the execution straight to address 0x402ba8, getting our wanted
Valid license response

Figure 7: Valid license loc

9
Applying the next patchline will do the job:

printf ’\x01’ | dd seek=$((0x2a08)) conv=notrunc bs=1 of=/usr/local/sf/bin/checklic

The bad news here are that any original license will stop working due to a nice ”Failed
[ license ]” message, this will include the already loaded and validated licenses and the new
not yet uploaded ones.
To make both work it will take some more effort patching the binary, modifying multiple
parts of sub_4029da, but our approach is anyway not too shabby.
Let’s try an even more elegant solution.

10
5 Searching for the signature certificate
One thing is clear, the license file is signed, and where a signature is it must be a valid
certificate/signing key. The first thing that I tried was to locate all the .pem, .der and
.key files without luck, there are plenty of certificates and keys but none of them is the
one we are looking for.

5.1 Intercepting the validation system


If we remember, there is a param for a key on the checklic binary, lets try to find when it’s
passed to the binary replacing the original checklic by a wrapper that logs all the calls to
the binary –important is to maintain the same permissions and owners–.
The following bash script was used in place of the original checklic:

#!/bin/sh

### Define or variables


cmdLine=$*
checklicBin="/Volume/home/admin/checklic"
now=‘date‘
parent="$(ps -o comm= $PPID)"
logFile="/tmp/sflicCMDLog.log"
logLine="[${now}] (Parent: $parent) $cmdLine"
evLine="${checklicBin} ${cmdLine}"

### Save the command to or logfile


echo $logLine >> $logFile

### Eval the original command calling or checklic


eval "${checklicBin} ${cmdLine}"

The purpose of this script is to log all the calls done against checklic into a log file
placed under /tmp/ and execute the original checklic with the initial params.
The first thing we notice is that it’s called every minute by Syncd.pl, asking for a
license content dump, the loaded licenses are stored under /etc/licenses.d/ in files with
the md5 of the license itself with a .lic extension.
After a while and after loading a custom license, no key is passed to the binary.
Let’s look with a strace if the application loads it from an hardcoded location with
strace checklic -d -f test.lic command, the result is also negative, the only loaded
files are multiple shared objects from standard libraries, some bus files and a configuration
file –/etc/sf/ims.conf– that hasn’t any clue for our problem.

11
5.2 Looking inside the guts of checklic revisited
Let’s recap, the signature certificates/keys/whatever aren’t stored on disk –apparently– nor
is checked against any remote server through an internet access –our FSM isn’t connected
to the internet–, so, the only place where this keys could be is embedded into the binary.
After a fast visual inspection of the entropy of the disassembled binary an interesting
zone appeared at the bottom right corner

Figure 8: Entropy map

This section contains a big chunk of random data, and the segment has a very descriptive
name gPublicKeys

Figure 9: Public keys segment

The segment contains basically two chunks of random data separated by some null
bytes. After dumping this two chunks, the first thing that catches our attention is the
difference in the size of the first chunk with 449 bytes and the second one with 558 bytes,
the other thing is that both chunks end with 0x02, 0x03, 0x01, 0x00, 0x01 –in red,
infra– this is characteristic of an ASN1 DER encoded data structure.
Digging a little bit deeper at the data chunks, it’s clearly visible that these chunks have
a padding –in green, infra–, and after it, a sequence of the beginning of an ASN1 DER

12
encoded public RSA key – x30, x82, x02, x0a, x02, x82, x02, x01, x00–, this is the
typical and characteristic MII begin of a base64 encoded RSA PEM key

Figure 10: RSA key one

Figure 11: RSA key two

The procedure responsible for loading the key from memory and convert it to a RSA-
PublicKey structure is sub_406482.

13
Taking a look at it we can see that the SHA1 digest of the certificate is calculated
and compared to something placed at the offset + 0x408 of the actual keys bytes chunk
position and taking 0x14 bytes from it, yes, 20 bytes, the length of a SHA1 digest!

Figure 12: Load public key

With this in mind we can teardown our extracted bytes chunk to a more coherent
structure

Figure 13: Cert structure teardown

14
Now we have an 8 byte long padding, a 526 byte long PKCS#1 RSA public Key, 498
null bytes, a 20 bytes SHA1 digest –presumable of the RSA key– and a 4 bytes trail.
The PKCS#1 is decoded to a RSAPublicKey on loc_406560

Figure 14: PKCS#1 decode

Now that we know the exact offsets of the certificate components, let’s dump the
embedded RSA key.

dd skip=$((0x10b48)) conv=notrunc bs=1 count=526 if=checklic of=cert1_dump.der

This will dump the first certificate to a file, and after calculating the SHA1 digest of
it, bingo!

# shasum -a1 cert1_dump.der


2321e92d7da24a5fd85d94ee21713eb43f511af2

Thats the same one of the data chunk.

5.3 Patching the binary with our keys


The first try was to generate a RSA key pair of 4096 bits with OpenSSL, but it didn’t
worked, my second try was to create my own RSA Key generator with go –the code is
available on my git–.
Once generated the key pair I prepared the public.der file for a proper patchline with

hexdump -ve ’1/1 "_x%.2x"’ public.der |sed ’s/_/\\/g’; echo ""

the second step was calculate the SHA1 and formatting it the same way.
With the public key and the hash, the composition of our patchlines is easy as:

15
printf ’\x30\x82\x02\x0a[...]\x03\x01\x00\x01’ | dd seek=$((0x10b48)) \
conv=notrunc bs=1 of=checklic_patched

For the key, and:

printf ’\x3A[...]\xE8’ | dd seek=$((0x10f48)) conv=notrunc bs=1 \


of=checklic_patched

For the hash, and this is it, now, our checklic binary is patched for our own RSA keys,
this patch must be applied to any device that will make use of a custom signed license,
this is for every sensor and FSM.
The next step will be create our own license generator!

16
6 Building our own license generator
Actually we know how a license looks like:

model 0x42;
expires forever;
node 00:11:22:33:44:55;
serial_number 123456789;
feature_id 0xC;
model_info 66E:50000:HOST,66E:50000:USER;
66E VirtualDC64bit;
---${signature}

The most important things we need to know here is what the feature_id and the
model codes actually are, after greping and finding a little around I came against these
perl modules:

• /var/sf/lib/perl/5.10.1/SF/LicenseCaps.pm

• /var/sf/lib/perl/5.10.1/SF/Sensor.pm

At the beginning of the LicenseCaps.pm file we can find the allowed capabilities map,
this will be perfect for defining our sensor license capabilities.

Figure 15: License allowed capabilities

17
In our case we will use the full suite of capabilities, it’s free! except the MALWARE one,
this feature makes use of Cisco’s Cloud, and I hope that there are more controls on the
Cloud side –further tests will confirm this–, so, our sensor capabilities line will end as:
[series_3_model_info: MMM:N:PROTECT+CONTROL+VPN+SSL]
For the basic license and other one with a subscription type license for the URLFilter
capability. This kind of licenses are a little different from the capability licenses:
model 0x42;
expires forever;
node 00:11:22:33:44:55;
serial_number 123456789;
feature_id 0xB;
model_info MMM:N:URLFilter;
MMM 3DXXXX;
license_type SUBSCRIPTION;
Being MMM the model info, N the number of licenses –one for each sensor– and XXXX the
model name.
The next interesting information is around line 248, where the following variables are
defined:
• $FEATURE_CODE_SERIES3 = 0x0A;
• $FEATURE_CODE_URLFILTER = 0x0B;
• $FEATURE_CODE_FIRESIGHT = 0x0C;
• $FEATURE_CODE_VIRTUAL = 0x09;
• $FEATURE_CODE_XBEAM = 0x06;
These variables are defining the feature_id. In our case, the useful ones are 0xA for
Series 3 sensors and 0xC for FSM appliances.
On the Sensor.pm the only useful thing we can find for our purposes, are the following
definitions

Figure 16: Sensor models definitions

18
Figure 17: Sensor network modules definitions

But this is not really interesting for our needs.


The only useful thing I found for determining the device model ID is, after a correct
device pairing, sshing again into the FSM and query the database directly

mysql -u root -padmin sfsnort -e "SELECT ip,model_number,model_id FROM sensor;"

+----------------+--------------+----------+
| ip | model_number | model_id |
+----------------+--------------+----------+
| 10.0.1.5 | 66 | E |
| 10.0.1.14 | 63 | E |
+----------------+--------------+----------+

This will be our model number for a 3D8120 sensor; 63E.


And this tied all together is the metadata of our license, this all is followed by a
separation of three dashes --- and appending the signature done with our private RSA
key in DER format of all the metadata except the three dashes. This process will be clearer
after a look on the code available on the aforementioned git repository.

19
7 Cracking guide
Do this at your own risk!

Cracking software is ilegal and unmoral, please use this only for testing and
educational purposes

7.1 RSA key generation


For the generation of our own RSA keys that later will sign our licenses execute:

go run rsaGen.go

This will generate a public and a private RSA key of 4096 bits. To generate the proper
patchline, the public key must be formatted with:

hexdump -ve ’1/1 "_x%.2x"’ public.der |sed ’s/_/\\/g’

7.2 Calculate the SHA1 of the public key


To calculate and format the RSA public key SHA1 hash on MacOS, use:

shasum -a1 crypto/public.der |cut -d" " -f1 | \


sed -E ’s/(.{2})/\1\\x/g’ |rev |cut -d"\\" -f2- |rev

7.3 Prepare the patchlines (x86-64 version)


The following commands will be responsible for patching the binary, only for 64 bits version,
for the 32 bits versions (Series 2) the procedure is the same, the only thing that changes is
the patch address.
The first one will write our new generated RSA key to the binary and the second line
will write the SHA1 hash to the binary.

Make a security copy of the checklic binary before this

printf ’${your_formated_public_key}’ | \
dd seek=$((0x10b48)) conv=notrunc bs=1 of=${target}

printf ’${your_formated_sha1}’ | \
dd seek=$((0x10f48)) conv=notrunc bs=1 of=${target}

20
7.4 Patch!
SSH into the FSM and get sudo, execute the two patchlines changing the ${target} for
the checklic binary.
Repeat the same process on all your Sensors.

7.5 Generate your licenses


For a FSM license run:

go run sflicgen.go -l 66:00:11:22:33:44:55 \


-k ../crypto/private.pem -fsm

and for a sensor license run:

go run sflicgen.go -l 66:00:11:22:33:44:55 \


-k ../crypto/private.pem -n 6 -mid 63E -mod 3D8120

Register them on your FSM, assign the capabilities to your sensors and enjoy.

Figure 18: Uploaded licenses

21
8 Conclusions
Protecting such a device from reverse engineering is extremely painful or impossible at all,
especially if the designer wants that the final user enjoys some ”open device” experience.
There are some alternatives to remediate this:
One alternative is closing the appliance to a point that it will converted into a blackbox,
only accessible to the technical support team, making the final user think about the actually
risks of letting inside its infrastructure a closed piece of hardware that nobody knows what
it actually does.
Another, more elegant solution, could be add an integrity check on the kernel or
initramd for detecting modifications on critical system components, this is not a hun-
dred percent effective solution, but it could increase the difficulty of this kind of hacks
enormously.

22

You might also like