图标相似度筛选在渗透攻防中的应用:感知哈希算法与直方图对比分析

发布时间:2024-10-16 17:35:13 作者:Potato 阅读量:327

在网络安全的渗透攻防过程中,影子资产的收集与分析是信息搜集阶段的关键任务之一。影子资产包括未被公开标记或遗留在互联网上的服务器、网站等,它们常常成为攻击者的突破口。为了提高影子资产的识别效率,安全研究者往往会借助资产测绘平台进行大范围的搜索。但这些搜索结果中,常常包含大量不相关的资产,因此对这些资产进行精细筛选显得尤为重要。本文将结合图标相似度筛选,深入探讨两种常见算法——感知哈希算法(pHash)与直方图相似度算法的原理、应用。

1. 影子资产与图标相似度

在收集影子资产时,网站的图标(favicon)是一项常被利用的特征。通过图标的相似度判断,安全人员可以快速筛选出相关性较高的网站。例如,若目标网站的图标与某些搜索结果中的图标高度相似,可能表明这些资产隶属于同一组织。因此,图标相似度的计算成为了筛选资产中的重要一步。

通常在图标相似度的判断中有两种较为广泛的技术路径:

  • 基于算法的相似度计算:如感知哈希算法(Perceptual Hashing, pHash)或直方图匹配算法,它们直接通过图像本身的特征进行计算。
  • 基于深度学习的神经网络模型:这种方法可以通过大量训练数据构建神经网络来判断图像相似度,但其复杂度和计算资源需求较高,且对训练数据质量依赖较大。

本文聚焦于第一类方法,即纯算法的实现,具体分析感知哈希和直方图算法。

2. 感知哈希算法 (Perceptual Hashing, pHash)

感知哈希算法的核心思想是将图像进行处理,得到一个相对固定长度的“哈希值”,该哈希值可以用于快速对比两张图片的相似度。感知哈希算法不同于传统的加密哈希(如MD5或SHA-1),它不追求唯一性,而是为了保留图片的视觉信息,使得相似的图片会生成相似的哈希值。pHash 具体的步骤如下:

  1. 缩放图片:将图片缩放为固定大小(如32x32),以减少计算量,同时保留关键视觉信息。

  2. 灰度处理:将彩色图像转换为灰度图像,去除颜色对比的干扰。

  3. 离散余弦变换(DCT):对灰度图像进行DCT变换,提取频域信息。低频部分保留了图像的主要结构和特征,而高频部分往往与细节噪声相关。

  4. 生成哈希值:从DCT变换的结果中,取其低频部分的平均值,并将每个像素值与该均值比较,生成一个二进制字符串(哈希值)。

  5. 汉明距离判断相似度:对比两张图片的哈希值,计算汉明距离(即两个二进制字符串不同位的数量)。距离越小,图片的相似度越高。

