Secure Coding - UMBC Center for Information Security and Assurance

advertisement
CMSC 426/626: Secure Coding
Krishna M. Sivalingam
Sources:
From Secure Coding, Mark and van Wyk, O’Reilly, 2003
www.cert.org/secure-coding
Where can errors occur?
During entire software lifecycle
 Security Architecture/Design stage
 Man-in-the-middle attack
 Race condition attack
 Replay attack
 Implementation Stage
 Buffer overflow attack
 Parsing error attack
 Back door attacks (aka Trapdoors)
 Code Maintenance Stage
Flaw Classifications






Landwehr’s Scheme
Bishop’s Scheme
Aslam’s Scheme
Du/Mathur’s classification
Flaws are Intentional and Inadvertent
Inadvertent Flaw Classifications
 Validation Error
 Domain Error
 Serialization and Aliasing
 Inadequate Authentication and Identification
 Boundary Condition Violation
 Other exploitable logic error
Study of Buffer Overflow Attack
 Cowan,
Crispin, Perry Wagle, Calton Pu, Steve
Beattie, and Jonathan Walpole. "Buffer Overflows:
Attacks and Defenses for the Vulnerability of the
Decade." Proceedings of DARPA Information
Survivability Conference and Expo (DISCEX), 1999

http://insecure.org/stf/mudge_buffer_overflow_tutorial.html
Buffer Overflows
 Inject
attack code by overflowing the buffer
 Usually involves adding code based on target
machines’ CPU opcodes
 Execute code with all the privileges of the vulnerable
program
 Thus, if program is running as root, attacker can
run at will any code as root
 Typically, manage to invoke execve /bin/sh or similar
to get a root shell
Program Segments
 An
executing program consists of:
 Code
 Initialized Data
 Global variables
 Stack
 Heap (for dynamic allocation)
 Remember that local variables, return address, etc.
are stored in the stack when a function is invoked
 When a local variable is over-run, it can alter return
address, etc.
Where to Inject Code
 On
the stack (automatic variables)
 On the heap (malloc or calloc variables)
 In static data areas
 Executable code need not be restricted to the
overflowing buffer – code can be injected elsewhere
 One
can also use existing code
 For example, if exec(arg) exists in program,
modify running code by making arg point to
“/bin/sh”
Jump to Attacker’s Code
 Activation
Record
 Overflow into return address on the stack and
make it point at the code.
 Function pointers
 Overflow into “void (*foo())()” and it point at the
code
 Setjmp and longjmp commands, that are used for
checkpointing and recovery
 Alter address given to longjmp to point to
attacker’s code
Buffer Overflow Details
 Look
at Mudge’s sample buffer overflow attack
Buffer Overflow Defenses
 Writing
Correct Code
 Vulnerable programs continue to emerge on a
regular basis
C has many error-prone idioms and a culture that
favors performance over correctness.
 Static Analysis
Tools
 Fortify – looks for vulnerable constructs
 Too many false positives
From Crispin Cowan’s SANS 2000 Talk on Web
Buffer Overflow Defenses
 Non-executable
buffers
 Non executable data segments
Optimizing compiles emit code into program data
segments
 Non
executable stack segments
Highly effective against code injection on the stack but
not against code injections on the heap or static
variables.
Buffer Overflow Defenses



Array Bound Checking
 Can run 12x-30x slower
 a[3] is checked but *(a+3) is not
Type safe languages: Java or ML
 There are millions of lines of C code in operating systems
and security system applications
 Attack the Java Virtual Machine which is a C program
StackGuard program: Adds a “canary” value, which is a 32-bit
random # or a known string terminator (CR, LF, ‘\0’, etc.)
 Compiler adds canary and system can check for this value
at runtime
 Entire RedHat system has been recompiled with this and
shown to be less vulnerable
Race Conditions
 http://seclab.cs.ucdavis.edu/projects/vulnerabilities/s
criv/ucd-ecs-95-08.pdf
 http://citeseer.ist.psu.edu/bishop96checking.html
 http://www.mirrors.wiretapped.net/security/develo
pment/secure-programming/bishop-dilger-1996checking-for-race-conditions-in-file-accesses.pdf
Race condition: What is it?
 Consider
a setuid program, owned by root
 UserA is presently executing the program, hence is
running it as root
 Assume that the program wants to write to a file.
