有时再图形界面的linux去fuzz GUI程序,GUI程序会阻挡我们的操作,这里将GUI程序放到虚拟显示设备显示,那再好不过了
1 | sudo apt-get install xvfb |
在Linux系统中,X服务器通过显示端口号来区分不同的显示屏,通常使用:0作为默认的物理显示端口,而虚拟显示端口从:1开始。所以虚拟显示端口起码得从1开始,1024x768x16 是分辨率,16是颜色的位数(8是256色,16是增强色,32位是真彩色)
而-screen应该是虚拟屏幕的编号
1 | Xvfb :1 -screen 0 1024x768x16 |
1 |
|
1 |
|
启动服务器,绑定的是编号是1的
1 | x11vnc -display :1 |
这个默认是screen 0,所以上面两个等价,假如是screen 1
1 | x11vnc -display :1.1 |
让程序再screen 1上显示,设置一下DISPLAY环境变量即可
1 | export DISPLAY=:1.1 |
之后即可通过vnc客户端连接5900端口即可
当然共享当前物理显示也行,就是编号是0
1 | x11vnc -display :0 |
当然最好设置密码
先生成密码文件
1 | fuzzplat@fuzzplat:~$ x11vnc -storepasswd |
你可以cat一下这个文件,是加密的,之后启动的时候通过-rfbauth指定密码文件路径
1 | x11vnc -display :2 -rfbauth /home/fuzzplat/.vnc/passwd |
再访问呢就要输入密码了
或者不太安全的是再命令行指定密码,下面的密码是test,推荐使用上面的
1 | x11vnc -display :1 -passwd test |
根据官网,Wazuh是一个免费的开源安全平台,它统一了XDR和SIEM的功能。它可以保护本地、虚拟化、容器化和基于云的环境中的工作负载。
Wazuh由多种开源项目组成,可以替代商业的XDR和SIEM解决方案。它可以保护从传统数据中心到公有云在内的多种环境。
Wazuh解决方案由一个通用代理和三个核心组件组成:Wazuh服务器,Wazuh索引器和Wazuh控制面板。
Wazuh解决方案基于部署在监控端点上的Wazuh代理,以及三个核心组件:Wazuh服务器、Wazuh索引器和Wazuh控制面板。
下图表示 Wazuh 组件和数据流。
Wazuh基于在被监控端点上运行的代理,这些代理将安全数据转发到中央服务器。无代理设备如防火墙、交换机、路由器和接入点也受支持,可以通过Syslog、SSH或使用其API主动提交日志数据。中央服务器解码和分析传入的信息,并将结果传递给Wazuh索引器进行索引和存储。
Wazuh索引器集群是一组一个或多个节点的集合,这些节点相互通信以对索引执行读写操作。不需要处理大量数据的小型Wazuh部署可以轻松地由单节点集群处理。当有许多监控端点时,当预计有大量的数据量时,或者当需要高可用性时,建议使用多节点集群。
对于生产环境,建议将Wazuh服务器和Wazuh索引器部署到不同的主机上。在这种场景中,Filebeat使用TLS加密通过安全地转发Wazuh警报和存档事件到Wazuh索引器集群(单节点或多节点)。
下图是Wazuh部署架构。它显示了解决方案的组件以及如何将Wazuh服务器和Wazuh索引器节点配置为集群,从而提供负载平衡和高可用性。
Wazuh代理持续地将事件发送到Wazuh服务器进行分析和威胁检测。为开始传输这些数据,代理与服务器上的代理连接服务建立连接,默认监听在1514端口上(这可以配置)。然后Wazuh服务器使用分析引擎解码并用规则检查接收到的事件。触发规则的事件会被添加警报数据,如规则ID和规则名称。事件可以根据是否触发了规则被缓存到下列一个或两个文件中:
/var/ossec/logs/archives/archives.json包含所有事件,无论是否触发了规则。
/var/ossec/logs/alerts/alerts.json仅包含优先级足够高的触发了规则的事件(阈值可以配置)。
Wazuh消息协议默认使用128 bits per block 和256-bit keys.的AES加密。也可选用Blowfish加密。
Wazuh服务器使用Filebeat通过TLS加密将警报和事件数据发送到Wazuh索引器。Filebeat读取Wazuh服务器的输出数据并将其发送到Wazuh索引器(默认监听在9200/TCP端口)。一旦数据被Wazuh索引器索引,Wazuh控制面板用于挖掘和可视化信息。
Wazuh控制面板查询Wazuh RESTful API(默认在Wazuh服务器的55000/TCP端口上监听)来显示Wazuh服务器和代理的配置和状态相关信息。它还可以通过API调用修改代理或服务器配置设置。此通信使用TLS加密,并使用用户名和密码进行认证。
警报和非警报事件除了被发送到Wazuh索引器,也存储在Wazuh服务器上的文件中。这些文件可以以JSON格式(.json)或纯文本格式(.log)编写。这些文件使用MD5、SHA1和SHA256校验和每天压缩和签名。目录和文件名结构如下:
1 | root@wazuh-manager:/var/ossec/logs/archives/2022/Jan# ls -l |
根据Wazuh服务器的存储容量,建议轮换和备份存档文件。通过使用cron作业,您可以轻松管理仅在服务器上本地保留存档文件的特定时间窗口,例如过去一年或过去三个月。(应该是通过cron定期删除过去一年或者过去三个月的文件)
也可以选择不存储存档文件,而只需依靠 Wazuh 索引器进行存档存储。
如果您定期运行Wazuh索引器快照备份和/或拥有用于高可用性的分片副本的多节点Wazuh索引器集群,则此替代方案可能更可取。
您甚至可以使用cron作业将快照索引移动到最终的数据存储服务器并使用MD5、SHA1和SHA256哈希算法对其进行签名。
注:下面以Ubuntu 20.04为例
下载并运行 Wazuh 安装助手
1 | curl -sO https://packages.wazuh.com/4.6/wazuh-install.sh && sudo bash ./wazuh-install.sh -a |
注意:假如不能连接GitHub,可以将https://raw.githubusercontent.com/wazuh/wazuh/${source_branch}/extensions/elasticsearch/7.x/wazuh-template.json
提前下载到自己服务器,再修改脚本的地址
下面表示安装成功
1 | INFO: --- Summary --- |
可以在wazuh-install-files.tar中的wazuh-passwords.txt文件中找到所有Wazuh索引器和Wazuh API用户的密码。要打印它们,请运行以下命令:
1 | sudo tar -O -xvf wazuh-install-files.tar wazuh-install-files/wazuh-passwords.txt |
安装了服务端登录,点击添加agent,就会给出命令
1 | wget https://packages.wazuh.com/4.x/apt/pool/main/w/wazuh-agent/wazuh-agent_4.6.0-1_amd64.deb && sudo WAZUH_MANAGER='192.168.X.X' dpkg -i ./wazuh-agent_4.6.0-1_amd64.deb |
启动agent服务
1 | sudo systemctl daemon-reload |
powershell管理员运行
1 | Invoke-WebRequest -Uri https://packages.wazuh.com/4.x/windows/wazuh-agent-4.6.0-1.msi -OutFile ${env.tmp}\wazuh-agent; msiexec.exe /i ${env.tmp}\wazuh-agent /q WAZUH_MANAGER='192.168.X.X' WAZUH_AGENT_NAME='FuzzManager' WAZUH_REGISTRATION_SERVER='192.168.X.X' |
对于OSSEC,印象就是HIDS,官方说是将 HIDS、日志监控和安全事件管理 (SIM)/安全信息和事件管理 (SIEM)融合在一起。
OSSEC主要功能
manager/Server 是 OSSEC 的核心部分,它存储了文件完整性检查数据库、日志、事件和系统审计相关的内容。所有规则、解码器和主要配置选项都集中存储在管理器中;这样即使大量agent也容易管理。
agent通过1514/udp 连接到服务器
Agent
agent是安装在要监控的系统上的一个小程序或程序集合。它将收集信息并将其转发给管理器进行分析和关联。一些信息是实时收集的,其他的是周期性的。默认情况下,它占用很小的内存和CPU,不会影响系统的使用。
安全性: 它以低权限用户(通常在安装期间创建)运行,并在与系统隔离的chroot中运行。大多数代理配置可以从管理器推送。
Agentless
对于无法安装代理的系统,无代理支持可允许执行完整性检查。无代理扫描可用于监控防火墙、路由器,甚至Unix系统。
猜测: 这应该通过ssh协议或者其他远程协议执行的检查
Virtualization/VMware
可以装在guest操作系统中,甚至可以 VMWare ESX(不一定支持所有版本)
在 VMware ESX 中安装代理后,您可以收到有关何时安装、移除、启动 VM Guest 等的警报。它还监视 ESX 服务器内部的登录、注销和错误。
此外,OSSEC还会对VMware执行互联网安全中心(CIS)检查,在启用任何不安全的配置选项或任何其他问题时发出警报。
防火墙、交换机和路由器
OSSEC可以从各种防火墙、交换机和路由器接收和分析syslog事件。它支持所有思科路由器、思科PIX、思科FWSM、思科ASA、Juniper路由器、Netscreen防火墙、Checkpoint等等。
下面这个图显示了中央管理器从代理和远程设备的系统日志接收事件。当检测到某些内容时,可以执行主动响应并通知管理员。
支持的系统很多
操作系统
1 | GNU/Linux (all distributions, including RHEL, Ubuntu, Slackware, Debian, etc) |
支持Syslog的设备
下面可以通过remote syslog支持:
1 | Cisco PIX, ASA and FWSM (all versions) |
agentless
使用OSSEC的无代理选项,也支持以下系统(用于日志分析和文件完整性检查):
1 | Cisco PIX, ASA and FWSM (all versions) |
以Ubuntu 20.04为例
先安装依赖项
1 | apt-get update && apt-get install build-essential make zlib1g-dev libpcre2-dev libevent-dev libssl-dev libsystemd-dev |
如果需要数据库支持,则应安装 mysql-dev 或 postgresql-dev
1 | apt-get install mysql-dev postgresql-dev |
要使用 SQLite 功能,libsqlite3-dev 包是必需的。
1 | apt-get install libsqlite3-dev |
安装的话是有deb包的源的
1 | wget -q -O - https://updates.atomicorp.com/installers/atomic | sudo bash |
下面尝试下载源码安装
1 | wget https://github.com/ossec/ossec-hids/archive/3.7.0.tar.gz |
这有两种安装,一种是执行./install.sh
,或者输入下面命令
1 | make TARGET=<server|local|agent> |
当然./install.sh可以配置一些信息,比较好,选择./install.sh
之后按需配置即可
最后显示这个就安装完了
1 | - 系统类型是 Debian (Ubuntu or derivative). |
启动服务/var/ossec/bin/ossec-control start
1 | # /var/ossec/bin/ossec-control start |
可以看到有6个模块
其实/var/ossec/etc/ossec.conf 也可以事后再配置的
检测规则在/var/ossec/rules下面,基本都是正则匹配
1 | root@ubuntu2004:/var/ossec/rules# ls |
解码器在/var/ossec/etc/decoder.xml
以下面为例,
<order>
元素定义了解码器中提取的字段的顺序。提取的是表达式中()
中的内容;而<fts>
元素用于定义全文搜索(Full Text Search)索引。它指定了要在日志事件中进行全文搜索的字段。在示例中,<fts>name, user, location</fts>
指定了三个字段的全文搜索索引,即”name”、”user”和”location”。通过创建全文搜索索引,可以提高对这些字段的搜索效率,并支持更复杂的日志分析和报警规则。1 | <decoder name="sshd"> |
新建用户测试
1 | root@ubuntu2004:~# useradd ossec_test |
这会在/var/log/auth.log
中留下记录
1 | root@ubuntu2004:~# tail /var/log/auth.log -n 2 |
可以看到配置文件默认已经有该文件的监控了
1 | <localfile> |
检测规则也有了,在syslog_rules.xml中
1 | <!-- Adduser messages --> |
配置文件也包含了这个规则文件syslog_rules.xml
1 | <rules> |
假如假装这是我们添加的规则,就用/var/ossec/bin/ossec-logtest
来测试,输入log内容即可
1 | root@ubuntu2004:/var/ossec/etc# /var/ossec/bin/ossec-logtest |
第一阶段预解码,之后由于这个无需再对后面的信息再解码了,第二阶段没有解码器,第三阶段就通过规则过滤告警了
/var/ossec/logs/alerts/alerts.log
中是出现了下面告警log
1 |
|
server的主机,安装的时候选server,之后开启远程机器syslog
1 | 3.5- 您希望接收远程机器syslog吗 (port 514 udp)? (y/n) [y]: |
之后server执行/var/ossec/bin/manage_agents
1 | 1. (A)dd an agent (A). |
重启服务
1 | /var/ossec/bin/ossec-control restart |
agent端,安装的时候选agent,之后执行/var/ossec/bin/manage_agents
选择(I)mport key from the server (I).
,之后复制上面得到的key即可
重启服务
1 | /var/ossec/bin/ossec-control restart |
搞个ossec-wui也能看到新的agent
https://www.ossec.net/docs/
《企业安全建设入门》
在某些情况下,可以通过更改请求的 Header 并包含内部地址来访问页面和私有文件,以下是一些示例;
1 | X-ProxyUser-Ip: 127.0.0.1 |
尝试对 url 进行一些更改,使用特殊字符或包括 HTML 编码,例如:
1 | test.com/admin/* |
下面是phpmyadmin 的绕过,限制了特定ip对/phpmyadmin/ 的访问,下面都不行
1 | /phpmyadmin/* |
下面3个斜杠就行
1 | ///phpmyadmin/// |
这是使用 2 个斜杠访问wordpress的登录后台
有人已经开发了攻击,帮助识别并绕过403
https://github.com/iamj0ker/bypass-403
Burpsuite Professional的插件
https://portswigger.net/bappstore/444407b96d9c4de0adb7aed89e826122
查找具有 403 权限的可能目录,我们可以使用 Dirsearch 对目录和文件执行暴力破解。
https://github.com/maurosoria/dirsearch
更确切地说,Kong是一个在Nginx中运行的Lua应用程序,并且可以通过lua-nginx模块实现。Kong不是用这个模块编译Nginx,而是与OpenResty一起分发,OpenResty已经包含了lua-nginx-module。OpenResty不是Nginx的分支,而是一组扩展其功能的模块。
这为可插拔架构奠定了基础,可以在运行时启用和执行Lua脚本(称为“插件”)。 因此,我们认为Kong是微服务架构的典范:它的核心是实现数据库抽象,路由和插件管理。 插件可以存在于单独的代码库中,并且可以在几行代码中注入到请求生命周期的任何位置。
安装docker和docker-compose
1 | # Install the latest version docker |
克隆仓库
1 | git clone https://github.com/Kong/docker-kong |
启动
1 |
|
如果没报错,可以加-d后台运行
我们可以查看下https://github.com/Kong/docker-kong/blob/master/compose/docker-compose.yml
看看docker里面启动了什么容器
这个Compose文件定义了三个服务:kong-migrations、kong-migrations-up和kong
kong-migrations服务用于执行Kong数据库迁移的初始化操作。该服务的命令为kong migrations bootstrap
,这个服务依赖于一个名为db的服务,表示它需要在db服务启动之后才能启动。此外,它还引用了一个名为kong_postgres_password的密钥,用于访问PostgreSQL数据库。该服务使用了名为kong-net的网络,并在失败时重新启动。
kong migrations bootstrap 命令是Kong在首次数据库初始化时使用的。
- 创建所需的数据库表
Kong需要一些核心表来存储配置数据,如kong.apis、kong.consumers等。bootstrap会根据数据库类型(Postgres/Cassandra)来创建并初始化这些核心表。
- 创建кong_migrations表
kong_migrations表用于记录已经运行的数据库迁移脚本版本。这Ensure the initial database schema宷一个> 初始化的数据库结构。
- 插入初始记录
会插入一些必须的初始数据,如设置表primary key等。
- 标记为执行完成
在kong_migrations表中插入一条执行记录,标记bootstrap已经完成。
所以在Kong首次使用一个空数据库时,需要先执行bootstrap建立初始表结构,然后才能使用kong migrations > > up执行后续的数据库升级。
与直接使用up命令不同,bootstrap专门用于初始化一个空数据库。执行成功后,该数据库即可用于启动Kong。
kong-migrations-up服务与kong-migrations服务类似,kong migrations up 和 kong migrations finish 这两个命令是Kong在数据库初始化和升级时使用的。
kong migrations up:
这个命令会运行所有未应用的数据库迁移脚本,以将Kong的数据库schema更新到最新版本。
Kong的数据库脚本存放在kong/migrations/目录下,每次Kong版本升级都会添加新的迁移脚本。
kong migrations up会按文件名顺序运行新增的迁移脚本,以分阶段地更新数据库结构。
kong migrations finish:
在所有迁移脚本运行完成后,这个命令将会删除kong_migrations表中记录的所有迁移历史。
kong_migrations表中存放了已运行迁移脚本的记录,用于判断尚未运行的脚本。
finish命令清除历史后,后续再次运行kong migrations up时会从头开始运行所有脚本。
所以这两个命令组合可以完成Kong数据库的初始化更新。
每次Kong版本升级都需要运行这两个命令,以更新数据库结构。
kong服务才是主要的Kong运行实例,是Kong网关的主要服务。
它使用了与前两个服务相同的Docker镜像,并可以通过环境变量${KONG_USER}指定运行用户,默认为kong。该服务配置了多个环境变量,包括Kong的管理员访问日志、代理访问日志、Kong的监听地址和端口等。它也引用了kong_postgres_password密钥,并使用了相同的网络和重新启动策略。此外,它还暴露了一些端口,包括代理监听端口、管理员监听端口以及Kong的Web管理界面监听端口。这些端口可以通过环境变量进行配置。该服务还定义了一个健康检查,每10秒执行一次kong health命令来检查服务的健康状态。它还将容器设置为只读模式,并挂载了一些卷用于存储Kong的运行数据和配置文件。最后,kong服务还设置了一个名为no-new-privileges的安全选项,用于禁止容器在运行时获取新的特权。
上面文件监听如下:
1 | 0.0.0.0:8000 |
1 | # netstat -antp | grep docker-proxy |
8000 就是Kong的转发流量的端口
8001 使用 Admin API 或通过 decK 配置 Kong
8002 访问 Kong 的管理 Web UI ( Kong Manager)
https://docs.konghq.com/gateway/latest/get-started/services-and-routes/
其实假如将监听改为0.0.0.0会更加方便实践,在生产环境应该不建议这么做了
用python flask写了简单的api示例
1 | # cat app.py |
测试没问题:
1 | root@ubuntu:~# curl http://192.168.145.131:808/users/1 |
1 | root@ubuntu2004:~/python-api# curl -i -s -X POST http://localhost:8001/services \ |
/flasktest的的流量定向到之前创建的 flask-api 服务
1 | root@ubuntu2004:~/python-api# curl -i -X POST http://localhost:8001/services/flask-api/routes \ |
现在我们访问,就可以了
1 | root@ubuntu2004:~/python-api# curl http://192.168.145.131:8000/flasktest/users/1 |
当然也可以在8002端口的web界面进行设置
1 | curl -X POST http://localhost:8001/upstreams \ |
1 | curl -X POST http://localhost:8001/upstreams/example_upstream/targets \ |
1 | curl -X PATCH http://localhost:8001/services/example_service \ |
多次访问查看host的变化在mockbin和httpbin 之间更改就是配置成功了(注:mock路径是之前官方文档创建的路由)
1 | curl -s http://localhost:8000/mock/headers |grep -i -A1 '"host"' |
插件那里有一些安全插件、流量控制的东西,这种东西自己搞可能就比较费劲了
当然还有代理缓存
https://docs.konghq.com/gateway/latest/get-started/services-and-routes/
]]>实验环境
Ubuntu 16.04
根据官网,debian系使用如下命令安装
1 | sudo mkdir -p /etc/apt/keyrings |
add-apt-repository出问题,报错invalid
手动添加到sources.list
1 |
|
apt update,报错NO_PUBKEY
1 | The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 97A80C63C9D8B80B |
我们添加以下:(97A80C63C9D8B80B根据上面报错修改)
1 | apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 97A80C63C9D8B80B |
再执行
1 | apt update |
先手动启动看看有无报错
1 | root@ubuntu:~# osqueryd |
发现少了conf文件
1 | cp /opt/osquery/share/osquery/osquery.example.conf /etc/osquery/osquery.conf |
之后就可以启动啦
1 | root@ubuntu:~# osqueryctl restart |
输入osqueryi即可开始查询
查询用户
1 | SELECT * from users; |
查询shell登录的用户
1 | SELECT * FROM logged_in_users; |
端口
1 | SELECT * FROM listening_ports; |
内核模块
1 | select name from kernel_modules; |
更多的表和结构可以查看
https://osquery.io/schema/5.9.1/
页面可以选择osquery的版本
]]>应用程序内嵌:RASP 技术通常以库或模块的形式嵌入到应用程序中,可以在应用程序的运行时启用和运行。这允许 RASP 技术深入了解应用程序的内部结构和行为。
实时监视:RASP 技术实时监视应用程序的执行。它跟踪应用程序的输入、输出、内部函数调用和数据流动等活动。
上下文感知:RASP 技术了解应用程序的上下文,包括用户、数据、环境和网络连接等。这有助于它更好地评估应用程序行为的合法性。
行为分析:RASP 技术对应用程序的行为进行分析,以检测不寻常的活动和潜在的攻击模式。它使用基于规则和机器学习等技术来进行分析。
攻击检测:RASP 技术识别和检测各种应用安全威胁,如 SQL 注入、跨站脚本(XSS)、跨站请求伪造(CSRF)等。
实时响应:当 RASP 技术检测到潜在的威胁时,它可以采取多种行动,包括拒绝请求、阻止攻击、记录事件、生成警报或采取其他安全响应措施。
自我保护:RASP 技术还可以自我保护,意味着它会尽力保护自身免受恶意攻击或尝试绕过它的行为。
安全策略配置:RASP 技术通常允许管理员配置安全策略,以适应不同的应用程序需求和威胁模式。这包括定义哪些行为是允许的,哪些是禁止的,以及如何响应各种威胁。
总的来说,RASP 技术通过深入了解应用程序的内部运行时行为,实时监视和分析应用程序活动,以检测和防止潜在的应用安全漏洞和攻击。这有助于应用程序更好地自我保护并提供实时的安全防护。但需要注意,RASP 技术通常不是独立的安全解决方案,而应与其他安全控制(如WAF、IDS/IPS等)一起使用,以建立更全面的安全防御体系。
实验环境
Ubuntu 16.04
tomcat 7
以java为例的,WAVSEP的漏洞靶场
1 | https://github.com/sectooladdict/wavsep/releases/tag/wavsep-v1.5-war |
首先安装Tomcat环境、mysql
1 | apt install tomcat7 tomcat7-admin mysql-server |
mysql可能需要修改root密码
1 | mysql -u root |
编辑tomcat配置文件
1 | root@ubuntu2004:/etc/tomcat7# vim tomcat-users.xml |
添加内容:
1 | <role rolename="manager-gui"/> |
创建数据库目录y
1 | mkdir /var/lib/tomcat7/db |
登录后台,上传war包部署
1 | http://192.168.X.X:8080/manager/html |
初始化
1 | http://localhost:8080/wavsep/wavsep-install/install.jsp |
先看看最新版的能不能行
下载 rasp-java.tar.gz 或者 rasp-java.zip 并解压缩。之后进入到解压后的目录中执行RaspInstall.jar
1 | wget https://github.com/baidu/openrasp/releases/download/v1.3.7/rasp-java.zip |
下面就是安装成功了
1 | root@ubuntu:~/rasp-2022-01-28# java -jar RaspInstall.jar -install /usr/share/tomcat7 |
之后重启tomcat
1 |
下面目录是官方的插件,用的nodejs写的
1 | root@ubuntu:/usr/share/tomcat7/rasp/plugins# ls |
下面链接是官方规则可以检测的漏洞类型,但有些是仅IAST商业版支持
https://rasp.baidu.com/doc/usage/web.html
不过默认没有开启阻断,需要编辑official.js开启,之后重启tomcat7
1 | // 若 all_log 开启,表示为观察模式,会将所有的 block 都改为 log |
访问以下sql注入
1 | http://192.168.XXX.XXX:8080/wavsep/active/SQL-Injection/SInjection-Detection-Evaluation-GET-500Error/Case01-InjectionInLogin-String-LoginBypass-WithErrors.jsp?username=textvalue%27%20or%207=7--%20&password=textvalue2 |
就会跳转到百度的页面
官方有文档
https://rasp.baidu.com/doc/dev/example.html
就是下nodejs
1 | apt-get install -y nodejs npm |
一个最小的SQL检测插件如下所示
1 | const plugin_version = '2018-1000-1000' |
主要就是调用 plugin.register 注册了SQL查询的检测函数,并将SQL语句打印到插件日志。
1 | params 为检查点提供的参数,如SQL语句、要读取的文件等等 |
检测函数return clean,其实就是放行,clean的action是ignore
而除了注册sql之外,还可以注册检测什么,可以看下面的链接
https://rasp.baidu.com/doc/dev/data.html
下面我随便列出一点
读取目录: directory
请求参数:request
删除文件:deleteFile
文件包含操作:include
文件上传:fileUpload
命令执行:command
代码执行(目前支持 eval/function 两种函数):eval
响应检查:response
写好之后可以用上面装好的rasp库进行测试,可以参考这里:https://rasp.baidu.com/doc/dev/test/main.html
测试用例以 JSON 格式保存
1 | [{ |
其中,action 表示期望的结果,是拦截、日志还是放行;id 是测试用例编号。其他字段主要是对请求上下文的模拟。
运行单元测试,需要两个关键参数
1 | rasp check -d ./unitCases -p myplugin.js |
实例:
tests文件夹放的是sql.json,来源:https://raw.githubusercontent.com/baidu/openrasp/191aa2e5ed8b80f9a3580d3c64dccb0e425ef373/agent/java/engine/src/test/resources/pluginUnitTest/unitCases/sql.json
1 | # |
默认的规则好像检测不到Get参数的反射型xss,我写两个简单的,不过就检测一个script,大家可以完善,不过调试的时候,好像querystring是有url编码的,这个需要注意,不然<script
是检测不到的
1 | const plugin_version = '2023-1015-1520' |
《基于开源软件打造企业安全》
]]>流量清洗是一种网络安全和数据管理技术,用于识别、过滤和处理网络流量中的异常、恶意或不良数据。这项技术通常由网络服务提供商、数据中心、云服务提供商和企业使用,以维护网络的安全性、性能和可用性。
实际上,流量清洗执行以下任务:
检测和过滤恶意流量:流量清洗系统能够检测和过滤包括病毒、恶意软件、僵尸网络攻击、分布式拒绝服务攻击(DDoS)和其他网络攻击形式的恶意流量。它们通过分析流量中的模式、行为和签名来实现此目标。
保护网络安全:流量清洗有助于防止网络威胁,确保关键网络资源和服务的安全。这对于保护网络免受未经授权的访问和攻击非常重要。
提高网络性能:流量清洗可以帮助过滤掉非必要或恶意的流量,从而减轻网络带宽压力,提高网络性能,确保合法流量能够正常传递。
维护服务可用性:通过阻止 DDoS 攻击和其他网络攻击,流量清洗有助于确保网络服务的可用性。这对于在线服务提供商、电子商务网站和其他依赖于持续在线性能的组织非常重要。
合规性和监控:流量清洗也用于监控网络活动,帮助组织遵守法规和监管要求。它提供了数据审计和记录功能,以便在需要时审查网络活动。
数据优化:一些流量清洗解决方案还可以帮助优化数据传输,减少数据冗余和传输时延,从而提高网络效率。
总结:就是不让一些恶意流量直接送到我们要防护的服务器,当然一般不能阻止攻击的流量
那么代码是怎么实现的呢
以下是一个伪代码示例,演示了如何基本实现流量清洗。请注意,这只是一个简化的示例,实际的流量清洗系统会更复杂和高级。
1 | # 伪代码示例 - 简单的流量清洗 |
这个简单的伪代码示例演示了一个基本的流量清洗系统,它检查传入数据包的源 IP 地址,如果源 IP 在已知的恶意 IP 列表中,就会丢弃该数据包。否则,它会将数据包正常转发。这是一个非常简化的示例,实际的流量清洗系统会更加复杂,包括更多的安全策略和功能,以及对各种网络协议和数据类型的支持。
这个一般是运营商才能干,比如电信的云堤,直接在骨干网的设备对流量进行处理
根据中国电信安全官网描述:
流量压制是利用中国电信作为基础运营商对互联网“手术刀式”的流量调度能力,通过发布黑洞路由,丢弃来自网络特定方向所有去往该客户IP地址(段)的流量,快速应对超大规模攻击。
]]>Ubuntu20.04
openresty-1.21.4.2
OpenResty 是一个基于 Nginx 的 Web 应用服务器,它将 Nginx 与一组强大的 Lua 模块集成在一起,提供了高性能、可扩展和灵活的 Web 开发环境。OpenResty 的目标是通过编写简洁的 Lua 代码来构建高性能的 Web 应用,而无需额外的服务器端脚本语言。
OpenResty 提供了丰富的 Lua 库和模块,可以与各种第三方服务和数据库进行交互,如 MySQL、Redis、Memcached 等,从而实现复杂的业务逻辑和数据处理。通过 Lua 脚本的编写,您可以在请求的不同阶段对请求进行处理、路由、验证、转发等操作,以及对响应进行过滤、修改等操作。
OpenResty 的优势主要有以下几点:
高性能:OpenResty 基于 Nginx,继承了其高性能、高并发处理能力和低资源消耗特点。同时,通过使用 Lua 进行自定义的请求处理和响应生成,可以进一步提高应用的性能。
可扩展:OpenResty 提供了丰富的 Lua 库和模块,可以轻松地扩展功能,从而满足不同业务场景的需求。借助这些扩展,您可以快速构建出符合自己业务需求的定制化 Web 服务器。
灵活性:OpenResty 提供了灵活的配置和编程方式,可以在全局层面和请求处理阶段进行高度定制。您可以根据需要对请求和响应进行精细控制,实现个性化的处理逻辑。
社区支持:OpenResty 拥有庞大的用户社区和开发者社区,提供了大量的资源、插件和示例代码,方便开发者学习和交流。
总之,OpenResty 是一个功能强大且易于使用的 Web 应用服务器,它通过集成 Nginx 和 Lua,提供了一种高性能、可扩展和灵活的方式来构建 Web 应用。无论是构建 API 服务、处理静态文件、实现反向代理还是构建微服务架构,OpenResty 都是一个值得考虑的选择。
安装依赖:
1 | apt update && apt install libpcre3-dev libssl-dev perl make build-essential curl zlib1g-dev |
下载
1 | wget https://openresty.org/download/openresty-1.21.4.2.tar.gz |
解压安装编译
1 | tar -xvf openresty-VERSION.tar.gz |
或者假如是Ubuntu可以直接根据官方文档,添加仓库,直接apt安装
下载
1 | git clone https://github.com/unixhot/waf.git |
将里面waf文件夹复制到Nginx配置文件目录
1 | cp -rf waf /usr/local/openresty/nginx/conf/ |
修改nginx配置文件nginx.conf
1 | # WAF |
这段 nginx 配置主要是实现使用 OpenResty 的 WAF (Web Application Firewall) 应用。具体含义如下:
lua_shared_dict limit 50m;:定义了名为 limit 的共享字典,大小为 50MB,这个共享字典是用来存储限流、计数等信息的。
lua_package_path “/usr/local/openresty/nginx/conf/waf/?.lua”;:定义了 Lua 脚本的搜索路径,这里是在 /usr/local/openresty/nginx/conf/waf/ 目录下寻找 Lua 文件。
init_by_lua_file “/usr/local/openresty/nginx/conf/waf/init.lua”;:在 Nginx 启动时执行一次 init.lua 脚本,主要完成 WAF 初始化操作。
access_by_lua_file “/usr/local/openresty/nginx/conf/waf/access.lua”;:在处理请求时,先执行 access.lua 脚本,主要完成 WAF 的访问控制功能。
Nginx+Lua WAF很重要的一个基础功能,即反向代理功能
一般通过Location里面添加 proxy_pass来实现
这里我本地实验,就不用反向代理了
1 | proxy_pass https://www.XXX.com/; |
WAF得配置在config.lua中
从access.lua可以看出检测的顺序
1 | require 'init' |
规则在rule-config目录
1 | root@vm:/usr/local/openresty/nginx/conf/waf# ls rule-config/ |
查看url.rule得内容
1 | root@vm:/usr/local/openresty/nginx/conf/waf/rule-config# cat url.rule |
可以看到一条规则一行
都是一些敏感文件,敏感后缀,敏感目录等
输入openresty启动nginx(其实是nginx得软连接)
1 | root@vm:~# ll /usr/local/openresty/bin/openresty |
在浏览器输入zip后缀
]]>对抗垃圾注册:
问题包括:撞库、暴力破解、盗号登录、非常用设备登录、黑产小号和僵尸号登录等
风控服务依赖于很多数据:设备指纹、IP信誉库、黑产手机号、社工库、用户画像等。
应提供多种密码保护手段:密保问题、安全中心手机版等
密码找回/重置不能存在逻辑漏洞或者过度的信息披露
提供异地登录提醒、异常登录提醒、破解账户提醒。
找回密码需要人机识别,方式批量找回
在密码找回、重置、安装证书等重要操作需要启用
保证同平台不能串号:PC和APP可以同时登录,但是两个PC不能登录同一个账户
假如登录就要踢下线
单点登录(Single Sign-On,简称SSO)是一种身份验证和授权机制,允许用户使用一组凭据(如用户名和密码)在多个应用程序或系统中进行身份验证,而无需为每个应用程序单独登录。
常见的SSO实现协议包括SAML(Security Assertion Markup Language)、OAuth(Open Authorization)和OpenID Connect等,这些协议定义了身份认证和授权的交互方式和流程。
但是凭借一个token就登录所有应用不是一个好设计,一旦xss盗取了,相当于全线溃防。一般对高安全域的,比如个人认证信息、支付类等重要的,引入第二层认证的secure token,只有一个token登录不了重要应用,需要两个token才可以。
拍下商品但不付款:高峰时段下单使用验证码
风控:小号、僵尸号与正常用户的区别、登录的途径、登录地域、登录设备指纹、收获地址等里啊分类标记
也可以临时更换业务逻辑使抢单程序失效;在抢购过程中使用验证码做人机识别
根据大数据标记用户恶意灰度。给优质账户高额回馈,低信誉小额优惠。
主要是竞争对手比价
爬虫特征:爬虫所在的IP段、不是正常的浏览器、可能不会解析JavaScript、缺少正常的浏览器客户端行为和通信 (跟DDos中的CC攻击人机识别有点类似)
根据账户注册信息的真实性、登录设备的真实性、绑卡异常、账户异常,结合自有或第三方历史征信数据综合判断欺诈的可能性。
可能包括: 虚假商品销售、钓鱼网站和假冒店铺、虚假评价和刷单、虚假退货和售后服务、虚假折扣和促销手段、虚假投诉和纠纷
来源:撞库、用户信息过度展现和披露、开放平台API滥用、供应链上下游信息泄露、内鬼兜售内部数据
成熟的大公司英国建立执行隐私保护的标准,对数据分类分级,加密脱敏。
依赖于以下几个方面:
交易风控在传统安全(包括认证、账户、KMS、PKI、客户端完整性等)的基础上还需要由3大组成部分:
交易风控团队需要两拨人:一来自传统金融行业,另一个来自互联网
点击欺诈,数据作假,所以目前都是按广告效果,实际订单效果收费
CPM(Cost per Mille): CPM指的是每千次展示成本。
CPC(Cost per Click): CPC指的是每次点击成本。
这两个都不行了,需要CPA(Cost per Action): CPA指的是每个行动的成本。
广告联盟优势跟黑产一样,假装正常用户注册登录充值,小量消费,只要消费低于广告费它就是赚的。
需要依靠账号标签以及对用户行为模式的数据分析来获取
主要是黄赌毒、舆情安全
基础手段:敏感字过滤、举报功能、人工审核
高级手段:抓取样本,用机器学习的方法做特征识别
除了盗号盗充,主要问题就是反外挂、私服、打金工作室
“打金工作室”通常指的是一种非法或违反游戏规则的活动,主要是指在网游中以非正当手段获取虚拟货币、装备或其他游戏资源,并出售给玩家获取利润的组织或个人。
这些打金工作室往往使用外挂、作弊程序、恶意刷钱等手段来获取游戏内的财产,这种行为严重破坏了游戏的平衡性和公平性。
保护手段:
最后还需各种情报的收集
这站在云计算平台厂商角度看, CaaS(Crime as a service),出了黄赌毒、很多虚拟机实例被植入木马变成“养鸡场”,僵尸网络的集中地,频繁DDos其他IDC或者用于暴力破解密码
云计算平台厂商可以做的是基于网络的异常流量分析
防护手段:
检测手段变现为一个个相对独立的产品形态,而防护则更多以零散的手段分布各处
1.网络(安全)设备:防火墙、WAF、NIDS(在大型IDC这些产品可能不一定是盒子,而是分布式软件,module或agent的形式)
2.OS层:HIDS数据,系统原始日志,应用层日志
3.运行时环境:JVM、Zend解析器的定制日志,形式上属于OS层面可以采集的数据
4.数据层:数据库、缓存以及大型的分布式数据库中间件代理所产生的访问和安全告警
5.漏洞信息:由网络扫描器或主机本地agent搜集的漏洞信息
6.资产和配置管理数据:iplist属于基础数据
上面做得比较好,可以考虑第三方威胁情报数据(IP信誉、恶意域名、灰色URL)
服务器负载均衡可能会充当WAF和人机识别模块
应用需要RASP运行时环境的沙箱检测
HIDS
大数据日志采集agent(比如Flume)
SQL / DB审计
IDC跨全球区域, 一般跟随运维基础架构,比如运维是多中心分治,安全数据也不会可以最求到汇聚点聚合。
敏感国家地区遵从合规性,可采用区域分治原则
对于企业的生产网络,最外围的威胁如下:
上面上全套对于大多数企业来说还是太贵,只能做一些妥协和裁剪
如果业务流量大部分是http类型,重点投入WAF、RASP和WEB扫描器,NIDS/NIPS可以忽略,如果有条件搞HIDS,优先关乎用户态检测,比如webshell和提权
而非HTTP协议,如SSH、MySQL等通用协议而不是私有的话,网络部分可以考虑NIDS,数据库部分使用SQL审计。
而小西街口、远程过程调用、数据缓存和持久化中私有协议占多数,就不考虑NIDS和SQL审计,而转向HIDS,私有协议对于入侵者来说是一道门槛,被渗透概率不搞,所以更多关乎操作系统本身。
非web业务,入存储节点,关注操作系统入侵,HIDS,重点在后门程序和Rootkit的检测
无论如何追求性价比,安全感总有一个底线
最起码对于这两个环节上具备一定的入侵感知能力,不至于发生了如此严重的事情还没有半点告警,
所以尽可能在数据库(或者数据访问层(Data Access Layer):DAL是应用程序与数据库之间的一个中间层)和主机这两个层面设防。
第一阶段:
第二阶段
之后投入到纵深防御+入侵感知体系建设才会事半功倍
运维:补丁和配置更改的具体实施工作
产品团队:代码级别的漏洞修复
安全防御体系建设小组负责在相关的乳清感知体系中update对于该漏洞的检测规则
总结:1.发现得快;2.修得快;3.修不了,临时规避
比如漏报的根因分析流程
单点检测深度不足?——选取的检测维度不够?——覆盖率不足?——安全产品的可用性?——数据质量?(数据非安全相关或者中低风险的告警太多)——人的问题?
]]>三个层面的攻防对抗:信息对抗、技术对抗、运营能力对抗
作者赞同腾讯的“河防”以及数字公司(应该指的360 )用的“塔防”概念
互联网安全的几个核心需求:快速检测、有限影响、快速溯源、快速恢复
Plan-A:直接从目标系统正面找漏洞,getshell,提权,后面扩大战果,安全建设的思路要阻止攻击者扩大战果
Plan-B:曲折迂回,从周围信任域开始下手(包括arp重定向、可嗅探的、可会话中间人的、可链路劫持的、相同内网的、密码满足同一规律的、互联互通信任关系的,灾备或者镜像站点等),获取一个点之后再折返,之后与A类似
Plan-C:社会工程学,针对管理员和办公网的APT,水坑攻击。
纵深防御体系:安全域、基于第二层的隔离、端口协议过滤、APP安全、Container层安全、OS层防御和提权、防止内核空间乱入、Hypervisor保护
第一层:安全域的划分,是对业务的抽象不是对物理服务器的划分;他们不一定同一个物理机房,但对应相同的安全等级,共享相同的访问控制策略(目的希望将安全事件的最大范围控制在一个安全域中)
第二层:基于数据链路层的隔离,使用VPC、Vxlan、Vlan等方法在安全域的基础上对一组服务器更细的粒度再画一道防线,进一步抑制单点沦陷后受害源扩大的问题
第三层:端口状态协议过滤,这是大多数防火墙的应用场景。解决对黑客暴露的攻击面问题。
第四层:APP安全,主要解决认证鉴权、注入、跨站和上传的应用层漏洞。
第五层:容器和运行时的环境。应用程序有漏洞,也不希望攻击者直接跳转到系统权限,方法是容器加固,比如阻止一些危险函数的运行,比如上传了webshell但是不被解析执行。
第六层:OS层防御,系统加固,主要对抗提权,SMAP(Supervisor Mode Access Prevention,管理模式访问保护)和SMEP(Supervisor Mode Execution Prevention,管理模式执行保护)、DEP、ASLR、stack-canary等,此外不是特别的需求要干掉LKM【Loadable Kernel Module(可加载内核模块)】,/dev/kmem (一个特殊的设备文件,用于提供对系统内核内存的直接访问。它允许用户级程序读取或写入内核虚拟地址空间中的数据。),限制/dev/mem的全地址空间的读写(/dev/mem 是一个特殊的设备文件,用于提供对系统物理内存的直接访问。它允许用户级程序读取或写入整个物理内存的内容。)
第六层:假如云计算环境,更底层的还有hypervisor
不管安全实践多么优秀的互联网公司,安全体系都离不开基础安全措施,不然上层的大数据入侵检测如同空中楼阁。在纵深防御中层层设卡,每个环节关注有限的点,使得入侵检测需要的覆盖面(广度)和检测层次(深度)随着攻击面的缩小而大幅缩减。
目的是将一组安全等级相同的计算机划入同一个安全域,对他们设置相同的网络边界,在网络边界上以最小权限开放对其他安全域的NACL(网络访问控制列表/策略),将域内计算机暴露的风险最小化,在发生攻击或蠕虫病毒是能将威胁最大化地隔离,减少域外时间对域内系统的影响
通常分为DMZ区和内网,还会通过硬件防火墙的不同端口来实现隔离,这种只适用于办公网络,对于大规模生产网络已经不适用。
DMZ(Demilitarized Zone,非军事区)是一个位于网络边界内的区域,用于隔离内部受信任的网络与外部不受信任的网络之间的安全边界。
有三层:接入层、应用层、数据层。
接入层:只开放80与443端口
应用层:工程技术人员可通过堡垒机访问应用层
数据库层:授权的第三方可通过ssh远程连接访问指定的数据层资源
其余所有端口默认阻断
安全域划分没有限定一定划分vlan,可以基于L3、L4的防火墙规则,甚至NAT都可以起到隔离作用。基于L2的划分比L3及之后的更可靠一点。
把不同的业务(垂直纵向)以及分层的服务(水平横向)一个个切开,在南北向的APT调用上保留最小权限的访问控制,在东西向如无系统调用关系则彼此隔离。
小网络可以做得很细,大网络的运维工作量大,需要妥协折中的策略。
只介绍生产网络和办公网络链接所涉及的安全域问题,为保证最大的隔离,尽可能采取如下措施:
所有安全工作的第一步,可以归入安全基线
1 | root@vps1:/boot# cat config-`uname -r` | grep DEVKMEM |
/proc/sys/kernel/randomize_va_space : ASLR,0是关闭,1是mmap base、stack和vdso page随机化,heap没有,2才增加了heap的随机化
/proc/sys/kernel/kptr_restrict 1:限制非特权用户对内核指针的访问,只有具有root权限的进程才能读取和使用内核指针。
/proc/sys/vm/mmap_min_addr是Linux内核中一个虚拟内存子系统的参数。它用于限制非特权用户在较低的虚拟内存地址范围内进行内存映射的能力。 设置为65536
禁用NAT:攻击者内网渗透会在边界开启端口转发,/proc/sys/net/ipv4/ip_forward,设置为0,假如无缘无故变为1,可能出了安全问题(但有些服务可能需要这个功能,)
Bash日志: 家目录的.bash_history,
下面配置可以加到.bashrc中
设置环境变量为只读
1 | readonly HISTFILE |
为history添加时间戳
1 | exportHISTTIMEFORMAT=' %F %T ' |
设置history文件只能追加
1 | chattr +a ~/.bash_history |
禁用其他shell
更改HISTFILE
为其他文件,并保留原路径下的.bash_history
1 | HISTFILE=/usr/local/log/cmd |
高阶的做法就是修改shell本身,对所有执行的命令无差别地记录
修改shell源码是一种方式,直接修改libc会更加高效,涉及的对象是exec函数族
1 | int execl(const char *path, const char *arg0, ... /* (char *) NULL */); |
exec 函数族的底层实现通常会调用 execve 函数。这是因为 execve 函数是 exec 系列函数中最底层、最通用的函数。
修改以上库函数,支持额外的syslog,就能记录所有运行过的程序。
另一种shell审计的高级方式是将shell的log统一收集后基于机器学习,学习正常管理员的shell命令习惯,而不是以静态规则定义黑白名单。
安全圈流行:可写目录不解析,解析目录不可写
ssh使用v2版本能,并禁止root用户远程登录
对付暴力破解最有效的方式是多因素认证或非密码认证
收集各种社工库,把内部测试研发运维的常用弱密码做成字典,周期性地更新字典并主动尝试破解公司内的各个系统的账户,能破解的都视为弱密码。
生产网络多层NACL:第一层 FW,第二层交换机(简单的NACL) ,第三层服务器(系统自导的防火墙就够用了)
自动化运维:大量push补丁
ITSM(信息技术服务管理)成熟度:不影响在线服务可用性
架构容灾能力:支持有损服务,灰度和滚动升级
系统能力:提供热补丁,无需重启
快速单个漏洞扫描:补丁push成功后的检测
一般建好第几,初步纵深防御建立起来才搞SOC(安全运营中心)
初期可以关注重要的,比如 lastlog和/var/log/secure,看看是否有非雇员登录
4A是指: 账户、认证、授权和审计
对于大规模的服务器集群,不太可能,每台服务器单独维护用户名和密码
一个是基于LDAP
一个基于堡垒机
传统商业NIDS
开源的snort
大型全流量NIDS——基于大数据的NIDS架构
多层防御结构
第一层:ISP近源清洗
第二层:云清理/CDN硬抗
第三层:DC级近目的的清洗
开源产品 OSSEC
MIG: 开源的分布式取证框架,不算严格意义的HIDS
OSquery:将操作系统当作数据库,用sql语句查询
Java:基于高危行为组合的检测模型、基于调用栈的检测模式
解决:SQL注入拖库、操作违规的审计
部署:旁路型、主机型、代理型
全局的信息汇聚与分析,将上面提到的数据进行汇聚和分析
ACL扫描:避免无需对外开放的ip或者端口暴露公网
弱口令扫描
系统及应用服务漏洞扫描
Web漏洞扫描
实践中:
Coverity
一般针对大型企业
分类示例: OA服务器域、事业部A桌面域、事业部B桌面域
而在桌面域可以细分,重度PC用户(运维、研发)、中度PC用户(运营、市场、媒体)、轻度PC用户(客服、线下销售)
重度的策略可以无需过于严格,轻度的可以相对严格的策略
微软自身解决方案中的SCCM
第三方终端管理软件中附带的补丁推送功能
作用主要在于实施一些基本的安全策略
360安全卫士、腾讯管家那些
不过现在微软的defender也不错了
主流方案:
IEEE 802.1X 是一种网络访问控制(NAC)协议,用于提高局域网(LAN)和无线局域网(WLAN)的安全性。它的主要目的是确保只有经过授权的设备和用户能够访问网络资源,从而减少未经授权的访问和网络攻击的风险。
vpn:暴力破解问题
安全方面有先天优势,尤其是物理安全方面,没有拷贝数据的USB口
安全体系需要构建的完备一点
此外还可以从陷阱网络和蜜罐入手
主要通过终端控制、网络出口控制、以及检测网络流量实现
本质是一种方法论和参考维度,ISO27001
安全团队的组织分类
安全KPI:覆盖率、覆盖深度、检出率/主动止损率、TCO(总拥有成本,Total Cost of Ownership)和 ROI(投资回报率,Return on Investment)
外部评价指标:攻防能力、视野和方法论、工程化能力(全线防御、纵深防御、自动化)、对业务的影响力
数据分类
访问控制
数据隔离
数据加密
密钥管理
安全删除
匿名化
内容分级:有些需要2FA认证才给访问才行
]]>对于有一定IT资产的企业,企业安全不是发现漏洞然后修复漏洞,在设置一下防火墙之类的。
攻防只解决了一半的问题,安全的工程化以及体系化的安全架构设计能力也是同样重要的。
安全建设包含:组织、管理、技术,组织 就是安全组织
作者认为的企业安全:从广义的信息安全或者狭义的网络安全出发,根据企业自身所处的产业低位、IT总投入能力、商业模式和业务需求为目标,而建立的安全解决方案以及为保障方案实践的有效性而进行的一系列系统化、工程化的日常安全活动的集合。
企业安全7大领域
在甲方,安全不是主营业务,归根结底,安全是一个保值型的后台智能,不是一个明显能创造收益的前台职能,是一个成本中心而非盈利中心。
核心:看产出是否对主营业务有帮助,工作成果能不能转化为主营业务竞争力
BCP(Business Continuity Plan):业务持续性计划,是一份组织为应对各种内部或外部的灾难、事故或业务中断而制定的详细计划。
DRP(Disaster Recovery Plan):灾难恢复计划,是一种面向信息技术系统和基础设施的计划,旨在在信息系统遭受破坏或中断时,尽快恢复其正常运行状态。
BS25999是一项国际标准,全称为《业务持续性管理》(Business Continuity Management)的英国标准。BS25999标准于2012年被国际标准化组织(ISO)正式接纳并发布为ISO 22301标准,通过遵循ISO 22301标准,组织可以建立一个系统化和综合的业务持续性管理体系,以增强对潜在中断的应对能力,并最大限度地减少对业务的影响。
通过遵循ISO 27001标准,组织可以建立一个系统化和综合的信息安全管理体系,以确保信息资产得到恰当的保护,减少信息安全风险,增强信息安全意识,以及满足法律法规和利益相关者的要求。
BS7799已经被ISO 27001所取代,因此在实践中,更推荐使用ISO 27001标准来建立信息安全管理体系。
推荐做法:
互联网安全工作包括:
互联网企业和传统企业在安全建设中的区别
传统企业安全问题特征:
大型互联网企业:
注: TCO (Total Cost of Ownership) 和 ROI (Return on Investment) 都是用于评估和分析企业投资决策的概念。TCO(总拥有成本)是指在使用某个产品或服务的全寿命周期中所涉及的所有费用。ROI(投资回报率)是一种衡量投资效益的指标,用于评估投资项目的经济回报。
互联网企业分为生产网络和办公网络,而某些传统企业可能只有办公网络,随着数字中国推进,传统企业也会有自己的生产网络。
互联网企业的生产网络都是以攻防为驱动,关注性能损耗、运维成本和软件成本,会把在服务器上装防病毒软件这个方案干掉
机房规模大了,不可能部署n个硬件盒子,需要适应分布式的系统架构
所以最终的解决方案应该是:自研或者对开源软件进行二次开发+无限水平扩展的软件架构+构建于普通中低端硬件之上(PC服务器甚至是白牌)+ 大数据机器学习的方式。
- 事前的安全基线- 建立是中的监控能力- 做好事后的应急响应能力:应急时间成本更短,溯源和根因分析能力更强
一般来说直接使用现成的就行,比如DEP、ASLR、操作系统基带的RBAC(基于角色的访问控制)
假如需要解决的是单一问题,用救火的方式,假如是一类问题才考虑如何更好地解决这一类问题,如果在微观细节上补洞总是补不完,不放看看更高抽象层次有没有解决方案,有没有新的路径解决这个大类的问题。
SDL(安全开发声明周期)
目前SDL包含:
安全设计
威胁建模
以下是威胁建模的一般步骤:
确定资产:确定需要保护的资产类型和重要性,例如机密数据、知识产权等。
构建系统和流程架构:通过绘制图表或使用其他工具,建立应用程序或系统的逻辑架构图,包括各种数据源、处理和存储组件、用户界面和网络连接。
定义攻击者模型:确定系统中可能的攻击者和攻击方式,例如黑客、内部员工、供应商或合作伙伴等。
识别威胁:基于攻击者模型,识别可能的威胁和攻击,例如SQL注入、跨站点脚本攻击、社交工程攻击等。
评估威胁严重性:对每个识别出的威胁进行概率和严重性评估,确定其风险级别。
提出对策:针对识别出的威胁,提出相应的安全措施和防御措施,包括技术控制、流程和策略、培训和意识提高等方面。
验证措施:对提出的防御措施进行测试和验证,确定其有效性和可行性。
需要注意的是,威胁建模并非一次性的过程,需要随着应用程序或系统的变化不断更新和维护。此外,威胁建模需要针对不同的应用程序或系统进行定制化,考虑到其特定的业务需求和技术实现。最后,威胁建模不是万能的,不能保证完全避免所有的安全漏洞和攻击。但是,它可以帮助企业减少风险,并更好地处理安全事件。
安全编码:
缓冲区溢出
整数算法错误
跨站点脚本
SQL注入
弱加密
安全测试:
安全测试和功能测试是软件测试的两个不同方面,它们主要关注的是不同的目标。
功能测试是验证软件系统是否按照规定的需求和预期功能进行工作。它确保软件的各项功能在各种条件下正常运行,包括用户界面、数据处理、业务逻辑等。功能测试主要关注系统是否能够正确地执行特定任务,如输入验证、功能覆盖等,并且通常以预期结果为基准进行验证。
而安全测试是为了评估软件系统的安全性能和强度。它专注于发现系统中可能存在的安全漏洞、风险和潜在威胁,并提出相应的建议来增强系统的安全性。安全测试旨在模拟真实的攻击场景,包括黑盒测试和白盒测试,测试人员会尝试以各种方式绕过访问控制、注入恶意代码、暴露敏感信息等。
因此,安全测试和功能测试在测试目标、方法和侧重点上存在一些区别:
测试目标:功能测试主要关注系统的功能和操作是否正常;安全测试重点关注系统的安全漏洞和潜在的威胁。
测试方法:功能测试通常采用黑盒测试或白盒测试,关注输入和输出的正确性;安全测试则会使用更多的黑盒测试和渗透测试来模拟真实攻击并评估系统的防御能力。
侧重点:功能测试关注系统功能的完整性和正确性;安全测试则侧重于发现系统的弱点和漏洞,以及提供相应的修复建议。
需要注意的是,功能测试和安全测试是相辅相成的,两者都是保证软件质量和安全性的重要组成部分。综合进行功能测试和安全测试,可以确保软件系统不仅具备基本功能,还能够抵御各种潜在的安全威胁。
隐私
隐私开发的最佳实践是在软件和应用程序的开发过程中,将隐私保护作为核心原则并采取相应的措施。以下是一些隐私开发的最佳实践:
数据分类和敏感性评估:对所处理的数据进行分类,确定敏感数据的范围和安全级别,并进行相应的风险评估。
数据加密:采用适当的加密算法和加密技术,对存储在数据库、传输过程中的数据进行加密,确保数据在非授权访问时无法被读取或理解。
用户授权和访问控制:实施身份验证和授权机制,确保只有经过授权的用户才能访问和处理敏感数据。包括使用强密码、多因素身份验证等来增强用户的账户安全性。
匿名化和脱敏处理:对敏感数据进行匿名化或脱敏处理,以减少个人身份的识别风险。
最小权限原则:给予用户和程序仅必要的权限,避免过度收集和访问用户的个人信息。
错误处理和日志记录:合理记录和审计系统操作和错误信息,及时检测和响应潜在的安全事件和隐私问题。
安全漏洞管理:及时监测和修复软件中的安全漏洞,定期进行安全评估和渗透测试,确保系统的安全性。
隐私政策和通知:制定明确的隐私政策,并将其通知给用户,告知数据收集、使用和共享的目的和方式。
第三方服务供应商的选择和审查:对于使用第三方提供的服务或工具,要评估其隐私和安全措施,确保他们符合合规要求。
员工培训和教育:对开发人员和相关人员进行隐私意识和最佳实践的培训,确保团队整体上具备隐私保护的意识和技能。
综上所述,隐私开发的最佳实践需要全面考虑软件和应用程序的整个生命周期,从需求分析到发布和运营过程中都应当注重隐私保护,并采取相应的技术和管理措施来保障用户的隐私权益。
隐私测试是评估应用程序、系统或产品在处理用户个人信息时是否符合隐私保护要求的过程。以下是一些隐私测试的最佳实践:
设计测试方案:根据隐私保护的相关法规、标准和最佳实践,制定详细的测试方案,明确测试目标、范围和方法。
数据分类和敏感性评估:对测试所使用的数据进行分类,确定敏感数据的范围和安全级别,并进行相应的风险评估。
合规性检查:评估应用程序、系统或产品是否符合相关法规和隐私保护的最佳实践,包括隐私政策、用户授权和访问控制、数据加密和匿名化等方面的要求。
数据收集和使用测试:验证应用程序、系统或产品是否按照隐私政策中规定的目的和方式收集和使用用户个人信息,是否尊重用户的选择和权利。
安全性测试:检查数据传输和存储的安全性措施,包括加密算法、访问控制、身份验证等方面的测试,以确保数据在传输和存储过程中的安全性。
第三方服务供应商测试:评估第三方服务供应商是否符合隐私保护的要求,包括数据处理和共享、数据安全管理等方面的测试。
用户权益测试:验证用户在隐私保护方面的权益是否得到充分保障,包括访问、修改、删除个人信息的测试,以及用户投诉和申诉机制的测试。
日志和审计测试:确保应用程序、系统或产品具备适当的日志和审计功能,记录关键操作和事件,以便追踪和调查潜在的隐私问题。
跨平台和跨设备测试:针对不同的操作系统、设备和网络环境,测试应用程序、系统或产品在不同环境下的隐私保护能力。
审查测试报告和改进措施:综合测试结果,编写详细的测试报告,并提出改进建议和优化措施,以进一步完善隐私保护。
综上所述,隐私测试需要综合考虑法规、标准和最佳实践,涵盖数据分类、合规性检查、安全性测试、用户权益测试等多个方面。通过全面的隐私测试,可以识别和解决可能存在的隐私问题,确保应用程序、系统或产品符合隐私保护的要求。
高级概念方面的培训
DevOps的交付模式:互联网交付节奏快,没有足够事件去思考安全,而SDL会拖慢发布的节奏,需要经验丰富的安全人员和自动化工具的支持
历史问题:甲方安全团队都是以救火方式开始的,SDL不是安全建设的第一个想到的事情。还需要摆平研发
业务模式:互联网以Web为主,事后修补成本低,加上产品生命周期不长。
SDL的门槛:第一,安全专家少,懂攻防又要懂开发,懂漏洞又要懂设计,对于研发部门缺少指导的安全设计;第二,工具支持少,静态代码扫描、动态Fuzz等,工欲善其事必先利其器。
1.重度的场景:对于偏底层的大型软件,迭代周期较长,对架构设计要求比较全面,后期改动成本大,这种应在事前切入,在立项设计阶段就英国进行安全设计和威胁建模等工作。
2.轻度的场景:架构简单、开发周期短、交付时间要求比较紧,SDL太过于笨重,攻防驱动修改就足以解决问题
SDL在大部分不差钱的互联网企业属于形式上都有,落地比较粗糙,通常只有一两个环节,瓶颈是人和工具的缺失。
这是微软开发的用于威胁建模的工具,有助于风险识别的覆盖面
6个维度:Spoofing(假冒)【认证】、Tampering(篡改)【完整性】、Repudiation(否认)【不可抵赖性】、Information Disclosure(信息泄露)【机密性】、Denial of service(拒绝服务)【可用性】、Elevation of Privilege(权限提升)【授权】
如何使用:画出数据流关系图(DFD),包含四个元素:数据流、数据存储、进程和交互方,再加上信任边界
画出图后,对每个节点元素和过程进行分析判断是否存在上述的6个维度的威胁,并制定对应的风险缓解措施。
上面的high level的威胁建模,low level的威胁建模需要话了时序图后根据具体的协议和数据交互进行更进一步的分析。
安全标准到底有什么用?归根结底为了给你一个参考和指引,当你把基础的技术防护手段实施之后,过了上任之初的救活阶段之后,就需要停下来思考一下整个企业安全范畴中,哪些事情是短板,哪些领域尚且空白,需要在哪些点上继续深挖才能覆盖公司整体的安全建设,而安全标准的价值就是告诉你,在安全建设的领域里可能有那么100件事情是需要做的,但具体选择只做80件还是99件还是100件全是你自己的事情,但标准也只告诉你100件事是什么,怎么实现,对应的技术方案和流程是没有的,实现和落地是需要自己想的,本质上是用于开拓视野。
业务持续性管理(BCM):项目管理——风险分析和回顾——业务影响分析——恢复策略——计划实施——测试和演练——程序管理
PDCERF 模型是应急响应的一个通用框架,用于指导组织在发生安全事件时如何有效应对。PDCERF 模型的六个阶段分别是:
准备(Preparation):在事件发生之前,组织需要做好充分的准备,包括制定应急计划、建立应急响应团队、培训人员等。包括工具准备,静态编译的ls,ifconfig,psdeng
检测(Detection):在事件发生后,组织需要尽快发现和识别事件,以便及时采取措施。
遏制(Containment):在事件发生后,组织需要采取措施控制事件,防止其扩大影响。
根除(Eradication):在事件发生后,组织需要采取措施消除事件的影响,并防止事件再次发生。
恢复(Recovery):在事件发生后,组织需要采取措施恢复业务,使其恢复到正常运行状态。
跟踪(Follow-up):在事件发生后,组织需要对事件进行跟踪和分析,以便总结经验教训,提高应急响应能力。
遏制或者作者说的抑制,首先要了解业务、数据流、各服务接口的调用关系,这些都是日常的积累,否则随便一个隔离又吧什么服务搞down了。如果安全团队平时连个数据流图都没有,发现单点出现问题,大致的系统间的影响和潜在的最大受害范围都估算不出来。
lv0:没有安全措施
lv1:自己认为自己是安全的:做过渗透测试,交付的代码没有高危漏洞
lv2:有救火的能力:由攻防团队,有基本的入侵检测能力
lv3:安全体系化:接近完整的纵深防御体系,覆盖入侵检测和防护
lv4:业务层面安全得到满足:账户的基础服务都有安全风控措施
lv5:最佳实践阶段:完整的纵深防御,高度自动化、大数据和机器学习,精准对抗
新概念新产品层出不穷,大多数不能说是替代,而只是演进、升级和补充。
]]>通过在ida的python console输入下面代码获取plugin路径(下面获取的一般是C盘的用户路径,C:\Users\XXXX\AppData\Roaming\Hex-Rays\IDA Pro\plugins),或者你直接放到IDA根目录的plugins文件夹
1 | import idaapi, os; print(os.path.join(idaapi.get_user_idadir(), "plugins")) |
知道路径后将lighthouse项目的plugins文件夹的lighthouse文件夹和lighthouse_plugin.py放到plugins目录即可
重新打开IDA,就可以看到加载文件那里多了Code coverage file
DynamoRIO就是针对windows,很简单(我使用的是DynamoRIO-Windows-8.0.0-1,据说Lighthouse默认使用的drcov文件版本为version 2,但是最新版的DynamoRIO生成的drcov文件的版本为version 3)
1 | bin64\drrun.exe -t drcov -- XXX.exe |
官方指南: https://github.com/gaasedelen/lighthouse/blob/develop/coverage/pin/README.md
下载pin tools: https://www.intel.com/content/www/us/en/developer/articles/tool/pin-a-binary-instrumentation-tool-downloads.html
注意: 下载最新版的无法编译通过,我当时下载的Pin3.13,可以编译通过
编译:
cd lighthouse/coverage/pin
export PIN_ROOT=/root/pin-3.13 #上面下载后解压的pin的路径
export PATH=$PATH:$PIN_ROOT
make # 默认编译intel64
make TARGET=ia32 # 指定编译ia32
pin覆盖率获取
1 | ~/tools/pin-3.13/pin -t obj-intel64/CodeCoverage.so -- ./src/target ./testfile |
使用 -w 命令行标志,可以指示pintool仅对您指定的模块进行插桩,可以加快速度,也大大减少收集的数据量。
1 | ~/tools/pin-3.13/pin -t obj-intel64/CodeCoverage.so -w target -- ./src/target ./testfile |
而且-w可以有多个
1 | ~/tools/pin-3.13/pin -t obj-intel64/CodeCoverage.so -w target -w libcrypto.so.1.1 -- ./src/target ./testfile |
Frida在移动平台上的支持最好,如iOS或Android,声称对Windows、MacOS、Linux和QNX提供一些支持。实际上, frida-drcov.py 只应用于收集移动应用程序的覆盖数据。
安装Frida
1 | pip install frida |
一旦安装了Frida,可以使用frida-drcov.py
脚本来收集正在运行的进程的覆盖率
1 | python frida-drcov.py <process name | pid> |
默认会生成frida-cov.log覆盖率文件
使用 -o 标志,可以指定覆盖率日志文件的自定义名称/位置:
1 | python frida-drcov.py -o more-coverage.log foo |
以htop为例,首先启动htop,之后执行下面命令
1 | python frida-drcov.py htop |
结束掉htop,之后再结束上面命令,即可生成frida-cov.log,就可以导入到IDA了。
]]>QEMU是AFL++支持的后端之一,用于Binary-only的模糊测试,这是通过patch QEMU来执行原始二进制文件,以收集覆盖率信息。
此外,针对QEMU模式,可以配置不同的环境比那里来优化模糊测试的性能和覆盖率。
插桩相关:
变异相关:
执行相关:
从理论到实践有时看起来很乏味,经常会引发一些反复出现的问题,比如:
这是一个二进制文件,它接收一个文件名作为输入,并尝试解析相应文件的内容作为X509证书。
学习示例源码:https://github.com/airbus-seclab/AFLplusplus-blogpost/tree/main/src
main函数:调用init初始化,之后将文件作为参数传递给parse_cert函数
parse_cert函数:调用read_file函数读取文件,之后调用base64_decode进行文件解码,最后调用parse_cert_buf
parse_cert_buf函数:使用openssl库的d2i_X509进行解析,尝试获取CN并打印。
注:在证书中,”CN” 代表 “Common Name”,即 “通用名称”。它是用于标识证书(如SSL证书)所关联的实体(例如网站、服务器等)的一个字段。通常情况下,CN字段会包含一个域名(或者IP地址),用于指示证书所属的主体实体的名称。在SSL证书中,CN字段通常用于验证证书是否与访问的域名匹配,以确保通信的安全性。
原作者故意在函数中留了一个缓冲区溢出漏洞:strcpy(cn, subj); // Oops
1 | int parse_cert_buf(const unsigned char *buf, size_t len) { |
而且作者在主函数的开头故意添加了一个虚拟的 init 函数,以模拟一个初始化阶段,这会花费一些时间并使目标变得缓慢启动,不过才usleep50毫秒。
在现实生活中,目标显然不像我们上面的X509解析器那样简单。事实上,对于一个只有二进制文件没有源码的目标进行有效的模糊测试,总是要先进行逆向工程,一般有以下阶段:
由于上面的示例比较简单,所以不需要花太长时间来找到易受攻击的代码、调用追踪并确定感兴趣的函数就是parse_cert_buf
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
需要收集目标程序期望的输入格式的文件,由于示例是一个证书解析器,那就可以用openssl生成一个证书:
1 | $ openssl req -nodes -new -x509 -keyout key.pem -out cert.pem |
1 | 这个命令是使用OpenSSL工具生成自签名的RSA密钥对和X.509数字证书文件的命令。下面是对每个选项的解释: |
作者把—–BEGIN CERTIFICATE—–和—–END CERTIFICATE—–以及前后空格给去掉当作
在使用这个语料库之前,我们可以进行预处理
作者将其写成了脚本build_corpus.sh:先进行cmin,再缩减样本大小tmin
1 | #!/bin/bash |
其中afl_config.sh 文件如下:
1 | $ cat afl_config.sh |
通过默认的形式启动AFL++的QEMU模式,目标的所有基本块都被插桩,共享库不包含在插桩中。
1 | #!/bin/bash |
我们可以在下面的不断优化中查看执行速度的变化
在我的机器上,这个默认模式,速度大概是18每秒
对于插桩的调优,可能有以下原因:
如果需要调优,可有下面变量可用
在上面证书解析的例子中,parse_cert_buf 的插桩很重要,但是对于main的插桩就不那么相关了,还有共享库libssl.so
我们可以通过AFL_QEMU_INST_RANGES来将插桩限制在想要关注的函数上,即parse_cert_buf的第一条指令到最后一条指令
注意:可以使用 AFL_CODE_START 和 AFL_CODE_END 来完成这个操作。然而, AFL_QEMU_INST_RANGES 更加灵活,因为它允许指定多个范围进行插桩。
作者写好了脚本来设置
1 | # The base address at which QEMU loads our binary depends on the target |
inst_start就是QEMU_BASE_ADDRESS+函数文件内偏移
inst_end就是函数文件内偏移+函数大小
作者给的find_func函数有点难理解,下面的其实更好理解,双引号是正则匹配,后面是输出规则
1 | function find_func() { |
可以使用下面的更简单
1 | objdump -t "$target_path" | grep $1 | awk '{print "0x"$1, "0x"$5}' |
上面脚本可添加echo $fuzz_func_addr $fuzz_func_size
可以输出获取的值,看看是否正确
1 | $ ./find_func.sh parse_cert_buf |
之后启动afl的时候,通过启用AFL++-QEMU的调试模式( AFL_DEBUG ),我们可以检查插桩范围是否与我们设置的一样
1 | $ AFL_DEBUG=1 ./fuzz.sh | grep Instrument |
在模糊测试时,AFL++会运行目标程序直到达到特定地址(AFL入口点),然后从该地址fork进行每一次迭代。默认情况下,AFL入口点被设置为目标程序的入口点(在我们的示例中, target 的 _start
函数)。
1 | $ AFL_DEBUG=1 ./fuzz.sh | grep entrypoint |
可以看到,确实是1320偏移
1 | .text:0000000000001320 public _start |
在某些情况下(如我们的示例中),程序的初始化阶段可能需要一些时间。由于每次迭代都要进行初始化,这直接影响了模糊测试的速度。这正是 AFL_ENTRYPOINT 选项旨在解决的情况。
这样的话我们可以跳过初始化阶段,直达AFL_ENTRYPOINT 地址,停在AFL_ENTRYPOINT地址与fuzzer同步,让fuzzer对目标进行快照,之后便可有在AFL_ENTRYPOINT之后继续执行。
对于上面的例子,init函数是确定性的,也无需模糊测试,所以可以将AFL_ENTRYPOINT 设置为 parse_cert
parse_cert是1550偏移
1 | $ ./find_func.sh parse_cert |
通过AFL_ENTRYPOINT环境变量设置一下即可
1 | read fuzz_func_addr fuzz_func_size < <(find_func "parse_cert") |
可以看到确实更改了入口点
查看现在的速度,已经提升到600+,原始作者更牛逼,直接1000+,估计他的cpu性能更好
“持久模式”是AFL++的一个功能,允许它在每次迭代时避免调用 fork 。相反,它会在子进程到达特定地址( AFL_QEMU_PERSISTENT_ADDR )时保存其状态,并在到达另一个地址( AFL_QEMU_PERSISTENT_RET )时恢复该状态。
注意:如果没有设置 AFL_QEMU_PERSISTENT_RET ,可以使用 AFL_QEMU_PERSISTENT_RETADDR_OFFSET 。如果没有设置这些值,AFL++将在到达第一个 ret 指令时停止(仅当 AFL_QEMU_PERSISTENT_ADDR 指向函数的起始位置时,否则必须手动设置该值)。
“恢复”状态可能意味着“恢复寄存器”( AFL_QEMU_PERSISTENT_GPR )和/或“恢复内存”( AFL_QEMU_PERSISTENT_MEM )。由于恢复内存状态的成本较高,只有在必要时才应该进行;在模糊测试时,要关注稳定性值,以确定是否需要启用此功能。
使用 AFL_QEMU_PERSISTENT_GPR=1,QEMU将保存通用寄存器的原始值,并在每个持久周期中恢复它们。
即使在使用持久模式时,AFL++ 仍会不时调用 fork (每 AFL_QEMU_PERSISTENT_CNT 次迭代,或默认为1000次)。如果稳定性足够高,增加此值可能会提高性能(最大值为10000)。
目标中循环越稳定,您可以运行的时间就越长;循环越不稳定,循环计数值就应该越低。一个较低的值可以是100,最大值应该为10000。默认值是1000。可以使用AFL_QEMU_PERSISTENT_CNT来设置此值。
在上面的例子,以通过将 AFL_QEMU_PERSISTENT_ADDR 设置为与 AFL_ENTRYPOINT 相同的值(即 parse_cert 函数的地址)来开始。这样,AFL++将恢复进程到在读取输入文件内容之前的状态。
1 | read fuzz_func_addr fuzz_func_size < <(find_func "parse_cert") |
在这个例子中,稳定性保持在100%而无需恢复内存状态,因此我们只设置 AFL_QEMU_PERSISTENT_GPR 。我们还将 AFL_QEMU_PERSISTENT_CNT 增加到最大值,因为这不会对我们的稳定性产生负面影响。
下面可以看到Persistent也设置为1660偏移, gpr开启
1 | $ AFL_DEBUG=1 ./fuzz.sh | grep Persistent |
再看看此时的速度是接近6000,速度有了10倍增长
尽管使用了持久模式,但在达到模糊函数之前,我们的目标仍然会执行一些不必要的操作,尤其是打开和读取由模糊器生成的文件的内容。
我们可以使用“内存模糊测试”来跳过这一步骤,直接从模糊测试器的内存中读取输入!
为了做到这一点,我们必须实施一个“hook’”。作者说这个源码比较简单,源码地址
定义了一个 afl_persistent_hook_init 函数,它声明了我们是否要使用内存模糊测试
1 | int afl_persistent_hook_init(void) { |
更有趣的是,我们定义了一个函数afl_persistent_hook
,可以在每次迭代之前覆盖寄存器值和内存,就在达到 AFL_QEMU_PERSISTENT_ADDR 地址之前。我们所要做的就是覆盖包含要解析的缓冲区的内存,并在正确的寄存器中设置其长度。
1 | #define g2h(x) ((void *)((unsigned long)(x) + guest_base)) |
作者是受afl++的示例启发的: https://github.com/AFLplusplus/AFLplusplus/blob/stable/utils/qemu_persistent_hook/read_into_rdi.c
注意:您可以通过运行 gdb 并在目标函数的开始的地方中断,或直接查看反汇编代码来确定要使用的寄存器。
这个钩子应该被编译为一个共享库,AFL++将在运行时加载它。
要指示AFL++使用我们的hook,我们只需将 AFL_QEMU_PERSISTENT_HOOK 设置为我们 .so 文件的路径:
1 | export AFL_QEMU_PERSISTENT_HOOK="$BASEPATH/src/hook/libhook.so" |
要使用内存模糊测试,需要在迭代过程中跳过read_file的调用,需要修改 AFL_QEMU_PERSISTENT_ADDR ,这里有两个选项:
1、将AFL_QEMU_PERSISTENT_ADDR 设置为 base64_decode 的起始地址。在这种情况下,我们还要对 base64_decode 函数进行模糊测试;
2、或者我们将AFL_QEMU_PERSISTENT_ADDR 设置在 parse_cert_buf 。在这种情况下, base64_decode 将不会被测试。
由于 base64_decode 是由一个我们不想进行模糊测试的可信外部库实现的(在这种情况下是OpenSSL),我们将选择第二个选项。
因此,我们可以将 AFL_QEMU_PERSISTENT_ADDR 移动到 parse_cert_buf 的地址:
1 | read fuzz_func_addr fuzz_func_size < <(find_func "parse_cert_buf") |
修改 AFL_QEMU_PERSISTENT_ADDR 对我们的语料库有影响。事实上,模糊测试器生成的缓冲区现在直接用于 parse_cert_buf (而不是传递给 base64_decode )。这意味着我们需要重建我们的语料库。在我们的情况下,这很容易:我们只需要解码之前语料库中的base64文件,并将它们保存为原始二进制文件。
1 | base64 -d test.cert.b64 > test.cert |
这样我们不再从文件中读取数据,但是目标程序期望从一个文件中读取数据,否则它将立即退出。,所以我们需要创建一个空文件,传递给程序。
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
在Debug模式中也有successfully got fuzzing shared memory
1 | $ AFL_DEBUG=1 ./fuzz.sh | grep AFL |
注意:由于执行速度并不是唯一重要的指标,当然你还应该关注其他指标,比如稳定性、新发现的路径、覆盖率等等。
回顾一下我们迄今为止取得的成就:
在大多数情况下,这样的配置足以运行成功模糊测试,尤其是与多处理器结合的时候。
然而,对于这个例子,我们还决定使用高度结构化的数据格式为输入进行模糊测试。
在这种情况下,引入新的方式来改变输入数据可能会很有趣。
确实,AFL++的另一个可调节的方面是生成和变异逻辑。AFL++内置了一组简单(但非常有效)的变异方法:
在大多数情况下,这些突变已足够用来探索代码进行模糊测试。但是某些数据格式具有内部约束,如果不满足这些约束,样本将被提前拒绝。
这就是ASN.1的情况,这是我们示例中使用的格式:如果在生成突变时不考虑这些约束,可能会导致大多数样本被目标系统立即丢弃为无效样本,从而无法实现任何增加的覆盖率。这意味着模糊测试活动需要一段时间才能收敛到相关的生成案例,影响fuzzing的效率或者直接导致毫无成果。
为了解决这种情况,AFL++允许用户提供自定义的变异器,以指导模糊测试工具生成更适合的输入。正如官方文档中所详细说明的那样,只要这个变异器实现了所需的API函数,就可以将其插入到AFL++中。
有几种方法可以在AFL++中实现语法感知的变异器,其中之一是AFL++项目中的语法变异器。
然而,由于它不支持ASN.1,我们转而依赖于处理ASN.1的libprotobuf。
我们从官方文档和现有的框架中汲取灵感,构建了AFL++和我们自定义变异器之间的“粘合剂”。
最终实现为 custom_mutator.cpp
实现了以下来自AFL++ API的函数:
确实, afl_custom_post_process 函数发挥着重要的作用:我们的自定义变异器基于libprotobuf,因此需要protobuf数据作为输入。然而,我们的目标只能解析ASN.1数据,因此我们需要将数据从protobuf转换为ASN.1。幸运的是,protobuf变异器已经在 x509_certificate::X509CertificateToDER 中实现了这个功能。
以下是整个过程:
实际就是将输入通过afl_custom_fuzz进行变异,再通过afl_custom_post_process将数据从protobuf转换为ASN.1
和以前一样,我们需要调整我们语料库中文件的格式,以与我们的模糊测试工具相匹配。这一次,我们需要将我们的ASN.1 DER文件转换为protobuf格式。为此,我们实现了一个自定义脚本(asn1_to_protobuf.py)
只需将 AFL_CUSTOM_MUTATOR_LIBRARY 设置为我们 .so 文件的路径
1 | export AFL_CUSTOM_MUTATOR_LIBRARY="$BASEPATH/libmutator.so" |
禁用了AFL++执行的所有默认变异和修剪操作
1 | export AFL_DISABLE_TRIM=1 |
这一次,不是关于提高性能,而是关于深入探索更深层次的路径。在我们的例子中,这是一个非常小的目标,很难衡量这种影响。
然而,通常会通过比较覆盖范围并使用自定义变异器来检查是否达到了新的分支来完成此操作。
然而,您无需在使用自定义变异器和使用默认的AFL++变异器之间做出选择:通过运行多个模糊测试实例,您可以兼得两者的优点,我们将在下一步中讨论这个问题。
(from实践者:由于这个使用了谷歌的proto,编译出了点问题,暂时放弃这个的实践)
这一步是我们将所有内容整合在一起来运行我们的实际模糊测试活动。实际上,在真实的活动中,你不会仅限于在一个核心/线程/机器上进行模糊测试。幸运的是,AFL++可以同时运行多个实例。
在同一台机器上,由于AFL++的设计方式,有一个最大的CPU核心/线程数量是有用的,使用更多的核心会导致整体性能下降。这个值取决于目标,限制在每台机器32到64个核心之间。
需要注意的是,即使在达到这个限制之前,性能的增加也不是成比例的(核心数量翻倍并不意味着每秒执行次数翻倍):需要额外的开销来同步进程。
当运行多个模糊测试实例时,可以通过并行使用各种策略和配置来优化覆盖率。然而,由于该页面主要针对源代码可用的模糊目标,因此对于仅有二进制代码的模糊测试,需要进行一些调整。
当对源代码可用的目标进行模糊测试时,许多功能(例如ASAN、UBSAN、CFISAN、COMPCOV)需要使用特定选项重新编译目标。
尽管在处理二进制目标时重新编译不是一个选项,但是QEMU中仍然提供了一些这些功能
例如, AFL_USE_QASAN 可以使用 LD_PRELOAD 自动注入库来使用 ASAN 和 QEMU。同样, AFL_COMPCOV_LEVEL 可以在 QEMU 中使用 COMPCOV,无需重新编译目标。
下面的start_child用来启动子进程
1 | children=() |
1 | # Run 1 afl-fuzz instance with CMPLOG (-c 0 + AFL_COMPCOV_LEVEL=2) |
1 | $ /AFLplusplus/afl-whatsup -s output/ |
查看edges、crashes执行速度随实践变化的情况
1 | $ /AFLplusplus/afl-plot output/afl-main /tmp/plot |
通过afl-showmap输出覆盖情况
1 | "$afl_path/afl-showmap" -Q -C -i "$output_path"/afl-main/queue/ -o afl-main.cov -- "$target_path" /tmp/.afl_fake_input |
一旦AFL++识别出崩溃或卡死,它将把触发它的输入保存在您的输出目录中的一个专用文件夹中,以便您可以重现它。
下面是一些有用的工具:
没合并之前,有个人搞了个Blender,据说是Automatic whole-program fuzzing,就是不需要编写模糊目标函数,而是直接接受要测试的二进制文件(最好是使用了内存检测和覆盖率的编译结果,但不需要修改源代码)。
https://github.com/dvyukov/centipede/tree/dvyukov-blender/blender
根据README的描述,此工具是拦截系统调用,忽略程序的所有输出(写入磁盘/网络的数据),并向输入提供随机数据(从磁盘/网络读取的数据)。
此外,运行一个随机的未知二进制文件是不安全的(它可能会格式化磁盘、删除文件等)。系统调用拦截的第二个重要作用是隔离。在 Blender 下,二进制文件完全被隔离,并且不会对真实世界产生任何影响。这使得可以安全地运行带有随机输入的随机二进制文件。
Blender 有2种使用模式:
1、独立使用:在这种模式下,二进制文件以随机方式执行一次。
2、结合Centipede使用,Centipede 其实类似于libfuzzer,二进制文件将使用Centipede进行循环测试。
构建Blender
1 | bazel build -c opt blender:all |
以bash为例
1 | git clone https://git.savannah.gnu.org/git/bash.git |
运行二进制文件并使用 Blender 进行模糊测试(在运行时进行模糊测试)
1 | LD_PRELOAD=/XXX/XXX/bazel-bin/blender/blender.so ./bash |
但是会报错:
1 | blender.cc:238: FAIL: close_range (errno: Function not implemented) |
后来发现close_range() 是一个 Linux 特定的系统调用,它在内核版本 5.9 中被引入。而ubuntu 20.04的默认内核是5.4,所以使用下面命令升级内核
1 | apt update |
上面使用了LD_PRELOAD,如果你可以将一个额外的库链接到二进制文件中,那么你可以链接 bazel-bin/blender/libblender.pic.lo 代替。
如果没有检测到错误,它将不会打印任何内容并以0状态退出(没有正常输出和状态)。如果检测到错误,将打印错误报告并以非0状态退出。
作者说可以与压力工具一起用作一种简易的模糊测试工具
1 | go get golang.org/x/tools/cmd/stress |
build Centipede 和 Blender
1 | bazel build -c opt :all blender:all |
使用一些额外的标志构建目标二进制文件
1 | CC=clang CFLAGS="-fsanitize=address,undefined -g -fno-builtin -fsanitize-coverage=trace-pc-guard,pc-table,trace-cmp" \ |
使用Centipede运行
1 | mkdir /tmp/workdir |
然而,在Linux上恢复已删除的进程二进制文件是很容易的,只要该进程仍然在内存中。
在 Linux 系统中,/proc/<PID>/exe
文件是一个特殊的符号链接文件,它指向当前正在运行的进程所执行的可执行文件。即使该可执行文件已经被删除,该符号链接仍然存在,并且可以继续指向被删除的文件。
这是因为 Linux 系统中的文件删除实际上是通过引用计数来处理的。当一个文件被打开或执行时,系统会为该文件增加一个引用计数。只有当该文件的引用计数降为零时,才会将其删除并释放磁盘空间。
所以恢复已删除的进程二进制文件的基本命令很简单。
1 | cp /proc/<PID>/exe /tmp/recovered_bin |
下面以sleep命令来模拟一个已从磁盘中删除的进程。您可以在自己的Linux系统上安全地运行这一系列命令,以便练习恢复已删除的二进制文件。
1 | cd /tmp |
1 | # root @ ubuntu in ~ [16:37:43] |
可以看到文件确实不存在了,进程还在运行
1 | $ ps -aux | grep 3600 |
我们ls查看,可以看到文件被标记为删除了
1 | $ ls -al /proc/13499/exe |
我们用cp恢复
1 | cp /proc/13499/exe /tmp/recovered_bin |
可以看到文件完好无缺
1 | # root @ ubuntu in /tmp [16:40:38] |
假如这正是一个病毒木马,你可以可以在安全的虚拟环境中,使用调试器和ida去分析了。
所以,绝不要轻易杀掉你发现的可疑进程,你可能失去获取病毒木马的机会。
如果系统感染了某种病毒,请将其隔离在网络中,然后慢慢查看。不要急于行动,因为这样会破坏关键数据。
]]>二进制污染是篡改系统命令并用恶意版本替换它。这可以是全面替换为一个新文件,设计成像旧命令一样运行,或者篡改原地可执行文件,使其直接运行恶意代码。
如果一个毫不知情的用户运行了一个被污染的命令,就是以该用户身份运行攻击者想要执行的代码。
下面的shell模拟污染/bin/ls
注意:不要在生成环境中进行下面的实验操作!!!
注意:不要在生成环境中进行下面的实验操作!!!
注意:不要在生成环境中进行下面的实验操作!!!
1 | # root @ ubuntu in ~/tmp [16:09:03] |
当然上面是写了无害的echo \"POISONED /bin/ls active!\"
,我们可以做任何shell可以做的操作,添加crontab,往authorized_keys添加公钥,下载木马等等。
可以看到ls已经被我们污染了
1 | $ ls /tmp/ |
如果手动去寻找,非常耗时,且很难下手。在Ubuntu系统中,仅在/bin和/sbin目录下就有500多个命令。如果再加上/usr/bin和/usr/sbin目录,那就有数千个命令了。因此,首先要尝试的是运行软件包验证来加快这个过程。
假如是Redhat based的系统,可以执行rpm -Va | grep ^..5.
假如是Debian/Ubuntu based的系统,可以apt安装debsums,执行debsums -c
下面我以Ubuntu为例,可以看到,debsums 很快发现了/bin/ls不对劲
1 | # root @ ubuntu in ~ [16:11:56] |
假如上面debsums 没有发现任何内容,接下来我们需要手动操作,查找不是ELF的可执行文件,当然攻击者可以用另一个编译好的二进制文件替换一个二进制文件。但是替换shell是最容易实现的
比如针对/bin目录: file /bin/* | grep -v ELF | grep -v link
, grep -v link
是忽略掉软链接文件
1 | $ file /bin/* | grep -v ELF | grep -v link |
我们可以看到这里也有/bin/ls,而且还是个Bourne-Again shell script,这就很有问题了。
如果你怀疑某个命令可能被篡改,请直接使用strings命令查看是否有任何可疑内容。不要对你认为可能是恶意文件的任何文件运行strace命令。我们将这一点用粗体标出,因为有些人可能想尝试strace命令,但实际上运行strace会在主机上运行实际的可执行文件,这是一个非常糟糕的想法。
1 | $ strings /bin/ls |
可以看到这里还有隐藏目录/bin/.bin/
最后我们用rm -rf /bin/.bin/ && mv /bin/ls.bak /bin/ls
来恢复ls
https://sandflysecurity.com/blog/detecting-linux-binary-file-poisoning/
]]>对Linux进程进行取证,可以通过/proc/<PID>/environ
来查看某个进程的环境变量,来获取一些信息。
所以说,遇到可疑的进程不要立即杀掉,不然取证都可能无从下手。
当在Linux上启动一个进程时,该进程的许多环境变量将在其运行期间保持不变。那么虽然启动该进程的原始shell已经消失很久,但在有一些shell变量仍然继承下来了。
在进程的环境变量中可以获得什么呢?
history anti-forensics的证据
二进制文件的命令行和路径
启动进程的用户
启动时二进制文件使用的自定义变量,可能包含密钥和其他内容
SSH连接信息:哪个ip启动的
……
对于第5点,即使攻击者从日志中清除了他们的IP地址,如果他们通过SSH进入,很有可能他们使用的IP地址仍然留在他们启动的进程中,等待被获取。
假如我们是攻击者,连上一台机子的ssh
注: HISTSIZE是一个环境变量,用于控制命令历史记录的大小。通过将HISTSIZE设置为0,即export HISTSIZE=0,实际上是告诉操作系统不保存任何命令历史记录。这意味着你运行的每个命令都不会被记录下来,无法通过上下箭头键或history命令访问之前执行的命令。
ssh连上后我们在机子上执行
1 | export HISTSIZE=0 |
通过列出正在监听的端口,可以查看到一个x的可疑进程。
1 | $ netstat -antp | grep LISTEN |
查看进程环境变量(我手动将ip用X打码了)
1 | $ strings /proc/16343/environ |
从上面我们可以提取出下面有用的信息
HISTSIZE=0,这个说过了,属于反取证的方式
SSH_CONNECTION=10.82.X.X 5561 172.16.2.3 22 这个比下面的多了本机的网卡的ip
SSH_CLIENT=10.82.X.X 5561 22 这两个就是ssh的信息,10.82.X.X就是攻击者所使用的ip,该ip或许只是攻击者的跳板
SHELL=/bin/bash 启动所使用的shell
PWD=/tmp 启动时的路径
OLDPWD=/root 进入/tmp目录之前的路径
USER=root 启动进程的用户
可以看到,在调查进程活动之前,不要草率地终止可疑的进程。在弄清楚进程活动之前就终止进程,会立即丢失许多有用的信息,比如进程环境变量。
https://sandflysecurity.com/blog/using-linux-process-environment-variables-for-live-forensics/
]]>fuzz端就两个功能,发送新增的样本或者crash,以及接收新样本
会对corpus_dir和crash_dir的文件创建进行hook,一旦有新的文件创建,就调用__send_seed
和__send_crash
函数, afl的fuzzer_stats文件有修改也会调用__send_telemetry
发送
1 | # Configure hookds on workspace |
下面就是发送函数
1 | def __send_seed(self, filename: Path): |
在class AFLPPDriver
类的__init__
函数会调用self.__setup_agent()
来初始化回调函数
1 | def __setup_agent(self): |
接收函数
1 | def __seed_received(self, typ: SeedType, seed: bytes): |
通过add_seed可以看到,通过md5文件名存储,说明通过md5去重的
1 | def add_seed(self, seed: bytes): |
下面是收到样本(seed)的回调函数
1 | def register_seed_callback(self, cb: Callable) -> None: |
在set_proxy函数中会设置这个回调函数
1 | def _register_all(self): |
而在PastisBroker类的__init__
函数会调用self._register_all()
,收到种子后就调用seed_received函数
可以看到这里哦天哪故宫md5计算,但是没用来判断,只是用_seed_pool
这个字段判断,
1 | def seed_received(self, cli_id: bytes, typ: SeedType, seed: bytes): |
比如它支持GitHub Actions,GitLab,Google Cloud Build和Prow,我们最常见到的应该是GitHub Actions
ClusterFuzzLite 重用了 OSS-Fuzz 工具链来简化构建。这意味着 ClusterFuzzLite 将在 docker 容器中构建您的项目。所以加入你熟悉OSS-Fuzz,这就看着很像了。只不过多了一些参数,比如–external
有一个问题就是他这个只支持libfuzzer!!!,所以局限性还是有的。
首先环境的配置好:
首先需要在项目根目录新建.clusterfuzzlite
文件夹,包含下面三个文件
上面的文件不用我们新建,可以使用命令新建模板
1 | $ cd /path/to/oss-fuzz |
以https://github.com/libexpat/libexpat.git
为例
1 | cd / && git clone https://github.com/libexpat/libexpat.git expat |
主要编辑build.sh文件即可,主要最后编译出来的fuzzer需要复制到$OUT即可
1 | cd $SRC/expat/ |
上搞完就可以本地测试了
模板命令
1 | $ python infra/helper.py build_image --external $PATH_TO_PROJECT |
实际命令
1 | python infra/helper.py build_image --external $PATH_TO_PROJECT |
假如没问题说明build.sh写得没问题,环境库依赖也没问题
这将检查您的模糊测试目标是否使用正确的sanitizer编译,并且在模糊测试几秒钟后不会崩溃。
1 | $ python infra/helper.py check_build --external $PATH_TO_PROJECT --sanitizer <address/undefined/memory> |
1 | $ python infra/helper.py run_fuzzer --external --corpus-dir=<path-to-temp-corpus-dir> $PATH_TO_PROJECT <fuzz_target> |
<path-to-temp-corpus-dir>
就是宿主机你自己准备好的种子文件路径<fuzz_target>
是编译出来的fuzzer的名字
1 | $ python infra/helper.py build_fuzzers --external --sanitizer coverage $PATH_TO_PROJECT |
步骤4是可选的,run_fuzzer没问题即可就行了
ClusterFuzzLite可以以pull request为触发,也可以cron定时触发
下面就以GitHub Actions为例了,需要在.github/workflows目录新建文件
1 | .github/workflows/cflite_pr.yml (for PR fuzzing, pull request为触发) |
之后展示了一些默认的配置设置,默认配置已经适用于大多数项目
.github/workflows/cflite_pr.yml
1 | name: ClusterFuzzLite PR fuzzing |
字段解析:
language: 更改为目标代码的语言
sanitizers: 更改或启用更多消毒剂。
fuzz-seconds: 更改模糊测试的时间。
parallel-fuzzing:使用并行模糊测试。
接下是.github/workflows/cflite_batch.yml
1 | name: ClusterFuzzLite batch fuzzing |
.github/workflows/cflite_build.yml
1 | name: ClusterFuzzLite continuous builds |
.github/workflows/cflite_cron.yml
1 | name: ClusterFuzzLite cron tasks |
之后将代码都提交github,之后在Actions那里可以看到Workflow
此外谷歌官方人员也有个curl示例
1 | https://github.com/oliverchang/curl/ |