以下是感知哈希算法的Java实现:

  1. package com.potato.potatotool.content.redTeam.infoGathering.imgSimilarity;
  2. import java.awt.Graphics2D;
  3. import java.awt.color.ColorSpace;
  4. import java.awt.image.BufferedImage;
  5. import java.awt.image.ColorConvertOp;
  6. import java.io.File;
  7. import java.io.FileInputStream;
  8. import java.io.InputStream;
  9. import java.net.URL;
  10. import javax.imageio.ImageIO;
  11. /**
  12. * @author Potato
  13. * @desc 图片感知哈希算法(pHash)通过计算图片的感知哈希值并比较哈希值之间的汉明距离来判断图片相似度
  14. */
  15. public class ImgPHsh {
  16. private int size = 32; // 默认DCT处理的图像大小为32x32
  17. private int smallerSize = 8; // 默认保留的DCT较低频部分为8x8
  18. private double[] c; // DCT系数数组
  19. private ColorConvertOp colorConvert = new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null);
  20. /**
  21. * 构造方法,初始化DCT系数
  22. */
  23. public ImgPHsh() {
  24. initCoefficients();
  25. }
  26. /**
  27. * 构造方法,允许自定义图像大小和保留的低频区域大小
  28. * @param size 图像大小
  29. * @param smallerSize 保留的低频区域大小
  30. */
  31. public ImgPHsh(int size, int smallerSize) {
  32. this.size = size;
  33. this.smallerSize = smallerSize;
  34. initCoefficients();
  35. }
  36. /**
  37. * 初始化DCT系数
  38. */
  39. private void initCoefficients() {
  40. c = new double[size];
  41. for (int i = 1; i < size; i++) {
  42. c[i] = 1;
  43. }
  44. c[0] = 1 / Math.sqrt(2.0);
  45. }
  46. /**
  47. * 计算汉明距离,用于比较两个图片的pHash值
  48. * @param s1 第一个哈希字符串
  49. * @param s2 第二个哈希字符串
  50. * @return 汉明距离(值越小,相似度越高)
  51. */
  52. private int calculateHammingDistance(String s1, String s2) {
  53. int distance = 0;
  54. for (int k = 0; k < s1.length(); k++) {
  55. if (s1.charAt(k) != s2.charAt(k)) {
  56. distance++;
  57. }
  58. }
  59. return distance;
  60. }
  61. /**
  62. * 生成图片的pHash值
  63. * @param is 输入图片流
  64. * @return 图片的pHash值(二进制字符串)
  65. * @throws Exception 处理图像时可能抛出的异常
  66. */
  67. private String getHash(InputStream is) throws Exception {
  68. BufferedImage img = ImageIO.read(is);
  69. // 步骤1:调整图像尺寸为size x size(默认为32x32)
  70. img = resize(img, size, size);
  71. // 步骤2:将图像转为灰度图
  72. img = grayscale(img);
  73. // 步骤3:获取图像的DCT值
  74. double[][] dctValues = calculateDCT(img);
  75. // 步骤4:仅保留左上角的8x8低频DCT值
  76. // 步骤5:计算均值(排除[0,0]元素)
  77. double avg = calculateDCTAverage(dctValues);
  78. // 步骤6:生成二进制哈希字符串
  79. return generateHash(dctValues, avg);
  80. }
  81. private String getHash(byte[] imageBytes) throws Exception {
  82. InputStream is = new ByteArrayInputStream(imageBytes);
  83. BufferedImage img = ImageIO.read(is);
  84. img = resize(img, size, size);
  85. img = grayscale(img);
  86. double[][] dctValues = calculateDCT(img);
  87. double avg = calculateDCTAverage(dctValues);
  88. return generateHash(dctValues, avg);
  89. }
  90. /**
  91. * 调整图片尺寸
  92. * @param image 原图像
  93. * @param width 目标宽度
  94. * @param height 目标高度
  95. * @return 调整后的图像
  96. */
  97. private BufferedImage resize(BufferedImage image, int width, int height) {
  98. BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
  99. Graphics2D g = resizedImage.createGraphics();
  100. g.drawImage(image, 0, 0, width, height, null);
  101. g.dispose();
  102. return resizedImage;
  103. }
  104. /**
  105. * 将图像转为灰度图
  106. * @param img 原图像
  107. * @return 灰度图像
  108. */
  109. private BufferedImage grayscale(BufferedImage img) {
  110. colorConvert.filter(img, img);
  111. return img;
  112. }
  113. /**
  114. * 计算DCT转换后的值
  115. * @param img 灰度图像
  116. * @return DCT值矩阵
  117. */
  118. private double[][] calculateDCT(BufferedImage img) {
  119. double[][] pixelValues = new double[size][size];
  120. // 获取图像像素值
  121. for (int x = 0; x < img.getWidth(); x++) {
  122. for (int y = 0; y < img.getHeight(); y++) {
  123. pixelValues[x][y] = getBlue(img, x, y);
  124. }
  125. }
  126. // 应用DCT转换
  127. return applyDCT(pixelValues);
  128. }
  129. /**
  130. * 获取图像中某像素点的蓝色值(灰度图中只有蓝色通道有值)
  131. * @param img 图像
  132. * @param x 像素点x坐标
  133. * @param y 像素点y坐标
  134. * @return 该像素点的蓝色值
  135. */
  136. private static int getBlue(BufferedImage img, int x, int y) {
  137. return img.getRGB(x, y) & 0xff;
  138. }
  139. /**
  140. * 计算DCT的平均值,排除[0,0]位置
  141. * @param dctValues DCT值矩阵
  142. * @return 平均值
  143. */
  144. private double calculateDCTAverage(double[][] dctValues) {
  145. double total = 0;
  146. for (int x = 0; x < smallerSize; x++) {
  147. for (int y = 0; y < smallerSize; y++) {
  148. total += dctValues[x][y];
  149. }
  150. }
  151. total -= dctValues[0][0]; // 排除DC分量
  152. return total / ((smallerSize * smallerSize) - 1);
  153. }
  154. /**
  155. * 生成pHash值(二进制字符串)
  156. * @param dctValues DCT值矩阵
  157. * @param avg DCT均值
  158. * @return 二进制哈希字符串
  159. */
  160. private String generateHash(double[][] dctValues, double avg) {
  161. StringBuilder hash = new StringBuilder();
  162. for (int x = 0; x < smallerSize; x++) {
  163. for (int y = 0; y < smallerSize; y++) {
  164. if (x != 0 || y != 0) {
  165. hash.append(dctValues[x][y] > avg ? "1" : "0");
  166. }
  167. }
  168. }
  169. return hash.toString();
  170. }
  171. /**
  172. * 计算两个图片之间的相似度(0到1.0)
  173. * @param srcFile 源图像文件
  174. * @param canFile 候选图像文件
  175. * @return 相似度(0到1.0)
  176. * @throws Exception 处理图像时可能抛出的异常
  177. */
  178. public double match(File srcFile, File canFile) throws Exception {
  179. String srcHash = getHash(new FileInputStream(srcFile));
  180. String canHash = getHash(new FileInputStream(canFile));
  181. int hammingDistance = calculateHammingDistance(srcHash, canHash);
  182. return 1.0 - (double) hammingDistance / (smallerSize * smallerSize - 1);
  183. }
  184. /**
  185. * 计算两个图片之间的相似度(0到1.0)
  186. * @param srcUrl 源图像URL
  187. * @param canUrl 候选图像URL
  188. * @return 相似度(0到1.0)
  189. * @throws Exception 处理图像时可能抛出的异常
  190. */
  191. public double match(URL srcUrl, URL canUrl) throws Exception {
  192. String srcHash = getHash(srcUrl.openStream());
  193. String canHash = getHash(canUrl.openStream());
  194. int hammingDistance = calculateHammingDistance(srcHash, canHash);
  195. return 1.0 - (double) hammingDistance / (smallerSize * smallerSize - 1);
  196. }
  197. /**
  198. * 计算两个图片之间的相似度(0到1.0)
  199. * @param srcImg 源图像byte[]
  200. * @param canImg 候选图像byte[]
  201. * @return 相似度(0到1.0)
  202. * @throws Exception 处理图像时可能抛出的异常
  203. */
  204. public double match(byte[] srcImg, byte[] canImg) throws Exception {
  205. String srcHash = getHash(srcImg);
  206. String canHash = getHash(canImg);
  207. int hammingDistance = calculateHammingDistance(srcHash, canHash);
  208. return 1.0 - (double) hammingDistance / (smallerSize * smallerSize - 1);
  209. }
  210. public int calculateImageDistance(byte[] srcImg, byte[] canImg) throws Exception {
  211. String srcHash = getHash(srcImg);
  212. String canHash = getHash(canImg);
  213. return calculateHammingDistance(srcHash, canHash);
  214. }
  215. /**
  216. * 离散余弦变换(DCT)算法
  217. * @param pixelValues 图像像素值矩阵
  218. * @return DCT值矩阵
  219. */
  220. private double[][] applyDCT(double[][] pixelValues) {
  221. int N = size;
  222. double[][] DCT = new double[N][N];
  223. for (int u = 0; u < N; u++) {
  224. for (int v = 0; v < N; v++) {
  225. double sum = 0.0;
  226. for (int i = 0; i < N; i++) {
  227. for (int j = 0; j < N; j++) {
  228. sum += Math.cos(((2 * i + 1) / (2.0 * N)) * u * Math.PI) *
  229. Math.cos(((2 * j + 1) / (2.0 * N)) * v * Math.PI) *
  230. pixelValues[i][j];
  231. }
  232. }
  233. sum *= ((c[u] * c[v]) / 4.0);
  234. DCT[u][v] = sum;
  235. }
  236. }
  237. return DCT;
  238. }
  239. }

  1. javaImageIO类默认无法解析ico类型文件(还有部分其他类型、以及经过加工过的图片),需要使用三方库为ImageIO提供支持,
  2. 例如,mvn项目为ImageIO支持icopom.xml中添加:
  3. <dependency>
  4. <groupId>com.twelvemonkeys.imageio</groupId>
  5. <artifactId>imageio-ico</artifactId>
  6. <version>3.0.2</version>
  7. </dependency>

