오랜만에 포너블 문제를 풀었다.
그간 다른 것들을 공부하느라 워게임을 못풀었는데

감떨어질까봐 하나 풀어봤는데, 역시 감이 떨어진 느낌이 들었다.
틈틈히 다시 풀어봐야겠다.!

pwnable.kr 사이트의 echo2 문제이다.

이 문제는 echo 서비스를 실행하는 프로그램을 연결해두었다.


(echo2 문제)


파일을 주기 때문에 직접 다운받아서 분석해볼 수 있다.



(보호기법)


보호기법을 보면 되있는게 없다.
그래서 50점 짜리였나보다. (오래걸리진 않았지만 그닥 쉽게 풀진 않은것으로 보아 감이 많이 떨어진 느낌이다.)

echo2 프로그램에서는 2가지 서비스를 제공한다.
FSB 라는 항목인데 여기서는 스택에 입력을 받았다가, 입력한 문자열을 그대로 다시 화면에 보여주는 기능
UAF 라는 항목에서는 힙영역에 입력을 받아 저장했다가 다시 화면에 보여주는 기능을 한다.

대놓고 어떤 취약점이 있는지 알려주었다.

그러면 FSB 취약점부터 확인해본다!



(fsb 취약점)


printf 에다가 인자를 문자열 버퍼 주소를 그대로 넣는 것을 볼 수 있다.
이렇게 되면 fsb 취약점이 생기게 된다.

그런데 실제로 문제를 풀 때 여기서 조금 헤메었다.
그 이유는
실제 내 컴퓨터에서는 메모리 노출 정보가 달랐다.

아래 사진을 보면서 설명하겠다.



(내 컴퓨터)


내 컴퓨터에서는
64비트 컴퓨터의 함수 전달 방식처럼 레지스터의 값들을 출력해주었다.
rdi, rsi rdx, rcx, r8, r9 이 순서대로 출력이 된다.
실제 위 사진처럼 해당 레지스터 정보가 출력된다.

그런데 실제 서버에 연결을 하였을 때는 달랐다.



(실제 연결시)


실제 연결시 레지스터의 정보들이 나오는 것이 아니라 바로 스택의 정보가 나왔다.
위 사진을 보면 문자열이 나오고 있는 것을 확인 할 수 있다.
이유는 잘 모르겠지만...
이 것 때문에 처음에 만든 exploit을 뜯어고쳤다.
처음에 만든 exploit은 내 컴퓨터에서는 돌아갔는데 서버에서는 동작하지 않았다.
그 이유가 stack 주소를 잘 찾지 못했기 때문이었다.

실제로 연결하였을 때 문자열이 나오는 것을 보고 다시 메모리 정보를 leak하였다.



(눈에 띄는 주소)


해보았을 때 문자열이 다 끝나고 다음의 값들이 나오는 것을 볼 수 있었는데

400acb라는 값이 눈에 띄었다.
나는 이 값이 무엇인지 알고 있었다. 이 주소는 main 함수의 주소였다.

그렇다! ret 주소였다.



(ret 주소)


그렇다면?

그 앞에 있는 것은 rbp 주소! 스택주소를 알아내었다.



(rbp 주소)


그 다음 UAF 취약점이다.
나는 그 동안 heap 영역에 대해서 정리를 해왔는데
이 부분에 있어서 너무 쉽게 응용할 수 있게 되었다.

main에서 함수가 호출 된 후 마지막에 cleanup함수가 호출된다.



(cleanup)


cleanup 함수에서는 o객체를 free해준다.
o객체 안에는 greeting함수와 byebye함수 주소가 있고
실제로 greeting과 byebye함수를 호출할 때 o객체에 접근하여 호출한다.

여기서 4를 입력으로 주어 종료를 시도하면 cleanup 함수가 실행된다.
문제는 그 다음에 다시 정말 종료할 지 묻는다.
이 때 n을 눌러 종료하지 않게 되면
다시 main의 루프로 돌아가게 되는데 이 때는 이미 o객체가 free 된 후에서 프로그램이 진행된다.

echo2함수 안에서 보면



(greeting 함수 호출)


greeting 함수 호출 할 때 o객체에 접근하여



(greeting 함수)


greeting함수를 호출하는 것을 볼 수 있다.


그렇다는 건 이 값을 덮어쓸 수 있다는것! 왜냐!
바로 UAF (3번)을 입력하면 malloc을 다시 주는데 이 주소를 다시 할당해주기 때문이다.


(재할당)


실제로 다시 해보면 malloc을 통해서 받는 주소는 아까 free된 o객체의 주소를 넘겨주었다.
이제 이 주소에다가 0x20 만큼 적을 수 있으므로 greeting 함수위치에 다른 주소를 적을 수 있다는 것이다.

우리는 쉘코드를 스택에 올리고 그 쉘코드 주소를 여기다 적어줄 것이다.

쉘코드를 스택에 올릴 것인데, 바로 맨 처음 이름을 입력받는 부분이다.

입력을 받는 부분은 아래와 같다.



(이름 영역)


이 곳에 쉘코드를 올릴 것이고 그 위에 값을 보면 아까 우리가 확인한 rbp 값을 확인할 수 있다.
0x20 차이가 난다.

exploit 코드를 보면서 정리하겠다.



(shellcode 업로드)


쉘코드를 업로드하는 부분이다. 이름입력할 때 쉘코드를 업로드하고
이 부분은 스택영역이다.

그 후 스택 주소를 찾아서 정확한 쉘코드 주소를 찾아야한다.



(쉘코드 주소 찾기)


그 후 UAF 취약점 공략이다.



(UAF 공략)


