이름을 부르지 않고 C 함수 호출하기

Calling a function in C without naming it

학교의 자동 채점 시스템은 허용된 함수만 사용하도록 AST를 검사한다. execve를 직접 부를 수 없자, 저자는 ASan이 printf를 대체한다는 점을 악용해 printf와 mmap의 오프셋을 유출한다. mmap으로 쓰기·실행 가능한 페이지를 얻고, 직접 작성한 기계어로 syscall을 호출해 셸을 획득했다. ASLR을 우회하는 이 익스플로잇은 학교에 제보되었지만, 뚜렷한 패치 방법은 아직 없다.

우리는 학교의 검사를 우회하여 모든 syscall을 호출할 수 있고, 우리의 경우 셸 접근을 얻기 위해 execve를 호출할 수 있다.
  1. ashdnazg

    우리 대학은 훨씬 덜 신경 썼고, 제출물을 다른 모든 것과 같은 네트워크에서 실행했지만 거의 권한이 없는 사용자로 실행했습니다.

    자동 테스트가 내 제출물을 크래시시켰을 때, 나는 그냥 `system`을 사용해서 테스트 입력을 내 홈 디렉토리에 덤프했습니다. 하지만 권한 설정을 잊어버려서 실제로 접근할 수 없었습니다! 추가 chmod를 하면서 몇 번 더 재제출했고, 매번 다른 것을 망가뜨리면서 결국 버그를 재현하고, 고치고, 다시 제출하고, 모든 (또는 대부분의) 증거를 삭제할 수 있었습니다.

  2. Kevin_Flynn

    우리는 우리 코드가 ASan으로 컴파일된다는 것을 알고 있기 때문에, 항상 허용되는 함수인 printf와 임의의 어셈블리 코드 실행을 제공하는 mmap 사이의 오프셋을 유출하기로 했습니다. 따라서 학교의 검사를 우회하고 모든 syscall을 호출할 수 있으며, 우리의 경우 execve를 호출하여 셸 접근 권한을 얻을 수 있습니다.

    우리는 더 조사하지 않고 단순히 이 가능한 문제를 학교에 보고했습니다.

    이를 패치할 간단한 방법은 보이지 않습니다.

    결함은 제출 시스템에 있는 것 같습니다.

    제출 시스템은 당신의 코드를 트램폴린 라이브러리와 빌드/재링크하여 금지할 각 함수의 본문을 오류 보고 및 중단으로 대체할 수 있습니다. 당신의 예에서 그것은 다음을 트랩할 것입니다:

    char *code =

    notmmap.fn(NULL, 4096, PROT_READ | PROT_WRITE | PROT_EXEC,

    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

    그리고 제출 검증의 실행 단계에서 PROT_EXEC 플래그를 사용하는 것을 방지합니다.

    AI에 따르면, 리눅스에서: "... 프로그램을 실행하기 전에 각 프로세스에 적용되는 seccomp-BPF 필터. 이는 mmap의 prot 인수를 검사하고 PROT_EXEC이 설정되면 EPERM을 반환할 수 있습니다."

    추가로, 리눅스에서: "systemd는 서비스에 대해 MemoryDenyWriteExecute=yes를 제공합니다. 이는 모든 실행 가능한 매핑을 금지하는 것보다 덜 제한적입니다: 쓰기 가능+실행 가능 매핑 및 메모리를 실행 가능하게 만드는 관련 방법을 대상으로 합니다."

    ( IF ... 기사를 올바르게 읽었다면 )

    ps. 제안된 해결책을 학과장이나 다른 권위자에게 제출하여 그들이 당신에게 어떤 종류의 보상을 줄 수 있도록 하세요 [...]

이 날의 다른 글

2026-10-08