퍼징 연구 안내서

퍼징(fuzzing)에 입문하는 것은 쉬운 일이 아닙니다. 저는 구글에서 처음으로 이 주제에 대해 검색했던 때를 기억합니다. 블랙/화이트/그레이와 같은 다양한 색상의 이름을 가진 기법들, 그리고 변이 및 모델 기반 생성 등 정말 많은 기법이 존재합니다. 그리고 모든 퍼저(fuzzer)에는 이 모든 기법이 조금씩 다 포함되어 있는것 같습니다. 너무 복잡한 분야입니다. 마치 어두운 숲으로 들어가는 것처럼 덩굴이 어디에서 시작되고 끝나는지조차 알 수 없습니다.

일반적으로 모든 연구에 대한 저의 시작점은 위키피디아입니다. 이 주제에 대해 위키피디아를 살펴보겠습니다.

– 퍼저는 입력이 처음부터 새로 생성되는지 또는 기존 입력을 수정하여 생성되는지에 따라 생성 기반(generation-based) 또는 변이 기반(mutation-based)으로 구분합니다.
– 퍼저는 입력 구조를 인식하는지에 따라 우둔함(dumb) 또는 영리함(smart)으로 구분합니다.
– 퍼저는 프로그램 구조를 인식하는지에 따라 화이트, 그레이 또는 블랙 박스로 구분합니다.

Wikipedia

“생성 기반”은 일반적으로 그렇게 할 수 있는 모델이 있음을 의미합니다. 그렇다면 “스마트” 퍼징과 “생성 기반” 퍼징의 차이점은 무엇일까요? 화이트나 그레이는 어떤 의미이며, 우둔함(dumb)은 무엇일까요? 여러분이 처음부터 이 분야를 알고 있고, 모든 것을 조금씩 볼 시간이 있었다고 해도, 변화속도가 너무 빨라 매년 나오는 수십 개의 새로운 퍼저와 논문을 따라잡기가 어렵습니다.

fuzzing-survey.org [1] 프로젝트에 기록된 퍼저의 수가 200에 다다르고 있습니다. (이 숫자는 새로운 퍼저를 공개하지 않는 퍼징 논문을 제외한 것입니다) 이렇게 점차 복잡해지는 상황에 어떻게 대처해야 할까요?

TL; DR: 많은 수의 퍼저를 줄일 수는 없지만, 퍼저를 이해할 수 있는 프레임워크를 통해 이해하기 쉽게 만들 수 있습니다. 우리의 연구 [2]에서는 모든 퍼저를 다섯 부분으로 나누어 더 빠르고 간단하게 이해하고 분석할 수 있게 합니다. 게시글 끝에 있는 다이어그램을 참조하거나, 아래의 유튜브를 통해 볼 수 있습니다.

숲으로 가는 첫걸음

대부분의 사람들이 처음 배울 때 사용하는 구글 검색을 해보겠습니다. 위에서 언급했듯이, 처음에 나타나는 것은 혼란스럽고 이상한 용어들입니다. 그러나 여기에는 퍼징에 대해 공인된 단순한 정의가 존재하지 않으며, 심지어 퍼징의 핵심에 대한 명확한 정의조차 없습니다. 저는 트위터에서 학계와 실무자들 모두가 참여하는 토론을 몇 번 본적이 있습니다. 여기서 모든 사람은 퍼저의 핵심이 무엇인지에 대한 자신만의 생각을 가지고 있었습니다.

위키피디아에서는 다음과 같이 정의합니다. 퍼징 또는 퍼즈 테스팅(fuzz testing)은 컴퓨터 프로그램에 대한 입력으로 유효하지 않거나, 예상치 못한, 또는 무작위의 데이터를 제공하는 자동화된 소프트웨어 테스트 기법입니다. 그런 다음 프로그램의 충돌, 내장 코드 검증(assertion) 오류 또는 잠재적인 메모리 누출과 같은 예외들을 모니터링합니다.

