Dave G. | October 30th, 2007 | Filed Under: Disclosure, Industry Punditry
In the past, I have acknowledged QNX and IRIX as security manatees for their complete lack of effort around local security.
iDefense released seven, count them, seven local privilege escalation vulnerabilities in AIX today. Four of them are actually stack overflows. Yes, you heard me, stack overflows. One of them is actually in ftp. Another one is in dig. Yes, dig is setuid root on AIX.
Is there anyone that can actually explain to me why dig and ftp are setuid root executables?
Reader ‘Loic.’ commented:
The reason why “ftp” (but also “host”, “telnet”, “dig”, etc.) are setuid root on AIX is that these binaries use the AIX “system audit” functions (’auditproc()’ et al.) which require root privilege.
This is insane but is nothing new, it was already that way in AIX 4 (~8 years ago).
If the setuid bit is removed from the binaries, they just plain stop working (with no error message).
13 Comments
Thomas Ptacek | October 29th, 2007 | Filed Under: Uncategorized
Our friend Rich Mogull suggested that Leopard is “perhaps the most
significant update in the history of Mac OS X - perhaps in the history
of Apple”. Good little fanboy that I am, I had Leopard installed this
weekend. Let’s evaluate the security advances.
The Good
Leopard gets a few things right.
Sandboxing
What It Is.
The XNU kernel now has a role-based access control system, applied at
the system call - mach call layer. You can write flexible policies
about what any given program can or cannot do.
Why You Care.
Mail.app should not be allowed to add accounts to your system. Safari
should not be allowed to load kernel extensions. iChat should not be
allowed to install a backdoored SSH server. Smart security people
assume that every application they run contains some hidden bug that will
allow attackers to upload their own code into the running
program. With kernel-enforced access control, even if an attacker does
that, you still stand a chance.
What Leopard Gets Right.
Do not be deceived (and, like me, embarassed) by the sandbox(7)
documentation. Leopard sandboxes are flexible and interesting. They’re
apparently compiled from Scheme programs (sandbox-compilerd embeds
TinyScheme) that live in /usr/share/sandbox. You can break
sandbox-compilerd open in TextEdit and read the compiled-in Scheme
code; they’ve got a lot of the bases covered, including obscure stuff
like SYSV IPC, the BSD sysctl interface, and signals.
What Leopard Gets Wrong.
Three things.
1.
They didn’t document any of this. You can’t officially use this API to
secure your own code. We can’t read their code or specifications to
test whether it’s secure.
2.
The existing profiles suck. For instance, the Leopard “Quick Look”
feature is billed as a test case for sandboxing, because it
automatically opens and parses content in your download folder. But
all Quick Look sandboxing does is restrict network access. Who cares?
A Quick Look exploit is just going to install a trojan somewhere else,
and that trojan won’t be governed by sandboxes.
3.
Almost nothing you care about is sandboxed. For instance: Mail,
Safari, and iChat.
My Verdict.
It’s not a pretty win, but I’ll take it. Sandboxes are better in a
variety of ways than what off-the-shelf Vista provides. Apple should
provide an “Instruments.app”-style interface on this feature, like
they did for DTrace, and let a community develop around hardening Darwin.
Input Manager Restrictions
What It Is.
Input managers are bundles that are loaded into all running
programs. Originally intended for the mundane tasks of
internationalization and accessibility, they’ve mutated into a generic
plugin facility for all Cocoa programs. If you’re using things like
SIMBL, Saft, SafariStand, Sogudi, or Pith Helmet, you’re abusing input
managers. Leopard “breaks” them.
Why You Care.
Input managers are terrifying. They’re arbitrary blobs of code that
get injected into almost every Mac application. They are a “UI
extension interface” in the same way that Back Orifice 2k is a “remote
system administration facility”.
What Leopard Gets Right.
Input managers in Leopard are only loaded from
“/Library/InputManagers”, not from the user’s home directory, and are
only loaded if they’re owned by “root”.
What this means is that you can still get them to work, but the most
likely code injection exploits in Safari can’t, because they can’t
write to “/Library” and they can’t make files be owned by root.
My Verdict.
A clean win. Apple straightforwardly closed off a major attack vector
with minimal disruption to existing third-party plugins.
The Bad
I’m prepared to be wrong about these.
Guest Account
What It Is.
The Leopard “Guest” account erases itself at logout, providing an
ostensible “clean” environment for people to use your machine without
cluttering it with garbage, accessing your personal information, or
betraying their own personal information.
Why You Care.
Sometimes people want to use your computer. In Tiger, if you let them,
they can hijack your machine.
What Leopard Gets Right.
The idea of a secure guest account is useful.
What Leopard Gets Wrong.
Everything but the idea of a secure guest account.
For example:
Leopard Guest users can install cron jobs. These are scheduled
background tasks, run out of launchd, that will execute even if
the Guest user is not logged in. Leopard Guest cron jobs persist
after logout.
Leopard Guest users can change the wireless network you’re
connected to. Even after logout, when you switch to your “real”
account, your Guest’s wireless network selection appears to
persist.
Leopard Guest users can mount remote filesystems. Even after they
log out, the mount mount in “/Volumes” remains.
The long and the short of it? Leopard Guest users can remain resident
on your machine, even after their home directory has been deleted by
the Leopard log out process. They can install daemons that listen on
network ports to allow themselves back in. Or they can wait in the
background for the next “Guest” to log in and steal all their
information.
My Verdict.
Pretend like this feature doesn’t exist.
Address Space Randomization
What It Is.
A huge portion of all low-level attacks involve bugs that let
attackers corrupt program memory. Most of the time, if you can corrupt
memory, you can divert the program from its own code and into code of
your choosing.
The most common exploit technique for these bugs is called
“ret-to-libc”. Without the gory details, the exploit effectively
allows a blob of data the attacker writes into your program to be used
as a scripting language, invoking (“ret”) all the functionality the OS
exposes to programs (“libc”).
Ret-to-libc attacks require the attacker to know where the various
facilities are, so they can be scripted. On OS X Tiger, that was easy:
every 10.4.9 Mac kept those facilities at the same locations in
memory. In Leopard, the OS randomizes the locations, to make them
harder to predict. This feature is called “ASLR”.
Why You Care.
This feature gets top billing as “protection against buffer
overflows”; it’s also a first line of defense against heap overflows,
uninitialized variable attacks, and integer overflows.
What Apple Gets Right.
Some library offsets are in fact randomized.
What Apple Gets Wrong.
The dynamic linker library (dyld) is not randomized. From what I can
tell, ten different Leopard macs booted at ten different times will
have the same offset to dyld.
You care because dyld is full of useful functionality. Like,
dynamically linking new libraries into memory, or recovering the base
addresses for existing libraries.
Can I say right now that you can exploit this to take over a Mac?
No. But ASLR is either something you get right, or is simply a speed
bump for attackers. Some other things to know about Leopard ASLR:
Library offsets don’t change between invocations of the same
program.
Library offsets don’t change between invocations of different
programs (Safari and iChat have CoreServices at the same location).
I haven’t seen my library offsets change once, although I have
observed that they are different from a seperate Leopard install.
So, assuming for a second that dyld and the Objective-C runtime
(vastly more complicated than the standard C runtime, or even the C++
runtime) don’t monkeywrench Leopard ASLR: if I can run code on your
box for any reason, I can probably walk past ASLR features in any of
your programs. If any of your programs leak information (a far more
common problem than buffer overflows), I can probably collect enough
information to beat ASLR in every other program.
My Verdict.
This feature removes a talking point argument about Microsoft Windows
Vista’s superior security, but it doesn’t address the underlying
point of that argument. Cocoa programs running in Darwin are less
secure than Win32 programs running under NTOSKRNL, and aren’t even in
the same ballpark as Managed C++ or C# programs.
The Irrelevant
None of these features are going to stop your Macbook from getting compromised.
Filevault Encryption
Filevault in Tiger used 128-bit AES keys. Now it uses 256-bit AES
keys. There’s a Fields Medal waiting for the person who breaks 128-bit
AES. That person can’t necessarily break Leopard Filevault. Awesome.
The funny part about this is that the Filevault keys are still
protected by the weakest key in the system: your user password.
Application-Aware Firewall
The Tiger firewall provided all-or-nothing policies for what kinds of
connections would be allowed or disallowed into your computer. The
Leopard firewall breaks them into per-application policies. That would
be great, but the interface offers only a blanket all-or-nothing
policy on inbound connections; you can’t tell it not to let iTunes
connect outbound.
If you care about about application security policy —- and you should
—- someone like Unsanity is inevitably going to rig up an OS X
intrusion prevention system built on Sandboxes, and that system will
give you fine-grained control over what iChat and iTunes are allowed
to do. I’ve never bothered configuring the OS X firewall, and I’m not
going to start in Leopard.
Tagged Downloads
Yes, it’s true, when you download a program with Safari and run it for
the first time, you will get a dialog box warning you that you
downloaded the program and are running it for the first time. I give
the average Leopard user approximately 6 hours before clicking “OK” on
this dialog becomes a function of their autonomous nervous system.
Digital Signatures
You can sign executables in Leopard. If you allow a signed executable
to run after you download it, you ostensibly won’t be bothered with
dialog boxes for future downloads from the same author. Awesome. That
will shave 45 milliseconds off the download process for the average
Mac user.
This feature gets prominent billing in some Leopard round-ups, but it
shouldn’t. I haven’t found a signed program to verify yet. From what I
can tell, nothing shipped with Leopard is signed (possibly excepting
kernel extensions). I hexfiended NOPs into a variety of programs, thus
invalidating any conceivable RSA signature on them. They ran just
fine.
Even if third-party code is signed, if every binary on the system they
depend on remains unprotected, code signatures won’t do anything to
stop trojans on your system.
110 Comments
Eric Monti | October 28th, 2007 | Filed Under: Development, Reversing
In this much delayed installment I’d like to expand on my last one entitled “Exploring Protocols 1″. This is going to be a long one, folks. I guess the big delay in getting this out resulted in a backlog of all the things I wanted to cover. The discussion veers into tools and samples some simple code for dissecting unfamiliar PDUs. There’s more to the “protocol tool” category than just dissecting, of course. But it’s usually the first step and this post will try to focus mostly on it.
The protocol exploration and tools journey often starts out something like this:
1. Got an unknown or little known protocol we’d like to learn more about and maybe mess with.
2. Think: “Hey, self… Wireshark has lots of decodes. Lets check it out.” Then one of two things often happens:
- Turns out it is a protocol wireshark DOES decode. “Nice! But what if we want to actively or passively mess with it? Wireshark is a sniffer…”
or…
- Turns out this is a protocol wireshark doesn’t know about. But it does seem to have a framework for building new ones? Shouldn’t be too hard to just plug in a new decode… should it?
Let me be clear before going any further with this: Wireshark is fantastic! I use it ALL the time. I don’t have to tell anyone who’s ever used it how long and impressive it’s list of features and dissectors is. It’s gotten a great reputation and it’s well deserved.
But I’ve not had much luck using Wireshark’s framework to add new dissectors or make use of existing ones in other programs. The dissectors Wireshark supports are written in C and compiled in at build time [** see note] Sure it uses pcap and there’s numerous pcap based tools for packet mangling/manipulation. That might warrant the effort, but WireShark is first and foremost a sniffer, and we need to do a lot more than sniff protocols. Its dissectors aren’t yet as easy as on might like to make available in other programs. Every time I’ve looked into it I end up deciding to just end up writing my own tools from scratch. The reasons will probably become evident as I go on.
** Note: this may be in the process of changing. The Wireshark folks are beginning to implement a LUA interpreter right into the sniffer. LUA is an embedded programming language. It’s cool stuff, but so far it’s still pretty new in Wireshark and it’s still just intended as a tool for developing C dissectors.
But anyway… back to my numbers:
3. What’s needed a more flexible framework. “This is not the wheel I am looking for. Reinvent!!!”
Ok so bear with me. I’m going to jump ahead to the tools and talk some about the techniques I’ve used to attack the problem above in the real world. I’ll digress a bit and yammer seemingly pointlessly about a few iSCSI details too.
Yes, we’ll need a protocol to talk about. For simplicity (… ok well, “reference” anyway) we’re going to stick with iSCSI from the first installment. Wireshark actually dissects iSCSI quite completely. This may defeat the point of the discussion about exploring unknown protocols for some, but for now it’s still a good thing since we can actually compare what Wireshark can do with what we build with our own toolchain.
Let’s start with a simple iSCSI PDU hexdump for reference:

Our initial goal was to figure out a bit about the format. I talked about that in the last post. Check out the last “Exploring Protocols 1“. Now we’ll try to dissect iSCSI PDU’s in a manner similar to Wireshark.
In the not too distant past, I would have probably used C/C++ for this. This is mostly because C/C++ has ’structs’ and pointers. The ’struct’ lets you describe binary data to your program by defining fields as elements a structure. Using the structure as the type for a pointer variable lets you apply the structure to a buffer in memory like an overlay. This is pretty obvious stuff to anybody who does any C coding at all, but not everybody does. This simple feature is really powerful and efficient. I still get a few goosebumps when my structures “lay over” properly.
Here is an example of a trivial iSCSI_dissector in C. This sample program is not too robust, but serves as a good starting point. I used a structure borrowed and adapted from linux-iscsi-3.6.3. You should be able to compile this program with “gcc -o iscsi_dissect iscsi_dissect.c” on any *ix and maybe windows. First lets just look at the structure defined for the header:

The structure for the header defines the fields and sizes based on what the iSCSI RFC calls for. The size of the datatype (uint*_t) defines the width of the field.
There are some funky field alignment issues that the linux-iscsi header structure doesn’t try to fully address in the BHS structure definition, though.
This is just nitpicking (bitpicking?) and may distract a little from protocol dissection, but lets take a quick look again at the first four bytes from the RFC 3720 syntax description. This time, the structure elements from linux-iscsi are lined up with each field from the RFC description.

