• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Ivy Bridge Lenovo ThinkPad Internal Flashing
2
3## Introduction
4
5Old versions of stock BIOS for these models have several security issues.
6In order to flash coreboot internally, two of them are of interest.
7
8**First** is the fact the `SMM_BWP` and `BLE` are not enabled in BIOS
9versions released before 2014. We have tested many versions on T430 and
10X230 and found out that `SMM_BWP=1` only since the update, the changelog
11of which contains following line:
12
13> (New) Improved the UEFI BIOS security feature.
14
15**Second** is [S3 Boot Script vulnerability](https://support.lenovo.com/eg/ru/product_security/s3_boot_protect),
16that was discovered and fixed later.
17
18## Requirements
19
20- USB drive (in case you need to downgrade BIOS)
21- Linux install that (can be) loaded in UEFI mode
22```{toctree}
23:maxdepth: 1
24
25CHIPSEC <https://github.com/chipsec/chipsec>
26```
27
28## BIOS versions
29
30Below is a table of BIOS versions that are vulnerable enough for our
31goals, per model. The version number means that you need to downgrade to
32that or earlier version.
33
34```{eval-rst}
35+------------+--------------+
36| Model      | BIOS version |
37+============+==============+
38| X230       | 2.60         |
39+------------+--------------+
40| X230T      | 2.58         |
41+------------+--------------+
42| T430       | 2.64         |
43+------------+--------------+
44| T430s      | 2.59         |
45+------------+--------------+
46| T530       | 2.60         |
47+------------+--------------+
48| W530       | 2.58         |
49+------------+--------------+
50```
51
52If your BIOS version is equal or lower, skip to the
53**[Examining protections](#examining-protections-theory)** section. If not,
54go through the downgrade process, described next.
55
56## Downgrading BIOS
57
58Go to the Lenovo web site and download BIOS Update Bootable CD for your
59machine of needed version (see above).
60
61Lenovo states that BIOS has "security rollback prevention", meaning once
62you update it to some version X, you will not be able to downgrade it to
63pre-X version. That's not true. It seems that this is completely
64client-side restriction in flashing utilities (both Windows utility and
65Bootable CD). You just need to call `winflash.exe` or `dosflash.exe`
66directly. Therefore you need to modify the bootable CD image you just
67downloaded.
68
69Extract an El Torito image:
70
71    geteltorito -o ./bios.img g1uj41us.iso
72
73Mount the partition in that image:
74
75    sudo mount -t vfat ./bios.img /mnt -o loop,offset=16384
76
77List files, find the `AUTOEXEC.BAT` file and the `FLASH` directory:
78
79    ls /mnt
80    ls /mnt/FLASH
81
82Inside the `FLASH` directory, there should be a directory called
83`G1ET93WW` or similar (exact name depends on your ThinkPad model and
84BIOS version). See what's inside:
85
86    ls /mnt/FLASH/G1ET93WW
87
88There must be a file with `.FL1` extension called `$01D2000.FL1` or
89something similar.
90
91Now open the `AUTOEXEC.BAT` file:
92
93    sudo vim /mnt/AUTOEXEC.BAT
94
95You will see a list of commands:
96
97    @ECHO OFF
98    PROMPT $p$g
99    cd c:\flash
100    command.com
101
102Replace the last line (`command.com`) with this (change path to the
103`.FL1` file according to yours):
104
105    dosflash.exe /sd /file G1ET93WW\$01D2000.FL1
106
107Save the file, then unmount the partition:
108
109    sudo umount /mnt
110
111Write this image to a USB drive (replace `/dev/sdX` with your USB drive
112device name):
113
114    sudo dd if=./bios.img of=/dev/sdX bs=1M
115
116Now reboot and press F1 to enter BIOS settings. Open the **Startup** tab
117and set the startup mode to **Legacy** (or **Both**/**Legacy First**):
118
119![](ivb_bios_legacy_only.jpg)
120
121Press F10 to save changes and reboot.
122
123Now, before you process, make sure that AC adapter is connected! If your
124battery will die during the process, you'll likely need external
125programmer to recover.
126
127Boot from the USB drive (press F12 to select boot device), and BIOS
128flashing process should begin:
129
130![](ivb_bios_flashing1.jpg)
131
132![](ivb_bios_flashing2.jpg)
133
134It may reboot a couple of times in the process. Do not interrupt it.
135
136When it's completed, go back to the BIOS settings and set startup mode
137to **UEFI** (or **Both**/**UEFI First**). This is required for
138vulnerability exploitation.
139
140![](ivb_bios_uefi_only.jpg)
141
142Then boot to your system and make sure that `/sys/firmware/efi` or
143`/sys/firmware/efivars` exist.
144
145## Examining protections (theory)
146
147There are two main ways that Intel platform provides to protect BIOS
148chip:
149- **BIOS_CNTL** register of LPC Interface Bridge Registers (accessible
150    via PCI configuration space, offset 0xDC). It has:
151  * **SMM_BWP** (*SMM BIOS Write Protect*) bit. If set to 1, the BIOS is
152    writable only in SMM. Once set to 1, cannot be changed anymore.
153  * **BLE**  (*BIOS Lock Enable*) bit. If set to 1, setting BIOSWE to 1
154    will raise SMI. Once set to 1, cannot be changed anymore.
155  * **BIOSWE** (*BIOS Write Enable*) bit. Controls whether BIOS is
156    writable. This bit is always R/W.
157- SPI Protected Range Registers (**PR0**-**PR4**) of SPI Configuration
158  Registers (SPIBAR+0x74 - SPIBAR+0x84). Each register has bits that
159  define protected range, plus WP bit, that defines whether write
160  protection is enabled.
161
162  There's also **FLOCKDN** bit of HSFS register (SPIBAR+0x04) of SPI
163  Configuration Registers. When set to 1, PR0-PR4 registers cannot be
164  written. Once set to 1, cannot be changed anymore.
165
166To be able to flash, we need `SMM_BWP=0`, `BIOSWE=1`, `BLE=0`, `FLOCKDN=0` or
167SPI protected ranges (PRx) to have a WP bit set to 0.
168
169Let's see what we have. Examine `HSFS` register:
170
171    sudo chipsec_main -m chipsec.modules.common.spi_lock
172
173You should see that `FLOCKDN=1`:
174
175    [x][ =======================================================================
176    [x][ Module: SPI Flash Controller Configuration Locks
177    [x][ =======================================================================
178    [*] HSFS = 0xE009 << Hardware Sequencing Flash Status Register (SPIBAR + 0x4)
179        [00] FDONE            = 1 << Flash Cycle Done
180        [01] FCERR            = 0 << Flash Cycle Error
181        [02] AEL              = 0 << Access Error Log
182        [03] BERASE           = 1 << Block/Sector Erase Size
183        [05] SCIP             = 0 << SPI cycle in progress
184        [13] FDOPSS           = 1 << Flash Descriptor Override Pin-Strap Status
185        [14] FDV              = 1 << Flash Descriptor Valid
186        [15] FLOCKDN          = 1 << Flash Configuration Lock-Down
187
188Then check `BIOS_CNTL` and PR0-PR4:
189
190    sudo chipsec_main -m common.bios_wp
191
192Good news: on old BIOS versions, `SMM_BWP=0` and `BLE=0`.
193
194Bad news: there are 4 write protected SPI ranges:
195
196     [x][ =======================================================================
197     [x][ Module: BIOS Region Write Protection
198     [x][ =======================================================================
199     [*] BC = 0x 8 << BIOS Control (b:d.f 00:31.0 + 0xDC)
200         [00] BIOSWE           = 0 << BIOS Write Enable
201         [01] BLE              = 0 << BIOS Lock Enable
202         [02] SRC              = 2 << SPI Read Configuration
203         [04] TSS              = 0 << Top Swap Status
204         [05] SMM_BWP          = 0 << SMM BIOS Write Protection
205     [-] BIOS region write protection is disabled!
206
207     [*] BIOS Region: Base = 0x00500000, Limit = 0x00BFFFFF
208     SPI Protected Ranges
209     ------------------------------------------------------------
210     PRx (offset) | Value    | Base     | Limit    | WP? | RP?
211     ------------------------------------------------------------
212     PR0 (74)     | 00000000 | 00000000 | 00000000 | 0   | 0
213     PR1 (78)     | 8BFF0B40 | 00B40000 | 00BFFFFF | 1   | 0
214     PR2 (7C)     | 8B100B10 | 00B10000 | 00B10FFF | 1   | 0
215     PR3 (80)     | 8ADE0AD0 | 00AD0000 | 00ADEFFF | 1   | 0
216     PR4 (84)     | 8AAF0800 | 00800000 | 00AAFFFF | 1   | 0
217
218Other way to examine SPI configuration registers is to just dump SPIBAR:
219
220    sudo chipsec_util mmio dump SPIBAR
221
222You will see `SPIBAR` address (0xFED1F800) and registers (for example,
223`00000004` is `HSFS`):
224
225    [mmio] MMIO register range [0x00000000FED1F800:0x00000000FED1F800+00000200]:
226    +00000000: 0BFF0500
227    +00000004: 0004E009
228    ...
229
230As you can see, the only thing we need is to unset WP bit on PR0-PR4.
231But that cannot be done once `FLOCKDN` is set to 1.
232
233Now the fun part!
234
235`FLOCKDN` may only be cleared by a hardware reset, which includes S3
236state. On S3 resume boot path, the chipset configuration has to be
237restored and it's done by executing so-called S3 Boot Scripts. You can
238dump these scripts by executing:
239
240    sudo chipsec_util uefi s3bootscript
241
242There are many entries. Along them, you can find instructions to write
243to `HSFS` (remember, we know that `SPIBAR` is 0xFED1F800):
244
245     Entry at offset 0x2B8F (len = 0x17, header len = 0x0):
246     Data:
247     02 00 17 02 00 00 00 01 00 00 00 04 f8 d1 fe 00 |
248     00 00 00 09 e0 04 00                            |
249     Decoded:
250       Opcode : S3_BOOTSCRIPT_MEM_WRITE (0x0002)
251       Width  : 0x02 (4 bytes)
252       Address: 0xFED1F804
253       Count  : 0x1
254       Values : 0x0004E009
255
256These scripts are stored in memory. The vulnerability is that we can
257overwrite this memory, change these instructions and they will be
258executed on S3 resume. Once we patch that instruction to not set `FLOCKDN`
259bit, we will be able to write to PR0-PR4 registers.
260
261## Creating a backup
262
263Before you proceed, please create a backup of the `bios` region. Then,
264in case something goes wrong, you'll be able to flash it back externally.
265
266The `me` region is locked, so an attempt to create a full dump will fail.
267But you can back up the `bios`:
268
269    sudo flashrom -p internal -r bios_backup.rom --ifd -i bios
270
271If you will ever need to flash it back, use `--ifd -i bios` as well:
272
273    sudo flashrom -p <YOUR_PROGRAMMER> -w bios_backup.rom --ifd -i bios
274
275**Caution:** if you will omit `--ifd -i bios` for flashing, you will
276brick your machine, because your backup has `FF`s in place of `fd` and
277`me` regions. Flash only `bios` region!
278
279## Removing protections (practice)
280
281The original boot script writes 0xE009 to `HSFS`. `FLOCKDN` is 15th bit, so
282let's write 0x6009 instead:
283
284    sudo chipsec_main -m tools.uefi.s3script_modify -a replace_op,mmio_wr,0xFED1F804,0x6009,0x2
285
286You will get a lot of output and in the end you should see something
287like this:
288
289     [*] Modifying S3 boot script entry at address 0x00000000DAF49B8F..
290     [mem] 0x00000000DAF49B8F
291     [*] Original entry:
292      2  0 17  2  0  0  0  1  0  0  0  4 f8 d1 fe  0 |
293      0  0  0  9 e0  4  0                            |
294     [mem] buffer len = 0x17 to PA = 0x00000000DAF49B8F
295      2  0 17  2  0  0  0  1  0  0  0  4 f8 d1 fe  0 |
296      0  0  0  9 60  0  0                            |     `
297     [mem] 0x00000000DAF49B8F
298     [*] Modified entry:
299      2  0 17  2  0  0  0  1  0  0  0  4 f8 d1 fe  0 |
300      0  0  0  9 60  0  0                            |     `
301     [*] After sleep/resume, check the value of register 0xFED1F804 is 0x6009
302     [+] PASSED: The script has been modified. Go to sleep..
303
304Now go to S3, then resume and check `FLOCKDN`. It should be 0:
305
306    sudo chipsec_main -m chipsec.modules.common.spi_lock
307
308    ...
309    [x][ =======================================================================
310    [x][ Module: SPI Flash Controller Configuration Locks
311    [x][ =======================================================================
312    [*] HSFS = 0x6008 << Hardware Sequencing Flash Status Register (SPIBAR + 0x4)
313        [00] FDONE            = 0 << Flash Cycle Done
314        [01] FCERR            = 0 << Flash Cycle Error
315        [02] AEL              = 0 << Access Error Log
316        [03] BERASE           = 1 << Block/Sector Erase Size
317        [05] SCIP             = 0 << SPI cycle in progress
318        [13] FDOPSS           = 1 << Flash Descriptor Override Pin-Strap Status
319        [14] FDV              = 1 << Flash Descriptor Valid
320        [15] FLOCKDN          = 0 << Flash Configuration Lock-Down
321    [-] SPI Flash Controller configuration is not locked
322    [-] FAILED: SPI Flash Controller not locked correctly.
323    ...
324
325Remove WP from protected ranges:
326
327    sudo chipsec_util mmio write SPIBAR 0x74 0x4 0xAAF0800
328    sudo chipsec_util mmio write SPIBAR 0x78 0x4 0xADE0AD0
329    sudo chipsec_util mmio write SPIBAR 0x7C 0x4 0xB100B10
330    sudo chipsec_util mmio write SPIBAR 0x80 0x4 0xBFF0B40
331
332Verify that it worked:
333
334    sudo chipsec_main -m common.bios_wp
335
336    [x][ =======================================================================
337    [x][ Module: BIOS Region Write Protection
338    [x][ =======================================================================
339    [*] BC = 0x 9 << BIOS Control (b:d.f 00:31.0 + 0xDC)
340        [00] BIOSWE           = 1 << BIOS Write Enable
341        [01] BLE              = 0 << BIOS Lock Enable
342        [02] SRC              = 2 << SPI Read Configuration
343        [04] TSS              = 0 << Top Swap Status
344        [05] SMM_BWP          = 0 << SMM BIOS Write Protection
345    [-] BIOS region write protection is disabled!
346
347    [*] BIOS Region: Base = 0x00500000, Limit = 0x00BFFFFF
348    SPI Protected Ranges
349    ------------------------------------------------------------
350    PRx (offset) | Value    | Base     | Limit    | WP? | RP?
351    ------------------------------------------------------------
352    PR0 (74)     | 0AAF0800 | 00800000 | 00AAF000 | 0   | 0
353    PR1 (78)     | 0ADE0AD0 | 00AD0000 | 00ADE000 | 0   | 0
354    PR2 (7C)     | 0B100B10 | 00B10000 | 00B10000 | 0   | 0
355    PR3 (80)     | 0BFF0B40 | 00B40000 | 00BFF000 | 0   | 0
356    PR4 (84)     | 00000000 | 00000000 | 00000000 | 0   | 0
357
358Bingo!
359
360Now you can [flash internally]. Remember to flash only the `bios` region
361(use `--ifd -i bios -N` flashrom arguments). `fd` and `me` are still
362locked.
363
364Note that you should have an external SPI programmer as a backup method.
365It will help you recover if you flash non-working ROM by mistake.
366
367
368[flash internally]: ../../tutorial/flashing_firmware/int_flashrom.md
369