UAF를 통해 o객체에 다시 접근하여 greeting 주소 부분에다가 shellcode 주소를 적어준다.

그리고 아무 기능이나 다시 시작하면 greeting 함수가 시작 될때 shellcode가 실행되어 쉘을 얻을 수 있다.



(쉘 획득)


문제 풀이 끝!

'WarGame > 500 Project' 카테고리의 다른 글

(67/500) pwnable.kr - note  (0) 2018.03.29
(66/500) pwnable.kr - rsa_calculator  (1) 2018.03.10
(64/500) backdoor - Enter the matrix  (0) 2017.10.31
(63/500) pwnable.kr - syscall  (2) 2017.10.22
(62/500) NOE.systems - BURYBURY  (0) 2017.10.01


오늘 해결한 문제는 fsb 문제!



(fsb)



FSB가 뭘까 했는데 검색해보니 Format String Bug의 줄임말이었다.
포멧스트링 공격이라..!
기사 공부하면서 배웠던 내용이지만 직접 해보는 건 처음이라 다시 많이 찾아보면서 공부하였다.

단순히 메모리값을 노출시키는데 그치지않고 값 또한 변조할 수 있다는 사실을 알았다.

문제의 소스코드!



(소스코드)



소스코드를 보니 pw와 key가 같으면 쉘을 던져준다.
pw와 key를 같게 해야하니 key를 변조 시키면 되겠다 라는 생각이 들었다.
key는 /dev/urandom 에서 랜덤한 값을 8바이트 가져온다.

fsb 공격의 기회를 4번 주는데 풀면서 이해했는데 왜 4번을 준지 이해했다.
GOT를 overwrite할 수도 있지만 4번을 준 이유는 pw와 key를 같게 하게 해서 풀으라는 문제 출제자의 의도인듯 했다.

처음에 당황했던 것은 찾아보면서 공부할 때는 버퍼가 모두 스택에 있었던 경우라서 버퍼에 직접 주소를 입력할 수 있고 그 주소를 직접 덮어썻는데 문제에서는 버퍼가 전역변수로 설정되어있어 스택에 존재하지 않는다...

그렇기에 스택에 key값의 버퍼 주소를 직접 적어주고 그 주소를 이용해 key값을 덮어 써야한다.
key의 자료형은 unsigned long long 이기에 8바이트 한번에 4바이트씩 덮어 쓸수 있으므로 2번 해야한다. 따라서 4번의 공격 기회를 준것이다.

스택에서 사용할 수 있는 주소를 보자!



(사용할 수 있는 주소)



위 사진을 보면 우리가 쓸만한 변수 주소가 보인다.

0xffedb0 주소에 먼저 key값의 주소를 적을 것이다.



(key값 주소 적기)



포멧스트링 공격을 하고 메모리를 살펴보면



(fsb공격 후 메모리)



key 주소가 덮여 쓰여진 것을 확인 할 수 있다.




(key주소)


key는 총 8바이트 크기의 자료형이므로 그 다음 4바이트도 덮어써줘야하므로 
key주소+4바이트 주소를 적어준다.



(완성)



완성된 주소를 볼 수 있다.
이제 두 주소를 이용해 원하는 값을 적고 pw입력할 때 그 값을 입력할 것이다.

처음에는 0101010101010101 를 입력하려고 했다.



(key 덮어쓰기)



이렇게 덮어쓰면 key 첫 4바이트에 01010101 이 덮어쓰여지는 것을 볼 수 있다.


(key 변조)



이렇게 그 다음 4바이트도 덮어 쓸 수 있다.

하지만 pw를 입력하는데에 문제가 있었다.
입력할 때 strtoull 함수를 이용한다.
입력한 수를 코드를 보면 인자로 10을 주어 입력된 문자열을 10진수로 인식하여 unsigned long long 자료형에 맞추어 숫자로 바꾸어준다.

그런데 어셈블 코드가 좀 수상했다.



(strtoull 근방 코드)



SAR ? 
31바이트를 오른쪽으로 움직인다. 부호를 신경써서. 즉 0이나 1 밖에 나올 수 없다.

0101010101010101 를 만들기 위해 값을 입력해보겠다.



(테스트)



eax와 edx에 값이 잘 들어가는 것을 볼수 있다.



(잘 들어간 값)



그런데 그 뒤 코드들 때문에 4바이트가 날아간다...




(0이 되버림)



음수를 입력하면 -1이 되고 양수를 입력하면 0 이 된다.

즉,,, key 주소 다음 4바이트에 있는  값이 0이되거나 ffffffff 이 되야한다.

검색을 해보던 중 해결할 만한 방법을 찾아냈다.



(0 입력)



%20$n

20번째 위치 인자 주소에 출력된 바이트 수를 입력한다. 여기서는 출력되는게 없으므로 0바이트!



(입력된 0바이트)



0바이트가 입력된 것을 확인 할 수 있다.

key값을 전부 0으로 만들고 0을 입력할 것이다.!

자! 그럼 공격을 해보자!



(key 주소 입력)



(key+4 주소 입력)



주소를 입력하고 그 주소에 있는 값을 0으로 덮어쓴다.



(key 값)



(key+4 값)



그 후 0을 입력하면 성공!~



(성공!)



쉘을 획득했다.


(문제 해결)

'WarGame > 500 Project' 카테고리의 다른 글

(60/500) pwnable.kr - crypto1  (0) 2017.08.27
(59/500) pwnable.kr - dragon  (0) 2017.08.17
(57/500) pwnable.kr - ascii_easy  (2) 2017.08.09
(56/500) pwnable.kr - asm  (0) 2017.07.14
(55/500) pwnable.kr - uaf  (0) 2017.07.12

+ Recent posts