Neither the ‘opcode’ nor ‘flags’ elements in the structure are supposed to take up an entire byte in the BHS if you read the RFC “literally”.
The Basic Header Segment as defined in the RFC has a null bit, followed by an ‘I’ bit, a 6-bit opcode, and a single ‘F’ (final) bit followed by 7 bits allocated as “opcode specific”, or as linux-iscsi called it, “reserved”.
10.2.1.1 I
For request PDUs, the I bit set to 1 is an immediate delivery
marker.
10.2.1.2. Opcode
The Opcode indicates the type of iSCSI PDU the header
encapsulates.
...
So the first two bits should always be “0 0″ or “0 1″. Why the first bit is not used is unclear, but in obvservation of iSCSI it seems like it’s always set to ‘0′.
So what about that 6-bit opcode after ‘F’? Well if you look closely in the spec, you wont find any op-code higher than the number ‘63′ (or 0×3f in hex). Why? Because at least 7 bits are needed to store for the number 64 (or 0×40 hex) and higher. So there can never be more than 63 types of opcode represented in the “Opcode” field alone. Like so:
63 is "0 0 1 1 1 1 1 1" in bits
64 is "0 1 0 0 0 0 0 0"
There’s another similar (but different) situation right after this one:
10.2.1.3. Final (F) bit
When set to 1 it indicates the final (or only) PDU of a
sequence.
10.2.1.4. Opcode-specific Fields
These fields have different meanings for different opcode
types.
The basic header segment is just a template for all the types of header segments. They’re all defined in the RFC too. If you read up on them, it turns in several cases the remaining 7 bits in the the ‘[F][rsvd1]’ byte for are used for other flags. In some cases it’s really “reserved”. In other cases it’s used for codes that are significant to the specific segment type. Sometimes the meaning of the ‘F’ bit even gets changed.
It’s a common practice not to define every single bit in a field separately and just combine them in one byte. When using the structure, you’d just use bitwise operations against various values to set, check and clear individual bits.
Protocols often try to squeeze a use out of every single bit. This can give rise to occasional situations where a weird alignment issue like the ‘rsvd1′ or ‘opcode’ ones can result in unexpected behaviors. Depending on the implementation and what assumptions the developer makes, assigning values to anything after the ‘I’ or ‘F’ might inadvertently get set or cleared. This type of thing can might have dangerous side effects.
Queue haunted house organ music...
Ok… don’t know and can’t think of any even remotely dangerous iSCSI opcode or rsvd1 side effects. I and F seem pretty benign to me just from reading the RFC and theres probably no case short of a grotesquely bad implementation where they’d get clobbered by their neighboring values. The spooky music is… um… just to get in the Halloween spirit. Yea! Happy Halloween everybody!
So, here’s what the output from iscsi_dissect.c looks like (cleaned up slightly for display):
Dissecting iSCSI frame: (Actual PDU Length = 136 bytes)
Format is big endian so the hex order matches wire.
Opcode: = 36 : (0x24)
Flags: = 128 : (0x80)
Op-Specific1 = 0 : (0x00)
Op-Specific2 = 0 : (0x00)
TotalAHSLen: = 0 : (0x00)
DataSegmentLen = 85 : (0x000055)
LUN: hex: = 0000000000000000
InitTaskTag: = 1 : (0x00000001)
Opcode Specific Fields in hex:
ff ff ff ff 00 00 00 02 00 00 00 02 00 00 00 03 00
00 00 00 00 00 00 00 00 00 00 00
Data segment strings: (segment length: 88 bytes):
TargetName=iqn.2009-08.com.splatomatic:storage.lvmx00
TargetAddress=192.168.1.10:3260,1x00
x00
x00
x00
The struct -> buffer overlay used in the C program is simple and kind-of elegant. Structures are also nice since they can serve as a short-hand for describing the format of messages we’re trying to figure out.
This version also resembles the way most actual iSCSI implementations probably work. For grey/black-box security testing, this can be an advantage. You may gain insights that will help you find where implementation flaws lurk in the real product. Using the same language that as actual implementation can arguably let you get closer to the same thought processes the developers used. If there was a point to that random ranting about partial use of bit-fields within bytes, that was it. The rant should also serve as a case study in following useless random rabbit-holes too early in the exploration phase. Which is another good lesson on exploring protocols and would make a good blog-post by itself. I’m sure most people have already dropped out of this overly long post by now. Too bad for them, they’ll totally miss out on the best part.
Ok… for some, the problem with C is that, well, it can be too rigid. I personally think that higher level interpreted languages are better for doing exploratory work like this. As you’re examining unfamiliar and possibly undocumented protocols or formats, you’re constantly refining your idea of what your structures should look like and what you want to do with them. You don’t want to have to stop and recompile for every change. You *really* dont want to find yourself having to redesign your tools several times over.
One of the frustrating things about writing quick/dirty tools from scratch for fault testing or fuzzing is first getting rid of faults in your own testing tools. Usually the quicker and dirtier your C is, the harder it becomes to work with. There are lots of programmers out there that this is may not be a problem for. They probably stopped reading a while ago too. But even they end up relying on abstraction to some extent.
My experience has been that using higher level languages gives you more freedom to experiment and you get a lot of relatively stable free abstraction already without having to build it yourself. To put it bluntly, you can get away with more, for longer, usually with less code. On the other hand, all that abstraction can get in your way sometimes when you need to get closer to the wire, but this isn’t as big of a deal as people make it out to be.
So lets see how we could have written a similar dissector/decoder in an interpreted language. I’m going to use Ruby. Ruby is nice. It has some particularly useful qualities for protocol exploration (besides just being “nice”):
- It’s an interpreted scripting language. We can make modifications and tweaks on the fly much more easily. No recompiling necessary.
- Ruby code is very portable. Very few problems getting your code to work on different platforms.
- It’s got built in large numbers, a string data-type that doubles as a raw buffer, and lots of other free and generally well designed classes methods for for doing all sorts of commonly useful things. All in all this makes for fewer things to screw up as you’re cobbling something together quickly (as I tend to need to).
- Modular design is, I think, actually harder *not* to do with Ruby. Keeping things modular when developing exploratory tools will mean that exploration phase actually yields highly useable code that we can adapt very easily down the road.
- Did I mention Ruby is nice?
One thing ruby doesn’t really do without add-ons is ’structures’. The way Ruby uses references to objects is similar to pointers. Actually, Ruby’s references definitely harken back to C/C++, the language it’s written in. But the similarities aren’t completely linear. It’s also a moot point because what really helps protocol design is ’structs’.
“But somebody must have done something about this by now!”, you say? Actually several have. One such thing is called BitStruct. I’ve been using it a lot. Not only does BitStruct let you map out binary structures in a way similar to C’s ’struct’, but it’s goes further. It is really handy for keeping track of and getting at useful field-related information you’re likely to want. Things like descriptions, sizes, offsets, and even display format are all available as parts of a hash and through free methods. Extending the hash-based design for say “annotations” is as easy as tying new elements to a field’s hash. Bit-struct also has its own free (if somehwat rudimentary) ‘inspect’ and ‘inspect_detailed’ methods for dissecting your structures in human readable format. There’s a ‘describe’ class method that returns a human-readable description of the format itself. BitStruct has some alignment quirks of its own, but like C’s structs you can work around them.
Take a look at this code. It’s a lot more descriptive than the C struct version. The descriptions are actually part of the code, not comments. The formats for fields are specified right in the structure too!

