SROP(Sigreturn-oriented programming)
- SROP는 sigreturn 시스템 콜을 이용하여 레지스터에 원하는 값을 저장할 수 있다.
- 해당 기법을 이용하여 원하는 시스템 함수를 호출할 수 있다.
Signal
-
signal은 프로세스에게 이벤트가 발생했음을 알린다.
-
signal은 다른 프로세스에게 시그널을 전송 할 수 있다.
- signal은 원시적인 형태의 IPC(interprocess communication)로 사용 할 수 있다.
- signal은 자기 자신에게 시그널을 보낼수도 있다.
-
signal은 일반적으로 커널이 송신하며, 다음과 같은 이벤트 종류가 있다.
- signal은 생성되면 프로세스에 전달되고, 전달된 시그널의 종류에 따라 다음과 같은 동작이 실행된다.
- 시그널 무시
- 프로세스 종료
- 코어 덤프 파일을 생성 후 프로세스 종료
- 프로세스 중지
- 프로세스의 실행을 재개
Signal handler
- signal handler는 프로그램이 특정 시그널의 기본 동작을 수행하는 대신 프로그래머가 원하는 동작을 수행하도록 변경할 수 있다.
- signal handler는 User Mode 프로세스에 정의되어 있고 User Mode 코드 세그먼트에 포함된다.
- signal handler가 User Mode 에서 실행되는 동안 Kernel Mode에서 handle_signal() 함수가 실행 된다.
- User Mode에서 Kernel Mode로 진입시 User Mode에서 사용중이던 context를 Kernel stack에 저장한다.
- Kernel Mode에서 User Mode로 진입시 Kernel stack은 모두 초기화된다.
- 이러한 문제를 해결하기 위해 setup_frame(), sigreturn() 함수를 사용한다.
- Signal handler는 다음과 같이 처리된다.
- 인터럽트 또는 예외가 발생하면 프로세스는 Kernel Mode로 전환된다.
- 커널은 User Mode로 돌아 가기 전에 do_signal() 함수를 실행한다.
- do_signal() 함수는 handle_signal()을 호출하여 signal를 처리한다.
- handle_signal() 함수는 setup_frame()을 호출하여 User Mode Stack에 context를 저장한다.
- 프로세스가 User Mode로 다시 전환되면 signal handler가 실행된다.
- signal handler가 종료되면 setup_frame() 함수에 의해 User Mode stack에 저장된 리턴 코드가 실행된다.
- 해당 코드에 의해 sigreturn() 시스템 함수가 호출된다.
- sigreturn() 시스템 함수에 의해 Kernel Mode Stack에서 일반 프로그램의 hardware context를 User Mode의 stack에 복사한다.
- sigreturn() 함수는 restore_sigcontext() 을 호출하여 User Mode 스택을 원래 상태로 복원한다.
- 시스템 호출이 종료되면 일반 프로그램은 실행을 재개 할 수 있다.
Example
- 다음과 같이 handle_signal 함수에 Break point를 설정한다.
- 그리고 GDB가 인트럽트에 반응하지 않도록 설정한다.
다음과 같이 프로그램을 실행 후 "Ctrl + C"를 눌러서 Interrupt 신호를 발생시킨다.
- bt명령어를 이용해 handle_signal 함수가 호출되기 전에 실행된 함수 목록을 확인 할 수 있다.
- ebp+12 부터 struct sigcontext 시작
Frame 0
다음과 같이 0번째 Frame에서 Stack에 저장된 각 각의 레지스터 값을 확인 할 수 있다.
Frame 1
다음과 같이 1번째 Frame의 내용을 보면 __kernel_sigreturn() 함수에서 에서 sys_sigreturn() 시스템 함수 호출한다.
- x86에서 sys_sigreturn 시스템 함수의 번호는 0x77(119) 이다.
Frame 2
다음과 같이 signal에 대한 처리가 끝난 후에 Frame 0의 Stack에 저장된 값이 레지스터에 저장된 것을 확인 할 수 있다.
sigreturn()
- sigreturn() 시스템 함수는 Signal을 처리하는 프로세스가 Kernel Mode에서 User Mode 돌아 올때 stack을 복원하기 위해 사용되는 함수 이다.
- sigreturn() 함수는 stack을 복원하기 위해 restore_sigcontext()를 호출한다.
- restore_sigcontext() 함수는 COPY_SEG(), COPY() 함수 등 을 이용하여 stack에 저장된 값을 각 레지스터에 복사한다.
-
즉, ROP와 같이 값을 레지스터에 저장할 수 있는 Gadget이 없어도 sigreturn() 함수를 이용해 각 레지스터에 원하는 값을 저장할 수 있다.
-
stack에 저장된 레지스터 값들은 restore_sigcontext()함수의 인자값 &frame->sc에 의해 전달된다.
- &frame->sc"는 sigcontext 구조체 이다.
Proof of concept
다음과 같이 Overflow를 확인할 수 있다.
Exploit 순서
-
sigreturn()함수를 이용해 레지스터에 필요한 값을 저장
- ESP : sigreturn() 함수 호출 후 이동할 주소("int 0x80" 명령어가 저장된 주소)
- EBX : "/bin/sh" 문자열이 저장된 주소
- EAX : execve() 함수의 시스템 콜 번호
- EIP : "int 0x80" 명령어가 저장된 주소
- CS : User Code(0x23)
- SS : User Data / Stack(0x2b)
- int 0x80 명령어 실행
확인해야 할 정보 목록
- Libc offset
- printf
- __kernel_sigreturn
-
"/bin/sh"명령가 저장된 영역
-
Gadgets
Libc offset
Offset of __kernel_sigreturn
다음과 같이 __kernel_sigreturn() 함수를 Exploit에 사용할 수 있다.
Find Gadgets
32bit이기 때문에 sigreturn() 함수를 vdso 영역에서 확인 할 수 있다.
CS(Code segment) & SS(Stack Segment)
Segment
purpose |
Segment(32bit) |
Segment(64bit-32bit) |
Kernel Code |
0x60 |
0x8 |
Kernel Data/Stack |
0x68 |
0x18 |
User Code |
0x73 |
0x23 |
User Data/Stack |
0x7b |
0x2b |
exploit
use pwntools
REF : https://www.lazenca.net/display/TEC/01.SROP%28Sigreturn-oriented+programming%29+-+x86
댓글 영역