Week 14.b CS3650 04/10 2024 1. Access control (Unix) 2. Stack smashing --------------------------- Admin: - final exam: -- time: 04/24, 3:30 PM -- location: West Village F 020 1. Access control (Unix) The problem of access control: A subject accesses an object. Should OS allow or deny? subjects: users, processes, or any other actors objects: files, devices, or any other resources (different abstractions will give you different subjects/objects). There are two common approaches: --access control list (ACL) --capability-based Both are used in today's OSes. At a high level: ACL usually associates with objects. When an subject accesses an object, system checks if subject is in the obj's access list Capability usually associates with subjects. When an subject accesses an object, system checks if subject has the capability to access the obj. A. Intro Unix's access control * UIDs and GIDs UIDs are historically unsigned 16-bit integers (0-65535). UNIX keeps the mapping between usernames and UIDs in the file /etc/passwd. [try "$ cat /etc/passwd"] see your UID by: $ id and you can get your username by "$ whoami" special user: uid 0, called root, treated specially by the kernel as administrator uid 0 has all permissions: can read any file, do anything certain ops only root can do: --binding to ports less than 1024 --change current process's user or group ID --mount or unmount file systems --opening raw sockets (so you can do something like ping remote machines, for example) --set clock --halt or reboot machine --change UIDs (so login program needs to run as root) GIDs are also 16-bit integers. A group represents a group of users. [see all groups by "$ cat /etc/group"] * processes have a user ID and one or more group IDs when a process runs, it is associated with UID/GIDs [see them by "$ ps -l"] * files and directories are access-controlled. [see them by "$ ls -n"] you saw this in Lab4 (recall "mode" in inode) system stores with each file who owns it. where's the info stored? (answer: inode.) [draw figure of a Unix system with UIDs] [running processes] User (uid=1000) --> login (uid=0) | (check username/passwd) | +----> shell (uid=1000) | +--> vim (uid=1000) +--> gcc (uid=1000) +--> chrome (uid=1000) [fs] / (owner:uid=0) | +-->home (owner:uid=0) | +--> user (owner: uid=1000) | +-> ... note: devices are abstracted as files in Unix, so they are access-controlled in the same manner. Notice that login is authentication (our last topic). Questions: (a) why password has no echo on screen? (b) if failed, should the login tell users if the username or the password is incorrect? (c) if failed, should it takes longer to reject a wrong username? B. Setuid So far so good, are we done? Question: how can users update their password stored in "/etc/passwd"? Can a user "vim /etc/passwd" and modify? [answer: of course no! The file also contains other users' information.] --Some legitimate actions require more privs than UID --E.g., how should users change their passwords? --Passwords are stored in root-owned /etc/passwd and /etc/shadow files --going to go into a bit of detail. why? because setuid/setgid are the sole means on Unix to *raise* a process's privilege level --Solution: Setuid/setgid programs idea: a way for root -- or another user -- to delegate its ability to do something. --special "setuid" bit in the permissions of a file --Run with privileges of file's owner or group --Each process has _real_ and _effective_ UID/GID -- _real_ is user who launched setuid program -- _effective_ is owner/group of file, used in access checks --for setuid programs, on exec() of binary, kernel sets effective uid = file uid --Examples: --/usr/bin/passwd : change a user's passwd. User needs to be able to run this, but only root can modify the password file. --/bin/su: change to new user ID if correct password is typed. $ ls -l `which passwd` -rwsr-xr-x 1 root root 63736 Jul 27 2021 /usr/bin/passwd $ ls -l `which su` -rwsr-xr-x 1 root root 63568 Jan 10 2021 /usr/bin/su [note the 's' in "-rwsr-xr-x"] --Obviously need to own file to set the setuid bit --Need to own file and be in group to set setgid bit --Have to be EXTREMELY careful when writing setuid code --Here's an example for intuition Imagine you leave your terminal unattended, and some other user ("attacker") sits down and types: $ cp /bin/sh /tmp/break-acct $ chmod 4755 /tmp/break-acct the leading 4 sets the setuid bit. the 755 means "rwxr-xr-x" Question: what will happen if the attacker (or anyone else) later runs: $ /tmp/break-acct -p result: attacker now has a shell with your privileges and can do anything you can do (read your private files, remove them, overwrite them, etc.). in fact anyone on the system can run break-acct to get the same effect (since it's world-executable). More generally, imagine that you are writing a program on a shared system, you are the owner, and you set the setuid bit What you are doing is letting that program run with *your* privileges. --Of course that was an attack. Sometimes people intentionally install setuid-root binaries. When you do that, as a system administrator or packager, you have to be extremely careful. You're saying in essence that everyone on the system should be able to run the binary with root's privileges. --Fundamental reason you need to be careful: very difficult to anticipate exactly how and in what environment the code will be run....yet when it runs, it runs with *your* privileges (where "your" equals "root" or "whoever set the setuid bit on some code they wrote") --NOTE: Attackers can run setuid programs any time (no need to wait for root to run a vulnerable job) --FURTHER NOTE: Attacker controls many aspects of program's environment C. EXAMPLE ATTACKS that exploit setuid --running a program with setuid assumes that the functionality of the program is limited such that "no harm" can be done by an attacker. for example, "passwd" only changes the password of whoever calls this program... ...AND it authenticates users with old passwords. There are no other things that "passwd" can do. --So, if all programs have limited functions, what can go wrong? --Example: Close fd 2 before execing program -- passwd program (pseudocode): fd = open("/etc/passwd") ask user the old password check ask user the new password write(fd, new_password) --notice: setuid program opens the passwd file ("/etc/passwd") (normally, would be fd=3, but because fd 2 was closed, the file will be given fd 2). --attack: close fd 2 before execing program (recall fork-exec separation) --then, the program later encounters an error message and does fprintf(stderr, "some error msg"). --result: the error message goes into the password file! --fix: for setuid programs, kernel will open dummy fds for 0,1,2 if not already open Notes: --at a high level, the real issue is that the correct version of the code is way harder to write than the incorrect version: --correct version has to traverse path manually --be super-careful when running as setuid --cannot just blame application writers; must also blame the interfaces with which they're presented. --rules are incoherent. not clear how permissions compose 2. Stack smashing * stack frame & calling convention, revisited -- revisit the first handout -- recall what stack frame looks like -- recall how calling convention works * Stack smashing There are many ways to attack computers. Today we study the "classic" method: buffer overflow. ('buffer overflow' is one way to conduct a stack smashing attack.) Introduction to buffer overflow attacks This method has been adapted to many different types of attacks, but the concepts are similar. We study this attack not to teach you all to become hackers but rather to educate you about vulnerabilities: what they are, how they work, and how to defend against them. Please remember: _although the approaches used to break into computers are very interesting, breaking in to a computer that you do not own is, in most cases, a criminal act_. A. [demo] B. Let’s examine a vulnerable server, buggy−server.c [see handout] C. Let’s examine how an unscrupulous element (a hacker, a script kiddie, a worm, and so on) might exploit the server.