INSIGHTS | January 17, 2013

Offensive Defense

I presented before the holiday break at Seattle B-Sides on a topic I called “Offensive Defense.” This blog will summarize the talk. I feel it’s relevant to share due to the recent discussions on desktop antivirus software   (AV)

What is Offensive Defense?

The basic premise of the talk is that a good defense is a “smart” layered defense. My “Offensive Defense” presentation title  might be interpreted as fighting back against your adversaries much like the Sexy Defense talk my co-worker Ian Amit has been presenting.

My view of the “Offensive Defense” is about being educated on existing technology and creating a well thought-out plan and security framework for your network. The “Offensive” word in the presentation title relates to being as educated as any attacker who is going to study common security technology and know it’s weaknesses and boundaries. You should be as educated as that attacker to properly build a defensive and reactionary security posture. The second part of an “Offensive Defense” is security architecture. It is my opinion that too many organizations buy a product to either meet the minimal regulatory requirements, to apply “band-aide” protection (thinking in a point manner instead of a systematic manner), or because the organization thinks it makes sense even though they have not actually made a plan for it. However, many larger enterprise companies have not stepped back and designed a threat model for their network or defined the critical assets they want to protect.

At the end of the day, a persistent attacker will stop at nothing to obtain access to your network and to steal critical information from your network. Your overall goal in protecting your network should be to protect your critical assets. If you are targeted, you want to be able to slow down your attacker and the attack tools they are using, forcing them to customize their attack. In doing so, your goal would be to give away their position, resources, capabilities, and details. Ultimately, you want to be alerted before any real damage has occurred and have the ability to halt their ability to ex-filtrate any critical data.

Conduct a Threat Assessment, Create a Threat Model, Have a Plan!

This process involves either having a security architect in-house or hiring a security consulting firm to help you design a threat model tailored to your network and assess the solutions you have put in place. Security solutions are not one-size fits all. Do not rely on marketing material or sales, as these typically oversell the capabilities of their own product. I think in many ways overselling a product is how as an industry we have begun to have rely too heavily on security technologies, assuming they address all threats.

There are many quarterly reports and resources that technical practitioners turn to for advice such as Gartner reports, the magic quadrant, or testing houses including AV-Comparatives, ICSA Labs, NSS Labs, EICAR or AV-Test. AV-Test , in fact, reported this year that Microsoft Security Essentials failed to recognize enough zero-day threats with detection rates of only 69% , where the average is 89%. These are great resources to turn to once you know what technology you need, but you won’t know that unless you have first designed a plan.

Once you have implemented a plan, the next step is to actually run exercises and, if possible, simulations to assess the real-time ability of your network and the technology you have chosen to integrate. I rarely see this done, and, in my opinion, large enterprises with critical assets have no excuse not to conduct these assessments.

Perform a Self-assessment of the Technology

AV-Comparatives has published a good quote on their product page that states my point:

“If you plan to buy an Anti-Virus, please visit the vendor’s site and evaluate their software by downloading a trial version, as there are also many other features and important things for an Anti-Virus that you should evaluate by yourself. Even if quite important, the data provided in the test reports on this site are just some aspects that you should consider when buying Anti-Virus software.”

This statement proves my point in stating that companies should familiarize themselves with a security technology to make sure it is right for their own network and security posture.

There are many security technologies that exist today that are designed to detect threats against or within your network. These include (but are not limited to):

  • Firewalls
  • Intrusion Prevention Systems (IPS)
  • Intrusion Detectoin Systems (IDS)
  • Host-based Intrusion Prevention Systems (HIPS)
  • Desktop Antivirus
  • Gateway Filtering
  • Web Application Firewalls
  • Cloud-Based Antivirus and Cloud-based Security Solutions

Such security technologies exist to protect against threats that include (but are not limited to):

  • File-based malware (such as malicious windows executables, Java files, image files, mobile applications, and so on)
  • Network-based exploits
  • Content based exploits (such as web pages)
  • Malicious email messages (such as email messages containing malicious links or phishing attacks)
  • Network addresses and domains with a bad reputation

These security technologies deploy various techniques that include (but are not limited to):

  • Hash-detection
  • Signature-detection
  • Heuristic-detection
  • Semantic-detection
There are of course others  techniques (that I won’t go into great detail in this blog on) for example:
  • Reputation-based
  • Behavioral based
It is important to realize that there is no silver bullet defense out there, and given enough expertise, motivation, and persistence, each technique can be defeated. It is essential to understand the limitations and benefits of a particular product so that you can create a realistic, layered framework that has been architected to fit your network structure and threat model. The following are a few example attack techniques against each protection technique and technology (these have been widely publicized):

 

 

For the techniques that I have not listed in this table such as reputation, refer to my CanSecWest 2008 presentation “Wreck-utation“, which explains how reputation detection can be circumvented. One major example of this is a rising trend in hosting malicious code on a compromised legitimate website or running a C&C on a legitimate compromised business server. Behavioral sandboxes can also be defeated with methods such as time-lock puzzles and anti-VM detection or environment-aware code. In many cases, behavioral-based solutions allow the binary or exploit to pass through and in parallel run the sample in a sandbox. This allows what is referred to as a 1-victim-approach in which the user receiving the sample is infected because the malware was allowed to pass through. However, if it is determined in the sandbox to be malicious, all other users are protected. My point here is that all methods can be defeated given enough expertise, time, and resources.

