This shows you the differences between two versions of the page.
isc:labs:03 [2023/10/23 14:39] david.gherghita |
isc:labs:03 [2025/01/23 12:36] (current) radu.mantu [03. [15p] Password Hashing] |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | /* ~~SHOWSOLUTION~~ */ | + | ===== Lab 03 - Authentication in Linux ===== |
- | + | ||
- | ====== Lab 03 - Hardware Security ====== | + | |
===== Objectives ===== | ===== Objectives ===== | ||
- | * Hardware Security Basics | + | |
- | * Side Channel Attacks | + | * Hashing |
- | * HSMs: Java Card & Simulator | + | * Linux PAM |
+ | * Multi-Factor Authentication | ||
===== Preparation ===== | ===== Preparation ===== | ||
- | You may use the UPB's [[https://cloud.grid.pub.ro|OpenStack cloud to instantiate a Virtual Machine]] to be used for this lab! | + | You may use the UPB's [[https://cloud.grid.pub.ro|OpenStack]] cloud to instantiate a Virtual Machine. |
- | [[:isc:info:virtualmachine|Read these instructions if you wanna know how!]]. | + | Read these [[:isc:info:virtualmachine|instructions]] if you wanna know how! |
===== Overview ===== | ===== Overview ===== | ||
- | ===== Basics ====== | + | Hashing is the process of converting data — text, numbers, files, or anything, really — into a fixed-length string of letters and numbers. Data is converted into these fixed-length strings, or hash values, by using a special algorithm called a hash function. |
- | For a long time, hardware had a central role in computer security. Take, for example, the CPU's protection rings model (on x86): they realize a privilege separation between a hypervisor / Operating System kernel and the user applications and is enforced at hardware-level for efficiency. | + | Linux Pluggable Authentication Modules (PAM) is a suite of libraries that allow a Linux system administrator to configure methods to authenticate users. |
- | Nowadays, the security requirements of certain applications has led to the implementation of additional access control or cryptographic functions directly into the hardware, e.g., AES-NI / SHA SSE-based instructions, the Trusted Platform Module cryptoprocessor, Smart Cards or Trusted Execution Environments (ARM TrustZone, Intel SGX, memory encryption etc.). | + | "pam_exec" is a PAM module that can be used to run an external command. |
- | On a different note, hardware is also susceptible to security bugs: side channel attacks, cryptographic vulnerabilities (e.g., cache or timing attacks or the much recent Spectre / Meltdown speculative execution bugs), hardcoded credentials or even manufacturer-introduced backdoors. | + | Multi-factor authentication (MFA) is a multi-step account login process that requires users to enter more information than just a password. For example, along with the password, users might be asked to enter a code sent to their email, answer a secret question, or scan a fingerprint. A second form of authentication can help prevent unauthorized account access if a system password has been compromised. |
- | These are very difficult (or even impossible) to fix without re-designing the chip and replacing the faulty products. | + | |
- | ===== Side Channel Attacks ====== | + | ===== Tasks ===== |
- | A side-channel attack is a type of cyber-attack that targets the unintended //side effects// of a software application / hardware component in a computer system, rather than attacking it directly. These side effects may include signals or data that are generated by the system's physical components, such as its power consumption, electromagnetic emissions, or even sound. | + | In the current security lab, we'll explore the fundamentals of Linux authentication. |
- | By analyzing these side effects, an attacker can gain information about the system's operations, such as encryption keys or other sensitive data, without directly accessing the system. Side-channel attacks can be executed remotely or locally and are often used to target cryptographic systems that use secret keys. | + | We'll start by examining how the OS performs hashing. First, we'll crack it and then we'll replicate it using Python. |
- | ===== Java Smart Cards ====== | + | Then, we'll utilize the "pam_exec" module to set up a custom Python script for user authentication. By exploiting a weak password vulnerability, we will be able to perform a successful login. |
- | Java smart cards are small electronic devices that have an embedded microprocessor and memory, which can be programmed with Java Card technology to perform secure transactions and store sensitive information. Java Card technology is a subset of Java that has been designed specifically for smart card environments. | + | Finally, we'll enhance security measures by implementing Multi-Factor Authentication (MFA) with Google Authenticator. |
- | Java smart cards can be found in various forms, such as SIM cards in mobile phones, banking cards, e-passports, and employee ID cards. They can be purchased from smart card manufacturers or vendors, or provided by organizations to their customers or employees. | + | ==== 01. [5p] Setup ==== |
- | To program and manage Java smart cards, specialized software development kits and tools are needed, such as Java Card Development Kit (JCDK), Global Platform Card Specification, and Smart Card Integrated Development Environment (IDE). Developers can use these tools to create and test Java Card applets that run on the smart cards and perform various secure operations. | + | We use Docker: |
- | ===== Tasks ==== | + | <code bash> |
- | ==== [40p] 1. Python timing side channel attack ==== | + | docker pull ghcr.io/cs-pub-ro/isc-auth-pam:latest |
- | + | mkdir ~/auth-lab | |
- | Download the {{isc:labs:lab03-sidechannel.zip|side channel demo}} archive here. | + | docker run --rm --name auth-lab -v $(pwd)/auth-lab/:/home/hacker/auth-lab -it ghcr.io/cs-pub-ro/isc-auth-pam |
- | + | </code> | |
- | Implement the TODOs and crack the password via a timing attack ;) | + | |
<note> | <note> | ||
- | Hint: you have LunarVim installed on the VM, use ''lvim ${file}'' to start it! | + | The ''~/auth-lab'' folder is used as persistent volume so you won't lose + sync your work inside the container! |
</note> | </note> | ||
+ | |||
+ | Download the {{:isc:labs:lab03-pam.zip|lab archive}} inside the ''~/auth-lab'' directory and unzip it. | ||
+ | |||
+ | Analyse the users and groups on the system. What user are we interested in? | ||
<solution -hidden> | <solution -hidden> | ||
- | {{isc:labs:lab-3-sidechannel-solved.zip|Solved attack.py here}}. | + | <code> |
+ | |||
+ | User "dani.mocanu", member of group "top_10_manelisti". | ||
+ | |||
+ | </code> | ||
</solution> | </solution> | ||
- | ==== [60p] 2. Java Card Simulator ==== | ||
- | {{ :isc:labs:lab03.png?direct&600 |}} | + | ==== 02. [15p] Password Cracking ==== |
+ | Use John the Ripper to crack our user's password. You need to run it as super user on the file that contains the passwords. | ||
- | In order to simulate a Java Card, we must install all required Java components (Oracle JavaCard SDKs, jCardSim, IsoApplet, VSmartCard). | + | We want to use the default mode "wordlist" with the default location ''/usr/share/john/password.lst''. |
- | **Note**: you don't need to do this on the ISC VM 2023.1 (has already been setup)! | + | If you are getting an error "No password hashes loaded (see FAQ)", you need to specify the format of the hash. It is named the same as the Linux password hashing function ;) |
+ | |||
+ | **References:** | ||
+ | * https://www.openwall.com/john/doc/OPTIONS.shtml | ||
+ | |||
+ | <solution -hidden> | ||
+ | <code> | ||
+ | |||
+ | $ sudo john /etc/shadow --format=crypt | ||
+ | dani.mocanu:snoopdog | ||
- | <spoiler> | ||
- | * Download the [[https://github.com/martinpaljak/oracle_javacard_sdks|Oracle JavaCard SDKs]]: | ||
- | <code bash> | ||
- | git clone https://github.com/martinpaljak/oracle_javacard_sdks.git "$HOME/oracle_javacard_sdks" | ||
- | export JC_HOME="$HOME/oracle_javacard_sdks/jc222_kit" | ||
- | export JC_CLASSIC_HOME="$HOME/oracle_javacard_sdks/jc305u3_kit" | ||
</code> | </code> | ||
- | * Since we don't have a physical smart card, we need a simulator: download & install [[https://github.com/arekinath/jcardsim|JCardSim]]: | + | </solution> |
- | <code bash> | + | |
- | git clone https://github.com/arekinath/jcardsim.git "$HOME/jcardsim" | + | ==== 03. [15p] Password Hashing ==== |
- | cd "$HOME/jcardsim"; mvn initialize && mvn clean install | + | |
- | </code> | + | Fill in the TODOs in ''gen_hash.py'' to generate a new password hash. Using your super user privileges, manually overwrite the old password of our user. |
- | * We now need an applet to install on our (emulated) Smart Card. [[https://github.com/philipWendland/IsoApplet|IsoApplet]] is an open source applet implementing Public Key cryptography operations (with OpenSC integration): | + | |
- | <code bash> | + | Test if you were successful by trying to log in (''su'') using the new password. |
- | git clone -b main-javacard-v2.2.2 https://github.com/philipWendland/IsoApplet.git "$HOME/IsoApplet" | + | |
- | cd "$HOME/IsoApplet" | + | <note warning> |
- | # install dependencies (fortunately, this project uses git submodules) | + | **crypt** was deprecated in PEP 594. See [[https://docs.python.org/3/library/crypt.html|this]] for alternatives. **legacycrypt** works.</note> |
- | git submodule init && git submodule update | + | |
- | # unfortunately, jCardSim cannot simulate CAPs (compiled applet firmwares)... | + | <solution -hidden> |
- | # so we directly compile the Java files (make sure to have the card simulator's SDK in Java Path): | + | <code> |
- | javac -classpath "$HOME/jcardsim/target/jcardsim-3.0.5-SNAPSHOT.jar" "$HOME/IsoApplet/src/xyz/wendland/javacard/pki/isoapplet/"*.java | + | |
- | </code> | + | TODO(1): |
- | * Finally, note that we need a Card Reader to interface with the smart cards. So, with our simulated card, we will have to use a virtual card reader software (''vpcd'' from [[https://frankmorgner.github.io/vsmartcard/virtualsmartcard/README.html|vsmartcard]]): | + | password = 'parolanoua' |
- | <code bash> | + | |
- | git clone https://github.com/frankmorgner/vsmartcard.git "$HOME/vsmartcard" | + | TODO(2): |
- | cd "$HOME/vsmartcard/virtualsmartcard" | + | salt = crypt.mksalt(crypt.METHOD_SHA512) |
- | autoreconf -vis && ./configure && sudo make install | + | |
- | # Restart PCSC daemon to load our new vcard driver | + | TODO(3): |
- | sudo systemctl restart pcscd | + | hash = crypt.crypt(password, salt) |
- | cd ~ # go back to home | + | |
</code> | </code> | ||
+ | </solution> | ||
- | Finally, we must create a configuration file for ''jcardsim''': | + | ==== 04. [5p] Account Locking ==== |
+ | As we want to use a Python script to log in to the user account we worked on so far, you need to delete and lock its password so that password-based authentication is disabled for this user account. | ||
+ | |||
+ | **Reference:** | ||
+ | * https://linux.die.net/man/1/passwd | ||
+ | |||
+ | <solution -hidden> | ||
<code> | <code> | ||
- | $ cat $HOME/jcardsim.cfg # <-- yes, create this file ! | + | |
- | com.licel.jcardsim.card.applet.0.AID=F276A288BCFBA69D34F31001 | + | sudo passwd -dl dani.mocanu |
- | com.licel.jcardsim.card.applet.0.Class=xyz.wendland.javacard.pki.isoapplet.IsoApplet | + | |
- | com.licel.jcardsim.card.ATR=3B80800101 | + | |
- | com.licel.jcardsim.vsmartcard.host=localhost | + | |
- | com.licel.jcardsim.vsmartcard.port=35963 | + | |
</code> | </code> | ||
- | </spoiler> | + | </solution> |
- | <html><br></html> | + | |
- | **[Re]Start the PCSC service:** | + | ==== 05. [10p] Linux PAM ==== |
- | <code bash> | + | |
- | # the VM does not automatically start this, so do it manually | + | We wish to write our own authentication module in Python. |
- | sudo systemctl restart pcscd | + | |
+ | For this, we must modify the ''common-auth'' Linux PAM configuration file (look in ''/etc/pam.d'') and add this as the **first** rule: <code> | ||
+ | auth sufficient pam_exec.so expose_authtok stdout quiet <path-to-auth.py> | ||
</code> | </code> | ||
- | **Start the simulator:** | + | As we want to use the script to authenticate only our special user, and because it will be called for all users, it should be //sufficient// to authenticate using it, but not //required//. |
+ | |||
+ | In order for authentication to be successfully performed using Python, we need 3 features, which can be achieved by passing the proper options to the ''pam_exec.so'' module: | ||
+ | * perform reads in the Python script, | ||
+ | * perform prints from the Python script, | ||
+ | * do not print anything else. | ||
+ | |||
+ | <note tip> | ||
+ | If you need to debug your //auth.py// script, delete the ''quiet'' parameter from the PAM config. Now, your stdout and stderr are no longer suppressed. | ||
+ | |||
+ | ---- | ||
+ | |||
+ | The PAM module may return different error codes depending on the nature of the error. Use the **errno** tool to check their meaning. | ||
<code bash> | <code bash> | ||
- | java -classpath "$HOME/jcardsim/target/jcardsim-3.0.5-SNAPSHOT.jar:$HOME/IsoApplet/src" com.licel.jcardsim.remote.VSmartCard "$HOME/jcardsim.cfg" | + | $ apt install errno |
+ | $ errno 13 | ||
+ | EACCES 13 Permission denied | ||
</code> | </code> | ||
+ | |||
+ | ---- | ||
+ | |||
+ | Remember that ''^?'' sequences (where ''?'' certain upper-case letters) represents a control character. If you get an error that contains such a sequence, take a look at the hexdump. | ||
+ | </note> | ||
+ | |||
+ | **References:** | ||
+ | * https://linux.die.net/man/5/pam.d | ||
+ | * https://man7.org/linux/man-pages/man8/pam_exec.8.html | ||
+ | |||
+ | <solution -hidden> | ||
+ | <code> | ||
+ | $ cat /etc/pam.d/common-auth | ||
+ | ... | ||
+ | # here are the local modules | ||
+ | auth sufficient pam_exec.so expose_authtok stdout quiet /home/hacker/auth-lab/auth.py | ||
+ | ... | ||
+ | </code> | ||
+ | </solution> | ||
+ | |||
+ | ==== 06. [20p] Python Script ==== | ||
+ | |||
+ | Edit ''auth.py'' and fill in TODOs(6.*). | ||
+ | |||
+ | When you're done, [[http://crackstation.net|crack the new password hash]] and try to log in ;) | ||
+ | |||
<note hint> | <note hint> | ||
- | Hint: use separate terminals or ''tmux'', since the command is blocking ;) | + | Note that the password hash is hardcoded in Python (you will also find the algorithm by cracking it!) without any salt. |
+ | Once you figure it out, use Python's ''hashlib'' to compute the input's ''user_hash'' and compare them! | ||
</note> | </note> | ||
- | **Loading the Smart Card applet:** | + | <solution -hidden> |
+ | <code> | ||
+ | TODO(6.1): | ||
+ | if "top_10_manelisti" not in user_groups: | ||
+ | return False | ||
+ | |||
+ | TODO(6.2): | ||
+ | hash_object = hashlib.sha256() | ||
+ | hash_object.update(user_password.encode("utf-8")) | ||
+ | user_hash = hash_object.hexdigest() | ||
+ | |||
+ | 13412ffd6149204f40e546ffa9fbd7124b410198a6ba3924f788622b929c8eb2 ---crackstation.net---> poochiedontsurf | ||
+ | </code> | ||
+ | </solution> | ||
+ | |||
+ | ==== 07. [30p] Multi-Factor Authentication ==== | ||
+ | |||
+ | Finally, let's add two-factor authentication to our script! | ||
+ | |||
+ | Edit ''setup_mfa.py'', input a 32-byte secret and print its QR enrollment code to the console. | ||
+ | After this, run the script and enroll the key inside a [[https://www.rfc-editor.org/rfc/rfc6238|RFC 6238 (TOTP)]] compatible (e.g.: Google Authenticator, TOTP Authenticator, KeePassXC etc.). | ||
+ | |||
+ | Solve the remaining TODOs(7.*) in ''auth.py'' to integrate your MFA (note: the TOTP's secret key should be the same!). | ||
<note> | <note> | ||
- | The APDU [[https://en.wikipedia.org/wiki/Smart_card_application_protocol_data_unit|Smart Card Application Protocol Data Unit]] is a communication protocol used for interfacing with smart cards, standardized in ISO/IEC 7816-4. | + | **Hint / workaround:** PAM only gives you one ''input()'' with the user-typed password (then closes stdin, any following reads will get EOF). |
+ | So, in order to read both a password and a numeric TOTP code, you must read them all at once (use whatever convention you desire, e.g.: password then 6-digit code either concatenated or split by space, then parse/extract it in Python). | ||
- | We use an [[https://jcardsim.org/docs/quick-start-guide-using-in-cli-mode|initial APDU script]] to install & execute the IsoApplet into the emulated smart card. | + | Custom ''.so'' PAM plugins have no such limitations (but you must then write them in a system programming language). |
</note> | </note> | ||
- | <code bash> | + | <note important>If you're getting an error (e.g., invalid padding) while scanning QR / verifying the TOTP, make sure ''TOTP_SECRET'' is 32 bytes in length!</note> |
- | # install IsoApplet usign a APDU script | + | |
- | opensc-tool --card-driver default --send-apdu 80b800001a0cf276a288bcfba69d34f310010cf276a288bcfba69d34f3100100 | + | |
- | opensc-tool -n | + | |
- | # create PKCS#15 structure on our smart card (also set a PIN and a PUK, for security purposes) | + | **References:** |
- | pkcs15-init --create-pkcs15 --so-pin 123456 --so-puk 0123456789abcdef | + | * https://pyauth.github.io/pyotp/#module-pyotp |
- | # generate an RSA key pair to use for signing (note: auth-id is a PIN slot) | + | * https://pyqrcode.readthedocs.io |
- | pkcs15-init --generate-key rsa/2048 --id 1 --key-usage decrypt,sign --label MyRSAKey --auth-id FF --pin 123456 | + | |
- | # download the generated public key to your machine | + | |
- | pkcs15-tool --read-public-key "1" --output "smartcard-pubkey.pem" | + | |
- | echo "Sunt de acord să cedez toată averea mea asistenților de ISC. Adevăraaat\!" > textToSign.txt | + | <solution -hidden> |
- | openssl dgst -engine pkcs11 -sign "pkcs11:object=MyRSAKey;type=private;pin-value=123456" -keyform ENGINE -sha256 -out textSignature.sig textToSign.txt | + | <code> |
- | # now everyone can check whether the document is correctly signed using the public key: | + | setup_mfa.py: |
- | openssl dgst -sha256 -verify smartcard-pubkey.pem -keyform PEM -signature textSignature.sig textToSign.txt | + | |
- | # modificați fișierul textToSign.txt și re-verificați semnătura digitală... ce se întâmplă? | + | |
- | </code> | + | |
- | Finally, here's one last challenge: use ''openssl'' to encrypt / decrypt a file using this key! | + | TODO(1): |
+ | TOTP_SECRET = "NeverGonnaGiveYouUpNeverGonnaLet" | ||
+ | |||
+ | TODO(2): | ||
+ | qr_code = pyqrcode.create(totp_auth) | ||
+ | print(qr_code.terminal(quiet_zone=1)) | ||
+ | |||
+ | auth.py: | ||
+ | |||
+ | TODO(7.1): | ||
+ | TOTP_SECRET = "NeverGonnaGiveYouUpNeverGonnaLet" | ||
+ | |||
+ | TODO(7.2): | ||
+ | user_password = user_secret[:-6] | ||
+ | user_totp = user_secret[-6:] | ||
+ | |||
+ | TODO(7.3): | ||
+ | totp = pyotp.TOTP(TOTP_SECRET) | ||
+ | totp_correct = totp.verify(user_totp) | ||
- | <solution -hidden> | ||
- | <code bash> | ||
- | openssl pkeyutl -encrypt -in textToSign.txt -pubin -inkey smartcard-pubkey.pem -out encrypted.enc | ||
- | openssl pkeyutl -decrypt -in encrypted.enc -engine pkcs11 -keyform ENGINE -inkey "pkcs11:object=MyRSAKey;type=private;pin-value=123456" -out decrypted.txt | ||
</code> | </code> | ||
</solution> | </solution> | ||
- | Bonus: [[https://access.redhat.com/articles/1523343|You can configure OpenSSH to use a private key stored inside a smart card for authentication]]! | + | ===== Feedback ===== |
- | + | ||
- | ==== 3. Feedback ==== | + | |
- | Please take a minute to fill in the [[https://forms.gle/5Lu1mFa63zptk2ox9|feedback form]] for this lab. | + | Please take a minute to fill in the [[https://docs.google.com/forms/d/e/1FAIpQLSeMrKoWY6UKe1N_BASUARA-HixTuvSfrEnx_FKstT-RW464NQ/viewform |feedback form]] for this lab. |