Wednesday, January 19, 2011

Update

Apologies to anyone who thought this might be updated on a regular basis (including myself).

Things wound down quite seriously in November, and I returned from Poland last week (where there were many piękni widoki) to find I had a lot of catching up to do.

Here's a quick list of the projects I have at the moment. Hopefully one of these will grab me so I can make a few more posts about it.

  • Extending the IPv6 version of the ARP replay attack for WEP into a usable utility, and performing some better tests with it (doable, since I acquired another wireless AP)
  • Phase two of the drive by download project (as per the last update)
  • Further exploration into VOIP (the asterisk server is working fine as it is though...)
  • Configuring reverse DNS entries for my IPv6 subnet
  • Honing my reversing skills further with more crackmes and wargames
There is also the need for a job somewhere in there... but that'll hopefully sort itself out while I play around... right?

Friday, November 5, 2010

Monitoring ActiveX execution

Intro

My project this year involved hooking the load of ActiveX modules, and the next step is to actually monitor its execution and check for exploits. Let's take a step back first and have a recap of the ways in which a piece of software can be exploited.

Exploits

To exploit an application, there are two steps - injecting code, and altering the flow of execution. There are many ways of injecting code, and these are often hard to distinguish from legitimate data provisioning, so we will look at ways in which the flow of data can be altered. They are as follows:
  1. Overwriting a segment of code. This is the hammer in our knife set, as not only is it almost impossible (without having first exploited the application anyway), it destroys the underlying data.
  2. Overwriting a pointer which is used by a JMP or CALL command. This is slightly more precise, but requires somehow overwriting a specific part of memory, which is also quite difficult, but is much more feasible than #1
  3. Overwriting the pointer to the previous stack frame. This is traditionally done through an overflow of a stack-based buffer, but can also be done by a heap overflow exploit. This used to be quite common, but there is a fourth option that has come into play recently
  4. Overwriting the pointer to an exception handler. This requires that an exception be somehow triggered, and that the handler is in a module that doesn't have safeSEH activated. It's a bit of a stretch, but it is one of the ways that DEP is bypassed in modern exploits.
Now I'm by no means an expert here, but I think it's safe to rule out #1 due to code sections generally not having write privileges, and tentatively rule out #2, although a clever heap overflow exploit could take advantage of something like this (although the reason I can think of is in a non-DEP environment while trying to evade detection techniques such as the one described below, since in a non-DEP environment, #3 is much easier).

This leaves us with #3 and #4, each of which requires very different approaches. #3 should theoretically be disabled by DEP, however applications which have memory spaces that are both writeable and executable are still vulnerable, since an overflow would load the following addresses in the stack frame (memcpy, [padding DWORDs for each argument of the original function], address of w/x memory, address of w/x memory, address of shellcode, pointer to length) which would make the return instruction jump to the memcpy function, copy the shellcode to the w/x buffer, and then on return execute that memory. Given also that not every computer has DEP enabled (even windows 7 it is a per-application opt-in by default), and old hardware may not be DEP capable, this is still an area where protection is required.

An approach for protecting against attacks in category #4 requires that either modifications to the SEH chain are monitored, or that each SEH handler is tested when an exception is raised. The first option means breakpointing every SEH record in the chain (easy, but requires lots of breakpoints). The advantage of this is that the instruction pointer can be checked for every modification to the SEH chain, and suspicious modifications can be flagged (eg writes from within HeapFree and the like are probably a result of a heap overflow). The second option is a little easier but possibly not as effective, however the advantage lies in how non-invasive it is - the KiDispatchUserException function is patched to add extra checks, and these checks can include checking the page that the handler is executing from - if it's writeable (which is normally not the case for executable memory), then mark as suspicious.

Category #3 attacks are still important to block, even on modern systems. As mentioned earlier, even windows 7 uses the optin DEP rather than optout scheme for most apps, and apps that do take advantage of this can be circumvented by a return-to-libc attack, although with aslr this becomes more difficult. Since these (and most of category #2 except JMP[] ) all alter the stack, it is sufficient to breakpoint stack memory, and then either keep a separate collection of stack frames to compare after each RET instruction, or just check the permissions of the memory that the instruction pointer references.

