아...정말로 이 문제 풀다가 pwnable과 손절할뻔 했다....

우선 main문은 별게 없다. 그냥 buf에 보고싶은 값을 10진수로 입력받으면 해당 값을 주소로 변환해서 출력해주고, src에 값을 입력해주면 print_message에서 출력해준다음 끝나는 문제이다.

print_message함수를 자세히 보면 dest에 데이터를 넘겨주고 출력하는데 아까 main문에서 본 read함수의 입력값보다 dest의 값이 훨씬 작음으로 bof가 일어난다. 해당 함수의 ret를 잘 덮어 system함수값을 입력해주면 끝날 것 같다......라고 생각했는데 libc의 sh를 사용하지 않고 풀어야했다.(문제 난이도 급상승...)

일단 sh를 적을 공간이 필요했는데, bss에 적기에는 여분의 공간이 너무 적었다....해서, 스택을 이용해 문제를 풀기로 했다.

스택에 "sh"를 넣고 슥 풀면 문제가 해결된다. (절대 쓰기 귀찮아서 안쓰는게 아님)

'war game > game' 카테고리의 다른 글

[practice]-2015410208  (0) 2019.08.17
[practice]-2015410212  (0) 2019.08.12
[practice]-19950320  (0) 2019.07.28
[practice]-daRk_TempLer  (0) 2019.07.23
[practice]-rain_dROP  (0) 2019.07.23

오늘도 짱짱아이다로 열어보니 대학교 팀을 고르고 game함수가 있는 조건문으로 뛰어서 스코어가 121209이상이면 조건문 안으로 들어오는 것 같다. 해당 조건문에 들어오면 read함수에서 s크기보다 더 많이 받아주는 것을 볼 수 있다. bof취약점이다. 해당 부분을 맞춰주고, sh같은 문자가 들어있는지 검사한 뒤에 마지막으로 buf가 변조되었는지 봐주고 함수가 종료된다.

우선 game함수를 보면 menu함수에서 menu출력해주고 경기할 값을 입력해주면 해당 값에 따라 gogo함수에서 진행해서 전역면수 score값을 바꿔준다. 7번은 숨겨진 항목!

score은 unsigned int이고, gogo에는 score을  -- 해주는 기능이 있음으로 score값이 -가 되면 엄청 큰 숫자로 바뀌게 된다.

원하는 조건문까지 들어온 것을 확인할 수 있다. 보면 ebp가 0x124만큼 떨어져 있음으로 저만큼 채우고 ret값에 system함수 주소 넣어주고   sh주소 찾아서 인자로 넣어주면 될 것 같다......라고 생각했는데 오류가 떴다

확인해보니 memcmp함수에서 buf와 random_bak을 비교해주더라. s을 덮으면서 buf도 같이 덮어서 그런거 같은데 buf값을 어케 확인해 줄까 고민하다가 4u가 눈에 띄었다. team이름을 정하는 부분에서 printf함수를 보면 %s가 \n이 나올때까지 출력한다 한다. 그 앞에 read함수는 4u만큼 입력값을 받는데 생각해보면 뒤에 atoi로 변환해 v8에 넣어주고 nptr은 출력해주는 것을 볼 수 있다. 그럼 read에서 `1aaa`를 넣어주면 \n도 안들어가니 계속 출력될 것 같다. 

이런식으로 작성해주면 되겠다!....했는데 되지 않는다...

다시 덮은 스택을 보고 있는데 포인터로 선언된 v10이 마음에 걸렸다. 해당 부분을 맞춰줘야 하나 싶어 주소를 찾아 넣어주니 해결 되었다!

'war game > game' 카테고리의 다른 글

[practice]-19950320  (0) 2019.07.28
[practice]-daRk_TempLer  (0) 2019.07.23
[practice]-rain_dROP  (0) 2019.07.23
[practice]-catchme  (0) 2019.07.16
[practice]-rop_practice64  (0) 2019.07.15

아....64bit rop는 거의 처음이였는데 삽질만 100만번 한 것 같다....

우선 짱짱 아이다로 문제를 열어보면 사용할 수 있는 함수가 puts, read함수 두개이다.  (32bit rop에서 wirte함수로만 풀어봐서 puts는 처음이라 당황했다.)

 

조사해보니 64bit rop는 인자를 받는 피연산자가 굉장히 중요하다더라. 인자 받는 순서는 rdi, rsi, rdx순서이다.

그럼 우선 rop를 하기위해 gadget를 찾아보자.

이런식으로 ROPgadget 명령어를 입력하면 찾을 수 있다.

pead를 이용해서도 찾을 수 있다. gadget을 확인해보니 'pop rdx'가 없어서 libc에서 찾아보도록했다. 

rp를 이용해서 찾으면 저런식으로 libc에서 해당 gadget의 offset을 구할 수 있다. 나중에 libc base를 leak해서 더해주면 사용할 수 있다.(rp는 그냥 사이트에서 다운받으면 되지만, 난 mac이여서 chmod도 해줘야했다. 삽질..ㅎ)

 

이제 plt의 주소를 구해줘야 하는데 난 귀찮아서 ELF를 이용해 구했지만 직접 구할 수도 있다.

 

짱짱 아이다 functions window라던가

gdb-peda p 명령어 라던가.

 

이제 plt도 구했으니 offset을 구해보자.

우선 gdb peda에서 info proc map으로 libc base주소를 찾아주고,(b*main 같은거 하고 r 해주고 해야한다.)

이런 식으로 함수의 offset을 구해주면 기본적인 준비는 다 끝났다.

 

이제 pwntools이용해서 페이로드만 잘 써주면 되는데 여기서도 엄청나게 삽질을 했다.

우선 gadget rdx를 쓰려면 offset만 구한 것 임으로 libc base leak를 해줘야 한다. 그런데 입력은 read로 한번만 받으니 답이 안나왔다.

페이로드를 두번 보낼 수도 없고...........(?) 라고생각하면서 생각해보니 처음 페이로드로 leak을 하고, 그 뒤에 ret에 main주소를 넣어서 다시 돌아오면 두번 쓸 수 있을 것 같았다.

main주소 구해주고,

 

이런식으로 leak해줬다. 여기서도 보면 raw_input('AA')는 페이로드 중간에 멈추게 해서 다른 창으로 pid를 입력하면 디버거 할 수 있게 해줘 주소가 잘 들어갔는지 확인 할 수 있고, recv(1024)는 계속 인자를 받아봤는데 쓰레기값이 들어가는 것 같아 덮인게 잘못 들어갔나 싶어 넣어줬더니 되었다.(아직 잘 모른단 소리)

저런 식으로 libc 주소를 leak하고, read_addr에도 실 주소를 저장해서 다음 페이로드 때 system_offset에서만 더해서 계산하면 system주소를 read_got에 덮을 수 있다.

마지막으로 다시한번 페이로드를 보내면 해결 되었다.

아 추가로 삽질 한게 있는데 rdx gadget을 보면 pop rdx; pop rsi; ret이다. 따라서 인자 순서를 반대로 넣어줘야한다,...(이거로도 몇시간,,,)

 

최종 페이로드...ㅎ

'war game > game' 카테고리의 다른 글

[practice]-19950320  (0) 2019.07.28
[practice]-daRk_TempLer  (0) 2019.07.23
[practice]-rain_dROP  (0) 2019.07.23
[practice]-derby  (0) 2019.07.17
[practice]-catchme  (0) 2019.07.16

+ Recent posts