CTF solver & Writeup author

- cheese



CEMU

Welcome to MATRIX

nc 175.119.158.136 31337

nc 175.119.158.132 31337



제시하는 조건에 따라 바이트 코드를 전송하는 어셈블리 코딩 문제이다.

문제는 총 다섯 개의 스테이지로 구성되어 있으며, nc 로 접속해 보면 현재 레지스터의 값과 함께 스테이지 클리어 조건을 제시한다.

스테이지별 클리어 조건은 아래와 같다.



Stage 1

서버에서 제시하는 값에 맞게 레지스터를 세팅하는 Opcode 를 작성하여 보낸다. (mov eax, 121212 / mov bx, 111, ...)


Stage 2

EAX + ESI - ESP * ECX = 4211345 와 같이, 레지스터를 이용한 방정식이 주어진다.

Stage 1에서와 마찬가지로, 조건에 맞게 레지스터를 세팅해 주는 Opcode 를 작성하여 풀이한다. 

식의 첫번째 레지스터는 항상 EAX 이며, 다음 사칙연산기호는 + 와 * 밖에 나오지 않았으므로 그에 맞게 코드를 작성했다.


Stage 3

Secret memory 를 찾는 문제이다.

문제에 별 다른 정보가 없었기 떄문에, 우선 secret memory 내에 특정 데이터가 있을 것이라고 판단하고 메모리 주소를 brute force 하는 방식으로 풀이를 시도했다.

간헐적으로 키값으로 추정되는 데이터의 일부가 나타났으나, ASLR 이 걸려 있는지 주소값이 계속 바뀌어 풀이 방법을 변경했다.

코드 외의 영역이 모두 0x00 으로 덮여 있는 점을 이용하여, 메모리를 탐색하다가 0x00 이 아닌 값을 발견했을 때 정지하도록 하는 간단한 어셈블리 코드를 작성하여 해결하였다.


Stage 4

Stage 1 과 비슷한 문제로, 서버에서 EIP 값을 제시한다. 간단한 계산을 통해 nop sled 코드를 작성하여 해결하였다.


Stage 5

flag 파일을 읽는 것이 문제이며, 간단한 system call 코드를 전송하니 함수 호출에 대한 결과를 돌려주었다.

sendfile 이 예상처럼 동작하지 않아, 임시방편으로 open/read/mov 코드를 작성했고 flag 를 얻을 수 있었다.




ex.py


from pwn import *

