[Pwnable.xyz - TLSv00]
Wargmae/Pwnable.xyz

[Pwnable.xyz - TLSv00]

728x90

 

Excute

먼저 다운로드 한 파일을 실행시키면 다음과 같은 형태의 프로그램이 실행 된다.

프로그램 실행 결과

Key-generate load flag 그리고 print flag를 선택해 줄 수 있으나 당연히 2번이나 3번 옵션을 실행하면 flag를 노출시키지 않는다. 2번의 경우 can’t open flag 를 출력하고 프로그램이 종료되며 3번 옵션의 경우 WARNING: NOT IMPLEMENTED를 출력하고 Wanna take a survey instead?를 출력하는데 아무 값을 입력하지 않아도 Segmentaion fault가 나온다.

 


 

Analyze

먼저 문제 파일에 어떤 보호기법이 걸려있는지 조회하기 위해 gdb에 올려 checksec명령을 진행하여 확인하였다.

Mitigation

 

그리고 Hex-ray에 올려 main 함수를 확인하여 프로그램의 전반적인 흐름을 파악한다.

main

main 함수

  • Line 9 : generate_key 함수 실행
  • Line 19~21 : v3 2인 경우 load_flag 함수 실행
  • Line 25~29 : v3 1인경우 key_len을 받고 generate_key함수 실행
  • Line 31~34 : v33인 경우 print_flag함수 실행

generate_key

generate_key함수

  • Line 11 : memset함수를 사용해 s배열을 0x48만큼 0으로 초기화
  • Line 12~23 : open 함수를 이용해 /dev/urandom을 열어 s배열에 난수를 a1만큼 저장해준 후 배열의 전체를 돌면서 0이 들어있으면 그부분을 채우고 strcpy를 통해 s배열 값을 key변수에 복사한다.

 

 

Load_flag

load_flag함수

 

  • Line 6 open함수를 이용해 flag를 연다.
  • Line 12 read함수를 통해 0x40만큼 flag변수(전역변수) flag파일로부터 읽어 들인 값을 저장한다
  • Line 13~14 for문으로 0에서 0x3f번 반복하며 flag[i] = flag[i] ^ key[i] 를 통해 flag배열에 결과적으로 암호화된 값이 저장된다.

 

 

Print_flag 함수

print_flag함수

  • Line 6 do_comment변수를 result변수에 대입해준다.
  • Line 7 do_comment의 주소가 0이고 입력 값이 121(‘y’)일 경우 do_comment의 주소를 f_do_comment(함수의 경우 함수이름 자체가 함수 호출 주조이다.)로 바꾸어주고 result변수에 바뀐 do_comment 값을 넣어준다.

 

f_do_comment 함수

f_do_comment함수

  • Read 함수로 buf변수에 0x21만큼 입력을 받는다.

 

여기까지 핵심이라고 생각되는 함수들을 전반적으로 살펴 보았으나 print_flag함수에서 기대와 다르게 flag값을 출력시켜주지 않는다. 그러다 IDA에서 real_print_flag함수를 확인 할 수 있었다.

 

 

real_print_flag

real_print_flag

실질적으로 flag를 출력해주는 함수임을 확인 할 수 있다.

 

 


 

 

Solve

전반적으로 프로그램의 구성을 살펴보았다. 해결방법을 살펴보던 중 real_print_flag함수와 f_do_comment함수가 매우 가까운 위치에 존재한다는 것을 확인할 수 있었다.

함수 시작 주소 확인

두 함수 모두 마지막 한 바이트를 제외하면 모두 같은 값을 가지는 것을 알 수 있다. 그런데 아까 print_flag함수에서 특정 조건하에서 do_comment변수의 값을 f_do_comment함수의 주소로 새롭게 대입시켜주는 것을 확인 할 수 있는데 만약 여기서 대입시키는 값을 마지막 1 바이트의 값이 0x00이 될 수 있도록 조작 해주면 real_print_flag함수를 호출 할 수 있을 것이다. 따라서 현재 목표는 정확히 result변수에 대입되는 값에서 하위 1바이트를 00으로 바꿀 수 있는 방법을 찾아야한다.

 

