Тест фаззинга для библиотеки разбора QR-кода
Тест фаззинга для библиотеки разбора QR-кода

фон

В апреле появилась новость о том, что в WeChat произошел сбой при открытии изображений. В то время он распространялся в группе WeChat и вызывал различные сбои в работе телефона.

История чата

Поскольку автор в то время был занят написанием Java Web, я не сразу воспользовался этой горячей точкой, но у меня также было небольшое понимание принципа сбоя. Недавно копание уязвимостей в Java как раз подошло к концу, поэтому я вдруг вспомнил об этом деле.

этот bug Основная причина из — в деформированном изQR-коде, приводящем к ошибке нулевого указателя при декодировании. Подробный анализ и исправление записей см. fix(wechat_qrcode): Init nBytes after the count value is determined #3480

домаQR-код Можно сказатьда Встречается повсюдуизвещь,Если мы говорим декодированиеизосновной SDK Если есть лазейки, последствия, вероятно, будут очень масштабными. Кроме того, во многих приложениях реализованы функции тихого декодирования, основанные на различных странных целях и целях. Если можно обнаружить уязвимость, которую можно использовать, это также типично. 0-click сцена.

Поэтому я планирую просто Fuzz Вот соответствующий код декодирования изQR-кода, поместите его в фоновый режим сервера и запустите медленно, и надеюсь, однажды утром перемещение кирпичей не займет слишком много времени. boki Пробуждение может принести неожиданную награду.

компилировать

Fuzz из Первый естественный шаг — сначала успешно скомпилировать целевой код, а затем попытаться скомпилировать его с помощью инструментатора.

Репозиторий кода, в котором ранее возникла проблема: https://github.com/opencv/opencv_contrib,этотда opencv Подрепозиторий под OpenCV модуль, основанный на README из Введения, скомпилировать эти модули,обработать следующим образом:

Язык кода:javascript
копировать
$ cd <opencv_build_directory>
$ cmake -DOPENCV_EXTRA_MODULES_PATH=<opencv_contrib>/modules <opencv_source_directory>
$ make -j5

Другими словами, компилировать эти модули все равно нужно в зависимости от OpenCV из репозитория исходного кода, поэтому мы скачали оба репозитория для компиляции. Чтобы избежать проблем, я просто сделаю это напрямую. AFL++ руководитькомпилировать Понятно,использовать cmake изкомпилировать Заказследующее:

Язык кода:javascript
копировать
cmake -DCMAKE_C_COMPILER=afl-clang-fast -DCMAKE_CXX_COMPILER=afl-clang-fast++ \
  -DCMAKE_CXX_FLAGS="-fsanitize=address,undefined -fno-sanitize-recover=all -g" \
  -DCMAKE_C_FLAGS="-fsanitize=address,undefined -fno-sanitize-recover=all -g" \
  -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,undefined -fno-sanitize-recover=all" \
  -DCMAKE_MODULE_LINKER_FLAGS="-fsanitize=address,undefined -fno-sanitize-recover=all" \
  -DCMAKE_BUILD_TYPE=Debug,ASAN,UBSAN -DWITH_SSE2=ON -DMONOLITHIC_BUILD=ON -DBUILD_SHARED_LIBS=OFF \
  -DOPENCV_EXTRA_MODULES_PATH=/home/evilpan/fuzzing/opencv_contrib/modules \
  /home/evilpan/fuzzing/opencv

make -j128 -C modules/wechat_qrcode

Ключевой момент — не использовать динамические библиотеки.,И даиспользовать статическую библиотеку,потому что AFL Для окончательного тестирования программа будет выполнять только статическую компиляцию покрытия кода и не будет учитывать динамическую компиляцию библиотеки.

Позже узнал cmake Не нужно указывать столько опций, достаточно указать afl-clang,config позже в make Если указано через переменные среды AFL_USE_ASAN Вот и все, АФЛ Выберем соответствующие параметры компилирования. обратитесь к: https://aflplus.plus/docs/fuzzing_in_depth/

Язык кода:javascript
копировать
$ cmake -DCMAKE_C_COMPILER=afl-clang-fast -DCMAKE_CXX_COMPILER=afl-clang-fast++ -DBUILD_SHARED_LIBS=OFF
$ env AFL_USE_ASAN=1 make -j32

Проверьте свои навыки

компилировать После завершения вы можете написатьтесткод.Но согласно предыдущемуиз pull-request, который также предоставляется при исправлении ошибок testcase:

