Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Lab7/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
all:
./build.sh
AFL_DEMO=1 ./AFLplusplus/afl-clang-fast -O0 -w program.c -o program
mkdir -p input
echo -ne "\x00" > input/seed0

run:
AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 AFLplusplus/afl-fuzz -i input -o output -- ./program

clean:
rm -rf AFLplusplus input output program
77 changes: 77 additions & 0 deletions Lab7/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Lab7

## Introduction

In this lab, you will write a LLVM pass in `llvm-pass/afl-demo-pass.so.cc` and `llvm-pass/afl-demo-rt.o.c`, and enable AFL++ to detect command injection vulnerabilities.

## Environment (Important.)

1. x86_64 machine
2. Ubuntu 22.04
3. llvm-14

## Requirement

**(100%)** In this lab, you will write a LLVM pass in `llvm-pass/afl-demo-pass.so.cc` & `llvm-pass/afl-demo-rt.o.c` and satisfy the following requirements.
1. When running afl++ to fuzz `program`, `program` can't crash by `system("echo AAA");` at line 34 in `program.c`. It's not command injection, and you will see the error message below when you try to fuzz:
```
[-] PROGRAM ABORT : We need at least one valid input seed that does not crash!
```
Of course, you can not just detect this line to avoid it. We will modify this command and add additional system functions (which won't cause command injection) in `program.c` during testing with your fuzzer.
2. When running afl++ to fuzz `program`, the fuzzer needs to find the command injection `system(cmd)` at line 18 in `program.c`.
3. Write a report in `{student_ID}.pdf` to explain your work.
- Your report must include the following sections
- Your name and student ID,
- Explanation of your work
- Copy the crash fuzzer report and crash input (use `xxd`) in `{student_ID}.pdf`.

**Template**

Name:
student_ID:

```
Explanation of your work
```

Crash fuzzer report
```

american fuzzy lop ++4.01c {default} (./program) [fast]
┌─ process timing ────────────────────────────────────┬─ overall results ────┐
│ run time : 0 days, 0 hrs, 0 min, 18 sec │ cycles done : 9 │
│ last new find : 0 days, 0 hrs, 0 min, 8 sec │ corpus count : 7 │
│last saved crash : 0 days, 0 hrs, 0 min, 3 sec │saved crashes : 1 │
│ last saved hang : none seen yet │ saved hangs : 0 │
├─ cycle progress ─────────────────────┬─ map coverage┴──────────────────────┤
│ now processing : 5.3 (71.4%) │ map density : 30.77% / 76.92% │
│ runs timed out : 0 (0.00%) │ count coverage : 39.40 bits/tuple │
├─ stage progress ─────────────────────┼─ findings in depth ─────────────────┤
│ now trying : havoc │ favored items : 7 (100.00%) │
│ stage execs : 312/1175 (26.55%) │ new edges on : 7 (100.00%) │
│ total execs : 97.2k │ total crashes : 1 (1 saved) │
│ exec speed : 5329/sec │ total tmouts : 1 (0 saved) │
├─ fuzzing strategy yields ────────────┴─────────────┬─ item geometry ───────┤
│ bit flips : disabled (default, enable with -D) │ levels : 6 │
│ byte flips : disabled (default, enable with -D) │ pending : 0 │
│ arithmetics : disabled (default, enable with -D) │ pend fav : 0 │
│ known ints : disabled (default, enable with -D) │ own finds : 6 │
│ dictionary : n/a │ imported : 0 │
│havoc/splice : 4/38.3k, 3/58.5k │ stability : 100.00% │
│py/custom/rq : unused, unused, unused, unused ├───────────────────────┘
│ trim/eff : 0.00%/7, disabled │ [cpu000: 12%]
└────────────────────────────────────────────────────┘

```
Crash Input:
```
$ xxd output/default/crashes/id\:000000\,sig\:06\,src\:000006\,time\:15137\,execs\:81803\,op\:havoc\,rep\:2
00000000: 4655 5a5a 2146 ec40 FUZZ!F.@
```

## Submission

1. Lab7 will not have github ci, so the grade of Lab7 will be determined with your report `{studemt_ID}.pdf`
2. Submit the report `{student_ID}.pdf` to explain your work.
3. You must submit these two files `llvm-pass/afl-demo-pass.so.cc` and `llvm-pass/afl-demo-rt.o.c`.
4. You need to commit and push the corresponding changes to your repository, which contains the code that satisfies the aforementioned requirements.
10 changes: 10 additions & 0 deletions Lab7/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/bash -ex

if [ ! -d "AFLplusplus" ]; then
git clone -b 4.01c --depth 1 https://github.com/AFLplusplus/AFLplusplus.git
git -C AFLplusplus apply ../integration.diff
fi

cp llvm-pass/* AFLplusplus/instrumentation
cd AFLplusplus
make LLVM_CONFIG=llvm-config-14
108 changes: 108 additions & 0 deletions Lab7/integration.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
diff --git a/GNUmakefile.llvm b/GNUmakefile.llvm
index 685964b7..9f309c08 100644
--- a/GNUmakefile.llvm
+++ b/GNUmakefile.llvm
@@ -308,7 +308,7 @@ ifeq "$(TEST_MMAP)" "1"
endif

PROGS_ALWAYS = ./afl-cc ./afl-compiler-rt.o ./afl-compiler-rt-32.o ./afl-compiler-rt-64.o
-PROGS = $(PROGS_ALWAYS) ./afl-llvm-pass.so ./SanitizerCoveragePCGUARD.so ./split-compares-pass.so ./split-switches-pass.so ./cmplog-routines-pass.so ./cmplog-instructions-pass.so ./cmplog-switches-pass.so ./afl-llvm-dict2file.so ./compare-transform-pass.so ./afl-ld-lto ./afl-llvm-lto-instrumentlist.so ./SanitizerCoverageLTO.so
+PROGS = $(PROGS_ALWAYS) ./afl-llvm-pass.so ./SanitizerCoveragePCGUARD.so ./split-compares-pass.so ./split-switches-pass.so ./cmplog-routines-pass.so ./cmplog-instructions-pass.so ./cmplog-switches-pass.so ./afl-llvm-dict2file.so ./compare-transform-pass.so ./afl-ld-lto ./afl-llvm-lto-instrumentlist.so ./SanitizerCoverageLTO.so ./afl-demo-pass.so ./afl-demo-rt.o

# If prerequisites are not given, warn, do not build anything, and exit with code 0
ifeq "$(LLVMVER)" ""
@@ -436,6 +436,9 @@ endif
afl-llvm-dict2file.so: instrumentation/afl-llvm-dict2file.so.cc instrumentation/afl-llvm-common.o | test_deps
$(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL) instrumentation/afl-llvm-common.o

+afl-demo-pass.so: instrumentation/afl-demo-pass.so.cc instrumentation/afl-llvm-common.o | test_deps
+ $(CXX) $(CLANG_CPPFL) -shared $< -o $@ $(CLANG_LFL)
+
.PHONY: document
document:
$(CLANG_BIN) -D_AFL_DOCUMENT_MUTATIONS $(CFLAGS_SAFE) $(CPPFLAGS) $(CLANG_CFL) -O3 -Wno-unused-result -fPIC -c instrumentation/afl-compiler-rt.o.c -o ./afl-compiler-rt.o
@@ -453,6 +456,9 @@ document:
@printf "[*] Building 64-bit variant of the runtime (-m64)... "
@$(CC) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -m64 -fPIC -c $< -o $@ 2>/dev/null; if [ "$$?" = "0" ]; then echo "success!"; else echo "failed (that's fine)"; fi

+./afl-demo-rt.o: instrumentation/afl-demo-rt.o.c
+ $(CC) $(CLANG_CFL) $(CFLAGS_SAFE) $(CPPFLAGS) -O3 -Wno-unused-result -fPIC -c $< -o $@
+
.PHONY: test_build
test_build: $(PROGS)
@echo "[*] Testing the CC wrapper and instrumentation output..."
@@ -475,6 +481,7 @@ install: all
@if [ -f ./afl-cc ]; then set -e; install -m 755 ./afl-cc $${DESTDIR}$(BIN_PATH); ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-c++; fi
@rm -f $${DESTDIR}$(HELPER_PATH)/afl-llvm-rt*.o $${DESTDIR}$(HELPER_PATH)/afl-gcc-rt*.o
@if [ -f ./afl-compiler-rt.o ]; then set -e; install -m 755 ./afl-compiler-rt.o $${DESTDIR}$(HELPER_PATH); fi
+ @if [ -f ./afl-demo-rt.o ]; then set -e; install -m 755 ./afl-demo-rt.o $${DESTDIR}$(HELPER_PATH); fi
@if [ -f ./afl-lto ]; then set -e; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-lto; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-lto++; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto; ln -sf afl-cc $${DESTDIR}$(BIN_PATH)/afl-clang-lto++; install -m 755 ./afl-llvm-rt-lto*.o ./afl-llvm-lto-instrumentlist.so $${DESTDIR}$(HELPER_PATH); fi
@if [ -f ./afl-ld-lto ]; then set -e; install -m 755 ./afl-ld-lto $${DESTDIR}$(BIN_PATH); fi
@if [ -f ./afl-compiler-rt-32.o ]; then set -e; install -m 755 ./afl-compiler-rt-32.o $${DESTDIR}$(HELPER_PATH); fi
diff --git a/include/envs.h b/include/envs.h
index 25b792fa..bbe9a99e 100644
--- a/include/envs.h
+++ b/include/envs.h
@@ -226,6 +226,7 @@ static char *afl_environment_variables[] = {
"AFL_USE_QASAN",
"AFL_PRINT_FILENAMES",
"AFL_PIZZA_MODE",
+ "AFL_DEMO",
NULL

};
diff --git a/src/afl-cc.c b/src/afl-cc.c
index 2667ae28..7da0b89c 100644
--- a/src/afl-cc.c
+++ b/src/afl-cc.c
@@ -57,6 +57,7 @@ static u8 * lto_flag = AFL_CLANG_FLTO, *argvnull;
static u8 debug;
static u8 cwd[4096];
static u8 cmplog_mode;
+static u8 demo_mode;
u8 use_stdin; /* dummy */
static int passthrough;
// static u8 *march_opt = CFLAGS_OPT;
@@ -699,6 +700,23 @@ static void edit_params(u32 argc, char **argv, char **envp) {

}

+
+ if (demo_mode) {
+
+#if LLVM_MAJOR >= 11
+ cc_params[cc_par_cnt++] = "-fexperimental-new-pass-manager";
+ cc_params[cc_par_cnt++] = alloc_printf(
+ "-fpass-plugin=%s/afl-demo-pass.so", obj_path);
+#else
+ cc_params[cc_par_cnt++] = "-Xclang";
+ cc_params[cc_par_cnt++] = "-load";
+ cc_params[cc_par_cnt++] = "-Xclang";
+ cc_params[cc_par_cnt++] =
+ alloc_printf("%s/afl-demo-pass.so", obj_path);
+#endif
+
+ }
+
// cc_params[cc_par_cnt++] = "-Qunused-arguments";

if (lto_mode && argc > 1) {
@@ -1100,6 +1118,9 @@ static void edit_params(u32 argc, char **argv, char **envp) {
if (lto_mode)
cc_params[cc_par_cnt++] =
alloc_printf("%s/afl-llvm-rt-lto.o", obj_path);
+ if (demo_mode)
+ cc_params[cc_par_cnt++] =
+ alloc_printf("%s/afl-demo-rt.o", obj_path);
break;

case 32:
@@ -2153,6 +2174,8 @@ int main(int argc, char **argv, char **envp) {
if (!be_quiet && cmplog_mode)
printf("CmpLog mode by <andreafioraldi@gmail.com>\n");

+ demo_mode = !!getenv("AFL_DEMO");
+
#if !defined(__ANDROID__) && !defined(ANDROID)
ptr = find_object("afl-compiler-rt.o", argv[0]);

137 changes: 137 additions & 0 deletions Lab7/llvm-pass/afl-demo-pass.so.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#define AFL_LLVM_PASS

#include "config.h"
#include "debug.h"

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/time.h>

#include <list>
#include <memory>
#include <string>
#include <fstream>
#include <set>
#include <iostream>

#include "llvm/Config/llvm-config.h"
#include "llvm/Pass.h"
#include "llvm/Passes/PassPlugin.h"
#include "llvm/Passes/PassBuilder.h"
#include "llvm/IR/PassManager.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Verifier.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/MemorySSAUpdater.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/Constants.h"

#include "llvm/Passes/OptimizationLevel.h"

#include "afl-llvm-common.h"

using namespace llvm;

namespace {

class AFLDEMOPass : public PassInfoMixin<AFLDEMOPass> {

public:
AFLDEMOPass() {

}

PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
llvm::StringRef GetCallInsFunctionName(CallInst *call);

protected:

};

} // namespace

extern "C" ::llvm::PassPluginLibraryInfo LLVM_ATTRIBUTE_WEAK
llvmGetPassPluginInfo() {

return {

LLVM_PLUGIN_API_VERSION, "AFLDEMOPass", "v0.1", [](PassBuilder &PB) {

PB.registerOptimizerLastEPCallback(
[](ModulePassManager &MPM, OptimizationLevel OL) {

MPM.addPass(AFLDEMOPass());

});

}};

}

PreservedAnalyses AFLDEMOPass::run(Module &M, ModuleAnalysisManager &MAM) {

LLVMContext & C = M.getContext();
Type * VoidTy = Type::getVoidTy(C);
FunctionCallee demo_crash = M.getOrInsertFunction("__demo_crash", VoidTy);

for (auto &F : M) {

llvm::StringRef fn = F.getName();

if (fn.equals("_start") || fn.startswith("__libc_csu") ||
fn.startswith("__afl_") || fn.startswith("__asan") ||
fn.startswith("asan.") || fn.startswith("llvm."))
continue;

for (auto &BB : F) {

for (auto &I : BB) {

if (CallInst *call = dyn_cast<CallInst>(&I)) {

if (GetCallInsFunctionName(call).equals("system")) {

IRBuilder<> IRB(&I);
IRB.CreateCall(demo_crash)->setMetadata(M.getMDKindID("nosanitize"),
MDNode::get(C, None));

}

}

}

}

}

return PreservedAnalyses::all();

}

llvm::StringRef AFLDEMOPass::GetCallInsFunctionName(CallInst *call) {

if (Function *func = call->getCalledFunction()) {

return func->getName();

} else {

// Indirect call
return dyn_cast<Function>(call->getCalledOperand()->stripPointerCasts())
->getName();

}

}

43 changes: 43 additions & 0 deletions Lab7/llvm-pass/afl-demo-rt.o.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#ifdef __ANDROID__
#include "android-ashmem.h"
#endif
#include "config.h"
#include "types.h"
#include "cmplog.h"
#include "llvm-alternative-coverage.h"

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>
#include <stddef.h>
#include <limits.h>
#include <errno.h>

#include <sys/mman.h>
#ifndef __HAIKU__
#include <sys/syscall.h>
#endif
#ifndef USEMMAP
#include <sys/shm.h>
#endif
#include <sys/wait.h>
#include <sys/types.h>

#if !__GNUC__
#include "llvm/Config/llvm-config.h"
#endif

#ifdef __linux__
#include "snapshot-inl.h"
#endif

void __demo_crash() {

fprintf(stderr, "system found!\n");
abort();

}
Loading