Thursday, January 27, 2011

ASFRecorder

As fantastic as streaming audio and video are, sometimes it's nice to reply things later. As far as websites which host .flv go, the act of saving the media file is fairly trivial, and is done by a wide range of browser plugins. Websites which actually rely on a client-side stream player are a different story though...

I was after a simple option, and ideally something single-purpose. Apps like VLC are up to the task, but a bit too big to bundle in a plugin, and lack some desired features (like resuming, in the case of VLC). There is a Japanese app called GetASFStream which appears to do a good job, and even rebuilds the header based on the streams chosen (which as far as I can tell simply chooses the first audio and video streams). There's a couple of problems though - it's in japanese, doesn't appear to be open source, and doesn't appear to have commandline support. So the search continues...

I then stumbled across the code for an application called ASFRecorder. It appears to be unchanged since 2001, and as a result, lacks a few features.

For starters, it doesn't recognise the content type "application/vnd.ms.wms-hdr.asfv1", which Microsoft gives little data on, but it appears I'm not the only one to come across this problem.

Once I'd patched the code to take newer ContentType values, I came to another problem - it doesn't parse the payload parsing information section properly - instead of actually interpreting it as per the spec (which is freely downloadable), it appears as if the original author picked a few common values, or found them from trial and error, instead of calculating the length as a general case function. Once this is fixed, ASFRecorder happily dumps the stream to a file, but we're not done yet!

As described here, ASFRecorder only downloads the first stream, and dumps the header has it. This is quite messy, but the attempt is quite a valid one - if the stream is dumped directly to a file, then in theory it can be played straight back. However, it appears the code was only ever written for single stream broadcasts, which means the user is limited to either audio streams, or soundless video streams (ie. radio or porn), and so despite the file being written with a multi-stream header, only the first stream is saved.

I decided to undertake the rewarding task of building my own header parser app (which I might post if anybody cares enough to look at the code) so I could compare the (incorrect) output of ASFRecorder with the (correct) output of GetASFStream. After comparing the two headers, and trying (unsuccessfully) to simply paste the header from the correct dump onto the incorrect one (which stopped it from playing completely), I discovered that the reason ASFRecorder was only dumping a single stream was because that's all it was asking for.

By changing the hardcoded reply message so that it asks for two streams instead of one, my dump is suddenly working correctly! However, there is a bit more tidying that needs to be done, and some of it is necessary before release, but there is also some I can save until later

  • Actually coding a general parser for the payload parsing information
  • Changing the handler to take all MIME types for ASF files
  • Parsing the return value from the server to give a proper selection of streams
  • Processing the whole header, writing a new one, and arranging the streams accordingly
  • Building a proper resume function to compensate for the new header
  • Somewhere along the line incorporating this into a browser plugin
And that's all.... looks fairly straightforward.

One final comment to make about the ASF file format - it's actually logical. The last time I messed with m$ file formats was DIB and WAV files, each with their own quirks and rude deviations from the standard. It seems when m$ does their writing from scratch, they do a proper job of it.

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.