Язык кода:javascript
копировать
TEST(Objdetect_QRCode_bug, issue_3478) {
    auto detector = wechat_qrcode::WeChatQRCode();
    std::string image_path = findDataFile("qrcode/issue_3478.png");
    Mat src = imread(image_path, IMREAD_GRAYSCALE);
    ASSERT_FALSE(src.empty()) << "Can't read image: " << image_path;
    std::vector<std::string> outs = detector.detectAndDecode(src);
    ASSERT_EQ(1, (int) outs.size());
    ASSERT_EQ(16, (int) outs[0].size());
    ASSERT_EQ("KFCVW50         ", outs[0]);
}

Вы можете обратиться к этому коду, чтобы написать наше из тестовая обвязка. Я менял прямо здесь. test_main.cpp,Не использовать структуру модульного тестирования, а писать самостоятельно.,инициал из test-harness Код выглядит следующим образом:

Язык кода:javascript
копировать
int main(int argc, char **argv) {
  if (argc < 2) return 1;
  std::string image_path(argv[1]);
  Mat src = imread(image_path, IMREAD_GRAYSCALE);
  if (!src.empty()) {
    auto detector = wechat_qrcode::WeChatQRCode();
    std::vector<std::string> outs = detector.detectAndDecode(src);
  }
  return 0
}

После модификации вам останется только переустановить модуль:

Язык кода:javascript
копировать
make -C modules/wechat_qrcode

Сгенерированный тестовый двоичный файл build/bin/opencv_test_wechat_qrcode:

Язык кода:javascript
копировать
afl-fuzz -i corpus/ -o output -t +2000 -- ./opencv_test_wechat_qrcode @@

corpus Я наугад бросил в него несколько файлов с искаженным QR-кодом и убежал!

Jack, slow fuzz

Хоть он и умеет бегать, но он медленный!

Предварительная оптимизация

Приведенный выше фазз-код слишком медленный и его необходимо оптимизировать! Корректировка организационной структуры! Передайте холод каждому фаззеру!

Поскольку предыдущий запуск считывает файл напрямую, интуитивной оптимизацией является использование AFL++ из persistent mode,Немного измените код,напрямую buffer Прочтите его как исходное изображение, как показано ниже:

Язык кода:javascript
копировать
int fuzz_buf(unsigned char *buf, size_t size) {
  Mat src = imdecode(Mat(1, size, CV_8UC1, buf), IMREAD_GRAYSCALE);
  if (!src.empty()) {
    auto detector = wechat_qrcode::WeChatQRCode();
    std::vector<std::string> outs = detector.detectAndDecode(src);
    return outs.size();
  }
  return -1;
}

__AFL_FUZZ_INIT();

int main(int argc, char **argv) {
  // if (argc < 2) return 1;
  // return fuzz(argv[1]);
#ifdef __AFL_HAVE_MANUAL_CONTROL
  __AFL_INIT();
#endif
  unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF;
  while (__AFL_LOOP(10000)) {
    int len = __AFL_FUZZ_TESTCASE_LEN;
    fuzz_buf(buf, len);
  }
  return 0;
}

Данное исполнение не требует @@ Теперь вы можете запустить его напрямую:

Язык кода:javascript
копировать
afl-fuzz -i corpus/ -o output -t +2000 -- ./opencv_test_wechat_qrcode_persist

Fuzzing cv::Mat

Вы можете видеть, что скорость значительно улучшилась! И пробежав более десяти минут, появился Крэш!

Оптимизируйте еще раз

Сначала остановите переднюю часть fuzzer Давайте проанализируем существующие сбой, а сбой во время выполнения примерно следующий:

Язык кода:javascript
копировать
$ ./opencv_test_wechat_qrcode output/default/crashes/id\:000001\,sig\:06\,src\:000478\,time\:871148\,execs\:98951\,op\:havoc\,rep\:4
terminate called after throwing an instance of 'cv::Exception'
  what():  OpenCV(4.7.0-dev) /home/jielv/fuzzing/opencv/modules/imgcodecs/src/loadsave.cpp:74: error: (-215:Assertion failed) size.width > 0 in function 'validateInputImageSize'

Aborted

на самом деле,Я немного разочарован тобой. Когда я выписал тебя,да Надеюсь, вы сможете сравнить Фурукаву. Я надеюсь, ты прибежишь после,ты можешь попробовать,Дай мне несколько быстрых segment вина. Для этого уровня не стоит выбрасывать несколько Abort Просто из.

