深度优先搜索与广度优先搜索

article/2025/9/16 21:54:36

算法是作用于具体数据结构之上的,深度优先搜索算法和广度优先搜索算法都是基于“图”这种数据结构的。这是因为,图这种数据结构的表达能力很强,大部分涉及搜索的场景都可以抽象成“图”。

图上的搜索算法,最直接的理解就是,在图中找出从一个顶点出发,到另一个顶点的路径。为了搞清楚图的搜索算法,必须先把图的存储方式理解透彻。

图的存储

图有多种存储方法,最常用的两种分别是:邻接矩阵和出边数组。

邻接矩阵的存储方式如下图所示,底层依赖一个二维数组。

对于无向图来说,如果顶点i与顶点j之间有边,我们就将A[i][j]和 A[j][i]标记1;对于有向图来说,如果顶点i到顶点j之间,有一条箭头从顶点i指向顶点j的边,那我们就将A[i][j]标记为1。同理,如果有一条箭头从顶点j指向顶点i的边,我们就将A[j][i]标记为1。对于带权图,数组中就存储相应的权重。

用邻接矩阵来表示一个图,虽然简单、直观,但是比较浪费存储空间。对于无向图来说,如果A[i][j]等于1,那A[j][i]也肯定等于1。实际上,我们只需要存储一个就可以了。也就是说,无向图的二维数组中,如果我们将其用对角线划分为上下两部分,那我们只需要利用上面或者下面这样一半的空间就足够了,另外一半白白浪费掉了。

针对上面邻接矩阵比较浪费内存空间的问题,出边数组可以避免空间浪费。如下图所示,每个顶点对应一条链表,链表中存储的是与这个顶点相连接的其他顶点。

例如上图中,我们要确定,是否存在一条从顶点2到顶点4的边,那我们就要遍历顶点2的所有出边,看出边是否能到达顶点4。所以,比起邻接矩阵的存储方式,在出边数组中查询两个顶点之间的关系就没那么高效了。

//无向图
public class UndirectedGraph { /*** 顶点的个数*/private int v;/*** 邻接表(出边数组)*/private ArrayList<Integer>[] edges;public UndirectedGraph(int v) {this.v = v;edges = new ArrayList[v];for (int i = 0; i < v; ++i) {edges[i] = new ArrayList<>();}}/*** 对于无向图,其实就是点s到点t的两条边* 用两条有向边代表无向图中的一条边*/public void addEdge(int s, int t) {edges[s].add(t);edges[t].add(s);}
}

深度优先搜索(DFS)

深度优先搜索用的是一种比较著名的算法思想,回溯思想。这种思想解决问题的过程,非常适合用递归来实现。例如下图中演示了用深度优先搜索的思想寻找一条从点s到点c的路径的方法。从图中我们可以看出,深度优先搜索找出来的路径,并不是点s到点c的最短路径。

我把上面的过程用递归的形式写下来如下。深度优先搜索代码里,有个比较特殊的全局变量found,它的作用是,当我们已经找到终止点之后,我们就不再递归地继续查找了。

//全局变量或者类成员变量
boolean found = false;
private int  v;
private ArrayList<Integer>[] edges;public void existPath(int start, int t) {boolean[] visited = new boolean[v];recurDfs(start, t, visited);
}private void recurDfs(int current, int t, boolean[] visited) {if (found == true) {return;}visited[current] = true;if (current == t) {found = true;return;}for (int i = 0; i < edges[current].size(); ++i) {int q = edges[current].get(i);if (!visited[q]) {recurDfs(q, t, visited);}}
}

理解了深度优先搜索算法之后,深度优先搜索的时间、空间复杂度是多少呢?从示意图可以看出,每条边最多会被访问两次,一次是遍历,一次是回退。所以,图上的深度优先搜索算法的时间复杂度是O(E),E表示边数。深度优先搜索算法的消耗内存主要是visited、数组和递归调用栈。visited数组的大小跟顶点的个数V成正比,递归调用栈的最大深度不会超过顶点的个数,所以总的空间复杂度就是O(V)。

广度优先搜索(BFS)

广度优先搜索直观地讲,就是一种“地毯式”层层推进的搜索策略,即先查找离起始顶点最近的,然后是次近的,依次往外搜索。理解起来并不难,示意图如下。

尽管广度优先搜索的原理挺简单,但代码实现还是稍微有点复杂度。实际上,这样得到的一条路径就是从起始点到指定点的最短路径。

