다양한 기록

Return-Oriented Programming (ROP) 본문

운영체제보안

Return-Oriented Programming (ROP)

라구넹 2024. 12. 6. 00:31

공격자는 system()을 쓰고 싶은데 libc에 없음..

=> fork 다음 exec을 할 수 있음

 

공격자 입장

- 악의적인 코드 주입, 라이브러리 함수 호출도 안하고, 본래 코드 조작도 안하고 임의의 연산을 하는 방법을 만들어보자

-> ROP

* 그러나 여전히 스택 내용은 변조해야 함

 

명령어의 조각을 찾아야 함

명령어들의 순차 .. 각 sequence는 2~5개의 명령이고, return 으로 끝남

시퀀스들이 체이닝되어 모여 가젯 (gadget)

가젯은 특정한 일을 수행 (ex. 로드, 스토어, xor, branch)

=> 가젯들을 결합하여 원하는 액션을 강제로

 

시퀀스들을 차례차례 실행하게 하고 싶으면 버퍼를 넘치게해서 각 시퀀스들의 시작 주소들을 넣으면 됨

 

ROP

- 인스트럭션 시퀀스와 가젯의 관계

- Instruction sequence : ret instruction(return)으로 끝나는 명령어들의 시퀀스

- Gadget : 여러 인스트럭션 시퀀스로 구성

Input example:

pattern1 + pattern2 + ret_addr_1 + ret_addr_2 + ret_addr_3 + Argument + ret_addr_4 + ret_addr_5 + ret_addr_6

 

pattern1 : 버퍼 덮기 .. 80바이트

pattern2 : Saved ebp 덮기 .. 4바이트

시퀀스 시작 주소 6개 : 4*6 = 24 바이트

인자 1개 : 4바이트

80 + 4 + 24 + 4 = 112

 

인자는 왜 필요한가?

pop이 있는 시퀀스가 있어서 스택에 인자가 하나 빠지게 됨

아무거나 일단 넣어줘야 해서 필요

결과적으로 스택은 위 이미지처럼 바뀜


Unintended instruction sequences (의도되지 않은 명령 순차들)

- 프로그래머가 의도하지 않은 ret 명령으로 끝나는 명령어의 순차

- 유효한 명령의 중간으로 점프하여 찾아지고, 새로운 의도되지 않은 명령 순차를 생성

 

x86 아키텍처에서 의도되지 않은 명령 순차가 발견 되는 이유 (.. CISC라.. RISC는 더 적음)

1. 가변 길이 명령어 (variable-lenth instructions)

- 명령어의 크기가 고정되어 있지 않음

2. 비정렬 메모리 접근 (unaligned memory access)

- 워드 크기 N일때, 주소가 N으로 나누어 떨어지지 않는 곳에서 읽는 것을 의미

 

b8 13 00 00 00	mov $0x13, %eax	// eax에 0x13 넣기
e9 c3 f8 ff ff	jmp 3aae9	// 상대주소 3aaae9로 점프

이런 명령어들이 존재한다고 가정 ..

00 00 00 e9 c3 을 분리해가면?

 

00 00	add %al, (%eax)	// eax가 가리키는 메모리 주소에 al의 값 쓰기, 간접 주소 지정
00 e9	add %ch, %cl	// cl에 ch값 더함
c3	ret		// return instruction

 

아예 다른 명령을 만들어버릴 수 있음

 

개발자가 만든 명령의 중간에 점프하여 새로운 시퀀스를 만들 수 있음

 

예시: 메모리 로드

목표: %eax 레지스터에 0xDEADBEEF (pointed to by 0x8010ABCD)

 

1)

첫번째 리턴 어드레스가 eip에 들어감 => 첫번째 시퀀스 시작

 

2)

pop 작동, eax 값 변경

 

3)

ret 후 다음 시퀀스로 이동

 

4)

movl 64(%eax), %eax에 의해 eax 값에서 64 위에 있는 값을 eax에다 집어넣음

=> 로드 성공


ROP 방어 기법

가장 쉬운 건 리턴을 다 없애기 .. 리턴 대신 jmp를 넣음

그런데 이러니까 JOP(Jump-Oriented Programming) 발생

 

아니면

In-Place Code Randomization

- ASLR의 finer-grained level 확장, 서드 파티 애플리케이션 적용 가능, 실질적으로 0의 오버헤드

* Instruction Substituition

- 다양한 명령어를 동일한 길이의 기능적으로 동등한 명령어로 대체 -> 코드 이미지의 바이트를 변경, 공격자의 예상 순서로부터 변형

* Instruction Reordering

- 베이직 블럭 내 재배열

- Register prevention code 재배열 (특정 레지스터의 값을 안전하게 보존하기 위한 코드)


정리

- Non-executable-stack을 우회하는 기법

- 함수 호출과 관련하여 로우 레벨 이해가 필요

- ROP는 일반화된 기법