声明
本文仅供学习和研究,由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,海青实验室及文章作者不承担任何责任。
安全狗海青实验室拥有此文章的修改和解释权,如欲转载或传播,必须保证此文的完整性,包括版权声明在内的全部内容,未经海青实验室同意,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。
近日得到了红日安全团队制作的一套渗透测试靶场,由于笔者对内网和域渗透并不熟悉,正好借此来学习一下渗透测试的基本操作和流程。有意思的是,笔者在前台发现了一个SQL注入,并且使用了一个小trick,所以分享一下。
一、Web服务器的突破
整个网络服务起来以后,扫描了一下目标IP,查看了开放了哪些端口。
显然存在WEB应用,访问看看。(注:我没用扫描器,讲道理实战应该是没有yxcms这个目录的,我是看了一下靶机的文件结构)
当得知了是YXCMS的系统,那么剩下的就是收集该系统存在的已知漏洞,那问题是,版本号还不知道。在github上搜了一下这套系统的源码,查看了一下目录结构,发现有一个升级日志.txt。根据之前审计代码的经验,多数的CMS会有一个README和类似升级日志这样的文件,记录一下当前版本的一些信息。
试试访问看,果然有——这样就拿到了版本号,那接着就是找yxcms1.2.1版本的漏洞。
搜索后会发现有这么一个网站,预留的后台账户……我感觉这个靶场应该没有修改过这个密码,就拿这个弱密码去尝试了。
ok,成功进入后台,在后台可以看到编辑模板的地方,竟然还可以直接创建PHP文件,但是创建完的文件路径需要寻找,一时间我没找到,我是下载了源码在本地测试发现路径如下:
WWW\yxcms\protected\apps\default\view\default\a.php
可怜的kali只有一把C刀,感觉要找把好用的菜刀。
二、以代码审计的方式突破
显然,上述攻破WEB服务器的方式太过于走运:恰好就那么一个预留账号,还是默认密码,这种方式不具有普遍意义。既然我们已经能拿到对应版本的源码了,总该尝试一下以审计的方式,找出漏洞点拿下服务器。因为对该系统的框架不是很熟悉,笔者只了解到是个MVC架构,屋漏偏逢连夜雨,Xdebug在此时又出问题了,无法动态调试,于是就进行静态分析,不断打印输出exit。
目标:找到一个不需要验证的、或者普通用户权限的注入点,拿下管理员账号。
很快,在Index控制器下可以发现如下代码。其中变量code是可控,并且解密后赋值给变量$acc,再之后传入了find方法之中,为了构造出完整的POC进行注入,需要找到最终构造SQL语句的代码。
find方法定义在model.php文件,显然第一个参数是条件语句。那么如上以拼接的方式构造SQL语句,显然很有可能出现SQL注入的问题。
在cpModel.class.php中找到了find方法和select方法的定义,最终的查询条件是在select方法中构造,因此将构造好Where条件打印出来看看。
接着就是跟进query方法,在此构造完整的查询语句,并且执行,在此次打印出查询语句。
这样其实就已经抓住了SQL语句构造的关键点了,再回头看最初的一行代码:
$acc=cp_decode(urldecode($_GET[‘code’]),config(‘ENCODE_KEY’));
显然,cp_decode是一个自定义的解密函数,代码如下
有解密自然就有加密。
思路很明显了,构造好SQL注入的payload,调用加密函数进行加密,然后传入,试试看。
payload:11' or '1'='1
加密后:
7e2bRaLd9061hM95hQB2apg0gw7kbOQcWLDFQWU9aPnWWi9%252FRgJFYj0eIYHmUiJ9JlQ
效果如下:解密之后拼接进SQL语句,显然,此处存在注入。
三、使用几行代码复活SQLmap
此时又面临了一个问题,如何自动化进行注入呢?作为一个脚本小子,自然想到使用SQLmap,可是有着自定义的加密函数,难不成要手撸一个python版的加密?然后再写SQLmap的tamper?太繁琐了!渗透神器在此竟然无用武之地?
其实,只需用几行代码就能复活神器!
在本地搭建一个flask平台接受SQLmap传递来的payload,然后去访问写有加密函数的PHP文件获取加密后的payload,最终再往目标网站上发包!
画了个大概的流程图:
flask平台代码如下:
from flask import Flask
from flask import request
import requests
php_url = "http://127.0.0.1/encode.php?payload={}" #加密函数文件
tar_url = "http://yxcmsapp/index.php?r=member/index/getpassword&code={}" #目标网站
app = Flask(__name__)
@app.route('/',methods=['GET'])
def getStr():
payload = request.args.get('payload') # 接受SQLmap的payload
print("payload is .........: {}".format(payload))
print("Encoding ....")
en_str = php_url.format(payload)
rs = requests.get(en_str)# 将payload发送至加密函数文件进行加密
print("Encoding payload......: {}".format(rs.text))
print("attack!")
attack_rs = requests.get(tar_url.format(rs.text)) #将加密后的payload发往目标站点
return attack_rs.text
if __name__ == '__main__':
app.run()
除去一些输出语句,总共就没几行代码。
加密函数文件内容直接复制过来,如下:
因为源程序中解码时调用了一次urldecode,所以要两次encode。
最后,使用SQLmap对flask平台进行SQL注入,效果如下。
最终,可以通过注入拿下管理员的账号,剩下的getshell的操作就和之前一样了。
值得一提的是,这套系统定义了一个in函数,用来防止SQL注入。可能开发者发现加密后的函数并不存在特殊字符就没用进行in函数的转义了吧,从而导致注入的产生。
上述的方法在很多场景下都可以使用,比如利用了JS对前端的一些参数加密后传输、表单收到Token保护等。如果不想分析原有的加密算法,就可以采用这种中转的方式进行攻击。拿了shell之后不知道该如何继续了,初体验就暂时到此结束。
已经WEB服务的大门已被攻破,在内网的操作这里就不作展开了。
四、总结
靶场其实是实际案例的一种映射,很多运维人员在建立企业网站时采用的就是此类的开源系统。的确,一键式的部署能够快速建站极其便利,但同时也带来了安全风险,譬如默认的管理员账号密码、系统版本信息、固定的网站目录等一些信息也随之暴露给攻击者。
因此、在广大用户选用开源系统快速建站的同时要注意选用安全性较高、积极维护的开源系统。关注该系统的历史版本是否存在漏洞,以及是否及时修补。有条件或者必要的情况下,可以对该系统进行一次代码审计排查隐患,也可以选择网站安全狗等系列WAF产品来抵御攻击。
*本文作者:安全狗safedog,转载请注明来自FreeBuf.COM
来源:freebuf.com 2020-04-09 10:00:05 by: 安全狗safedog
请登录后发表评论
注册