private boolean existPathBfs(int current, int t) {if (current == t) {return true;}visited[current] = true;Queue<Integer> queue = new ArrayDeque<>();queue.add(current);while (!queue.isEmpty()) {int point = queue.poll();for (int i = 0; i < edges[point].size(); ++i) {int q = edges[point].get(i);if (!visited[q]) {if (q == t) {return true;}queue.add(q);visited[q] = true;}}}return false;
}

BFS代码中的queue是一个队列,用来存储已经被访问、但相连的顶点还没有被访问的顶点。因为广度优先搜索是逐层访问的,也就是说,我们只有把第k层的顶点都访问完成之后,才能访问第k+1层的顶点。当我们访问到第k层的顶点的时候,我们需要把第k层的顶点记录下来,稍后才能通过第k层的顶点来找第k+1层的顶点。所以,我们用这个队列来实现记录的功能。

广度优先搜索的时间、空间复杂度是多少呢?最坏情况下,终止顶点t离起始顶点s很远,需要遍历完整个图才能找到。这个时候,每个顶点都要进出一遍队列,每个边也都会被访问一次,所以,广度优先搜索的时间复杂度是 O(V+E),其中,V表示顶点的个数,E表示边的个数。当然,对于一个连通图来说,也就是说一个图中的所有顶点都是连通的,E肯定要大于等于V-1,所以,广度优先搜索的时间复杂度也可以简写为O(E)。空间消耗主要在几个辅助变量visited数组、queue队列上。这三个存储空间的大小都不会超过顶点的个数,所以空间复杂度是O(V)。

DFS与BFS的实际应用

样题一:岛屿的数量

给你一个由’1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。此外,你可以假设该网格的四条边均被水包围。

DFS的思路:将二维网格看成一个无向图,竖直或水平相邻的点’1’之间有边相连。为了求出岛屿的数量,我们可以扫描整个二维网格。如果一个位置为’1’,则以其为起始节点开始进行深度优先搜索。在深度优先搜索的过程中,每个搜索到的’1’都会被重新标记。

最终岛屿的数量就是我们进行深度优先搜索的次数。

class Solution {//垂直水平四个方向组成的方向数组private int[] dx = {-1,0,1,0};private int[] dy = {0,1,0,-1};private boolean[][] visited;public int numIslands(char[][] grid) {visited = new boolean[grid.length][grid[0].length];int ans = 0;for (int i = 0; i < grid.length; i++) {for (int j = 0; j < grid[0].length; j++) {if (grid[i][j] == '1' && !visited[i][j]) {//以grid[i][j]这个点为起点,作深度优先遍历dfs(grid, i, j);//递归的次数就是图中陆地独立成片的块数ans++;}}}return ans;}//从点(x,y)出发,深度优先遍历private void dfs(char[][] grid, int x, int y) {//标记当前点grid[x][y]已经访问过了visited[x][y] = true;//然后遍历grid[x][y]点的所有出边,这里就是上下左右4个for (int i = 0; i < 4; i++) {int nx = x + dx[i];int ny = y + dy[i];//判断坐标合法时,才继续遍历if(nx < 0 || nx >= grid.length || ny < 0 || ny >= grid[0].length) {continue;}//只遍历没访问过且为陆地的点if (grid[nx][ny] == '1' && !visited[nx][ny]) {dfs(grid, nx, ny);}}}
}

同样地,我们也可以使用广度优先搜索代替深度优先搜索。

BFS的思路:为了求出岛屿的数量,我们可以扫描整个二维网格。如果一个位置为‘1’,则将其加入队列,开始进行广度优先搜索。在广度优先搜索的过程中,从原点出发能到达的每个点‘1’都会被重新标记。直到队列为空,搜索结束。

最终岛屿的数量就是我们进行广度优先搜索的次数。

