스택 카나리아 오염은 어떻게 기록됩니까?


11

플래그 GCC -fstack-protector 플래그를 사용하면 스택 오버 플로우 방지를 위해 스택 카나리아를 사용할 수 있습니다. 기본적으로이 플래그의 사용이 최근에 더욱 두드러졌습니다.

패키지가 -fstack-protector로 컴파일되고 프로그램에서 버퍼가 오버플로되면 다음과 같은 오류가 발생할 수 있습니다.

*** buffer overflow detected ***: /xxx/xxx terminated

그러나 "누구"가이 오류 메시지를 담당합니까? 이 메시지는 어디에 기록됩니까? syslog 데몬이이 메시지를 선택합니까?

답변:


10

스택 스매싱은의 libssp일부인에 의해 감지됩니다 gcc. 그것은 아주 열심히하려고 터미널에 출력 메시지를, 단지 그게 시스템 로그에 기록 않는 실패하면 - 그래서 실제로 당신은 데몬 아마도 GUI 응용 프로그램 로그에 메시지를 오버 플로우 버퍼 볼 수 있습니다.

메시지가 출력되면 libssp응용 프로그램 충돌을 비롯하여 다양한 방법으로 종료합니다. 비정상 종료 엑시트 로거 중 하나에 의해 발견 될 수 있지만 보장되지는 않습니다.


1
이 설명을 자세히 살펴볼 수있는 구체적인 예를 들어 보겠습니다. 이 예제에서는 nginx를 선택하겠습니다. 스택 카나리아로 nginx를 컴파일했습니다. nginx를 실행하면 프로세스가 시작되지만 쉘에 아무것도 출력하지 않습니다. 대신 모든 메시지가 여러 로그 파일에 기록됩니다. nginx가 스택 스매싱을 감지하면 nginx에서 libssp사용하는 stderr 출력으로 메시지를 출력합니다. 그런 다음 libssp프로세스 (또는 nginx의 하위 프로세스)를 종료하려고 시도 할 수 있습니다. "필요하지 않은"응용 프로그램이 중단되면 비정상적인 종료 로거가이를 선택하지 않습니다. 이것이 올바른 해석입니까?
aedcv

그렇진 - 그것은 됩니다 사용하여 응용 프로그램을 중단하려고 __builtin_trap()상태 127로 종료, 세그먼트 위반을 자극하는 노력이 실패 다음 경우, 첫째, 그것은 실패하는 경우에만
스티븐 키트

메시지 인쇄 부분은 핵심 산출 방법 (예 :)을 통한 종료보다 더 나은 성공을 보장하지 않습니다 abort().
maxschlepzig

7

CentOS / Fedora와 같은 최신 Linux 배포판 은 기본적으로 충돌 처리 데몬 (예 : systemd-coredump또는 abortd)을 설정합니다.

따라서 프로그램이 비정상적인 방식 (segfault, catch되지 않은 예외, 중단, 잘못된 명령 등)으로 종료되면이 이벤트는 해당 데몬에 의해 등록 및 기록됩니다. 따라서 시스템 저널에서 일부 메시지와 추가 세부 사항 (예 : 코어 파일, 로그 등)이있는 디렉토리에 대한 참조를 찾을 수 있습니다.

$ cat test_stack_protector.c 
#include <string.h>

int f(const char *q)
{
  char s[10];
  strcpy(s, q);
  return s[0] + s[1];
}

int main(int argc, char **argv)
{
  return f(argv[1]);
}

엮다:

$ gcc -Wall -fstack-protector test_stack_protector.c -o test_stack_protector

실행 :

$ ./test_stack_protector 'hello world'
*** stack smashing detected ***: ./test_stack_protector terminated
======= Backtrace: =========
/lib64/libc.so.6(+0x7c8dc)[0x7f885b4388dc]
/lib64/libc.so.6(__fortify_fail+0x37)[0x7f885b4dfaa7]
/lib64/libc.so.6(__fortify_fail+0x0)[0x7f885b4dfa70]
./test_stack_protector[0x400599]
./test_stack_protector[0x4005bd]
/lib64/libc.so.6(__libc_start_main+0xea)[0x7f885b3dc50a]
./test_stack_protector[0x40049a]
======= Memory map: ========
00400000-00401000 r-xp 00000000 00:28 1151979                            /home/juser/program/stackprotect/test_stack_protector
00600000-00601000 r--p 00000000 00:28 1151979                            /home/juser/program/stackprotect/test_stack_protector
00601000-00602000 rw-p 00001000 00:28 1151979                            /home/juser/program/stackprotect/test_stack_protector
0067c000-0069d000 rw-p 00000000 00:00 0                                  [heap]
7f885b1a5000-7f885b1bb000 r-xp 00000000 00:28 1052100                    /usr/lib64/libgcc_s-7-20170915.so.1
7f885b1bb000-7f885b3ba000 ---p 00016000 00:28 1052100                    /usr/lib64/libgcc_s-7-20170915.so.1
7f885b3ba000-7f885b3bb000 r--p 00015000 00:28 1052100                    /usr/lib64/libgcc_s-7-20170915.so.1
7f885b3bb000-7f885b3bc000 rw-p 00016000 00:28 1052100                    /usr/lib64/libgcc_s-7-20170915.so.1
7f885b3bc000-7f885b583000 r-xp 00000000 00:28 945348                     /usr/lib64/libc-2.25.so
7f885b583000-7f885b783000 ---p 001c7000 00:28 945348                     /usr/lib64/libc-2.25.so
7f885b783000-7f885b787000 r--p 001c7000 00:28 945348                     /usr/lib64/libc-2.25.so
7f885b787000-7f885b789000 rw-p 001cb000 00:28 945348                     /usr/lib64/libc-2.25.so
7f885b789000-7f885b78d000 rw-p 00000000 00:00 0 
7f885b78d000-7f885b7b4000 r-xp 00000000 00:28 945341                     /usr/lib64/ld-2.25.so
7f885b978000-7f885b97b000 rw-p 00000000 00:00 0 
7f885b9b0000-7f885b9b3000 rw-p 00000000 00:00 0 
7f885b9b3000-7f885b9b4000 r--p 00026000 00:28 945341                     /usr/lib64/ld-2.25.so
7f885b9b4000-7f885b9b6000 rw-p 00027000 00:28 945341                     /usr/lib64/ld-2.25.so
7ffc59966000-7ffc59987000 rw-p 00000000 00:00 0                          [stack]
7ffc5999c000-7ffc5999f000 r--p 00000000 00:00 0                          [vvar]
7ffc5999f000-7ffc599a1000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
zsh: abort (core dumped)  ./test_stack_protector 'hello world'

