CTF

Canary 우회 ( __fortify_fail() 및 환경변수env를 이용한 Arbitrary Read)

JUNFUTURE 2024. 4. 17. 14:30

1. flag 값을 전역변수(주소를 알고있는) 에 저장하는 루틴이 있음

2. 주어진 함수나 ROP를 이용해 write할 수 있는 방법이 없음(출력 -> leak 불가)

3. __fortify_fail() 을 이용하여 환경변수에서 파일 이름을 가져오는 경우

 

사용할 수 있는 canary leak 방법이다.

 

int __cdecl main(int argc, const char **argv, const char **envp)
{
  char buf[256]; // [esp+4h] [ebp-10Ch] BYREF
  unsigned int canary; // [esp+104h] [ebp-Ch]

  canary = __readgsdword(0x14u);
  read_flag();
  read(0, buf, 512);
  return 0;
}

 

카나리가 적용된 예시 코드(의사코드)로 위를 보면, read_flag 에서는 플래그 파일을 읽어서 특정 전역 변수에 저장해준다고 가정하자.
이때 해당 함수에는 read 외에는 출력할 수 있는 방법이 전혀 없어 사용자의 입력을 단한번 받은 뒤에 프로그램이 종료된다.

이런식으로 ./target 이라는 파일 이름을 가진 바이너리에 canary가 걸려있을때, 
canary가 detect되는 경우 ./target terminated 라는 파일이름과 함께 종료됐음을 나타내는 메세지를 띄워줄 수 있다.

 

이는 __fortify_fail() 에서 환경변수에 저장된 target 이라는 파일 이름을 가져오기 때문인데,
환경변수가 저장된 위치를 나타내는 주소가 스택에 있기 때문에, 만약 overflow가 발생하면

스택에 있는 이 주소를 바꿔 임의주소에 있는 값을 읽을 수 있다.

 

아래 사진을 살펴보면 ./targe이라는 이름을 읽어오는 주소는 0xffc80d14 이고

지역 버퍼는 0xffc80b3c인 것을 알 수 있다.

 

0xffc80d14 - 0xffc80b3c 는 0x1d8(십진수로 472)로 지역버퍼 크기인 512보다 작고, 스택 버퍼 오버플로우를 이용해 덮어쓸 수 있는 주소가 된다.