class Solution {//垂直水平四个方向组成的方向数组private int[] dx = {-1,0,1,0};private int[] dy = {0,1,0,-1};private boolean[][] visited;public int numIslands(char[][] grid) {visited = new boolean[grid.length][grid[0].length];int ans = 0;for (int i = 0; i < grid.length; i++) {for (int j = 0; j < grid[0].length; j++) {if (grid[i][j] == '1' && !visited[i][j]) {//以grid[i][j]这个点为起点,作广度优先遍历bfs(grid, i, j);ans++;}}}return ans;}//从点(x,y)出发,广度优先遍历private void bfs(char[][] grid, int x, int y) {//标记点(x,y)为已经访问过了visited[x][y] = true;Queue<Pair> queue = new ArrayDeque<>();queue.add(new Pair(x, y));while (!queue.isEmpty()) {Pair pair = queue.poll();//然后遍历grid[x][y]点的所有出边,这里就是上下左右4个for (int i = 0; i < 4; i++) {int nx = pair.row + dx[i];int ny = pair.column + dy[i];//判断坐标合法时,才继续遍历if(nx < 0 || nx >= grid.length || ny < 0 || ny >= grid[0].length) {continue;}//只遍历没访问过且为陆地的点if (grid[nx][ny] == '1' && !visited[nx][ny]) {queue.add(new Pair(nx, ny));//入队时标记visited数组visited[nx][ny] = true;}}}}class Pair {int row;int column;public Pair(int row, int column) {this.row = row;this.column = column;}}
}

样题二:被包围的区域

注意关键解释:被围绕的区域不会存在于边界上,换句话说,任何边界上的 ‘O’ 都不会被填充为 ‘X’。 任何不在边界上,或不与边界上的 ‘O’ 相连的 ‘O’ 最终都会被填充为 ‘X’。如果两个元素在水平或垂直方向相邻,则称它们是“相连”的。

问题可以转化为:从边界上的‘O’出发所有能被访问到的‘O’都不能被填充为’X’,剩下的‘O’可以被填充为’X’,这是一个搜索问题。

思路:将所有存在于边界上的点’O’都打上标记,例如标记为’#‘,然后从这些点出发作搜索,所有能到达的点’O’也打上标记’#‘,最后将矩阵中所有标记为’#‘的点都填充为’O’,所有为’O’的点都填充为’X’。

DFS思路下的代码。

class Solution {private int[] dx = {-1,0,1,0};private int[] dy = {0,1,0,-1};private boolean[][] visited;//寻找和边界连通的O,如果这个O与边界连通,那么不能替换,否则要替换public void solve(char[][] board) {visited = new boolean[board.length][board[0].length];for (int i = 0; i < board.length; i++) {for (int j = 0; j < board[0].length; j++) {if (board[i][j] == 'X') {continue;}//判断点是否在边界上,如果在边界上并且是O,并且没访问过,就访问一次boolean isEdge = (i == 0 || j == 0 || i == board.length - 1 || j == board[0].length - 1);if (isEdge && board[i][j] == 'O') {dfs(board, i, j);}}}for (int i = 0; i < board.length; i++) {for (int j = 0; j < board[0].length; j++) {if (board[i][j] == 'O') {board[i][j] = 'X';} else if (board[i][j] == '#') {board[i][j] = 'O';continue;}}}}//从点(x,y)出发作深度优先遍历,访问从点(x,y)所能到达的所有点private void dfs(char[][] board, int x, int y) {if (board[x][y] == '#') {return;}visited[x][y] = true;board[x][y] = '#';//然后遍历board[x][y]的所有点,这里就是上下左右4个for (int i = 0; i < 4; i++) {int nx = x + dx[i];int ny = y + dy[i];//判断坐标合法时,才继续遍历if(nx < 0 || nx >= board.length || ny < 0 || ny >= board[0].length) {continue;}//只遍历没访问过且为'O'的点if (board[nx][ny] == 'O' && !visited[nx][ny]) {dfs(board, nx, ny);}}}
}

BFS思路下的代码。

class Solution {private int[] dx = {-1,0,1,0};private int[] dy = {0,1,0,-1};private boolean[][] visited;//寻找和边界连通的O,如果这个O与边界连通,那么不能替换,否则要替换public void solve(char[][] board) {visited = new boolean[board.length][board[0].length];for (int i = 0; i < board.length; i++) {for (int j = 0; j < board[0].length; j++) {if (board[i][j] == 'X') {continue;}//判断点是否在边界上,如果在边界上并且是'O',并且没访问过,就访问一次boolean isEdge = (i == 0 || j == 0 || i == board.length - 1 || j == board[0].length - 1);if (isEdge && board[i][j] == 'O') {bfs(board, i, j);}}}for (int i = 0; i < board.length; i++) {for (int j = 0; j < board[0].length; j++) {if (board[i][j] == 'O') {board[i][j] = 'X';} else if (board[i][j] == '#') {board[i][j] = 'O';continue;}}}}//从点(x,y)出发作深度优先遍历,访问从点(x,y)所能到达的所有点private void bfs(char[][] board, int x, int y) {visited[x][y] = true;board[x][y] = '#';Queue<Pair> queue = new ArrayDeque<>();queue.add(new Pair(x, y));while (!queue.isEmpty()) {Pair pair = queue.poll();//然后遍历board[x][y]的所有点,这里就是上下左右4个for (int i = 0; i < 4; i++) {int nx = pair.row + dx[i];int ny = pair.column + dy[i];//判断坐标合法时,才继续遍历if(nx < 0 || nx >= board.length || ny < 0 || ny >= board[0].length) {continue;}//只遍历没访问过且为'O'的点if (board[nx][ny] == 'O' && !visited[nx][ny]) {queue.add(new Pair(nx, ny));visited[nx][ny] = true;board[nx][ny] = '#';}}}}class Pair {int row;int column;public Pair(int row, int column) {this.row = row;this.column = column;}}
}