pHash 在对图片进行相似度判断时具有以下优点:

  • 高效:生成和比较哈希值的过程非常快速,适合大量图片的快速筛选。
  • 鲁棒性:pHash 对图片的缩放、旋转等轻微变动具有较强的抗干扰能力。
  • 简洁性:相比于复杂的神经网络,pHash 算法易于理解和实现。

    3. 直方图相似度算法

    另一种常用的图片相似度计算方法是基于图像直方图的比较。图像的直方图是一个表示不同灰度级或颜色值的像素分布的图像统计信息。其基本思想是,若两幅图片的直方图分布相似,则图片内容也很可能相似。

直方图算法的主要步骤如下:

  1. 将图片分为颜色通道:通常将图片拆分为RGB三个通道,分别计算各通道的像素分布。

  2. 计算直方图:统计每个通道中每种颜色值的像素数,生成直方图。

  3. 归一化:为了使不同大小的图片可以进行对比,通常需要对直方图进行归一化处理。

  4. 比较直方图:使用欧氏距离或巴氏距离等方式,计算两张图片直方图之间的差异。距离越小,图片的相似度越高。

下面是一个直方图相似度计算的示例代码:

  1. package com.potato.potatotool.content.redTeam.infoGathering.imgSimilarity;
  2. import java.awt.image.BufferedImage;
  3. import java.io.File;
  4. import java.io.IOException;
  5. import java.net.URL;
  6. import javax.imageio.ImageIO;
  7. /**
  8. * @author Potato
  9. * @desc 该类用于计算和比较图像的直方图相似度(使用巴氏系数)
  10. */
  11. public class ImgHistogram {
  12. // 颜色最大值255,用于归一化计算
  13. private static final int COLOR_MAX_VALUE = 255;
  14. // 红、绿、蓝通道的bin数量
  15. private int redBins;
  16. private int greenBins;
  17. private int blueBins;
  18. // 默认构造函数,初始化bin数量为4
  19. public ImgHistogram() {
  20. this(4, 4, 4); // 默认使用4个bin
  21. }
  22. // 可以自定义红、绿、蓝bin数量的构造函数
  23. public ImgHistogram(int redBins, int greenBins, int blueBins) {
  24. this.redBins = redBins;
  25. this.greenBins = greenBins;
  26. this.blueBins = blueBins;
  27. }
  28. /**
  29. * 计算图像的直方图数据
  30. * @param image 输入的BufferedImage对象
  31. * @return 归一化的直方图数据
  32. */
  33. private float[] calculateHistogram(BufferedImage image) {
  34. int width = image.getWidth();
  35. int height = image.getHeight();
  36. int[] pixels = new int[width * height];
  37. float[] histogramData = new float[redBins * greenBins * blueBins];
  38. // 获取图像的RGB像素数据
  39. getRGB(image, 0, 0, width, height, pixels);
  40. float totalPixels = 0;
  41. // 遍历图像中的每个像素,计算直方图
  42. for (int row = 0; row < height; row++) {
  43. for (int col = 0; col < width; col++) {
  44. int index = row * width + col;
  45. int red = (pixels[index] >> 16) & 0xff; // 提取红色分量
  46. int green = (pixels[index] >> 8) & 0xff; // 提取绿色分量
  47. int blue = pixels[index] & 0xff; // 提取蓝色分量
  48. // 计算每个分量所在的bin索引
  49. int redIdx = getBinIndex(redBins, red);
  50. int greenIdx = getBinIndex(greenBins, green);
  51. int blueIdx = getBinIndex(blueBins, blue);
  52. // 计算该像素在直方图数组中的位置
  53. int histogramIndex = redIdx + greenIdx * redBins + blueIdx * redBins * greenBins;
  54. histogramData[histogramIndex] += 1;
  55. totalPixels += 1;
  56. }
  57. }
  58. // 将直方图数据归一化
  59. for (int i = 0; i < histogramData.length; i++) {
  60. histogramData[i] /= totalPixels;
  61. }
  62. return histogramData;
  63. }
  64. /**
  65. * 将颜色值映射到相应的bin上
  66. * @param binCount bin的数量
  67. * @param color 当前的颜色值
  68. * @return 颜色所在的bin索引
  69. */
  70. private int getBinIndex(int binCount, int color) {
  71. int binIndex = (color * binCount) / COLOR_MAX_VALUE;
  72. return binIndex >= binCount ? binCount - 1 : binIndex;
  73. }
  74. /**
  75. * 获取图像的RGB值数组
  76. * @param image 输入的BufferedImage对象
  77. * @param x 开始的x坐标
  78. * @param y 开始的y坐标
  79. * @param width 宽度
  80. * @param height 高度
  81. * @param pixels 用于存储RGB值的像素数组
  82. * @return 填充了RGB值的像素数组
  83. */
  84. private int[] getRGB(BufferedImage image, int x, int y, int width, int height, int[] pixels) {
  85. int type = image.getType();
  86. if (type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB) {
  87. return (int[]) image.getRaster().getDataElements(x, y, width, height, pixels);
  88. }
  89. return image.getRGB(x, y, width, height, pixels, 0, width);
  90. }
  91. /**
  92. * 计算两张图片直方图的巴氏系数(Bhattacharyya Coefficient)
  93. * @param histogram1 图像1的直方图
  94. * @param histogram2 图像2的直方图
  95. * @return 返回巴氏系数,0到1之间,1表示完全相同
  96. */
  97. private double calculateSimilarity(float[] histogram1, float[] histogram2) {
  98. double similarity = 0;
  99. for (int i = 0; i < histogram1.length; i++) {
  100. similarity += Math.sqrt(histogram1[i] * histogram2[i]);
  101. }
  102. return similarity;
  103. }
  104. /**
  105. * 比较两张图片文件的相似度
  106. * @param srcFile 源图片文件
  107. * @param canFile 候选图片文件
  108. * @return 两张图片的相似度
  109. * @throws IOException 文件读取异常
  110. */
  111. public double match(File srcFile, File canFile) throws IOException {
  112. BufferedImage srcImage = ImageIO.read(srcFile);
  113. BufferedImage canImage = ImageIO.read(canFile);
  114. return match(srcImage, canImage);
  115. }
  116. /**
  117. * 比较两张图片的相似度(通过URL读取)
  118. * @param srcUrl 源图片URL
  119. * @param canUrl 候选图片URL
  120. * @return 两张图片的相似度
  121. * @throws IOException URL读取异常
  122. */
  123. public double match(URL srcUrl, URL canUrl) throws IOException {
  124. BufferedImage srcImage = ImageIO.read(srcUrl);
  125. BufferedImage canImage = ImageIO.read(canUrl);
  126. return match(srcImage, canImage);
  127. }
  128. /**
  129. * 比较两张图片的相似度(通过byte[])
  130. * @param srcBytes 源图片的字节数组
  131. * @param canBytes 候选图片的字节数组
  132. * @return 两张图片的相似度
  133. * @throws IOException 字节数组读取异常
  134. */
  135. public double match(byte[] srcBytes, byte[] canBytes) throws IOException {
  136. BufferedImage srcImage = ImageIO.read(new ByteArrayInputStream(srcBytes));
  137. BufferedImage canImage = ImageIO.read(new ByteArrayInputStream(canBytes));
  138. return match(srcImage, canImage);
  139. }
  140. /**
  141. * 比较两张BufferedImage图像的相似度
  142. * @param srcImage 源图片
  143. * @param canImage 候选图片
  144. * @return 两张图片的相似度
  145. * @throws IOException 如果图像为空,抛出异常
  146. */
  147. private double match(BufferedImage srcImage, BufferedImage canImage) throws IOException {
  148. if (srcImage == null || canImage == null) {
  149. throw new IllegalArgumentException("Source or candidate image cannot be null.");
  150. }
  151. float[] srcHistogram = calculateHistogram(srcImage);
  152. float[] canHistogram = calculateHistogram(canImage);
  153. return calculateSimilarity(srcHistogram, canHistogram);
  154. }
  155. }

