Outline Designing and Writing ‹General principles Secure Application Code • Least privilege, defense in depth, … ‹Example • vs qmail John Mitchell ‹Tools for • Type-safe programming languages • Purify • Perl tainting • Code analysis algorithms • Run-time monitoring (another lecture)

General topics in this course Before you start building …

‹Vulnerabilities ‹What are the security requirements? • How hackers break into systems • Confidentiality (secrets remain secret) – Circumvent security mechanisms (e.g., dictionary attack) • Integrity (meaning preserved) – Use code for purpose it was not intended () • Availability ‹Defensive programming • Accountability • Build all with security in mind This ‹What threats are possible? • Make sure video game is not a boot loader lecture ‹Who do you trust / not trust? ‹Security Mechanisms • Authentication • Access control Security = preserve properties against attack • Network protocols

General advice Compartmentalization

‹Compartmentalization ‹Divide system into modules • Principle of least privilege • Each module serves a specific purpose • Minimize trust relationships • Assign different access rights to different modules ‹Defense in depth – Read/write access to files • Use more than one security mechanism – Read user or network input • Secure the weakest link – Execute privileged instructions (e.g., Unix root) • Fail securely ‹Principle of least privilege ‹Keep it simple • Give each module only the rights it needs ‹Consult experts • Don’t build what you can easily borrow/steal • Open review is effective and informative

1 Compartmentalization (II) Example: .NET