样题三:省份数量

思路:给出的矩阵isConnected其实就是典型的邻接矩阵,这种图的存储方式很简洁。对于无向图,矩阵按对角线对称。问题可以转化成求无向图中连通块的个数,顶点数量为n,顶点的编号为0到n-1,矩阵isConnected描述了各个顶点的连接情况(矩阵中有一半信息是冗余的)。只需要从一个顶点出发遍历其能到达的其他所有顶点,当前顶点与其能到达的其他顶点构成连通块,统计这样的连通块的个数。

DFS与BFS的思路都能解决此问题,代码如下:

class Solution {//在无向图中,若从顶点a到顶点b有路径,则称a和b是连通的。//若无向图中,任意两个不同的顶点都连通,则称无向图为连通图//求无向图中连通块数量public int findCircleNum(int[][] isConnected) {int ans = 0;//初始化int v = isConnected.length;boolean[] visited = new boolean[v];//无向图中共有v个顶点,顶点编号为0到v-1,找图中连通块的数量for (int i = 0; i < v; i++) {//已经访问过的不再访问if (!visited[i]) {//连通块的数量就是dfs或bfs搜索的次数// dfs(isConnected, i, visited);bfs(isConnected, i, visited);ans++;}}return ans;}//深度优先搜索private void dfs(int[][] isConnected, int cur, boolean[] visited) {//已经访问过了,不再访问if (visited[cur]) {return;}visited[cur] = true;//从点cur出发,遍历其能到达的所有其他点,cur自己除外for (int i = 0; i < isConnected[0].length; i++) {if (i != cur && isConnected[cur][i] == 1) {dfs(isConnected, i, visited);}}}//广度优先搜索private void bfs(int[][] isConnected, int cur, boolean[] visited) {//已经访问过了,不再访问if (visited[cur]) {return;}Queue<Integer> queue = new ArrayDeque<>();visited[cur] = true;queue.add(cur);//从顶点cur出发,遍历其能到达的其他点while (!queue.isEmpty()) {Integer vertex = queue.poll();//从顶点cur出发,遍历其能到达的并且没有访问过的其他点for (int i = 0; i < isConnected[0].length; i++) {if (i != vertex && isConnected[vertex][i] == 1 && visited[i] == false) {queue.add(i);visited[i] = true;}}}}
}

样题四:马走日

马在中国象棋以日字形规则移动,给定一个大小为n*m的棋盘,并指定一个初始坐标(x,y),要求不能重复经过棋盘上的同一个点,计算马可以有多少种途径可以遍历棋盘上的所有点,输出一个整数,表示马能遍历棋盘所有点的途径总数,若无法遍历所有点则输出0。输入的测试数据为一行四个整数,分别表示棋盘的大小以及初始位置坐标n、m、x、y。

样例输入:

5 4 0 0

样例输出:

32

思路:使用深搜去搜索,每走到一个点就做上标记,在一条路走到底的时候,取消已遍历节点的标记,标记的节点数大于棋盘上的总节点数则为一种遍历方法,停止遍历,累计遍历方法即可。