Хотя есть и я -g из причин, но здесь из Abort Фактически, все они появляются выше из imdecode , это немного отклонилось от того, что я ожидал. Я, очевидно, хотел запустить декодирование QR-кода, но в итоге оно долгое время работало в ненужном месте. Хотя image codec Также поверхность атаки,Но я не хочу делать это сейчас,И этой поверхностью атаки, должно быть, воспользовались многие другие.,Вероятность возникновения проблем не очень велика.

Поэтому нам необходимо дополнительно оптимизировать код. Сейчас AFL Вариация изда jpg/png из картинок,Но мы хотим Мутациизна самом деледаQR-кодиз картиноксодержание!поэтомуэтот Есть две идеи для субоптимизации.:

  1. Обеспечить настройку мутации,Возвращайте по одному каждый раз МутацииизQR-код;
  2. Сдавайся AFL Он мутирует сам, но после мутации да содержимое из напрямую преобразуется в cv::Mat Затем выполните расшифровку QR-кода;

Независимо от того, какую идею вы используете, вам нужно уметь комбинировать изображения с cv::Mat Преобразуйте друг друга, иначе, даже если есть crash Также может оказаться невозможным создание законных изображений, что сделает их непригодными для использования.

Mat2Vector

Сначала я подумал о том, чтобы полениться и позволить ChatGPT помочь мне сгенерировать код для преобразования Mat в массив символов, как показано ниже:

Язык кода:javascript
копировать
std::vector<char> mat_to_vector(const cv::Mat& mat) {
    // Copy data from cv::Mat to vector<char>
    std::vector<char> data(mat.data, mat.data + mat.total() * mat.elemSize());
    return data;
}

Затем используйте оригинал ожидаемого изображения, чтобы imread читать как cv::Mat,и используйте вышеизложенноеизфункция преобразована в vector И сохраните его на диск для формирования нового прогноза, чтобы его можно было напрямую мутировать и генерировать при мутировании. cv::Mat:

Язык кода:javascript
копировать
int fuzz_buf(unsigned char *buf, size_t size) {
  // Mat src = imdecode(Mat(1, size, CV_8UC1, buf), IMREAD_GRAYSCALE);
  Mat src = Mat(std::vector<unsigned char>(buf, buf + size));
  return fuzz_mat(src);
}

Идеал прекрасен, но такой бег не дает результатов! Предполагаю, что Mat Кроме data данные,Должны быть метаданные,Используется для представления матрицы характеристик.,Например, строка/столбец,Непосредственное заполнение данных не может представлять оригинал из матрицы.,В результате при декодировании QR-кода возникает ошибка и она завершается очень рано.

cv::Mat

Поскольку лень ни к чему не приведет, я могу только серьезно взглянуть на Мэта.

cv::Mat да OpenCV используется для выражения n размерный массив изданных структур, используемых для представления n Размер одноканальной или многоканальной матрицы, обычно структура относительно компактна по сравнению с матрицей. Для разреженных данных из многомерных матриц обычно используется SparseMat выразить.

Для матриц/массивов M С точки зрения его расположение данных основано на data и step Определите, например, для двумерного массива:

Язык кода:javascript
копировать
M.at(i,j) = M.data + M.step[0] * i + M.step[1] * j

Уведомление M.step[i] >= M.step[i+1],фактически M.step[i] >= M.step[i+1]*M.size[i+1]。этотозначает, что для двумерной матрицы,данныеда Хранение по строкам из(построчно),Для данных трехмерной матрицы да сохраняется плоскость за плоскостью.

Наша цель — создать репрезентативное изображение с QR-кодом. Мат, лучше бы да можно было сохранять на диск и читать с диска, что нам удобно использовать afl-fuzz Укажите корпус и приступайте пух. Ю да интересно, есть ли какой-либо таргетинг на сериализацию/антисериализацию? cv::Mat из, я проверил и оказывается есть, сериализацияиз Код выглядит следующим образом:

Язык кода:javascript
копировать
cv::Mat img = cv::imread("example.jpg"); // Load an image
cv::FileStorage fs("example.yml", cv::FileStorage::WRITE); // Create a file storage object for writing
fs << "image" << img; // Write the image to the file
fs.release(); // Close the file

Обратный процесс сериализации и сериализации аналогичен:

Язык кода:javascript
копировать
cv::Mat img;

