Archive for January, 2006

Security Job Ubiquity

Dave G. | January 31st, 2006 | Filed Under: Industry Punditry

Whilst roaming about the financial district today, I noticed that every payphone had these flyers taped to them. Normally, I wouldn’t even give them a second thought, but the phrase ‘identity theft’ jumped out at me. They seem suspicious because:

  1. Flyers are printed on inkjet, and really poor quality paper around
  2. They also contain a typo
  3. The company are looking for managers in Manhattan in a salary range of 25-75k
  4. No experience required
  5. ONLY 7 POSITIONS LEFT!

All i’m saying is, I won’t be to surprised if the job application asks for your credit card number…

If it is legitimate, it is shocking to see security jobs that don’t require a nightstick and a big keyring being posted as flyers.

Comment Bubble No Comments

How I Learned Stop Worrying & Love The BER

Thomas Ptacek | January 31st, 2006 | Filed Under: Bitching About Protocols, Development, Matasano

An anonymous comment to my shell-script-ASN.1 post says, in effect, “you’re pretty close to having LDAP with that script”.

I’m pretty sure I’m all the way to having LDAP. Here’s how I find out:

  1. Skim the LDAP RFC.
  2. Capture an LDAP request:
    window1 $ ldapsearch -h localhost -LLL "(sn=smith)" cn sn telephoneNumber window0 $ nc -l -p 389 | hexify 303e020101633904000a01000a0100 020100020100010100870b6f626a65 6374636c6173733019041773757070 6f727465645341534c4d656368616e 69736d73
  3. Parse the data:
    window0 $ pbpaste | openssl asn1parse -inform DER | awk ... cons:SEQUENCE prim:INTEGER cons:appl prim:OCTET prim:ENUMERATED prim:ENUMERATED prim:INTEGER prim:INTEGER prim:BOOLEAN prim:cont cons:SEQUENCE prim:OCTET
  4. Write this script:
    #!/bin/sh # ldapmsg.sh searchRequest() { asn1 seq -T aC3 $* } ldapDN() { asn1 string $* } ldapAttribute() { t=$1 ; shift ; asn1 string -T cP$t $* } enumerated() { asn1 int -T 10 $* } boolean() { asn1 int -T uP1 $* } ( asn1 int 1 ; ( echo -n "" | ldapDN ; enumerated 0 ; enumerated 0 ; asn1 int 0 ; asn1 int 0 ; boolean 0 ; ldapAttribute 7 objectclass ; ( asn1 string "supportedSASLMechanisms" ) | asn1 seq ) | searchRequest ) | asn1 seq
  5. Test:
    $ ldapmsg.sh | hexify | sum 46713 1 $ pbpaste | sum 46713 1

OpenSSL’s ASN.1 parse is handy. To use a script like this in the real world, you might do something like:

$ ldapmsg.sh | nc directory-server 389 | openssl asn1parse -inform DER

My point, though, is that “tag” magic aside, the ability to encode strings, sequences, and integers is 99% of all of ASN.1/BER.

Obviously it’d take MORE shell scripting to do anything in LDAP. But:

  1. It’s shell scripting.
  2. For a lot of vulnerability work, I don’t need to completely execute transactions, I just need to exercise code paths in the message parser, and one message does just fine for that.

Comment Bubble No Comments

Inspirational Protocol Design Message For The Day

Thomas Ptacek | January 31st, 2006 | Filed Under: Bitching About Protocols

Tracked down from the Wikipedia page on BER, this comp.arch post from 1993:

As a matter of holy principle, Internet communication protocols (once decompressed if that is applicable) should either be directly addressable as C data structures (with use of “network byte order”), or accessed as human read/writeable text streams (SNMP/NNTP).

BER is already in widespread use. Are we too late to save the Internets?

Comment Bubble No Comments

And Hypothetically Speaking About ASN.1…

Thomas Ptacek | January 30th, 2006 | Filed Under: Bitching About Protocols, Development, Matasano

If you had yourself a program “asn1 int” that consumed its arguments and printed to standard output the binary BER representation of an ASN.1 integer, like so:

$ asn1 int 0 | hexify 020100

and you had yourself a program “asn1 seq” that consumed its standard input and printed to standard output that data wrapped in a BER ASN.1 sequence, like so:

$ asn1 int 0 | asn1 seq | hexify 3003020100

then you could generate yourself a random RSA private key block on the command line, like this:

