Attack Overview
Speculative execution has been a widely reported and studied vulnerability that focuses on violating memory isolation. For a while Intel’s SGX was thought to be safe from speculative execution, but recent research has shown that this is not the case. The Foreshadow attack is capable of violating all security assumptions surrounding intel SGX and requires a true hardware level patch to fix.
Foreshadow is an extension upon Meltdown which allows SGX memory to sit unprotected in the cache. The key to defeating SGX’s protections lies in abusing the legacy permission checks which occur before SGX can implement its own protections. Originally, SGX was thought to be secure as when an invalid memory access occurs all data gets overwritten with a dummy value of –1. This behavior is called “abort page” semantics. In order to defeat this protection, we need to cause a “page fault”. A page fault is part of the legacy permission checks which if failed, deny SGX the opportunity to overwrite the data.
Once this page fault occurs, an exception is thrown which can be handled by our attacking process. So how do we cause this page fault? We leverage the ability to mark memory as strictly increasing in privilege level with the unprivileged mprotect command.
Using this command, we abuse the “not present” bit of page tables. Traditional Meltdown attacks focus on the “supervisor bit” which is used to isolate memory from user processes, but this alone will unfortunately reach and “abort page” causing our attack to fail. By marking the page as not present, we can effectively preempt SGX protections and cause a page fault.
Now that we know how to cause a page fault, we need to extract the secret residing in the cache. Foreshadow has done all the hard work of defeating SGX protections, so now we can leverage a traditional Meltdown attack to do the rest. The below code attempts to dereference the secret’s pointer and transiently execute the subsequent code.
As long as we win the race between our transient code (lines 6-8) the secret should reside in cache. We then simply measure access time to the oracle to extract the byte. Putting it all together, we can see the process outlined in the below diagram.
For those interested in a demonstration of this attack they can find it at https://youtu.be/8ZF6kX6z7pM. By sheer chance I own an SGX capable CPU and was able to run an educational demo available at https://github.com/jovanbulck/sgx-step. As can be seen in my output below, foreshadow was able to extract 59/64 bytes of the secret residing in the enclave. I've often found that it can achieve 100% efficiency as outlined by the foreshadow paper.
==== Victim Enclave ====
Base: 0x7f2cbd800000
Size: 4194304
Limit: 0x7f2cbdc00000
TCS: 0x7f2cbdb7e000
SSA: 0x7f2cbdb7ff48
AEP: 0x7f2cbf8bc77b
EDBGRD: debug
[pt.c] /dev/mem opened!
[main.c] Randomly generated enclave secret at 0x7f2cbda1d6c0 (page 0x7f2cbda1d000); alias at 0x7f2cbfcff6c0 (revoking alias access rights)
+-------------------------------------------------------------------------------------------+
| XD | PK | IGN | RSVD | PHYS ADRS | IGN | G | PAT | D | A | PCD | PWT | U/S | R/W | P |
| 0 | x | x | 0 | 0x00007041d000 | x | x | x | 1 | 1 | x | x | 1 | 1 | 1 |
+-------------------------------------------------------------------------------------------+
+-------------------------------------------------------------------------------------------+
| XD | PK | IGN | RSVD | PHYS ADRS | IGN | G | PAT | D | A | PCD | PWT | U/S | R/W | P |
| 0 | x | x | 0 | 0x00007041d000 | x | x | x | 0 | 1 | x | x | 1 | 1 | 0 |
+-------------------------------------------------------------------------------------------+
[foreshadow.c] cache hit/miss=50/218; reload threshold=108
--------------------------------------------------------------------------------
[main.c] Foreshadow secret extraction
--------------------------------------------------------------------------------
[main.c] prefetching enclave secret (EENTER/EEXIT)...
[main.c] extracting secret from L1 cache..
[main.c] verifying and destroying enclave secret..
shadow[ 0]=0x54; enclave[ 0]=0x54 ** shadow[ 1]=0x00; enclave[ 1]=0xff
shadow[ 2]=0x0b; enclave[ 2]=0x0b shadow[ 3]=0x05; enclave[ 3]=0x05
shadow[ 4]=0xa1; enclave[ 4]=0xa1 shadow[ 5]=0x8d; enclave[ 5]=0x8d
shadow[ 6]=0xbd; enclave[ 6]=0xbd shadow[ 7]=0xd4; enclave[ 7]=0xd4
shadow[ 8]=0x51; enclave[ 8]=0x51 shadow[ 9]=0x44; enclave[ 9]=0x44
shadow[10]=0x5b; enclave[10]=0x5b shadow[11]=0xc7; enclave[11]=0xc7
shadow[12]=0x79; enclave[12]=0x79 shadow[13]=0x6a; enclave[13]=0x6a
shadow[14]=0x42; enclave[14]=0x42 shadow[15]=0xaf; enclave[15]=0xaf
shadow[16]=0xc0; enclave[16]=0xc0 ** shadow[17]=0x00; enclave[17]=0x91
shadow[18]=0x22; enclave[18]=0x22 shadow[19]=0x02; enclave[19]=0x02
shadow[20]=0xd3; enclave[20]=0xd3 shadow[21]=0xf3; enclave[21]=0xf3
shadow[22]=0xa3; enclave[22]=0xa3 shadow[23]=0x4e; enclave[23]=0x4e
shadow[24]=0xfb; enclave[24]=0xfb ** shadow[25]=0x00; enclave[25]=0x3f
shadow[26]=0x45; enclave[26]=0x45 shadow[27]=0x21; enclave[27]=0x21
shadow[28]=0xb3; enclave[28]=0xb3 ** shadow[29]=0x00; enclave[29]=0xee
shadow[30]=0xa4; enclave[30]=0xa4 shadow[31]=0x96; enclave[31]=0x96
shadow[32]=0xae; enclave[32]=0xae shadow[33]=0x85; enclave[33]=0x85
shadow[34]=0xeb; enclave[34]=0xeb shadow[35]=0x21; enclave[35]=0x21
shadow[36]=0xd4; enclave[36]=0xd4 shadow[37]=0x9e; enclave[37]=0x9e
shadow[38]=0xa7; enclave[38]=0xa7 shadow[39]=0x3a; enclave[39]=0x3a
shadow[40]=0x95; enclave[40]=0x95 shadow[41]=0x84; enclave[41]=0x84
shadow[42]=0xe0; enclave[42]=0xe0 shadow[43]=0xb0; enclave[43]=0xb0
shadow[44]=0xef; enclave[44]=0xef shadow[45]=0x84; enclave[45]=0x84
shadow[46]=0xa4; enclave[46]=0xa4 shadow[47]=0xff; enclave[47]=0xff
shadow[48]=0xd6; enclave[48]=0xd6 shadow[49]=0x44; enclave[49]=0x44
shadow[50]=0x0e; enclave[50]=0x0e shadow[51]=0xaa; enclave[51]=0xaa
shadow[52]=0x0b; enclave[52]=0x0b shadow[53]=0x8b; enclave[53]=0x8b
shadow[54]=0x04; enclave[54]=0x04 shadow[55]=0x1c; enclave[55]=0x1c
shadow[56]=0x0f; enclave[56]=0x0f shadow[57]=0x2b; enclave[57]=0x2b
shadow[58]=0x34; enclave[58]=0x34 shadow[59]=0xd8; enclave[59]=0xd8
shadow[60]=0xc0; enclave[60]=0xc0 ** shadow[61]=0x00; enclave[61]=0xe8
shadow[62]=0xea; enclave[62]=0xea shadow[63]=0xce; enclave[63]=0xce
[foreshadow.c] [FAIL] Foreshadow missed 5 bytes out of 64 :/
==== Victim Enclave ====
Base: 0x7f2cbd800000
Size: 4194304
Limit: 0x7f2cbdc00000
TCS: 0x7f2cbdb7e000
SSA: 0x7f2cbdb7ff48
AEP: 0x7f2cbf8bc77b
EDBGRD: debug
[pt.c] /dev/mem opened!
[main.c] Randomly generated enclave secret at 0x7f2cbda1d6c0 (page 0x7f2cbda1d000); alias at 0x7f2cbfcff6c0 (revoking alias access rights)
+-------------------------------------------------------------------------------------------+
| XD | PK | IGN | RSVD | PHYS ADRS | IGN | G | PAT | D | A | PCD | PWT | U/S | R/W | P |
| 0 | x | x | 0 | 0x00007041d000 | x | x | x | 1 | 1 | x | x | 1 | 1 | 1 |
+-------------------------------------------------------------------------------------------+
+-------------------------------------------------------------------------------------------+
| XD | PK | IGN | RSVD | PHYS ADRS | IGN | G | PAT | D | A | PCD | PWT | U/S | R/W | P |
| 0 | x | x | 0 | 0x00007041d000 | x | x | x | 0 | 1 | x | x | 1 | 1 | 0 |
+-------------------------------------------------------------------------------------------+
[foreshadow.c] cache hit/miss=50/218; reload threshold=108
--------------------------------------------------------------------------------
[main.c] Foreshadow secret extraction
--------------------------------------------------------------------------------
[main.c] prefetching enclave secret (EENTER/EEXIT)...
[main.c] extracting secret from L1 cache..
[main.c] verifying and destroying enclave secret..
shadow[ 0]=0x54; enclave[ 0]=0x54 ** shadow[ 1]=0x00; enclave[ 1]=0xff
shadow[ 2]=0x0b; enclave[ 2]=0x0b shadow[ 3]=0x05; enclave[ 3]=0x05
shadow[ 4]=0xa1; enclave[ 4]=0xa1 shadow[ 5]=0x8d; enclave[ 5]=0x8d
shadow[ 6]=0xbd; enclave[ 6]=0xbd shadow[ 7]=0xd4; enclave[ 7]=0xd4
shadow[ 8]=0x51; enclave[ 8]=0x51 shadow[ 9]=0x44; enclave[ 9]=0x44
shadow[10]=0x5b; enclave[10]=0x5b shadow[11]=0xc7; enclave[11]=0xc7
shadow[12]=0x79; enclave[12]=0x79 shadow[13]=0x6a; enclave[13]=0x6a
shadow[14]=0x42; enclave[14]=0x42 shadow[15]=0xaf; enclave[15]=0xaf
shadow[16]=0xc0; enclave[16]=0xc0 ** shadow[17]=0x00; enclave[17]=0x91
shadow[18]=0x22; enclave[18]=0x22 shadow[19]=0x02; enclave[19]=0x02
shadow[20]=0xd3; enclave[20]=0xd3 shadow[21]=0xf3; enclave[21]=0xf3
shadow[22]=0xa3; enclave[22]=0xa3 shadow[23]=0x4e; enclave[23]=0x4e
shadow[24]=0xfb; enclave[24]=0xfb ** shadow[25]=0x00; enclave[25]=0x3f
shadow[26]=0x45; enclave[26]=0x45 shadow[27]=0x21; enclave[27]=0x21
shadow[28]=0xb3; enclave[28]=0xb3 ** shadow[29]=0x00; enclave[29]=0xee
shadow[30]=0xa4; enclave[30]=0xa4 shadow[31]=0x96; enclave[31]=0x96
shadow[32]=0xae; enclave[32]=0xae shadow[33]=0x85; enclave[33]=0x85
shadow[34]=0xeb; enclave[34]=0xeb shadow[35]=0x21; enclave[35]=0x21
shadow[36]=0xd4; enclave[36]=0xd4 shadow[37]=0x9e; enclave[37]=0x9e
shadow[38]=0xa7; enclave[38]=0xa7 shadow[39]=0x3a; enclave[39]=0x3a
shadow[40]=0x95; enclave[40]=0x95 shadow[41]=0x84; enclave[41]=0x84
shadow[42]=0xe0; enclave[42]=0xe0 shadow[43]=0xb0; enclave[43]=0xb0
shadow[44]=0xef; enclave[44]=0xef shadow[45]=0x84; enclave[45]=0x84
shadow[46]=0xa4; enclave[46]=0xa4 shadow[47]=0xff; enclave[47]=0xff
shadow[48]=0xd6; enclave[48]=0xd6 shadow[49]=0x44; enclave[49]=0x44
shadow[50]=0x0e; enclave[50]=0x0e shadow[51]=0xaa; enclave[51]=0xaa
shadow[52]=0x0b; enclave[52]=0x0b shadow[53]=0x8b; enclave[53]=0x8b
shadow[54]=0x04; enclave[54]=0x04 shadow[55]=0x1c; enclave[55]=0x1c
shadow[56]=0x0f; enclave[56]=0x0f shadow[57]=0x2b; enclave[57]=0x2b
shadow[58]=0x34; enclave[58]=0x34 shadow[59]=0xd8; enclave[59]=0xd8
shadow[60]=0xc0; enclave[60]=0xc0 ** shadow[61]=0x00; enclave[61]=0xe8
shadow[62]=0xea; enclave[62]=0xea shadow[63]=0xce; enclave[63]=0xce
[foreshadow.c] [FAIL] Foreshadow missed 5 bytes out of 64 :/
Impact and Mitigations
Foreshadow is able to effectively violate all confidentiality assumptions of intel SGX. Researchers have been able to demonstrate attacks against intel’s own launch and quoting enclaves. These attacks steal important signing keys which would allow attackers to both launch rogue enclaves and sign bogus attestation reports.
Current speculative execution mitigations like KASIER, which focuses on page-table isolation, are unfortunately insufficient to stop foreshadow. This is because SGX is distrustful of the operating system’s kernel to begin with, and the enclave lives entirely in the address space of the host process. It seems that intel will have to implement hardware level changes to truly patch this vulnerability. The main point that I’ve taken away from this attack is summed up nicely by the team behind foreshadow, “An important lesson from the recent wave of transient execution attacks including Spectre, Meltdown, and Foreshadow, however, is that current processors exceed our levels of understanding”.
References
Van Bulck, Jo, et al. "Foreshadow: Extracting the keys to the intel {SGX} kingdom with transient out-of-order execution." 27th {USENIX} Security Symposium ({USENIX} Security 18). 2018.
References
Van Bulck, Jo, et al. "Foreshadow: Extracting the keys to the intel {SGX} kingdom with transient out-of-order execution." 27th {USENIX} Security Symposium ({USENIX} Security 18). 2018.
Comments
Post a Comment