Big Data, Machine Learning, and Natural Language Processing

My presentation also mentioned something we hear a lot about today… BIG DATA. Big Data plus Machine Learning coupled with Natural Language Processing allows a clustering or classification algorithm to make predictive decisions based on statistical and mathematical models. This technology is not a replacement for what exists. Instead, it incorporates what already exists (such as hashes, signatures, heuristics, semantic detection) and adds more correlation in a scientific and statistic manner. The growing number of threats combined with a limited number of malware analysts makes this next step virtually inevitable.

While machine learning, natural language processing, and other artificial intelligence sciences will hopefully help in supplementing the detection capabilities, keep in mind this technology is nothing new. However, the context in which it is being used is new. It has already been used in multiple existing technologies such as anti-spam engines and Google translation technology. It is only recently that it has been applied to Data Leakage Prevention (DLP), web filtering, and malware/exploit content analysis. Have no doubt, however, that like most technologies, it can still be broken.

Hopefully most of you have read Imperva’s report, which found that less than 5% of antivirus solutions are able to initially detect previously non-cataloged viruses. Regardless of your opinion on Imperva’s testing methodologies, you might have also read the less-scrutinized Cisco 2011 Global Threat report that claimed 33% of web malware encountered was zero-day malware not detectable by traditional signature-based methodologies at the time of encounter. This, in my experience, has been a more widely accepted industry statistic.

What these numbers are telling us is that the technology, if looked at individually, is failing us, but what I am saying is that it is all about context. Penetrating defenses and gaining access to a non-critical machine is never desirable. However, a “smart” defense, if architected correctly, would incorporate a number of technologies, situated on your network, to protect the critical assets you care about most.

 

 

 

The Cloud versus the End-Point

If you were to attend any major conference in the last few years, most vendors would claim “the cloud” is where protection technology is headed. Even though there is evidence to show that this might be somewhat true, the majority of protection techniques (such as hash-detection, signature-detection, reputation, and similar technologies) simply were moved from the desktop to the gateway or “cloud”. The technology and techniques, however, are the same. Of course, there are benefits to the gateway or cloud, such as consolidated updates and possibly a more responsive feedback and correlation loop from other cloud nodes or the company lab headquarters. I am of the opinion that there is nothing wrong with having anti-virus software on the desktop. In fact, in my graduate studies at UCSD in Computer Science, I remember a number of discussions on the end-to-end arguments of system design, which argued that it is best to place functionality at end points and at the highest level unless doing otherwise improves performance.

The desktop/server is the end point where the most amount of information can be disseminated. The desktop/server is where context can be added to malware, allowing you to ask questions such as:

 

  • Was it downloaded by the user and from which site?
  • Is that site historically common for that particular user to visit?
  • What happened after it was downloaded?
  • Did the user choose to execute the downloaded binary?
  • What actions did the downloaded binary take?

Hashes, signatures, heuristics, semantic-detection, and reputation can all be applied at this level. However, at a gateway or in the cloud, generally only static analysis is performed due to latency and performance requirements.

This is not to say that gateway or cloud security solutions cannot observe malicious patterns at the gateway, but restraints on state and the fact that this is a network bottleneck generally makes any analysis node after the end point thorough. I would argue that both desktop and cloud or gateway security solutions have their benefits though, and if used in conjunction, they add even more visibility into the network. As a result, they supplement what a desktop antivirus program cannot accomplish and add collective analysis.

 

Conclusion

My main point is that to have a secure network you have to think offensively by architecting security to fit your organization needs. Antivirus software on the desktop is not the problem. The problem is the lack of planing that goes into deployment as well as the lack of understanding in the capabilities of desktop, gateway, network, and cloud security solutions. What must change is the haste with which network teams deploy security technologies without having a plan, a threat model, or a holistic organizational security framework in place that takes into account how all security products work together to protect critical assets.

With regard to the cloud, make no mistake that most of the same security technology has simply moved from the desktop to the cloud. Because it is at the network level, the latency of being able to analyze the file/network stream is weaker and fewer checks are performed for the sake of user performance. People want to feel safe relying on the cloud’s security and feel assured knowing that a third-party is handling all security threats, and this might be the case. However, companies need to make sure a plan is in place and that they fully understand the capabilities of the security products they have chosen, whether they be desktop, network, gateway, or cloud based.

If you found this topic interesting, Chris Valasek and I are working on a related project that Chris will be presenting at An Evening with IOActive on Thursday, January 17, 2013. We also plan to talk about this at the IOAsis at the RSA Conference. Look for details!

INSIGHTS | November 2, 2012

iOS Security: Objective-C and nil Pointers

iOS devices are everywhere now. It seems that pretty much every other person has one…an iPhone, iPad or iPod touch – and they’re rivaled in popularity only by Android devices.

If you do secure code review, chances are that with the explosion in the number of iOS apps, you may well have done a source code review of an iOS app, or at least played around with some Objective-C code. Objective-C can be a little strange at first for those of us who are used to plain C and C++ (i.e. all the square brackets!), and even stranger for Java coders, but after a while most of us realise that the standard iOS programming environment is packed with some pretty powerful Cocoa APIs, and Objective-C itself actually has some cool features as well. The runtime supports a number of quirky features as well, which people tend to learn shortly after the standard “Hello, World!” stuff…