$ ( asn1 int 0 ; asn1 int 1 ; asn1 int 11 ; asn1 int 2 ; asn1 int 3 ; asn1 int 3 ; asn1 int 3 ; asn1 int 3 ; asn1 int 3 ) | asn1 seq | hexify 301b02010002010102010b020102020103020103020103020103020103

Of course, that’s not very realistic. So you’d extend “asn1 int” to consume its own standard input when needed:

$ dd if=/dev/random bs=1 count=50 | asn1 int -r 020a807321825fa8a1c87516

And now it’s starting to get interesting:

#!/bin/sh # randkey.sh r8() { dd if=/dev/random bs=1 count=$1 2>/dev/null } echo "-----BEGIN RSA PRIVATE KEY-----" ( asn1 int 0 ; r8 256 | asn1 int -r ; asn1 int 11 ; r8 256 | asn1 int -r ; r8 128 | asn1 int -r ; r8 128 | asn1 int -r ; r8 128 | asn1 int -r ; r8 128 | asn1 int -r ; r8 128 | asn1 int -r ; ) | asn1 seq | b64 echo "-----END RSA PRIVATE KEY-----"

So we can do:

$ ./randprivkey | openssl rsa -text Private-Key: (2048 bit) modulus: 00:87:49:f1:dd:33:4c:45:aa:fa:62:bd:a6:c5:65: # and so on

and we’d start to be a little impressed by the Unix shell. Of course, we wouldn’t need to stop there; we could add another parameter to the “asn” commands, “-L” to specify, not sense, the BER length. Then our “randkey” might look like:

#!/bin/sh r8() { dd if=/dev/random bs=1 count=$1 2>/dev/null } r8r() { j=`random` r8 `expr $j % $1` } echo "-----BEGIN RSA PRIVATE KEY-----" ( asn1 int 0 ; r8r 1000 | asn1 int -r ; asn1 int -L `random` 11 ; r8 256 | asn1 int -r ; r8r 128 | asn1 int -r ; r8r 1280 | asn1 int -r ; r8r 1280 | asn1 int -r ; r8r 1280 | asn1 int -r ; r8r 128 | asn1 int -r ; ) | asn1 seq -L `random` | b64 echo "-----END RSA PRIVATE KEY-----"

and we’re fuzzing DER private key parsers on the command line.

But why would we stop there? We could add support for OIDs:

$ asn1 oid 1.2.3.4 06032a0304

and for strings:

$ asn1 string helu world 040a68656c7520776f726c64

and then we could write this script:

#!/bin/sh # snmpget.sh snmpget() { asn1 seq -T cC0 } ( asn1 int 0 ; asn1 string private ; ( asn1 int 12131415 ; asn1 int 0 ; asn1 int 0 ; ( ( asn1 oid 1.2.3.4 ; asn1 null ) | asn1 seq ) | asn1 seq ) | snmpget ) | asn1 seq

and run it like this:

$ snmpget.sh | nc -u 1.2.3.4 161

and, if we were watching in tcpdump, we’d see this:

10.0.1.5.53456 > 1.2.3.4.snmp: [udp sum ok] { SNMPv1 C=private { GetRequest(23) R=12131415 .iso.2.3.4 } }

and we’d start to wonder if there wasn’t something to this whole ASN.1 thing after all.

Right before we started hurling random bizarre SNMP GETs all over the place and watching what broke.

We’ll race you. Who can write “asn1 int,string,oid,seq” in AWK first?

Comment Bubble 4 Comments

Matasano & The Other RSA

Thomas Ptacek | January 30th, 2006 | Filed Under: Matasano

A few quick things:

  1. After a few interesting questions, we’re doing to drop another veil: we’re working on an inline device. Oh, what the hell, I’ll let another one go: the product has absolutely nothing to do with extracting key information from proprietary protocols.
  2. We’ll be at RSA in San Jose this year. Not formally. Some of us will trade zero-day for beer. Some of us are owed beer and intend to collect.
  3. Relating thing (1) and thing (2): if you are in a position to give feedback on, uh, “an inline security device”, and will be at RSA, we’d like to buy you a cup of coffee. Drop us a line: < daveg > AT matasano.com.

Comment Bubble No Comments

Gimme Back My Thunder, Guilfanov!

Thomas Ptacek | January 29th, 2006 | Filed Under: Reversing

We’ll consider ourselves schooled; Ilfak’s FindCrypt IDA Pro plugin does what we talked about for RSA and AES, only for, like, everything. He hunts down PKCS headers as well, but doesn’t mention key extraction (they DO sometimes wind up in binaries). And I’d want to know whether this is reliable on BE as well as LE architectures. But I guess I’ll be able to find that out tomorrow.

