AFL++로 퍼즈 테스트를 더 효과적으로 하는 요령

Tips for more effective fuzz testing with AFL++

nullprogram.com ▲ 152 댓글 28 luu

요약

AFL++ 퍼즈 테스트는 설정과 시험 코드를 조금만 다듬어도 더 빠르게 더 많은 버그를 찾습니다.

개발자 크리스 웰런스가 6년 동안 약 1,000개 프로젝트를 퍼즈 테스트(무작위 입력을 넣어 오류를 찾는 시험)하며 모은 요령을 정리했습니다. 대상은 glibc 기반 리눅스에서 AFL++로 시험하는, 소스 코드가 공개된 C와 C++ 프로그램입니다.

왜 중요한가

  • 아직 퍼즈 테스트를 거치지 않은 프로그램에서는 대개 버그가 하나 이상 나와, 적은 노력으로도 성과를 기대할 수 있습니다.
  • 저자는 이 요령과 템플릿으로 시험 코드를 몇 분 만에 작성한다고 하며, 도입 부담이 작다는 점을 보여 줍니다.
  • 공식 템플릿이 권하는 방식에도 버그를 놓치는 허점이 있어, 기존 퍼즈 테스트도 다시 점검할 필요가 있습니다.

핵심 내용

  • 퍼시스턴트 모드(프로세스를 다시 띄우지 않고 반복 실행하는 방식)를 쓰면 보통 10배쯤 빨라집니다.
  • AFL++의 입력 버퍼는 실제 입력보다 커서 ASan이 읽기 초과를 놓치므로, 크기에 맞춘 복사본을 넘겨야 합니다.
  • ASan과 UBSan(메모리 오류와 미정의 동작을 잡는 검사 도구)은 기본으로 켜 둡니다.
  • 대상의 소스 파일을 시험 코드에 직접 포함하면 빌드 설정이 줄고 정적 함수에도 접근할 수 있습니다.
  • 고정 버퍼 크기를 65536에서 16처럼 작게 줄이면 큰 버퍼에 숨어 있던 버그가 빨리 드러납니다.

HN 반응

  • 빅테크 최고 직급 엔지니어의 코드에서도 AFL이 결함을 찾았다는 경험담을 두고, C의 안전성이 실력만의 문제인지 논쟁이 벌어졌습니다.
  • 한 이용자는 퍼시스턴트 모드로 바꾸자 초당 실행 수가 440회에서 7만 회로 늘었다면서도, 관련 문서는 부실하다고 지적했습니다.

댓글