Objective-C brings a few of its own concepts and terminology into the mix as well. Using Objective-C syntax, we might call a simple method taking one integer parameter like this:

returnVal = [someObject myMethod:1234];

In other object-oriented languages like C++ and Java we’d normally just refer to this as “calling a member function” or “calling a method”, or even “calling a method on an object”. However, Objective-C differs slightly in this respect and as such, you do not call methods – instead, you “send a message to an object”. This concept as a whole is known as ‘message passing’.

The net result is the same – the ‘myMethod’ method associated with someObject’s class is called, but the semantics in how the runtime calls the method is somewhat different to how a C++ runtime might.

Whenever the ObjC compiler sees a line of code such as “[someObject myMethod]”, it inserts a call to one of the objc_msgSend(_XXX) APIs with the “receiver” (someObject) and the “selector” (“myMethod:”) as parameters to the function. This family of functions will, at runtime, figure out which piece of code needs to be executed bearing in mind the object’s class, and then eventually JMPs to it. This might seem a bit long-winded, but since the correct method to call is determined at runtime, this is part of how Objective-C gets its dynamism from.

The call above may end up looking something roughly like this, after the compiler has dealt with it:

objc_msgSend(someObject, “myMethod:”, 1234);

The version of objc_msgSend that is actually called into depends on the return type of the method being called, so accordingly there are a few versions of the interface in the objc_msgSend family.
For example, objc_msgSend() (for most return types), objc_msgSend_fpret() (for floating point return values), and objc_msgSend_stret(), for when the called method returns a struct type.

But what happens if you attempt to message a nil object pointer? Everyone who plays around with Objective-C code long enough soon realises that calling a method on a nil object pointer – or, more correctly, “messaging” a nil object pointer – is perfectly valid. So for example:

someObject = nil;
[someObject myMethod];

is absolutely fine. No segmentation fault – nothing. This is a very deliberate feature of the runtime, and many ObjC developers in fact use this feature to their advantage. You may end up with a nil object pointer due to an object allocation failure (out of memory), or some failure to find a substring inside a larger string, for example…

i.e.

 MyClass myObj = [[MyClass alloc] init]; // out-of-memory conditions give myObj == nil

In any case, however an object pointer got to be nil, there are certain coding styles that allow a developer to use this feature perfectly harmlessly, and even for profit. However, there are also ways that too-liberal use of the feature can lead to bugs – both functionally and security-wise.

One thing that needs to be considered is, what do objc_msgSend variants return if the object pointer was indeed found to be nil? That is, we have have

 myObj = nil;
someVariable = [myObj someMethod];

What will someVariable be equal to? Many developers assume it will always be some form of zero – and often they would be correct – but the true answer actually depends on the type of value that someMethod is defined to return.  Quoting from Apple’s API documentation:

“””
– If the method returns any pointer type, any integer scalar of size less than or equal to sizeof(void*), a float, a double, a long double, or a long long, then a message sent to nil returns 0.

– If the method returns a struct, as defined by the OS X ABI Function Call Guide to be returned in registers, then a message sent to nil returns 0.0 for every field in the struct. Other struct data types will not be filled with zeros.

– If the method returns anything other than the aforementioned value types, the return value of a message sent to nil is undefined.
“””

The second line above looks interesting. The rule on the second line deals with methods that return struct types, for which the objc_msgSend() variant called in these cases will be the objc_msgSend_stret() interface.. What the above description is basically saying is, if the struct return type is larger than the width of the architecture’s registers (i.e. must be returned via the stack), if we call a struct-returning method on a nil object pointer, the ObjC runtime does NOT guarantee that our structure will be zeroed out after the call. Instead, the contents of the struct are undefined!

When structures to be “returned” are larger than the width of a register, objc_msgSend_stret() works by writing the return value into the memory area specified by the pointer passed to objc_msgSend_stret(). If we take a look in Apple’s ARM implementation of objc_msgSend_stret() in the runtime[1], which is coded in pure assembly, we can see how it is indeed true that the API does nothing to guarantee us a nicely 0-initialized struct return value:

/********************************************************************
* struct_type    objc_msgSend_stret(id    self,
*                SEL    op,
*                    …);
*
* objc_msgSend_stret is the struct-return form of msgSend.
* The ABI calls for a1 to be used as the address of the structure
* being returned, with the parameters in the succeeding registers.
*
* On entry: a1 is the address where the structure is returned,
*           a2 is the message receiver,
*           a3 is the selector
********************************************************************/

ENTRY objc_msgSend_stret
# check whether receiver is nil
teq     a2, #0
bxeq    lr

If the object pointer was nil, the function just exits…no memset()’ing to zero – nothing, and the “return value” of objc_msgSend_stret() in this case will effectively be whatever was already there in that place on the stack i.e. uninitialized data.

Although I’ll expand more later on the possible security consequences of getting
undefined struct contents back, most security people are aware that undefined/uninitialized data can lead to some interesting security bugs (uninitialized pointer dereferences, information leaks, etc).

So, let’s suppose that we have a method ‘myMethod’ in MyClass, and an object pointer of type MyClass that is equal to nil, and we accidentally attempt to call
the myMethod method on the nil pointer (i.e. some earlier operation failed), we have:

struct myStruct {
int myInt;
int otherInt;
float myFloat;
char myBuf[20];
}

[ … ]

struct myStruct returnStruct;

myObj = nil;
returnStruct = [myObj myMethod];

Does that mean we should definitely expect returnStruct, if we’re running on our ARM-based iPhone, to be full of uninitialized junk?

Not always. That depends on what compiler you’re using, and therefore, in pragmatic terms, what version of Xcode the iOS app was compiled in.

If the iOS app was compiled in Xcode 4.0 or earlier, where the default compiler is GCC 4.2[2], messaging nil with struct return methods does indeed result in undefined structure contents, since there is nothing in the runtime nor the compiler-generated assembly code to zero out the structure in the nil case.

However, if the app was compiled with LLVM-GCC 4.2 (Xcode 4.1) or Apple LLVM (circa Xcode 4.2), the compiler inserts assembly code that does a nil check followed by a memset(myStruct, 0x00, sizeof(*myStruct)) if the object pointer was indeed nil, adjacent to all objc_msgSend_stret() calls.

Therefore, if the app was compiled in Xcode 4.1 or later (LLVM-GCC 4.2 or Apple LLVM), messaging nil is *guaranteed* to *always* result in zeroed out structures upon return – so long as the default compiler for that Xcode release is used.. Otherwise, i.e. Xcode 4.0, the struct contents are completely undefined.

These two cases become apparent by comparing the disassemblies for calls to objc_msgSend_stret() as generated by 1) GCC 4.2, and 2) Apple LLVM. See the IDA Pro screen dumps below.

 Figure 1 – objc_msgSend_stret() with GCC 4.2

Figure 2 – objc_msgSend_stret() with Apple LLVM

Figure 1 clearly shows objc_msgSend_stret() being called whether the object pointer is nil or not, and upon return from the function memcpy() is used to copy the “returned”  struct data into the place we asked the structure to be returned to, i.e. our struct on stack. If the object pointer was nil, objc_msgSend_stret() just exits and ultimately this memcpy() ends up filling our structure with whatever happened to be there on the stack at the time…

In Figure 2, on the other hand, we see that the ARM ‘CBZ’ instruction is used to test the object pointer against 0 (nil) before the objc_msgSend_stret() call, with the memset()-to-0 code path instead being taken if the pointer was indeed nil. This guarantees that in the case of the objective pointer being nil, the structure will be completely zeroed.

Thus, summed up, any iOS applications released before July 2011 are extremely likely to be vulnerable, since they were almost certainly compiled with GCC. Apps built with Xcode 4.1 and up are most likely not vulnerable. But we have to bear in mind that a great deal of developers in real-world jobs do not necessarily update their IDE straightaway, regularly, or even at all (ever heard of corporate policy?). By all accounts, it’s probable that vulnerable apps (i.e. Xcode 4.0) are still being released on the App Store today.

It’s quite easy to experiment with this yourself with a bit of test code. Let’s write some code that demonstrates the entire issue. We can define a class called HelloWorld, and the class contains one method that returns a ‘struct teststruct’ value; and the method it simply puts a ton of recognisable data into an instance of ‘teststruct’, before returning it. The files in the class definition look like this:

hello.m

#import “hello.h”

@implementation HelloWorld

– (struct teststruct)sayHello
{
// NSLog(@”Hello, world!!nn”);

struct teststruct testy;
testy.testInt = 1337;
testy.testInt2 = 1338;
testy.inner.test1 = 1337;
testy.inner.test2 = 1337;

testy.testInt3 = 1339;
testy.testInt4 = 1340;
testy.testInt5 = 1341;
testy.testInt6 = 1341;
testy.testInt7 = 1341;
testy.testInt8 = 1341;
testy.testInt9 = 1341;
testy.testInt10 = 1341;
testy.testFloat = 1337.0;
testy.testFloat1 = 1338.1;
testy.testLong1 = 1337;
testy.testLong2 = 1338;

strcpy((char *)&testy.testBuf, “hello worldn”);

return testy;
}

@end

hello.h

#import <Foundation/Foundation.h>

@interface HelloWorld : NSObject {
// no instance variables
}

// methods
– (struct teststruct)sayHello;

@end

struct teststruct {
int testInt;
int testInt2;

struct {
int test1;
int test2;
} inner;

int testInt3;
int testInt4;
int testInt5;
int testInt6;
int testInt7;
int testInt8;
int testInt9;
int testInt10;
float testFloat;
float testFloat1;
long long testLong1;
long long testLong2;
char testBuf[20];

};

We can then write a bit of code in main() that allocates and initializes an object of class HelloWorld, calls sayHello, and prints the values it received back. Then, let’s set the object pointer to nil, attempt to call sayHello on the object pointer again, and then print out the values in the structure that we received that time around. We’ll use the following code:

#import <UIKit/UIKit.h>
#import <malloc/malloc.h>
#import “AppDelegate.h”
#import “hello.h”
#import “test.h”
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
struct teststruct testStructure1;
struct teststruct testStructure2;
struct teststruct testStructure3;
struct otherstruct otherStructure;

HelloWorld *hw = [[HelloWorld alloc] init];
TestObj *otherObj = [[TestObj alloc] init];

testStructure1 = [hw sayHello];

