Moinmoin远程代码执行漏洞分析

2013-11-26 16:24:06 24 10675 1


有基友表示需要原文的链接,放到开头这里了https://www.pentesterlab.com/exercises/cve-2012-6081/
0x01 摘要
       在PentesterLab上看到的一个python写的wiki系统漏洞分析,感觉比较经典,正好拿来学习下python脚本漏洞的挖掘。

0x02 补丁分析与利用过程
       这个漏洞官方已经进行了修补,我们通过对比前后版本代码来确定漏洞位置,对比后发现在AttachFile.py,twikidraw.py和anywikidraw.py两个文件发生了变化,如下图所示:



      可以看出在twikidraw.py和anywikidraw.py两个文件都添加了一行使用tainfilename方法处理target参数的代码,而在AttachFile.py文件添加的注释中刚好解释了这一原因,是为了防止恶意用户通过使用目录遍历符(../)来进行目录遍历和代码执行攻击。
      根据应用程序执行流程,定位到twikidraw.py文件中同名类的execute方法,发现其中执行的save方法可以将用户提交的内容本地保存到target参数所指向的文件。
      MoinMoin这套应用程序为用户提供了一个插件目录,用户可以根据自己的需求来写py类型的插件。这样一来我们的利用目的也就明确了,通过target参数过滤不严的问题,向插件目录写一个插件(py脚本)来实现代码执行。
      通过查询MoinMoin文档,决定写一个action插件,这种插件API就像下面这样:
def execute(pagename, request):
[...]
根据API,我们实现了一个执行系统命令的插件:
import os
def execute(pagename, request):
stream = os.popen(request.values['cmd'])
request.write(stream.read())

       不过到这里还并没有结束,在save方法会通过AttachFile.py文件中的put方法,将上传文件内容放入一个tar文件中。代码如下所示:
ci.put('drawing' + ext, filecontent, content_length)
其中ext为上传文件的后缀名。所以也就是说,我们不能通过content来上传py脚本了。不过查看tar的描述,我们可以看到这样一段话:
Traditionally, old tars have a limit of 100 characters. GNU tar attempted two different approaches to overcome this limit, using and extending a format specified by a draft of some P1003.1. The first way was not that successful, and involved `@MaNgLeD@' file names, or such; while a second approach used `././@LongLink' and other tricks, yielding better success. In theory, GNU tar should be able to handle file names of practically unlimited length. So, if GNU tar fails to dump and retrieve files having more than 100 characters, then there is a bug in GNU tar, indeed.

      大意是说tar会将文件名一起放入到tar文件中,并且不做任何压缩处理。但是如果文件大小超过100个字符,那么将会在文件头处添加“././@LongLink”作为标识。
      由此我们重新整理思路,我们可以通过上传文件的后缀名来将py脚本保存至target指向的文件。但是我们面临三点限制:
1. 应用程序使用os.path.splitext方法切割后缀名,所以后缀名必须是一个以“.”开始的字符串,并且后面的内容中不能再有“.”了,否则就会被作为后缀名再次进行切割。也就是说我们上传文件的文件名要像这样“drawing.PAYLOAD”
2. 由于文件名会被一起放入在文件中,所以我们要确保文件名不会导致python语法出错
3. 最后就是之前我们提到的,确保文件名处最多只有100个字符
      第一个问题可以通过将PAYLOAD中的“.”用八进制进制编码“\56”代替。对于第二个问题,我们可以在同一行中使用if()else(),来确保不会出现语法错误,即drawing.z if()else()。然后后我们尽可能的压缩我们的PAYLOAD成下面这个样子,刚好100个字符。
payload = "drawing.s if()else()\nimport os\ndef
execute(p,r):exec\"print>>r,os\\56popen(r\\56values['c'])\\56read()\""
0x03 漏洞重现
      通过Burp suite抓取访问twikidraw代码的数据包,并定位上传内容的POST数据。如下图所示:


      修改target参数和filename表单

      提交表单后,访问插件shell,提交参数c为uname –a,效果如下图所示:

关于作者

唐门三少17篇文章105篇回复

评论24次

要评论?请先  登录  或  注册
  • 4楼
    2013-11-26 18:29

    能否将PentesterLab上的这个文章链接也发一下?感谢

  • 3楼
    2013-11-26 18:13

    有点意思 本地上传文件名 会保存在服务器写入的文件头里 且大于100字节则会被压缩 同理不超过100字节 控制写入文件内容同样是可以写入代码并包含执行吧 但漏洞利用的最好方法却是控制2个文件名的参数的确有点意外 假如攻击压缩算法对抗文件压缩 那失败的压缩文件同样存在我们需要的代码 这样100字节的限制就可以忽略了 这样算YY吗呵呵 现在ruby的框架好像开始流行了呢 要学的东西真多╮(╯▽╰)╭

  • 2楼
    2013-11-26 17:13

    厉害,大牛。。。

  • 1楼
    2013-11-26 17:08

    赞 不错,