0x00000000000006b2 <+8>: mov rax,QWORD PTR fs:0x28
0x00000000000006bb <+17>: mov QWORD PTR [rbp-0x8],rax
0x00000000000006bf <+21>: xor eax,eax
위 코드와 같이 rbp 직전에 8바이트 만큼의 공간에다 fs:0x28, 즉 카나리 값을 넣는걸을 볼 수 있다.
0x00000000000006dc <+50>: mov rcx,QWORD PTR [rbp-0x8]
0x00000000000006e0 <+54>: xor rcx,QWORD PTR fs:0x28
0x00000000000006e9 <+63>: je 0x6f0 <main+70>
0x00000000000006eb <+65>: call 0x570 <__stack_chk_fail@plt>
마지막에 이를 fs:0x28값과 xor 시켜 0, 즉 참(어셈 조건문은 0일때 참이다) 일 때 점프 시켜 프로그램을 정상 흐름으로 돌려놓는다.
*(리눅스의 fs는 Thread Local Storage(TLS)를 가리키는 포인터, 세그먼트 레지스터이다. TLS엔 다양한 프로그램 실행에 필요한 데이터들이 저장되어 있다.)
카나리 생성과정
먼저 gdb 명령어 "catch"를 사용하여 gdb의 특정이벤트, 카나리 생성 이벤트를 탐지, catchpoint를 설정하려면
catch syscall arch_prctl 을 입력해야한다. (arch_prctl은 fs의 값을 설정할 때 호출되는 시스템 콜이다.)
그 결과 rdi에 ARCH_SET_FS의 상숫값과 rsi에 0x7fff.,,,,,(TLS 저장주소)를 알 수 있다.
카나리는 fs+0x28 이므로, TLS주소 + 0x28 에 존재한다.
gdb의 "watch"라는 명령어는 해당 주소에 저장된 값이 변경되면 프로세스를 중단 시키는 명령어 이다.
이를 사용해 TLS+0x28, 카나리 값이 설정되는 순간을 볼 수 있다.
그 결과 securiry_init()/ rtld.c 함수에서 설정된다는 것을 알 수 있다.
카나리 우회
##PASS
완벽한 방패는 없다 했는가.. 카나리 역시 우회하는 방법이 있었으니...
"우리의 만능 해결사 등장!!!"
Brute Force....라고 할뻔... ㅋ Brute Force를 쓰면 풀리긴 하나, 이는 실제 서버에 적용할 수 없으며 최대 64bit -> 256^7, 32bit -> 256^3번의 연산이 필요하다.. 흠,, 뻘짓을 하고 싶다면 추천! 물론 로컬에서..
##PASS
TLS 접근
TLS에 전역변수로 카나리가 저장된다. 이는 매 함수 마다 참조 하므로, 다른 실행의 프로그램이 아닌 이상 같은 카나리가 사용된다. --> 실행중 TLS의 주소를 알고, 임의 주소에 대한 읽기 또는 쓰기가 가능하다면, TLS의 카나리 값을 읽거나, 임의의 값으로 조작 가능!
결과: 카나리를 leak 하여 익스 가능.
익스 방법: buf를 받고 이를 출력한다는 시나리오 일때, buf를 canary까지 오버플로우 한다. 단 하위 1바이트 만을 침범시켜야한다. 그 이후는 canary의 하위 1바이트는 구별을 위해 \x00으로 하기 떄문.
'Pwnable > Tech' 카테고리의 다른 글
FSB 에 대해 (0) | 2022.02.07 |
---|---|
PIE와 RELRO (0) | 2022.01.27 |
-Heap- Tcache Poisoning (0) | 2022.01.06 |
-Heap- DFB(Double Free Bug) (0) | 2022.01.05 |
-Heap- ptmalloc2의 구조 (0) | 2022.01.05 |