다음과 같은 두 가지 구성 요소를 볼 수 있습니다.

  1. 반드시 유효하지 않은 무작위적인 입력을 생성합니다.
  2. 프로그램의 충돌을 일으키는것을 추구합니다.

첫 번째 부분은 우리가 결정할 아래의 정의와 크게 다르지 않지만, 문제가 있습니다. 그 문제는 입력이 생성되는 방식과 심지어 입력 생성의 목표까지 가정한다는 것입니다. 일부 퍼저는 “유효하지 않은” 입력을 생성하는 것을 목표로 하지 않는 퍼저들이 존재하며, 무작위성을 기반으로 생성되지 않는 퍼저들이 존재합니다. 어떤 것을 정의할때는 특정 방법을 지향하는 내용을 포함해서는 안됩니다. 퍼저의 저자들은 입력을 생성하는 방법에서 뛰어난 창의성을 보여주었습니다. 매번 새로 출판된 논문과 공개된 도구의 혁신성에 감탄합니다. 제한적인 정의로 인해 혁신적인 아이디어가 방해받지 않도록 하는것이 중요합니다.

위키피디아 두 번째 정의는 더욱 오해의 소지가 있습니다. 문장 자체에서 알 수 있듯이 충돌에 대한 정의가 없습니다. 심지어 일부 퍼저는 더는 충돌을 추구하지 않습니다. 이러한 목표는 사용자가 결정하도록 해야 합니다.

정의와 첫 번째 모델

퍼징은 프로그램이 정확성 정책을 위반하는지 테스트하기 위해 생성된 입력으로 프로그램을 반복적으로 실행하는 프로세스를 의미합니다.

Wikipedia

이것이 우리가 조사를 위해 정의한 내용입니다(또는 더 정확하게는, 공식화하기 위한 단순화된 버전입니다). 중요한 것은 다음과 같이 정의에 없는 것입니다.

  • 입력이 어떻게 생성되었는지는 정의하지 않습니다.
  • 퍼저가 구현되는 방식에서 무작위성이 중요한 구성 요소이지만, 무작위성에 대해 정의하지 않습니다.
  • 퍼징의 목표를 정의하지 않습니다. 단지, 사용자가 적절하다고 생각하는 대로 정의할 수 있는 “정확성 정책”만 정의합니다.

이제 동적, 자기 반복적, 테스트 프로세스 같은 퍼징의 핵심에 도달할 수 있을 만큼 충분히 구체적인 것과 모든 기법과 퍼저/사용자 모두가 원하는 목표를 포괄할 수 있을 만큼 일반적인 것이 남았습니다. 그러나 너무 일반적이기 때문에 여러분은 이 정의가 퍼저를 이해하는 데 도움이 되지 않는다고 말할 수도 있습니다. 우리는 이 점을 해결하기 위해 범용적인 모델을 구축할 것입니다.

먼저, 정의를 기반으로 한 간단한 모델부터 시작합니다. 퍼저는 기본적으로 다음의 두 가지 작업만 수행합니다.

  1. InputGen은 입력을 생성합니다.
  2. InputEval은 테스트 대상 프로그램에서 이 입력을 실행하고 정확성 정책을 위반하는지를 점검합니다(e.g. “세그멘테이션 오류가 발생하는가”).

그리고 이 두 단계는 사용자가 선택한 횟수만큼 무한으로 반복됩니다.

모델 구체화

위에서 설명한 모델은 1990년 Miller가 처음 제안한 퍼저의 접근 방법을 충분히 설명할 수 있습니다. 하지만 그 이후로 많은 발전을 하면서 더 복잡해졌기 때문에, 우리의 모델은 현재의 최신 기술을 보다 원활하게 이해할 수 있도록 이를 반영해야 합니다.

