Learning Objectives
Upon completing this room, you will learn the following:
- Cryptography key terms
- Importance of cryptography
- Caesar Cipher
- Standard symmetric ciphers
- Common asymmetric ciphers
- Basic mathematics commonly used in cryptography
Cryptography’s ultimate purpose is to ensure secure communication in the presence of adversaries. The term secure includes confidentiality and integrity of the communicated data. Cryptography can be defined as the practice and study of techniques for secure communication and data protection where we expect the presence of adversaries and third parties. In other words, these adversaries should not be able to disclose or alter the contents of the messages.
Cryptography is used to protect confidentiality, integrity, and authenticity. In this age, you use cryptography daily, and you’re almost certainly reading this over an encrypted connection. Consider the following scenarios where you would use cryptography:
- When you log in to TryHackMe, your credentials are encrypted and sent to the server so that no one can retrieve them by snooping on your connection.
- When you connect over SSH, your SSH client and the server establish an encrypted tunnel so no one can eavesdrop on your session.
- When you conduct online banking, your browser checks the remote server’s certificate to confirm that you are communicating with your bank’s server and not an attacker’s.
- When you download a file, how do you check if it was downloaded correctly? Cryptography provides a solution through hash functions to confirm that your file is identical to the original one.
As you can see, you rarely have to interact directly with cryptography, but its solutions and implications are everywhere in the digital world. Consider the case where a company wants to handle credit card information and process related transactions. When handling credit cards, the company must follow and enforce the Payment Card Industry Data Security Standard (PCI DSS). In this case, the PCI DSS ensures a minimum level of security to store, process, and transmit data related to card credits. If you check the PCI DSS for Large Organizations, you will learn that the data should be encrypted both while being stored (at rest) and while being transmitted (in motion).
In the same way that handling payment card details requires complying with PCI DSS, handling medical records requires complying with their respective standards. Unlike credit cards, the standards for handling medical records vary from one country to another. Example laws and regulations that should be considered when handling medical records include HIPAA (Health Insurance Portability and Accountability Act) and HITECH (Health Information Technology for Economic and Clinical Health) in the USA, GDPR (General Data Protection Regulation) in the EU, DPA (Data Protection Act) in the UK. Although the list is not exhaustive, it gives an idea about the legal requirements that healthcare providers should consider depending on their country. These laws and regulations show that cryptography is a necessity that should be present yet usually hidden from direct user access.
We have just introduced several new terms, and we need to learn them to understand any text about cryptography. The terms are listed below:
- Plaintext is the original, readable message or data before it’s encrypted. It can be a document, an image, a multimedia file, or any other binary data.
- Ciphertext is the scrambled, unreadable version of the message after encryption. Ideally, we cannot get any information about the original plaintext except its approximate size.
- Cipher is an algorithm or method to convert plaintext into ciphertext and back again. A cipher is usually developed by a mathematician.
- Key is a string of bits the cipher uses to encrypt or decrypt data. In general, the used cipher is public knowledge; however, the key must remain secret unless it is the public key in asymmetric encryption. We will visit asymmetric encryption in a later task.
- Encryption is the process of converting plaintext into ciphertext using a cipher and a key. Unlike the key, the choice of the cipher is disclosed.
- Decryption is the reverse process of encryption, converting ciphertext back into plaintext using a cipher and a key. Although the cipher would be public knowledge, recovering the plaintext without knowledge of the key should be impossible (infeasible).
The two main categories of encryption are symmetric and asymmetric.
Symmetric Encryption
Symmetric encryption, also known as symmetric cryptography, uses the same key to encrypt and decrypt the data, as shown in the figure below. Keeping the key secret is a must; it is also called private key cryptography. Furthermore, communicating the key to the intended parties can be challenging as it requires a secure communication channel. Maintaining the secrecy of the key can be a significant challenge, especially if there are many recipients. The problem becomes more severe in the presence of a powerful adversary; consider the threat of industrial espionage, for instance.
Consider the simple case where you created a password-protected document to share it with your colleague. You can easily email the encrypted document to your colleague, but most likely, you cannot email them the password. The reason is that anyone with access to their mailbox would access both the password-protected document and its password. Therefore, you need to think of a different way, i.e., channel, to share the password. Unless you think of a secure, accessible channel, one solution would be to meet in person and communicate the password to them.
Examples of symmetric encryption are DES (Data Encryption Standard), 3DES (Triple DES) and AES (Advanced Encryption Standard).
- DES was adopted as a standard in 1977 and uses a 56-bit key. With the advancement in computing power, in 1999, a DES key was successfully broken in less than 24 hours, motivating the shift to 3DES.
- 3DES is DES applied three times; consequently, the key size is 168 bits, though the effective security is 112 bits. 3DES was more of an ad-hoc solution when DES was no longer considered secure. 3DES was deprecated in 2019 and should be replaced by AES; however, it may still be found in some legacy systems.
- AES was adopted as a standard in 2001. Its key size can be 128, 192, or 256 bits.
There are many more symmetric encryption ciphers used in various applications; however, they have not been adopted as standards.
Asymmetric Encryption
Unlike symmetric encryption, which uses the same key for encryption and decryption, asymmetric encryption uses a pair of keys, one to encrypt and the other to decrypt, as shown in the illustration below. To protect confidentiality, asymmetric encryption or asymmetric cryptography encrypts the data using the public key; hence, it is also called public key cryptography.
Examples are RSA, Diffie-Hellman, and Elliptic Curve cryptography (ECC). The two keys involved in the process are referred to as a public key and a private key. Data encrypted with the public key can be decrypted with the private key. Your private key needs to be kept private, hence the name.
Asymmetric encryption tends to be slower, and many asymmetric encryption ciphers use larger keys than symmetric encryption. For example, RSA uses 2048-bit, 3072-bit, and 4096-bit keys; 2048-bit is the recommended minimum key size. Diffie-Hellman also has a recommended minimum key size of 2048 bits but uses 3072-bit and 4096-bit keys for enhanced security. On the other hand, ECC can achieve equivalent security with shorter keys. For example, with a 256-bit key, ECC provides a level of security comparable to a 3072-bit RSA key.
Asymmetric encryption is based on a particular group of mathematical problems that are easy to compute in one direction but extremely difficult to reverse. In this context, extremely difficult means practically infeasible. For example, we can rely on a mathematical problem that would take a very long time, for example, millions of years, to solve using today’s technology.
We will visit various asymmetric encryption ciphers in the next room. For now, the important thing to note is that asymmetric encryption provides you with a public key that you share with everyone and a private key that you keep guarded and secret.
Summary of New Terms
- Alice and Bob are fictional characters commonly used in cryptography examples to represent two parties trying to communicate securely. Symmetric encryption is a method in which the same key is used for both encryption and decryption. Consequently, this key must remain secure and never be disclosed to anyone except the intended party. Asymmetric encryption is a method that uses two different keys: a public key for encryption and a private key for decryption.
The building blocks of modern cryptography lie in mathematics. To demonstrate some basic algorithms, we will cover two mathematical operations that are used in various algorithms:
- XOR Operation
- Modulo Operation
XOR Operation
XOR, short for “exclusive OR”, is a logical operation in binary arithmetic that plays a crucial role in various computing and cryptographic applications. In binary, XOR compares two bits and returns 1 if the bits are different and 0 if they are the same, as shown in the truth table below. This operation is often represented by the symbol ⊕ or ^.
A | B | A ⊕ B |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
If this is the first time you work with a truth table, it is a table that shows all possible outcomes. The XOR truth table above states all four cases: 0 ⊕ 0 = 0, 0 ⊕ 1 = 1, 1 ⊕ 0 = 1, and 1 ⊕ 1 = 0.
Let’s consider an example where we want to apply XOR to the binary numbers 1010 and 1100. In this case, we perform the operation bit by bit: 1 ⊕ 1 = 0, 0 ⊕ 1 = 1, 1 ⊕ 0 = 1, and 0 ⊕ 0 = 0, resulting in 0110.
You may be wondering how XOR can play any role in cryptography. XOR has several interesting properties that make it useful in cryptography and error detection. One key property is that applying XOR to a value with itself results in 0, and applying XOR to any value with 0 leaves it unchanged. This means A ⊕ A = 0, and A ⊕ 0 = A for any binary value A. Additionally, XOR is commutative, i.e., A ⊕ B = B ⊕ A. And it is associative, i.e., (A ⊕ B) ⊕ C = A ⊕ (B ⊕ C).
Let’s see how we can make use of the above in cryptography. We will demonstrate how XOR can be used as a basic symmetric encryption algorithm. Consider the binary values P and K, where P is the plaintext, and K is the secret key. The ciphertext is C = P ⊕ K.
Now, if we know C and K, we can recover P. We start with C ⊕ K = (P ⊕ K) ⊕ K. But we know that (P ⊕ K) ⊕ K = P ⊕ (K ⊕ K) because XOR is associative. Furthermore, we know that K ⊕ K = 0; consequently, (P ⊕ K) ⊕ K = P ⊕ (K ⊕ K) = P ⊕ 0 = P. In other words, XOR served as a simple symmetric encryption algorithm. In practice, it is more complicated as we need a secret key as long as the plaintext.
Modulo Operation
Another mathematical operation we often encounter in cryptography is the modulo operator, commonly written as % or as m__o__d. The modulo operator, X%Y, is the remainder when X is divided by Y. In our daily life calculations, we focus more on the result of division than on the remainder. The remainder plays a significant role in cryptography.
You need to work with large numbers when solving some cryptography exercises. If your calculator fails, we suggest using a programming language such as Python. Python has a built-in int
type that can handle integers of arbitrary size and would automatically switch to larger types as needed. Many other programming languages have dedicated libraries for big integers. If you prefer to do your math online, consider WolframAlpha.
Let’s consider a few examples.
- 25%5 = 0 because 25 divided by 5 is 5, with a remainder of 0, i.e., 25 = 5 × 5 + 0
- 23%6 = 5 because 25 divided by 6 is 3, with a remainder of 5, i.e., 23 = 3 × 6 + 5
- 23%7 = 2 because 23 divided by 7 is 3 with a remainder of 2, i.e., 23 = 3 × 7 + 2
An important thing to remember about modulo is that it’s not reversible. If we are given the equation x%5 = 4, infinite values of x would satisfy this equation.
The modulo operation always returns a non-negative result less than the divisor. This means that for any integer a and positive integer n, the result of a%n will always be in the range 0 to n − 1.
Let’s break down the information simply:
-
XOR Operation: XOR compares each bit of two numbers. If the bits are different, the result is 1; if the bits are the same, the result is 0. For example, for binary numbers 101010101010 and 110011001100:
- Compare each bit:
- 1 ⊕ 1 = 0
- 0 ⊕ 1 = 1
- 1 ⊕ 0 = 1
- 0 ⊕ 0 = 0
- Result: 011001100110
XOR in Cryptography: XOR is used in encryption because it has a useful property: applying XOR with the same number twice cancels out the encryption. For example, if you encrypt with a key KKK, using P⊕K=CP \oplus K = CP⊕K=C, you can decrypt with C⊕K=PC \oplus K = PC⊕K=P.
- Compare each bit:
-
Modulo Operation: Modulo gives the remainder when one number is divided by another. For instance:
- 25%5=025 % 5 = 025%5=0
- 23%6=523 % 6 = 523%6=5
- 23%7=223 % 7 = 223%7=2
Key Concept: Modulo always returns a remainder that’s between 0 and one less than the divisor.
Now, for your questions:
- 1001⊕1010=00111001 \oplus 1010 = 00111001⊕1010=0011
- 118613842%9091=3565118613842 % 9091 = 3565118613842%9091=3565
- 60%12=060 % 12 = 060%12=0
Exchanging keys for symmetric encryption is a widespread use of asymmetric cryptography. Asymmetric encryption is relatively slow compared to symmetric encryption; therefore, we rely on asymmetric encryption to negotiate and agree on symmetric encryption ciphers and keys.
But the question is, how do you agree on a key with the server without transmitting the key for people snooping to see?
Analogy
Imagine you have a secret code for communicating and instructions for using the secret code. The question is how you can send these instructions to your friend without anyone else being able to read them. The answer is more straightforward than it seems; you could ask your friend for a lock. Only your friend has the key for this lock, and we’ll assume you have an indestructible box you can lock with it.
If you send the instructions in a locked box to your friend, they can unlock it once it reaches them and read the instructions. After that, you can communicate using the secret code without the risk of people snooping.
In this metaphor, the secret code represents a symmetric encryption cipher and key, the lock represents the server’s public key, and the key represents the server’s private key.
Analogy | Cryptographic System |
---|---|
Secret Code | Symmetric Encryption Cipher and Key |
Lock | Public Key |
Lock’s Key | Private Key |
Consequently, you would only need to use asymmetric cryptography once so that it won’t affect the speed, and then you can communicate privately using symmetric encryption.
The Real World
In reality, you need more cryptography to verify that the person you’re talking to is who they say they are. This is achieved using digital signatures and certificates, which we will visit later in this room.
RSA is a public-key encryption algorithm that enables secure data transmission over insecure channels. With an insecure channel, we expect adversaries to eavesdrop on it.
The Math That Makes RSA Secure
RSA is based on the mathematically difficult problem of factoring a large number. Multiplying two large prime numbers is a straightforward operation; however, finding the factors of a huge number takes much more computing power.
It’s simple to multiply two prime numbers together even on paper, say 113 × 127 = 14351. Even for larger prime numbers, it would still be a feasible job, even by hand. Consider the following numeric example:
- Prime number 1: 982451653031
- Prime number 2: 169743212279
- Their product: 982451653031 × 169743212279 = 166764499494295486767649
On the other hand, it’s pretty tricky to determine what two prime numbers multiply together to make 14351 and even more challenging to find the factors of 166764499494295486767649.
In real-world examples, the prime numbers would be much bigger than the ones in this example. A computer can easily factorise 166764499494295486767649; however, it cannot factorise a number with more than 600 digits. And you would agree that the multiplication of the two huge prime numbers, each around 300 digits, would be easier than the factorisation of their product.
Numerical Example
Let’s revisit encryption, decryption, and key usage in asymmetric encryption. The public key is known to all correspondents and is used for encryption, while the private key is protected and used for decryption, as shown in the figure below.
In the Cryptography Basics room, we explained the modulo operation and said it plays a significant role in cryptography. In the following simplified numerical example, we see the RSA algorithm in action:
- Bob chooses two prime numbers: p = 157 and q = 199. He calculates n = p × q = 31243.
- With ϕ(n) = n − p − q + 1 = 31243 − 157 − 199 + 1 = 30888, Bob selects e = 163 such that e is relatively prime to ϕ(n); moreover, he selects d = 379, where e × d = 1 mod ϕ(n), i.e., e × d = 163 × 379 = 61777 and 61777 mod 30888 = 1. The public key is (n,e), i.e., (31243,163) and the private key is $(n,d), i.e., (31243,379).
- Let’s say that the value they want to encrypt is x = 13, then Alice would calculate and send y = x__e mod n = 13163 mod 31243 = 16342.
- Bob will decrypt the received value by calculating x = y__d mod n = 16341379 mod 31243 = 13. This way, Bob recovers the value that Alice sent.
The proof that the above algorithm works can be found in modular arithmetic and is beyond the scope of this module. It is worth repeating that in this example, we picked a three-digit prime number, while in an actual application, p and q would be at least a 300-digit prime number each.
RSA in CTFs
The math behind RSA comes up relatively often in CTFs, requiring you to calculate variables or break some encryption based on them. Many good articles online explain RSA, and they will give you almost all of the information you need to complete the challenges. One good example of an RSA CTF challenge is the Breaking RSA room.
There are some excellent tools for defeating RSA challenges in CTFs. My favourite is RsaCtfTool, which has worked well for me. I’ve also had some success with rsatool.
You need to know the main variables for RSA in CTFs: p, q, m, n, e, d, and c. As per our numerical example:
- p and q are large prime numbers
- n is the product of p and q
- The public key is n and e
- The private key is n and d
- m is used to represent the original message, i.e., plaintext
- c represents the encrypted text, i.e., ciphertext
Crypto CTF challenges often present you with a set of these values, and you need to break the encryption and decrypt a message to retrieve the flag.
One of the challenges of using symmetric encryption is sharing the secret key. Let’s say you want to send a password-protected document to your business partner to discuss confidential business strategies. How would you share the password with them? It would be best if you had a secure channel to send the password, knowing that adversaries cannot read or alter it.
The Diffie-Hellman Key Exchange is a method used for two parties to securely establish a shared secret key over an insecure channel, like the internet, without the key ever being directly transmitted. This shared key can then be used to encrypt messages. Here’s a step-by-step breakdown of how it works and why it’s secure.
1. Basic Principles
The Diffie-Hellman algorithm relies on properties of modular arithmetic and the difficulty of the “Discrete Logarithm Problem,” which ensures that even if someone intercepts some values exchanged over the network, they cannot easily compute the shared secret.
2. The Setup: Publicly Agreed Values
Both parties agree on two public numbers:
- ppp: A large prime number, which is publicly known.
- ggg: A primitive root modulo ppp, also known as the “generator.” This is also a public number.
These values don’t need to be kept secret; they can be shared openly. The security comes from what each party does with these numbers privately.
3. Private Key Selection
Each party generates their own private key:
- Alice selects a random private number aaa.
- Bob selects a random private number bbb.
These private numbers are chosen randomly and kept secret. They form the basis of each party’s contribution to the shared key.
4. Calculation of Public Values
Each party then computes a “public value” to send to the other party using their private key:
- Alice’s public value AAA: A=gamod pA = g^a \mod pA=gamodp
- Bob’s public value BBB: B=gbmod pB = g^b \mod pB=gbmodp
The calculations use the generator ggg raised to the power of the party’s private number and then taken modulo ppp. Each party sends their public value to the other.
5. Exchange of Public Values
- Alice sends her public value AAA to Bob.
- Bob sends his public value BBB to Alice.
Since AAA and BBB are computed using the modular exponentiation of large numbers, intercepting these values does not provide the private keys aaa or bbb. The calculation needed to derive the private key from AAA or BBB is extremely difficult due to the Discrete Logarithm Problem.
6. Calculation of the Shared Secret
Now, both parties can independently calculate the shared secret key. This is done using the other party’s public value and their own private key:
- Alice’s calculation of the shared key: key=Bamod p\text{key} = B^a \mod pkey=Bamodp
- Bob’s calculation of the shared key: key=Abmod p\text{key} = A^b \mod pkey=Abmodp
Even though they calculate it differently, they arrive at the same result:
key=(gb)amod p=(ga)bmod p\text{key} = (g^b)^a \mod p = (g^a)^b \mod pkey=(gb)amodp=(ga)bmodp
This key is now shared and can be used for encryption between Alice and Bob. The reason they get the same result is because of the mathematical property that (gb)amod p=(ga)bmod p(g^b)^a \mod p = (g^a)^b \mod p(gb)amodp=(ga)bmodp.
7. Why It’s Secure
- Eavesdroppers: If a third party (often called Eve) intercepts the public values AAA and BBB, she would need to solve the Discrete Logarithm Problem to determine aaa or bbb, which is computationally infeasible with large numbers.
- Key Agreement without Key Transmission: The actual shared secret key is never transmitted over the network. Each party calculates it independently based on their private key and the other party’s public value.
Example Walkthrough
To illustrate, let’s assume smaller numbers for simplicity, though in real applications, large numbers (hundreds or thousands of bits) are used.
-
Public Values:
- Let’s say p=23p = 23p=23 and g=5g = 5g=5.
-
Private Keys:
- Alice selects a=6a = 6a=6.
- Bob selects b=15b = 15b=15.
-
Public Values Computation:
- Alice computes A=gamod p=56mod 23=8A = g^a \mod p = 5^6 \mod 23 = 8A=gamodp=56mod23=8.
- Bob computes B=gbmod p=515mod 23=19B = g^b \mod p = 5^{15} \mod 23 = 19B=gbmodp=515mod23=19.
-
Exchange Public Values:
- Alice sends A=8A = 8A=8 to Bob.
- Bob sends B=19B = 19B=19 to Alice.
-
Shared Secret Calculation:
- Alice computes key=Bamod p=196mod 23=2\text{key} = B^a \mod p = 19^6 \mod 23 = 2key=Bamodp=196mod23=2.
- Bob computes key=Abmod p=815mod 23=2\text{key} = A^b \mod p = 8^{15} \mod 23 = 2key=Abmodp=815mod23=2.
Both Alice and Bob independently arrive at the same shared key, 2, without having exchanged the private keys directly.
Real-World Use and Limitations
Diffie-Hellman is often used in combination with other cryptographic protocols like RSA to establish secure connections. However, it is vulnerable to “man-in-the-middle” attacks if the public keys are intercepted and replaced. To prevent this, Diffie-Hellman is typically used with authentication methods, such as digital signatures (e.g., RSA), to confirm the identities of the participants.
Authenticating the Server
If you have used an SSH client before, you would know the confirmation prompt in the terminal output below.
Terminal
root@TryHackMe# ssh 10.10.244.173
The authenticity of host '10.10.244.173 (10.10.244.173)' can't be established.
ED25519 key fingerprint is SHA256:lLzhZc7YzRBDchm02qTX0qsLqeeiTCJg5ipOT0E/YM8.
This key is not known by any other name.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added '10.10.244.173' (ED25519) to the list of known hosts.
In the above interaction, the SSH client confirms whether we recognise the server’s public key fingerprint. ED25519 is the public-key algorithm used for digital signature generation and verification in this example. Our SSH client didn’t recognise this key and is asking us to confirm whether we want to continue with the connection. This warning is because a man-in-the-middle attack is probable; a malicious server might have intercepted the connection and replied, pretending to be the target server.
In this case, the user must authenticate the server, i.e., confirm the server’s identity by checking the public key signature. Once you answer with “yes”, the SSH client will record this public key signature for this host. In the future, it will connect you silently unless this host replies with a different public key.
Authenticating the Client
Now that we have confirmed that we are talking with the correct server, we need to identify ourselves and get authenticated. In many cases, SSH users are authenticated using usernames and passwords like you would log in to a physical machine. However, considering the inherent issues with passwords, this does not fall within the best security practices.
At some point, one will surely hit a machine with SSH configured with key authentication instead. This authentication uses public and private keys to prove the client is a valid and authorised user on the server. By default, SSH keys are RSA keys. You can choose which algorithm to generate and add a passphrase to encrypt the SSH key.
ssh-keygen
is the program usually used to generate key pairs. It supports various algorithms, as shown on its manual page below.
Terminal
root@TryHackMe# man ssh-keygen
[...]
-t dsa | ecdsa | ecdsa-sk | ed25519 | ed25519-sk | rsa
Specifies the type of key to create. The possible values are “dsa”, “ecdsa”, “ecdsa-sk”, “ed25519”, “ed25519-sk”, or “rsa”.
[...]
The following is just for your information. At this stage, we recommend that you recognise their names only.
- DSA (Digital Signature Algorithm) is a public-key cryptography algorithm specifically designed for digital signatures.
- ECDSA (Elliptic Curve Digital Signature Algorithm) is a variant of DSA that uses elliptic curve cryptography to provide smaller key sizes for equivalent security.
- ECDSA-SK (ECDSA with Security Key) is an extension of ECDSA. It incorporates hardware-based security keys for enhanced private key protection.
- Ed25519 is a public-key signature system using EdDSA (Edwards-curve Digital Signature Algorithm) with Curve25519.
- Ed25519-SK (Ed25519 with Security Key) is a variant of Ed25519. Similar to ECDSA-SK, it uses a hardware-based security key for improved private key protection.
Let’s generate a key pair with the default options.
Terminal
root@TryHackMe# ssh-keygen -t ed25519
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/strategos/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/strategos/.ssh/id_ed25519
Your public key has been saved in /home/strategos/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:4S4DQvRfp52UuNwg++nTcWlnITEJTbMcCU0N8UYC1do strategos@g5000
The key's random art image is:
+--[ED25519 256]--+
| . +XXB. |
| . . . oBBo |
| . . . = + o=o |
| . . * X .o.E |
| . . o S + o . |
| . . o .. + o |
| o +. + o |
| +. . |
| .. |
+----[SHA256]-----+
In the above example, we didn’t use a passphrase to show you the content of the private key. Let’s look at the generated public key, id_ed25519.pub
, and the generated private key, id_ed25519
.
Terminal
strategos@g5000:~/.ssh$ cat id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINqNMqNhpXZGt6T8Q8bOplyTeldfWq3T3RyNJTmTMJq9 strategos@g5000
strategos@g5000:~/.ssh$ cat id_ed25519
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACDajTKjYaV2Rrek/EPGzqZck3pXX1qt090cjSU5kzCavQAAAJA+E+ajPhPm
owAAAAtzc2gtZWQyNTUxOQAAACDajTKjYaV2Rrek/EPGzqZck3pXX1qt090cjSU5kzCavQ
AAAEB981T2ngdoNm8gEzRU35bGHofqRMjfo5egxl0/9fap/NqNMqNhpXZGt6T8Q8bOplyT
eldfWq3T3RyNJTmTMJq9AAAACm9xYWJAZzUwMDABAgM=
-----END OPENSSH PRIVATE KEY-----
Note that the private key is shared above for demonstration purposes and was purged afterwards. Sharing a private key would be the most insecure act anyone can commit against their security. On another note, had we used -t rsa
, the resulting keys would have been much longer.
SSH Private Keys
As just mentioned, you should treat your private SSH keys like passwords. Never share them under any circumstances; they’re called private keys for a reason. Someone with your private key can log in to servers that accept it, i.e., include it among the authorised keys, unless the key is encrypted with a passphrase.
It’s very important to mention that the passphrase used to decrypt the private key doesn’t identify you to the server at all; it only decrypts the SSH private key. The passphrase is never transmitted and never leaves your system.
Using tools like John the Ripper, you can attack an encrypted SSH key to attempt to find the passphrase, highlighting the importance of using a complex passphrase and keeping your private key private.
When generating an SSH key to log in to a remote machine, you should generate the keys on your machine and then copy the public key over, as this means the private key never exists on the target machine using ssh-copy-id
. However, this doesn’t matter as much for temporary keys generated to access CTF boxes.
The permissions must be set up correctly to use a private SSH key; otherwise, your SSH client will ignore the file with a warning. Only the owner should be able to read or write to the private key (600
or stricter). ssh -i privateKeyFileName user@host
is how you specify a key for the standard Linux OpenSSH client.
Keys Trusted by the Remote Host
The ~/.ssh
folder is the default place to store these keys for OpenSSH. The authorized_keys
(note the US English spelling) file in this directory holds public keys that are allowed access to the server if key authentication is enabled. By default on many Linux distributions, key authentication is enabled as it is more secure than using a password to authenticate. Only key authentication should be accepted if you want to allow SSH access for the root user.
Using SSH Keys to Get a “Better Shell”
During CTFs, penetration testing, and red teaming exercises, SSH keys are an excellent way to “upgrade” a reverse shell, assuming the user has login enabled. Note that www-data usually does not allow this, but regular users and root will work. Leaving an SSH key in the authorized_keys
file on a machine can be a useful backdoor, and you don’t need to deal with any of the issues of unstabilised reverse shells like Control-C or lack of tab completion.
Integrity Checking
Hashing can be used to check that files haven’t been changed. If you put the same data in, you always get the same data out. Even if a single bit changes, the hash will change significantly, as demonstrated in Task 2. This means you can use it to check that files haven’t been modified or to ensure that the file you downloaded is identical to the file on the web server. The text file listed below shows the SHA256 hash of two Fedora Workstation ISO files. If running sha256sum
on the file you downloaded returned the same hash listed in this signed file, you can be confident that your file is identical to the official one.
AttackBox Terminal
root@AttackBox# head Fedora-Workstation-40-1.14-x86_64-CHECKSUM
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
# Fedora-Workstation-Live-osb-40-1.14.x86_64.iso: 2623733760 bytes
SHA256 (Fedora-Workstation-Live-osb-40-1.14.x86_64.iso) = 8d3cb4d99f27eb932064915bc9ad34a7529d5d073a390896152a8a899518573f
# Fedora-Workstation-Live-x86_64-40-1.14.iso: 2295853056 bytes
SHA256 (Fedora-Workstation-Live-x86_64-40-1.14.iso) = dd1faca950d1a8c3d169adf2df4c3644ebb62f8aac04c401f2393e521395d613
[...]
You can also use hashing to find duplicate files; if two documents have the same hash, they are the same document. This is very convenient for finding and deleting duplicate files.
HMACs
HMAC (Keyed-Hash Message Authentication Code) is a type of message authentication code (MAC) that uses a cryptographic hash function in combination with a secret key to verify the authenticity and integrity of data.
An HMAC can be used to ensure that the person who created the HMAC is who they say they are, i.e., authenticity is confirmed; moreover, it proves that the message hasn’t been modified or corrupted, i.e., integrity is maintained. This is achieved through the use of a secret key to prove authenticity and a hashing algorithm to produce a hash and prove integrity.
The following steps give you a fair idea of how HMAC works.
- The secret key is padded to the block size of the hash function.
- The padded key is XORed with a constant (usually a block of zeros or ones).
- The message is hashed using the hash function with the XORed key.
- The result from Step 3 is then hashed again with the same hash function but using the padded key XORed with another constant.
- The final output is the HMAC value, typically a fixed-size string.
The illustration below should clarify the above steps.
Technically speaking, the HMAC function is calculated using the following expression:
H__M__A__C(K,M) = H((K_⊕_o__p__a__d)||H((K_⊕_i__p__a__d)||M))
Note that M and K represent the message and the key, respectively.