public class Solution {// 方向数组,马走日,一共8种走法public static final int[][] directions = new int[][]{{1,2},{-1,2},{1,-2},{-1,-2},{2,1},{2,-1},{-2,1},{-2,-1}};private int ans = 0;public int path(int n, int m, int x, int y) {ans = 0;boolean[][] visited = new boolean[n][m];visited[x][y] = true;dfs(n, m, x, y, visited, 1);return ans;}public void dfs(int n, int m, int x, int y, boolean[][] visited, int step) {if (step >= n * m) {// 已经遍历了所有的点,方案加1ans++;return ;}visited[x][y] = true;for (int[] d : directions) {int nx = x + d[0];int ny = y + d[1];if (nx < 0 || nx >= n || ny < 0 || ny >= m) {continue;}// 已经访问过这个点if (visited[nx][ny]) {continue;}// 标记访问visited[nx][ny] = true;dfs(n, m, nx, ny, visited, step + 1);// 回溯修改visited[nx][ny] = false;}}}

小结

广度优先搜索,通俗的理解就是,地毯式层层推进,从起始顶点开始,依次往外遍历,遍历得到的路径就是,起始顶点到终止顶点的最短路径。广度优先搜索需要借助队列来实现。深度优先搜索用的是回溯思想,非常适合用递归实现。二者是图上的两种最常用、最基本的搜索算法,比起其他高级的搜索算法,比如A*、IDA*等,要简单粗暴,没有什么优化,所以,也被叫作暴力搜索算法。所以,这两种搜索算法仅适用于状态空间不大,也就是说图不大的搜索。


http://chatgpt.dhexx.cn/article/5AgaTFw8.shtml

相关文章

广度优先搜索和深度优先搜索

文章目录 1. 前言2. 广度优先搜索和深度优先搜索1&#xff09;深度优先搜索2&#xff09;广度优先搜索 3. 深度优先搜索算法框架1&#xff09;二叉树深度优先搜索模板2&#xff09;图深度优先搜索模板3&#xff09;二维矩阵深度优先搜索模板 4. 广度优先搜索算法框架1&#xff…

深度优先和广度优先算法

1、深度优先算法 遍历规则&#xff1a;不断地沿着顶点的深度方向遍历。顶点的深度方向是指它的邻接点方向。 最后得出的结果为&#xff1a;ABDECFHG。 Python代码实现的伪代码如下&#xff1a; 2、广度优先算法&#xff1a; 遍历规则&#xff1a; 1&#xff09;先访问完当…

深度优先搜索(DFS)和广度优先搜索(BFS)

代码随想录 深度优先搜索和广度优先搜索&#xff0c;都是图形搜索算法&#xff0c;它两相似&#xff0c;又却不同&#xff0c;在应用上也被用到不同的地方。这里拿一起讨论&#xff0c;方便比较。 先给大家说一下两者大概的区别&#xff1a; 如果搜索是以接近起始状态的程序依次…

算法:深度优先和广度优先(DFS,BFS)

一丶深度优先&#xff08;DFS&#xff09; 深度优先顾名思义: 就是往深的地方优先查找或遍历。 如图二叉树&#xff0c;想遍历树中所有结点可以用中序遍历&#xff0c;前序或后序。如果某一结点还有子结点就会往深处就是往下一结点&#xff0c;一直遍历直到最后一个结点没有子…

【算法】深度优先和广度优先

本文只是总结的相关概念&#xff0c;仅供自己复习&#xff0c;严禁转载&#xff0c;文末附有本文内容涉及的文章链接&#xff0c;请点开链接查看原文&#xff01; &#xff08;一&#xff09;深度优先 深度优先搜索属于图算法的一种&#xff0c;是一个针对图和树的遍历算法&am…

算法:深度优先遍历和广度优先遍历

什么是深度、广度优先遍历 图的遍历是指&#xff0c;从给定图中任意指定的顶点&#xff08;称为初始点&#xff09;出发&#xff0c;按照某种搜索方法沿着图的边访问图中的所有顶点&#xff0c;使每个顶点仅被访问一次&#xff0c;这个过程称为图的遍历。遍历过程中得到的顶点…

ms17010利用失败解决一则

没有反弹得到session并且提示如下&#xff1a; [-] 10.0.131.2:445 - Service failed to start, ERROR_CODE: 216 换了一个payload set payload windows/meterpreter/reverse_tcp set payload windows/x64/meterpreter/bind_tcp 就可以了。 如果遇到Unable to continue with i…

永恒之蓝MS17010复现

MS17010复现 靶机win7&#xff1a;192.168.41.150 攻击kali: 192.168.41.147 扫描 通过auxiliary/scanner/smb/smb_ms17_010模块扫描虚拟机是否存在ms17010漏洞 存在 拿shell 通过exploit/windows/smb/ms17_010_eternalblue 直接exp打&#xff0c;设置好参数和payload,window…

MS17010(永恒之蓝)漏洞利用与复现

MS17010(永恒之蓝)漏洞利用与复现 0X00简介 永恒之蓝是指2017年4月14日晚&#xff0c;黑客团体Shadow Brokers&#xff08;影子经纪人&#xff09;公布一大批网络攻击工具&#xff0c;其中包含“永恒之蓝”工具&#xff0c;“永恒之蓝”利用Windows系统的SMB漏洞可以获取系统…

网安学习记录1 ms17010漏洞

使用nmap对win7进行端口扫描 进行ms17-010漏洞利用

ms17010漏洞复现-2003

先使用Smbtouch模块检测一下是否有漏洞。 然后使用Doublepulsar写一个shellcode到本地。 生成成功后的截图&#xff1a; 再使用EternalRomance植入Doublepulsar后门。 成功的截图&#xff1a; PS:仿佛是由于之前已经上传过bin的缘故&#xff0c;第二次测试的时候失败了。但是不…

微软永恒之蓝ms17010补丁下载-wannacry

勒索病毒爆发:上百国家遭"感染",Windows勒索病毒恐怖蔓延!勒索病毒,掀起了全球上百个国家、数十亿用户对网络安全的恐慌,微软推出的永恒之蓝ms17010补丁下载专为勒索病毒专杀而设计,同时推出的勒索病毒文件恢复软件是大家得力的勒索病毒文件恢复助手!http://www.cata…

永恒之蓝漏洞自查-MS17010漏洞自查与修复

MS17010漏洞时间线回溯 2017-03-12&#xff0c;微软发布MS17-010补丁包2017-03-14&#xff0c;微软发布《MS17-010&#xff1a;Windows SMB 服务器安全更新说明》 https://support.microsoft.com/zh-cn/help/4012598/title2017-04-14&#xff0c;Shadowbroker发布漏洞利用工具…

ms17010复现

关于漏洞的复现干多了就发现&#xff0c;这种菜鸟级别的复现&#xff0c;&#xff0c;真是没有啥实用性&#xff0c;主要就是&#xff0c;自己玩玩&#xff0c;&#xff0c;&#xff0c;唉&#xff0c;&#xff0c; ms17_010,好像跟什么永恒之蓝&#xff0c;勒索病毒有啥关系。…

ms17010漏洞利用(主机漏洞利用)

攻击机&#xff1a;kali ip:192.168.248.129 靶机&#xff1a;win7 x64 enterprise ip: 192.168.248.130 启动msf&#xff0c; Msfconsole search ms 检查msf库里是否存在ms17-010漏洞 Nmap检测靶机开放端口&#xff1a;nmap –sV 192.168.248.130 445端口开放&#xff0c…

永恒之蓝(MS17010)漏洞kali使用MSF进行漏洞复现

永恒之蓝是指2017年4月14日晚&#xff0c;黑客团体Shadow Brokers&#xff08;影子经纪人&#xff09;公布一大批网络攻击工具&#xff0c;其中包含“永恒之蓝”工具&#xff0c;“永恒之蓝”利用Windows系统的SMB漏洞可以获取系统最高权限。 恶意代码会扫描开放445文件共享端…

永恒之蓝-MS17010 CVE-2017-0146

提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、永恒之…

永恒之蓝(ms17010)漏洞利用

目录 1.启动msf 2.检查msf库里是否存在ms17-010漏洞 3.扫描靶机开放端口 4.配置目标ip&#xff0c;本地ip并利用exploit进行攻击 5.查看靶机系统信息、用户身份并对远程主机当前屏幕截图 6.获得shell控制台进cmd操作&#xff0c;添加账户提升权限 7.远程登录靶机 8.输入…

〖EXP〗NSA MS17010永恒之蓝漏洞一键工具

漏洞简介 永恒之蓝是指2017年4月14日晚,黑客团体Shadow Brokers(影子经纪人)公布一大批网络攻击工具,其中包含“永恒之蓝”工具,“永恒之蓝”利用Windows系统的SMB漏洞可以获取系统最高权限。5月12日,不法分子通过改造“永恒之蓝”制作了wannacry勒索病毒,英国、俄罗斯…

MS17010漏洞利用总结

0x01 常规打法 扫描是否存在ms17-010漏洞&#xff1a; nmap -n -p445 --script smb-vuln-ms17-010 192.168.1.0/24 --openMSF常规漏洞利用&#xff1a; msf > use exploit/windows/smb/ms17_010_eternalblue msf > set rhost 192.168.1.112 反向打&#xff1a; msf …