/* what did sayHello return? */
NSLog(@”nsayHello returned:n”);
NSLog(@”testInt = %dn”, testStructure1.testInt);
NSLog(@”testInt = %dn”, testStructure1.testInt2);
NSLog(@”testInt = %dn”, testStructure1.testInt3);
NSLog(@”testInt = %dn”, testStructure1.testInt4);
NSLog(@”testInt = %dn”, testStructure1.testInt5);
NSLog(@”testInt = %dn”, testStructure1.testInt6);
NSLog(@”testInt = %dn”, testStructure1.testInt7);
NSLog(@”testInt = %dn”, testStructure1.testInt8);
NSLog(@”testInt = %dn”, testStructure1.testInt9);
NSLog(@”testInt = %dn”, testStructure1.testInt10);
NSLog(@”testInt = %5.3fn”, testStructure1.testFloat);
NSLog(@”testInt = %5.3fn”, testStructure1.testFloat1);
NSLog(@”testInt = %dn”, testStructure1.testLong1);
NSLog(@”testInt = %dn”, testStructure1.testLong2);
NSLog(@”testBuf = %sn”, testStructure1.testBuf);

/* clear the struct again */
memset((void *)&testStructure1, 0x00, sizeof(struct teststruct));
hw = nil;  // nil object ptr
testStructure1 = [hw sayHello];  // message nil

/* what are the contents of the struct after messaging nil? */
NSLog(@”nnafter messaging nil, sayHello returned:n”);
NSLog(@”testInt = %dn”, testStructure1.testInt);
NSLog(@”testInt = %dn”, testStructure1.testInt2);
NSLog(@”testInt = %dn”, testStructure1.testInt3);
NSLog(@”testInt = %dn”, testStructure1.testInt4);
NSLog(@”testInt = %dn”, testStructure1.testInt5);
NSLog(@”testInt = %dn”, testStructure1.testInt6);
NSLog(@”testInt = %dn”, testStructure1.testInt7);
NSLog(@”testInt = %dn”, testStructure1.testInt8);
NSLog(@”testInt = %dn”, testStructure1.testInt9);
NSLog(@”testInt = %dn”, testStructure1.testInt10);
NSLog(@”testInt = %5.3fn”, testStructure1.testFloat);
NSLog(@”testInt = %5.3fn”, testStructure1.testFloat1);
NSLog(@”testInt = %dn”, testStructure1.testLong1);
NSLog(@”testInt = %dn”, testStructure1.testLong2);
NSLog(@”testBuf = %sn”, testStructure1.testBuf);
}

OK – let’s first test it on my developer provisioned iPhone 4S, by compiling it in Xcode 4.0 – i.e. with GCC 4.2 – since that is Xcode 4.0’s default iOS compiler. What do we get?

2012-11-01 21:12:36.235 sqli[65340:b303]
sayHello returned:
2012-11-01 21:12:36.237 sqli[65340:b303] testInt = 1337
2012-11-01 21:12:36.238 sqli[65340:b303] testInt = 1338
2012-11-01 21:12:36.238 sqli[65340:b303] testInt = 1339
2012-11-01 21:12:36.239 sqli[65340:b303] testInt = 1340
2012-11-01 21:12:36.239 sqli[65340:b303] testInt = 1341
2012-11-01 21:12:36.240 sqli[65340:b303] testInt = 1341
2012-11-01 21:12:36.241 sqli[65340:b303] testInt = 1341
2012-11-01 21:12:36.241 sqli[65340:b303] testInt = 1341
2012-11-01 21:12:36.242 sqli[65340:b303] testInt = 1341
2012-11-01 21:12:36.243 sqli[65340:b303] testInt = 1341
2012-11-01 21:12:36.244 sqli[65340:b303] testInt = 1337.000
2012-11-01 21:12:36.244 sqli[65340:b303] testInt = 1338.100
2012-11-01 21:12:36.245 sqli[65340:b303] testInt = 1337
2012-11-01 21:12:36.245 sqli[65340:b303] testInt = 1338
2012-11-01 21:12:36.246 sqli[65340:b303] testBuf = hello world

2012-11-01 21:12:36.246 sqli[65340:b303]

after messaging nil, sayHello returned:
2012-11-01 21:12:36.247 sqli[65340:b303] testInt = 1337
2012-11-01 21:12:36.247 sqli[65340:b303] testInt = 1338
2012-11-01 21:12:36.248 sqli[65340:b303] testInt = 1339
2012-11-01 21:12:36.249 sqli[65340:b303] testInt = 1340
2012-11-01 21:12:36.249 sqli[65340:b303] testInt = 1341
2012-11-01 21:12:36.250 sqli[65340:b303] testInt = 1341
2012-11-01 21:12:36.250 sqli[65340:b303] testInt = 1341
2012-11-01 21:12:36.251 sqli[65340:b303] testInt = 1341
2012-11-01 21:12:36.252 sqli[65340:b303] testInt = 1341
2012-11-01 21:12:36.252 sqli[65340:b303] testInt = 1341
2012-11-01 21:12:36.253 sqli[65340:b303] testInt = 1337.000
2012-11-01 21:12:36.253 sqli[65340:b303] testInt = 1338.100
2012-11-01 21:12:36.254 sqli[65340:b303] testInt = 1337
2012-11-01 21:12:36.255 sqli[65340:b303] testInt = 1338
2012-11-01 21:12:36.256 sqli[65340:b303] testBuf = hello world

