
फ्रीडा-आधारित इन-प्रोसेस फ़ज़िंग सूट, AFL++ प्रॉक्सी, स्टैंडअलोन सक्रिय/निष्क्रिय मोड, और विभिन्न प्लेटफार्मों पर उच्च-प्रदर्शन कवरेज-निर्देशित कमज़ोरी खोज के लिए साझा मेमोरी संचार।
fpicker एक Frida-आधारित फज़िंग सूट है जो इन-प्रोसेस फज़िंग के लिए विभिन्न प्रकार के फज़िंग मोड प्रदान करता है, जैसे कि AFL++ मोड या पैसिव ट्रेसिंग मोड। यह Frida द्वारा समर्थित सभी प्लेटफार्मों पर चलना चाहिए।
fpicker के पीछे कुछ पृष्ठभूमि जानकारी और विचार एक ब्लॉगपोस्ट में पाए जा सकते हैं जो मैंने लिखा था।
Fpicker पिछले प्रयासों पर आधारित है ToothPicker, जो मेरी मास्टर थीसिस के दौरान विकसित किया गया था। अधिकांश fpicker मेरे नियोक्ता (ERNW) पर काम के घंटों के दौरान विकसित किया गया था।
fpicker चलाने के लिए आवश्यक:
frida-core-devkit Frida releases on GitHub पर पाया जाता है।
libfrida-core-ios.a, libfrida-core-macos.a, या libfrida-core-linux.a के रूप में स्टोर करें।frida-core.h) के लिए भी यही बात लागू होती है। उन्हें प्लेटफॉर्म के अनुसार frida-core-linux.h या frida-core-ios.h के रूप में स्टोर करें।update_frida_version.sh चलाएँ।केवल AFL++ मोड में चलाने पर आवश्यक:
CFLAGS="-DUSEMMAP=1" के साथ संकलित करें।CFLAGS="-DUSEMMAP=1 -DTARGET_OS_IOS" के साथ संकलित करें।Fpicker को macOS, iOS या Linux के लिए बनाया जा सकता है। Makefile वर्तमान में केवल macOS पर iOS के लिए बिल्डिंग का समर्थन करता है, लेकिन Linux पर iOS टूलचेन का उपयोग करके fpicker बनाना पूरी तरह से संभव होना चाहिए।
वांछित लक्ष्य के अनुसार चलाएँ:
make fpicker-macos
make fpicker-ios
make fpicker-linux
fpicker बनाने के लिए।
एक बार fpicker बन जाने के बाद, अगला कदम फज़िंग हार्नेस बनाना है:
विभिन्न नमूना फज़िंग मामलों के लिए examples फ़ोल्डर देखें। सामान्य दृष्टिकोण इस प्रकार है:
examples/test/test.js) (हार्नेस के बारे में अधिक जानकारी के लिए यहाँ देखें)frida-compile test.js -o harness.jsअब fpicker फज़िंग शुरू कर सकता है। सटीक कमांड कॉन्फ़िगरेशन और सेटअप पर अत्यधिक निर्भर करता है। निम्नलिखित में, कुछ उदाहरण मामले दिए गए हैं। ये ज्यादातर examples फ़ोल्डर में दिए गए उदाहरणों के अनुरूप हैं।
afl-fuzz -i examples/test-network/in -o ./examples/test-network/out -- \\
./fpicker --fuzzer-mode afl -e attach -p test-network -f ./examples/test-network/harness.js
./fpicker --fuzzer-mode standalone -e attach -p server-process -f harness.js --input-mode cmd \\
--command "./client-send @@" -i indir -o outdir
./fpicker --fuzzer-mode active --communication-mode shm -e attach -p server-process -f harness.js \\
-i indir -o outdir --standalone-mutator cmd --mutator-command "radamsa"
./fpicker --fuzzer-mode passive --communication-mode send -e attach -p server-process -o outdir -f harness.js
./fpicker --fuzzer-mode active -e attach -p test -D remote -o examples/test/out/ -i examples/test/in/ \\
-f fuzzer-agent.js --standalone-mutator cmd --mutator-command "radamsa"
प्रत्येक लक्ष्य के लिए अपने स्वयं के फज़िंग हार्नेस की आवश्यकता होती है। इस हार्नेस का सबसे महत्वपूर्ण हिस्सा Frida के Stalker के प्रवेश फ़ंक्शन को परिभाषित करना है, जो प्रभावी रूप से यह निर्धारित करता है कि इंस्ट्रुमेंटेशन किस बिंदु पर डाला जाता है। in-process मोड में यह सरल है। फ़ंक्शन आमतौर पर वह होता है जो प्रत्येक फज़िंग पुनरावृत्ति पर कॉल किया जाता है। हालांकि, यह एक अलग भी हो सकता है।
एक न्यूनतम हार्नेस कार्यान्वयन (command मोड में) इस प्रकार हो सकता है:
// Import the fuzzer base class
const Fuzzer = require("harness/fuzzer.js");
// The custom fuzzer needs to subclass the Fuzzer class to work properly
class TestFuzzer extends Fuzzer.Fuzzer {
constructor() {
// The constructor needs to specify the address of the targeted function and a NativeFunction
// object that can later be called by the fuzzer.
const FUZZ_FUNCTION_ADDR = Module.getExportByName(null, "FUZZ_FUNCTION");
const FUZZ_FUNCTION = new NativeFunction(
FUZZ_FUNCTION_ADDR,
"void", ["pointer", "int64"], {
});
super("test", FUZZ_FUNCTION_ADDR, FUZZ_FUNCTION);
}
}
const f = new TestFuzzer();
exports.fuzzer = f;
यह हार्नेस इंस्ट्रुमेंटेशन को FUZZ_FUNCTION फ़ंक्शन का अनुसरण करने के लिए कॉन्फ़िगर करता है। इंस्ट्रुमेंटेशन तब शुरू होगा जब यह फ़ंक्शन प्रवेश करेगा और फ़ंक्शन के वापस लौटने पर रुक जाएगा। इस फ़ंक्शन को सावधानी से चुना जाना चाहिए क्योंकि यह महंगा है और प्रक्रिया के अधिक (संभावित रूप से महत्वहीन) भागों को इंस्ट्रुमेंट किया जाता है, फज़र उतना ही धीमा हो जाता है। बेशक, यह गति और इच्छित कवरेज के बीच एक विचार है। इसके अतिरिक्त, फज़र वर्तमान में केवल उन फ़ंक्शनों का समर्थन करता है जो एक फज़िंग पुनरावृत्ति के दौरान केवल एक बार प्रवेश करते हैं, अर्थात, फ़ंक्शन को एक फज़ केस के दौरान एक से अधिक बार कॉल नहीं किया जाना चाहिए, अन्यथा कवरेज जानकारी अविश्वसनीय हो सकती है।
जब in-process मोड का उपयोग किया जाता है, तो फज़र स्क्रिप्ट में एक और फ़ंक्शन की आवश्यकता होती है। fuzz विधि। यह प्रत्येक पुनरावृत्ति पर कॉल किया जाएगा। इसे दो पैरामीटर दिए जाएंगे, एक बफर के लिए पॉइंटर और बफर की लंबाई। हमारा उदाहरण लक्ष्य फ़ंक्शन दो पैरामीटर लेता है, एक बफर के लिए पॉइंटर और इसकी लंबाई। इस प्रकार, हम बस fuzz विधि में प्राप्त पैरामीटर पास कर सकते हैं।
fuzz(payload, len) {
this.target_function(payload, parseInt(len));
}
passive मोड में, एक कॉलबैक निर्दिष्ट करने की आवश्यकता होती है जो आवश्यक डेटा को प्रोसेस करता है। फज़र एक पेलोड बफर और इसकी लंबाई प्राप्त करने की अपेक्षा करता है। जिस लक्ष्य फ़ंक्शन को फज़ किया जा रहा है, उसके आधार पर, इस डेटा को निकालने की आवश्यकता होती है। निम्नलिखित उदाहरण में, हमारे पास फिर से एक फ़ंक्शन है जिसके दो पैरामीटर हैं: एक बफर के लिए पॉइंटर और इसकी लंबाई। args पैरामीटर में लक्ष्य फ़ंक्शन को प्राप्त होने वाले सभी संभावित पैरामीटर होते हैं, इसलिए लंबाई पैरामीटर (जो हमारे मामले में दूसरा है) को args[1] से एक्सेस किया जा सकता है। फिर हम बफर को Uint8Array के रूप में पढ़ते हैं और sendPassiveCorpus विधि का उपयोग करके इसे वापस फज़र को भेजते हैं।
passiveCallback(args) {
const len = args[1];
const data = new Uint8Array(Memory.readByteArray(args[0], parseInt(len)));
// this encodes the data and sends it back to the fuzzer
this.sendPassiveCorpus(data, len);
}