文章目录
- overflow
- scanf
- get
- read
- strcpy
- strcat
- Find string in gdb
- gdb
- gdb peda
- Binary Service
- Find specific function offset in libc
- 手工
- 自动
- Find '/bin/sh' or 'sh' in library
- 手动
- 自动
- Leak stack address
- Fork problem in gdb
- Secret of a mysterious section - .tls
- Predictable RNG(Random Number Generator)
- Make stack executable
- Use one-gadget-RCE instead of system
- Hijack hook function
- Use printf to trigger malloc and free
- Use execveat to open a shell
overflow
假设:定义了char buf[40] signed int num
scanf
- scanf(“%s”, buf)
%s没有边界检查,可以溢出 - scanf(“%39s”, buf)
%39仅从输入中获取39个字节,并将NULL字节放在输入末尾,无法溢出 - scanf(“%40s”, buf)
从输入中获取40个字节,但还会在输入末尾的位置放NULL字节,存在单字节NULL溢出 - scanf(“%d”, &num)
结合alloca(num)使用,如果设置num为负值,会出现从栈上分配的堆与原来的栈帧重合
大多数时候,程序只检查了上界而没有忘记num可能为负数(或者说忘了设置num为无符号数),此时将num输入为负数可能有意外的效
果
alloca()是在栈(stack)上申请空间的
get
- gets(buf)
没有边界检查,可溢出 - fgets(buf,40,stdin)
从输入中获取39个字节,把NULL字节放在输入末尾,无用
read
- read(stdin, buf, 40) fread(buf, 1, 40, stdin)
从输入中获取40个字节,并且不会在末尾放置NULL字节,可能存在信息泄露
例如
0x7fffffffdd00: 0x4141414141414141 0x4141414141414141 0x7fffffffdd10: 0x4141414141414141 0x4141414141414141 0x7fffffffdd20: 0x4141414141414141 0x00007fffffffe1cd
此时如果用printf或puts用于输出buf,它将一直输出,直到NULL字节
此时可以得到’A’*40 + ‘\xcd\xe1\xff\xff\xff\x7f’,从而信息泄露成功
strcpy
假设:定义char buf2[60]
- strcpy(buf,buf2)
strcpy()函数将源字符串buf2 的每个字节拷贝到目的字符串buf 中,直到到达NULL字节,buf2字符串末尾的NULL字节也被拷贝过去,buf2可能比buf长,所以可能溢出 - stncpy(buf,buf2,40) memcpy(buf,buf2,40)
将40个字节从buf2复制到buf,但不会在末尾放置NULL字节,由于没有NULL字节,可能存在信息泄露,如printf或puts该内容时,同上面的read的信息泄露
strcat
- strcat(buf,buf2)
把 buf2 所指向的字符串追加到 buf 所指向的字符串的结尾。如果buf不够大,可能会导致溢出
会把NULL字节放在末尾,可能会导致一字节溢出
在某些情况下,可以使用该NULL字节正好覆盖储存堆栈地址的最低位字节 - strncat(buf, buf2, n)
strncat() 在strcat() 的基础上增加第三个参数,其中第三个参数限制添加的最大字符数,其他跟strcat() 一样:把拼接后的字符串作为新的第一个字符串同时也会把NULL字节放在末尾,第二个字符串的值不改变;返回值是第一个参数的地址
也可能会有单字节NULL溢出
Find string in gdb
environ利用
通过libc找到environ地址后,泄露environ地址处的值,可以得到环境变量地址,环境变量保存在栈中,通过偏移可以得到栈上任意变量的地址。
ssp((Stack Smashing Protect) )攻击
检测到stack smash时,__stack_chk_fail函数会在报错信息中会打印出libc_argv[0]的值,而libc_argv[0]指向的则是程序名。
若我们能够栈溢出足够的长度,覆盖到__libc_argv[0]的位置,那我们就能让程序打印出任意地址的数据,造成任意地址数据泄露。这就是ssp攻击。
在SSP攻击中,我们需要找到argv[0]和输出开始地址之间的距离
gdb
gdb print打印
- 在gdb中使用p/x ((char **)environ),argv[0]的地址将是打印的地址值 - 0x10
(gdb) p/x (char **)environ # 以十六级进制形式打印
$9 = 0x7fffffffde38
(gdb) x/gx 0x7fffffffde38-0x10 #以一个八个字节为单元十六进制形式显示一个单元地址的内容
0x7fffffffde28: 0x00007fffffffe1cd
(gdb) x/s 0x00007fffffffe1cd#显示地址对应的字符串
0x7fffffffe1cd: "/home/naetw/CTF/seccon2016/check/checker"
gdb peda
使用 searchmem "/home“可找到argv[0]的位置,如图在
[stack] : 0x7fffffffe2cc (“/home/llk/桌面/exp/dui/b00ks”)
Binary Service
ncat 将二进制文件转换为IP地址和端口
加载顺序为LD_PRELOAD > LD_LIBRARY_PATH > /etc/ld.so.cache > /lib>/usr/lib
LD_PRELOAD(not LD_PRELOAD_PATH) 是要在任何其他库之前加载的特定库 ( files ) 的列表,无论程序是否需要。LD_LIBRARY_PATH是在加载无论如何都会加载的库时要搜索的 目录列表。
- ncat -vc ./二进制文件名 -kl 127.0.0.1 端口号
当需要修改动态链接库的时候
- ncat -vc ‘LD_PRELOAD=/path/to/libc.so ./binary’ ./二进制文件名 -kl 127.0.0.1 端口号
- ncat -vc ‘LD_LIBRARY_PATH=/path/of/libc.so ./binary’ ./二进制文件名 -kl 127.0.0.1 端口号
然后可以通过nc 127.0.0.1 端口号来允许该程序
Find specific function offset in libc
当我们成功泄露函数地址时,可以得到libc的基地址通过得到函数地址减去函数的偏移
readelf是用来读取elf文件相关信息的
手工
- readelf -s libc文件 | grep 函数名
自动
- 使用pwntools提供的函数
from pwn import *libc = ELF('libc文件')
system_off = libc.symbols['函数']
Find ‘/bin/sh’ or ‘sh’ in library
objdump反汇编文件
手动
- strings -tx libc文件 | grep 字符串
自动
from pwn import *libc = ELF('libc.so')
...
sh = base + next(libc.search('sh\x00'))
binsh = base + next(libc.search('/bin/sh\x00'))
Leak stack address
Fork problem in gdb
Secret of a mysterious section - .tls
Predictable RNG(Random Number Generator)
Make stack executable
Use one-gadget-RCE instead of system
Hijack hook function
Use printf to trigger malloc and free
Use execveat to open a shell
参考Naetw大佬的GitHub上的总结