Quite as we expected, we end up with a struct full of what was already there in the return position on the stack – and this just happened to be the return value from the last call to sayHello. In a complex app, the value would be somewhat unpredictable.

And now let’s compile and run it on my iPhone using Xcode 4.5, where I’m using its respective default compiler – Apple LLVM. The output:

2012-11-01 21:23:59.561 sqli[65866:b303]
sayHello returned:
2012-11-01 21:23:59.565 sqli[65866:b303] testInt = 1337
2012-11-01 21:23:59.566 sqli[65866:b303] testInt = 1338
2012-11-01 21:23:59.566 sqli[65866:b303] testInt = 1339
2012-11-01 21:23:59.567 sqli[65866:b303] testInt = 1340
2012-11-01 21:23:59.568 sqli[65866:b303] testInt = 1341
2012-11-01 21:23:59.569 sqli[65866:b303] testInt = 1341
2012-11-01 21:23:59.569 sqli[65866:b303] testInt = 1341
2012-11-01 21:23:59.570 sqli[65866:b303] testInt = 1341
2012-11-01 21:23:59.571 sqli[65866:b303] testInt = 1341
2012-11-01 21:23:59.572 sqli[65866:b303] testInt = 1341
2012-11-01 21:23:59.572 sqli[65866:b303] testInt = 1337.000
2012-11-01 21:23:59.573 sqli[65866:b303] testInt = 1338.100
2012-11-01 21:23:59.574 sqli[65866:b303] testInt = 1337
2012-11-01 21:23:59.574 sqli[65866:b303] testInt = 1338
2012-11-01 21:23:59.575 sqli[65866:b303] testBuf = hello world

2012-11-01 21:23:59.576 sqli[65866:b303]

after messaging nil, sayHello returned:
2012-11-01 21:23:59.577 sqli[65866:b303] testInt = 0
2012-11-01 21:23:59.577 sqli[65866:b303] testInt = 0
2012-11-01 21:23:59.578 sqli[65866:b303] testInt = 0
2012-11-01 21:23:59.578 sqli[65866:b303] testInt = 0
2012-11-01 21:23:59.579 sqli[65866:b303] testInt = 0
2012-11-01 21:23:59.579 sqli[65866:b303] testInt = 0
2012-11-01 21:23:59.580 sqli[65866:b303] testInt = 0
2012-11-01 21:23:59.581 sqli[65866:b303] testInt = 0
2012-11-01 21:23:59.581 sqli[65866:b303] testInt = 0
2012-11-01 21:23:59.582 sqli[65866:b303] testInt = 0
2012-11-01 21:23:59.582 sqli[65866:b303] testInt = 0.000
2012-11-01 21:23:59.673 sqli[65866:b303] testInt = 0.000
2012-11-01 21:23:59.673 sqli[65866:b303] testInt = 0
2012-11-01 21:23:59.674 sqli[65866:b303] testInt = 0
2012-11-01 21:23:59.675 sqli[65866:b303] testBuf =

Also just as we expected; the Apple LLVM built version gives us all zeroed struct fields, as the compiler-inserted memset() call guarantees us a zeroed struct when we message nil.

Now, to be pragmatic, what are some potential security consequences of us getting junk, uninitialized data back, in real-world applications?

One possible scenario is to consider if we had a method, say, returnDataEntry, that, for example, returns a struct containing some data and a pointer. We could make the scenario more detailed, but for argument’s sake let’s just assume the structure holds some data and a pointer to some more data.

Consider the following code fragment, in which the developer knows they’ll receive a zeroed structure from returnDataEntry if the someFunctionThatCanFail()
call fails:

 struct someData {
int someInt;
char someData[50];
void *myPointer;
}

[ … ]

– (struct someData)returnDataEntry
{

struct someData myData;
memset((void *)&myData, 0x00, sizeof(struct someData)); /* zero it out */

if(!someFunctionThatCanFail()) {  /* can fail! */
/* something went wrong, return the zeroed struct */
return myData;
}

/* otherwise do something useful */
myData = someUsefulDataFunction();
return myData;
}

In the error case, the developer knows that they can check the contents of the struct against 0 and therefore know if returnDataEntry ran successfully.

i.e.

myData = [myObj returnDataEntry];
if(myData.myPointer == NULL) {
/* the method failed */
}

/* otherwise, use the data and pointer */

However, if we suppose that the ‘myObj’ pointer was nil at the time of the returnDataEntry call, and our app was built with a vulnerable version of Xcode, the returned structure will be uninitialized, and myData.myPointer could be absolutely anything, so at this point, we have a dangling pointer and, therefore, a security bug.

Equally, what if some method is declared to return a structure, and that data is later sent to a remote server over the network? A scenario like this could easily result in information leaks, and it’s easy to see how that’s bad.

Lastly, which is also quite interesting, let’s consider some Cocoa APIs that take structs and process them. We’ll take a bog standard structure – NSDecimal, for example. The NSDecimal structure is defined as:

typedef struct {
signed   int _exponent:8;
unsigned int _length:4;     // length == 0 && isNegative -> NaN
unsigned int _isNegative:1;
unsigned int _isCompact:1;
unsigned int _reserved:18;
unsigned short _mantissa[NSDecimalMaxSize];
} NSDecimal;