def ex():
	conn = remote('175.119.158.136', 31337)

	# stage 1
	conn.recvuntil('below')
	print conn.recvline()
	eax = int(conn.recvline()[6:],16)
	ebx = int(conn.recvline()[6:],16)
	ecx = int(conn.recvline()[6:],16)
	edx = int(conn.recvline()[6:],16)
	esp = int(conn.recvline()[6:],16)
	ebp = int(conn.recvline()[6:],16)
	esi = int(conn.recvline()[6:],16)
	edi = int(conn.recvline()[6:],16)

	ex = ""
	ex += asm('mov eax, 0x%x'%eax).encode('hex')
	ex += asm('mov ebx, 0x%x'%ebx).encode('hex')
	ex += asm('mov ecx, 0x%x'%ecx).encode('hex')
	ex += asm('mov edx, 0x%x'%edx).encode('hex')
	ex += asm('mov esp, 0x%x'%esp).encode('hex')
	ex += asm('mov ebp, 0x%x'%ebp).encode('hex')
	ex += asm('mov esi, 0x%x'%esi).encode('hex')
	ex += asm('mov edi, 0x%x'%edi).encode('hex')
	ex += '\n'
	conn.send(ex)

	# stage 2
	conn.recvuntil('below')
	conn.recvline()
	equatation = conn.recvline()
	print equatation
	eax = int(equatation[equatation.find('=')+2:])

	ex = ""
	if equatation[4] == '*':
		ex = ""
		ex += asm('mov eax, 0x%x'%eax).encode('hex')
		ex += asm('mov ebp, 0x1').encode('hex')
		ex += asm('mov ebx, 0x0').encode('hex')
		ex += asm('mov ecx, 0x0').encode('hex')
		ex += asm('mov edx, 0x0').encode('hex')
		ex += asm('mov esp, 0x0').encode('hex')
		ex += asm('mov esi, 0x0').encode('hex')
		ex += asm('mov edi, 0x0').encode('hex')
		ex += '\n'
		# eax = key, ebp = 1
	else:
		ex = ""
		ex += asm('mov eax, 0x%x'%eax).encode('hex')
		ex += asm('mov ebp, 0x0').encode('hex')
		ex += asm('mov ebx, 0x0').encode('hex')
		ex += asm('mov ecx, 0x0').encode('hex')
		ex += asm('mov edx, 0x0').encode('hex')
		ex += asm('mov esp, 0x0').encode('hex')
		ex += asm('mov esi, 0x0').encode('hex')
		ex += asm('mov edi, 0x0').encode('hex')
		ex += '\n'
		# eax = key, ebp .. = 0

	conn.send(ex)
	conn.recvuntil('Stage2 Clear!')
	
	#stage 3
	print conn.recv(1024)
	
	ex = ""
	ex += asm('mov eax, 0x1100').encode('hex')
	ex += asm('mov ecx, eax').encode('hex')
	ex += asm('nop').encode('hex')*100
	ex += asm('add ecx, 1').encode('hex')
	ex += asm('add dl, [ecx]').encode('hex')
	ex += asm('cmp dl, 0x0').encode('hex')
	ex += "74f0" # JE (EIP+5)-0x10 (jmp to nopsled)
	ex += asm('mov eax, ecx').encode('hex')
	ex += "\n"
	conn.send(ex)

	#stage 4
	print conn.recvuntil('EIP:')
	value = int(conn.recvline().strip(), 16)
	print conn.recv(1024)

	ex = ""
	ex += asm('nop').encode('hex')*(value-0x1000)
	ex += "\n"
	conn.send(ex)

	# stage 5
	print conn.recv(1024)

	ex = ""
	ex += asm('push 0x00').encode('hex')
	ex += asm('push 0x67616c66').encode('hex') # filename 'flag'

	ex += asm('mov ebx, esp').encode('hex')
	ex += asm('xor ecx, ecx').encode('hex')
	ex += asm('push 0x5').encode('hex')
	ex += asm('pop eax').encode('hex')
	ex += asm('cdq').encode('hex')
	ex += asm('int 0x80').encode('hex') # open()
	
	ex += asm('mov ebx, eax').encode('hex')
	ex += asm('mov eax, 0x3').encode('hex')
	ex += asm('mov ecx, 0x2000').encode('hex')
	ex += asm('mov edx, 0x64').encode('hex')
	ex += asm('int 0x80').encode('hex') # read ()

	ex += asm('mov eax, [0x2000]').encode('hex')
	ex += asm('mov ebx, [0x2004]').encode('hex')
	ex += asm('mov ecx, [0x2008]').encode('hex')
	ex += asm('mov edx, [0x200c]').encode('hex')
	ex += asm('mov esp, [0x2010]').encode('hex')
	ex += asm('mov ebp, [0x2014]').encode('hex')
	ex += asm('mov esi, [0x2018]').encode('hex')
	ex += asm('mov edi, [0x201c]').encode('hex')
	ex += asm('mov eax, [0x2020]').encode('hex') # get data from read()
	ex += "\n"
	conn.send(ex)

	while True:
		try:
			print conn.recv(1540)
		except: 
			break

	conn.close()
	print "done!"

if __name__ == "__main__":
	ex()


'Writeup' 카테고리의 다른 글

Codegate 2016 - fl0ppy  (2) 2016.03.20

+ Recent posts