2023. 1. 18. 16:51ㆍsystem(pwnable)시스템(포너블)/Dreamhack wargame
이 프로그램은 카나리(Canary) 및 NX 비트(Non-Executable bit) 보호 기법이 적용되어 있었으나, PIE(Position-Independent Executable)가 적용되지 않아 Return-to-Library (RTL) 공격이 가능하다.
풀이요약
1. 카나리 값을 누출하여 보호 기법을 무력화
2. 고정된 함수 주소(system@plt)와 /bin/sh 문자열 주소를 활용하는 ROP 체인(Return-Oriented Programming Chain)을 구성
3. 임의 코드 실행(RCE) 권한을 획득
4. 최종적으로 쉘(Shell)을 획득
1. 문제 파일 취약점 정리
취약점 : 스택 기반 버퍼 오버플로우
CVE/CWE : CWE-120: Buffer Copy without Checking Size of Input
공격 기법 : 카나리 누출을 이용한 Return-to-Library (RTL) / ROP
2. 취약점 상세 분석
2.1. 취약 시스템 및 코드
- 타겟 파일: rtl (Linux ELF 64-bit)
- rtl.c 파일 내용
char buf[0x30];
// ...
// [1] Leak Canary
read(0, buf, 0x100); // 첫 번째 read
// ...
// [2] Overwrite return address
read(0, buf, 0x100); // 두 번째 read
적용된 보안 대책 (Checksec 결과)
- Canary → 적용됨
- NX Bit → 적용됨
- PIE → 미적용
2.2. 취약점 내용
- 버퍼 오버플로우: 지역 변수 buf는 스택에 0x30 (48) 바이트로 할당되었으나, read 함수는 사용자로부터 최대 0x100 (256) 바이트를 읽어들이도록 설정되어 있음
이로 인해 buf의 경계를 넘어 스택 프레임 포인터(SFP), 스택 카나리, 저장된 복귀 주소(Return Address)까지 덮어쓸 수 있는 전형적인 스택 기반 버퍼 오버플로우가 발생가능 - RTL 공격 조건: 바이너리에 PIE가 적용되지 않아, system@plt와 전역 변수 /bin/sh 문자열의 주소값이 실행 시마다 고정되어 있다 이것이 ASLR이 적용되어 있더라도 ROP 체인을 구성할 수 있게함
3. 공격 시나리오 (Exploitation Scenario)
공격의 목표는 두 번째 버퍼 오버플로우를 통해 복귀 주소를 system("/bin/sh")을 호출하는 ROP 체인으로 덮어쓰는 것입니다.
3.1. 공격 단계
- 카나리 누출 (Canary Leak):
- 첫 번째 read 함수를 이용해 버퍼 크기(0x30)와 더미 공간(0x8)을 넘어 카나리까지 포함하는 0x39 바이트의 페이로드를 전송합니다.
- printf 함수가 해당 내용을 출력할 때, 누출된 카나리 값을 파싱하여 다음 공격에 사용할 수 있도록 확보합니다. (Canary의 첫 바이트는 Null Byte(\x00)로 처리되어 printf에서 문자열 종료로 인한 누락을 방지합니다.)
- ROP 체인 구성 및 복귀 주소 덮어쓰기:
- 두 번째 read 함수를 이용해 다음과 같은 ROP 체인을 구성하여 복귀 주소를 덮어씁니다.
- 패딩 (Padding): buf부터 카나리 직전까지의 공간 (0x38 바이트).
- 카나리 (Canary): 누출된 카나리 값.
- SFP (Saved Frame Pointer): 임의의 값 (0x8 바이트).
- ROP Chain
1. ret_gadget: 스택 정렬을 위해 사용
2. pop rdi; ret 가젯: /bin/sh 주소를 64비트 호출 규약의 첫 번째 인자 레지스터인 RDI에 로드하기 위해 사용.
3. /bin/sh 문자열 주소: system() 함수의 인자
4. system@plt 주소: 최종적으로 실행할 함수
- 두 번째 read 함수를 이용해 다음과 같은 ROP 체인을 구성하여 복귀 주소를 덮어씁니다.
4. 해결 방안 (Solution and Mitigation)
- 입력 길이 검증 강화
- 취약 코드에서 read(0, buf, 0x100); 대신 read(0, buf, sizeof(buf)); 또는 read(0, buf, 0x30);와 같이 buf의 실제 크기만큼만 읽도록 코드 수정하기
- 버퍼 오버플로우 위험이 있는 read() 대신 **fgets()**와 같이 버퍼 크기를 지정하는 안전한 함수를 사용하기
- 컴파일 옵션 강화 (PIE 적용)
- 바이너리 컴파일 시 PIE 옵션(-fPIE -pie)을 필수적으로 적용하여 코드와 데이터 섹션의 주소를 매 실행마다 무작위로 변경하기 (고정된 주소를 활용하는 RTL/ROP 공격을 차단하는 가장 근본적인 방법임)
- W^X 정책 준수
- NX 비트가 활성화된 경우에도, 런타임에 메모리 영역이 쓰기 가능인 동시에 실행 가능하지 않도록 W^X (Write XOR Execute) 하기
'system(pwnable)시스템(포너블) > Dreamhack wargame' 카테고리의 다른 글
| [Dreamhack] shell_basic (0) | 2022.11.03 |
|---|---|
| [Dreamhack] basic_exploitation_000(2) (0) | 2022.10.05 |
| pwndbg, pwntools 설치 오류 (0) | 2022.10.02 |
| [Dreamhack]basic_exploitation_000 빌드업(pwntools, gdb peda사용법) (0) | 2022.09.25 |