SROP기법은 Sigreturn-oriented-programming의 약자로 sigreturn syscall을 이용해 ROP를 하는 기법이다.
Sigreturn?
사용자가 Signal을 발생시킬때 프로세스는 Kernel Mode로 전환되게된다. 그 후 커널은 User Mode로 돌아 가기 전에 do_signal() 함수를 실행한다. 해당 함수는 handle_signal() 함수를 호출하여 사용자가 발생시킨 Signal을 처리한다. 그리고 handle_signal() 함수는 setup_frame() 함수를 호출하여 User Mode Stack에 context를 저장한다. 해당 context의 내용은 아래에 있다.
프로세스가 다시 User Mode로 전환되면 signal handler가 실행된다. 그리고 signal handler의 실행이 끝나면 setup_frame() 함수에 의해 아까 User Mode Stack에 저장된 리턴 코드가 실행된다. 해당 코드에 의해 sigreturn() 함수가 호출된다.
sigreturn() 함수에 의해 Kernel Mode Stack에서 일반 프로그램의 hardware context를 User Mode의 stack에 복사하고 restore_sigcontext() 함수를 호출하여 User Mode를 원래 상태로 복원한 후 다시 프로세스가 재개된다.

만약 우리가 해당 과정에서 사용되는 sigreturn()함수를 호출하게 된다면 우리가 원하는대로 레지스터를 바꿀 수 있게 된다.
32bit sigcontext
struct sigcontext
{
unsigned short gs, __gsh;
unsigned short fs, __fsh;
unsigned short es, __esh;
unsigned short ds, __dsh;
unsigned long edi;
unsigned long esi;
unsigned long ebp;
unsigned long esp;
unsigned long ebx;
unsigned long edx;
unsigned long ecx;
unsigned long eax;
unsigned long trapno;
unsigned long err;
unsigned long eip;
unsigned short cs, __csh;
unsigned long eflags;
unsigned long esp_at_signal;
unsigned short ss, __ssh;
struct _fpstate * fpstate;
unsigned long oldmask;
unsigned long cr2;
};
64bit sigcontext
struct sigcontext {
__u64 r8;
__u64 r9;
__u64 r10;
__u64 r11;
__u64 r12;
__u64 r13;
__u64 r14;
__u64 r15;
__u64 rdi;
__u64 rsi;
__u64 rbp;
__u64 rbx;
__u64 rdx;
__u64 rax;
__u64 rcx;
__u64 rsp;
__u64 rip;
__u64 eflags; /* RFLAGS */
__u16 cs;
__u16 gs;
__u16 fs;
union {
__u16 ss; /* If UC_SIGCONTEXT_SS */
__u16 __pad0; /* Alias name for old (!UC_SIGCONTEXT_SS) user-space */
};
__u64 err;
__u64 trapno;
__u64 oldmask;
__u64 cr2;
struct _fpstate __user *fpstate; /* Zero when no FPU context */
# ifdef __ILP32__
__u32 __fpstate_pad;
# endif
__u64 reserved1[8];
};
위의 코드가 sigreturn()에서 사용하게되는 sigcontext이다. 해당 구조체에 맞게 payload를 작성한다면 레지스터를 우리가 원하는대로 설정할 수 있다.
SROP
SROP를 이용한 expoit기법은 다양하다. 원하는 syscall을 전부 이용할 수 있으므로 syscall을 이용한 모든 expolit이 가능하게 된다.
mprotect
우선 64bit에서 사용하는 mprotect() 함수를 이용하는 방법이다. 해당함수는 메모리 영역의 권한을 설정할 수 있는 함수로 아래와 같은 인자를 요구한다.
int mprotect(void *addr, size_t len, int prot);
mprotect() 함수를 이용하면 shellcode를 이용한 expolit이 가능해진다. 이를 이용해 NX bit를 우회할 수 있다.
mmap
마찬가지로 32bit에서는 mmap() 함수를 이용해 mprotect()와 같은 역할을 할 수있다.
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
이러한 syscall 함수를 바이너리 취약점에 맞게 적절히 사용한다면 SROP를 통해 다양한 exploit이 가능하게된다.
참고사이트
'hacking > pwnable' 카테고리의 다른 글
| ptmalloc2 allocator (0) | 2022.12.06 |
|---|---|
| scanf (0) | 2022.12.06 |
| libc.so.6 (0) | 2022.12.06 |
| Lazy Binding (0) | 2022.12.06 |
| _IO_FILE (0) | 2022.12.06 |