
Easy Grade Pro 4.1 파일 파싱 버그는 초보자가 리버스 엔지니어링을 통해 취약점 연구를 시작하는 방법을 보여주는 교육적 예제로 사용됩니다.
리버스 엔지니어링을 통한 취약점 연구가 처음부터 가능하다는 것을 초보자에게 보여주기 위해 만들어진 교육용 예제입니다.
이 저장소는 취약점 연구를 시작하는 초보자, 특히 리버스 엔지니어링에 관심이 있는 사람들을 가르칠 때 사용할 수 있는 간단한 예제가 필요하다는 필요성에서 비롯되었습니다.
바이너리 익스플로잇 또는 바이너리 분석 관련 과정, 교육 세션 또는 석사 프로그램을 마친 후 많은 학생들은 실제 취약점 연구가 자신의 수준을 훨씬 뛰어넘는 것이라고 느낍니다. 그들은 일반적으로 리버스 엔지니어링을 커널 취약점, 브라우저 익스플로잇, 펌웨어 연구 또는 복잡한 현대 타겟과 같은 매우 고급 주제와 연관시키고, 그 때문에 아직 준비되지 않았다고 생각합니다. 실제로, 문제는 지식 부족이 아니라 현실적인 출발점의 부족입니다.
저는 기본 과정에서 배운 기술로도 실제 프로그램을 가져와서 작동 방식을 이해하고, 충돌을 유발하고, 실제 버그를 식별하는 것이 이미 가능하다는 것을 보여줄 수 있는 예제를 원했습니다.
이 저장소는 바로 그런 예제입니다. 복잡한 취약점을 찾는 것이 아닙니다. 초보자도 작고, 재현 가능하며, 이해할 수 있는 것에서 시작하여 여전히 실제 취약점 연구를 수행할 수 있음을 보여주는 것입니다.
이 저장소는 제 발표 **'당신의 첫 CVE로 이끄는 길'**과 직접적으로 관련되어 있습니다. 그 발표에서 저는 취약점 연구 세계에 진입하는 여러 방법이 있으며, 각 사람은 일반적으로 자신의 관심사에 따라 다른 길을 따르게 된다고 설명합니다.
어떤 사람들은 소스 코드 감사로 시작하고, 다른 사람들은 리버스 엔지니어링, 웹 보안, 기술 연구로 시작합니다. 이러한 모든 경로는 유효하지만, 중요한 것은 모든 영역에 초보자에게 친숙한 진입점이 있다는 것을 이해하는 것입니다.
초보자 경로의 예는 다음과 같습니다:
이러한 유형의 대상은 기본적으로 보일 수 있지만, 나중에 복잡한 시스템을 작업할 때 필요한 동일한 핵심 기술을 가르쳐줍니다.
이 저장소는 리버스 엔지니어링 분야에서 그러한 초보자 경로 중 하나를 나타냅니다.
여기에 문서화된 취약점은 오래된 애플리케이션을 분석하고, 파일 형식이 어떻게 파싱되는지 이해하며, 충돌로 이어지는 프로그래밍 실수를 식별하여 발견되었습니다. 영향 자체는 복잡하지 않지만, 그 과정은 실제적이고 재현 가능하며 취약점 연구가 실제로 어떻게 작동하는지 배우는 데 유용합니다.
이것이 '당신의 첫 CVE로 이끄는 길'을 설명할 때 제가 사용하는 예제 유형입니다. 리버스 엔지니어링이 처음부터 유효한 경로이며, 간단한 대상에서 시작하는 것이 허용될 뿐만 아니라 종종 가장 좋은 학습 방법임을 보여주기 위함입니다.
처음 시작할 때 현대 애플리케이션은 종종 너무 복잡합니다. 많은 경험 없이는 이해하기 어려운 보호, 완화 및 코드베이스를 사용합니다. 오래된 소프트웨어는 다릅니다.
레거시 애플리케이션은 현대 보안 관행을 염두에 두고 작성되지 않았습니다. 종종 기본적인 리버싱 기술로 이해할 수 있는 간단한 파싱 버그, 안전하지 않은 메모리 연산 및 논리 오류를 포함합니다. 이는 학습에 완벽하게 만듭니다.
오래된 프로그램을 사용하면 바이너리를 리버싱하고, 파일 형식을 이해하고, 충돌을 유발하고, 충돌을 분석하고, 버그를 찾고, 문제를 문서화하고, 취약점을 보고할 수 있습니다. 즉, 모든 취약점 연구자가 필요한 기본 기술을 배우게 됩니다.
이 예제가 바로 그런 것입니다.
이 예제는 매우 간단한 것을 보여주기 때문에 중요합니다:
리버스 엔지니어링을 좋아한다면 처음부터 그 길을 따를 수 있습니다. 마스터하는 데는 몇 년이 걸릴 수 있지만, 실제 작업을 시작하기 위해 몇 년을 기다릴 필요는 없습니다.
이 취약점(CVE-2025-70330))은 독점 .EGP 성적부 파일을 로드할 때 Easy Grade Pro 4.1의 파일 파싱 로직에 영향을 미칩니다.
애플리케이션은 파일에서 고정 위치 필드를 읽고 해당 값을 로드된 파일 버퍼 내의 오프셋으로 사용하여 내부 성적부 구조를 재구성합니다. 이러한 오프셋은 나중에 메모리 크기를 계산하고 동적으로 할당된 버퍼로 데이터를 복사하는 데 사용됩니다.
정상적인 조건에서 파일은 파싱이 계속되기 전에 여러 구조적 검사를 통과합니다. 그러나 이러한 검사가 성공하면 파서는 파일 내에 저장된 오프셋 값이 로드된 버퍼의 경계 내에 있는지 검증하지 않고 신뢰합니다.
그렇지 않으면 유효한 .EGP 파일 내의 특정 바이트를 수정함으로써 이러한 내부 오프셋 계산을 손상시킬 수 있습니다. 파서가 나중에 이러한 값을 사용할 때 유효한 파일 영역 외부의 메모리를 읽으려고 시도하여 액세스 위반 및 애플리케이션 충돌이 발생합니다.
이 조건은 범위를 벗어난 읽기(CWE-125)에 해당하며, 조작된 파일이 열릴 때 로컬 서비스 거부로 이어집니다.
.EGP 파일 형식은 오프셋 기반 접근 방식을 사용하여 파싱됩니다. 파서는 파일을 순차적으로 처리하는 대신 특정 데이터 블록이 파일 내에 위치해야 하는 시작 및 끝 오프셋을 포함하는 내부 구조를 읽습니다.
이러한 오프셋은 메모리 영역의 크기를 계산하고 로드된 파일 버퍼에서 새로 할당된 메모리로 데이터를 복사하는 데 사용됩니다.
취약한 로직은 다음과 같이 요약할 수 있습니다:
size = offset_end - offset_start + 1
buffer = calloc(1, size)
memcpy(buffer, file_buffer[offset_start - base_offset], size)
파일이 초기 유효성 검사를 통과하면 파서는 파일에 저장된 오프셋이 유효하다고 가정합니다. 계산된 소스 포인터가 로드된 파일 버퍼 내에 유지되는지 확인하는 검증은 수행되지 않습니다.
오프셋이 제어된 방식으로 조작되면 파서가 유효한 영역 외부의 메모리를 읽으려고 시도하여 memcpy() 작업 중에 액세스 위반이 발생할 수 있습니다.
모든 손상된 .EGP 파일이 충돌을 유발하는 것은 아닙니다.
파서는 취약한 코드 경로에 도달하기 전에 여러 일관성 검사를 수행합니다. 파일 구조가 너무 손상되면 애플리케이션이 조기에 파싱을 중지하고 성적부가 손상되었다고 보고합니다.
그러나 일부 수정은 내부 구조를 초기 검사를 통과할 수 있을 만큼 일관성 있게 유지하면서도 파싱 프로세스 후반에 잘못된 오프셋 값을 생성합니다.
이런 일이 발생하면 파서는 이러한 오프셋이 신뢰되고 메모리 복사 작업에 사용되는 더 깊은 루틴에 도달하여 결국 범위를 벗어난 읽기를 유발합니다.
충돌은 유효한 .EGP 파일을 수정하고 특정 오프셋에 제어된 데이터를 삽입하여 유발할 수 있습니다.
개념 증명은 다음 단계로 작동합니다:
PoC에 사용된 예제 매개변수:
이 수정은 파일이 초기 검사를 통과할 수 있을 정도로 구조적으로 유효하게 유지하지만, 나중에 파서가 사용하는 내부 오프셋 계산을 손상시켜 결국 애플리케이션 충돌을 유발합니다.
손상된 파일을 디버거에서 열면 메모리 복사 작업 중에 애플리케이션이 충돌합니다.
관찰된 예외는 잘못된 메모리 읽기로 인한 액세스 위반입니다.
디버깅 중에 memcpy()에서 사용된 잘못된 포인터는 파싱된 파일 구조에서 파생된 오프셋 계산에서 비롯됩니다. 이러한 오프셋이 로드된 파일 버퍼 외부의 메모리를 참조하면 소스 포인터가 매핑되지 않은 주소를 가리켜 충돌이 발생합니다.
이는 취약점이 파일 파싱 중 경계 검증 누락으로 인해 발생함을 확인합니다.
이 취약점은 공급업체에서 더 이상 유지 관리하지 않는 수명이 종료된 제품에 영향을 미칩니다.
이 문제는 교육 및 연구 목적으로 문서화되었으며, 초보자에게 소프트웨어가 단계별로 분석되어 버그가 어떻게 나타나고 실제 취약점이 어떻게 발견되는지 이해할 수 있는 구체적인 예를 제공하기 위함입니다.