ActiveX

Applying these to ActiveX modules is fairly straightforward. For performance reaspns it's best not to trace through the whole execution, but rather activate monitors when they're needed. Fortunately, the ActiveX interface makes this easy for us.

Each ActiveX object is instantiated by the CoGetClassObject() function, which returns an IClassFactory object, which exports a CreateInstance function. The first step then, is to hook CoGetClassObject() and then the CreateInstance function of every IClassFactory which is returned.

After this, we can detect the instantiation of every object, each of which contains a reference to its vtable, which is a structure containing references to functions and data objects. The function references point to functions in code memory, while the object references point to data memory, so these are easy to distinguish. A memory breakpoint across the whole structure allows us to hook every function that is called, and every object that is referenced.

Cunning plan
  1. Hook the CoGetClassObject function
  2. Hook the IClassFactory::CreateInstance function on every IClassFactory returned
  3. Breakpoint the vtable of every IUnknown returned
  4. Implement stack breakpoints whenever ActiveX functions are called

Once this is set up, every RET instruction will invoke a check of the stack to see if the destination memory is writeable and/or in data memory (covering #3), and at some stage this same function needs to be patched into KiDispatchUserException (covering #4) giving us fairly high confidence that any low level exploits will be detected.

Sunday, October 24, 2010

ARP reloaded: The IPv6 ping replay attack

I've been thinking about my neighbour solicitation replay concept today, and thought I would clarify a few points
  1. Sometimes (more rarely than on IPv4) these are sent to multicast/broadcast, and this can be detected by checking the destination MAC (FFFFFFFF for broadcast, 33:33:xx:xx:xx:xx for multicast)
  2. Unicast neighbour solicitation and neighbour advertisement packets can't be distinguished just from packet length (although if an obvious exchange of 2 packets occurs this can be inferred)
  3. Neighbour advertisement packets don't elicit replies
  4. The ICMPv6 packet does LOTS of things, some of which also demand a reply.
So I had a look at RFC4443 again, checked my dumps, and realised that the neighbour advertisement packets are far from useless. Let's have a look at the NA packet format:

       0                   1                   2                   3
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |     Type      |     Code      |          Checksum             |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |R|S|O|                     Reserved                            |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |                                                               |
      +                                                               +
      |                                                               |
      +                       Target Address                          +
      |                                                               |
      +                                                               +
      |                                                               |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |   Options ...
      +-+-+-+-+-+-+-+-+-+-+-+-
And then compare this to the echo request packet format

       0                   1                   2                   3
       0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |     Type      |     Code      |          Checksum             |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |           Identifier          |        Sequence Number        |
      +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      |     Data ...
      +-+-+-+-+-

The NA packet has type=136, code=0 and a checksum which is merely a sum of the packet as a set of 16-bit words. The echo request has type=128, code=0, same checksum style. It also has an identifier (can be anything) and a sequence number (can be anything) and room for any amount of data afterwards.

What does this mean? This means changing the type field from 136 to 128 (flipping bit 4) and adding 0x800 to the checksum converts this packet from a neighbour advertisement packet destined to a node which specifically requested it, into an echo request packet aimed at a node which we know to be alive and which is obliged to respond!

It works fine in plaintext, but what extra challenges are added when manipulating WEP encrypted packets?
  1. The ICV is a value appended to the end of a WEP encrypted packet. It is essentially the CRC-32 of the packet's contents, and due to its calculation by interpreting the packet data as polynomials rather than integers, this can be easily altered by XORing it with the CRC-32 of the changes made to the packet.
  2. The ICMPv6 checksum is slightly harder than this. Because the packet has been XORed against the keystream, an addition of 0x800 to the checksum may require flipping more than just bit 12. For example, if the checksum was 0x3800, an addition of 0x800 would result in a value of 0x4000, which requires bits 12, 13, 14 and 15 be flipped. Since the checksum is a ones-compliment sum, the worst case of a checksum initially being 0xFFFF would require 17 flips (with bit 12 being flipped once at the start and at the end). Fortunately this is unlikely, and in actual fact 50% of the time only 1 bit would need to be flipped, so one could easily discard half the NA packets, or could continue flipping bits until replies are sent.
I haven't tested this yet, but will try to get some code together soon. If nothing else, this just shows how easy it is to modify existing attacks for WEP, but it also shows the advantage (from an attacker's point of view) of having ARP functionality built into IPv6.

