├── pic
├── fit.png
├── hap.png
├── ipc.png
├── rom.png
├── amibcp.png
├── build.png
├── dcion.png
├── dfxagg.png
├── dissig.png
├── meinfo.png
├── txebin.png
├── TXERegion.png
├── bootguard.png
├── buildsucc.png
├── tracehub.png
├── usbdebug.png
└── cpu_me_halt.png
├── utock_gen.py
├── openipc_key_extract.py
├── me_exp_bxtp.py
├── patch.diff
├── config_decryptor.py
└── README.md
/pic/fit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ptresearch/IntelTXE-PoC/HEAD/pic/fit.png
--------------------------------------------------------------------------------
/pic/hap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ptresearch/IntelTXE-PoC/HEAD/pic/hap.png
--------------------------------------------------------------------------------
/pic/ipc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ptresearch/IntelTXE-PoC/HEAD/pic/ipc.png
--------------------------------------------------------------------------------
/pic/rom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ptresearch/IntelTXE-PoC/HEAD/pic/rom.png
--------------------------------------------------------------------------------
/pic/amibcp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ptresearch/IntelTXE-PoC/HEAD/pic/amibcp.png
--------------------------------------------------------------------------------
/pic/build.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ptresearch/IntelTXE-PoC/HEAD/pic/build.png
--------------------------------------------------------------------------------
/pic/dcion.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ptresearch/IntelTXE-PoC/HEAD/pic/dcion.png
--------------------------------------------------------------------------------
/pic/dfxagg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ptresearch/IntelTXE-PoC/HEAD/pic/dfxagg.png
--------------------------------------------------------------------------------
/pic/dissig.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ptresearch/IntelTXE-PoC/HEAD/pic/dissig.png
--------------------------------------------------------------------------------
/pic/meinfo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ptresearch/IntelTXE-PoC/HEAD/pic/meinfo.png
--------------------------------------------------------------------------------
/pic/txebin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ptresearch/IntelTXE-PoC/HEAD/pic/txebin.png
--------------------------------------------------------------------------------
/pic/TXERegion.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ptresearch/IntelTXE-PoC/HEAD/pic/TXERegion.png
--------------------------------------------------------------------------------
/pic/bootguard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ptresearch/IntelTXE-PoC/HEAD/pic/bootguard.png
--------------------------------------------------------------------------------
/pic/buildsucc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ptresearch/IntelTXE-PoC/HEAD/pic/buildsucc.png
--------------------------------------------------------------------------------
/pic/tracehub.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ptresearch/IntelTXE-PoC/HEAD/pic/tracehub.png
--------------------------------------------------------------------------------
/pic/usbdebug.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ptresearch/IntelTXE-PoC/HEAD/pic/usbdebug.png
--------------------------------------------------------------------------------
/pic/cpu_me_halt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ptresearch/IntelTXE-PoC/HEAD/pic/cpu_me_halt.png
--------------------------------------------------------------------------------
/utock_gen.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Unlock Token generator by Mark Ermolov (@_markel___)
3 | # Maxim Goryachy (@h0t_max)
4 | #
5 | # Details: https://github.com/ptresearch/IntelME-JTAG
6 | # https://github.com/ptresearch/IntelTXE-POC
7 |
8 | import argparse
9 | import struct
10 |
11 | UTFLOFFSET = 0x1fe0
12 |
13 | def parse_arguments():
14 | parser = argparse.ArgumentParser(description='Unlock Tocken generator')
15 | parser.add_argument('-f', help='path', type=str, default="utok.bin")
16 | return parser.parse_args().f;
17 |
18 | def genereate_utok():
19 | data = struct.pack("
6 |
7 |
8 | +
9 |
10 |
11 |
12 |
13 |
14 | +
15 | +
16 | +
17 | +
18 | +
19 | +
20 | +
21 | +
22 |
23 |
24 |
25 | @@ -138,12 +147,32 @@
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 | diff -ruN ./a/OpenIPC_1.1740.2381.100/Config/OpenIpcConfig.xml ./b/OpenIPC_1.1740.2381.100/Config/OpenIpcConfig.xml
63 | --- ./a/OpenIPC_1.1740.2381.100/Config/OpenIpcConfig.xml 2017-10-05 17:23:12.000000000 +0300
64 | +++ ./b/OpenIPC_1.1740.2381.100/Config/OpenIpcConfig.xml 2018-07-09 18:57:48.000000000 +0300
65 | @@ -1,7 +1,5 @@
66 |
67 | -
68 | -
69 | -
70 | -
71 | -
72 | +
73 | +
74 | +
75 |
76 | diff -ruN ./a/OpenIPC_1.1740.2381.100/Data/Xml/BXTP/ProductInfo.xml ./b/OpenIPC_1.1740.2381.100/Data/Xml/BXTP/ProductInfo.xml
77 | --- ./a/OpenIPC_1.1740.2381.100/Data/Xml/BXTP/ProductInfo.xml 2018-09-13 11:37:20.000000000 +0300
78 | +++ ./b/OpenIPC_1.1740.2381.100/Data/Xml/BXTP/ProductInfo.xml 2018-06-06 01:20:34.000000000 +0300
79 | @@ -4,21 +4,26 @@
80 |
81 |
82 |
83 | +
84 | +
85 | +
86 | +
87 | +
88 |
89 | -
90 | +
97 |
98 |
99 | -
100 | +
107 |
108 |
109 |
110 | diff -ruN ./a/OpenIPC_1.1740.2381.100/Data/Xml/BXTP/TapNetworks.B0.xml ./b/OpenIPC_1.1740.2381.100/Data/Xml/BXTP/TapNetworks.B0.xml
111 | --- ./a/OpenIPC_1.1740.2381.100/Data/Xml/BXTP/TapNetworks.B0.xml 2018-09-13 11:37:20.000000000 +0300
112 | +++ ./b/OpenIPC_1.1740.2381.100/Data/Xml/BXTP/TapNetworks.B0.xml 2018-06-04 20:18:32.000000000 +0300
113 | @@ -119,6 +119,7 @@
114 |
115 |
116 |
117 | +
118 |
119 |
120 |
121 |
--------------------------------------------------------------------------------
/config_decryptor.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # Decryptor for OpenIPC configuration by Mark Ermolov (@_markel___)
3 | # Maxim Goryachy (@h0t_max)
4 | #
5 | # Details: https://github.com/ptresearch/IntelME-JTAG
6 | # https://github.com/ptresearch/IntelTXE-POC
7 | from time import gmtime, strftime
8 | import os
9 | import sys
10 | import struct
11 | import shutil
12 | import zipfile
13 |
14 | from argparse import ArgumentParser as argpars
15 | from Crypto.Cipher import AES
16 | from Crypto.Hash import SHA as sha1
17 |
18 | try:
19 | xrange # Python 2
20 | except NameError:
21 | xrange = range # Python 3
22 |
23 |
24 | def create_backup(paths):
25 | archiveName = strftime("OpenIPC_backup_%Y%m%d_%H%M%S.zip", gmtime())
26 | zip = zipfile.ZipFile(archiveName, 'w', zipfile.ZIP_DEFLATED)
27 | for path in paths:
28 | for root, dirs, files in os.walk(path):
29 | for file in files:
30 | zip.write(os.path.join(root, file))
31 | zip.close()
32 |
33 | def decrypt_path(name):
34 | decryptName = ""
35 | counter = 0
36 | for c in name:
37 | if c == '_':
38 | decChar = ord('?')
39 | elif c == '-':
40 | decChar = ord('>')
41 | elif c == '\\' or c == '/' or c == '.':
42 | decryptName += c
43 | counter = 0
44 | continue
45 | elif c <= '9':
46 | decChar = ord(c) - ord('0')
47 | elif c <= 'Z':
48 | decChar = ord(c) - ord('7')
49 | elif c <= 'z':
50 | decChar = ord(c) - ord('=')
51 |
52 | counter += 1
53 | decChar = counter ^ decChar ^ 0xA
54 |
55 | if decChar == ord('?'):
56 | decChar = ord('_')
57 | elif decChar == ord('>'):
58 | decChar = ord('-')
59 | elif decChar >= ord('$') and decChar <= ord('='):
60 | decChar = decChar + ord('=')
61 | elif decChar >= ord('\n') and decChar <= ord('#'):
62 | decChar = decChar + ord('7')
63 | elif decChar <= ord('\t'):
64 | decChar = decChar + ord('0')
65 | else:
66 | decChar = ord(c)
67 | counter = 0
68 | decryptName += chr(decChar)
69 | return decryptName
70 |
71 | def copy_dir(srcPath, dstPath):
72 | for item in os.listdir(srcPath):
73 | src = os.path.join(srcPath, item)
74 | dst = os.path.join(dstPath, item)
75 | if os.path.isdir(src):
76 | shutil.copytree(src, dst, False, None)
77 | else:
78 | shutil.copy2(src, dst)
79 |
80 | class Decryptor:
81 | IVLEN = 16
82 | KEYLEN = 32
83 | COUNT = 5
84 | def __init__(self, key):
85 | self.iv, self.key = self.__bytes_to_key(key)
86 |
87 | def __bytes_to_key(self, key):
88 | d = ""
89 | hashStr = ""
90 | while len(hashStr) <= self.IVLEN + self.KEYLEN:
91 | sha = sha1.new()
92 | sha.update(d+key)
93 | d = sha.digest()
94 | for i in xrange(self.COUNT-1):
95 | sha = sha1.new()
96 | sha.update(d)
97 | d = sha.digest()
98 | hashStr += d
99 | key = hashStr[0:self.KEYLEN]
100 | iv = hashStr[self.KEYLEN:self.KEYLEN+self.IVLEN]
101 | return iv, key
102 |
103 | def __decrypt(self, cipherText):
104 | cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
105 | return cipher.decrypt(cipherText)
106 |
107 | def __remove_padding(self, plainText):
108 | plainSize = len(plainText)
109 | paddingSize = ord(plainText[-1])
110 | return plainText[:plainSize-paddingSize]
111 |
112 | def decrypt_data(self, cipherText):
113 | plainText = self.__decrypt(cipherText)
114 | return self.__remove_padding(plainText)
115 |
116 |
117 | class BinXMLParser:
118 | def __init__(self, decrypt):
119 | self.decrypt = decrypt
120 |
121 | def __offsetDetect(self):
122 | signature = self.data[0:8][::-1]
123 | self.offset = 0
124 | if signature == "Not DAL!":
125 | self.offset = 8
126 |
127 | def __read_bytes(self, size):
128 | result = self.data[self.offset:self.offset+size]
129 | self.offset += size
130 | return result
131 |
132 | def __read_int(self):
133 | val, = struct.unpack_from(' stringsCount
144 | self.strings = []
145 | for i in xrange(stringsCount):
146 | strlen = self.__read_int()
147 | str = self.__read_bytes(strlen)
148 | self.strings.append(str)
149 |
150 | def __get_item(self, level=0):
151 | tagName = self.strings[self.__read_int()]
152 | attr = self.__read_byte()
153 | self.xml += " "*level
154 | self.xml += "<" + tagName
155 | val = ""
156 | if attr & 1:
157 | self.__read_int()
158 | if attr & 2:
159 | val = self.strings[self.__read_int()]
160 | val = val.lstrip().rstrip()
161 | if attr & 4:
162 | attrs_count = self.__read_int()
163 | attrs_dict = {}
164 | for i in xrange(attrs_count):
165 | attrName = self.strings[self.__read_int()]
166 | attrVal = self.strings[self.__read_int()]
167 | if self.decrypt and attrName == "Path":
168 | attrVal= decrypt_path(attrVal)
169 | self.xml += " " + attrName + '="' + attrVal + '"'
170 | if attr & 8:
171 | self.xml += ">\n";
172 | childCount = self.__read_int()
173 | for i in xrange(childCount):
174 | self.__get_item(level+1)
175 |
176 | if val != "":
177 | self.xml += ">\n" + " "*(level+1) + val +"\n"
178 | self.xml += " "*level + "" + tagName + ">\n"
179 | else:
180 | if attr & 8:
181 | self.xml += " "*level + "" + tagName + ">\n"
182 | else:
183 | self.xml += "/>\n"
184 |
185 | def __xmlBuild(self):
186 | self.xml = ""
187 | self.__get_item()
188 | return self.xml
189 |
190 | def parse(self, binData):
191 | self.offset = 0
192 | self.data = binData
193 | self.__read_strings()
194 | return self.__xmlBuild()
195 |
196 |
197 | class IPCDecryptor:
198 | FORBIDIRNAME = ["Python", "enhancements", "__pycache__"]
199 | def __init__(self, path, key):
200 | self.path = path
201 | if (not os.path.exists(os.path.join(path, "Data", "Index.bin")) or
202 | not os.path.exists(os.path.join(path, "Config", "Index.bin"))):
203 | print ("Error: {} isn't OpenIPC root directory\n".format(path))
204 | exit(-1)
205 | self.dec = Decryptor(key.decode("hex"))
206 |
207 | def __decrypt_file(self, fileName):
208 | f = open(fileName, "rb")
209 | cipherText = f.read()
210 | f.close()
211 | assert len(cipherText) != 0
212 | plainText = self.dec.decrypt_data(cipherText)
213 | os.remove(fileName)
214 | return plainText
215 |
216 | def __decrypt_xml(self, fileName, newFileName, decryptPath):
217 | plainText = self.__decrypt_file(fileName)
218 | binXML = BinXMLParser(decryptPath)
219 | xml = binXML.parse(plainText)
220 | f = open(newFileName, "wb")
221 | f.write(xml)
222 | f.close
223 |
224 | def __decrypt_py(self, fileName, newFileName):
225 | plainText = self.__decrypt_file(fileName)
226 | f = open(newFileName, "wb")
227 | f.write(plainText)
228 | f.close
229 |
230 | def __decrypt_directory(self, path, name):
231 | fullPath = os.path.join(path,name)
232 | for item in os.listdir(fullPath):
233 | if os.path.isdir(os.path.join(fullPath, item)):
234 | if not (item in self.FORBIDIRNAME):
235 | decryptName = decrypt_path(item)
236 | if decryptName=="Python":
237 | if not self.skipPython:
238 | copy_dir(os.path.join(fullPath, item),
239 | os.path.join(fullPath, decryptName))
240 | shutil.rmtree(os.path.join(fullPath, item))
241 | self.__decrypt_directory(fullPath, decryptName)
242 | else:
243 | os.rename(os.path.join(fullPath, item),
244 | os.path.join(fullPath, decryptName))
245 | self.__decrypt_directory(fullPath, decryptName)
246 |
247 | else:
248 | decryptName = decrypt_path(item)
249 | extension = os.path.splitext(decryptName)[1]
250 | if extension == ".xml" or extension == ".xsd":
251 | self.__decrypt_xml(os.path.join(fullPath, item),
252 | os.path.join(fullPath, decryptName),
253 | False)
254 | elif not self.skipPython and extension == ".py":
255 | self.__decrypt_py(os.path.join(fullPath, item),
256 | os.path.join(fullPath, decryptName))
257 |
258 | def decrypt_files(self, noBackup, python):
259 | self.skipPython = python==False
260 | if not noBackup:
261 | create_backup([os.path.join(self.path, "Config"),
262 | os.path.join(self.path, "Data")])
263 | self.__decrypt_xml(os.path.join(self.path, "Config", "Index.bin"),
264 | os.path.join(self.path, "Config", "Index.xml"),
265 | False)
266 | self.__decrypt_xml(os.path.join(self.path, "Data", "Index.bin"),
267 | os.path.join(self.path, "Data", "Index.xml"),
268 | True)
269 | self.__decrypt_directory(self.path, "Data")
270 |
271 |
272 | def parse_arguments():
273 | pars = argpars(description='Decryptor for OpenIPC configuration')
274 | pars.add_argument('-p', help='path', type=str, default="OpenIPC")
275 | pars.add_argument('-nb', help="don't create backup", action="store_true")
276 | pars.add_argument('-k', help='AES key', type=str, required=True)
277 | pars.add_argument('-python', help='Decrypt Python files', action="store_true")
278 | return ( pars.parse_args().p,
279 | pars.parse_args().k,
280 | pars.parse_args().nb,
281 | pars.parse_args().python )
282 |
283 | def main():
284 | path, key, noBackup, python = parse_arguments()
285 | decryptor = IPCDecryptor(path, key)
286 | decryptor.decrypt_files(noBackup, python)
287 |
288 | if __name__ == "__main__":
289 | main()
290 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # **Disclaimer**
2 |
3 | **All information is provided for educational purposes only. Follow these instructions at your own risk. Neither the authors nor their employer are responsible for any direct or consequential damage or loss arising from any person or organization acting or failing to act on the basis of information contained in this page.**
4 |
5 | # Content
6 | [Introduction](#introduction)
7 | [Required Software](#required-software)
8 | [Generating the Payload](#generating-the-payload)
9 | [Generating the Unlock Token](#generating-the-unlock-token)
10 | [Preparing the SPI Flash Image](#preparing-the-spi-flash-image)
11 | [Integrating Files Into the Firmware Image](#integrating-files-into-the-firmware-image)
12 | [Disabling OEM Signing](#disabling-oem-signing)
13 | [Building the Firmware Image](#building-the-firmware-image)
14 | [BringUP Main CPU](#bringup-main-cpu)
15 | [Writing the Image to SPI Flash](#writing-the-image-to-spi-flash)
16 | [Preparing the USB Debug Cable](#preparing-the-usb-debug-cable)
17 | [Patching OpenIPC Configuration Files](#patching-openipc-configuration-files)
18 | [Decrypting OpenIPC Configuration Files](#decrypting-openipc-configuration-files)
19 | [Adding LMT Core to the Configuration](#adding-lmt-core-to-the-configuration)
20 | [Setting the IPC_PATH Environment Variable](#setting-the-ipc_path-environment-variable)
21 | [Performing an Initial Check of JTAG Operability](#performing-an-initial-check-of-jtag-operability)
22 | [Show CPU ME Thread](#show-cpu-me-thread)
23 | [Halting Cores](#halting-cores)
24 | [ME Debugging: Quick Start](#me-debugging-quick-start)
25 | [Reading Arbitrary Memory](#reading-arbitrary-memory)
26 | [Reading ROM](#reading-rom)
27 | [Why TXE?](#why-txe)
28 | [Tested Platforms List](#tested-platforms-list)
29 | [Authors](#authors)
30 | [License](#license)
31 |
32 |
33 | # Introduction
34 | Vulnerability [INTEL-SA-00086](https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00086.html) allows to activate [JTAG](https://en.wikipedia.org/wiki/JTAG) for [Intel Management Engine](https://en.wikipedia.org/wiki/Intel_Management_Engine) core. We developed our [JTAG PoC][8] for the [Gigabyte Brix GP-BPCE-3350C](https://www.gigabyte.com/ru/Mini-PcBarebone/GB-BPCE-3350C-rev-10) platform. Although we recommend that would-be researchers use the same platform, other manufacturers' platforms with the [Intel Apollo Lake](https://www.intel.com/content/www/us/en/embedded/products/apollo-lake/overview.html) chipset should support the PoC as well (for TXE version **3.0.1.1107**).
35 |
36 |
37 |
38 | # Required Software
39 |
40 | ## Intel System Tools
41 |
42 | Vulnerability *INTEL-SA-00086* involves a buffer overflow when handling a file stored on MFS (the [internal ME file system][6]). The full file path is */home/bup/ct*. You will need to integrate it into the ME firmware by using *Intel Flash Image Tool (FIT)*, one of the Intel System Tools provided by Intel to OEMs of hardware based on Intel PCH chipsets.
43 | Here is the structure of the root directory of the Intel System Tools package:
44 |
45 | 
46 |
47 | The Intel ME (TXE, SPS) System Tools utilities are not intended for end users—so you cannot find them on the official Intel website. However, some OEMs publish them as part of software updates together with device drivers. So, for integrating our PoC you need *Intel TXE System Tools* version 3.x, which can be found online.
48 |
49 | ## Intel System Studio
50 | You need to install Intel System Studio, a trial version of which can be downloaded from Intel [site](https://software.intel.com/en-us/system-studio). In our experiments, we used *Intel System Studio 2018*.
51 |
52 | ## Intel TXE Firmware
53 | The PoC targets **Intel TXE firmware version 3.0.1.1107**. The SPI Flash image for [Gigabyte GB-BPCE-3350C version F5](http://download.gigabyte.com/FileList/BIOS/brix_bios_gb-bpce-3350c_f5.zip) contains the necessary firmware version.
54 |
55 | ## Python
56 | All our scripts are written on Python. We recommend using [Python 2.7](https://www.python.org/download/releases/2.7/)
57 | Also the scripts require [pycrypto](https://pypi.org/project/pycrypto/) packet. To install *pycrypto*, run the following command:
58 | ```
59 | pip install pycrypto
60 | ```
61 |
62 | ## AMIBCP
63 |
64 | **This utility is only necessary if you need to bring up CPU.**
65 |
66 | EFI Human Interface Infrastructure (HII) is a special mechanism for creating a user interface in the UEFI, as well as processing and managing user input. EFI HII identifies default values for all options, including the hidden ones. As soon as the option related to DCI is found, it can be activated for the default configuration, and DCI can be enabled by restoring the BIOS factory settings. For bringing up the main CPU you need *AMI BIOS Configuration Program* version 5.xx, which can be also found online.
67 |
68 |
69 | # Generating the Payload
70 | Run the script **me_exp_bxtp.py**:
71 | ```
72 | me_exp_bxtp.py -f
73 | ```
74 | The script generates the necessary data and exports it to the specified file (indicate either the full file path or, within the current directory, simply a name, *ct.bin* by default). This file will be used later by *FIT*.
75 |
76 | # Generating the Unlock Token
77 | Run the script **me_utok_bxtp.py**:
78 | ```
79 | me_utok_bxtp.py -f
80 | ```
81 | The script generates the necessary data and exports it to the specified file (indicate either the full file path or, within the current directory, simply a name, *utok.bin* by default). This file will be used later by *FIT*.
82 |
83 | # Preparing the SPI Flash Image
84 |
85 | ## Activating DCI option
86 |
87 | **Skip this step if you don't need to bring up the CPU.**
88 |
89 | To activate the *DCI Enable* option, run the AMIBCP utility and use it to open the SPI firmware image provided with your platform. For the Gigabyte Brix GP-BPCE-3350C, open the file downloaded from the Gigabyte link indicated above (path to image file in the archive: F5/image.bin).
90 |
91 | 
92 |
93 | Now we need to enable the *HDCIEN* option in the *Setup Configuration* tab.
94 |
95 |
96 | ## Integrate payload
97 |
98 | To integrate *ct.bin* and *utok.bin* files, run the *FIT* utility (*fit.exe*) and use it to open the SPI firmware image.
99 |
100 | 
101 |
102 | # Other Hardware Platform
103 |
104 | If you are using an other hardware platform and don't have access to *TXE 3.0.1.1107*, you can download an SPI Flash image for [Gigabyte GB-BPCE-3350C version F5](http://download.gigabyte.eu/FileList/BIOS/brix_bios_gb-bpce-3350c_f5.zip) and extract the TXE section through *FIT*. *FIT* extracts different sections of the overall SPI image (SPI descriptor, UEFI/BIOS firmware, Intel ME firmware, and Unlock Token) when the image is opened and saves them in the folder *"image_name"/Decomp *.
105 |
106 | 
107 |
108 | So you can find the file with necessary Intel TXE firmware at /Decomp/TXE Region.bin
109 | Then, in *FIT*, open the SPI image for your particular platform and replace the file containing the Intel TXE firmware with the version obtained from the GB Brix 3350c image ("Intel(R) TXE Binary File" on the Flash Layout tab):
110 |
111 | 
112 |
113 | # Integrating Files Into the Firmware Image
114 |
115 | Now we need to indicate in *FIT* the files we generated for */home/bup/ct* and *Unlock Token*. On the *Debug* tab in *FIT*, you can specify the Trace Hub Binary and Unlock Token to integrate into the firmware. These should be the files that we generated already.
116 |
117 | 
118 |
119 | # Disabling OEM Signing
120 | Simply remove the OEM Public Key Hash field from *FIT*:
121 |
122 | 
123 |
124 | # Building the Firmware Image
125 | Build the image by selecting *Build Image* in the *Build menu*.
126 |
127 | 
128 |
129 | Ignore the message about BootGuard settings (click "Yes"):
130 |
131 | 
132 |
133 | If everything has been done correctly up to this point, the build process should be successful and *FIT* outputs something like the following console message:
134 |
135 | 
136 |
137 | # BringUP Main CPU
138 |
139 | **Skip this step if you don't need to bring up the CPU.**
140 |
141 | You have to activate HAP mode for bringing up the CPU. 0-bit of the byte at the offset +0x102 should be set:
142 |
143 | 
144 |
145 |
146 | # Writing the Image to SPI Flash[](#writeimage)
147 |
148 | **To write the image to SPI flash, we highly recommend using an SPI programmer.
149 | Be sure to back up the original firmware so you can restore from it if something goes wrong!**
150 |
151 | # Preparing the USB Debug Cable
152 |
153 | You will need a *USB 3.0 debug cable* to connect to the platform. Either [buy](https://www.datapro.net/products/usb-3-0-super-speed-a-a-debugging-cable.html) one specially made for the purpose or hack together your own from a USB 3.0 AM–AM cable by isolating the *D+*, *D-*, and *Vcc* contacts.
154 |
155 | 
156 |
157 | # Patching OpenIPC Configuration Files
158 |
159 | Intel develops and provides users with two software packages that can be used for JTAG debugging of platforms and the main CPU: DAL (DFx Abstraction Layer) and *OpenIPC*. Both *DAL* and *OpenIPC* are part of *Intel System Studio*. After installation of *Intel System Studio 2018*, *OpenIPC* appears in the following directory:
160 |
161 | Windows
162 | ```
163 | C:\Intel\OpenIPC_1.1740.2381.100
164 | ```
165 |
166 | Linux
167 | ```
168 | /opt/intel/system_studio_2018/system_debugger_2018/debugger/openipc
169 | ```
170 |
171 | The *OpenIPC* configuration is encrypted and does not support the TXE core. So decrypt the configuration and add a TXE description to it.
172 |
173 | ## Decrypting OpenIPC Configuration Files
174 |
175 | To decrypt the configuration files, extract the key from the *StructuredData* library (linux: *libStructuredData_x64.so*, Windows: *StructuredData_x64.dll*) in *OpenIPC/Bin* using the [IDA Pro](https://www.hex-rays.com/products/ida/support/download_freeware.shtml) script *openipc_key_extract.py*. Pass the key (in our case, *4504fb02be0a9c4c84df2a89cf508bc3*) to the script *config_decryptor.py* with path to the OpenIPC directory.
176 |
177 | ```
178 | config_decryptor.py –k 4504fb02be0a9c4c84df2a89cf508bc3 –p C:\Intel\OpenIPC
179 | ```
180 |
181 | ## Adding LMT Core to the Configuration
182 |
183 | The supplied version of OpenIPC does not have the necessary information about the TXE core. So we need to apply a patch (*patch.diff*) to the decrypted *OpenIPC* configuration files. Here's how to do it:
184 |
185 | ```
186 | patch -p2 < patch.diff
187 | ```
188 |
189 | # Setting the IPC_PATH Environment Variable
190 |
191 | After decryption and patching, set the *IPC_PATH* environment variable to the new *OpenIPC* directory so that *ipccli* uses the modified *OpenIPC* version. For instance:
192 |
193 | Windows
194 | ```
195 | set IPC_PATH=c:\Intel\OpenIPC\Bin
196 | ```
197 |
198 | # Performing an Initial Check of JTAG Operability
199 |
200 | The *activator* blocks subsequent loading by keeping the BUP process in a loop after JTAG is activated. After launch, the platform will not show any signs of life (the monitor does not turn on, keyboard indicators do not light up, and no BIOS POST sound is played). So you will need to check via DCI debugging that the platform has gotten "stuck" in the BUP module.
201 |
202 | Like *DAL*, the *OpenIPC* library includes a command-line interface (CLI), written in Python and provided as a library for Python as part of Intel System Studio, which can be installed on the system with the help of pip.
203 | The installation package for ipccli is at the following path:
204 | Windows
205 | ```
206 | \IntelSWTools\system_debugger_2018\debugger\ipccli\ ipccli-1.1740.544.100-py2.py3-none-any.whl
207 | ```
208 |
209 | Linux
210 | ```
211 | /opt/intel/system_studio_2018/system_debugger_2018/debugger/ipccli/ipccli-1.1811.727.100-py2.py3-none-any.whl
212 | ```
213 |
214 | To install ipccli, run the following console command:
215 |
216 | ```
217 | pip install ipccli-1.1740.544.100-py2.py3-none-any.whl
218 | ```
219 |
220 | Once installed, *ipccli* is available within the runtime of the corresponding Python version (the one from which pip was invoked).
221 | To get started with *OpenIPC*, run the following commands in the Python console:
222 | ```
223 | import ipccli
224 | ipc = ipccli.baseaccess()
225 | ```
226 |
227 | The mechanism for connecting to the target platform via DCI launches, resulting in the following console output:
228 |
229 | 
230 |
231 | When no connection is established—for example, if the platform is not powered on or is not physically connected via DCI—messages will resemble the following:
232 |
233 | 
234 |
235 | If *DCI* connection is successful, make sure that the *PERSONALITY* register of the *DFX_AGGRAGATOR* device equals 3.
236 | The *PERSONALITY* register has an *IR* (*Instruction Register*) code of *0x54*. To read it, run the following commands:
237 | ```
238 | dfx_agg = ipc.devs.mdu_dfx_agg_tap0
239 | ipc.irdrscan(dfx_agg, 0x54, 32)
240 | ```
241 |
242 | Here is what the result of that command should look like:
243 |
244 | 
245 |
246 |
247 |
248 |
249 |
250 |
251 | # ME Debugging: Quick Start
252 |
253 | The *ipccli* utility comes with rather detailed HTML documentation, which can be found in a folder of the *ipccli* Python package:
254 |
255 | ```
256 | \Lib\site-packages\ipccli\html\Index.html
257 | ```
258 |
259 | ## Show CPU ME Thread
260 |
261 | If the previous steps have been performed correctly, when a connection to the platform is made via *ipccli*, the *TXE* core is accessible via *CSE Tap* and *ipccli* allows accessing it by applying the following *ipccli* path:
262 |
263 | ```
264 | ipc.devs.cse_c0.threads[0]
265 | ```
266 |
267 | But since the PoC blocks loading of the platform until the main CPU is initialized, its cores are inaccessible via JTAG and the ME core can be accessed via the following command:
268 |
269 | ```
270 | ipc.threads[0]
271 | ```
272 |
273 | ## Halting Cores
274 |
275 | To halt ME processor instructions, run the following command:
276 |
277 | ```
278 | me = ipc.devs.cse_c0.threads[0]
279 | me.halt()
280 | ```
281 |
282 | To halt CPU processor instructions, run the following command:
283 |
284 | ```
285 | core = ipc.threads[0]
286 | core.halt()
287 | ```
288 |
289 |
290 | 
291 |
292 | The console displays the logical address of the instruction at which the halt was made.
293 |
294 | ## Reading Arbitrary Memory
295 |
296 | *OpenIPC* allows reading memory after the halt, for example:
297 |
298 | ```
299 | ipc.threads[0].mem("0xf0080004P", 4)
300 | ```
301 |
302 | You can specify a logical address (*sel:offset*), linear address (*L* modifier), or physical address (*P* modifier).
303 |
304 | ## Reading ROM
305 |
306 | The ME system agent (*MISA*) allows getting the initial physical address of the *ROM* region, which includes the ME reset vector. You can get the *ROM* address via the *Hunit ROM Memory Base* (*HROMMB*) register at offset 0xe20 MISA MMIO (*0xf0000000P*):
307 |
308 | 
309 |
310 | *ROM* always resides from *ROMBASE* to *0xffffffff*
311 | To copy the ROM to a file, run the following command:
312 |
313 | ```
314 | ipc.threads[0].memsave("", "0xfffe0000p", 0x20001)
315 | ```
316 |
317 | It is important to specify the size as *0x20001*, as opposed to *0x20000* (otherwise *OpenIPC* runs into issues due to problems with 64-bit access, which is not possible for the 32-bit ME core). The last byte of the file can be thrown out, since it is not part of the *ROM*.
318 |
319 |
320 | # Why TXE?
321 |
322 | The platform gives more opportunities for debugging without a special [Intel CCA-SVT](https://designintools.intel.com/Silicon_View_Technology_Closed_Chassis_Adapter_p/itpxdpsvt.htm) adapter and allows debugging the earliest stages of the TXE core via an ordinary *USB debug cable*.
323 |
324 |
325 | ## Related URLs:
326 |
327 | [Intel ME: The Way of the Static Analysis][4]
328 |
329 | [Intel DCI Secrets][5]
330 |
331 | [Intel ME: Flash File System Explained][6]
332 |
333 | [How to Hack a Turned-Off Computer or Running Unsigned Code in Intel Management Engine][7]
334 |
335 | [Inside Intel Management Engine][8]
336 |
337 | [Disabling Intel ME 11 via undocumented mode][9]
338 |
339 | ## Tested Platforms List
340 |
341 | * Gigabyte Mini-PC Barebone (BRIX) GB-BPCE-3350C (rev:1.1, 1.2)
342 | * Beelink M1
343 |
344 |
345 | # Authors
346 | Mark Ermolov ([@\_markel___][1])
347 |
348 | Maxim Goryachy ([@h0t_max][2])
349 |
350 |
351 | # Research Team
352 |
353 | Mark Ermolov ([@\_markel___][1])
354 |
355 | Maxim Goryachy ([@h0t_max][2])
356 |
357 | Dmitry Sklyarov ([@_Dmit][3])
358 |
359 |
360 | # License
361 | Copyright (c) 2018 Mark Ermolov, Maxim Goryachy at Positive Technologies
362 |
363 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
364 |
365 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
366 |
367 |
368 |
369 | [1]: https://twitter.com/_markel___
370 | [2]: https://twitter.com/h0t_max
371 | [3]: https://twitter.com/_Dmit
372 | [4]: https://www.troopers.de/troopers17/talks/772-intel-me-the-way-of-the-static-analysis/
373 | [5]: http://conference.hitb.org/hitbsecconf2017ams/sessions/commsec-intel-dci-secrets/
374 | [6]: https://www.blackhat.com/docs/eu-17/materials/eu-17-Sklyarov-Intel-ME-Flash-File-System-Explained-wp.pdf
375 | [7]: https://www.blackhat.com/docs/eu-17/materials/eu-17-Goryachy-How-To-Hack-A-Turned-Off-Computer-Or-Running-Unsigned-Code-In-Intel-Management-Engine-wp.pdf
376 | [8]: https://github.com/ptresearch/IntelME-JTAG
377 | [9]: http://blog.ptsecurity.com/2017/08/disabling-intel-me.html
378 |
--------------------------------------------------------------------------------