Unlike the C version, the rest of the code is really short. So short I’ll paste it all too:

So here is the iSCSI_dissector in Ruby. Getting BitStruct is a prerequisite ofcourse. Here’s how we run it and what our output looks like:
$ ruby ./iscsi_dissect.rb
-- Header Dissection --
Type: ISCSI_bhs:
Decode:
I bit = 0
Opcode = 36
F bit = 1
Opcode-specific 1 = 0x00
Opcode-specific 2 = 0x00
Opcode-specific 3 = 0x00
TotalAHSLength = 0
DataSegmentLength = 85
LUN or Op-specific = 0x0000000000000000
Initiator Task Tag = 1
Opcode-specific 4-12 = "377377377377�00�00�00
�02�00�00�00�02�00�00�00�03�00�00�00�00
�00�00�00�00�00�00�00�00"
Data Segment Body = "TargetName=iqn.2009-08.com.splatomatic:storage.lvm�00TargetAddress=192.168.1.10:3260,1�00�00�00�00"
-- Data Segment Body --
TargetName=iqn.2009-08.com.splatomatic:storage.lvmTargetAddress=192.168.1.10:3260,1
In fairness to C, I obviously didn’t do as much work on displaying the data segment but could have. I let ‘inspect’ take care of it to illustrate what it does (and doesn’t do).
It’s interesting to note that the dissector framework in Wireshark uses an similar notion of “adding fields” not unlike BitStruct’s. The sniffer needs easy and generalized access to a bunch of packet and protocol related meta-information used for displaying lots of different protocols, filtering, and so on. Abstracting fields makes a lot of sense for a sniffer and most of the reasons why match up for protocol reversing and prototyping.
So there you have it. In general, I tend to use Ruby over C for this stuff. It used to be Perl. It’s not because I think I have figured out all the typical implementation gotchas or that I don’t have anything to gain by “getting closer to the wire/implementation” either. It’s more because I’m lazy and/or slammed most of the time. It’s also been fun learning and using Ruby more.
If you prefer C/C++, then use it instead.
Python? great!
Perl? go for it!
LUA? Why not! We all may be doing it soon.
.NET? that’s swell!
Java? … really?
KSH? yea! That might even win you a beer!
WSH? um… wow! ok (but definitely no beer).
Whatever… don’t listen to me or anybody else, just use what you know and/or like and/or want to learn more of.
I guess if there’s been a point to the C versus Ruby thing, it’s that the real key is the end result. Language wars are for people with more free time on their hands than I have. If a language feels like it slows you down, then it’s probably not the right one. I say “get it done” first. If it makes you feel better, just call your early forays “prototyping”. You can always rewrite it in something else once you know how the protocol works. I do sometimes. To an extent, I sometimes think of “C vs. Ruby or Perl” that way, but in practice, I tend to use the four letter languages most of the time.
Anyway, back to the general topic of protocol exploration, and in summary:
For this and the last installment I’ve been talking about iSCSI; a protocol with pretty good RFC documentation and some open source code guiding us along the process of understanding and dissecting PDU’s. I’ll be talking about tackling lesser understood and undocumented protocols more in future posts. If iSCSI had been totally undocumented we’d have to figure a lot out on our own. Frankly, iSCSI could take a while to understand if it weren’t so well documented. It’s a pretty complicated protocol as far as they go. I’ve only scratched the surface by talking about the BHS.
I’ve gotten some kind words and gentle nudges to get me back to writing this from one or two of you and I want to say again “Thanks for the feedback!”. It should not have taken so long to get the 2nd installment out.
5 Comments
Dave G. | October 2nd, 2007 | Filed Under: Industry Punditry
As a consultant, I have been involved with many-a threat modeling exercise. Oftentimes, they are boring, process intensive sessions where you stare out the window praying that the meeting ends or that the lunch you ate contained botulism. They are also boring, process intensive meetings that have more impact on the longterm security of your organization than just about anything you are likely to do.
The reason for this is simple:
Most developers don’t give a damn about security. Threat modeling is a great way to get everyone on the same page. It is great when dev teams actually start talking to each other about security. Not everyone will think like an attacker, and that’s ok. As a matter of fact, I think having the security police in the room is potentially less valuable early on in the process. Let the people who produce the app think through this stuff. They are smart. And besides, if you provide the structure and have an approval process, you can always take a look at the TM documentation they produce.
Pen-testing re-inforces the wrong message [1]. Sure it’s a necessary part of the process [2], but just performing penetration testing trains developers to think about security they way they think about other code quality issues. Which is to say, “My code is perfectly secure until someone reports a vulnerability in it, at which point I will fix it and my code will be secure again.” [3].
Prioritize your teams. It helps focus the valuable time of your external security people to the right subject and prevents audit RFPs that ask you to look for buffer overflows in systems where the authentication, authorization and role system is broken by design, but the code is written in C#. —FX added [see comments].
Why am I talking about this? Adam Shostack blogged about Microsoft’s experiences rolling out the threat modeling process. Obviously, one thing that makes this work there is that they have management buy-in. But the point is, It Works There. I hope Adam is in a situation to be candid so that other we can all learn what to expect when trying to insert security into the development process.
(1) Don’t worry, I’ll defend penetration testing in the next sentence.
(2) Never doubt me.
(3) Yes, I am simplifying and generalizing.
8 Comments