cv::FileStorage fs("example.yml", cv::FileStorage::READ); // Create a file storage object for reading
fs["image"] >> img; // Read the image from the file
fs.release(); // Close the file

Здесь да будет cv::Mat Сериализовано в YAML данные,Вывод в следующем формате:

Язык кода:javascript
копировать
%YAML:1.0
---
img: !!opencv-matrix
   rows: 480
   cols: 640
   dt: u
   data: [ 103, 103, 104, 107, 110, 112, 112, 111, 114, 113, 113, 115,
           ...
           134, 135, 134, 132 ]

Если YAML Документы служат корпусом, который снова включает в себя YAML из синтаксического анализа и FileStorage Код не имеет ничего общего с кодом, и требования другие. Однако из сериализданных мы можем увидеть одну вещь, а именно: cv::Mat Кроме data данные содержат только дополнительные элементы rows、cols и дт. в dt должно означать data type,u да CV_8U Аббревиатура из.

Поскольку это черно-белое изображение, 480x640. изQR-код картинки, если мы хотим мутировать cv::Mat,Просто оставьте строки/столбцы/типы неизменными.,против data Проводится на региональном уровне bitflip Просто мутируйте!

Однако только bitflip Мутация из космоса будет такой же высокой, как 2^(640*480),Несомненно, данные геометрии.,даже еслида Толькопротивмаленький размеркартинанравиться 20x20 Это также неприемлемо. Поэтому мы по-прежнему возлагаем надежду на AFL из Обратная связь по покрытию может генерировать соответствующиеиз Мутации!

First Blood

использовать Вышеуказанная стратегия оптимизирует длину послеобрезанного корпуса, только один 29x29 изQR-кодкартинагенерироватьизматрица как исходнаякорпусруководить Мутации:

Язык кода:javascript
копировать
int fuzz_buf(void *buf, size_t size) {
  // Mat src = imdecode(Mat(1, size, CV_8UC1, buf), IMREAD_GRAYSCALE);
  if (size < 841) return -1;
  Mat src = Mat(29, 29, CV_8U, buf);
  return fuzz_mat(src);
}

Когда я начал бежать, я обнаружил, что моя скорость снова стала очень низкой.,Я думаю, корпус все еще слишком велик,Пусть он поработает в фоновом режиме некоторое время,Затем Иди и посмотри Понятно Две серии «Туалетной бумаги другого мира»。возвращатьсяпосле Обнаружил, что на самом деле существует crash:

После краткого анализа я обнаружил, что все они имеют один и тот же код. сбой, оптимизированный poc Результат выполнения следующий:

Язык кода:javascript
копировать
$ opencv_test_wechat_qrcode poc.bin
/home/evilpan/fuzzing/opencv_contrib/modules/wechat_qrcode/src/zxing/qrcode/detector/detector.cpp:1022:50: runtime error: signed integer overflow: -2147483648 + -2147483648 cannot be represented in type 'int'

этотдаодинцелочисленное переполнение,Появиться в qrcdoe При расчете размеров при обнаружении:

Язык кода:javascript
копировать
int Detector::computeDimension(Ref<ResultPoint> topLeft, Ref<ResultPoint> topRight,
                               Ref<ResultPoint> bottomLeft, float moduleSizeX, float moduleSizeY) {
    int tltrCentersDimension = ResultPoint::distance(topLeft, topRight) / moduleSizeX;
    int tlblCentersDimension = ResultPoint::distance(topLeft, bottomLeft) / moduleSizeY;

    float tmp_dimension = ((tltrCentersDimension + tlblCentersDimension) / 2.0) + 7.0; // Проблема в этой строке
    int dimension = cvRound(tmp_dimension);
    int mod = dimension & 0x03;  // mod 4

    switch (mod) {  // mod 4
        case 0:
            dimension++;
            break;
            // 1? do nothing
        case 2:
            dimension--;
            break;
    }
    return dimension;
}

При расчете опорных точек tltrCentersDimension + tlblCentersDimension Произошло целочисленное переполнение, PoC следующее:

PoC: целочисленное переполнение

конечно,этот PoC Сканирование кода непосредственно для да не может выявить из, потому что мы передали исходные данные изда, и да умер в detector среди.

Лишний

Хотя теперь можно производить некоторые сбои,Но изображение не является бинарным, а представляет собой изображение в оттенках серого.,потому чтонаш оригинализкорпусда Mat.data() Сохраненный в виде двоичных данных, каждый пиксель в этих данных также 8 bit из, но есть только два значения, а именно да 0 и 255, и в процессе мутации оно становится изображением в оттенках серого.

