
Signal μκ·Έλ
SROPμ λν΄μ μμ보기 μ μ μκ·Έλ(Signal)μ μ²λ¦¬νλ λ°©μμ μ΄ν΄ν΄μΌ νλ€.
μ΄μ체μ λ μ μ λͺ¨λμ 컀λ λͺ¨λλ‘ λλμ΄μ§λλ°, νμΌμ μμ±νκ³ , νλ‘κ·Έλ¨μ μ€ννλ λͺ¨λ μμ μ μ΄ λ κ°μ λͺ¨λκ° μλ‘ μνΈμμ©νλ©΄μ μ΄λ€μ§λ€.
μκ·Έλμ νλ‘μΈμ€μ νΉμ μ 보λ₯Ό μ λ¬νλ λ§€κ°μ²΄
- 리λ μ€μμλ λ€μν μκ·Έλμ μ 곡ν¨
include/linux/signal.h μΌλΆ
* +--------------------+------------------+
* | POSIX signal | default action |
* +--------------------+------------------+
* | SIGHUP | terminate |
* | SIGINT | terminate |
* | SIGQUIT | coredump |
* | SIGILL | coredump |
* | SIGTRAP | coredump |
* | SIGABRT/SIGIOT | coredump |
* | SIGBUS | coredump |
* | SIGFPE | coredump |
* | SIGKILL | terminate(+) |
* | SIGUSR1 | terminate |
* | SIGSEGV | coredump |
* | SIGUSR2 | terminate |
* | SIGPIPE | terminate |
* | SIGALRM | terminate |
* | SIGTERM | terminate |
* | SIGCHLD | ignore |
* | SIGCONT | ignore(*) |
* | SIGSTOP | stop(*)(+) |
* | SIGTSTP | stop(*) |
* | SIGTTIN | stop(*) |
* | SIGTTOU | stop(*) |
* | SIGURG | ignore |
* | SIGXCPU | coredump |
* | SIGXFSZ | coredump |
* | SIGVTALRM | terminate |
* | SIGPROF | terminate |
* | SIGPOLL/SIGIO | terminate |
* | SIGSYS/SIGUNUSED | coredump |
* | SIGSTKFLT | terminate |
* | SIGWINCH | ignore |
* | SIGPWR | terminate |
* | SIGRTMIN-SIGRTMAX | terminate |
* +--------------------+------------------+
* | non-POSIX signal | default action |
* +--------------------+------------------+
* | SIGEMT | coredump |
* +--------------------+------------------+
μκ·Έλ λμ λ°©μ
SIGALRM μμ μ½λ
// Name: sig_alarm.c
// Compile: gcc -o sig_alarm sig_alarm.c
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<stdlib.h>
void sig_handler(int signum){
printf("sig_handler called.\n");
exit(0);
}
int main(){
signal(SIGALRM,sig_handler);
alarm(5);
getchar();
return 0;
}
μ½λλ₯Ό μ΄ν΄λ³΄λ©΄, signal ν¨μλ₯Ό μ¬μ©ν΄ SIGALRM μκ·Έλμ΄ λ°μνλ©΄ sig_handler ν¨μλ₯Ό μ€ννλ€.
SIGALRM μκ·Έλμ΄ λ°μνλ©΄ 컀λ λͺ¨λλ‘ μ§μ νλ€.
* μ¬κΈ°μ μκ·Έλμ 컀λ λͺ¨λμμ μ²λ¦¬νκ³ λμ λ€μ μ μ λͺ¨λλ‘ λμμ νλ‘μΈμ€μ μ½λλ₯Ό μ€νν΄μΌ νλ€.
=> μ¦, μ μ λͺ¨λμ μνλ₯Ό λͺ¨λ κΈ°μ΅νκ³ λλμμ¬ μ μμ΄μΌ ν¨
(μν : μκ·Έλμ΄ λ°μνμ λ νλ‘μΈμ€μ λ©λͺ¨λ¦¬, λ μ§μ€ν° λ±)
do_signal
do_signal ν¨μλ μκ·Έλμ μ²λ¦¬νκΈ° μν΄ κ°μ₯ λ¨Όμ νΈμΆλλ ν¨μ
리λ μ€ μ»€λ 5.10μ΄ν λ²μ μμλ arch_do_signal, μμ λ²μ μμλ arch_do_signal_or_restart ν¨μλ‘ κ·Έ μ΄λ¦μ΄ λ³κ²½λμλ€.
arch_do_signal_or_restart ν¨μ
void arch_do_signal_or_restart(struct pt_regs *regs, bool has_signal)
{
struct ksignal ksig;
if (has_signal && get_signal(&ksig)) {
/* Whee! Actually deliver the signal. */
handle_signal(&ksig, regs);
return;
}
/* Did we come from a system call? */
if (syscall_get_nr(current, regs) >= 0) {
/* Restart the system call - no handlers present */
switch (syscall_get_error(current, regs)) {
case -ERESTARTNOHAND:
case -ERESTARTSYS:
case -ERESTARTNOINTR:
regs->ax = regs->orig_ax;
regs->ip -= 2;
break;
case -ERESTART_RESTARTBLOCK:
regs->ax = get_nr_restart_syscall(regs);
regs->ip -= 2;
break;
}
}
/*
* If there's no signal to deliver, we just put the saved sigmask
* back.
*/
restore_saved_sigmask();
}
ν΄λΉ ν¨μμμλ μκ·Έλμ ν΄λΉνλ νΈλ€λ¬κ° λ±λ‘λμ΄ μλμ§ νμΈνλ€.
λ§μ½ νΈλ€λ¬κ° λ±λ‘λμ΄ μλ€λ©΄ μκ·Έλμ λν μ 보μ λ μ§μ€ν° μ 보λ₯Ό μΈμλ‘ handle_signal ν¨μλ₯Ό νΈμΆν¨
handle_signal
linux/arch/x86/kernel/signal.c λ΄ handle_signal ν¨μ
static void
handle_signal(struct ksignal *ksig, struct pt_regs *regs)
{
...
failed = (setup_rt_frame(ksig, regs) < 0);
if (!failed) {
fpu__clear_user_states(fpu);
}
signal_setup_done(failed, ksig, stepping);
}
λ€μμ handle_signal ν¨μμ μΌλΆλ‘, setup_rt_frame ν¨μλ₯Ό νΈμΆνλ€.
ν΄λΉ ν¨μλ μκ·Έλμ μ μ©λ νΈλ€λ¬κ° μ‘΄μ¬ν κ²½μ°, νΈλ€λ¬μ μ£Όμλ₯Ό λ€μ μ€ν μ£Όμλ‘ μ½μ νλ€.
SIGALRMμ΄ λ°μν κ²½μ° ν΄λΉ μ½λλ₯Ό ν΅ν΄ sig_handler ν¨μκ° μ€νλλ€.
* signal handler νΈμΆ κ³Όμ
regs->si = (unsigned long)&frame->info;
regs->dx = (unsigned long)&frame->uc;
regs->ip = (unsigned long) ksig->ka.sa.sa_handler;
regs->sp = (unsigned long)frame;
sigreturn
νμ¬ νλ‘μΈμ€κ° λ°λλ κ±Έ 컨ν μ€νΈ μ€μμΉ(Context Switching)μ΄λΌκ³ νλ€.
μμ μμλ³Έ λ°μ κ°μ΄ 컀λμ΄ μ μ κ° μ€νν νλ‘μΈμ€λ₯Ό κ΄λ¦¬νκΈ° μν΄ λ€μν μ½λλ₯Ό μ€ννλ€. 컨ν μ€νΈ μ€νμΉμ΄ μΌμ΄λλ©΄ λ€μ μ μ νλ‘μΈμ€λ‘ 볡κ·ν΄μΌ νλ€. λ°λΌμ μ€μμΉμ΄ μΌμ΄λ λ μν©μ 컀λμμ κΈ°μ΅νκ³ , 컀λ μ½λμ μ€νμ λ§μΉλ©΄ κΈ°μ΅ν μ 보λ₯Ό λλλ € 볡κ·ν΄μΌ νλ€.
μ΄λ μ¬μ©λλ μμ€ν μ½μ΄ sigreturnμ΄λ€.
λ€μμ restore_sigcontext ν¨μμ μ½λμ΄λ€.
static bool restore_sigcontext(struct pt_regs *regs,
struct sigcontext __user *usc,
unsigned long uc_flags)
{
struct sigcontext sc;
/* Always make any pending restarted system calls return -EINTR */
current->restart_block.fn = do_no_restart_syscall;
if (copy_from_user(&sc, usc, CONTEXT_COPY_SIZE))
return false;
#ifdef CONFIG_X86_32
set_user_gs(regs, sc.gs);
regs->fs = sc.fs;
regs->es = sc.es;
regs->ds = sc.ds;
#endif /* CONFIG_X86_32 */
regs->bx = sc.bx;
regs->cx = sc.cx;
regs->dx = sc.dx;
regs->si = sc.si;
regs->di = sc.di;
regs->bp = sc.bp;
regs->ax = sc.ax;
regs->sp = sc.sp;
regs->ip = sc.ip;
#ifdef CONFIG_X86_64
regs->r8 = sc.r8;
regs->r9 = sc.r9;
regs->r10 = sc.r10;
regs->r11 = sc.r11;
regs->r12 = sc.r12;
regs->r13 = sc.r13;
regs->r14 = sc.r14;
regs->r15 = sc.r15;
#endif /* CONFIG_X86_64 */
/* Get CS/SS and force CPL3 */
regs->cs = sc.cs | 0x03;
regs->ss = sc.ss | 0x03;
regs->flags = (regs->flags & ~FIX_EFLAGS) | (sc.flags & FIX_EFLAGS);
/* disable syscall checks */
regs->orig_ax = -1;
#ifdef CONFIG_X86_64
/*
* Fix up SS if needed for the benefit of old DOSEMU and
* CRIU.
*/
if (unlikely(!(uc_flags & UC_STRICT_RESTORE_SS) && user_64bit_mode(regs)))
force_valid_ss(regs);
#endif
return fpu__restore_sig((void __user *)sc.fpstate,
IS_ENABLED(CONFIG_X86_32));
}
sigreturn μμ€ν μ½μ νΈμΆνλ©΄ λ΄λΆμ μΌλ‘ ν΄λΉ ν¨μλ₯Ό νΈμΆν΄ μ€νμ μ μ₯ν κ°μ κ°κ°μ λ μ§μ€ν°μ 볡μ¬νμ¬ κΈ°μ‘΄ μν©κ³Ό μ€νν μ½λλ₯Ό κΈ°μ΅νκ³ λ³΅κ·νλ€.
struct sigcontext sc;
/* Always make any pending restarted system calls return -EINTR */
current->restart_block.fn = do_no_restart_syscall;
if (copy_from_user(&sc, usc, CONTEXT_COPY_SIZE))
return false;
μ½λλ₯Ό 보면, sigcontext ꡬ쑰체μ μ‘΄μ¬νλ κ° λ©€λ² λ³μμ κ°μ μ½μ νλ κ±Έ νμΈν μ μλ€.
sigcontext
λ€μμ sigcontext ꡬ쑰체μ΄λ€.
/* __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];
};
μ½λλ₯Ό μ΄ν΄λ³΄λ©΄ λ μ§μ€ν° λͺ μΉμ κ°μ§ κ°κ°μ λ©€λ² λ³μκ° μ‘΄μ¬νλ κ±Έ νμΈν μ μλ€.
νμ μλ μ½λλ x86_64 μν€ν μ²μ ν΄λΉνλ ꡬ쑰체μ΄λ€. λ°λΌμ λ€λ₯Έ μν€ν μ²μ λ°μ΄λ리λ₯Ό 곡격ν λ λμ μν€ν μ²λ₯Ό νμ νκ³ ν΄λΉ ꡬ쑰체μ 컀λ μ½λλ₯Ό λΆμν΄μ μ§νν΄μΌ νλ€.
SROP
SigReturn-Oriented Programming(SROP)λ 컨ν μ€νΈ μ€μμΉμ μν΄ μ¬μ©νλ sigreturn μμ€ν μ½μ μ΄μ©ν ROPκΈ°λ²μ΄λ€.
ROPκ° μ½λ μ‘°κ°μ λͺ¨μμ μμμ μ½λλ₯Ό μ€ννλ 곡격 κΈ°λ²μΈ κ±Έ 보μ, SROPλ sigreturn μμ€ν μ½μ νΈμΆνκ³ , λ μ§μ€ν°μ 볡μ¬ν κ°μ 미리 μ€νμ μ μ₯ν΄ μμ μ½λλ₯Ό μ€ννλ κ±Έ μ μ μλ€.
λͺ¨λ λ μ§μ€ν°λ₯Ό μ‘°μν μ μλ λ§νΌ μ΅μ€νλ‘μ νμ©λκ° λ§€μ° λλ€.
SROP μμ μ½λ
// Name: sigrt_call.c
// Compile: gcc -o sigrt_call sigrt_call.c
#include <string.h>
int main()
{
char buf[1024];
memset(buf, 0x41, sizeof(buf));
asm("mov $15, %rax;"
"syscall");
}
λ€μ μμ λ₯Ό μ»΄νμΌνκ³ λλ²κ±°μμ μ€νν΄λ³΄λ©΄ λ€μκ³Ό κ°μ΄ λ μ§μ€ν°λ₯Ό μ‘°μν μ μλ κ±Έ νμΈν μ μλ€.
'DreamHack > SystemHacking' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
[Dreamhack System Hacking] send_sig (0) | 2022.11.14 |
---|---|
[Dreamhack System Hacking] SigReturn-Oriented Programming (0) | 2022.11.14 |
[DreamHack System Hacking] rtld (0) | 2022.09.22 |
[DreamHack System Hacking] __eviron (0) | 2022.09.21 |
[DreamHack System Hacking] Linux Library exploit > __environ (0) | 2022.09.21 |