Git提交时间篡改技术解析

本文深入探讨Git提交时间篡改技术,详细分析如何通过环境变量和Git命令修改提交时间戳,以及这种技术对代码审计和数字取证的影响。文章还提供了检测和防御这种时间篡改攻击的实用方法。

Commit Stomping:操纵Git历史以掩盖真相

简介

Commit Stomping是一种受时间戳篡改(timestomping)启发的技术,这是一种在攻击操作中使用的知名方法,通过操纵文件元数据来隐藏行动的真实时间。在Git中,Commit Stomping涉及修改提交时间戳,以误导观察者关于更改引入的时间。

这不是Git中的错误或漏洞。这是一个功能,当被误用时,可以用来伪装恶意或未经授权的更改,使得在审计、调查或代码审查期间难以建立准确的时间线。

为什么这种技术很重要

Git提交历史通常被依赖作为以下方面的真相来源:

  • 事件响应和取证时间线
  • 代码审计和合规性审查
  • 团队或开源环境中的归属认定

当提交时间戳被伪造时,确定更改的顺序及其来源变得更加困难。这在软件供应链安全、内部威胁和长期审计追踪的背景下具有重要影响。

Git如何跟踪时间

Git不仅存储发生了什么变化。它还存储关于谁进行了更改以及何时进行的元数据。每个提交包括两个不同的时间戳:

  • GIT_AUTHOR_DATE:内容最初编写的日期和时间
  • GIT_COMMITTER_DATE:提交最终确定到存储库中的日期和时间

在大多数工作流程中,这些值是相同的。然而,在重新基础、修改提交或由原始作者以外的人执行提交时会出现差异。

重新基础和修改场景

使用git rebasegit commit --amend会重写提交。Git保留GIT_AUTHOR_DATE但更新GIT_COMMITTER_DATE以反映更改被重写的时间。

1
git commit --amend

这会调整提交元数据而不改变创作时间,除非明确覆盖。

多个提交者

在协作工作流程中:

  • 开发人员可能创建补丁并通过电子邮件发送
  • 维护者或审阅者随后可能提交它

在这些情况下,作者和提交者可能在身份和时区上不同。如果时间戳没有标准化,这种差异可能会使取证分析复杂化。

手动时间戳控制

Git允许您通过环境变量控制两个时间戳:

1
2
3
GIT_AUTHOR_DATE="2025-05-01T10:00:00" \
GIT_COMMITTER_DATE="2025-01-15T15:30:00" \
git commit -m "Insert logic for token generation"

这使得合法的元数据保存或滥用伪造历史成为可能。

支持的时间戳格式

Git支持这些环境变量和--date标志的各种格式:

1. Git内部格式

1
<unix timestamp> <time zone offset>

示例:

1
GIT_AUTHOR_DATE="1700000000 +0100"

这表示2024年11月14日06:13:20 CET。

2. ISO 8601

1
2
GIT_AUTHOR_DATE="2024-11-14T06:13:20+01:00"
GIT_AUTHOR_DATE="2024-11-14 06:13:20 +0100"

3. RFC 2822

1
GIT_AUTHOR_DATE="Tue, 14 Nov 2024 06:13:20 +0100"

4. 相对时间

1
2
GIT_AUTHOR_DATE="2 weeks ago"
GIT_COMMITTER_DATE="yesterday"

5. 纪元时间

1
GIT_AUTHOR_DATE="@1700000000"

相当于"1700000000 +0000",除非另有指定。

使用自定义时间戳提交

Git允许您在创建时为提交分配任意时间戳。这意味着您可以伪造提交日期,使其看起来像是在完全不同的时间点完成的工作。这对于合法原因(如将历史代码移植到新存储库同时保留创作日期)可能很有用,但当被恶意使用时,它也是Commit Stomping的基础。

要使用回溯时间戳提交,您可以使用环境变量明确设置作者和提交者日期:

1
2
3
GIT_AUTHOR_DATE="2025-01-01T10:00:00" \
GIT_COMMITTER_DATE="2025-01-01T10:00:00" \
git commit -m "Backdated logic insert"

这将创建一个看起来像是在2025年初编写和提交的提交,无论实际制作日期如何。从时间线分析的角度来看,这与在该时间真正制作的提交无法区分,除非通过外部日志或镜像基础设施进行验证。

使用Commit Stomping重写历史

如果已经使用当前或不想要的时间戳进行了提交,您仍然可以返回并修改它。Git强大的历史重写工具使得事后伪造时间戳变得微不足道。这是Commit Stomping变得最有效的地方;重写现有提交以在 fabricated 历史上下文中植入或隐藏操作。

交互式重新基础

这种方法非常适合以受控方式更改一个或几个最近的提交:

1
git rebase -i HEAD~3

这将打开一个显示最后三个提交的编辑器。将要更改的提交的pick更改为edit。然后:

1
2
3
GIT_COMMITTER_DATE="2025-01-01T10:00:00" \
git commit --amend --no-edit --date "2025-01-01T10:00:00"
git rebase --continue

这将用您选择的日期替换原始时间戳,同时保持提交内容和哈希更改(因为Git哈希包括元数据)。这是在清理或操纵活动期间进行外科手术式踩踏的理想选择。

使用git filter-branch

如果您要重写更广泛提交集中的时间戳,或者想要针对历史深处的特定哈希,git filter-branch允许进行脚本化、大规模重写。

1
2
3
4
5
6
git filter-branch --env-filter '
if [ "$GIT_COMMIT" = "abc123" ]; then
    export GIT_AUTHOR_DATE="2025-01-01T10:00:00"
    export GIT_COMMITTER_DATE="2025-01-01T10:00:00"
fi
' -- --all