In the same vein, Luis pointed me at PEiD, which does for X86 PE files what “dezip” and “deezee” do for arbitrary buffers —- but finds, well, everything… not just compressed sections.

As someone who has spent most of his time working on Unix and embedded platforms, it’s a bit arresting to see how far the state of the art has advanced in binary analysis on Win32. Not just the tools available, but the apparent numbers and enthusiasm of people actually using the techniques.

Thanks, Ilfak and Luis!

Comment Bubble 3 Comments

113857983356470409

Jeremy Rauch | January 29th, 2006 | Filed Under: Disclosure

One of these days, I too shall get around to doing Rick Forno’s survey. I find stuff like this fascinating, and I’m looking forward to reading his interpretation of the result. But for now, there are just a couple of items I saw in Tom’s post that I thought I’d touch upon.

Its worth mentioning that I’ve been a full disclosure supporter for years. But I’ve never been a proponent of hasty disclosure. We seem to like to paint everyone in to two camps — for and against full disclosure. What about responsible disclosure?

Tom, according to his survey, believes that vulnerability information should be made public as quickly as possible following its discovery. Uncharacteristically, he makes no attempt to explain his views. He must be saving it for a separate post where he’s going to give Peter Lindstrom a hard time again. Poor guy.

I think the problem with this question is its scope. What does “as soon as possible” mean? Discover a vulnerability, get a proof-of-concept exploit working, and post to Bugtraq? Or work with the vendor to get a fix implemented, while subtly pressuring them to get things done in a timely manner? Tom may be a strongly agree in his post, but I counter he’s just looking to be controversial. If degree of agree indicates a scope from “never release” to “release immediately”, Tom (and the rest of us) are really more in the “somewhat agree” camp. Or at least, I am. Full disclosure with exploit is a good stick to prod a vendor with, but I’m not convinced it helps the end user.

And to the question regarding notifying customers before fixes are available — how’s that work? Shutting down services outright might be the “moral obligation”, but is it in the best interest of the investor? As security people, we forget that, at the end of the day, security matters so long as it doesn’t get in the way of our corporate overlords making money. How long do we keep our jobs if we start shutting down critical services every time someone releases a vulnerability that no fix or workaround is available for?

Most importantly, why is my picture all screwed up in the ;login article I linked to above?

ps: to make up for this touchy-feely post, I promise to post something technically interesting next. I’ll leave the security punditry to those who are better at it.

Comment Bubble No Comments

Four C Programming Anti-Idioms

Thomas Ptacek | January 29th, 2006 | Filed Under: Development

Excuse me, because this is off-topic to most of our readers, but very on-topic to me. The following are Four C Programming Anti-Idioms. Each one makes you go through extra effort to get worse code. Stop perpetuating them.

  1. Checking the return value of malloc() Heresy! Blasphemy! Shoddy engineering! Fuck you. So malloc() failed. What are you going to do about it? If you’re 99% of the malloc-checking C programmers in the world, when malloc fails inside a subroutine f(), you’ll do one of three things:
    • You’re going to return -1 from f(). Then, to be safe, in each of f()’s callers, you’ll check f()’s return value, returning -1 on failure. This recurs all the way back to main(), where you will detect -1 and exit.
    • You’ll return from f() without an abnormal error. f()’s callers won’t have an abnormal return value to check for, but that won’t matter, because by aborting f() you left the program in an unknown state and it’s going to segfault no matter what you do.
    • You’ll immediately abort the program.
    My affinity is clearly with the “immediately abort” crowd, and I add only this sentiment: cut out the middleman. Depending on whether you’re shipping production or not, you want one of two things to happen:
    1. You want the failed alloc to cause a segfault that you can catch and debug.
    2. You want the failed alloc to gracefully abort the program.

    (1) is accomplished by doing nothing. (2) is accomplished by preloading a version of malloc() that checks its return value and gracefully aborts on failure (it’s 2006. Why are you wasting time with “xmalloc”? Did you remember “xstrdup” too? Didn’t think so.)

    If you’re one of those clever people that wants to keep an “emergency reserve” of memory to gracefully close the whole program (instead of aborting), it’s still better to preload a new malloc than to explicitly check malloc’s return value.

    Less typing, safer code.

  2. Casting void-star

    It’s the void pointer’s job to stand in for other pointer types. In ANSI C99, the “cast” is implied when you pointers to or from void-star, and redundant when supplied explicitly.

    So this:

    int *i = malloc(sizeof(*i));

    is equivalent to this:

    int *i = (int*) malloc(sizeof(*i));

    But the redundant int-star cast isn’t just extra noise. Because the “implicit cast” behavior is unique to void-star, casting explicitly hides an error: if variable types change (say, you add an argument to a function), and what you thought was a void-star ceases to be a void-star, a casted assignment will suppress a

    valuable warning. For instance:

    void *v = NULL; int *i = v; // just peachy long long *ll = NULL; i = ll; // warning: assignment from incompatible type i = (int*) ll; // no warning, broken assignment

    Yes, yes, I know, you can’t assign FROM void-star without a cast in C++. Stop using C++. And look askance at ANY pointer cast in straight C code.

    Less typing, safer code.

  3. Passing pointers to tiny structures

    You want to return a pointer to a buffer and its length. You use the equivalent of:

    struct iov { u_char *base; size_t len; };

    On LP32, struct iov is as hard to pass in and out of a function as long long. Put differently, unless you go out of your way to individually allocate and pass pointers to long long to avoid the “overhead” (use of successive registers) of copying, you don’t get to pass pointers to struct iov.

    Dragging the point out further, I could say that if you use long long in your code, you should be passing “pair” structs instead of using out-args to store lengths. But I’m not going to go there, because that’d be hypocritical even if it was correct.

    Less typing, safer code.

  4. Wiring down pointer sizes in malloc()

    Moral cousin to gripe (2). You can “dereference” an undefined pointer in a “sizeof” expression. So this:

    v = malloc(sizeof(*v));

    equivalent to this:

    v = malloc(sizeof(struct V));

    except that in the latter example, if the type of “v” changes, you have two places your code needs to change, and god help you if you forget and the resulting code compiles anyways.

    Less typing, safer code.