24개 표시 · 전체 28개
  1. r0ze-at-hn HN

    정말 좋은 목록입니다.

    저는 AFL이 나오기 훨씬 전부터 퍼저를 만지작거리고 직접 만들기도 했는데, AFL이 나오고 코드 공간을 똑똑하게 탐색하게 된 뒤로는 판이 근본적으로 바뀌었습니다. 퍼징이 가능하도록 코드베이스를 손봤는데 버그를 못 찾아서 헛수고였던 적은 단 한 번도 없었습니다.

    게다가 이 분야는 아직 비교적 젊습니다. 예를 들어 재작년에는 트랜스포머 모델을 내부 학습 엔진으로 쓰는 퍼저를 만들었고, https://antithesis.com 같은 멋진 것들도 있습니다.

    퍼징이 아주 오래전부터 있었다는 건 알지만, 퍼저를 한 번도 써 본 적 없는 엔지니어를 아직도 이렇게 많이 만난다는 게 놀랍습니다. 저는 버그 고치는 게 싫고, 버그를 알아서 찾아 주고 정확히 재현되는 케이스까지 건네주는 도구가 좋습니다. 고(Go)에 퍼저가 내장된 것도 퍼징이 더 대중화되는 데 도움이 될 테니 반가웠습니다.

    요즘 같은 AI 시대에는 AI가 꼼수를 쓸 수 없는 검증 방법(그냥 'pass'만 반환하는 단위 테스트 같은 것)이 필요하고, 생성된 코드를 자동으로 평가할 방법도 필요한데, 퍼징이 딱 맞습니다. 게다가 코드를 죽일 방법을 찾느라 토큰을 계속 태우는 것보다 밤새 퍼징을 돌리는 편이 더 쌉니다.

  2. jonhohle HN

    저는 C/C++로 안전한 코드를 쓰는 건 실력의 문제라고 생각했습니다. 그런데 FAANG에서 최고 직급의 엔지니어들이 쓴 코드에서 AFL로 문제를 한두 개도 아니고 여러 개 찾아내고는 생각이 바뀌었습니다. 대단한 도구입니다.

  3. fasterik HN

    그래도 상당 부분은 실력의 문제 아닌가요. 실력 있는 프로그래머는 평균적으로 버그를 덜 만듭니다. 피해야 할 패턴을 알고 있고 품질 기준도 더 높으니까요. 프로그래밍 언어와 상관없이 버그가 하나도 없는 코드를 쓸 수 있는 사람은 없습니다. 그리고 직급이 실력과 상관관계가 있을 수는 있어도, 최고 직급에 무능한 사람이 없다는 뜻은 아닙니다.

  4. tikhonj HN

    더 안전한 C를 쓰는 건 실력의 문제입니다.

    안전한 C를 쓰려면 근본적으로 다른(훨씬, 훨씬 느린) 개발 프로세스나 더 나은 도구, 혹은 둘 다가 필요합니다. 실력만으로는 부족합니다.

  5. kragen HN

    형편없는 코드가 무능이 아니라 유능함의 결과일 때도 있습니다. 저보다 훨씬 뛰어난 프로그래머들이 일부러 끔찍한 코드를 쓰는 걸 봤습니다. 프로토타입을 가장 빨리 돌려 보고, 제대로 된 코드를 쓸 가치가 있는 문제인지 확인하는 가장 빠른 방법이었기 때문입니다.

  6. eptcyka HN

    안전한/좋은 C 코드를 쓰기는 정말 어렵다에서 사실 후진 코드가 좋을 때도 있다까지 댓글 두 개 만에 오는 게 참 재밌네요. 기존 코드에서 버그를 찾는 퍼저 얘기를 하던 맥락인데 말이죠.

  7. embedding-shape HN

    HN 댓글 스레드에서는 늘 있는 일이에요. 다들 자기 관점과 맥락에서 그걸 따로 밝히지 않고 답하니까, 하위 스레드를 읽지 않으면(이번에는 첫 사람은 프로덕션 소프트웨어 얘기를, 마지막 사람은 프로토타입 얘기를 하고 있죠) 서로 딴소리를 하는 것처럼 보입니다. 하지만 실제로는 다들 자기 환경과 맥락에서 맞는 얘기를 하고 있는 거예요.

  8. eptcyka HN

    이번에는 다들 이 주제에 실질적으로 도움이 되는지는 별로 따지지 않고, 그냥 자기 의견을 말하고 싶어서 댓글을 다는 것 같아요. 그리고 이제는 저도 마찬가지고요. :(

  9. kragen HN

    저는 jonhohle이 왜 "FAANG에서 최고 직급의 엔지니어들이 쓴 코드에서 AFL로 문제를 여러 개 찾아낼" 수 있었는지에 대해 댓글을 단 겁니다. 그분이 어떤 맥락에서 그 문제들을 찾았는지는 모릅니다. 언급할 만큼 중요하다고 보지 않았는지 쓰지 않았으니까요. 제 주장은 처음부터 끝까지, 그 맥락을 고려해야 한다는 겁니다.

  10. ambicapter HN

    사실 별로 중요하지 않습니다. 가장 실력 있는 프로그래머는 보통 더 어려운 일을 맡으니까, 버그 발생률은 비슷하게 유지됩니다.

  11. Conscat HN

    정적 분석과 퍼즈 테스트를 잘 활용하는 것도, 세부 사항에 신경 써야 하는 프로그래밍 언어를 다루는 실력의 일부라고 생각합니다.

  12. PorciiVorbesc HN

    >저는 C/C++로 안전한 코드를 쓰는 건 실력의 문제라고 생각했습니다.

    개발자들이 품질 있는 일을 하는 데 얼마나 신경 썼느냐의 문제예요. 경험 없는 사람이 열정이 있고 신경을 쓴다는 이유만으로 품질 좋은 결과물을 내놓는 경우도 있고(하프라이프는 게임이나 코딩 경력이 전혀 없던 사람들이 일부 참여해서 만들었잖아요), 반대로 잘나가는 록스타 개발자라는 사람들이 어떤 이유에선지 신경을 안 쓰고 쓰레기를 내놓기도 하죠. 그냥 출근 도장 찍고, 월급 받고, 퇴근하고 싶은 거예요.

    FAANG은 이미 한참 전에 실력의 기준이 아니게 됐어요. 거기 들어가는 건 리트코드를 열심히 갈고 7단계 면접을 뚫는 기술이고, 들어간 다음에는 더 좋은 곳으로 이직하거나 대량 해고당할 때까지 쉬면서 스톡옵션이 베스팅되기만 기다리는 거죠.

  13. pfdietz HN

    개발자들이 품질 있는 일을 하는 데 얼마나 신경 썼느냐의 문제예요.

    오히려 경영진이 품질에 얼마나 신경 쓰는지, 그리고 거기에 시간과 자원을 얼마나 쏟을 의향이 있는지의 문제입니다.

    그리고 그건 시장에서 코드 품질이 실제로 얼마나 중요하냐에 따라 결정됩니다.

  14. PorciiVorbesc HN

    FANG에는 자원이 없고 인디 개발자나 게임 스튜디오에는 있다는 건가요?

  15. bawolff HN

    세상 모든 자원이 있어도 엉뚱한 데 쓰면 소용없습니다.

  16. pfdietz HN

    제가 경영진이 쏟을 "의향이 있는" 정도라고 말한 걸 보세요. 얼마나 "가지고 있는지"가 아니라요.

  17. nxobject HN

    연말 출시일에 맞추려고 급하게 만든 AAA 게임의 코드베이스 품질을 너무 낙관하시는 것 같네요. 저는 게임이라면 버그에 좀 더 너그러운 편이긴 합니다.

  18. sczi HN

    상당한 규모의 C나 C++ 코드베이스 중에 악용 가능한 메모리 손상 문제가 한 번도 없었던 경우가 있었나요? 지금까지 그런 걸 해낸 개발자가 한 명도 없다면, 개발자의 열정이니 실력이니 하는 문제라고 계속 말할 수는 없다고 봅니다.

    그렇다고 메모리 손상 문제만 문제라는 건 아니고, 잘 성숙한 C/C++ 코드베이스를 메모리 안전 언어로 다시 쓰면 고치는 것보다 더 많은 문제가 생길 수도 있겠지만요...

  19. muvlon HN

    떠오르는 예가 postfix(SMTP 데몬)입니다. 메모리 안전성 문제가 0건은 아니지만 거의 없다시피 합니다. 프로젝트의 크기와 복잡도, 그리고 들여다보는 눈이 얼마나 많은지를 생각하면 확실히 비정상적으로 적은 수치입니다.

    반면 SMTP 스머글링이나 파일 시스템 권한 TOCTOU 같은 메모리와 무관한 버그는 꽤 '평범한'(즉 더 많은) 수준으로 나왔습니다. 그러니 개발자들이 버그를 안 쓰는 데 특별히 뛰어난 건 아닙니다.

    복잡한 메모리 관련 로직을 피할 수 있는 소프트웨어 아키텍처를 골랐기 때문일까요? 정말 모르겠습니다. postfix 개발자에게 직접 듣고 싶네요.

  20. uecker HN

    특별히 설계하고 검증한 코드를 제외하면 아마 없을 겁니다. 다만 메모리 안전성 문제가 워낙 적어서 다른 문제들에 비하면 현실적으로 무의미한 프로젝트도 분명 많습니다. 제가 본 문제 대부분은 경계 검사를 하는 문자열·버퍼 추상화만 써도 아주 쉽게 막을 수 있는 것들입니다.

    또 메모리 안전성 문제는 정의가 아주 분명해서 새니타이저, 퍼저, 검증 도구로 자동으로 찾을 수 있다는 점도 눈여겨볼 만합니다. 다른 많은 정확성 문제는 그렇지 않고, 메모리 안전성 문제를 다 고치고 나면 그쪽이 모든 코드의 큰 숙제로 남을 겁니다.

  21. rwmj HN

    때마침 올라온 글이네요. 저는 얼마 전 hivex(윈도 레지스트리 파서)의 퍼징을 persistent 모드로 바꿔서 획기적으로 늘렸습니다. 초당 실행 횟수가 440번쯤에서 7만 번으로 올랐어요. 테스트 케이스가 완전히 같지는 않지만요. 그런데 persistent 모드 문서는 정말 형편없습니다.

    https://github.com/libguestfs/hivex/commit/2254c62832c5688049d4443d78ac2055d3d2a237

  22. Selliks HN

    안녕하세요, 궁금한 게 있습니다. 찾아낸 크래시가 우연히 한 번 난 게 아니라 진짜라는 건 어떻게 알 수 있나요?

  23. eptcyka HN

    우연은 없습니다. 크래시가 났다면 그 자체가 신호예요. 심각한 버그가 아닐 수는 있어도, 어쨌든 버그입니다.

  24. monster_truck HN

    좋은 팁이네요, 감사합니다.

Hacker News에서 보기 ↗