1 概述
SROP: Sigreturn Oriented Programming ,系统Signal Dispatch之前会将所有寄存器压入栈,然后调用signal handler,signal handler返回时会将栈的内容还原到寄存器。 如果事先填充栈,然后直接调用signal handler,那在返回的时候就可以控制寄存器的值。
2 资源
1. Framing Signals—A Return to Portable Shellcode
http://www.ieee-security.org/TC/SP2014/papers/FramingSignals-AReturntoPortableShellcode.pdf
PS:SROP的论文,不容易理解,未读。
2. Sigreturn Oriented Programming (SROP) Attack攻击原理
http://www.freebuf.com/articles/network/87447.html
PS:介绍了SROP的基本原理。
3. Sigreturn Oriented Programming攻击简介
https://www.anquanke.com/post/id/85810
PS:介绍了SROP的基本原理。附带有32位的DEMO。
4. Playing around with SROP
https://x86overflow.blogspot.in/2014/04/playing-around-with-srop.html
PS:32位SROP DEMO
5. Sigreturn Oriented Programming
https://www.slideshare.net/AngelBoy1/sigreturn-ori
PS:介绍了SROP的基本原理
6. 2017 429 ichunqiu ctf smallest(pwn300) writeup
http://anciety.cn/2017/04/21/2017429ctf-smallest-writeup/
PS:64位SROP实例
7. Return to VDSO using ELF Auxiliary Vectors。https://v0ids3curity.blogspot.jp/2014/12/return-to-vdso-using-elf-auxiliary.html。
PS:VDSO的利用,SROP可以利用VDSO。
8. Defcon 2015 Qualifier fuckup
https://github.com/ctfs/write-ups-2015/tree/master/defcon-qualifier-ctf-2015/pwnable/fuckup
此题较难。
3 SROP原理
4 SROP利用
4.1 Signal Frame
Ubuntu 16.04 64
4.1.1 X86
Sigcontext
对x86来说,此数据结构为sigcontext。
大小为80字节,示例:
frame.set_regvalue("eax", SYS_MPROTECT) #125 frame.set_regvalue("ebx", page_text_segment) #0x08048000 frame.set_regvalue("ecx", 0x1000) frame.set_regvalue("edx", 0x7) frame.set_regvalue("ebp", page_text_segment) frame.set_regvalue("eip", INT_80) #0x08048071 frame.set_regvalue("esp", page_text_segment+16) frame.set_regvalue("cs", 0x23) frame.set_regvalue("ss", 0x2b) frame.set_regvalue("ds", 0x2b) frame.set_regvalue("es", 0x2b) frame.set_regvalue("fs", 0x0) frame.set_regvalue("gs", 0x0) 00000000: 00 00 00 00 00 00 00 00 2B 00 00 00 2B 00 00 00 ........+...+... 00000010: 00 00 00 00 00 00 00 00 00 80 04 08 10 80 04 08 ................ 00000020: 00 80 04 08 07 00 00 00 00 10 00 00 7D 00 00 00 ............}... 00000030: 00 00 00 00 00 00 00 00 71 80 04 08 23 00 00 00 ........q...#... 00000040: 00 00 00 00 00 00 00 00 2B 00 00 00 00 00 00 00 ........+....... |
/usr/include/x86_64-linux-gnu/bits/sigcontext.h
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;
};
4.1.2 X64
ucontext
Sigcontext
大小为248个字节(0xF8),示例:
frame = SigreturnFrame() frame.rsp = elf_hdr_addr+0x18 #0x400018 frame.rax = constants.SYS_mprotect #0x0a frame.rdi = elf_hdr_addr #0x400000 frame.rsi = 0x1000 frame.rdx = 0x7 frame.rip = syscall_addr 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │····│····│····│····│ * 00000070 00 00 00 00 00 00 00 00 00 00 40 00 00 00 00 00 │····│····│··@·│····│ 00000080 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │····│····│····│····│ 00000090 00 00 00 00 00 00 00 00 07 00 00 00 00 00 00 00 │····│····│····│····│ 000000a0 0a 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │····│····│····│····│ 000000b0 18 00 40 00 00 00 00 00 be 00 40 00 00 00 00 00 │··@·│····│··@·│····│ 000000c0 00 00 00 00 00 00 00 00 33 00 00 00 00 00 00 00 │····│····│3···│····│ 000000d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 │····│····│····│····│ * 00000100 00 00 00 00 00 00 00 00 0a │····│····│·│ |
/usr/include/x86_64-linux-gnu/bits/sigcontext.h
/usr/include/x86_64-linux-gnu/bits/sigstack.h
/usr/include/x86_64-linux-gnu/bits/sigset.h
typedef struct sigaltstack
{
void *ss_sp;
int ss_flags;
size_t ss_size;
} stack_t;
typedef struct _libc_fpstate *fpregset_t;
#ifdef __x86_64__
__extension__ typedef long long int greg_t;
#define NGREG 23
typedef greg_t gregset_t[NGREG];
#else /* !__x86_64__ */
typedef int greg_t;
#define NGREG 19
typedef greg_t gregset_t[NGREG];
#endif
/* Context to describe whole processor state. */
typedef struct
{
gregset_t gregs;
/* Note that fpregs is a pointer. */
fpregset_t fpregs;
__extension__ unsigned long long __reserved1 [8];
} mcontext_t;
# define _SIGSET_NWORDS (1024 / (8 * sizeof (unsigned long int)))
typedef struct
{
unsigned long int __val[_SIGSET_NWORDS];
} __sigset_t;
/* Userlevel context. */
typedef struct ucontext
{
unsigned long int uc_flags;
struct ucontext *uc_link;
stack_t uc_stack;
mcontext_t uc_mcontext; /* sigcontext for x86_64 */
__sigset_t uc_sigmask;
struct _libc_fpstate __fpregs_mem;
} ucontext_t;
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];
};
4.2 Sigreturn系统调用
关于sigreturn的系统调用:
/*for x86*/
mov eax,0x77
int 80h
/*for x86_64*/
mov rax,0xf
syscall
4.3 Sigreturn gadget
l X86 VDSO中有sigreturn gadget
millionsky@ubuntu-12:~/tmp$ objdump -d linux-gate.so.1 linux-gate.so.1: file format elf32-i386 Disassembly of section .text: ffffe400 <__kernel_sigreturn>: ffffe400: 58 pop %eax ffffe401: b8 77 00 00 00 mov $0x77,%eax ffffe406: cd 80 int $0x80 ffffe408: 90 nop ffffe409: 8d 76 00 lea 0x0(%esi),%esi ...... |
millionsky@ubuntu-16:~/tmp/VDSO$ objdump -D -b binary -mi386:x86-64 /tmp/linux-vsyscall.so | grep syscall -C 2 /tmp/linux-vsyscall.so: 文件格式 binary -- 0000000000000000 <.data>: 0: 48 c7 c0 60 00 00 00 mov $0x60,%rax 7: 0f 05 syscall 9: c3 retq a: cc int3 |
l X86也可以寻找设置eax和int $0x80的gadget
l X64 vsyscall中有syscall&ret指令
l X64也可以寻找设置rax和syscall指令的gadget
4.4 SROP利用
【利用方式】
1) 伪造sigcontext结构,push到栈中;
2) Ret address设置为sigreturn gadget;
3) 将signal frame中的RIP(EIP)设置为syscall/int 0x80;
4) 当sigreturn回来后,就会执行设置的syscall,如execve,read,write...etc
【前提】
需要可控的IP和栈(如ROP)
需要知道sigreturn系统调用gadget的地址;或者通过ROP构造sigreturn系统调用;
需要知道syscall/int 0x80指令的地址;
【特点】
全部的register都可控;
可以改变stack的位置;
【注意】
cs、ss、ds、es、fs、gs等segment selector register尽量按照原本的填,不然会喷掉;
Esp,ebp不可为0,不然一样会喷;