It’s pretty obvious by those underscores that all fields in NSDecimal are ‘private’ – that is, they should not be directly used or modified, and their semantics are subject to change if Apple sees fit. As such, NSDecimal structures should only be used and manipulated using official NSDecimal APIs. There’s even a length field, which could be interesting.

The fact that all fields in NSDecimal are documented as being private[3] starts to make me wonder whether the NSDecimal APIs are actually safe to call on malformed NSDecimal structs. Let’s test that theory out.

Let’s assume we got a garbage NSDecimal structure back from messaging a nil object at some earlier point in the app, and then we pass this NSDecimal struct to Cocoa’s NSDecimalString() API. We could simulate the situation with a bit of code like this:

NSDecimal myDecimal;

/* fill the two structures with bad data */
memset(&myDecimal, 0x99, sizeof(NSDecimal));

NSLocale *usLocale = [[NSLocale alloc] initWithLocaleIdentifier:@”en_US”];

NSDecimalString(&myDecimal, usLocale);

What happens?

If we quickly just run this in the iOS Simulator (x86), we crash with a write access violation at the following line in NSDecimalString():

<+0505>  mov    %al,(%esi,%edx,1)

(gdb) info reg esi edx
esi            0xffffffca    -54
edx            0x38fff3f4    956298228

Something has clearly gone wrong here, since there’s no way that address is going to be mapped and writable…

It turns out that the above line of assembly is part of a loop which uses length values derived from
the invalid values in our NSDecimal struct. Let’s set a breakpoint at the line above our crashing line, and see what things look like at the first hit of the
breakpoint, and then, at crash time.

0x008f4275  <+0499>  mov    -0x11c(%ebp),%edx
0x008f427b  <+0505>  mov    %al,(%esi,%edx,1)

(gdb) x/x $ebp-0x11c
0xbffff3bc:    0xbffff3f4

So 0xbffff3f4 is the base address of where the loop is copying data to. And after the write AV, i.e. at crash time, the base pointer looks like:

(gdb) x/x $ebp-0x11c
0xbffff3bc:    0x38fff3f4
(gdb)

Thus after a little analysis, it becomes apparent that the root cause of the crash is stack corruption – the most significant byte of the base destination address is being overwritten (with a 0x38 byte) on the stack during the loop. This is at least a nods towards several Cocoa APIs not being designed to deal with malformed structs with “private” fields. There are likely to be more such cases, considering the sheer size of Cocoa.

Although NSDecimalString() is where the crash occurred, I wouldn’t really consider this a bug in the API per se, since it is well-documented that members of NSDecimal structs
are private. This could be considered akin to memory corruption bugs caused by misuse of strcpy() – the bug isn’t really in the API as such – it’s doing what is was designed to do – it’s the manner in which you used it that constitutes a bug.

Interestingly, it seems to be possible to detect which compiler an app was built with by running a strings dump on the Info.plist file found in an app’s IPA bundle.

Apple LLVM

sh-3.2# strings Info.plist | grep compiler
“com.apple.compilers.llvm.clang.1_0

LLVM GCC

sh-3.2# strings Info.plist | grep compiler
com.apple.compilers.llvmgcc42

GCC

sh-3.2# strings Info.plist | grep compiler
sh-3.2#

What are the take home notes here? Basically, if you use a method that returns a structure type, check the object against nil first! Even if you know YOU’RE not going to be using a mid-2011 version
of Xcode, if you post your library on GitHub or similar, how do you know your code is not going to go into a widely used banking product, for example? – the developers for which may still be using a slightly older version of Xcode, perhaps even due to corporate policy.

It’d therefore be a decent idea to include this class of bugs on your secure code review checklist for iOS applications.

Thanks for reading.

Shaun.

[1] http://www.opensource.apple.com/source/objc4/objc4-532/runtime/Messengers.subproj/objc-msg-arm.s

[2] http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/WhatsNewXcode/Articles/xcode_4_1.html

[3] https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Miscellaneous/Foundation_DataTypes/Reference/reference.html

P.S. I’ve heard that Objective-C apps running on PowerPC platforms can also be vulnerable to such bugs – except with other return types as well, such as float and long long. But I can’t confirm that, since I don’t readily have access to a system running on the PowerPC architecture.

INSIGHTS | April 3, 2008

Atmel AT91SAM7S Overview

Atmel produces a number of ARM based devices in their portfolio of products. We had one laying around the lab so here we go as usual…

The device was a 48 pin QFP type package. We also purchased a sample of the other members of the family although the initial analysis was done on the AT91SAM7S32 part shown above. All pictures will relate to this specific part even though there is not a signifigant difference between the other members of this line except memory sizes.

After decapsulating the die from inside the QFP, we find a beautifully layed out 210nm 5 metal design! Thats right, 5 metal layers! Strangely enough, we would have thought this was a 220nm 5 metal but apparently Atmel doesn’t have a .22um process so this is matching their .21um.

The core runs at 1.8v and allows 1.65v operation (thus it is their ATC20 process being used). The datasheet on the device can be found here. The 32KB Flash part also contains 8KB of SRAM (that’s a lot of ram!).

Notice on this particular layout, there is CMP filler metal (e.g. dead metal, metal slugs that are not connected to anything floating in SIO2) covering almost the entire die.