直方图算法的优点在于:

  • 简单高效:不需要复杂的数学运算或数据转换,直接计算像素分布。
  • 易于扩展:可以应用于不同颜色空间的图像,例如RGB、HSV等。
    但是,直方图相似度也有一些局限性:

  • 敏感性:对图片的亮度、对比度变化较为敏感,容易受到颜色变化的影响。

  • 局部信息不足:直方图仅统计了颜色的总体分布信息,而忽略了图像中的空间结构。因此,某些图片在颜色分布上相似,但内容完全不同。

4. 感知哈希与直方图算法的对比

在图标相似度的计算中,感知哈希算法和直方图算法各有优势和劣势,具体选择取决于场景需求。

比较维度 感知哈希算法(pHash) 直方图算法
计算复杂度 较高,需进行DCT变换 低,直接计算像素分布
抗干扰能力 较强,能抵抗缩放、旋转等轻微变动 较弱,易受亮度、对比度变化影响
局部信息保留 良好,保留了图像的主要结构信息 差,忽略了图像的空间结构
实现难度 较高,需进行较复杂的图像处理 简单,基于基本的像素统计
适用场景 更适合判断内容相似的图标 适用于颜色分布相近的图片

两种方法结合在一起使用,提高准确率

5. 基于AI的相关性判断

