<div class="xblock xblock-public_view xblock-public_view-vertical" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-init="VerticalStudentView" data-runtime-class="LmsRuntime" data-runtime-version="1" data-block-type="vertical" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@vertical+block@c7ab765bb77e45b280bc51ab3b360698" data-request-token="86e0cdd403d411efabb30242ac12000b" data-graded="True" data-has-score="False">
<div class="vert-mod">
<div class="vert vert-0" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@video+block@ed7bf66e61d04b89a8fb2fcef99472b2">
<div class="xblock xblock-public_view xblock-public_view-video xmodule_display xmodule_VideoBlock" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-init="XBlockToXModuleShim" data-runtime-class="LmsRuntime" data-runtime-version="1" data-block-type="video" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@video+block@ed7bf66e61d04b89a8fb2fcef99472b2" data-request-token="86e0cdd403d411efabb30242ac12000b" data-graded="True" data-has-score="False">
<script type="json/xblock-args" class="xblock-json-init-args">
{"xmodule-type": "Video"}
</script>
<h3 class="hd hd-2">Video</h3>
<div
id="video_ed7bf66e61d04b89a8fb2fcef99472b2"
class="video closed"
data-metadata='{"autoAdvance": false, "autohideHtml5": false, "autoplay": false, "captionDataDir": null, "completionEnabled": false, "completionPercentage": 0.95, "duration": 0.0, "end": 0.0, "generalSpeed": 1.0, "lmsRootURL": "https://p.ost2.fyi", "poster": null, "prioritizeHls": false, "publishCompletionUrl": "/courses/course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1/xblock/block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@video+block@ed7bf66e61d04b89a8fb2fcef99472b2/handler/publish_completion", "recordedYoutubeIsAvailable": true, "savedVideoPosition": 0.0, "saveStateEnabled": false, "saveStateUrl": "/courses/course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1/xblock/block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@video+block@ed7bf66e61d04b89a8fb2fcef99472b2/handler/xmodule_handler/save_user_state", "showCaptions": "false", "sources": [], "speed": null, "start": 0.0, "streams": "1.00:rb0LYSxGVmg", "transcriptAvailableTranslationsUrl": "/courses/course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1/xblock/block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@video+block@ed7bf66e61d04b89a8fb2fcef99472b2/handler/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English"}, "transcriptTranslationUrl": "/courses/course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1/xblock/block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@video+block@ed7bf66e61d04b89a8fb2fcef99472b2/handler/transcript/translation/__lang__", "ytApiUrl": "https://www.youtube.com/iframe_api", "ytMetadataEndpoint": "", "ytTestTimeout": 1500}'
data-bumper-metadata='null'
data-autoadvance-enabled="False"
data-poster='null'
tabindex="-1"
>
<div class="focus_grabber first"></div>
<div class="tc-wrapper">
<div class="video-wrapper">
<span tabindex="0" class="spinner" aria-hidden="false" aria-label="Loading video player"></span>
<span tabindex="-1" class="btn-play fa fa-youtube-play fa-2x is-hidden" aria-hidden="true" aria-label="Play video"></span>
<div class="video-player-pre"></div>
<div class="video-player">
<div id="ed7bf66e61d04b89a8fb2fcef99472b2"></div>
<h4 class="hd hd-4 video-error is-hidden">No playable video sources found.</h4>
<h4 class="hd hd-4 video-hls-error is-hidden">
Your browser does not support this video format. Try using a different browser.
</h4>
</div>
<div class="video-player-post"></div>
<div class="closed-captions"></div>
<div class="video-controls is-hidden">
<div>
<div class="vcr"><div class="vidtime">0:00 / 0:00</div></div>
<div class="secondary-controls"></div>
</div>
</div>
</div>
</div>
<div class="focus_grabber last"></div>
</div>
</div>
</div>
<div class="vert vert-1" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@done+block@b511a2fba7014ee0ac89de860d925efb">
<div class="xblock xblock-public_view xblock-public_view-done" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="done" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@done+block@b511a2fba7014ee0ac89de860d925efb" data-request-token="86e0cdd403d411efabb30242ac12000b" data-graded="True" data-has-score="True">
<div class="page-banner"><div class="alert alert-warning"><span class="icon icon-alert fa fa fa-warning" aria-hidden="true"></span><div class="message-content">Completion is only accessible to enrolled learners. Sign in or register, and enroll in this course to view it.</div></div></div>
</div>
</div>
<div class="vert vert-2" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@discussion+block@039a8a4ea840404aa5edf8aa50881208">
<div class="xblock xblock-public_view xblock-public_view-discussion" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="discussion" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@discussion+block@039a8a4ea840404aa5edf8aa50881208" data-request-token="86e0cdd403d411efabb30242ac12000b" data-graded="True" data-has-score="False">
<div class="page-banner"><div class="alert alert-warning"><span class="icon icon-alert fa fa fa-warning" aria-hidden="true"></span><div class="message-content">Discussion is only accessible to enrolled learners. Sign in or register, and enroll in this course to view it.</div></div></div>
</div>
</div>
</div>
<script type="text/javascript">
(function (require) {
require(['/static/js/dateutil_factory.be68acdff619.js?raw'], function () {
require(['js/dateutil_factory'], function (DateUtilFactory) {
DateUtilFactory.transform('.localized-datetime');
});
});
}).call(this, require || RequireJS.require);
</script>
<script>
function emit_event(message) {
parent.postMessage(message, '*');
}
</script>
</div>
<div class="xblock xblock-public_view xblock-public_view-vertical" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-init="VerticalStudentView" data-runtime-class="LmsRuntime" data-runtime-version="1" data-block-type="vertical" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@vertical+block@c4adaf3528174d97905104fc3cf70e14" data-request-token="86e0cdd403d411efabb30242ac12000b" data-graded="True" data-has-score="False">
<div class="vert-mod">
<div class="vert vert-0" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@markdown+block@106140599be44ec4b21e87217c638227">
<div class="xblock xblock-public_view xblock-public_view-markdown" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="markdown" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@markdown+block@106140599be44ec4b21e87217c638227" data-request-token="86e0cdd403d411efabb30242ac12000b" data-graded="True" data-has-score="False">
<div class="markdown_xblock"><h2>Alpine configuration</h2>
<p>Since we are using Alpine Linux Live ISO, we need some adjustments to allow us to install packages.</p>
<p>Let's start with the networking setup:</p>
<pre><code>ip link set eth0 up
</code></pre>
<p>Now we can obtain the IP address:</p>
<pre><code>udhcpc
</code></pre>
<p>If things go well, you should see the following:</p>
<pre><code>udhcpc: started, v1.35.0
udhcpc: broadcasting discover
udhcpc: broadcasting select for 10.0.2.15, server 10.0.2.2
udhcpc: lease of 10.0.2.15 obtained from 10.0.2.2, lease time 86400
</code></pre>
<p>Let's modify DNS:</p>
<pre><code>echo "nameserver 8.8.8.8" > /etc/resolv.conf
</code></pre>
<p>And let Alpine know which repo to use:</p>
<pre><code>echo "http://dl-cdn.alpinelinux.org/alpine/v3.16/main" >> /etc/apk/repositories
</code></pre>
<p>Let's update and install the necessary package for BootOrder manipulation:</p>
<pre><code>apk update
</code></pre>
<pre><code>apk add efibootmgr binutils
</code></pre>
<p>When you are familiar with the above sequence, you can just paste the following snippet, and Alpine shell will consume every command as needed, so no redundant copy-pasting will be required:</p>
<pre><code>ip link set eth0 up
udhcpc
echo "nameserver 8.8.8.8" > /etc/resolv.conf
echo "http://dl-cdn.alpinelinux.org/alpine/v3.16/main" >> /etc/apk/repositories
apk update
apk add efibootmgr
</code></pre>
<p>Please copy and paste that command to your notepad since you must use it every time Alpine Linux is booted, which may often happen when trying to solve the following exercises.</p>
<h2>Variable parsing comparison</h2>
<p>Let's compare what we see in <code>/sys/firmware/efi/efivars/</code> vs how boot options are parsed by <code>efibootmgr</code>:</p>
<pre><code>xxd -g 1 /sys/firmware/efi/efivars/Boot0000-8be4df61-93ca-11d2-aa0d-00e098032b8c
</code></pre>
<p>We can also leverage famous <code>strings</code>:</p>
<pre><code>strings -e b /sys/firmware/efi/efivars/Boot0000-8be4df61-93ca-11d2-aa0d-00e098032b8c
</code></pre>
<p>Please repeat the command above with <code>Boot0001</code>, <code>Boot0002</code>, <code>Boot0003</code>, and <code>Boot0004</code>, trying to figure out what the given boot option variable intends to boot. Note your results.</p>
<p>Now please run:</p>
<pre><code>efibootmgr
</code></pre>
<p>And confirm if your analysis was correct.</p>
</div>
</div>
</div>
<div class="vert vert-1" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@done+block@2b3e810af99c4d1cbde98b38350cd4b4">
<div class="xblock xblock-public_view xblock-public_view-done" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="done" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@done+block@2b3e810af99c4d1cbde98b38350cd4b4" data-request-token="86e0cdd403d411efabb30242ac12000b" data-graded="True" data-has-score="True">
<div class="page-banner"><div class="alert alert-warning"><span class="icon icon-alert fa fa fa-warning" aria-hidden="true"></span><div class="message-content">Completion is only accessible to enrolled learners. Sign in or register, and enroll in this course to view it.</div></div></div>
</div>
</div>
<div class="vert vert-2" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@discussion+block@1d36fb0772aa4b7b9aa4701088d6de82">
<div class="xblock xblock-public_view xblock-public_view-discussion" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="discussion" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@discussion+block@1d36fb0772aa4b7b9aa4701088d6de82" data-request-token="86e0cdd403d411efabb30242ac12000b" data-graded="True" data-has-score="False">
<div class="page-banner"><div class="alert alert-warning"><span class="icon icon-alert fa fa fa-warning" aria-hidden="true"></span><div class="message-content">Discussion is only accessible to enrolled learners. Sign in or register, and enroll in this course to view it.</div></div></div>
</div>
</div>
</div>
<script type="text/javascript">
(function (require) {
require(['/static/js/dateutil_factory.be68acdff619.js?raw'], function () {
require(['js/dateutil_factory'], function (DateUtilFactory) {
DateUtilFactory.transform('.localized-datetime');
});
});
}).call(this, require || RequireJS.require);
</script>
<script>
function emit_event(message) {
parent.postMessage(message, '*');
}
</script>
</div>
<div class="xblock xblock-public_view xblock-public_view-vertical" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-init="VerticalStudentView" data-runtime-class="LmsRuntime" data-runtime-version="1" data-block-type="vertical" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@vertical+block@bb0f787a77404033bc8c6dec7c9a8cdb" data-request-token="86e0cdd403d411efabb30242ac12000b" data-graded="True" data-has-score="False">
<div class="vert-mod">
<div class="vert vert-0" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@markdown+block@e8399b7c544c4a8ca99d0dfd2d99294c">
<div class="xblock xblock-public_view xblock-public_view-markdown" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="markdown" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@markdown+block@e8399b7c544c4a8ca99d0dfd2d99294c" data-request-token="86e0cdd403d411efabb30242ac12000b" data-graded="True" data-has-score="False">
<div class="markdown_xblock"><p>To boot Alpine Linux directly without UEFI Shell interaction we have to acomplish two tasks:</p>
<ul>
<li>add Alpine Linux bootx64.efi file as boot option (by <code>efibootmgr</code> called bootnum)</li>
<li>set BootOrder variable to new boot option pointing to Alpine Linux bootloader</li>
</ul>
<p>In typical Linux environment if you master <code>efibootmgr</code> those two tasks can be performed with one command. Unfortunately our situation is more complicated because we would like to point at a medium that is not visible under Alpine Linux in a way that <code>efibootmgr</code> can recognize it. We want to use a file which resides on an ISO image mounted in our CDROM. This will be a challenge, but also a learning opportunity.</p>
<h1>Create boot option variable</h1>
<p>Since our variable is quite complicated we have to divide and conquer.</p>
<h2>Let's start with attributes:</h2>
<p>Every boot order variable, per spec, have to be non-volatile, boot-time accessible and run-time accessible.
Please fill <code>XX</code> with correct hexadecimal value.</p>
<div class="codehilite">
<pre><span></span><code><span class="nb">echo</span> -en <span class="s2">"\xXX\x00\x00\x00"</span> > var.attr
</code></pre>
</div>
<h2>Load option have to be active:</h2>
<p>Boot order variables are constructed by following the below <code>EFI_LOAD_OPTION</code> structure:</p>
<div class="codehilite">
<pre><span></span><code><span class="k">typedef</span> <span class="k">struct</span> <span class="nc">_EFI_LOAD_OPTION</span> <span class="p">{</span>
<span class="n">UINT32</span> <span class="n">Attributes</span><span class="p">;</span>
<span class="n">UINT16</span> <span class="n">FilePathListLength</span><span class="p">;</span>
<span class="c1">// CHAR16 Description[];</span>
<span class="c1">// EFI_DEVICE_PATH_PROTOCOL FilePathList[];</span>
<span class="c1">// UINT8 OptionalData[];</span>
<span class="p">}</span> <span class="n">EFI_LOAD_OPTION</span><span class="p">;</span>
</code></pre>
</div>
<p><code>OptionalData</code> in our case is not needed and we can ignore it.</p>
<p>Please fill <code>XX</code> with correct hexadecimal value to activate our option.</p>
<div class="codehilite">
<pre><span></span><code><span class="nb">echo</span> -en <span class="s2">"\xXX\x00\x00\x00"</span> > var.lo
</code></pre>
</div>
<h2>Description (aka label)</h2>
<p>Let's use some bash magic to convert string to hex:</p>
<div class="codehilite">
<pre><span></span><code><span class="nb">echo</span> -n <span class="s2">"Alpine Linux"</span><span class="p">|</span>xxd -p<span class="p">|</span>sed <span class="s1">'s/../\\x&\\x00/g'</span>
</code></pre>
</div>
<ul>
<li><code>echo -n "Alpine Linux"|</code> - print label and pipe the string to next command without new line</li>
<li><code>xxd -p</code> - output continuous hexdump</li>
<li><code>sed 's/../\\x&\\x00/g'</code> - replace every two characters (..) with prefix <code>\x</code> and postfix <code>\x00</code></li>
</ul>
<p>We have to null terminate that string by adding <code>\x00\x00</code> at the end. Final value can be passed to <code>var.desc</code> file.
We put our string into <code>var.desc</code> as follows:</p>
<div class="codehilite">
<pre><span></span><code><span class="nb">echo</span> -en <span class="k">$(</span><span class="nb">echo</span> -n <span class="s2">"Alpine Linux"</span><span class="p">|</span>xxd -p<span class="p">|</span>sed <span class="s1">'s/../\\x&\\x00/g'</span><span class="k">)</span> > var.desc
</code></pre>
</div>
<p>To add null-termination:</p>
<div class="codehilite">
<pre><span></span><code><span class="nb">echo</span> -en <span class="s2">"\x00\x00"</span> >> var.desc
</code></pre>
</div>
<h2>Device Path</h2>
<p>This is the most complicated part, and figuring that out without tools requires a deep understanding of our hardware model.</p>
<p>To point to our file we have to express QEMU hardware structure using language understood by UEFI. In human language that can be translated to a UEFI Device Path, it would be something like the following: The file bootx64.efi is in the \efi\boot directory on the first legacy Master Boot Record partition. That partition is on the first boot entry in the boot catalog of the CD-ROM, which is directly connected to port 0 of the host bus adapter (HBA) of the SATA controller. That SATA controller exists as a PCI function on 00:1f.2 (bus 0, device 0x1f, function 0x2) connected to the QEMU PCI Root Bridge.</p>
<p>Let's recall <code>EFI_DEVICE_PATH_PROTOCOL</code> structure:</p>
<div class="codehilite">
<pre><span></span><code><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
<span class="n">UINT8</span> <span class="n">Type</span><span class="p">;</span>
<span class="n">UINT8</span> <span class="n">SubType</span><span class="p">;</span>
<span class="n">UINT8</span> <span class="n">Length</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span>
<span class="p">}</span> <span class="n">EFI_DEVICE_PATH_PROTOCOL</span><span class="p">;</span>
</code></pre>
</div>
<h3>Device Path node 1</h3>
<p>The root of all device paths in QEMU is the PCI Root Bridge, which cannot be enumerated, so the only way to identify it is defined by the ACPI spec.</p>
<ul>
<li>ACPI Device Path is Type <code>0x02</code> and to identify our PCI Root Bridge we have to use SubType <code>0x01</code> ACPI Device Path. </li>
<li>Length is always 12 bytes (<code>0x0c</code>) as defined in the spec.</li>
</ul>
<p>So first part will look as follows:</p>
<pre><code>\x02\x01\x0c\x00
</code></pre>
<p>Following structure is SubType specific:</p>
<div class="codehilite">
<pre><span></span><code><span class="k">typedef</span> <span class="k">struct</span> <span class="p">{</span>
<span class="n">EFI_DEVICE_PATH_PROTOCOL</span> <span class="n">Header</span><span class="p">;</span>
<span class="c1">///</span>
<span class="c1">/// Device's PnP hardware ID stored in a numeric 32-bit</span>
<span class="c1">/// compressed EISA-type ID. This value must match the</span>
<span class="c1">/// corresponding _HID in the ACPI name space.</span>
<span class="c1">///</span>
<span class="n">UINT32</span> <span class="n">HID</span><span class="p">;</span>
<span class="c1">///</span>
<span class="c1">/// Unique ID that is required by ACPI if two devices have the</span>
<span class="c1">/// same _HID. This value must also match the corresponding</span>
<span class="c1">/// _UID/_HID pair in the ACPI name space. Only the 32-bit</span>
<span class="c1">/// numeric value type of _UID is supported. Thus, strings must</span>
<span class="c1">/// not be used for the _UID in the ACPI name space.</span>
<span class="c1">///</span>
<span class="n">UINT32</span> <span class="n">UID</span><span class="p">;</span>
<span class="p">}</span> <span class="n">ACPI_HID_DEVICE_PATH</span><span class="p">;</span>
</code></pre>
</div>
<ul>
<li>QEMU PCI Root Bridge is identified as <code>\xd0\x41\x03\x0a</code> and UID is all zeros</li>
</ul>
<p>Which gives us:</p>
<div class="codehilite">
<pre><span></span><code><span class="nb">echo</span> -en <span class="s2">"\x02\x01\x0c\x00\xd0\x41\x03\x0a\x00\x00\x00\x00"</span> > var.path_node1
</code></pre>
</div>
<h3>Device Path node 2</h3>
<p>Let's define our SATA controller function. We have to create structure data in following order:</p>
<ul>
<li>Type <code>0x01</code>- Hardware Device Path.</li>
<li>SubType <code>0x01</code>- PCI.</li>
<li>Length is always 6 bytes.</li>
<li>Two bytes expressing PCI function provided above.</li>
<li>Two bytes expressing PCI device provided above.</li>
</ul>
<p>Please fill <code>XX</code> with correct hexadecimal value.</p>
<div class="codehilite">
<pre><span></span><code><span class="nb">echo</span> -en <span class="s2">"\x01\x01\xXX\x00\xXX\xXX"</span> > var.path_node2
</code></pre>
</div>
<p>Note that reverse order of function and device is intended.</p>
<h3>Device Path node 3</h3>
<p>Our SATA controller has CDROM connected to HBA port 0. Let's express that in Device Path structure:</p>
<ul>
<li>Type <code>0x03</code> - Messaging Device Path</li>
<li>SubType <code>0x12</code> - SATA</li>
<li>Length is always 10 bytes.</li>
<li>Two bytes expressing port number.</li>
<li>Two bytes <code>0xffff</code> informing about direct connection.</li>
<li>Two bytes expressing Logical Unit Number, which is <code>0x0</code>.</li>
</ul>
<p>Please fill <code>XX</code> with correct hexadecimal value.</p>
<div class="codehilite">
<pre><span></span><code><span class="nb">echo</span> -en <span class="s2">"\x03\x12\xXX\x00\xXX\x00\xff\xff\x00\x00"</span> > var.path_node3
</code></pre>
</div>
<h3>Device Path node 4</h3>
<p>Now we have to explain to the system that we are dealing with the first boot entry from the boot catalog of our CD-ROM. The CD-ROM Media Device Path is used to define a system partition that exists on a CD-ROM. The CD-ROM is assumed to contain an ISO-9660 file system and follow the CD-ROM “El Torito” format. The Boot Entry number from the Boot Catalog is how the “El Torito” specification defines the existence of bootable entities on a CD-ROM. In EFI the bootable entity is an EFI System Partition that is pointed to by the Boot Entry.</p>
<ul>
<li>Type <code>0x04</code> - Media Device Path.</li>
<li>SubType <code>0x02</code> - CD-ROM “El Torito” Format.</li>
<li>Length is always 24 bytes.</li>
<li>Four bytes Boot Entry number from the Boot Catalog. We can use tools like <code>xorriso</code> to find number of entries in catalog in CD-ROM El-Torito format.</li>
<li>Eight byte starting Relative logical Block Address (RBA) of the partition on the medium, since CD-ROMs use RBAs.</li>
<li>Eight bytes size of the partition in units of Blocks, also called Sectors.</li>
</ul>
<p>Starting RBA and size can be figure out from <code>fdisk</code> output:</p>
<div class="codehilite">
<pre><span></span><code>user@ubuntu:~/edk2$ fdisk -l ~/alpine-virt-3.16.1-x86_64.iso
Disk /home/user/alpine-virt-3.16.1-x86_64.iso: <span class="m">47</span> MiB, <span class="m">49283072</span> bytes, <span class="m">96256</span> sectors
Units: sectors of <span class="m">1</span> * <span class="nv">512</span> <span class="o">=</span> <span class="m">512</span> bytes
Sector size <span class="o">(</span>logical/physical<span class="o">)</span>: <span class="m">512</span> bytes / <span class="m">512</span> bytes
I/O size <span class="o">(</span>minimum/optimal<span class="o">)</span>: <span class="m">512</span> bytes / <span class="m">512</span> bytes
Disklabel type: dos
Disk identifier: 0x090c5084
Device Boot Start End Sectors Size Id Type
/home/user/alpine-virt-3.16.1-x86_64.iso1 * <span class="m">0</span> <span class="m">96255</span> <span class="m">96256</span> 47M <span class="m">0</span> Empty
/home/user/alpine-virt-3.16.1-x86_64.iso2 <span class="m">216</span> <span class="m">3095</span> <span class="m">2880</span> <span class="m">1</span>.4M ef EFI <span class="o">(</span>FAT-12/16/32<span class="o">)</span>
</code></pre>
</div>
<p>Boot start of our EFI partition is 216 (0xd8). </p>
<p>Partition size which is expected by structure is little bit harder to calculate. You can find details in EDKII <a href="https://github.com/tianocore/edk2/blob/edk2-stable202202/MdeModulePkg/Universal/Disk/PartitionDxe/ElTorito.c#L238">source code</a>. So to simplify things partion size is already filled in following command.</p>
<p>Please fill <code>XX</code> with correct hexadecimal value.</p>
<div class="codehilite">
<pre><span></span><code><span class="nb">echo</span> -en <span class="s2">"\x04\x02\xXX\x00\x01\x00\x00\x00\xXX\x00\x00\x00\x00\x00\x00\x00\x00\x2d\x00\x00\x00\x00\x00\x00"</span> > var.path_node4
</code></pre>
</div>
<h3>Device Path node 5</h3>
<p>The next is probably the most complicated. We have to define the Hard Drive Media Device Path, which is used to represent a partition on a hard drive, or CD-ROM in this case.</p>
<p>Each partition has at least Hard Drive Device Path node, each describing an entry in a partition table. EFI supports Master Boot Record (MBR) and GUID Partition Table (GPT) partitioning formats. Partitions are numbered according to their entry in their respective partition table, starting with 1. Partitions are addressed in EFI starting at Logical Block Address (LBA) zero. A partition number of zero can be used to represent the raw hard drive or a raw extended partition</p>
<p>The partition format is stored in the Device Path to allow new partition formats to be supported in the future. The Hard Drive Device Path also contains a Disk Signature and a Disk Signature Type. The disk signature is maintained by the OS and only used by EFI to partition Device Path nodes. The disk signature enables the OS to find disks even after they have been physically moved in a system.</p>
<p>Load Option Processing defines special rules for processing the Hard Drive Media Device Path. These special rules enable a disk’s location to change and still have the system boot from the disk.</p>
<ul>
<li>Type <code>0x04</code> - Media Device Path</li>
<li>SubType <code>0x01</code> - Hard Drive</li>
<li>Length is always 42 bytes.</li>
<li>Next four bytes describes the entry in a partition table, starting with entry 1. Our bootloader reside on partition 1.</li>
<li>Next eight bytes mean starting LBA (logical block address) of the partition on the hard drive. In our case it is 0.</li>
<li>Next eight bytes mean size of the partition in units of Logical Blocks. Which we already learned is 2880 (or <code>0xb40</code> in our node structure).</li>
<li>Next sixteen bytes are signature unique to this partition: If SignatureType is 0, this field has to be initialized with 16 zeroes. If SignatureType is 1, the MBR signature is stored in the first 4 bytes of this field. The other 12 bytes are initialized with zeroes. If SignatureType is 2, this field contains a 16 byte signature. As previously explained, signatures only make sense for real hard drives. So despite the fact that the SignatureType for the Alpine Linux ISO should be 1 (because of it using MBR), here we use all zeros. </li>
<li>Next byte expres define partition format, which in our case is MBR, so value should <code>0x01</code>.</li>
<li>Next byte describe type of disk signature, which is MBR so the value should be <code>0x01</code>.</li>
</ul>
<div class="codehilite">
<pre><span></span><code><span class="nb">echo</span> -en <span class="s2">"\x04\x01\x2a\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x0b\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x01"</span> > var.path_node5
</code></pre>
</div>
<h3>Device Path node 6</h3>
<p>Final non-standard node, which will point to bootloader file.</p>
<ul>
<li>Type <code>0x04</code> — Media Device Path</li>
<li>SubType <code>0x04</code> - File Path.</li>
<li>Length depends on the size of our string + 4 bytes.</li>
</ul>
<div class="codehilite">
<pre><span></span><code><span class="nb">echo</span> -n <span class="s2">"\efi\boot\bootx64.efi"</span><span class="p">|</span>wc
</code></pre>
</div>
<p>Gives us 21 characters, since UEFI use UTF-16 we have to count 2 bytes per character. String ends with null. So we have 42 (2 bytes x 21 characters) + 2 (null) = 44 bytes.
We have to add 4 bytes for header so length would be 46 bytes.</p>
<ul>
<li>Next 44 bytes are NULL-terminated Path string including directory and file names, which in our case is "\efi\boot\bootx64.efi". We will reuse previously learned Linux cmd-fu to generage correct part of the structure.</li>
</ul>
<div class="codehilite">
<pre><span></span><code><span class="nb">echo</span> -n <span class="s2">"\efi\boot\bootx64.efi"</span><span class="p">|</span>xxd -p<span class="p">|</span>sed <span class="s1">'s/../\\x&\\x00/g'</span>
</code></pre>
</div>
<p>Let's create our final node:</p>
<div class="codehilite">
<pre><span></span><code><span class="nb">echo</span> -en <span class="s2">"\x04\x04\x30\x00"</span> > var.path_node6
</code></pre>
</div>
<div class="codehilite">
<pre><span></span><code><span class="nb">echo</span> -en <span class="k">$(</span><span class="nb">echo</span> -n <span class="s2">"\efi\boot\bootx64.efi"</span><span class="p">|</span>xxd -p<span class="p">|</span>sed <span class="s1">'s/../\\x&\\x00/g'</span><span class="k">)</span> >> var.path_node6
</code></pre>
</div>
<p>and null-termination our string:</p>
<div class="codehilite">
<pre><span></span><code><span class="nb">echo</span> -en <span class="s2">"\x00\x00"</span> >> var.path_node6
</code></pre>
</div>
<h3>Device Path node 7</h3>
<p>We have to tell UEFI parsers that device path ended. There is special way for that.</p>
<ul>
<li>Type <code>0x7F</code> - End of Hardware Device Path</li>
<li>SubType <code>0xFF</code> - End Entire Device Path</li>
<li>Length is always 4 bytes.</li>
</ul>
<div class="codehilite">
<pre><span></span><code><span class="nb">echo</span> -en <span class="s2">"\x7f\xff\x04\x00"</span> > var.path_node7
</code></pre>
</div>
<h2>Let's put together device path</h2>
<div class="codehilite">
<pre><span></span><code>cat var.path_node1 var.path_node2 var.path_node3 var.path_node4 var.path_node5 var.path_node6 var.path_node7 > var.path
</code></pre>
</div>
<h2>Finally let's count all bytes structure has</h2>
<div class="codehilite">
<pre><span></span><code>wc var.path
</code></pre>
</div>
<p>Our structure should be 146 bytes.</p>
<div class="codehilite">
<pre><span></span><code><span class="nb">echo</span> -en <span class="s2">"\x92\x00"</span> > var.fpl
</code></pre>
</div>
<h2>Put whole boot order variable together</h2>
<div class="codehilite">
<pre><span></span><code>cat var.attr var.lo var.fpl var.desc var.path > var
</code></pre>
</div>
<h2>Create boot option</h2>
<ul>
<li>As we explored in previous exercise we know that next boot order variable should be Boot0005</li>
<li>We should also confirm what GUID boot option UEFI variables use in our system and replace X with that GUID.</li>
</ul>
<div class="codehilite">
<pre><span></span><code>dd <span class="k">if</span><span class="o">=</span>var <span class="nv">of</span><span class="o">=</span><span class="s2">"/sys/firmware/efi/efivars/Boot0005-X"</span> <span class="nv">bs</span><span class="o">=</span><span class="k">$(</span>stat -c %s var<span class="k">)</span>
</code></pre>
</div>
<h2>Final result</h2>
<p><code>efibootmgr -v</code> should give you following result:</p>
<pre><code>BootCurrent: 0000
Timeout: 0 seconds
BootOrder: 0001,0002,0003,0004,0000
Boot0000* UiApp FvVol(7cb8bdc9-f8eb-4f34-aaea-3ee4af6516a1)/FvFile(462caa21-7614-4503-836e-8ab6f4662331)
Boot0001* UEFI QEMU DVD-ROM QM00005 PciRoot(0x0)/Pci(0x1f,0x2)/Sata(2,65535,0)N.....YM....R,Y.
Boot0002* EFI Internal Shell FvVol(7cb8bdc9-f8eb-4f34-aaea-3ee4af6516a1)/FvFile(7c04a583-9e3e-4f1c-ad65-e05268d0b4d1)
Boot0003* UEFI QEMU HARDDISK QM00001 PciRoot(0x0)/Pci(0x1f,0x2)/Sata(0,65535,0)N.....YM....R,Y.
Boot0004* UEFI PXEv4 (MAC:525400123456) PciRoot(0x0)/Pci(0x2,0x0)/MAC(525400123456,1)/IPv4(0.0.0.00.0.0.0,0,0)N.....YM....R,Y.
Boot0005* Alpine Linux PciRoot(0x0)/Pci(0x1f,0x2)/Sata(0,65535,0)/CDROM(1,0xd8,0x2d00)/HD(1,MBR,0x0,0x0,0xb40)/File(\efi\boot\bootx64.efi)
</code></pre>
<p>If your results look different, please analyze which part of the device path is incorrect.</p>
<h1>Please set correct boot order.</h1>
<p>Set BootOrder to:</p>
<ol>
<li>UiApp</li>
<li>Alpine Linux</li>
<li>UEFI QEMU DVD-ROM QM00005</li>
<li>EFI Internal Shell</li>
<li>UEFI QEMU HARDDISK QM00001</li>
<li>UEFI PXEv4 (MAC:525400123456)</li>
</ol>
<p>Power off:</p>
<div class="codehilite">
<pre><span></span><code>poweroff
</code></pre>
</div>
<blockquote>
<p>And start QEMU again to check if modified boot order was applied. After start we should be able to enter BIOS menu, but if no hot key will be hit Alpine Linux should boot next.</p>
</blockquote>
<p>Please note that because we use Alpine Live ISO to try again or check variables status we have to go though configuration from Exercise #4 one more time if we want to use <code>efibootmgr</code> or <code>sbsigntools</code>.</p>
</div>
</div>
</div>
<div class="vert vert-1" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@done+block@00bee6dcc9f447d4abeac93f701a7456">
<div class="xblock xblock-public_view xblock-public_view-done" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="done" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@done+block@00bee6dcc9f447d4abeac93f701a7456" data-request-token="86e0cdd403d411efabb30242ac12000b" data-graded="True" data-has-score="True">
<div class="page-banner"><div class="alert alert-warning"><span class="icon icon-alert fa fa fa-warning" aria-hidden="true"></span><div class="message-content">Completion is only accessible to enrolled learners. Sign in or register, and enroll in this course to view it.</div></div></div>
</div>
</div>
<div class="vert vert-2" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@discussion+block@2c969cce93f64bfd8b08022bc3733296">
<div class="xblock xblock-public_view xblock-public_view-discussion" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="discussion" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@discussion+block@2c969cce93f64bfd8b08022bc3733296" data-request-token="86e0cdd403d411efabb30242ac12000b" data-graded="True" data-has-score="False">
<div class="page-banner"><div class="alert alert-warning"><span class="icon icon-alert fa fa fa-warning" aria-hidden="true"></span><div class="message-content">Discussion is only accessible to enrolled learners. Sign in or register, and enroll in this course to view it.</div></div></div>
</div>
</div>
</div>
<script type="text/javascript">
(function (require) {
require(['/static/js/dateutil_factory.be68acdff619.js?raw'], function () {
require(['js/dateutil_factory'], function (DateUtilFactory) {
DateUtilFactory.transform('.localized-datetime');
});
});
}).call(this, require || RequireJS.require);
</script>
<script>
function emit_event(message) {
parent.postMessage(message, '*');
}
</script>
</div>
<div class="xblock xblock-public_view xblock-public_view-vertical" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-init="VerticalStudentView" data-runtime-class="LmsRuntime" data-runtime-version="1" data-block-type="vertical" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@vertical+block@1addb9e70be649f59779b1415b34639e" data-request-token="86e0cdd403d411efabb30242ac12000b" data-graded="True" data-has-score="False">
<div class="vert-mod">
<div class="vert vert-0" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@video+block@aa6f590c5f4145279dfced1c2b5321f3">
<div class="xblock xblock-public_view xblock-public_view-video xmodule_display xmodule_VideoBlock" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-init="XBlockToXModuleShim" data-runtime-class="LmsRuntime" data-runtime-version="1" data-block-type="video" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@video+block@aa6f590c5f4145279dfced1c2b5321f3" data-request-token="86e0cdd403d411efabb30242ac12000b" data-graded="True" data-has-score="False">
<script type="json/xblock-args" class="xblock-json-init-args">
{"xmodule-type": "Video"}
</script>
<h3 class="hd hd-2">Video</h3>
<div
id="video_aa6f590c5f4145279dfced1c2b5321f3"
class="video closed"
data-metadata='{"autoAdvance": false, "autohideHtml5": false, "autoplay": false, "captionDataDir": null, "completionEnabled": false, "completionPercentage": 0.95, "duration": 0.0, "end": 0.0, "generalSpeed": 1.0, "lmsRootURL": "https://p.ost2.fyi", "poster": null, "prioritizeHls": false, "publishCompletionUrl": "/courses/course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1/xblock/block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@video+block@aa6f590c5f4145279dfced1c2b5321f3/handler/publish_completion", "recordedYoutubeIsAvailable": true, "savedVideoPosition": 0.0, "saveStateEnabled": false, "saveStateUrl": "/courses/course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1/xblock/block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@video+block@aa6f590c5f4145279dfced1c2b5321f3/handler/xmodule_handler/save_user_state", "showCaptions": "false", "sources": [], "speed": null, "start": 0.0, "streams": "1.00:Z9keGrBCmoU", "transcriptAvailableTranslationsUrl": "/courses/course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1/xblock/block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@video+block@aa6f590c5f4145279dfced1c2b5321f3/handler/transcript/available_translations", "transcriptLanguage": "en", "transcriptLanguages": {"en": "English"}, "transcriptTranslationUrl": "/courses/course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1/xblock/block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@video+block@aa6f590c5f4145279dfced1c2b5321f3/handler/transcript/translation/__lang__", "ytApiUrl": "https://www.youtube.com/iframe_api", "ytMetadataEndpoint": "", "ytTestTimeout": 1500}'
data-bumper-metadata='null'
data-autoadvance-enabled="False"
data-poster='null'
tabindex="-1"
>
<div class="focus_grabber first"></div>
<div class="tc-wrapper">
<div class="video-wrapper">
<span tabindex="0" class="spinner" aria-hidden="false" aria-label="Loading video player"></span>
<span tabindex="-1" class="btn-play fa fa-youtube-play fa-2x is-hidden" aria-hidden="true" aria-label="Play video"></span>
<div class="video-player-pre"></div>
<div class="video-player">
<div id="aa6f590c5f4145279dfced1c2b5321f3"></div>
<h4 class="hd hd-4 video-error is-hidden">No playable video sources found.</h4>
<h4 class="hd hd-4 video-hls-error is-hidden">
Your browser does not support this video format. Try using a different browser.
</h4>
</div>
<div class="video-player-post"></div>
<div class="closed-captions"></div>
<div class="video-controls is-hidden">
<div>
<div class="vcr"><div class="vidtime">0:00 / 0:00</div></div>
<div class="secondary-controls"></div>
</div>
</div>
</div>
</div>
<div class="focus_grabber last"></div>
</div>
</div>
</div>
<div class="vert vert-1" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@markdown+block@953acbc3a8f04182ae253d2f2ad9735c">
<div class="xblock xblock-public_view xblock-public_view-markdown" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="markdown" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@markdown+block@953acbc3a8f04182ae253d2f2ad9735c" data-request-token="86e0cdd403d411efabb30242ac12000b" data-graded="True" data-has-score="False">
<div class="markdown_xblock"><h2>Example past vulnerability in the processing of the complex CapsuleUpdate scatter/gather process:</h2>
<p>Whitepaper: <a href="https://www.mitre.org/sites/default/files/publications/14-2221-extreme-escalation.pdf">https://www.mitre.org/sites/default/files/publications/14-2221-extreme-escalation.pdf</a> <br />
Slides: <a href="https://www.mitre.org/sites/default/files/publications/14-2221-extreme-escalation-presentation.pdf">https://www.mitre.org/sites/default/files/publications/14-2221-extreme-escalation-presentation.pdf</a> <br />
Video: <a href="https://www.youtube.com/watch?v=X_Jxsl3vVcA">https://www.youtube.com/watch?v=X_Jxsl3vVcA</a></p>
</div>
</div>
</div>
<div class="vert vert-2" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@done+block@5ccffc477bce43b28e4e84110e51277d">
<div class="xblock xblock-public_view xblock-public_view-done" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="done" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@done+block@5ccffc477bce43b28e4e84110e51277d" data-request-token="86e0cdd403d411efabb30242ac12000b" data-graded="True" data-has-score="True">
<div class="page-banner"><div class="alert alert-warning"><span class="icon icon-alert fa fa fa-warning" aria-hidden="true"></span><div class="message-content">Completion is only accessible to enrolled learners. Sign in or register, and enroll in this course to view it.</div></div></div>
</div>
</div>
<div class="vert vert-3" data-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@discussion+block@f3f2b615dc824bb488fafeaa3938b997">
<div class="xblock xblock-public_view xblock-public_view-discussion" data-course-id="course-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1" data-block-type="discussion" data-usage-id="block-v1:OpenSecurityTraining2+Arch4021_intro_UEFI+2023_v1+type@discussion+block@f3f2b615dc824bb488fafeaa3938b997" data-request-token="86e0cdd403d411efabb30242ac12000b" data-graded="True" data-has-score="False">
<div class="page-banner"><div class="alert alert-warning"><span class="icon icon-alert fa fa fa-warning" aria-hidden="true"></span><div class="message-content">Discussion is only accessible to enrolled learners. Sign in or register, and enroll in this course to view it.</div></div></div>
</div>
</div>
</div>
<script type="text/javascript">
(function (require) {
require(['/static/js/dateutil_factory.be68acdff619.js?raw'], function () {
require(['js/dateutil_factory'], function (DateUtilFactory) {
DateUtilFactory.transform('.localized-datetime');
});
});
}).call(this, require || RequireJS.require);
</script>
<script>
function emit_event(message) {
parent.postMessage(message, '*');
}
</script>
</div>