You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardexpand all lines: security-fuzzing-handbook/fuzzing-handbook.md
+38-38
Original file line number
Diff line number
Diff line change
@@ -60,7 +60,7 @@ This chapter goes over background concepts of fuzzing and gives a practical demo
60
60
## Fuzzing foundations
61
61
Fuzzing is a program analysis technique closely connected to testing. In testing, a common practice is to execute code using a fixed input setting. In fuzzing, the testing is done using pseudo-random data as input to a target piece of code, meaning the target code is run over and over again with pseudo-random data as input. The goal of fuzzing is to discover if any arbitrary input can lead to a bug in the target code. For example, a simple way to fuzz a modern browser is to generate random files and then open each file in the browser with the goal of identifying potential patterns that can cause issues in the browser.
62
62
63
-
The common set up when fuzzing a piece of software is to construct a fuzzing set up for the code and then run this fuzzer for an extended period of time, and monitor if any bugs occur in the target code during the process. The fuzzer can be run in many settings, including running it locally locally, as part of a CI/CD pipeline or part of a larger management framework for handling the running of fuzzers. The specific time run for the fuzzer ranges from a few minutes to hundreds or even thousands of hours.
63
+
The common set up when fuzzing a piece of software is to construct a fuzzing set up for the code and then run this fuzzer for an extended period of time, and monitor if any bugs occur in the target code during the process. The fuzzer can be run in many settings, including running it locally, as part of a CI/CD pipeline or part of a larger management framework for handling the running of fuzzers. The specific time run for the fuzzer ranges from a few minutes to hundreds or even thousands of hours.
64
64
65
65
The core technique of fuzzing is simple in that it executes target code indefinitely using pseudo-random input. However, fuzzing comes in many flavors and in this handbook we will be concerned with the concert of coverage-guided fuzzing. This is a technique that relies on monitoring the target code under to extract the specific code executed by a given input, and use this to improve generation of pseudo-random input to increase likelihood of generating new inputs that trigger unique code paths. Coverage-guided fuzzing has had a significant impact on fuzzing in the last 15 years and is the most common fuzzing technique used in modern software development.
66
66
@@ -102,14 +102,14 @@ In order to make the fuzzing work the developer compiles the fuzzing harness and
102
102
#include <stdlib.h>
103
103
104
104
int parseUntrustedBuffer(const uint8_t *buffer, size_t size) {
105
-
if (size < 2) {
106
-
return -1;
107
-
}
108
-
if (buffer[0] == 'A') {
109
-
if (buffer[1] == 'B') {
110
-
assert(0);
111
-
}
105
+
if (size < 2) {
106
+
return -1;
107
+
}
108
+
if (buffer[0] == 'A') {
109
+
if (buffer[1] == 'B') {
110
+
assert(0);
112
111
}
112
+
}
113
113
return 0;
114
114
}
115
115
```
@@ -124,7 +124,7 @@ The question in place for the fuzzer in this case is whether it will come up wit
124
124
extern int parseUntrustedBuffer(const uint8_t *buffer, size_t size);
125
125
126
126
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
ompiling this and launching the fuzzer in a manner similar to Example 1 will result in the binary running forever. In each iteration of the fuzzer it will either print “Size 123” or “Not size 123”, however, by default it will never stop. This can seem counterintuitive at first, partly because it signals that there is no notion of “completeness” when fuzzing, as opposed to testing. This is correct in the sense there is no single truth value denoting if the fuzzing is complete or not, it is by nature an infinite while loop. To this end, a harness is generally run until either one of the conditions hold:
194
+
Compiling this and launching the fuzzer in a manner similar to Example 1 will result in the binary running forever. In each iteration of the fuzzer it will either print “Size 123” or “Not size 123”, however, by default it will never stop. This can seem counterintuitive at first, partly because it signals that there is no notion of “completeness” when fuzzing, as opposed to testing. This is correct in the sense there is no single truth value denoting if the fuzzing is complete or not, it is by nature an infinite while loop. To this end, a harness is generally run until either one of the conditions hold:
195
195
196
196
1. A timeout has been reached;
197
197
2. The fuzzer found a bug and, therefore, exits.
@@ -356,7 +356,7 @@ The core task that we have to do in order to use LibFuzzer to fuzz a target appl
356
356
#include <stdint.h>
357
357
358
358
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
359
-
/* Fuzz driver implementation */
359
+
/* Fuzz driver implementation */
360
360
}
361
361
```
362
362
@@ -834,17 +834,17 @@ We can use the following fuzzer to attack this code:
834
834
835
835
```c
836
836
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size){
837
-
char *new_str = (char *)malloc(size+1);
838
-
if (new_str == NULL){
839
-
return 0;
840
-
}
841
-
memcpy(new_str, data, size);
842
-
new_str[size] = '\0';
843
-
844
-
attack_me(new_str);
845
-
846
-
free(new_str);
847
-
return 0;
837
+
char *new_str = (char *)malloc(size+1);
838
+
if (new_str == NULL){
839
+
return 0;
840
+
}
841
+
memcpy(new_str, data, size);
842
+
new_str[size] = '\0';
843
+
844
+
attack_me(new_str);
845
+
846
+
free(new_str);
847
+
return 0;
848
848
}
849
849
```
850
850
@@ -1578,14 +1578,14 @@ The project has two fuzzers `fuzz_complex_parser.c:`
1578
1578
#include "char_lib.h"
1579
1579
1580
1580
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
1581
-
char *ns = malloc(size+1);
1582
-
memcpy(ns, data, size);
1583
-
ns[size] = '\0';
1584
-
1585
-
count_lowercase_letters(ns);
1586
-
1587
-
free(ns);
1588
-
return 0;
1581
+
char *ns = malloc(size+1);
1582
+
memcpy(ns, data, size);
1583
+
ns[size] = '\0';
1584
+
1585
+
count_lowercase_letters(ns);
1586
+
1587
+
free(ns);
1588
+
return 0;
1589
1589
}
1590
1590
```
1591
1591
@@ -1600,14 +1600,14 @@ and `fuzz_char_lib.c`
1600
1600
#include "char_lib.h"
1601
1601
1602
1602
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
# Malicious maintainer introduces sophisticated backdoor in xz
4
+
5
+
A backdoor was introduced in `xz`, a compression tool integral to various
6
+
Linux distributions. Over the course of several years, a malicious actor
7
+
or actors attained maintainer status and implanted a sophisticated,
8
+
multi-stage backdoor that relied on the specific build processes of `xz`
9
+
to activate, resulting in a modified `liblzma` library that can be used
10
+
by any software linked against this library.
11
+
12
+
## Impact
13
+
14
+
The backdoor was discovered on March 28, 2024, specifically in versions
15
+
5.6.0 and 5.6.1 of the XZ Utils package, and was assigned CVE-2024-3094.
16
+
17
+
The compromised package was distributed across several Linux distributions
18
+
including Fedora, Debian, Kali Linux, openSUSE, Arch Linux, and various
19
+
package managers like Homebrew and pkgsrc.
20
+
21
+
The apparent goal of this backdoor was to enable remote code execution
22
+
via `sshd` on affected systems by intercepting the `RSA_public_decrypt()`
23
+
function, looking for an attacker controlled key, and executing the payload
24
+
via `system()` function.
25
+
26
+
This incident achieved mainstream media coverage, driving further recognition
27
+
of the threats involved in exploiting trust and lack of visibility into
28
+
maintainer activities.
29
+
30
+
The initial response guidance involved rolling back the version of `xz`,
31
+
but this proved difficult in some ecosystems which had to intervene to
32
+
create epochs. Also, for a number of days after the disclosure, the `xz`
33
+
repository on GitHub was disabled which made it more cumbersome for the
34
+
public to research what had happened.
35
+
36
+
## Type of compromise
37
+
38
+
While rooted on a malicious maintainer that attained this status by a
39
+
long-term effort by an actor or actors to subvert the project, this incident
40
+
also exhibits some attack chaining characteristics including the exploitation
41
+
of trusted build and distribution mechanisms to deploy the backdoor. From
42
+
the [Cloud Security Alliance](https://cloudsecurityalliance.org/blog/2024/04/25/navigating-the-xz-utils-vulnerability-cve-2024-3094-a-comprehensive-guide)
43
+
report:
44
+
45
+
> The backdoor was deliberately concealed by the developer. It gets incorporated
46
+
into the binary during the RPM or DEB packaging process for x86-64 architecture,
47
+
using gcc and gnu linker, under the guise of a "test" step.
0 commit comments