퍼저를 개선하기 위해 가장 먼저 한 일은 메인 루프가 아니라, 루핑 프로세스를 더욱 효율적으로 만들기 위해 존재하는 초기 준비 단계를 강화하는 것입니다. 우리가 PreProcess 함수라고 부르는 것은 많은 것을 포함합니다. 예를 들어, 입력 생성을 준비하는 데 사용할 수 있습니다. 이는 입력을 생성하는 모델을 만들거나 시드(seed)를 준비함으로써 가능합니다. 퍼저는 일반적으로 이 시드를 수정하여 새로운 입력을 생성합니다. 이 첫 단계는 프로그램 자체를 준비하는 데에도 사용할 수 있습니다. 예를 들어, 프로그램을 실행하는 동안 정확성 정책을 탐지할 수 있습니다. 이는 추려내기(sanitizing)라고 불리며, 이 주제에 대한 자세한 내용은 이 뛰어난 연구 [3]를 참조합니다.  PreProcess 단계는 프로그램을 고안해서 실행에 대한 자세한 정보를 얻을 수 있는 좋은 시점이기도 합니다. 이것은 블랙, 그레이 및 화이트 박스 퍼징으로 구분합니다. 이 주제에 대한 자세한 설명은 우리의 연구 [2]를 참조합니다.

다음으로 추가된 함수는 Schedule 함수입니다. 이 함수는 계획 단계에 필수적으로 포함됩니다. 여기에서 퍼저는 목표를 달성하는 가장 효과적인 방법을 결정합니다 (하지만 목표를 정의하는 것은 간단하지 않습니다). 실제로 스케줄링은 종종 다음 입력 세트를 생성하기 위해 수정될 시드를 선택하거나, 모델을 사용하여 입력을 생성하는 방법에 대해 나타냅니다. 학계에서는 지난 몇 년간, 이 주제에 집중해 왔으며, 특히, 가장 주목할 만한 연구는 AFLFast [4] 입니다. 스케줄링은 “퍼저에 일정한 시간이 주어질 때, 이 시간을 어떻게 사용할 것인가?” 라는 에너지 할당 문제에 비유되기도 합니다.

마지막으로, 가장 복잡하지만 가장 영향력 있는 단계인 “구성 업데이트” 또는  ConfUpdate라고 하는 단계입니다. 이 단계는 퍼저가 학습하는 단계입니다.  Schedule이 자원를 어떻게 할당할까에 관한 것이라면 이 단계는 정보에 관한 것입니다. 프로그램을 실행할 때마다 너무 많은 데이터가 생성될 가능성이 있으므로 모든 데이터를 저장할 수는 없습니다. 따라서 퍼저는 마지막 실행에서 가장 유용한 데이터를 선택해야 합니다. 이것이 블랙 박스 퍼저와 화이트 및 그레이 박스 퍼저를 구분하는 특성입니다. 블랙 박스 퍼저는 실행으로부터 아무것도 (또는 거의 아무것도) 학습하지 않습니다. 반면에, 화이트 및 그레이 박스 퍼저는 각 실행이 다음의 모든 실행에 영향을 미칠 수 있습니다. 여기에서 Sidewinder [5]에 의해 처음 창안되고 AFL [6]로 대중화된 진화 알고리즘이 개발됩니다. (이 알고리즘의 예는 아래를 참조합니다.)

Final Fuzzing Model:

이론에서 실전으로

모델을 만드는 목표는 퍼저의 방식을 더 잘 이해하기 위함입니다. 이제 뛰어난 모델을 준비했으니 어떻게 작동하는지 살펴보겠습니다.

간단한 zzuf부터 시작하겠습니다. 이것은 초기에 등장한 퍼저 중 하나입니다. 에서 언급했듯이 처음에 나온 퍼저들은 이해하기 쉽습니다.

  • zzufInputGen은 시드의 변이(수정)입니다.
  • InputEval은 생성된 입력에 대한 프로그램의 원시 실행입니다.

이게 전부입니다. zzuf는 다른 함수들을 구현하지 않습니다.