Comment Bubble 16 Comments

Ancient flaws leave OS X vulnerable?

Dave G. | January 27th, 2006 | Filed Under: Defenses

ZDNet has an article about Mac OS X being insecure due to ancient vulnerabilities. I am not sure if they are talking about legacy vulnerabilities from BSD/NeXT, or just vulnerability classes from a lost age. Maybe both. The article also predicts that Apple will go through some rough times and states that they aren’t the best company to work with as a vulnerability researcher.

As far as vulnerabilities go, I definitely think that OS X is still somewhat early on in the vulnerability path. I suspect that after an initial shakeout of legacy vulnerabilities inherited from its predecessors, the real problems OS X will face will be newer code written by OS 9 developers (both at Apple and third party developers). No one really thought about security on OS9, so even dealing with file permissions can be a new experience for developers. When I was doing vulnerability research for OSX, I was partial to looking at setuid binaries that had spaces or capital letters in the filename. Pristine, unaudited code.

Lets also take a moment to say what Apple does well.

  1. Limited Attack Surface. Early on, they kept the number of services on the desktop to a minimum. Learned from everyone else’s mistakes.
  2. Builtin Firewall. Barely necessary thanks to #1. While it didn’t always set up rules the way I liked it, it was forward thinking.
  3. Pinched Opensource Code. This doesn’t always work out well for a vendor, but for the most part, they borrowed code that had already been audited by many, many people.
  4. Replaced sendmail with postfix. Not as big a deal as it used to be, but continues to show security playing a role in decision making.

When it comes to reporting vulnerabilities to Apple, I would like to think that I have some experience working with Apple. I think they are pretty middle of the road when it comes to interacting with security researchers. They aren’t particularly fast, and they could communicate a little more frequently, but things usually get fixed in reasonable timeframe for an OS vendor. Of course, everyone’s experiences dealing with vendors on security vulnerabilities is different. Sometimes it has to do with communication styles of the researcher, other times the vendor is ignorant or even malicious.

Comment Bubble 2 Comments

Two things:

Thomas Ptacek | January 25th, 2006 | Filed Under: Navel Gazing, Reversing

First: looking for the AES CBC IV your reversing target is using? Open up Ollydbg, attach to the process, hit ‘M’ for the memory map, right click, ‘Search’, and look for “E6 AB AB 4D”. It’s an AES S-Box. No hits? Try some of the others. Remember, these are backwards for LE. Your memory breakpoint will probably hit in the lowest-level AES transform function. Hit ‘K’ for the stack trace and jump up one or two.

Second: I changed the blog template. Hate me later, I’m busy now.

Comment Bubble No Comments

Who We Are

Matasano is a team of internationally respected security experts who have led security efforts at @stake, Microsoft, ISS, Secure Computing, Arbor Networks, Secure Networks, Bloomberg, Sandia Labs, and others. Read more about our team and how we can help you today.