종료 상태는 134이며 128 + 6, 즉 128 + 중단 신호 번호입니다.

시스템 저널 :

Oct 16 20:57:59 example.org audit[17645]: ANOM_ABEND auid=1000 uid=1000 gid=1000 ses=3 subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 pid=17645 comm="test_stack_prot" exe="/home/juser/program/stackprotect/test_stack_protector" sig=6 res=1
Oct 16 20:57:59 example.org systemd[1]: Started Process Core Dump (PID 17646/UID 0).
Oct 16 20:57:59 example.org audit[1]: SERVICE_START pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='unit=systemd-coredump@21-17646-0 comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
Oct 16 20:57:59 example.org systemd-coredump[17647]: Process 17645 (test_stack_prot) of user 1000 dumped core.

                           Stack trace of thread 17645:
                           #0  0x00007f885b3f269b raise (libc.so.6)
                           #1  0x00007f885b3f44a0 abort (libc.so.6)
                           #2  0x00007f885b4388e1 __libc_message (libc.so.6)
                           #3  0x00007f885b4dfaa7 __fortify_fail (libc.so.6)
                           #4  0x00007f885b4dfa70 __stack_chk_fail (libc.so.6)
                           #5  0x0000000000400599 f (test_stack_protector)
                           #6  0x00000000004005bd main (test_stack_protector)
                           #7  0x00007f885b3dc50a __libc_start_main (libc.so.6)
                           #8  0x000000000040049a _start (test_stack_protector)
Oct 16 20:57:59 example.org audit[1]: SERVICE_STOP pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='unit=systemd-coredump@21-17646-0 comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
Oct 16 20:58:00 example.org abrt-notification[17696]: Process 17645 (test_stack_protector) crashed in __fortify_fail()

즉, 당신은에서 로그인 얻을 auditd감사 데몬 systemd-coredump 충돌 핸들러입니다.

충돌 처리 데몬이 구성되어 있는지 확인하려면 다음을 확인하십시오 /proc.

$ cat /proc/sys/kernel/core_pattern
|/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %e

(Fedora 26, x86-64에서 테스트 된 모든 것)


1
이 예제를 게시하게되어 매우 기쁩니다. 카나리아는 gcc에 의해 배치됩니다. (내가 틀렸다면 정정 해주세요) 저는 다음과 같은 일이 있다고 가정합니다 : gcc는 카나리아 기능을 구현하기 위해 프로그램에 "추가 코드"를 넣습니다. 실행 중 및 함수가 반환되기 전에 값이 확인됩니다. 오염 된 경우 프로그램은 "스택 스매싱 감지"메시지를 출력하고 오류를 발생시킵니다. 이 오류는 OS에서 발생하고 세그먼트 오류를 ​​인식하고 게시 한 역 추적 및 메모리 맵을 인쇄합니다. 마지막으로, OS는 응용 프로그램을 죽이고 코어 덤프를 생성하고, SYS 저널 로그
aedcv

@aedcv, 이것은 거의 이야기입니다. 더 정확하게 말하자면 스택 스매싱 검사 코드 abort()는 중단 신호를 생성합니다. 즉, 세그먼트 오류가 발생하지 않습니다. 중단 / 세그먼트 오류 등의 기본 신호 처리기에서도 동일한 동작이 발생합니다. 코어를 작성하고 신호 번호를 인코딩하는 종료 상태가 0이 아닌 프로세스를 종료하십시오. 핵심 작성은 커널에 의해 수행되며 그 동작은을 통해 구성 할 수 /proc/.../core_pattern있습니다. 위의 예에서 사용자 공간 도우미가 구성되어 호출됩니다. 커널은 또한 감사를 시작합니다.
maxschlepzig

@maxschlepzig 그것은 abort()SSP 코드가 사용 __builtin_trap()하지는 않지만 그 효과는 동일합니다.
Stephen Kitt

1
@StephenKitt는 위의 예제에서 스택 추적을 살펴 봅니다. 거기에서 당신은 어떻게 abort()불려지 는지 분명히 알 수 있습니다 .
maxschlepzig

1
물론 @maxschlepzig 그렇습니다. 그러나 그것은 구현 세부 사항입니다 (GCC 코드는 __builtin_trap()에 대한 명시 적 종속성을 피하기 위해 사용 합니다 abort()). 다른 배포판에는 다른 스택 추적이 있습니다.
Stephen Kitt
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.