除了使用图标相似度来筛选影子资产,还可以借助AI技术进一步分析网站内容,判断其与目标资产的相关性。这通常包括以下几个步骤:

  • 数据提取:提取网站的标题(title)、域名(domain)及页面内容的开头部分(body_start),这些信息通常能够有效反映网站的主题和用途。

  • AI模型训练:通过大规模训练数据,构建用于分析文本内容的机器学习模型,如自然语言处理(NLP)模型。这些模型能够识别网页内容的主题、关键词,并判断其与目标资产的相关性。

  • 相关性判断:使用训练好的模型,对目标网站和影子资产的网站内容进行对比,分析它们的主题相似度。如果内容相关性高,则可以认为该资产与目标有较大关联。

这种基于AI的分析能够极大提高筛选的准确性,尤其是在应对大量资产时,可以减少人工筛查的工作量。AI的加入使得渗透攻防中的自动化水平进一步提高,有助于更快、更精准地发现潜在的攻击入口。

  1. package com.potato.potatotool.content.redTeam.infoGathering.imgSimilarity;
  2. import com.potato.potatotool.content.redTeam.infoGathering.Utils;
  3. import java.io.File;
  4. import java.io.IOException;
  5. import java.net.URL;
  6. import java.util.Base64;
  7. import java.util.Map;
  8. /**
  9. * @author Potato
  10. * @desc 该类用于结合 ImgPHsh 和 ImgHistogram 两种方法,提高图片相似度判断的准确率
  11. */
  12. public class ImgSimilarity {
  13. private ImgHistogram imgHistogram;
  14. private ImgPHsh imgPHsh;
  15. // 权重设置,用于综合两种相似度
  16. private double histogramWeight = 0.5; // 直方图相似度的权重
  17. private double phashWeight = 0.5; // pHash相似度的权重
  18. private double histogramThreshold = 0.8; // 直方图相似度的阈值
  19. private double phashThreshold = 0.8; // pHash相似度的阈值
  20. // 默认构造函数,初始化直方图和pHash
  21. public ImgSimilarity() {
  22. this.imgHistogram = new ImgHistogram();
  23. this.imgPHsh = new ImgPHsh();
  24. }
  25. // 可以自定义权重的构造函数
  26. public ImgSimilarity(double histogramWeight, double phashWeight) {
  27. this();
  28. this.histogramWeight = histogramWeight;
  29. this.phashWeight = phashWeight;
  30. }
  31. /**
  32. * 比较两张图片的相似度,结合直方图和pHash
  33. * @param srcFile 源图片文件
  34. * @param canFile 候选图片文件
  35. * @return 综合的相似度
  36. * @throws IOException 如果文件读取异常
  37. */
  38. public double match(URL srcFile, URL canFile) throws Exception {
  39. // 获取直方图相似度
  40. double histogramSimilarity = imgHistogram.match(srcFile, canFile);
  41. // 获取pHash相似度
  42. double pHshSimilarity = imgPHsh.match(srcFile, canFile);
  43. // 综合相似度
  44. return histogramWeight * histogramSimilarity + phashWeight * pHshSimilarity;
  45. }
  46. public double match(File srcFile, File canFile) throws Exception {
  47. // 获取直方图相似度
  48. double histogramSimilarity = imgHistogram.match(srcFile, canFile);
  49. // 获取pHash相似度
  50. double pHshSimilarity = imgPHsh.match(srcFile, canFile);
  51. // 综合相似度
  52. return histogramWeight * histogramSimilarity + phashWeight * pHshSimilarity;
  53. }
  54. public double match(byte[] srcFile, byte[] canFile) throws Exception {
  55. // 获取直方图相似度
  56. double histogramSimilarity = imgHistogram.match(srcFile, canFile);
  57. // 获取pHash相似度
  58. double pHshSimilarity = imgPHsh.match(srcFile, canFile);
  59. // 综合相似度
  60. return histogramWeight * histogramSimilarity + phashWeight * pHshSimilarity;
  61. }
  62. // 根据阈值判断是否相似
  63. public boolean matchSimilar(byte[] srcFile, byte[] canFile) throws Exception {
  64. // 获取直方图相似度
  65. double histogramSimilarity = imgHistogram.match(srcFile, canFile);
  66. // 获取pHash相似度
  67. double pHshSimilarity = imgPHsh.match(srcFile, canFile);
  68. return (histogramSimilarity > histogramThreshold || pHshSimilarity > phashThreshold);
  69. }
  70. // 设置直方图相似度的权重
  71. public void setHistogramWeight(double histogramWeight) {
  72. this.histogramWeight = histogramWeight;
  73. }
  74. // 设置pHash相似度的权重
  75. public void setPhashWeight(double phashWeight) {
  76. this.phashWeight = phashWeight;
  77. }
  78. public static void main(String[] args) throws Exception {
  79. Map<String, String> webInfoMap = Utils.getWebInfo("https://211.160.72.129");
  80. System.out.println(webInfoMap);
  81. byte[] srcFile = Base64.getDecoder().decode(webInfoMap.get("iconBase64"));
  82. Map<String, String> webInfoMap1 = Utils.getWebInfo("https://43.143.141.199:8443");
  83. System.out.println(webInfoMap1);
  84. byte[] canFile = Base64.getDecoder().decode(webInfoMap1.get("iconBase64"));
  85. boolean similarity = new ImgSimilarity().matchSimilar(srcFile, canFile);
  86. System.out.println("是否相似: " + similarity);
  87. double similarity1 = new ImgSimilarity().match(new URL("https://t8.baidu.com/it/u=3036650915,1842869833&fm=193"), new URL("https://t9.baidu.com/it/u=140484125,2114791292&fm=193"));
  88. System.out.println("综合相似度: " + similarity1);
  89. }
  90. }

6. 结语

在渗透攻防中,影子资产的筛选对提高攻击效率至关重要。图标相似度筛选是快速筛选潜在目标的有效手段,而感知哈希算法和直方图算法各具特点,适用于不同场景,可以两种方法结合在一起使用,提高准确率。结合AI技术进行内容相关性判断,可以进一步提高筛选精度,为渗透测试人员提供更多准确的目标。

支付宝打赏 微信打赏

我要评论

Catfish(鲶鱼) Blog V 4.7.3