The system must check whether UserA has the right
privileges on this file, checked as follows:
if (access(filename, W_OK) == 0){
if ((fd = open(filename, O_WRONLY)) == NULL){
perror(filename);
return(0);
}
/* now write to the file */
Race condition: What is it?
 In
the time between verifying access and opening
the file, if the file referred to changes, then its access
will not have been checked
 Called TOCTTOU (Time-of-check-To-Time-ofUse) binding flaw
 For example, if access is originally checked on
/tmp/X AND before execution of write statement:
/tmp/X is deleted AND
Hard link from /etc/passwd is created to /tmp/X
 Then,
process will write to /etc/passwd!
 Present in xterm program, while logging sessions
Source: Bishop and Dilger’s 1996 paper in
Computing Systems
Race conditions, contd.






Similar attack possible on binmail program
Binmail appends mail to an existing mail spool file
 E.g. /usr/spool/mail/jkl
Binmail verifies if file exists (and is not a symbolic link)
Before binmail writes to file, jkl is deleted AND made a hard
link to /etc/passwd
Now, binmail appends data to /etc/passwd
 Attacker can create a new account with no password and
root privileges
Note that binding flaws do not arise when file descriptors are
used!
Good Practices in Implementation
 Inform
Yourself
 Follow Vulnerability Discussions and Alerts (eg.
www.cert.org)
 Read books and papers on secure coding
practices, analyses of software flaws, etc.
 Explore open source software
Examples of how to and how not to write code
Good Practices in Implementation
 Handle
Data with Caution
 Cleanse data: Examine input data for malicious
intent (altering character sets, using dis-allowed
characters)
 Perform bounds checking
Check array indices
 Check
configuration files
Can be modified by attacker
 Check
command-line parameters
 Don’t trust web URLs and parameters within
 Be careful of web content (variables hidden in
HTML fields)
Good Practices in Implementation
 Check
web cookies
 Check environment variables
 Set valid initial values for data
 Understand filename references and use them
correctly
 Check for indirect file references (e.g. Shortcuts,
symbolic links)
 Be careful of how program and data files are
located (as in searching using PATH variable)
 Reuse “Good” Code whenever Practical
Good Practices in Implementation


Sound Review Processes
 Perform Peer review of Code
 Perform Independent Validation and Verification
Use automated security tools
 Static Code checkers
 RATS - Rough Auditing Tool for Security
 SPLINT – Source code scanner http://splint.org/
 Uno: http://spinroot.com/uno/

Runtime checkers
 Libsafe: http://directory.fsf.org/libsafe.html
 PurifyPlus: http://www-306.ibm.com/software/awdtools/purifyplus/
 Immunix Tools:
Good Practices in Implementation

Profiling Tools
 Papillon for Solaris: http://www.roqe.org/papillon/
 Gprof from GNU
 Janus – policy enforcement and profiling;
http://www.cs.berkeley.edu/~daw/janus/

Black-box Testing for Fault-Injection Tools
 Appscan: http://www.watchfire.com/securityzone/default.aspx
 Whisker: wiretrip.net
 ISS Database Scanner: http://www.iss.net/

Perform network-based vulnerability scans
 Nmap: http://insecure.org/nmap/
 Nessus: http://www.nessus.org/
 ISS Internet Scanner
Good Practices in Implementation
 Make
Generous Use of Checklists
 Security checklists must be created and checked
against. For example:
Application requires password for access
All user ID logins are unique
Uses role-based access control
Encryption is used
 Code
should be Maintainable
 Practice standards of in-line documentation
 Remove obsolete code
 Test all code changes
Implementation, Don’ts
 Don’t
write code that uses relative filenames
 Fully qualified filenames should be used
 Don’t refer to a file twice in the same program by its
name
 Always use file descriptors after initial open
 Prevents “race condition attack” that exploit time
between access check and file execution
 Don’t invoke untrusted programs from within trusted
ones
 Avoid using setuid or similar mechanisms whenever
possible
 Don’t assume that users are not malicious
Implementation, Don’ts
 Don’t
dump core – code must fail gracefully
 Coredump can be used to extract valuable data
stored in memory during execution
 Don’t assume that a system call (or any function
call) is always successful – always check for return
values and error variable values
 Computer-based random number generators are
“pseudo-random” and can have repitition
 Don’t invoke shell or command line from within a
program
 Don’t use world writable storage, even for temporary
files
Implementation, Don’ts
 Don’t
trust user-writable storage not to be tampered
with
 Don’t keep sensitive data in a database without
password protection
 Don’t code usernames/passwords into an
application
 Don’t echo passwords!
 Don’t rely on host-level file protection mechanisms
 Don’t make access decisions based on environment
variables or command-line arguments
 Don’t issue passwords via email
To be Continued
Download