AI VIDEO BRIEFING
퍼징(Fuzzing)이란? 무작위 테스트로 보안 취약점과 컴파일러 버그를 자동으로 찾아내는 방법
프로그래머가 예상하지 못한 입력으로 소프트웨어의 버그를 찾는 퍼징의 원리와, 컴파일러 검증·커버리지 가이드 퍼징(AFL) 같은 실제 활용 방식을 컴퓨터파일 영상으로 정리했습니다.

핵심 메시지
쉽게 이해하기
프로그래머는 소프트웨어를 설계할 때 보통 그것이 무엇을 해야 하는지, 사용자가 어떻게 쓸지, 자연스럽게 저지를 실수는 무엇일지를 생각한다. 그러나 워드 프로세서로 동영상 파일을 열거나 기상천외한 내용을 붙여 넣는 것처럼, 말도 안 되는 사용 방식까지 떠올리지는 않는다. 소프트웨어가 망가지는 원인은 대개 이렇게 '개발자가 생각하지 못한 예상 밖 입력'에 있고, 무작위 테스트, 즉 퍼징(fuzzing)은 바로 그런 입력을 찾아내는 좋은 방법이다. 이 기법은 워낙 자명해서 누가 처음 시작했는지조차 다소 모호하다.
퍼징은 인터넷 시대에 더욱 중요해졌다. 전 세계 수십억 명이 쓰는 크롬·사파리·파이어폭스 같은 웹 브라우저는 완전히 개방된 시스템이다. 피싱 공격으로 악성 페이지에 접속하면 그 페이지는 임의의 콘텐츠를 담을 수 있으므로, 브라우저는 어떤 HTML이나 자바스크립트가 들어와도 취약점을 노출하지 않고 견뎌야 한다. 영상은 대규모 언어 모델 같은 개방형 시스템에서도 오작동을 넘어 원격 실행 공격의 진입점이 될 수 있는 입력이 우려되며, 무작위 입력으로 시스템을 두드려 그런 '뒷문'을 우연히 발견할 수 있다는 점에서 퍼징이 효과적인 방어책이라고 설명한다.
퍼징에는 두 극단이 있다. 한쪽은 본래 넣어선 안 될 엉망진창의 악성 입력을 던져 취약점을 찾는 것이고, 다른 한쪽은 매우 정교하게 잘 만들어진 복잡한 입력을 넣어 소프트웨어가 '올바르게 동작했는지'를 확인하는 것이다. 후자의 좋은 예가 컴파일러다. GCC나 Clang 같은 컴파일러도 다른 프로그램처럼 예기치 못한 입력에 크래시할 수 있지만, 더 고약한 버그는 '잘못된 컴파일(miscompilation)'이다. 소스 코드를 군말 없이 실행 파일로 바꿔 놓고도, 그 번역이 원래 프로그램의 의미를 보존하지 못한 경우다. 예컨대 x + y를 곱셈 명령으로 잘못 옮긴다면 잘못된 컴파일이다. 컴파일러는 번역 과정에서 정교한 최적화를 수행하는데, 그 최적화에 개발자가 예상 못 한 엣지 케이스가 숨어 있을 수 있다.
이를 잡기 위해 미국 유타 대학교에서 시작된 Csmith 같은 퍼저는 해당 언어 문법에 맞는 무작위 프로그램을 생성한다. 이 프로그램들은 의미 있는 일을 하진 않지만 실행하면 결정적인(deterministic) 정수 결과를 내도록 만들어진다. 같은 프로그램을 GCC와 Clang에 각각 컴파일해 같은 입력으로 실행했을 때 결과가 다르다면, 두 컴파일러 중 하나에 버그가 있다는 뜻이다. 단, C·C++에는 0으로 나누기나 배열 범위 밖 접근처럼 '정의되지 않은 동작(undefined behavior)'이 많은데, 이런 경우엔 결과가 달라도 정상일 수 있으므로, Csmith의 핵심 혁신은 바로 정의되지 않은 동작이 없는 프로그램을 생성하는 데 있다.
영상은 테스트의 본질적 한계도 짚는다. 소프트웨어 테스트는 버그의 존재를 보여줄 수 있을 뿐, 버그의 부재를 증명하지는 못한다. 다만 반복해서 버그를 찾아 고치고, 점점 버그를 찾기 어려워지는 과정이 소프트웨어가 더 신뢰할 만해지고 있다는 증거가 된다. 마지막으로 소개되는 것이 구글 엔지니어가 만든 AFL(American Fuzzy Lop)이 대중화한 '커버리지 가이드 퍼징'이다. 시스템을 미로에 비유하면, 단순 무작위 입력은 미로 깊은 곳까지 들어가지 못한다. 커버리지 가이드 퍼징은 실제 예시 입력들로 시작한 말뭉치(corpus)에서 입력을 꺼내 비트 뒤집기·바이트 교체·이어 붙이기 등으로 무작위 변형하고, 그 변형된 입력이 '이전에 도달한 적 없는 새로운 코드 경로'에 닿으면 흥미로운 입력으로 보고 말뭉치에 다시 넣는다. 이는 개체군·무작위 변이·적합도 함수를 가진 진화 알고리즘과 같아서, 초당 수천에서 수만 번씩 입력을 진화시키며 시스템 깊숙한 곳의 버그까지 도달한다. 예컨대 '--only' 같은 명령행 옵션도, 대시 하나를 우연히 찾으면 그것이 말뭉치에 남아 이후 변이로 두 번째 대시와 글자들이 붙으며, 퍼저가 입력의 기대 형식을 스스로 발견해 나간다.
주요 인사이트
- 버그의 근원은 종종 '개발자가 상상하지 못한 사용 방식'에 있다. 퍼징은 인간의 상상력 밖에 있는 입력을 기계적으로 만들어내 그 사각지대를 공략한다.
- 퍼징은 보안과 정확성이라는 서로 다른 목표에 모두 쓰인다. 악성 입력으로 크래시를 유도하는 것과, 잘 만든 입력으로 컴파일러의 잘못된 최적화를 잡아내는 것은 같은 기법의 양 끝이다.
- 두 컴파일러의 결과를 비교하는 '차등 테스트'는 정답을 모르는 상황에서도 불일치만으로 버그의 존재를 드러내는 영리한 검증 방식이다.
- 정의되지 않은 동작(UB)이 많은 C·C++에서는, 의미 있는 비교를 하려면 먼저 UB 없는 프로그램을 생성하는 것이 핵심 난제다. Csmith의 진짜 기여가 여기에 있다.
- 커버리지 가이드 퍼징은 진화 알고리즘과 본질적으로 같다. 새 코드 경로라는 '적합도'를 기준으로 입력을 선별·변이시키며, 단순 무작위로는 닿을 수 없는 깊은 상태까지 도달한다.
- 모든 버그가 똑같이 중요한 것은 아니다. GCC가 비출력 문자 덩어리에 크래시한다고 해서 실제로 문제 되는 버그라고 보긴 어렵다. 어떤 버그를 신경 쓸지 판단하는 것도 테스트의 일부다.
자주 묻는 질문
퍼징(fuzzing)이란 무엇인가요?
무작위 또는 변형된 입력을 소프트웨어에 자동으로 던져, 개발자가 예상하지 못한 입력에서 발생하는 버그나 취약점을 찾아내는 테스트 기법입니다. '무작위 테스트(randomized testing)'라고도 부릅니다.
퍼징으로 컴파일러의 버그는 어떻게 찾나요?
Csmith 같은 퍼저로 정의되지 않은 동작이 없고 결과가 결정적인 무작위 프로그램을 만든 뒤, 같은 프로그램을 GCC와 Clang 등 서로 다른 컴파일러로 컴파일해 같은 입력으로 실행합니다. 결과가 다르면 두 컴파일러 중 하나에 잘못된 컴파일(miscompilation) 같은 버그가 있다는 뜻입니다.
커버리지 가이드 퍼징은 일반 무작위 퍼징과 무엇이 다른가요?
AFL이 대중화한 방식으로, 변형된 입력이 이전에 도달하지 못한 새로운 코드 경로에 닿을 때만 그 입력을 말뭉치에 남겨 계속 변이시킵니다. 새 커버리지를 적합도로 삼는 진화 알고리즘처럼 동작해, 단순 무작위 입력으로는 닿기 어려운 시스템 깊은 곳의 버그까지 도달합니다.
테스트로 소프트웨어에 버그가 없음을 증명할 수 있나요?
아니요. 테스트는 버그의 존재를 보여줄 수 있을 뿐, 부재를 증명하지는 못합니다. 다만 반복해서 버그를 찾아 고치고 점점 찾기 어려워지는 과정이 소프트웨어가 더 신뢰할 만해지고 있다는 증거가 됩니다. 부재 증명은 형식 검증을 쓰는 고신뢰 안전필수 영역에서나 가능합니다.
원문과 출처
이 글은 원본 영상의 자막을 바탕으로 한국어 독자를 위해 요약했습니다. 전체 맥락과 최신 정보는 원문에서 확인하세요.
YouTube 원본 영상 보기 ↗