这会在所有分支中有选择地更改提交abc123的时间戳。您可以扩展逻辑以匹配作者名称、消息或范围。虽然功能强大,但filter-branch也是资源密集型的,并且没有备份就无法撤消。

考虑改用git filter-repo。它更快、更灵活,并且对大型存储库更安全。

自动化Commit Stomping

如果目标是隐藏更改的真实顺序或使存储库的时间线看起来嘈杂和随机,您可以自动化整个提交历史中的Commit Stomping。这会在时间线中引入熵,使得更难识别关键操作发生的时间。

这是一个使用filter-branch和随机Unix时间戳的简单示例:

1
2
3
4
git filter-branch --env-filter '
export GIT_AUTHOR_DATE="$(date -d @$((RANDOM % 1000000000 + 1000000000)))"
export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
' -- --all

此脚本随机将作者和提交者日期设置为宽纪元范围内的值。您可以调整随机性或针对特定范围,以将更改混合到特定时间框架中(例如,将后门放入旧发布周期中)。

这种方法嘈杂、不可逆,并且在无理由进行时是篡改的明显迹象,但在对抗性模拟或攻击操作中,它可以完全打破基于时间线的调查。

检测Commit Stomping

发现Commit Stomping并不总是直接的,特别是在快速移动的存储库或那些没有一致提交卫生的存储库中。然而,在取证审查、审计或一般源代码控制卫生检查期间,有明显的指标应该引起注意。

注意以下情况:

多个提交中相同或过于相似的时间戳

具有完全相同GIT_AUTHOR_DATE和GIT_COMMITTER_DATE的提交,特别是连续出现,表明自动化或手动回溯。当提交似乎反映逻辑上独立的工作部分时,这尤其可疑。

作者和提交者日期不匹配

如果作者日期明显早于提交者日期(例如,几个月或几年),可能表明重写或伪造的历史。虽然在重新基础或补丁应用期间有些差异是正常的,但大的差距应该被调查。

时间顺序不一致

出现顺序混乱的提交,其中较新的提交具有较早的时间戳,可能是历史操纵的迹象。虽然Git不强制执行严格的时间顺序,但这种提交的模式可以揭示篡改或恶意行动的迹象。

与外部日志的差异

将提交时间戳与您的CI/CD流水线、Webhook事件日志或镜像存储库进行比较。如果一个提交声称来自1月,但构建系统在4月首次看到它,那就是一个危险信号。

不寻常的历史回溯集群

如果一个贡献者突然开始提交大量具有遥远过去时间戳的代码,可能是试图插入或埋葬更改而不引起注意。

在受监管或高信任环境中定期审计提交元数据是供应链完整性的有价值部分。

防御Commit Stomping

Git是一个围绕灵活性和离线工作流程设计的分布式系统。这种灵活性包括让用户为提交分配任意时间戳,这也意味着Git不会验证提供的日期是否真实。如果您希望加强存储库以防止时间线操纵,以下措施将有所帮助:

要求和验证签名提交

GPG或SSH签名提交提供了一种验证提交者身份的方法。虽然这不能直接防止时间戳篡改,但它增加了一层问责制,并有助于检测未经授权的重写尝试。将签名检查集成到您的CI流水线中,并拒绝受保护分支上的未签名提交。

在摄取时捕获元数据

在更改进入您的生态系统的点记录提交事件 - 这可能是CI/CD流水线中的时间戳记录、Git服务器中的审计追踪,或存储在日志聚合器中的Webhook有效负载。这些摄取日志为更改实际发生的时间创建了一个外部参考点。

使用具有不可变存储的镜像存储库

将提交推送到安全位置托管的只读镜像。此镜像充当时间线的独立副本。如果有人在主存储库中重写历史,您可以与镜像进行比较以识别差异。

锁定历史重写

禁用主分支或受保护分支上的强制推送。这不会阻止某人在分叉或个人分支中重写历史,但它会防止未经授权的时间线更改在未经通知的情况下进入您的关键分支。

监控异常模式

使用提交分析工具或基本脚本来监视时间戳异常,例如大的日期差距、提交历史中的向后跳跃或旧日期提交的突发。将其与发布或合规周期中的定期手动审查配对。

最终,防御Commit Stomping是关于在开发过程周围建立信任和验证层。Git给了您绳子 - 团队是用它安全地构建还是上吊取决于这些控制措施的实施方式。

最终想法

Commit Stomping不是传统意义上的漏洞 - 没有漏洞利用,没有CVE,也没有即将到来的补丁。这是Git分布式和基于信任的设计的一个真实案例,可以转变为欺骗技术。问题不在于Git被破坏,而在于它隐含地信任用户。这种信任可能被滥用。

手动设置或重写提交时间戳的能力本质上并不坏。它通常用于实际原因,比如在导入旧项目时保留日期,将贡献与外部系统对齐,或整理混乱的提交历史。但在错误的手中,它可能被滥用来重写过去,掩盖更改真正进行的时间,隐藏恶意编辑,或甩掉任何试图追踪发生了什么以及何时发生的人。

在源代码控制成为安全边界一部分的世界中,假设Git日志的完整性已经不够好了。重要的是将版本历史视为可变的,除非证明 otherwise,并用提供外部验证的控制措施包围Git:CI/CD日志记录、签名提交、不可变镜像和行为监控。

如果您正在模拟高级对手,响应内部威胁,在事件期间审查代码历史,或构建强化的开发流水线,操纵时间戳的能力必须是您威胁模型的一部分,并且意识到各种攻击的影响是关键。如果您不寻找它,您就不会看到它 - 如果您不防御它,您将在取证追踪中留下一个安静的间隙。

归根结底,Git讲述了一个故事。Commit Stomping让您重写该故事的时间线,并沿途更改一些关键细节。

Git链接:https://github.com/ZephrFish/CommitStomping-Info

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计