Open Source Social Network(OSSN),是一款用PHP编写的社交网络软件。OSSN允许用户创建一个社交网站,帮助拥有相似专业或个人兴趣的人建立社交关系。该软件拥有约50万下载量。
OSSN官网地址:
https://www.opensource-socialnetwork.org/
Open Source Social Network(OSSN)5.3之前版本中存在一处任意文件读取漏洞(CVE-2020-10560)。漏洞因OSSN生成的Site_Key强度过低从而可以遭受被暴力破解而产生,成功破解Site_Key的攻击者可以利用Site_Key构造出任意文件读取链接,通过components\OssnComments\ossn_com.php文件提供的文件预览接口,读取文件。
Open Source Social Network应用可以从如下官网链接下载:
https://www.opensource-socialnetwork.org/download
应用首页如下图
OSSN中提供Comment功能,访问者可以对帖子进行评论,见下图:
评论帖子时,用户可以上传图片以及表情,如下图红框处:
当选择本地图片并上传后,将在评论中生成一个预览,见下图:
注意,这时还没有点击发布评论,上图图片只是上传成功后的一个预览图片。该临时图像文件存储于tmp目录并在前端呈现了预览。
我们来看下这个临时图片文件是如何获取并在页面中展示的。查看一下图片链接,如下图:
链接如下:
我们可以猜测出image参数对应的字符串应该是文件地址的加密形式,只有构造出正确的base64字符串,攻击者就可以读取任意文件。
最重要的是,经过测试发现,访问这个链接并不需要用户登陆。任何人都可以通过这个链接直接访问我们上传的这个图片文件。
接下来分析下后台代码,看看这个base64字符串是如何还原出文件路径以及如何被构造出来的
上文链接对应的后台代码位于 \components\OssnComments\ossn_com.php
在ossn_com.php中case 'staticimage'分支里,程序将请求中image参数值取出,并进行base64_decode解码。见下图:
随后,对解码后的值再次base64_decode解码,然后利用ossn_string_decrypt方法解码并获取文件地址。见下图:
接着,通过ossn_validate_filepath方法对文件路径进行校验。见下图红框:
ossn_validate_filepath方法如下图所示,可见该方法对目录遍历进行了过滤
即使过滤了../ 我们仍然可以通过绝对路径来进行文件读取,例如直接读取/etc/passwd
最后,程序利用file_get_contents方法对文件内容进行读取,并使用echo进行打印。见下图红框:
通过阅读代码也可以验证之前的测试结果:该接口并未进行身份校验,未登录的用户依然可以通过该接口访问文件。
问题又回到了如何构造加密字符串上。我们首先来看一下程序是如何解码的,位于libraries\ossn.lib.system.php文件中
通过上图的代码看,在解码过程中,需要用到site_key值。
经过分析后发现,程序通过ossn_site_settings方法在数据库中读取site_key值,我们先来看一下存储于ossn_site_settings表中site_key值是什么,见下图:
site_key值为c1a725ed,可见是一个8位数
这样看来,只要破解出这个8位数的site_key,即可构造出指向任意文件路径的链接。
我们接着分析这个site_key是如何生成的,生成代码位于libraries\ossn.lib.upgrade.php文件中,见下图:
通过分析上图加密过程不难发现,该8位随机数是通过如下方式产生的:
以字符串“ ossn”开头。
通过rand方法生成一个随机数并拼接到“ ossn”字符串后。
计算此字符串的md5值。
将字符3-11取出作为site_key值。
本次漏洞就出在计算site_key值的第二步,也就是通过rand产生随机数这一步。
关于rand方法,可以参考php官网
在官网介绍页面中明确的给出了警告,见上图底部
警告
此函数不会生成加密安全值,并且不应将其用于加密目的。如果需要密码安全的值,请考虑改用random_int(),random_bytes()或openssl_random_pseudo_bytes()。
rand方法之所以不安全,其中一个比较重要的原因是它能产生的随机数范围有限:
rand方法在没有提供可选参数 min 和 max时,返回 0 到 RAND_MAX之间的伪随机整数.
在笔者的windows主机上,RAND_MAX值仅为32767
而在笔者的Linux环境中,这个值为2147483647
据资料显示,rand最大可能值为2,147,483,647
因此,只需要生成最多20亿个rand值,将其依次带入ossn_generate_site_secret计算出对应的site_key值,这些site_key值即为所有的site_key值可能值。如果运气好,目标主机是一台windows主机,这样的操作仅仅重复3万多次即可,因为windows主机下rand产生的最大值仅为32767。
在分析了弱密钥是如何生成之后,我们需要一种方法来识别生成的密钥是否有效。在临时图片文件被上传到服务器时,会被存储于ossn_data/tmp/photos文件夹中,见下图:
因此上文中的加密数据成功解码后,其字符串中一定会包含tmp/photos字符串。我们这里用我们的密钥解一下上文中的编码,看一下这个推论是否正确,结果如下图:
可见成功解开的文件路径中的确存在tmp/photos字符串
因此,暴力破解的思路很明朗了
1、攻击者在评论里上传一个图片,不点击发送,查看此时图片临时预览链接,获取链接中image参数值。例如:http://192.167.30.119/comment/staticimage?image=UiszT0RJYStoQll2N2g5cHhmQW9PRHlCNVgrSWFKVzFQRHE4eTJqSWthVUVjUFBIb3pxME1FNUJFdk5ER2pONXI4V2pyeXJSMm9VPQ==中的UiszT0RJYStoQll2N2g5cHhmQW9PRHlCNVgrSWFKVzFQRHE4eTJqSWthVUVjUFBIb3pxME1FNUJFdk5ER2pONXI4V2pyeXJSMm9VPQ==>
2、将数字0-2147483647依次带入ossn_generate_site_secret中计算出对应的site_key
3、依次将site_key与image值带入ossn_string_decrypt中,获取解密后的明文
4、如果明文中含有tmp/photos字符串,解密成功,此时的site_key即为正确的site_key值
在获取site_key值后,可以通过ossn_string_encrypt方法,对想要读取的文件进行加密,通过http://192.167.30.119/comment/staticimage?image=接口进行读取即可
上文所涉及的工具如下:
site_key计算工具
https://github.com/LucidUnicorn/CVE-2020-10560-Key-Recovery
加密解密工具