이제 한 단계 높여서 AFL을 살펴봅시다. 우리의 모델이 다양한 기능을 가진 이 퍼저를 제대로 분류할 수 있을까요💪? 여기에서는 퍼징을 사용자 지정할 수 있는 수많은 옵션을 제공하기 위해 AFL의 “표준 사용”에 대해 설명합니다.

  1. PreProcess: AFL은 프로그램의 각 분기가 특정 입력으로 실행된 횟수를 읽도록 프로그램을 고안해서 캠페인을 준비합니다. 이 정보를 분기 적중 횟수(branch-hit-count)라 합니다.
  2. InputGen: AFL은 시드 기반 그레이 박스 퍼저이므로 입력 생성은 실제로 zzuf와 유사한 방식으로, 시드를 수정하여 새로운 입력을 생성합니다. (실제로 내부적으로는 상당히 달라서 이 분야의 전문가들은 여기에 절대 동의하지 않을 수도 있지만, 자세한 내용은 생략합니다😝.)
  3. InputEval: 프로그램이 실행됩니다. (1)단계에 의해 설정된 정보를 바탕으로 실행하게 됩니다.
  4. 그레이 박스 퍼저의 핵심은 다음과 같습니다. ConfUpdate단계에서 AFL은 방금 실행한 입력이 다른 것과 충분히 다른 경우 이를 시드에 추가합니다. “충분히 다른지” 여부를 판단하는 함수를 적합성 함수라고 합니다. 관심이 있는 독자는 이 주제에 대해 특별히 내가 작성한 논문을 참조할 수 있습니다(참조: Ankou).
  5.  Schedule은 지루해 보일 수 있습니다. AFL은 라운드 로빈 방식으로 각 시드를 하나씩 검토합니다. 그러나 좀 더 복잡하게, AFL은 일부 내부 경험적 접근(heuristics)에 따라 각 시드에 다른 수의 실행을 할당합니다.

여전히 난해한 부분이 있다면, 우리의 연구 [2]를 참조하세요. 이 논문에서 우리는 이 프레임워크에 대해 50개 이상의 퍼저를 적용했습니다😉. 이렇게 구분함으로써 내가 생각하는 퍼징에 대한 방식을 형성했으며, 연구에도 큰 도움이 되었습니다. 나는 논문을 읽을 때마다 “여기서 개선하려고 하는 단계는 무엇인가”라고 자문합니다. 예를 들어, 앞에서 언급한 AFLFastSchedule함수에 대해 개선한 방식입니다. (또한, 이 스케줄링에 필요한 정보를 수집하기 위해 ConfUpdate를 약간 수정합니다.) 이 프레임워크가 여러분에게도 도움이 되기를 바랍니다.

마지막 팁으로, 어떤 주제를 잘 이해하기 위해서는 해보는 것이 필수적인 부분임을 강조하고자 합니다. Andreas Zeller 그룹에서는 훌륭한 퍼징 북 [7]을 만들었습니다. 온라인 Jupyter notebooks에서는 퍼저를 사용하여 직접 해볼 수 있는 간단하고 재미있는 방법을 제공합니다.

Reference

[1] https://fuzzing-survey.org/
[2] The Art, Science, and Engineering of Fuzzing: A Survey, TSE 2019
[3] SoK: Sanitizing for Security, IEEE S&P 2019
[4] AFLFast, https://github.com/mboehme/aflfast
[5] Sidewinder: An Evolutionary Guidance System For Malicious Input Crafting, Black Hat USA 2006
[6] AFL, https://lcamtuf.coredump.cx/afl/
[7] The Fuzzing Book, https://www.fuzzingbook.org/

Valentin Manès

After spending three years as a researcher at Cyber Security Research Center (CSRC) at KAIST, Korea, Valentin Manès is now a Software Engineer at Qonto, France. He received his Master’s degree from Télécom ParisTech with a specialization in information security. His interest is towards improving bug finding ability in automatic software testing.

역자 주

이글은 Valentin 연구원이 쓴 원문을 번역한 글입니다.

5 명이 이 글에 공감합니다.