Чтобы решить эту проблему,Мы можем только восстановить структуру,Убедитесь, что каждый байтиз Мутацииможет производить эффективныеиздвоичное изображение。Каждый пиксель изображения занимает всего 1 бит, благодаря памяти да байтовой адресации, каждый байт может быть сохранен 8 пикселей.

Написал MatWrapper инкапсулировать cols、rows、type и data данные и добавить serialize/deserialize Метод реализации сериализации:

Язык кода:javascript
копировать
class MatWrapper {
public:
  int mRows;
  int mCols;
  int mType;
  int mSize;
  std::vector<uchar> mBuf;

  MatWrapper() {}

  void save(const std::string& filename, bool compact=false) {
    std::ofstream fs(filename);
    fs << serialize(compact);
    fs.close();
  }

  void load(const std::string& filename, bool compact=false) {
    std::stringstream ss;
    std::ifstream file(filename, std::ios::binary);
    ss << file.rdbuf();
    deserialize(ss.str(), compact);
  }

  void fromImage(const std::string& filename) {
    auto mat = imread(filename, IMREAD_GRAYSCALE);
    mRows = mat.rows;
    mCols = mat.cols;
    mType = mat.type();
    // assert(mat.elemSize() == 1);
    mSize = mat.total() * mat.elemSize();
    mBuf = std::vector<uchar>(mat.data, mat.data + mSize);
  }

  void toImage(const std::string& filename) {
    imwrite(filename, get());
  }

  Mat get() { return Mat(mRows, mCols, mType, mBuf.data()); }

  std::string serialize(bool compact = false) const { }
  bool deserialize(const std::string& buf, bool compact = false) { }
  // ...
};

compact Выразите, будет ли да 8 Сжатие пикселей есть 1 Байтс, полный код довольно длинный, и я не буду его здесь публиковать. После написания я сначала пакетно конвертировал предыдущий корпус изображений изQR-кода в пользовательские сериализацииизданные, а затем использовал. AFL Укажите новый корпус для мутации пух. Когда у меня кончились деньги, я закодировал себя bug (смущенный), после ремонта по одному, после того, как оно, наконец, может быстро кончиться изцелочисленное снова переполнение, и на этот раз из PoC Также есть настоящие черно-белые изображения с QR-кодом.

Но да! Новый вариант использования также работает очень медленно.,Возможно, при даантисериализации было слишком много изменений.,Результирующая скорость фактически почти такая же, как и у стандартного формата сжатого изображения.,В общем, такое ощущение, что это пустая трата времени.,но Сдавайся Он работает какое-то время。

QR-код

На вершине Fuzzer При работе в фоновом режиме я также ясно подумал о проблеме, связанной с вариантом использования этого теста. Хотя текущая мутация стратегии может генерировать двоичные Bitmap изображение, но не всегда допустимо использование QR-кода, поэтому покрытие кода всегда detect Этап не может быть пройден и не выполняется. decode

Идеальная стратегия может каждый раз генерировать случайный, легальный QR-код.,И провести мутацию на основе решетки из. с этой целью,Нам нужно сначала понять, как реализован QR-кодиз.

базовая структура

QR-код обычно состоит из нескольких частей, как показано ниже:

ISO/IEC 18004 - QR Code bar code symbology specification

Кроме того, существует микро-QR-код M3, который содержит только одну точку привязки, но он используется относительно редко и не может быть отсканирован WeChat. Я не буду о нем здесь рассказывать.

Краткое введение в каждую часть:

  • Quiet Zone: Вокруг QR-кода имеется белая рамка, а цвет фона должен отличаться от цвета QR-кода, чтобы он не влиял на анализ;
  • Postion Detection Patterns: Режим определения положения, также называемый точкой привязки, используется для определения местоположения QR-кода. Используйте точечную сетку (модуль), указывающий размер внешней черной границы да; 7x7,Размер черного блока посередине — да. 3x3
  • Separators for Postion Detection Patterns: из разделительной линии вокруг опорной точки ширина линии равна одной пунктирной сетка;
  • Timing Patterns: Режим синхронизации для позиционирования x/y Когда вал QR-код погнут, его можно в определенной степени отремонтировать, согнув эти две линии;
  • Alignment Patterns: режим выравнивания, в Version 2 и позже использовался для дальнейшего облегчения выравнивания. Каждый шаблон выравнивания имеет размер черной сетки. 5x5,белая сетка 3x3,Черная точка посередине занимает один квадрат. Режим выравнивания по номеру и Версия связанная;
  • Format Infomation: Информация о формате, учет 30 точечная сетка, занимающая обе стороны 15 Каждый из них имеет одинаковый контент и служит резервной копией друг друга;
  • Version Information: Информация о версии также имеет два резервных блока, каждый из которых занимает 3x6 размер;
  • Data and Error Correction Codewords: Область данных содержит изданный код кода и информацию для исправления ошибок;