The picture above actually has had the top 2 metal layers removed. Metal 5 (M5) being the highest with the CMP filler and some power planes. Metal 4 (M4) had additional power planes and routing wires.

With Metals 1-3 still present, we can get a nice overview of the floorplan now. We can see the Flash, Fuses, and SRAM clearly. The Flash has a solid coating of metal over the entire cell area which has become common from Atmel to prevent UV light attacks we suppose?

We can now label the areas on the original top metal overview photo. There is a small boot-rom loader present on the device as well and is explained in the manual.

These cells were actually on Metal 1 and 2 but there are connections via Metal 3 as well.

There were additional power planes across the lower area of the photo from Metal 4 and 5 that cover those fuses however this isn’t buying them any security if the actual lock bits were buried there. A laser can go right through it all keeping the power-bus in tact with a hole in it.

In summary, this is a very well secured device. Fuses buried in a 5 metal layer design make the Microchip DSPIC’s look like a piece of cake in comparision (They are 350nm 4 metal).

We didn’t test this, but we are sure UV will set this fuses to a bad state if you can get the light to the floating gate since most all Atmel’s behave this way.

Nice job Atmel!

INSIGHTS | February 13, 2008

Atmel CryptoMemory AT88SC153/1608 :: Security Alert

A “backdoor” has been discovered by Flylogic Engineering in the Atmel AT88SC153 and AT88SC1608 CryptoMemory.

Before we get into this more, we want to let you know immediately that this backdoor only involves the AT88SC153/1608 and no other CryptoMemory devices.

The backdoor involves restoring an EEPROM fuse with Ultra-Violet light (UV).  Once the fuse bit has been returned to a ‘1’, all memory contents is permitted to be read or written in the clear (unencrypted).

Normally in order to do so, you need to either authenticate to the device or use a read-once-given “secure code” as explained in the AT88SC153 datasheet and the AT88SC1608 datasheet.

For those of you who are unfamiliar Atmel’s CryptoMemory, they are serial non-volatile memory (EEPROM) that support a clear or secure channel of communications between a host (typically an MCU) and the memory.  What is unique about the CryptoMemory are their capabilities in establishing the secure channel (authenticating to the host, etc).

These device includes:

High-security Memory Including Anti-wiretapping

64-bit Authentication Protocol

Secure Checksum

Configurable Authentication Attempts Counter

These device includes:

  • Multiple Sets of Passwords
  • Specific Passwords for Read and Write
  • Password Attempts Counters
  • Selectable Access Rights by Zone
  • High-security Memory Including Anti-wiretapping
  • 64-bit Authentication Protocol
  • Secure Checksum
  • Configurable Authentication Attempts Counter

Section 5 of the datasheet labled, “Fuses” clearly states, “Once blown, these EEPROM fuses can not be reset.

This statement is absolutely false.  UV light will erase the fuses back to a ‘1’ state.  Care must be used to not expose the main memory to the UV or else it too will erase itself.

We are not going to explain the details of how to use the UV light to reset the fuse.  We have tried to contact Atmel but have not heard anything back from them.

Reading deeper into the datasheet under Table 5-1, Atmel writes, “When the fuses are all “1”s, read and write are allowed in the entire memory.

As strange as it reads, they really do mean even if you have setup security rules in the configuration memory, it doesn’t matter.  The fuses override everything and all memory areas are readable in the clear without the need for authentication or encrypted channel!  The attacker can even see what the “Secure Code” is (it is not given out in the public documentation, nor with samples).  Atmel was even kind enough to leave test pads everywhere so various levels of attackers can learn (entry to expert).

Our proof of concept was tested on samples we acquired through Atmel’s website.  Atmel offers samples to anyone however they do not give out the “Secure code” as mentioned above.
  • The secure code of the AT88SC153 samples was “$D_ $F_ $7_”.
  • The secure code of the AT88SC1608 was “$7_ $5_ $5_”.

We are not going to show you the low nibble of the 3 bytes to make sure we don’t give the code out to anyone.  This is enough proof to whoever else knows this code.  That person(s) can clearly see we know their transport code which appears to be common to all samples (e.g. All die on a wafer contain the same secure code until a customer orders parts at which time that customer receives their own secure code.).  A person reading this cannot guess the secure code in because there are 12 bits to exhaustively search out and you only have 8 tries ;).

Of all the other CryptoMemory products, only the AT88SC153/1608 has this backdoor.  We have successfully analyzed the entire CryptoMemory product line and can say that the backdoor doesn’t exist in any other CryptoMemory part.  None of the CryptoMemory parts are actually as “secure” as they make it seem.  The words, “Smoke n’ Mirrors” comes to mind (It is almost always like that).  In this particular category of CryptoMemory, there are two parts, the AT88SC153 and the larger AT88SC1608.

Thus the questions-
    • Why has Atmel only backdoored this part (NSA for you conspiracists)?
    • Who was the original intended customer supposed to be?
    • Was the original intention of these devices to be used in a product that used some kind of cryptography?

If the above was true, was this device originally intended to be a cryptographic key-vault?

All these questions come to mind because the backdoor makes it so easy to extract the contents of the device they want you to trust.  Some of you may be familiar with the GSM A5/1 algorithm having certain bits of the key set to a fixed value.

Judging by the wording of the documentation, Atmel gives the appearance that CryptoMemory are the perfect choice for holding your most valuable secrets.

Give us your thoughts…