srop에 대해서 이야기 해보려고 한다.
이 기법을 배우려면 기본적으로 rop가 무엇인지에 대해서 이해를 한 후 배우면 좋을 것 같다.
우선 제목에 나와있다시피 Signal이 무엇인지에 대해서 알아야 할 필요가 있다.
번역을 하자면 신호인데 그럼 어떤 신호를 이용해서 rop 기법을 이용하는 건지 의문을 갖을 수 있다.
여기서 말하는 signal은 비동기적으로 발생하는 이벤트에 대한 알림으로 특정 프로세스에 대해서 사전에 정의 된 조건이 달성되면 알려주는 것을 말한다.
그렇다면 signal이 발생되면 어떤 일들이 일어나는지에 대해서 알아보려고 한다.

사진을 보면 User Mode와 Kernel Mode가 있는 것을 볼 수가 있다. 하지만 이는 이해를 하는데 방해가 된다고 개인적으로 생각한다. 그 이유는 signal이 발생이 되면 kernel mode로 바뀐다고 생각 할 수 있기 때문이다. 하지만 그런게 아니고 signal이 발생이 되면 kerenl에게 어떤 task를 수행하고 그 결과를 달라고 하는 것을 user mode에서 kernel mode로 바뀌는다고 설명하는 것 같다.
do_signal()은 처리할 signal를 확인하며 handle_signal() 함수가 처리를 하고 setup_frame() 함수를 통해서 signal handler를 수행 할 수게 준비를 한다. 이 때 kernel mode로 올 때 레지스터는 초기화가 된다. 그 후 프로세스가 signal handle를 하고 기존에 프로세스에서 사용하고 있던 레지스터를 복원을 하여 프로세스에게 전달해준다. 여기서 우리가 주목해야하는 부분은 초기화 된 부분을 다시 원상태로 바꾸는 함수인 sys_sigreturn()에 주목을 한다.
syscall를 할 때 이 함수를 실행하게 하려면 syscall number를 알아야한다. sigreturn num은 0xf이다. rax에 0xf를 넣은 후 syscall 함수에 전달을 하면 sigerturn 함수가 실행이 된다.
다음은 kernel에서 다루는 context에서 바꿔야하는 레지스터 위치를 파악을 한후 그 위치에 맞게 값을 넣어 원하는 레지스터의 값을 바꿔주면 된다.
아래는 context의 구조체이다. x64
# else /* __x86_64__: */
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];
};
이제는 예시로 위 방법으로 어떻게 shell 권한을 얻는지 이야기 해보려고 한다.
syscall를 한 다음 rax에 0xf값을 주고 sigreturn을 실행시킨 후 rdi에 /bin/sh를 갖고 있는 libc 주소를 넣고 다시 rax에 0x3b를 넣어서 다시 syscall를 하면 execute 함수를 실행시킬 수 있게 변조를 한 후 권한을 탈취하면 된다.
이상으로 srop에 대해서 알아 보았다.
좋은 사이트를 찾아서 아래에 놓아둔다.
https://cpuu.postype.com/post/9973608