QR-кодизмминимальная единица точечной сетки (модуль),Размер точечной сетки, занимаемый длиной стороны QR-кода, называется размером QR-кодиз (Dimension).,Связанные с размером и версией:

Язык кода:javascript
копировать
Dimension = Version * 4 + 17

Например, когда Version равный 2 При этом длина стороны равна да 25 точечная сетка:

Format Information Эта область содержит такую ​​информацию, как уровни исправления ошибок. Как упоминалось ранее, всего их количество. 15 Пунктирная сетка, включающая:

  • Уровень исправления ошибок: 2-точечная сетка, то есть 4 уровня исправления ошибок;
  • данныемаска: 3 Пунктирная сетка, то есть 8 тип маски;
  • Код исправления ошибок: 10 баллов;

Использование кода исправления ошибок BCH Код, используемый из Code Words Просто сохраните его в изданной области, упомянутой ранее.

стратегия мутации

Изучите основы QR-кодизпосле,Мы хотя бы знаем, что можно и что нельзя менять в QR-коде. Кодирование QR-кода довольно сложное из-за,Хотя мы можем использовать существующую стратегию кодирования для генерации QR-кода.,Но это заставит нас пропустить уязвимости, которые могут быть связаны с проблемами кодирования.

Соблюдение принципа: сначала беги, потом разговаривай.,Я написал очень уродливый прототип, используя Python для деления трех на пять и деления на два.,Сначала да генерирует случайный изQR-код:

Язык кода:javascript
копировать
def random_qrcode() -> qrcode.QRCode:
    version = randint(1, 40)
    box_size = randint(1, 8)
    border = 1
    error_correction = randint(0, 3)
    mask_pattern = randint(0, 7)
    data = randstr(randint(1, 25))
    
    qr = qrcode.QRCode(
        version=version,
        error_correction=error_correction,
        box_size=box_size,
        border=border,
        image_factory=None,
        mask_pattern=mask_pattern)
    qr.add_data(data)
    qr.make()
    return qr

make после qrcode из modules Он уже сгенерирован, поэтому мутируем его на его основе:

Язык кода:javascript
копировать
def mutate(qr: qrcode.QRCode, add_buf):
    if not add_buf or len(add_buf) == 1:
        # do not mutate
        return
    # flip modules in qrcode randomly
    width = len(qr.modules)
    rng = random.Random()
    flipped = set()
    for i in range(0, len(add_buf) - 1, 2):
        val = add_buf[i] + (add_buf[i+1] << 8)
        if val in flipped:
            continue
        flipped.add(val)
        rng.seed(val)
        x = rng.randint(0, width - 1) # col
        y = rng.randint(0, width - 1) # row
        # print("flip", (x, y))
        # avoid position patterns, 7x7 and 1 space
        if x < 8 and y < 8:
            continue
        if x < 8 and y >= (width - 8):
            continue
        if x >= (width - 8) and y < 8:
            continue
        qr.modules[y][x] = not qr.modules[y][x]

qr.modules да представляет собой сетку точек из двумерного массива, мы из стратегии мутации Очень просто и грубо,Просто случайным образом переверните сетку точек непосредственно на основе введенных данных.,Черное из становится белым из,Белое из становится черным. Несколько небольших оптимизаций:

  1. использовать Random Грядущий генерал 0xffff Размер из случайного числа scale по ширине width вне диапазона;
  2. Если точки были перевернуты, нет необходимости переворачивать их снова;
  3. Случайным образом переверните диапазон и исключите три угла и области меток позиционирования;

Custom Mutators

Теперь мы можем генерировать случайные картинки из QR-кода! Далее вам нужно объединить его с Fuzzer Совместить. В официальной документации Custom Mutators in AFL++ упомянутое в мы можем скомпилировать .so и пройти AFL_CUSTOM_MUTATOR_LIBRARY переменные среды дают AFL++ Предоставляет пользовательские мутаторы, а также может использовать Python API предоставить мутаторы.

