中级ROP-ret2_libc_csu_init
首先,我们需要了解一下64位文件的传参方式: 当参数少于7个时,参数从左到右放入寄存器:rdi,rsi,rdx,rcx,r8,r9 当参数为7个及以上时,前6个还是上面的寄存器,但多于6位的参数从右到左依次入栈,同32位 12345H(a, b, c, d, e, f, g, h)a -> %rdi, b -> %rsi, c -> %rdx, d -> %rcx, e -> %r8, f -> %r9h -> [esp]g -> [esp]call H 原理在64位程序中,函数的前6个参数是通过寄存器传递的,但是在大多数时候,我们很难找到每一个寄存器对应的gadgets。这时候,我们可以利用x64下的_libc_csu_init中的gadgets。这个函数是用来对libc进行初始化操作的,而一般的程序都会调用libc函数,所以这个函数一定会存在我们来分析一下这个函数: 可以发现从0x40061A一直到函数的结尾,我们都可以使用栈溢出构造栈上数据来控制rbx,rbp,r12,r13,r14,r15寄存器中的数据,也就...
基本ROP-ret2libc实战
实战0自己手动编写一个简单的栈溢出漏洞程序 12345678910111213141516#undef _FORTIFY_SOURCE //用于取消glibc提供的fortify检查#include <stdio.h>#include <stdlib.h>#include <unistd.h> void vulnerable_function(){ char buf[128]; read(STDIN_FILENO, buf, 256);} int main(int argc, char** argv){ vulnerable_function(); write(STDOUT_FILENO, "Hello, World\n", 13);} 通过ldd命令查看程序需要的共享模块 1234$ ldd ret2libc linux-gate.so.1 (0xf7fc7000) libc.so.6 => /lib32/libc.so....
基本ROP-ret2libc
利用思路ret2libc这种攻击方式主要是针对动态链接(Dynamic linking)编译的程序,因为正常情况下是无法在程序中找到像system()、execve() 这种系统级函数。因为程序运行时会调用libc.so(程序被装载时,动态链接器会将程序所需的所有动态链接库加载至进程空间,libc.so就是其中最基本的一个),libc.so是linux下C语言库中的运行库glibc的动态链接版,并且libc.so中包含了大量的可以利用的函数,如system()、execve() 等系统级函数,我们可以通过找到这些函数在内存中的地址覆盖掉返回地址来获得当前进程的控制权。通常情况下,我们会选择执行system(“/bin/sh”) 来打开shell,因此我们就有两个问题: 找到system()函数的地址 在内存中找到”/bin/sh”这个字符串的地址 动态链接(Dynamic linking)动态链接是指在程序装载时通过动态链接器将程序所需的所有动态链接库(Dynamic linking library) 装载至进程空间中(程序按照模块拆分...
基本ROP-ret2syscall
原理ret2syscall就是调用系统函数以达到getshell的目的在计算机中,系统调用是一种编程方式,计算机程序从该程序中向执行其的操作系统内核请求服务,这可能包括与硬件相关的服务(例如,访问硬盘驱动器),创建和执行新进程以及诸如进程调度之类的集成内核服务进行通信。系统调用提供了进程与操作系统之间的基本接口因此,我们要做的是:让程序调用execve(“/bin/sh”, NULL, NULl)函数即可拿到shell 攻击步骤调用此函数的具体步骤如下(32位): eax应该为0xb ebx应该指向/bin/sh的地址,其实执行sh的地址也可以 ecx应该为0 edx应该为0 执行int 0x80触发中断即可执行execve()获取shell系统在运行的时候会使用以上4个寄存器,所以上面的内容我们也可以写为int 0x80(eax, ebx, ecx, edx)。只要我们把对应获取shell的系统调用参数放到对应寄存器中,那么我们再执行int 0x80就可以执行对应的系统调用 而我们如何控制这些寄存器的值?在学习汇编函数时,最常用的就是...
基本ROP-ret2shellcode
原理ret2shellcode,即控制程序执行shellcode代码。shellcode指的是完成某个功能的汇编代码,常见的功能主要是获取目标系统的shell。一般来说,shellcode需要我们自己填充。这其实是另外一种典型的利用方法,即此时我们需要自己去填充一些可执行的代码 利用前提 程序存在溢出,并且还要能够控制返回地址 程序运行时,shellcode所在区域要拥有执行权限(NX保护关闭、bss段可执行) 操作系统还需要关闭ASLR(地址空间布局随机化)保护 攻击步骤 先使用cyclic测试出溢出点,构造初步的payload 确定程序中的溢出位,看是否可在bss段传入数据 使用GDB的vmmap查看进程的完整内存布局(一般用户提交的变量在bss段中) 先发送为shellcode的数据写入到bss段 将程序溢出到上一步用户提交变量的地址 示例 [!info] .bss段不可执行在现在较高版本的Ubuntu上,.bss段权限已经被设定为不可执行。所以shellcode在.bss段上的已经无法成功攻击了但是mprotect()函数可以动态修改.bss段属性,使得.bss段恢复...
基本ROP-ret2text
原理ret2text即控制程序执行程序本身已有的的代码(.text)。其实,这种攻击方法是一种笼统的描述。我们控制执行程序已有的代码的时候也可以控制程序执行好几段不相邻的程序已有的代码(也就是gadgets),这就是我们所要说的ROP。这时我们就需要知道对应返回代码的位置,当然程序可能开启了某些保护,我们需要想办法绕过这些保护 [!note]顾名思义,ret2text(return to text),也就是说我们的利用点在原文件中寻找相对应的危险代码即可(例如进程存在危险函数system(“/bin/sh”)或execv(“/bin/sh”)的片段,我们可以直接劫持返回地址到危险函数上,从而getshell),控制程序执行程序本身已有的代码(.text) 利用前提开启了NX,栈上无法直接写入shellcode当NX保护开启,就表示题目给了你system(“/bin.sh”),如果关闭,表示你需要自己构造shellcode 示例 [!info] 栈帧布局对齐GCC编译32位程序时,默认保持栈帧边界按照16字节对齐,所以有时在实际...
缓冲区溢出之栈溢出
栈溢出缓冲区溢出:简单来说,缓冲区溢出就是超长的数据向小缓冲区复制,导致数据超出了小缓冲区,致使缓冲区其他的数据遭到破坏而栈溢出是缓冲区溢出的一种,也是最常见的。只不过栈溢出发生在栈,堆溢出发生在堆 12345678910111213141516171819202122232425262728293031323334#include <stdio.h>#include <string.h>#define PASSWORD "12345"int test(char *password){ int ret_num; char buffer[8]; ret_num = strcmp(password, PASSWORD); strcpy(buffer, password); return ret_num;}int main(){ int flag = 0; char password[88]; while (1) { printf(&q...
pwntools语法
框架1from pwn import * #导入pwntools模块 1context(arch = 'i386', os = 'linux') #设置目标机的信息 123456r = remote('exploitme.example.com', 31337)'''用来建立一个远程连接,url或ip作为地址,然后指明端口这里也可以仅仅是用本地文件,调式时更方便'''r = process("./pwn") #pwn即为文件名,这使得改变远程和本地十分方便 1234567891011asm(shellcraft.sh())'''asm()函数接收一个字符串作为参数,得到汇编码的机器代码例如:>>> asm('mov eax, 0')'\xb8\x00\x00\x00\x00'shellcraft模块是shellcode的模块,包含一些生成shellc...
Linux动态链接中的PLT表和GOT表
引言文件在编译链接时,是不知道glibc动态库内printf的函数地址的,而只是写了一个“占位符”在汇编中,glibc动态库内printf的函数地址只有装载进内存时才能够知道 但是进程运行起来后,glibc动态库装载了,printf函数地址也确定了,那call指令是怎么重定位地址的呢? 一种简单的方法就是将指令中的“占位符”修改成printf函数的真实地址即可。但是随之又出现两个问题: 现代操作系统不允许修改代码段,只能修改数据段 如果函数是在一个动态库(.so)中,修改了代码段,那么它就无法做到系统内所有进程共享同一个动态库所以prinf函数的地址只能回写到数据段,而不是代码段,这样的回写其实叫做运行时重定位,与之相应的还有链接时重定位 编译与链接每个编译单元(通常是一个.cpp文件)都会经历编译和链接两个阶段 编译阶段是将.c源代码编译成汇编指令的中间文件,即.o中间文件。由于编译阶段无法知道printf函数的地址,所以call指令后会预先放一个占位符,然后用重定位项来描述:这个地址在链接时需要修正,它的修正值是根据printf函数地址(更确切应该说是符号,链接器眼中只有...
Linux ELF文件保护机制
Linux ELF文件的保护机制主要有四种:Canary、NX、PIE、RELRO 一、CanaryLinux Canary是一种用于检测缓冲区溢出漏洞的安全机制,它在函数返回值之前添加的一串随机数(不超过机器字长)(也叫做cookie),末位为/x00(提供了覆盖最后一字节输出泄露Canary的可能)。如果出现缓冲区溢出攻击,覆盖内容覆盖到Canary处,就会改变原本该处的数值。当程序执行到此处时,会检查Canary值是否跟开始的值一样,如果不一样,程序会崩溃,从而达到保护返回地址的目的。Canary的确切位置会因为系统不同和编译器而异,但通常存储在栈帧的底部,位于局部变量和函数的返回地址之间,以防止缓冲区溢出攻击。 二、NXNX即No-eXecute(不可执行)的意思,NX(DEP)的基本原理是将数据所在内存页标识为不可执行,当程序溢出成功转入shellcode时,程序会尝试在数据页面上执行指令,此时CPU就会抛出异常,而不是去执行恶意指令。 [!info]这里的“标识”,指的是内存页表项中的一个比特位。在x86架构中叫NX位;而ARM架构中叫XN 正常在栈溢出时通过跳转...
