正则补充/无参函数绕过RCE实验
免责声明本文全部实验操作均在本人完全可控的自建本地靶场环境完成文章仅用于网络安全原理学习与技术研究。 根据《中华人民共和国网络安全法》未经授权对任何第三方系统进行探测、命令执行、文件写入等操作属于违法行为。严禁复制、使用本文中的 Payload、代码应用到未获得授权的设备上。若读者将文中内容用于非法用途一切法律责任由行为人本人承担与本文作者无关。php正则\w匹配字母、数字、下划线 [A‑Za‑z0‑9_]\W大写 W\w取反等价于[^A‑Za‑z0‑9_]匹配所有非单词字符空格、标点符号、分号、$、(、)等。正则元字符 ^不在 [ ] 里面开头锚点^ 匹配字符串的开始位置不匹配实际字符只匹配位置。/^a/匹配以 a 开头的字符串在方括号 [^ ] 里面取反否定字符集[^abc]匹配不是 a、不是 b、不是 c的任意一个字符。只有写在[ ]的最第一位才代表取反写在中间就是普通字符^。/[^0‑9]/ // 匹配非数字等价 \D /[^a]/ // 匹配不是a的字符 /[a^b]/ // ^放在中间就是普通脱字符不取反匹配a、^、b(?R) (?0)递归调用整个正则表达式。/[^\W]\((?R)?\)/正则含义[^\W]匹配字母数字下划线左边的字符出现一次或多次\(匹配左括号(?R):如果条件允许从头完整重新跑一遍整个正则表达式递归R表示递归。第二个问号是可以有0次或者一次\)匹配右括号[^\W] \( → 然后执行(?R)?递归递归跑完再执行后面的\)。eval(phpinfo())匹配完 eval(执行(?R)从头跑完整正则成功匹配内层phpinfo()递归完成回到外层继续匹配外层的)。匹配无参数函数调用无参数函数形态函数名()可以嵌套无参函数--绕过思路思考这个正则是什么意思。?php highlight_file(__FILE__); if(; preg_replace(/[^\W]\((?R)?\)/, , $_GET[code])) { eval($_GET[code]); } ?getallheaders()获取全部 HTTP 请求头返回一个关联数组?php echo pre; var_dump(getallheaders()); ?PHP 输出字符串pre发给浏览器浏览器收到之后解析为 HTML 标签作用保留原始文本里面的换行\n、空格、tab 缩进[Priority] 显示数组键 (key)string(6) u0, i告诉你这是字符串字符串长度 6后面是内容在这里1 个数组里面存放了 10 组「键 值」数据。foreach是 PHP 专门用来遍历数组的循环把数组拆开只取出键和值的内容?php foreach (getallheaders() as $name $value) { echo pre; echo $name: $value\n; } ?current别名pos读取当前数组指针指向的值默认为第一个用next将数组内部指针向后移动一位用prev将数组内部指针向前移动一位用end直接把数组内部指针移动到最后一个元素例如PHP 内置预定义常量EOL End Of Line行结束符、换行。?php echo pre; $a array(1,2,3,4); echo 这是第一个,current($a), PHP_EOL; echo 这是指针第一次移位,next($a), PHP_EOL; echo 指针第一次移位的值,current($a),PHP_EOL; echo 这是指针第二次移位,next($a), PHP_EOL; echo 指针第二次移位的值,current($a),PHP_EOL; echo 这是指针向前移位,prev($a), PHP_EOL; echo 指针第三次移位的值,current($a),PHP_EOL; echo 指针直接移到末尾,end($a), PHP_EOL; echo 当前的值,current($a), PHP_EOL; // $mode plane; ?方法一使用getallheaders 数组指针逃逸?????实验到底是只能apache使用还是nginxapach都能使用生成后门文件成功留下后门方法二get_defined_varsdefined是定义的意思返回由所有已定义变量所组成的数组,返回调用该函数所在作用域内全部已定义变量的数组PHP?php echo pre; $b array(1, 1, 2, 3, 5, 8); $arr get_defined_vars(); print_r($arr[b]); // 打印变量数组的所有可用键 print_r(array_keys(get_defined_vars())); ?PHP 超全局变量不是在脚本代码中定义的而是在 PHP 请求初始化阶段由 PHP 引擎自动创建并注册到当前运行环境中。get_defined_vars()可以读取当前环境中的变量因此能够查看这些超全局变量。它们本质是预分配的数据容器专门用来存放 HTTP 请求解析后的对应数据容器的创建和客户端是否提交数据无关。即便访问时不带 URL 参数、没有 POST 提交、没有 Cookie$_GET、$_POST、$_COOKIE依然存在只是内部没有元素表现为空数组。当请求携带对应数据时PHP 会把解析完成的键值对填充到对应的数组容器中。这些变量处于全局作用域所以get_defined_vars()扫描全局变量集合时可以获取到它们。观察get_defined_vars()输出确认超全局变量存在。返回当前全部全局变量可以看到数组内自带_GET、_POST、_COOKIE等 PHP 超全局变量证明可以在 code 内部拿到 GET 请求参数。1.观察get_defined_vars()输出确认超全局变量存在2.新增第二个 GET 参数观察get_defined_vars()的 $_GET 数组变化URL 额外增加1phpinfo();此时$_GET数组就有两个 keycode、1key1 的值就是我们想要执行的字符串phpinfo();。但是此时还无法直接调用因为不能写$_GET[1]这种方括号语法会被正则拦截。3.验证直接数组下标取值获取第二个参数字符串数组[键名]方括号是 PHP 数组访问语法一层[]访问一维两层[][]访问二维嵌套数组。get_defined_vars() → 返回大数组里面包含_GET、_POST等 key[_GET] → 取出这个大数组中 key 为_GET的值这个值本身又是一个数组PHP 的$_GET本身就是数组[a]从_GET数组取 keya的元素如果a对应的值还是二维数组就继续写第二个[b]验证直接数组下标取值获取第二个参数字符串这里编辑代码再次查看成功取出phpinfo();字符串。code 里面包含[]符号正则无法把这整行全部清空处理后残留不是;if 判断失败eval 不会触发页面没有执行效果。4.pos()获取数组第一个元素观察 $_GET 数组结构获取数组当前指针指向的第一个元素。get_defined_vars()第一个元素就是$_GET数组拿到$_GET数组[codexxx,1phpinfo();]。此时指针停在code这个 key。5.next()移动数组内部指针跳到第二个参数6.最终 payload直接执行取出的字符串触发 phpinfo原理preg_replace() 的作用不是直接修改传进去的变量而是返回一个新的字符串。实际上正则匹配过程system( next( pos( get_defined_vars() ) ) )匹配到最后的返回值是。if判断条件成立。如下图匹配成功后变量的值并没有改变所以说使用eval(next(pos(get_defined_vars()))); 时传入的参数最终原封不动的传入eval($_GET[code]);中而参数中的eval用来提取phpinfo();外层的eval再执行phpinfo写入后门

相关新闻

最新新闻

日新闻

周新闻

月新闻