Friday, October 22, 2010

IPv6 Neighbour solicitation replay attack

After setting up an ad-hoc WEP network (with the totally secure key of 12:34:56:78:90 - not actually that uncommon in practise unfortunately) I set up airodump and tested aireplay-ng's replay feature (which only does ARP packets, so gave me no results), and from the amount of traffic generated (cat /dev/urandom over ssh) aircrack-ng managed to somehow retrieve the key! I had a bit more of a search and a look through the aircrack code, and I can only assume that aircrack got lucky with its bruteforcing stage, as there is no reference anywhere to it actively cracking from IPv6 packets. This isn't totally unbelievable, given that the first 8 bytes (the LLC header) are the same between IPv4 and IPv6, but was still surprising.

Instead of trying to implement an IPv6 extension to aircrack at this stage, I thought it would be interesting to modify aireplay-ng to allow it to replay neighbour solicitation requests. This turned out to only require a couple of modifications (removing the last check from the filter_packet function for broadcast MAC addresses at line 590ish and adding checks for lengths 112 and 104 at line 2500ish), and I was ready to go. The test didn't work quite as well as I wanted it to - it only seemed to generate single advertisements a few seconds apart, but I'll put this down to the linux and bsd boxes I was using (rfc4861 makes no mention of waiting between packets) - a windows box (aka ARP farm) should give the the results I want.

Next steps:
  1. Test if my ARP farm windows boxes also work as NA farms
  2. Possibly add some code to aireplay to distinguish between NA and NS packets based on the responses elicited
  3. Look deeper into the aircrack code and find where it parses IPv4 packets, and add IPv6 functionality (and a -6 switch?)

IPv6 WEP cracking

Those of you with interests in security will no doubt know how trivial it is to break WEP keys using a known-plaintext attack to recover the first 16 bytes of keystream for each packet, and then executes the PTW attack once there are about 20,000-80,000 packets captured. The original known-plaintext attack for IPv4 relied on the predictability of the first 16 bytes of ARP packets, the first 8 being the LLC header (always the same) and the first 8 bytes of the ARP header (the same except for the last byte, but this is predictable based on the MAC addresses - ARP requests are broadcast, ARP replies are unicast). Gathering ARP packets was made even easier due to the ARP replay attack - where a captured ARP request is replayed to quickly generate large numbers of ARP replies, each encrypted with a different IV.

The PTW attack with its ability to determine non-consecutive key bytes made a passive attack more feasible too - normal IP packets can be used, and the two bytes which are assumed to be random (the identification field) can be bruteforced.

Unfortunately, WEP was more or less left untouched after 2007, with a few extensions to the PTW attack, and reapplication of KoreK's correlations, but there doesn't appear to be an IPv6 version of this yet (EDIT: aircrack actually decrypted the dump of my ipv6 test). IPv6 requires that we find ways of implementing both a replay attack, and a passive attack, however it appears that they have a lot more in common on IPv6 than they did under IPv4.

Because IPv6 uses ICMPv6 instead of ARP for its neighbour discovery (RFC 4861), only an attack on the IPv6 header is required, which makes life easier. So assuming the LLC header stays the same (will confirm later), let's have a look at the first 8 bytes:

Byte 0.5: Version (6) - this is trivial if we know the network is running IPv6 (can infer this from IPv6 multicast MAC addresses)
Bytes 1-4:  Traffic class and Flowlabel - 0 if no QoS/MPLS is implemented
Bytes 5-6: Payload length (can be deduced from packet length)
Byte 7: Next header (is probably going to be TCP, UDP or ICMP)
Byte 8: Hop limit (I've seen 255 and 1 for local packets, 128 for leaving packets, and various numbers for packets received from outside the LAN).

As we can see, quite a bit of this can be easily guessed. If we're simply intercepting LAN traffic, then it's unlikely that the traffic class and flow label fields are giong to be used, making our first 4 bytes 0, the payload byte is guessable (total 6 predictable bytes so far). The next header field is in practise only going to be one of 3 values (and if the length matches can be assumed to be ICMP, or if it is too long can be assumed to be TCP/UDP), which leaves us with the hop limit field, which can easily be bruteforced (as the current IPv4 attack shows that bruteforcing 2 bytes is feasible).

For a replay attack, an ICMPv6 Neighbour solicitation packet is required. Unfortunately for us, there is no obvious way to distinguish between solicitation and advertisement packets, so it is somewhat trial and error, at least when unicast solicitations happen. From what I've seen in my (incredibly limited) tests, these happen more frequently than ARP exchanges on IPv4, which should make it easier to capture neighbour solicitations.

Neighbour solicitation/advertisement packets are always 64/72 bytes long (only counting the IPv6 and ICMP headers + payload), so packets of this length can be assumed (possibly incorrectly) to be neighbour solicitation/advertisements, which gives us a 50/50 chance of getting a solicitation packet. But what if we have an advertisement, and want to convert it into a solicitation, what do we need to do?

Firstly, the type needs to be changed from 136 to 135. Secondly, the field that was used for flags is reserved in the solicitation packet, so this should be zeroed (trial and error on the 3 currently used bits, or just assume the recipient is going to ignore this field). Thirdly, if the option is set (dest link-layer address) this needs to be changed, which can easily be done by xoring the MAC addresses from the unencrypted link layer header. This leaves us with one final problem - swapping the source and destination IP addresses from the IP header. To do this would require inside knowledge, and it is probably easier to break the WEP key passively than try and guess these, but what would we need to do if we could figure them out? The checksum used here isn't cryptographically secure, and can be updated in the same way as the WEP ICV because we know which bits have been altered, so the packet can then be used for replaying... but this isn't realistic.

In summary:
  • WEP is still a stupid idea
  • If QoS and MPLS aren't being used, the passive attack is easier than under IPv4
  • The new "ARP" replay attack should work just as well as the old one


References:
  1. Breaking 104 bit WEP in less than 60 seconds 
  2. http://tools.ietf.org/html/rfc4861
  3. http://tools.ietf.org/html/rfc4443

    Wednesday, October 20, 2010

    IPv6 touchup

    My home network is largely sorted for IPv6 with just a couple of problems

    1. My windows boxes don't get default routes
    2. My linux boxes use the prefix from the route advertisement rather than from DHCPv6
    It turns out you need to explicitly tell radvd to send out a default route or else windows won't pick it up, whereas linux does this automatically. The following radvd.conf file fixed this for me:

    interface eth1
    {
       AdvSendAdvert on;
       AdvManagedFlag on;
       MinRtrAdvInterval 3;
       MaxRtrAdvInterval 10;
       prefix 2001:1234:5678:1::/64
       {
          AdvOnLink on;
          AdvAutonomous on;
          AdvRouterAddr on;
       };
       route ::/0{
       };
    };  


    Meanwhile the DHCPv6 problem was due to debian not having a DHCPv6 client by default. I downloaded wide-dhcpv6-client, played with the config for a bit, and finally got something that worked:

    interface eth0
    {
      send ia-na 1;
      request domain-name-servers;
      request domain-name;
    };

    id-assoc na 1 {
    };


    One point to remember is that you need to manually create a duid, and this can be done with wide_mkduid.pl (which you can find easily on google), and this allows you to query DHCPv6 from debian.

    This still doesn't fix windows xp however, but it's getting old now, so hopefully it won't be an issue once people finally start migrating properly to IPv6.

    In other news, the gsm729 codec worked well with my SIP server, allowing me  to make softphone calls to cellphones, but when using my n95 through the sip server I still couldn't hear anything back... so a bit more investigation to be done yet.

    Sunday, October 17, 2010

    79228162514264337593543950336 addresses

    My subnet request got approved! Let's go through some of the details.

    Naturally, the first thing to set up was the firewall (because the best way to implement security is from the start). After hacking together bits and pieces from various scripts on the net, I managed to put together something that let everything out and only ssh in.

    # Always accept loopback traffic
    ip6tables -A INPUT -i lo -j ACCEPT

    # Always accept traffic from the inside
    ip6tables -A INPUT -i eth1 -j ACCEPT
    # Allow all ICMP traffic
    ip6tables -A INPUT -p icmpv6 -j ACCEPT

    # make sure in-new chain is open
    ip6tables -N in-new
    ip6tables -N fw-new

    # Strict sixxs
    ip6tables -A INPUT -i sixxs -m state --state RELATED,ESTABLISHED -j ACCEPT
    ip6tables -A INPUT -i sixxs -m state --state NEW -j in-new
    ip6tables -A FORWARD -i sixxs -o eth1 -m state --state NEW -j fw-new

    # Inbound sixxs connections
    ip6tables -A in-new -p tcp -m tcp --dport 22 --syn -j ACCEPT
    ip6tables -A in-new -p udp -m udp --dport 53 -j ACCEPT
    ip6tables -A in-new -j REJECT
    ip6tables -A fw-new -j REJECT

    # Reject everything else
    ip6tables -A INPUT -i sixxs -j REJECT


    With this set up, the next step was to get DHCP going. Unfortunately it wasn't that simple - address, router, and DNS setup is split into two separate categories, with router advertisement and IP autoconf done through ICMPv6 (requiring a router advertisement server) and DNS and some IP hints done through DHCPv6.

    I installed radvd, and after some playing ended up with the following conf file:

    interface eth1
    {
       AdvSendAdvert on;
       AdvManagedFlag on;
       MinRtrAdvInterval 3;
       MaxRtrAdvInterval 10;
       prefix 2001:1234:5678:1::/64
       {
          AdvOnLink on;
          AdvAutonomous on;
          AdvRouterAddr on;
       };
    };


    The AdvManagedFlag was something that tripped me up, it tells hosts to still look for DHCPv6 for DNS and further IP hints, while AdvAutonomous meant that they would do global IPv6 autoconf.

    Next step was DHCPv6. There were a couple of packages, but I ended up settling for wide-dhcpv6. The config for this looked like so:

    option domain-name-servers fe80::4428:200:94:20;

    interface eth1 {
            address-pool pool1 3600;
            send domain-name-servers;
    };

    pool pool1{
            range
    2001:1234:5678:1:cafe:f00d::1000 to 2001:1234:5678:1:cafe:f00d::2000;
    };

    host gary {
            duid 00:03:00:07:12:7a:34:02:38:a0:9a:47:7f:09;
            address
    2001:1234:5678:1:cafe:f00d::123 1800 7200;
    };


    I was surprised with the DUID entries, I have yet to find out why this is used instead of MAC address for stateful DHCPv6 setup, but nonetheless it's working now.

    Next step was to get ipv6 set up on all my machines. My windows 7 box proved most difficult, however once it was sorted it even picked up the DHCPv6 IP hints without any problem, although I still had to manually set a route in netsh.

    My debian laptop worked fine, and as with my archlinux virtual machine, the ipv6 module needed to be loaded (added to /etc/modules to auto load on boot).

    Windows XP was just as easy - netsh interface ipv6 install, and it picked up everything fine.

    I'm enjoying this tunnel, and as you can see from the configs, I've already started finding ways to play with my addresses. I can now see the dancing kame.net turtle, and interestingly the list of friends in chat on facebook looks different on their ipv6 page (tiled by profile photo, rather than listed).

    Next step: start using ipv6 versions of things, and finding ipv6 services to use!

    Untl then though, I need to get my codecs sorted, so I can start calling mobile phones through my VOIP setup...