Поэтому мы из мутатора Следующее:

Язык кода:javascript
копировать
def fuzz(buf, add_buf, max_size):
    """
    Called per fuzzing iteration.
    """
    qr = random_qrcode()
    mutate(qr, add_buf)
    img = qr.make_image()
    stream = BytesIO()
    img.save(stream, "png")
    ret = stream.getvalue()
    if len(ret) > max_size:
        return bytearray(buf)
    return bytearray(ret)

Примечание: fuzz Интерфейс параметров buf Обычно содержит оригинал corpus из контента, add_buf Затем да возвращает содержимое после мутации, здесь да PNG данные. Поэтому я хочу add_buf Модификация как источник вариаций modules на самом деле с да что-то не так. В тот момент я ошибочно подумал, что. add_buf да Случайные данные, но энтропии совсем не хватает, поэтому входные данные позже напрямую игнорируются, и все генерируется случайным образом.

сохрани это как random_qrcode.py И для запуска используйте следующую команду:

Язык кода:javascript
копировать
env AFL_CUSTOM_MUTATOR_ONLY=1 PYTHONPATH=$PWD/mutators AFL_PYTHON_MODULE=random_qrcode afl-fuzz -i corpus/ -o output -t +9000 -- ./opencv_test_wechat_qrcode_persist2

Здесь я уточнил AFL_CUSTOM_MUTATOR_ONLY=1,ненужный AFL сама измутация, потому что AFL мутация да основана на исходном корпусе, и я не хочу мутировать на двоичном уровне исходной картинки, иначе она вернется к исходной картинке. Теперь мы каждый раз генерируем случайную картинку из QR-кода, и да это определенно законно из PNG формат, чтобы избежать исключений при декодировании изображений. Я также установил исходный корпус для представления координат точек, а не изображений.

конечно,этот fuzzer Так медленно бежать! Это потому, что каждый раз, когда мы его генерируем, нам нужно сначала сгенерировать QR-код, мутировать его, а затем закодировать в PNG Изображение, а затем введите изображение в цель для анализа.

Решение можно передать C++ Перейдите непосредственно к созданию QR-кода, а затем преобразуйте QR-код непосредственно в cv::Mat Перейти в качестве входных данных. С одной стороны, это может сэкономить PNG С другой стороны, от процесса кодирования и декодирования также можно избавиться. Python изполагаться。QR-Code-generator Возможно, это хорошее решение. Однако, учитывая предыдущие неудачные попытки Лишнеза, он не уверен, насколько сильно это может улучшить скорость.

Кроме того, текущие отзывы о покрытиииз Мутациина самом деледаограниченныйиз(если естьизразговаривать),Из документации,LibFuzzer Поддержка пользовательских мутаций может быть лучше. и LibFuzzer Может естественным образом поддерживать многоядерность без необходимости использования AFL мне нужно сделать их кучу самому slave。

В любом случае, окончательный результат работы:

Язык кода:javascript
копировать
$ afl-whatsup -s output/
/usr/local/bin/afl-whatsup status check tool for afl-fuzz by Michal Zalewski

Summary stats
=============

       Fuzzers alive : 17
      Total run time : 32 days, 13 hours
         Total execs : 8 millions, 198 thousands
    Cumulative speed : 36 execs/sec
       Average speed : 2 execs/sec
       Pending items : 567 faves, 22476 total
  Pending per fuzzer : 33 faves, 1322 total (on average)
       Crashes saved : 0
         Hangs saved : 0
Cycles without finds : 0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0/0
  Time without finds : 35 seconds

Ну, хотя OpenCV "Очень безопасно", но библиотека разбора даQR-кода не единственная! Вы нашли еще одну часто используемую библиотеку синтаксического анализа ZXing Зайди в тест, оказывается, проблему еще можно выяснить!

Подвести итог

Эту статью можно рассматривать как типичный пример даиз Fuzzing Путь добычи уязвимостей. Используйте его первым Generic Fuzzer Запустите, а затем улучшите стратегию благодаря постоянному углубленному пониманию кода. мутации, со временем стали Structure Aware Fuzzing из Результаты! Хотя AFL Хорошо иметь челнок и позволить машине работать за вас, но если вы хотите получить лучшие результаты, вам все равно придется оптимизировать ее самостоятельно. Если вы не посмотрите на код, вы не сможете понять причину, даже если обнаружите проблему, или не сможете написать приложение. награда-0 или отправьте ошибку, если необходимо patch В результате другие разработчики впоследствии revert И раскритиковали и пригвоздили к позорному столбу истории. Таким образом, сочетание автоматического аудита кода часто позволяет достичь более эффективных результатов анализа уязвимостей.

