Today we are talking about different classes of bugs and how we can use tools to find them.
During the course, we have seen many different kinds of vulnerabilities in software.
-
Create a group with your neighbors.
-
Talk about what classes of bugs you can think of, e.g., what you have encountered in this course or in other context and collect them on a sheet of paper.
-
Discuss whether they are security relevant, i.e., could an attacker exploit them?
-
Meet with the neighboring group and compare your lists. Did they think of different vulnerabilities?
-
Take a look at the Common Weakness Enumeration -- a project that lists and categorizes security-related problems and their relationships in software and hardware.
Try to find some of the vulnerability classes you though of in CWE.
You can for example use the following views to navigate CWE:
C is a widely used programming language. It is, however, easy to make mistakes that often lead to security problems behavior. Fortunately, the available tooling has improved in recent years.
Very helpful are the so-called sanitizers available in the GCC and Clang compilers. When enabled, these sanitizers instrument the resulting binary program with additional checks. At run-time, the inserted checks are able to detect certain classes of errors and provider information to the developer where/how the error occurred. Hence, it is compile programs (or test suites) with sanitizers to detect bugs that otherwise would not have had directly observable consequences.
You are given three programs address.c
, thread.c
, and undefined.c
which
contain very questionable code and different kinds of bugs to demonstrate the
powers of the different sanitizers. Run make
to compile them.
The manual memory management and the absence of automatic bounds checking in C
are major sources of trouble. The AddressSanitizer, enabled with
-fsanitize=address
, is able to detect such mistakes.
Consider the program address.c
which is obviously buggy.
$ ./address AAAAAAAAAAAAAAA BBBBBBBBBBBBBBB
What's your name?
lennart
============== Moin lennart ==============
Do you like pointers?
YES!
WTF???
free(): invalid pointer
[1] 2385487 abort (core dumped) ./address AAAAAAAAAAAAAAA BBBBBBBBBBBBBBB
Run it with ASan and see what kind of errors it detects.
Multi-threading and synchronization is not trivial either. The
ThreadSanitizer, enabled with -fsanitize=thread
, is able to detect data races
and other threading-related issues.
Consider the program thread.c
(some of you might find it familiar) and
observe the inconsistent output:
$ ./thread 10000 40
there are 1220 primes up to 10000
$ ./thread 10000 40
there are 1202 primes up to 10000
$ ./thread 10000 40
there are 1209 primes up to 10000
Use TSan to detect the problems in the code.
Undefined behavior can occur when a C program violates a rule given by the C language standard and the standard does not specify what should happen in this cases. Then the compiler as allowed to do as it pleases.
This can be used to generate faster code: The compiler is allowed to assume that certain invalid things do not happen and can then optimize the code based on these assumptions
Consider the program undefined.c
and follow the comments in the file. Use
UBSan, enabled with -fsanitize=undefined
, to detect possible issues.
$ ./undefined 36 6
36
6
no overflow happened :)
42
success
p = 0x7ffd33643991
s = 328350
The following articles give a good introduction to the concept of undefined behavior:
- John Regehr, A Guide to Undefined Behavior in C and C++
- Chris Lattner, What Every C Programmer Should Know About Undefined Behavior
Install American Fuzzy Lop (AFL) (or its
successor project AFL++) and gcc-multilib
:
$ sudo apt install afl gcc-multilib
In the directories random_password
and broken_register
you find two
programs with corresponding Makefiles. Use AFL to find crashing inputs. E.g.,
you can use afl-gcc
(instead of gcc
) to compile executables with
instrumentation and afl-fuzz
to perform the actual fuzzing.
If you are boredwant a challenge, you can try to exploit the two programs
at home. These are non-trivial, though, and at least random_password
requires concepts that we did not discuss in class. Goal is to print
flag.txt
or to get a shell.