1. Canaries
1) Canaries (Canary word)
- 버퍼 오버플로우를 모니터하기 위해 버퍼와 제어 데이터 사이에 설정된 값
- 버퍼 오버플로우가 발생 시
Canary 값이 손상, Canaries 데이터 검증에 실패, 오버플로우에 대한 경고 출력, 손상된 데이터 무효화 처리
2) 종류
① Terminator canaries
- Canary 값을 문자열의 끝을 나타내는 문자들 (NULL, CR, LF, EOF)을 이용하여 생성
- 공격자는 Canaries를 우회하기 위해 return address를 쓰기 전에 null 문자 사용해야 함
- null 문자로 인해 오버플로우 방지 (strcpy 함수는 null문자의 위치까지 복사)
- 그럼에도 공격자는 잠재적으로 Canary를 알려진 값으로 겹쳐 쓰고 정보를 틀린 값으로 제어해서 Canary 검사 코드 통과 가능
② Random canaries
- Canary 값을 랜덤하게 생성
- 프로그램 초기 설정 시에 전역 변수에 Canary 값이 저장됨
- 이 값은 보통 매핑되지 않은 페이지에 저장
- 해당 메모리를 읽으려는 시도를 할 경우 segmentation fault가 발생하고 프로그램 종료됨
- 공격자가 Canary 값이 저장된 스택 주소를 알거나 스택의 값을 읽어올 수 있으면 Canary 값을 확인할 수 있음
③ Random XOR canaries
- Canary 값을 모든 제어 데이터 또는 일부를 사용해 xor 하여 생성
- Canary의 값, 제어 데이터가 오염되면 Canary 값이 달라짐
- Random Canaries와 동일한 취약점 갖고 있음
- 스택에서 Canary 값을 읽어오는 방법이 조금 더 복잡함
- 공격자는 Canary를 다시 인코딩하기 위해서 원래의 Canary 값, 알고리즘, 제어 데이터가 필요함\
2. 예제
1) 소스 코드
#include <stdio.h>
void main(int argc, char **argv)
{
char Overflow[32];
printf("Hello world!\n");
gets(Overflow);
}
2) Canary 값 확인
lazenca0x0@ubuntu:~/Documents/Definition/protection/Canary$ gdb -q ./Canary
Reading symbols from ./Canary...(no debugging symbols found)...done.
gdb-peda$ disassemble main
Dump of assembler code for function main:
0x00000000004005d6 <+0>: push rbp
0x00000000004005d7 <+1>: mov rbp,rsp
0x00000000004005da <+4>: sub rsp,0x40
0x00000000004005de <+8>: mov DWORD PTR [rbp-0x34],edi
0x00000000004005e1 <+11>: mov QWORD PTR [rbp-0x40],rsi
0x00000000004005e5 <+15>: mov rax,QWORD PTR fs:0x28
0x00000000004005ee <+24>: mov QWORD PTR [rbp-0x8],rax
0x00000000004005f2 <+28>: xor eax,eax
0x00000000004005f4 <+30>: mov edi,0x4006b4
0x00000000004005f9 <+35>: call 0x400490 <puts@plt>
0x00000000004005fe <+40>: lea rax,[rbp-0x30]
0x0000000000400602 <+44>: mov rdi,rax
0x0000000000400605 <+47>: mov eax,0x0
0x000000000040060a <+52>: call 0x4004c0 <gets@plt>
0x000000000040060f <+57>: nop
0x0000000000400610 <+58>: mov rax,QWORD PTR [rbp-0x8]
0x0000000000400614 <+62>: xor rax,QWORD PTR fs:0x28
0x000000000040061d <+71>: je 0x400624 <main+78>
0x000000000040061f <+73>: call 0x4004a0 <__stack_chk_fail@plt>
0x0000000000400624 <+78>: leave
0x0000000000400625 <+79>: ret
End of assembler dump.
gdb-peda$ b *0x000000000040060a
Breakpoint 1 at 0x40060a
gdb-peda$ b *0x0000000000400610
Breakpoint 2 at 0x400610
gdb-peda$ r
Starting program: /home/lazenca0x0/Documents/Definition/protection/Canary/Canary
Hello world!
Breakpoint 1, 0x000000000040060a in main ()
gdb-peda$ i r rdi
rdi 0x7fffffffe180 0x7fffffffe180
gdb-peda$ ni
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
0x000000000040060f in main ()
gdb-peda$ x/10gx 0x7fffffffe180
0x7fffffffe180: 0x4141414141414141 0x4141414141414141
0x7fffffffe190: 0x4141414141414141 0x4141414141414141
0x7fffffffe1a0: 0x00007fffffffe200 0x3a3b864735c7b300
0x7fffffffe1b0: 0x0000000000400630 0x00007ffff7a2d830
0x7fffffffe1c0: 0x0000000000000000 0x00007fffffffe298
gdb-peda$ c
Continuing.
Breakpoint 2, 0x0000000000400610 in main ()
gdb-peda$ i r rbp
rbp 0x7fffffffe1b0 0x7fffffffe1b0
gdb-peda$ x/gx 0x7fffffffe1b0 - 0x8
0x7fffffffe1a8: 0x3a3b864735c7b300
gdb-peda$ ni
0x0000000000400614 in main ()
gdb-peda$ i r rax
rax 0x3a3b864735c7b300 0x3a3b864735c7b300
gdb-peda$ ni
0x000000000040061d in main ()
gdb-peda$ i r rax
rax 0x0 0x0
gdb-peda$ ni
0x0000000000400624 in main ()
gdb-peda$ x/2i $rip
=> 0x400624 <main+78>: leave
0x400625 <main+79>: ret
gdb-peda$
- disassemble 등의 명령어가 안 먹혀서 코드를 복사한 것으로 대체함
- 사용자 값이 저장되는 영역은 0x7fffffffe180
- 해당 영역에 코드에서 할당한 길이의 문자를 저장 ('A' * 32)
- 0x400610 코드 영역에서 rax 레지스터에 rbp - 0x8 영역에 저장된 값을 저장
- rbp(0x7fffffffe1b0) - 0x8 = 0x7fffffffe1a8
- 0x7fffffffe1a8 영역에 저장된 값 : 0x3a3b864735c7b300
- 0x400614 코드 영역에서 rax 레지스터에 저장된 값과 fs:0x28 레지스터에 저장된 값을 xor 연산
- 0x40061d 코드 영역에서 rax 레지스터의 값이 0과 같으면 0x400624 영역으로 이동
- 이로 인해 정상적으로 프로그램 종료
3) Canary 값을 덮어썼을 경우 프로그램 동작 확인
gdb-peda$ r
Starting program: /home/lazenca0x0/Documents/Definition/protection/Canary/Canary
Hello world!
Breakpoint 1, 0x000000000040060a in main ()
gdb-peda$ i r rdi
rdi 0x7fffffffe180 0x7fffffffe180
gdb-peda$ ni
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBB
0x000000000040060f in main ()
gdb-peda$ x/10gx 0x7fffffffe180
0x7fffffffe180: 0x4141414141414141 0x4141414141414141
0x7fffffffe190: 0x4141414141414141 0x4141414141414141
0x7fffffffe1a0: 0x4141414141414141 0x4242424242424242
0x7fffffffe1b0: 0x0000000000400600 0x00007ffff7a2d830
0x7fffffffe1c0: 0x0000000000000000 0x00007fffffffe298
gdb-peda$ c
Continuing.
Breakpoint 2, 0x0000000000400610 in main ()
gdb-peda$ i r rbp
rbp 0x7fffffffe1b0 0x7fffffffe1b0
gdb-peda$ x/gx 0x7fffffffe1b0 - 0x8
0x7fffffffe1a8: 0x4242424242424242
gdb-peda$ ni
0x0000000000400614 in main ()
gdb-peda$ i r rax
rax 0x4242424242424242 0x4242424242424242
gdb-peda$ ni
0x000000000040061d in main ()
gdb-peda$ i r rax
rax 0x61061c8ecf993242 0x61061c8ecf993242
gdb-peda$ ni
0x000000000040061f in main ()
gdb-peda$ x/3i $rip
=> 0x40061f <main+73>: call 0x4004a0 <__stack_chk_fail@plt>
0x400624 <main+78>: leave
0x400625 <main+79>: ret
gdb-peda$ c
Continuing.
*** stack smashing detected ***: /home/lazenca0x0/Documents/Definition/protection/Canary/Canary terminated
Program received signal SIGABRT, Aborted.
- 버전이 달라서 그런지 주소값이랑 결과가 달라서 코드를 복사한 것으로 대체함
- 사용자 입력 값이 저장되는 위치와 Canary의 위치는 앞에서 설명한 것과 동일
- 사용자 입력 값으로 'A' * 40 + 'B' * 8 을 입력
- 해당 값으로 인해 canary의 값이 0x4242424242424242(BBBBBBBB) 으로 변경
- 0x400610 코드 영역에서 rax 레지스터에 rbp - 0x8 영역에 저장된 값을 저장
- rbp(0x7fffffffe1b0) - 0x8 = 0x7fffffffe1a8
- 0x7fffffffe1a8 영역에 저장된 값 : 0x4242424242424242
- 0x400614 코드 영역에서 rax 레지스터에 저장된 값과 fs:0x28 레지스터에 저장된 값을 xor 연산
- 0x40061d 코드 영역에서 rax 레지스터의 값이 0x61061c8ecf993242 이기 때문에 다음 코드 영역(0x40061f)으로 이동
- 이로 인해 프로그램에서 "stack smashing detected" Error 메시지를 출력
3. 바이너리 파일의 보호기법 확인
1) checksec.sh
- checksec.sh에서 아래와 같은 결과 출력
① Canary_Do-not-set : No canary found
② Canary : Canary found
4. "Checksec.sh" 파일에서 Canary 발견 방법
1) Binary
- 아래와 같은 방법으로 바이너리의 Canary 설정여부 확인
- 'readelf' 명령어를 이용해 해당 파일의 심볼 테이블 정보를 가져와서 Canary 설졍여부를 확인
- 파일의 심볼 테이블에 "__stack_chk_fail"가 있으면 Canary가 적용되었다고 판단
2) Process
- 아래와 같은 방법으로 프로세서의 Canary 설정여부를 확인합니다.
- Binary의 확인 방식과 비슷하며, 전달되는 파일의 경로가 다음과 같이 다름 ex) /proc/<PID>/exe
- 추가된 동작은 '/proc/<PID>/exe' 파일에 'Symbol table' 정보가 있는지 확인
'Security > System Hacking' 카테고리의 다른 글
[Dreamhack System Hacking] STAGE 6 (0) | 2022.02.06 |
---|---|
[Dreamhack System Hacking] STAGE 5 - ssp_001 (0) | 2022.01.30 |
[Dreamhack System Hacking] STAGE 5 (0) | 2022.01.30 |
[Dreamhack System Hacking] STAGE 4 - basic_exploitation_001 (0) | 2022.01.30 |
[Dreamhack System Hacking] STAGE 4 - basic_exploitation_000 (0) | 2022.01.30 |
댓글