‹Example class NativeMethods { • Sendmail runs as root // This is a call to unmanaged code. Executing this method requires – Root privilege needed to bind port 25 // the UnmanagedCode security permission. Without this permission, – No longer needed after port bind established // an attempt to call this method will throw a SecurityException: • But most systems keep running as root [DllImport("msvcrt.dll")] – Root privileges needed later to write to user mailboxes public static extern int puts(string str); • Will look at qmail for better security design [DllImport("msvcrt.dll")] ‹Minimize trust relationships internal static extern int _flushall(); • Clients, servers should not trust each other } – Both can get hacked • Trusted code should not call untrusted code

Code denies permission not needed Defense in Depth

[SecurityPermission(SecurityAction.Deny, Flags = ‹Failure is unavoidable – plan for it SecurityPermissionFlag.UnmanagedCode)] ‹Have a series of defenses private static void MethodToDoSomething() • If an error or attack is not caught by one { try mechanism, it should be caught by another { Console.WriteLine(“ … "); ‹Examples SomeOtherClass.method(); • Firewall + network intrusion detection } • SSH + Tripwire catch (SecurityException) ‹Fail securely { • Many, many vulnerabilities are related to error … handling, or testing features, error } messages }

Secure the weakest link Keep It Simple

‹Think about possible attacks ‹Use standard, tested components • How would someone try to attack this? • Don’t implement your own cryptography • What would they want to accomplish? ‹Don’t add unnecessary features ‹Find weakest link(s) • Extra functionality ⇒ more ways to attack • Crypto library is probably pretty good ‹Use simple algorithms that are easy to verify • Is there a way to work around crypto? • A trick that may save a few instructions may – Data stored in encrypted form; where is key stored? – Make it harder to get the code right ‹Main point – Make it harder to modify and maintain code • Do security analysis of the whole system • Spend your time where it matters

2 Promote Privacy Don’t reinvent the wheel

‹Discard information when no longer needed ‹Consult experts • No one can attack system to get information ‹Allow public review ‹Examples ‹Use software, designs that other have used • Don’t keep log of old session keys • Delete firewall logs • Don’t run unnecessary services (fingerd) ‹Examples ‹Hiding sensitive information is hard • Bad use of crypto: 802.11b • Information in compiled binaries can be found • Protocols without expert review: 802.11i • Insider attacks are common • Use standard url parser, crypto library, good • Security by obscurity doesn’t work!!! random number generater, …

Example: Mail Transport Agents Market share

‹Sendmail Year Sendmail Qmail • Complicated system • Source of many vulnerabilities 1996 80% ‹Qmail 1997 76% • Simpler system designed with security in mind 1998 63% • Gaining popularity 2000 55% 2001 47% 9% 2002 42% 17% Qmail was written by Dan Bernstein, starting 1995 $500 reward for successful attack; no one has collected

Simplified Mail Transactions Stanford Sendmail Vulnerability

Sent: Tuesday, March 04, 2003 1:12 PM Mail Mail To: [email protected] Mail User Mail User Transport Transport Agent Agent Subject: Stanford ITSS Security Alert: sendmail Header Agent Agent Processing Vulnerability

sendmail is the most popular Mail Transfer Agent (MTA) Mail Mail program in use on the Internet, … mbox Delivery Delivery mbox Agent Agent sendmail contains an error in one of the security checks it employs on addresses in its headers, which may allow an ‹ Message composed using an MUA attacker to execute malicious code within the sendmail security context, usually root… ‹ MUA gives message to MTA for delivery • If local, the MTA gives it to the local MDA All users of sendmail should patch immediately … • If remote, transfer to another MTA

3 Example: qmail Structure of qmail

‹Least privilege qmail-smtpd qmail-inject • Each module uses least privileges necessary • Only one setuid program qmail-queue – setuid to one of the other qmail user IDs, not root Incoming SMTP mail Other incoming mail – No setuid root binaries • Only one run as root qmail-send – Spawns the local delivery program under the UID and GID of the user being delivered to – No delivery to root qmail-rspawn qmail-lspawn – Always changes effective uid to recipient before running user-specified program ‹Other secure coding ideas qmail-remote qmail-local

Structure of qmail Structure of qmail

qmail-smtpd qmail-inject qmail-smtpd qmail-inject

qmail-queue qmail-queue ‹ Splits mail msg into 3 files ‹ qmail-send signals • Message contents • qmail-lspawn if local • 2 copies of header, etc. • qmail-remote if remote qmail-send qmail-send ‹ Signals qmail-send

qmail-rspawn qmail-lspawn qmail-rspawn qmail-lspawn

qmail-remote qmail-local qmail-remote qmail-local

Structure of qmail Structure of qmail

qmail-smtpd qmail-inject qmail-smtpd qmail-inject

qmail-queue qmail-queue

qmail-send qmail-send

qmail-lspawn qmail-lspawn ‹ qmail-lspawn ‹ qmail-local • Spawns qmail-local • Handles alias expansion • qmail-local runs with ID of • Delivers local mail user receiving local mail • Calls qmail-queue if needed qmail-local qmail-local

4 Structure of qmail Least privilege

qmail-smtpd qmail-inject qmail-smtpd qmail-inject

qmail-queue qmail-queue setuid

qmail-send qmail-send

qmail-rspawn qmail-rspawn qmail-lspawn root

‹ qmail-remote • Delivers message to remote MTA qmail-remote qmail-remote qmail-local

qmailq – user who is allowed to read/write mail queue UIDs Principles, sendmail vs qmail

qmaild user ‹Do as little as possible in setuid programs qmail-smtpd qmailq qmail-inject • Of 20 recent sendmail security holes, 11 worked qmail-queue only because the entire sendmail system is setuid setuid • Only qmail-queue is setuid – Its only function is add a new message to the queue qmail-send ‹Do as little as possible as root qmailr qmails root • The entire sendmail system runs as root qmail-rspawn qmail-lspawn root – protection has no effect • Only qmail-start and qmail-lspawn run as root. setuid user qmailr user qmail-remote qmail-local

Principles, sendmail vs qmail Keep it simple

‹Programs and files are not addresses ‹Parsing • sendmail treats programs and files as addresses • Limited parsing of strings – “sendmail goes through horrendous contortions trying to – Minimizes risk of security holes from configuration errors keep track of whether a local user was responsible for an address. This has proven to be an unmitigated disaster” ‹Libraries (DJB) • Avoid standard C library, stdio • qmail programs and files are not addresses – “Write bug-free code” (DJB) – “The local delivery agent, qmail-local, can run programs ‹Don’t repeat functionality or write to files as directed by ~user/.qmail, but it's always running as that user. Security impact: .qmail, like • One simple mechanism handles forwarding, .cshrc and .exrc and various other files, means that aliasing, and mailing lists (instead of 3) anyone who can write arbitrary files as a user can • Single delivery mode instead of a selection execute arbitrary programs as that user. That's it.” (DJB)

5 Comparison Additional general advice [Wheeler]

Program Component Lines Words Chars Files qmail-1.01 16028 44331 370123 288 • Avoid buffer overflow • Secure software design sendmail-8.8.8 52830 179608 1218116 53 Validate input Respond • Language-specific problems judiciously zmailer-2.2e10 57595 205524 1423624 227 • Application-specific issues smail-3.2 62331 246140 1701112 151 Call other code -1.90 67778 272084 2092351 127 carefully

See Wheeler’s book on web

Summary from [Wheeler] Additional reading

‹ Validate all your inputs ‹Contents • Command line inputs, environment variables, CGI inputs, … • Contemporary security • Don't just reject “bad” input, define “good” and reject all else – Need for secure systems, proactive security process ‹ Avoid buffer overflow • Secure Coding Techniques ‹ Structure your program security – The buffer overrun • Secure the interface, minimize privileges – Determining appropriate access control • Make the initial configuration and defaults safe – Running with least privilege • Avoid race conditions – Protecting secret data • Trust only trustworthy channels – All input is evil – Most servers must not trust clients for security checks – …. ‹ Carefully call out to other resources • More Secure Coding techniques • Check all system calls and return values • Special Topics – Testing, code review, secure installation, privacy

Tools for producing secure code Purify

‹C vs type safe languages ‹Goal • Buffer overflows are array bounds violations • Instrument a program to detect run-time memory • Java, ML, … check array bounds, prevent overflow errors (out-of-bounds, use-before-init) and memory leaks ‹Purify • Find memory errors on the heap ‹Technique • Works on relocatable object code ‹Perl tainting – Link to modified malloc that provides tracking tables • Track use of untrusted input • Memory access errors: insert instruction sequence ‹Automated code analysis tools before each load and store instruction • Can catch many kinds of errors • Memory leaks: GC algorithm

6 Perl tainting Safe Perl mail command (?)

‹Run-time checking of Perl code ‹Check email string against pattern and parse • Perl used for CGI scripts, security sensitive $email = $form_data{"email"}; • Taint checking stops some potentially unsafe calls if ( $email =~ /(\w{1}[\w-.]*)\@([\w-.]+)/) { ‹Tainted strings $email = "$1\@$2"; • User input, Values derived from user input } else { warn ("TAINTED DATA SENT BY …"); • Except result of matching against untainted string $email = ""; # successful match did not occur } ‹Prohibited calls ‹What does this accomplish? • print $form_data{"email"} . "\n"; • Only send email to address that “looks good” – OK since print is safe (???) • Programmer responsible for “good” pattern • system("mail " . $form_data{"email"}); • Perl cannot guarantee that email addr is OK – Flagged system call with user input as argument

Automated code analysis for C Checking secure software

‹Example tool ‹Many rules for writing secure code • Ken Ashcraft and Dawson Engler, Using • “sanitize user input before using it” Programmer-Written Compiler Extensions to Catch • “check permissions before doing operation X” Security Holes, IEEE Security and Privacy 2002 ‹How to find errors? • Used modified compiler to find over 100 security • Formal verification holes in and BSD + rigorous • http://www.stanford.edu/~engler/ – costly, expensive. *Very* rare to do for software • Testing: + simple, few false positives – requires running code: doesn’t scale & can be impractical ‹Benefit • Manual inspection • Capture recommended practices, known to + flexible experts, in tool available to all – erratic & doesn’t scale well. • What to do??

Metacompilation (MC) Sanitize integers before use

‹Analyze compiler data structure to check code Warn when unchecked integers from untrusted • Extensions dynamically linked into GNU gcc compiler sources reach trusting sinks • Applied down all paths in input program source Network • E.g., extension to check user input Syscall copyin(&v, p, len) param packet GNU compiler Linux copy_from_user(&frame) any<= v <= any 2.4.5: v.tainted v.clean Use(v) se401_newfram(…, frame) “unsafe use drivers/ checker of frame!” memcpy(p, q, v) array[v] usb/ se401->frame[frame] =… copyin(p,q,v) while(i < v) see401.c return ret; copyout(p,q,v) … ERROR Actual error in Linux: raid5 driver disables interrupts, and then if it fails to allocate buffer, returns with them disabled. This kernel deadlock is actually hidden by an immediate segmentation fault since the callers dereference the pointer without checking for NULL Linux: 125 errors, 24 false; BSD: 12 errors, 4 false

7 Example security holes Example security holes

‹Remote exploit, no checks ‹Missed lower-bound check:

/* 2.4.9/drivers/isdn/act2000/capi.c:actcapi_dispatch */ /* 2.4.5/drivers/char/drm/i810_dma.c */ isdn_ctrl cmd; if(copy_from_user(&d, arg, sizeof(arg))) ... return –EFAULT; while ((skb = skb_dequeue(&card->rcvq))) { if(d.idx > dma->buf_count) msg = skb->data; return –EINVAL; ... buf = dma->buflist[d.idx]; memcpy(cmd.parm.setup.phone, Copy_from_user(buf_priv->virtual, d.address, d.used); msg->msg.connect_ind.addr.num, msg->msg.connect_ind.addr.len -1);

User-pointer inference Results for BSD and Linux

‹Problem: which are the user pointers? ‹ All bugs released to implementers; most serious fixed • Hard to determine by dataflow analysis • Easy to tell if kernel believes pointer is from user! Linux BSD ‹Belief inference Violation Bug Fixed Bug Fixed Gain control of system 18 15 3 3 • “*p” implies safe kernel pointer Corrupt memory 43 17 2 2 • “copyin(p)/copyout(p)” implies dangerous user ptr Read arbitrary memory 19 14 7 7 • Error: pointer p has both beliefs. Denial of service 17 5 0 0 Minor 28 1 0 0 ‹Implementation: 2 pass checker Total 125 52 12 12 inter-procedural: compute all tainted pointers local pass to check that they are not dereferenced

Conclusions

‹Security takes extra effort • Know your security goals Linux BSD • Design with security in mind Local bugs 109 12 – Compartmentalize, least privilege Global bugs 16 0 – Minimize setuid, root Bugs from inferred ints 12 0 • Implement carefully False positives 24 4 – Keep it simple Number of checks ~3500 594 – Think about attacks; secure the weakest link • Use tools that detect common coding problems – There are also tools that can analyze designs, but that’s another story (harder to use, current research)

8