가장 의심스러운 부분으로 generate_key 함수에 포함된 strcpy함수를 생각해 볼 수 있다.main함수에서 generate_key함수의 인자로 63을 주는 것을 확인할 수 있는데 실제 generate_key함수 내부에서는 입력값을 0x40(64)까지 제한하는 것을 확인 할 수 있다.

이러한 이유 때문에 generate_key함수를 자세히 들여다 보다 strcpy함수를 확인 할 수있었다. strcpy함수는 마지막에 null바이트를 붙여 주기 때문에 0x40만큼 더미 없이 완전히 꽉 채워준 형태로 전달하게 되면 결과적으로 0x41만큼이 복사되며 해당 공격을 off-by-one공격이라고 한다.

bss영역 확인

Bss에 위와 같이 변수들이 선언 되어있다. 따라서 위에서 말한 것처럼 원래 f_do_comment의 주소가 들어있는 do_comment 변수의 마지막 하위 1바이트를 00으로 만들 수 있을 것이다. (전역변수는 낮은 주소에서 큰 주소로 자란다) 여기까지의 추론으로 real_print_flag 함수를 호출 할 수 있게 되었다.

하지만 여기서 문제가 발생하는데 real_print_flag는 이미 xor연산을 통해 암호화된 flag값을 출력해주기 때문에 off-by-one을 이용해 성공적으로 real_print_flag함수를 호출 하였더라도 문제는 해결되지 않는다.

 

여기까지의 해결방법을 우선 정리하면  

Sol)

1.     Option 3에서 y를 입력해 f_do_comment의 주소를 do_comment에 대입해준다

2.     Option 1를 선택해 0x40(64)를 입력해 key배열을 꽉 채워 off-by-one 공격을 트리거 한다.

3.     Option 2를 선택해 flag를 암호화된 형태로 로드해준다.

4.     Option 3에서 n(y만 아니면 상관없다)을 입력해 real_print_flag함수를 호출 시킨다.

 

이제 암호화 되어있는 flag를 복호화 시킬 방법을 찾아야한다. 먼저 암호화되는 방식은

flag[i] = flag[i] ^ key[i]이다. 만약 앞에서 말한 sol 1~2를 진행해서 do_comment real_print_flag의 주소를 성공적으로 넣어주었다면 key의 길이를 0부터 차근차근 올려가면서 strcpy함수가 호출될 때 key의 마지막 바이트에 null(0x00)이 들어가는 것을 이용하면 xor연산의 특징을 이용해 암호화가 애초에 진행되지 않은 상태의 flag를 얻어 낼 수 있다. (xor연산에서 00을 연산하면 자기자신이 나온다.) 키의 길이를 0부터 63까지 입력해주며 64회 수행하면 복호화 된 flag를 얻을 수 있을 것이다.

 

 

 

결과적으로 문제해결을 위한 솔루션은 다음과 같다.

 

Sol)

1.      Option 3에서 y를 입력해 f_do_comment의 주소를 do_comment에 대입해준다

2.      Option 1을 선택해 0x40(64)를 입력해 key배열을 꽉 채워 off-by-one 공격을 트리거 한다.

3.      Option 1을 선택하고 key배열을 재설정한다.

4.      Option2를 선택하고 flag를 로드한다.

5.      Option3를 선택해 변조된 주소인 real_print_flag함수를 출한다

6.      3,4,5를 반복적으로 실행해준다.

 

 

exploit코드는 아래와 같다.

Flag를 확인할 수 있다. 다만 어떤 문제인지 확인 할 수 없으나 중간중간에 잘못 출력 되는 문자들이 발생한다. 작성한 exploit을 여러 번 실행시켜 완전한 flag를 얻을 수 있었다. 또한 flag의 첫번쨰 값은 알 수 없기 때문에 플래그 형식상 F를 예상 할 수 있어 스크립트를 쓸 때 F로 설정해 주었다.

728x90

'Wargmae > Pwnable.xyz' 카테고리의 다른 글

[Pwnable.xyz – Punch it]  (0) 2021.01.17
[Pwnable.xyz - PvP]  (0) 2021.01.13
[Pwnable.xyz - J-U-M-P]  (4) 2021.01.07
[Pwnable.xyz - Welcome]  (1) 2021.01.02