Pinned resources
Honestly a pretty good lecture on first principles.
Also the lecturer opened the floor to suggest topics for security stuff. Infrastructure security module come AY2023/24 Sem 2.
Main motivation is to subvert almost all forms of malicious threats (even up to kernel rootkits) by isolating into a sandbox.
The concept of virtual machines actually came out from 1960s to share machines between users (e.g. IBM). The late 1990s focused on RISC/CISC virtualization to mitigate under-utilization, ease-of-maintenance, security (e.g. VMWare). Today the virtualization model is heavily utilized in cloud computing.
Two-fold security goals for virtualization, specifically the isolation of code, data and resources between:
assuming that the TCB (i.e. Host OS and VMM) are bug-free, and that guest VMs may contain arbitrary malware. These translate to the following enforcement goals for a VMM:
Although virtualization was historically designed for performance rather than for security, there are some main security uses of virtualization, including:
The guest OS, from its perspective, runs in (privileged) ring 0, but actually runs in ring 1 on the host OS. The VMM, which actually runs in ring 0, traps the instructions called by the guest and emulates these instructions (e.g. accesses to page table). This is known as trap-and-emulate.
There is a problem: x86 architecture has a few instructions that are privileged but do not generate traps, e.g. cli
(clear interrupt) traps, but popf
(pop flag) does not trap for performance reasons.
This can be resolved using direct binary translation (DBT), which has the VMM inspecting all privileged x86 instructions to be executed and replacing non-trapping instructions with explicit traps. This was first implemented in Dynamo that led to the foundation of VMWare. See link. Transparency is not violated, since the memory accesses itself can also be trapped.
To get rid of the significant overhead from instruction inspection, other techniques include:
Commercial VMMs are not fully transparent, which makes it possible to detect (e.g. for malware to use anti-VM techniques, or copy protection via VM-duplication). Known as the red-pill attack, and there are many vectors:
Despite inter-VM containment, because shared states are utilized, convert channels will exist. One example is via the use of shared cache latencies (e.g. sender deterministically performs a random memory access, and the receiver records bit 1 if long read time for fixed memory location, and 0 otherwise - CCS'09). Other channels via disk, I/O, virtualization latencies, exist as well.
Other readings:
System time can vary in VMs, will it affect virtualization detection techniques?
To thwart the possibility of malicious OS layers loading before user OS layers, we can implement a hardware root-of-trust via the use of Trusted Execution Environments (TEEs), to allow assumptions of malicious software.
Examples of TEE implementations: TPM 1.2 (2004), TrustZone (2005), Intel TXT (2006), TPM 2.0 (2014), Intel SGX (2016).
Remote attestation is the first primitive implemented in TEE. During loading of each OS layer, a measurement is triggered on them and hashes are derived from them and stored in the TPM registers. The CPU cannot tamper with the TPM directly. All these hashes are digitally-signed by the TPM using a hardware AIK signing key, and then sent to a remote server for hash validation.
Loading of hardware key
There are methods where the manufacturer cannot tell what the signing key is, using physically-uncloneable functions (PUFs), e.g. via randomness in CMOS manufacturing process.
Trusted boot is enforced by implementing this remote attestation with a local secure storage.
Data sealing can also be performed by computing the hash of the software requesting the seal, and storing both the hashes and the disk encryption key is both stored in the secure storage. Unseals only if hash matches.
With these primitives, we can construct root-of-trust applications, e.g. Windows BitLocker performs block-level encryption of volumes, Linux TrustedGrub, eXtensible Modular Hypervisor Framework.
As opposed to static RTM which performs verification at load time, dynamic RTM is also possible using Intel TXT SKINT
and SENTER
instructions. See also the use of enclaves in iOS.
Some definitions:
"Protection and access control in operating systems," Lampson72, defines the use of an explicit access control matrix to assign rights between users and resources. But this is not the only way to think about access control.
Problems with this OS model is with the presence of programs with ambient authority, e.g. cp
program that is used by almost every user and has the authority to write to any file on the Android system, which then violates the principle of least privilege.
A different way of implementing access rights is to use a capability model, which is a (pointer, metadata) tuple embedding access rights. These are sufficient and necessary for access to objects, and can be created or modified only by querying the security monitor. Such capabilities however must be unforgeable.
cp < foo.txt > bar.txt | +--- capability 2 +--- capability 1
Note that while the security monitor is effectively an ambient authority, the security monitor can be embedded in hardware or enclaves for stronger protection guarantees.
A direct comparison:
Access control | Capabilities | |
---|---|---|
Pre-specified policies | Needed, implemented centrally by security monitor | None, follows natural flow of access rights (e.g. programs can pass on capabilities) |
Revocation | Yes, and easy to implement | Possible by changing the capability on the object, but requires some careful design |
Ambient authority | Yes | No |
Assumptions | Complete mediation (syscalls must make access checks) | Unforgeability |
The bulk of syscalls introduced into later versions of Android seem to come from Java semantics, e.g. for stack inspection, isolation. The base number of syscalls originates from UNIX (BSD-variant) syscalls. In contrast, the ioctl
library seems to introduce less syscalls, likely because of the use of the Java higher level language for programs.
Checks for enforcement (e.g. process sandboxing, IRMs, capabilities, virtualization, TEE) come in the form of policy mechanisms. Three main types of access controls:
Confused deputy problem
Let's talk about the second line of defense, which is to minimize the impact of attacks that we know will happen. Two distinct methods:
Some checks that an inline reference monitor can check for includes:
We illustrate one such inline reference monitor, whose goal is fault isolation (also known as "address sandboxing").
Threat model: Attacker controls all memory values in M.
Main idea is to insert some inline instrument inside the program (e.g. via recompiling), such that all memory accesses are forced to point to the memory region M only.
; Original code mov (ebp),eax ; Modified (instrumented) code call (InRange(ebp)) ; checks if in defined memory range jz error_label ; jumps if Z flag set mov (ebp),eax ; move memory pointed by ebp
The checking function call can be made faster, by constraining the possible values of the memory address (i.e. coerce rather than check). This is known as Fast-SFI.
; Original code mov (ebp),eax ; Faster instrumented code and ebp,0x00ff or ebp,0xbe00 mov (ebp),eax
This is still problematic, since one can force instructions to jump directly to the mov (ebp),eax
. This can be prevented by using dedicated registers, e.g. reg1
, that is outside the control of the attacker - the argument is that regardless of which program instruction you jump to, the memory addressed by reg1
will *always* be safe.
mov ebp,reg1 and reg1,0x00ff or reg1,0xbe00 mov (reg1),eax
This simplifies the verification for Fast-SFI, which only involves checking three points:
Rule of thumb: We need to minimize the size of the TCB (trusted computing base) that we need to trust in order to verify the correctness of the program, and/or the security properties of the program.
Security principle 1: Minimize TCB
Reduce what one needs to trust, e.g., by separating verifier from the enforcement.
and a collorary:
Security principle 2: Separation of concerns
Separate the policy from its enforcement.
Involves using the higher privileges of the OS/kernel to define syscall policies, e.g. "no exec() system calls", or even an exploit pattern "no exec()-after-read() system calls". This also has standard enumerations in Linux:
seccomp
: no syscalls, except exit(), sigreturn(), as well as read() and write() on already-open file descriptorsseccomp-bpf
: configurable policies, including syscallSecurity principle 3: Principle of Least Privilege
Each component should only have smallest set of necessary privileges.
A collorary implies that allowlist policies (e.g. "seccomp") are preferred over denylist policies (e.g. "no exec-after-read") which are much broader.
The problem in many software involves the philosophy of bundling functionality. We want to avoid cascading failures when one component fails:
The solution is the use of privilege separation, i.e. compartmentalization and assignment of least privilege. This principle is used in the Google Chrome browser:
Recall the goals of memory safety:
We can achieve this either by compilation, binary rewriting, or more simply, insertion of memory tracking metadata and inline monitors (assuming such metadata can only be accessed by monitors, and cannot be corrupted).
Use of referent objects implementation for spatial memory safety involves using shadow memory, e.g. JK-Tree, Baggy BC.
struct { char str[8]; void (*func)(); } node; char* ptr = node.str; strcpy(ptr, "overflow..."); // bound for 'node' used for 'ptr'
The problem of overlapping objects in assigning bounds is avoided by using fat pointers, i.e. pointers that directly store the bounds metadata. One such implementation is Softbound.
Basic implementation for fat pointer
Unsafe typecasting under fat pointers
In both approaches, runtime overhead is rather high, up to twice as long.
We also need to track the creation and destruction of pointers, to ensure that deallocated pointers are not accessed. Simple mechanisms like a quick and dirty pointer nullification does not achieve temporal safety (there can be other objects that reference the same memory space, e.g. char* p = (char*) malloc(SIZE); char* q = p;
).
An alternative implementation is to have a matching lock and key values iff the memory object is temporally safe to access. An overview implementation is shown below. Note that this mechanism provides complete temporal safety, so long as program has spatial safety (to ensure data does not overflow).
Basic implementation of lock-and-key
Performance overhead is still close to 200%, due dynamic checking.
We can incorporate the concepts from both lock+key and fat pointers for full memory safety, but this incurs high performance overheads.
This is the basis for C++17 smart pointers, and in Rust. Such smart pointers wrap pointer objects, with automatic allocation and deallocation, as well as preserve metadata about the resource object. Smart pointers own the resource object (and so can be solely responsible for freeing objects when the pointer goes out of scope), performs bounds-checking.
In C++17, this is implemented as:
unique_ptr
: pointers that can be moved but cannot be copied.shared_ptr
: includes reference count metadata, and frees only when number of pointers pointing to resource goes to zero.In Rust, smart pointers are used by default. This allows for static rule baked into the language to avoid runtime checking.
Memory safety, with some useful references:
In the code below, because printf
first argument is treated as a format string, the user can inject format strings to read directly from the stack, i.e. AAAA %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x
.
#include <stdio.h> int main() { srand(time(NULL)); char localStr[100]; int magicNumber = rand() % 100; int userCode = 0xBBBBBBBB; printf("Username? "); fgets(localStr, sizeof(localStr), stdin); printf("Hello "); printf(localStr); printf("What is the access code? "); scanf("%d", &userCode); if (userCode == magicNumber) { printf("You win!\n"); } }
Because C tries to be as generic as possible with data widths, implementation details are often left to the compilers, which can have different behavior depending on the platform. For integers, since the use of two's complement allows the use of the same operation,
There are usually constraints to modifying the underlying binary, e.g. read-execute-only. Separate channels exist to modify writable sections of the running code at run time, e.g. by modifying the stack. Suppose an attacker wants to inject a payload that forks a new bash shell:
int main(int argc, char *argv[]) { char *sh; char *args[2]; sh = "/bin/bash"; args[0] = sh; args[1] = NULL; execve(sh, args, NULL); }
which translates into the following shell code
During the buffer overflow earlier, we:
Since it is difficult to determine the correct offset to reach the start of the shellcode, one can prepend a series of NOP instructions to the shellcode (execution will reach shellcode as long as return address points to somewhere within this NOP sled).
Sometimes we don't even require the attack payload, such as in the return-to-libc
attack that changes the return address to the execve
line within the C library.
https
-> http
)Secure
keyword so that it is sent only over HTTPSexample.com\0.evil.com
as the common name (string comparison in vulnerable SSL library)opacity: 0.1; pointer-events: none
Note
Interesting exercise hosted by Prateek: Ask how compromised CAs can be detected and avoided, then reflect and expand on suggestions.
Slides are a little old...? Certificate pinning is not commonly supported today.
Side-channels are information leakage which are not intended, e.g. consider the RSA exponentiation algorithm:
$$$$ y = g^k \text{mod}\;N $$$$
can be decomposed into squaring-and-multiplying operations.
r0 = 1; r1 = g for j = len(s)
Another example is the "Lucky Thirteen".
This is a pretty good resource to start getting into some legacy attacks:
Perfect secrecy is impractical due to the large key size requirement. We reduce the threat model into an attacker that is computationally bounded, i.e. the adversary can use all deterministic, efficient algorithms that run in polynomial time. This allows for constructions using PRGs that are computationally hard,
$$$$ \text{Enc}(k, m) = \text{PRG}(k) \oplus m $$$$
We can show that pseudorandom generators (stream ciphers) exist from the existence of one-way functions.
Side-note on the use of hard one-way functions:
Two pioneers in key exchange:
Perfect forward secrecy achieved by discarding messages that performs the key generation (what about an on-path attacker that can passively log all transactions?).
Note that Diffie-Hellman (DH) is not a secure key exchange protocol, since it is susceptible to an MitM attack. Adding of signatures in DH Station-to-Station (STS) to sign the messages being sent, we can achieve an authenticated key exchange.
With computational hardness, we can distill more primitives, i.e. digital signatures, and authenticated key DHKE + signatures.
A high level overview of SSL/TLS goes roughly as follows:
This is a nice diagrammatic overview:
Some notes:
When performing security analysis, we state the assumptions in the threat model (which should be likely to be true), and then formulate security arguments. In HTTPS, the assumptions of the threat model are:
Instead of having an attack-centric viewpoint, we focus on the capabilities of the attacker instead.
Strong threat model of network attacker: All traffic between parties can be intercepted. Additionally, eavesdropper can listen in, while malicious actor can modify as well.
Basic cryptographic primitives are elements like encryption, MAC and digital signatures. These can, in turn, provide security goals such as confidentiality, integrity, and authenticity.
To discuss security, we can adopt the following procedure:
To ensure a secure channel, we need to distill some sort of advantage over any network attacker, either:
Correctness is straightforward to define -> decryption of encrypted message returns the original message. Security on the other hand needs to be less dependent on attacker capabilities, e.g. "attacker cannot guess key from ciphertext" is dependent on attacker prior knowledge (such as cryptanalysis methods).
Threat model:
In the context of a chosen plaintext attacker (CPA), the security goal is then defined as perfect secrecy, where probability of guessing message is independent of the given ciphertext:
$$$$ Pr[m_{guess}|c] = Pr[m_{guess}] $$$$
Please read the work of Shannon's.
We first consider a minimal one-bit encryption scheme, where $$ M, K, C \in \{0,1\} $$, to derive a scheme that exhibits both correctness and perfect secrecy. The space of possible functions is $$ 2^4 $$, but not all share correctness nor perfect secrecy:
Function | Correctness | Perfect secrecy |
---|---|---|
AND | No: given c=0, m=? | No: given c=1, we know m=1 |
c=m | Yes | No: given c=x, we know m=x |
c=k | No: given c=x, m=? | Yes |
random | No | Yes |
XOR | Yes: bijective function | Yes: with uniform k, each value of m equally probable with each value of c |
Main limitation is that the key space must be larger than message space.
Key expansion
In practical deployment, we run key expansion over a much smaller pre-shared key. This no longer fulfills the perfect secrecy condition (why?).
In a weaker threat model where the attacker does not have infinite computation power (i.e. bounded by computation in polynomial time), a weaker form of secrecy can still be guaranteed.
Integrity is provided by MAC, which has the following definition over the message, key and tag space $$ (K,M,T) $$:
The goal of the attacker is existential forgery under a chosen message attack (CMA), i.e. guess tag t from message m. The security goal is tend to
Consider again the one-bit MAC, where the tag space $$ |T| = 2^n = 1 $$. The signing algorithm cannot be XOR (as in OTP), because the key can be identified under a CMA (supply m = 0).
Note that the publicly available information now spans the space $$ (M,T) $$, which is two bits. The secret required to have a perfectly secure MAC is then to also have a two-bit secret. We can define the following signing algorithm with two one-bit secrets $$a$$ and $$b$$, and this falls under the family of universal hashes:
$$$$ t = (a\cdot{}m + b) \text{mod} 2 $$$$
Note again that if two combinations of (m,t) are generated with the same secrets a and b, then the secret can be extracted -> randomness over choice of (a,b).
This is the definit
Need to read through this again.
To elaborate on the securities afforded by the TCP protocol. Overview of TCP handshake - to authenticate the client to the server.
Need to distinguish what the threat model is when looking at vulnerabilities of the protocol, for example the TCP protocol is not designed to provide authentication on the OSI layer.
Some vulnerabilities:
Here's a nice resource on security of DNS.
A stateless firewall inspects packets and checks if they match rules. These devices need to have high overall throughput. Note that the device on which the firewall sits must also be able to support the TCP reconstruction process (why?). Other types of firewalls include stateful firewalls and application-layer firewalls.
On Linux, firewall is implemented within the netfiler framework (iptables
), with different hooks for packets, e.g. INPUT, FORWARD, POST-ROUTING.
Some vulnerabilities:
Some mitigations:
Firewall threat model
Adversary capabilties:
Assumptions:
Weakness is this threat model: defender needs to know every specific attack pattern for setting policy, and adversary can easily evade these assumptions.
The point of this section is to emphasize that thinking of the threat model conceptually is important for defending against attacks.
Lecturer: Prateek Saxena (consider the following publications: HTML5 privilege separation (Dropbox), Finding and preventing script injection vulnerabilities).
Content focuses on exploring the attack surface across multiple OSI layers, examples of attacks on each, and more importantly, the defenses that can be deployed. Different threat models can be explored1).
Assumed knowledge:
We need to address not the perceived security risks (e.g. infant abduction vs infant mortality), but address the real security risks instead. Q: What security measure is worth deploying?
Other important information:
The internet consisting of autonomous systems (AS) which function like a cloud of routers, that can intercommunicate using the BGP protocol (seems like an internal routing table within routers, with inter-router communication over 179/tcp). This is related to the concept of gateways.
A good high-level overview of BGP. Some vulnerabilities:
There are mitigations, from Cloudflare advertises its nodes as a single ASN globally, then