Справочная ссылка

Заявление об авторских правах: Свободное воспроизведение – некоммерческое – непроизводное – сохранение авторства (CC 4.0 BY-SA)

Исходный адрес: https://cloud.tencent.com/developer/article/2345087

boy illustration
Углубленный анализ переполнения памяти CUDA: OutOfMemoryError: CUDA не хватает памяти. Попыталась выделить 3,21 Ги Б (GPU 0; всего 8,00 Ги Б).
boy illustration
[Решено] ошибка установки conda. Среда решения: не удалось выполнить первоначальное зависание. Повторная попытка с помощью файла (графическое руководство).
boy illustration
Прочитайте нейросетевую модель Трансформера в одной статье
boy illustration
.ART Теплые зимние предложения уже открыты
boy illustration
Сравнительная таблица описания кодов ошибок Amap
boy illustration
Уведомление о последних правилах Points Mall в декабре 2022 года.
boy illustration
Даже новички могут быстро приступить к работе с легким сервером приложений.
boy illustration
Взгляд на RSAC 2024|Защита конфиденциальности в эпоху больших моделей
boy illustration
Вы используете ИИ каждый день и до сих пор не знаете, как ИИ дает обратную связь? Одна статья для понимания реализации в коде Python общих функций потерь генеративных моделей + анализ принципов расчета.
boy illustration
Используйте (внутренний) почтовый ящик для образовательных учреждений, чтобы использовать Microsoft Family Bucket (1T дискового пространства на одном диске и версию Office 365 для образовательных учреждений)
boy illustration
Руководство по началу работы с оперативным проектом (7) Практическое сочетание оперативного письма — оперативного письма на основе интеллектуальной системы вопросов и ответов службы поддержки клиентов
boy illustration
[docker] Версия сервера «Чтение 3» — создайте свою собственную программу чтения веб-текста
boy illustration
Обзор Cloud-init и этапы создания в рамках PVE
boy illustration
Корпоративные пользователи используют пакет регистрационных ресурсов для регистрации ICP для веб-сайта и активации оплаты WeChat H5 (с кодом платежного узла версии API V3)
boy illustration
Подробное объяснение таких показателей производительности с высоким уровнем параллелизма, как QPS, TPS, RT и пропускная способность.
boy illustration
Удачи в конкурсе Python Essay Challenge, станьте первым, кто испытает новую функцию сообщества [Запускать блоки кода онлайн] и выиграйте множество изысканных подарков!
boy illustration
[Техническая посадка травы] Кровавая рвота и отделка позволяют вам необычным образом ощипывать гусиные перья! Не распространяйте информацию! ! !
boy illustration
[Официальное ограниченное по времени мероприятие] Сейчас ноябрь, напишите и получите приз
boy illustration
Прочтите это в одной статье: Учебник для няни по созданию сервера Huanshou Parlu на базе CVM-сервера.
boy illustration
Cloud Native | Что такое CRD (настраиваемые определения ресурсов) в K8s?
boy illustration
Как использовать Cloudflare CDN для настройки узла (CF самостоятельно выбирает IP) Гонконг, Китай/Азия узел/сводка и рекомендации внутреннего высокоскоростного IP-сегмента
boy illustration
Дополнительные правила вознаграждения амбассадоров акции в марте 2023 г.
boy illustration
Можно ли открыть частный сервер Phantom Beast Palu одним щелчком мыши? Супер простой урок для начинающих! (Прилагается метод обновления сервера)
boy illustration
[Играйте с Phantom Beast Palu] Обновите игровой сервер Phantom Beast Pallu одним щелчком мыши
boy illustration
Maotouhu делится: последний доступный внутри страны адрес склада исходного образа Docker 2024 года (обновлено 1 декабря)
boy illustration
Кодирование Base64 в MultipartFile
boy illustration
5 точек расширения SpringBoot, супер практично!
boy illustration
Глубокое понимание сопоставления индексов Elasticsearch.
boy illustration
15 рекомендуемых платформ разработки с нулевым кодом корпоративного уровня. Всегда найдется та, которая вам понравится.
boy illustration
Аннотация EasyExcel позволяет экспортировать с сохранением двух десятичных знаков.