Posts (page 38 of 43)

  • The Bogey-Owl

    The Advanced Persistent Threat (APT) is competing with Cyberwar for security word of the year. It would have been nice if we had given other important words like HTTPS or prepared statements their chance to catch enough collective attention to drive security fixes. Alas, we still deal with these fundamental security problems due to Advanced Persistent Ignorance.

    It’s not wrong to seek out APT examples. It helps to have an idea about their nature, but we must be careful about seeing the APT boogeyman everywhere.

    Threats have agency. They are persons (or natural events like earthquakes and tsunamis) that take action against your assets (like customer information or encryption keys). An XSS vuln in an email site isn’t a threat – the person trying to hijack an account with it is. With this in mind, the term APT helpfully self-describes two important properties of a threat:

    • it’s persistent
    • it’s advanced

    Persistence is uncomplicated. The threat actor has a continuous focus on the target. This doesn’t mean around-the-clock port scanning just waiting for an interesting port to appear. It means active collection of data about the target as well as development of tools, techniques, and plans once a compromise is attained. Persistent implies patience in searching for “simple” vulns as much as enumerating resources vulnerable to more sophisticated exploits.

    A random hacker joyriding the internet with sqlmap or metasploit be persistent, but the persistence is geared towards finding any instance of a vuln rather than finding one instance of a vuln in a specific target. It’s the difference between a creep stalking his ex versus a creep hanging out in a bar waiting for someone to get really drunk.

    The advanced aspect of a threat leads to more confusion than its persistent aspect. An advanced threat may still exploit simple vulns like SQL injection. The advanced nature need not even be the nature of the exploit (like using sqlmap). What may be advanced is how they leverage the exploit. Remember, the threat actor most likely wants to do more than grab passwords from a database. With passwords in hand it’s possible to reach deeper into the target network, steal information, cause disruption, and establish more permanent access.

    Stolen passwords are one of the easiest backdoors and the most difficult to detect. Several months ago RSA systems were hacked. Enough information was allegedly stolen that observers at the time imagined it would enable attackers to spoof or otherwise attack SecurID tokens and authentication schemes.

    Now it seems those expectations have been met with not one, but two major defense contractors reporting breaches that apparently used SecurID as a vector.

    I don’t want you to leave without a good understanding of what an insidious threat looks like. Let’s turn to the metaphor and allegory of television influenced by the Cold War.

    Specifically, The Twilight Zone season 2, episode 28, “Will the Real Martian Please Stand Up” written by the show’s creator, Rod Serling.

    Spoilers ahead. Watch the episode before reading further. It’ll be 25 minutes of entertainment you won’t regret.

    The set-up of the episode is that a Sheriff and his deputy find possible evidence of a crashed UFO, along with very human-like footprints leading from the forested crash site into town.

    The two men follow the tracks to a diner where a bus is parked out front. They enter the diner and ask if anyone’s seen someone suspicious. You know, like an alien. The bus driver explains the bus is delayed by the snowy weather and they had just recently stopped at this diner. The lawmen scan the room, “Know how many you had?”

    “Six.”

    In addition to the driver and the diner’s counterman, Haley, there are seven people in the diner. Two couples, a dandy in a fedora, an old man, and a woman. Ha! Someone’s a Martian in disguise!

    What follows are questions, doubt, confusion, and a jukebox. With no clear evidence of who the Martian may be, the lawmen reluctantly give up and allow everyone to depart. The passengers reload the bus1. The sheriff and his deputy leave. The bus drives away.

    But this is the Twilight Zone. It wouldn’t leave you with a such a simple parable of paranoia; there’s always a catch.

    The man in the fedora and overcoat, Mr. Ross, returns to the diner. He laments that the bus didn’t make it across the bridge. (“Kerplunk. Right into the river.”)

    Dismayed, he sits down at the counter, cradling a cup of coffee in his left hand. The next instant, with marvelous understatement, he pulls a pack of cigarettes from his overcoat and extracts a cigarette – using a third hand to retrieve some matches.

    We Martians (he explains) are looking for a nice remote, pleasant spot to start colonizing Earth.

    Oh, but we’re not finished. Haley nods at Mr. Ross’ story. You see, the inhabitants of Venus thought the same thing. In fact, they’ve already intercepted and blocked the Ross’ Martian friends in order to establish a colony of their own.

    Haley smiles, pushing back his diner hat to reveal a third eye in his forehead.

    That, my friends, is an advanced persistent threat!


    1. The server rings up their bills, charging one of them $1.40 for 14 cups of coffee. I’m not sure which is more astonishing – drinking 14 cups or paying 10 cents for each one. 

  • I finished the original May 2011 version of this article and its linguistic metaphor a few days before coming across an article that described research showing the feasibility of identifying language patterns over encrypted channels.

    One goal of an encryption algorithm is to create diffusion of the original content in order to camouflage that content’s structure. For example, diffusion applied to a long English text, say one of Iain M. Bank’s novels would reduce the frequency of the letter e from the most common one to (ideally) an equally common frequency within the encrypted output (aka ciphertext).

    The confusion property of an encryption algorithm would obscure meaning with something like replacing every letter e with the letter z, but that wouldn’t affect how frequently the letter appears – hence the need for diffusion.

    Check out the Communication Theory of Secrecy Systems by Claude Shannon for the original (and far superior) explanation of these concepts.

    There have been analyses of SSL and SSH that demonstrated how it was possible to infer the length of encrypted content (which therefore might reveal the length of a password even if the content is not known) or guess whether content was HTML or an image. The Skype analysis is a fantastic example of looking for structure within an encrypted stream and making inferences from those observations.

  • Our previous article started with an overview of the ViewState object. It showed some basic reverse engineering techniques to start deconstructing the contents embedded within the object. This article broaches the technical aspects of implementing a parser to automatically pull the ViewState apart.

    We’ll start with a JavaScript example. The code implements a procedural design rather than an object-oriented one. Regardless of your design preference, JavaScript enables either method.

    The ViewState must be decoded from Base64 into an array of bytes. We’ll take advantage of browsers’ native atob and btoa functions rather than re-implement the Base64 routines in JavaScript. Second, we’ll use the proposed [ArrayBuffer] data type in favor of JavaScript’s String or Array objects to store the unencoded ViewState. Using ArrayBuffer isn’t necessary, but it provides a more correct data type for dealing with 8-bit values.

    Here’s a function to turn the Base64 ViewState into an array of bytes in preparation of parsing:

    function analyzeViewState(input) {
        var inputLength = input.length;
        var rawViewState = atob(input);
        var rawViewStateLength = rawViewState.length;
        var vsBytes = new Uint8Array(ArrayBuffer(rawViewStateLength));
    
        for(i = 0; i < rawViewStateLength; ++i) {
            vsBytes[i] = rawViewState.charCodeAt(i);
        }
    
        if(vsBytes[0] == 0xff & vsBytes[1] == 0x01) { // okay to continue, we recognize this version
            var i = 2;
            while(i < vsBytes.length) {
                i = parse(vsBytes, i);
            }
        }
        else {
            document.writeln("unknown format");
        }
    }
    

    The parse function will basically be a large switch statement. It takes a ViewState buffer, the current position in the buffer to analyze (think of this as a cursor), and returns the next position. The skeleton looks like this:

    function parse(bytes, pos) {
        switch(bytes[pos]) {
            case 0x64: // EMPTY
                ++pos;
                break;
            default: // unknown byte
                ++pos;
                break;
        }
        return pos;
    }
    

    If you recall from the previous article, strings were the first complex object we ran into. But parsing a string also required knowing how to parse numbers. This is the function we’ll use to parse numeric values. The functional approach coded us into a bit of a corner because the return value needs to be an array that contains the decoded number as an unsigned integer and the next position to parse (we need to know the position in order to move the cursor along the buffer):

    function parseUInteger(bytes, pos) {
        var n = parseInt(bytes[pos]) & 0x7f;
    
        if(parseInt(bytes[pos]) > 0x7f) {
            ++pos;
            var m = (parseInt(bytes[pos]) & 0x7f) << 7;
            n += m;
    
            if(parseInt(bytes[pos]) > 0x7f) {
                ++pos;
                var m = (parseInt(bytes[pos]) & 0x7f) << 14;
                n += m;
            }
        }
    
        ++pos;
    
        return [n, pos];
    }
    

    With the numeric parser created we can update the switch statement in the parse function:

    function parse(bytes, pos) {
        var r = [0, 0];
        switch(bytes[pos]) {
            case 0x02:
                ++pos;
                r = parseUInteger(bytes, pos);
                pos = r[1];
                document.writeln("number: " + r[0]);
                break;
            ...
    

    Next up is parsing strings. We know the format is 0x05, followed by the length, followed by the “length” number of bytes. Now add this to the switch statement:

    switch(bytes[pos]) {
        ...
        case 0x05:
            ++pos;
            r = parseUInteger(bytes, pos);
            var size = r[0];
            pos = r[1];
            var s = parseString(bytes, pos, size);
            pos += size;
            document.writeln("string (" + size + "): " +
                s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;'));
            break;
        ...
    

    The parseString function will handle the extraction of characters. Since we know the length of the string beforehand it’s unnecessary for parseStringto return the cursor’s next position:

    function parseString(bytes, pos, size) {
        var s = new String("");
    
        for(var i = pos; i < pos + size; ++i) {
            s += String.fromCharCode(parseInt(bytes[i], 10));
        }
    
        return s;
    }
    

    We’ll cover two more types of objects before moving on to an alternate parser. A common data type is the Pair. As you’ve likely guessed, this is an object that contains two objects. It could also be called a tuple that has two members. The Pair is easy to create. It also introduces recursion. Update the switch statement with this:

    switch(bytes[pos]) {
        ...
        case 0x0f:
            ++pos;
            document.writeln("pair");
            pos = parse(bytes, pos); // member 1
            pos = parse(bytes, pos); // member 2
            break;
        ...
    

    More containers quickly fall into place. Here’s another that, like strings, declares its size, but unlike strings may contain any kind of object:

    switch(bytes[pos]) {
        ...
        case 0x16:
            ++pos;
            r = parseUInteger(bytes, pos);
            var size = r[0];
            pos = r[1];
            document.writeln("array of objects (" + size + ")");
            for(var i = 0; i < size; ++i) {
                pos = parse(bytes, pos);
            }
            break;
        ...
    

    From here you should have an idea of how to expand the switch statement to cover more and more objects. You can use this page as a reference. JavaScript’s capabilities exceed the simple functional approach of these previous examples; it can handle far more robust methods and error handling. Instead of embellishing that code, let’s turn our text editor towards a different language: C++.

    Diving into C++ requires us to start thinking about object-oriented solutions to the parser, or at least concepts like STL containers and iterators. You could very easily turn the previous JavaScript example into C++ code, but you’d really just be using a C++ compiler against plain C code rather than taking advantage of the language.

    In fact, we’re going to take a giant leap into the Boost.Spirit library. The Spirit library provides a way to create powerful parsers using clear syntax. (Relatively clear despite one’s first impressions.) In Spirit parlance, our parser will be a grammar composed of rules. A rule will have attributes related to the data type is produces. Optionally, a rule may have an action that executes arbitrary code.

    Enough delay. Let’s animate the skeleton of our new grammar. The magic of template meta-programming makes the following struct valid and versatile. Its why’s and wherefore’s may be inscrutable at the moment; however, the gist of the parser should be clear and, if you’ll forgive some exaltation, quite elegant in terms of C++:

    template <typename Iterator> struct Grammar : boost::spirit::qi::grammar<Iterator> {
        Grammar() : Grammar::base_type(start) {
            using boost::spirit::qi::byte_;
    
            empty = byte_(0x64);
            object = empty | pair;
            pair = byte_(0x0f) >> object >> object;
            version = byte_(0xff) >> byte_(0x01);
            start = version // must start with recognized version
                >> +object; // contains one or more objects
        }
    
        qi::rule<Iterator> empty, object, pair, start, version;
    };
    

    We haven’t put all the pieces together for a complete program. We’ll put some more flesh on the grammar before unleashing a compiler on it. One of the cool things about Spirit is that you can compose grammars from other grammars. Here’s how we’ll interpret strings. There’s another rule with yet another grammar we need to write, but the details are skipped. All it does it parse a number (see the JavaScript above) and expose the value as the attribute of the UInteger32 rule.1 The following example introduces two new concepts, local variables and actions:

    template <typename Iterator> struct String : boost::spirit::qi::grammar<Iterator, qi::locals<unsigned> > {
        String() : String::base_type(start) {
            using boost::spirit::qi::byte_;
            using boost::spirit::qi::omit;
            using namespace boost::spirit::qi::labels;
    
            start = omit[ (byte_(0x05) | byte_(0x1e))
                >> length[ _a = _1 ] ]
                >> repeat(_a)[byte_] ;
        }
    
        UInteger32<Iterator> length; qi::rule<Iterator, qi::locals<unsigned> > start;
    };
    

    The action associated with the length rule is in square brackets. (Not to be confused with the square brackets that are part of the repeat syntax.) Remember that length exposes a numeric attribute, specifically an unsigned integer. The attribute of a rule can be captured with the _1 placeholder. The local variable for this grammar is captured with _a. Local variables can be passed into, manipulated, and accessed by other rules in the grammar. In the previous example, the value of length is set to _a via simple assignment in the action. Next, the repeat parser takes the value of _a to build the “string” stored in the ViewState. The omit parser keeps the extraneous bytes out of the string.

    Now we can put the String parser into the original grammar by adding two lines of code (highlighted in bold). That this step is so trivial speaks volumes about the extensibility of Spirit:

        ...
        object = empty | my_string | pair;
        ...
        start = version // must start with recognized version
            >> +object; // contains one or more objects
    }
    
    String<Iterator> my_string;
    qi::rule<Iterator> empty, ...
    

    The String grammar introduced the repeat parser. We’ll use that parser again in the grammar for interpreting ViewState containers. At this point the growth of the grammar accelerates quickly because we have good building blocks in place:

        ...
        using boost::spirit::qi::byte_;
        using boost::spirit::qi::repeat;
    
        container = byte_(0x16)
            >> length [ _a = _1 ]
            >> repeat(_a)[object] ;
    
        empty = byte_(0x64);
    
        object = empty | my_string | pair;
        ...
    }
    
    String<Iterator> my_string;
    UInteger32<Iterator> length;
    qi::rule<Iterator, qi::locals<unsigned> > container;
    qi::rule<Iterator> empty, ...
    

    This has been a whirlwind introduction to Spirit. If you got lost along the way, don’t worry. Try going through the examples in Spirit’s documentation. Then, re-read this article to see if the concepts make more sense. I’ll also make the sample code available to help get you started.

    There will be a few surprises as you experiment with building Spirit grammars. For one, you’ll notice that compilation takes an unexpectedly long time for just a dozen or so lines of code. This is due to Spirit’s template-heavy techniques. While the duration contrasts with “normal” compile times for small programs, I find it a welcome trade-off considering the flexibility Spirit provides.

    Another surprise will be error messages. Misplace a semi-colon or confuse an attribute and you’ll be greeted with lines and lines of error messages. Usually, the last message provides a hint of the problem. Experience is the best teacher here. I could go on about hints for reading error messages, but that would be an article on its own.

    Between compile times and error messages, debugging rules might seem a daunting task. However, the creators of Spirit have your interests in mind. They’ve created two very useful aids to debugging: naming rules and the debug parser. The following example shows how these are applied to the String grammar. Once again, the change is easy to implement:

        ...
        start = omit[ (byte_(0x05) | byte_(0x1e))
            >> length[ _a = _1 ] ]
            >> repeat(_a)[byte_] ;
    }
    
    start.name(“String”); // Human readable name for the rule
    debug(start); // Produce XML output of the parser’s activity
    
    UInteger32<Iterator> length;
    qi::rule<Iterator, qi::locals<unsigned> > start;
    };
    

    As a final resource, Boost.Spirit has its own web site with more examples, suggestions, and news on the development of this fantastic library.

    It seems unfair to provide all of these code snippets without a complete code listing for reference or download. Plus, I suspect formatting restrictions may make it more difficult to read. Watch for updates to this article that provide both full code samples and more readable layout. Hopefully, there was enough information to get you started on creating your own parsers for ViewState or other objects.

    In the next article in this series we’ll shift from parsing ViewState to attacking it and using it to carry our attacks past input validation filters into the belly of the web app.


    1. Spirit has pre-built parsers for many data types, including different types of integers. We need to use custom ones to deal with ViewState’s numeric serialization.