├── CONTRIBUTING.md ├── LICENSE ├── README.md └── strng.c /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing Guidelines 2 | ======================= 3 | 4 | The preferred coding style for this project is the [QEMU Coding 5 | Style](https://git.qemu.org/?p=qemu.git;a=blob_plain;f=CODING_STYLE;hb=HEAD). 6 | See also the [QEMU Coding 7 | Guidelines](https://git.qemu.org/?p=qemu.git;a=blob_plain;f=HACKING;hb=HEAD). 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Ramon de C Valle 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included 12 | in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Blizzard CTF 2017: Sombra True Random Number Generator (STRNG) 2 | ============================================================== 3 | 4 | Sombra True Random Number Generator (STRNG) is a QEMU-based challenge I 5 | developed for Blizzard CTF 2017. The challenge was to achieve a VM escape 6 | from a QEMU-based VM and capture the flag located at /root/flag on the host. 7 | 8 | 9 | Installation 10 | ------------ 11 | 12 | The image used and distributed with the challenge was the Ubuntu Server 13 | 14.04 LTS Cloud Image. The host used the same image as the guest. The guest 14 | was reset every 10 minutes and was started with the following command: 15 | 16 | ./qemu-system-x86_64 \ 17 | -m 1G \ 18 | -device strng \ 19 | -hda my-disk.img \ 20 | -hdb my-seed.img \ 21 | -nographic \ 22 | -L pc-bios/ \ 23 | -enable-kvm \ 24 | -device e1000,netdev=net0 \ 25 | -netdev user,id=net0,hostfwd=tcp::5555-:22 26 | 27 | Access to the guest was provided by redirecting incoming connections to the 28 | host on port 5555 to the guest on port 22. The guest login was "ubuntu" with 29 | password "passw0rd". 30 | 31 | 32 | Usage 33 | ----- 34 | 35 | STRNG is a QEMU-based emulated hardware device. The device has four 32-bit 36 | registers accessible through memory-mapped I/O and port-mapped I/O: rand's 37 | seed (0), rand (1), rand_r's seed (2), and rand_r (3). These registers can 38 | be accessed directly using memory-mapped I/O at BAR0 or indirectly through 39 | the STRNG_PMIO_ADDR (0) and STRNG_PMIO_DATA (4) 32-bit ports using 40 | port-mapped I/O at BAR1. 41 | 42 | To generate a random number 43 | 1. Write the rand's seed to register 0. 44 | 2. Write to register 1 to call the device's rand implementation. 45 | 3. Read the generated random number from register 1. 46 | 47 | Or 48 | 1. Write the rand_r's seed to register 2. 49 | 2. Write to register 3 to call the device's rand_r implementation. 50 | 3. Read the generated random number from register 3. 51 | 4. Optional: Read the state of rand_r from register 2. 52 | 53 | 54 | Contributing 55 | ------------ 56 | 57 | See [CONTRIBUTING.md](CONTRIBUTING.md). 58 | 59 | 60 | License 61 | ------- 62 | 63 | Licensed under the MIT license. See [LICENSE](LICENSE) for license text and 64 | copyright information. 65 | -------------------------------------------------------------------------------- /strng.c: -------------------------------------------------------------------------------- 1 | #include "qemu/osdep.h" 2 | #include "hw/pci/pci.h" 3 | 4 | #define STRNG(obj) OBJECT_CHECK(STRNGState, obj, "strng") 5 | 6 | #define STRNG_MMIO_REGS 64 7 | #define STRNG_MMIO_SIZE (STRNG_MMIO_REGS * sizeof(uint32_t)) 8 | 9 | #define STRNG_PMIO_ADDR 0 10 | #define STRNG_PMIO_DATA 4 11 | #define STRNG_PMIO_REGS STRNG_MMIO_REGS 12 | #define STRNG_PMIO_SIZE 8 13 | 14 | typedef struct { 15 | PCIDevice pdev; 16 | MemoryRegion mmio; 17 | MemoryRegion pmio; 18 | uint32_t addr; 19 | uint32_t regs[STRNG_MMIO_REGS]; 20 | void (*srand)(unsigned int seed); 21 | int (*rand)(void); 22 | int (*rand_r)(unsigned int *seed); 23 | } STRNGState; 24 | 25 | static uint64_t strng_mmio_read(void *opaque, hwaddr addr, unsigned size) 26 | { 27 | STRNGState *strng = opaque; 28 | 29 | if (size != 4 || addr & 3) 30 | return ~0ULL; 31 | 32 | return strng->regs[addr >> 2]; 33 | } 34 | 35 | static void strng_mmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) 36 | { 37 | STRNGState *strng = opaque; 38 | uint32_t saddr; 39 | 40 | if (size != 4 || addr & 3) 41 | return; 42 | 43 | saddr = addr >> 2; 44 | switch (saddr) { 45 | case 0: 46 | strng->srand(val); 47 | break; 48 | 49 | case 1: 50 | strng->regs[saddr] = strng->rand(); 51 | break; 52 | 53 | case 3: 54 | strng->regs[saddr] = strng->rand_r(&strng->regs[2]); 55 | 56 | default: 57 | strng->regs[saddr] = val; 58 | } 59 | } 60 | 61 | static const MemoryRegionOps strng_mmio_ops = { 62 | .read = strng_mmio_read, 63 | .write = strng_mmio_write, 64 | .endianness = DEVICE_NATIVE_ENDIAN, 65 | }; 66 | 67 | static uint64_t strng_pmio_read(void *opaque, hwaddr addr, unsigned size) 68 | { 69 | STRNGState *strng = opaque; 70 | uint64_t val = ~0ULL; 71 | 72 | if (size != 4) 73 | return val; 74 | 75 | switch (addr) { 76 | case STRNG_PMIO_ADDR: 77 | val = strng->addr; 78 | break; 79 | 80 | case STRNG_PMIO_DATA: 81 | if (strng->addr & 3) 82 | return val; 83 | 84 | val = strng->regs[strng->addr >> 2]; 85 | } 86 | 87 | return val; 88 | } 89 | 90 | static void strng_pmio_write(void *opaque, hwaddr addr, uint64_t val, unsigned size) 91 | { 92 | STRNGState *strng = opaque; 93 | uint32_t saddr; 94 | 95 | if (size != 4) 96 | return; 97 | 98 | switch (addr) { 99 | case STRNG_PMIO_ADDR: 100 | strng->addr = val; 101 | break; 102 | 103 | case STRNG_PMIO_DATA: 104 | if (strng->addr & 3) 105 | return; 106 | 107 | saddr = strng->addr >> 2; 108 | switch (saddr) { 109 | case 0: 110 | strng->srand(val); 111 | break; 112 | 113 | case 1: 114 | strng->regs[saddr] = strng->rand(); 115 | break; 116 | 117 | case 3: 118 | strng->regs[saddr] = strng->rand_r(&strng->regs[2]); 119 | break; 120 | 121 | default: 122 | strng->regs[saddr] = val; 123 | } 124 | } 125 | } 126 | 127 | static const MemoryRegionOps strng_pmio_ops = { 128 | .read = strng_pmio_read, 129 | .write = strng_pmio_write, 130 | .endianness = DEVICE_LITTLE_ENDIAN, 131 | }; 132 | 133 | static void pci_strng_realize(PCIDevice *pdev, Error **errp) 134 | { 135 | STRNGState *strng = DO_UPCAST(STRNGState, pdev, pdev); 136 | 137 | memory_region_init_io(&strng->mmio, OBJECT(strng), &strng_mmio_ops, strng, "strng-mmio", STRNG_MMIO_SIZE); 138 | pci_register_bar(pdev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY, &strng->mmio); 139 | memory_region_init_io(&strng->pmio, OBJECT(strng), &strng_pmio_ops, strng, "strng-pmio", STRNG_PMIO_SIZE); 140 | pci_register_bar(pdev, 1, PCI_BASE_ADDRESS_SPACE_IO, &strng->pmio); 141 | } 142 | 143 | static void strng_instance_init(Object *obj) 144 | { 145 | STRNGState *strng = STRNG(obj); 146 | 147 | strng->srand = srand; 148 | strng->rand = rand; 149 | strng->rand_r = rand_r; 150 | } 151 | 152 | static void strng_class_init(ObjectClass *class, void *data) 153 | { 154 | PCIDeviceClass *k = PCI_DEVICE_CLASS(class); 155 | 156 | k->realize = pci_strng_realize; 157 | k->vendor_id = PCI_VENDOR_ID_QEMU; 158 | k->device_id = 0x11e9; 159 | k->revision = 0x10; 160 | k->class_id = PCI_CLASS_OTHERS; 161 | } 162 | 163 | static void pci_strng_register_types(void) 164 | { 165 | static const TypeInfo strng_info = { 166 | .name = "strng", 167 | .parent = TYPE_PCI_DEVICE, 168 | .instance_size = sizeof(STRNGState), 169 | .instance_init = strng_instance_init, 170 | .class_init = strng_class_init, 171 | }; 172 | 173 | type_register_static(&strng_info); 174 | } 175 | type_init(pci_strng_register_types) 176 | --------------------------------------------------------------------------------