×

一、环境准备

CentOS 7 安装 Ruby

参照:https://blog.csdn.net/fredricen/article/details/142205493

(1)确定系统版本

 cat /etc/os-release

(2)安装RVM

RVM是一个linux下的Ruby的多版本管理工具,可以维护多个Ruby版本,切换版本。对于开发Ruby应用程序比较友好。还有个优点就是不需要梯子,对于国内用户友好。

安装GPG的key,用于身份验证

 gpg2 --keyserver keyserver.ubuntu.com --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB

安装RVM最新稳定版本

 \curl -sSL https://get.rvm.io | bash -s stable

(3)安装Ruby的前置依赖—更新 gcc

 yum install centos-release-scl -y

执行成功后,系统会生成:

 /etc/yum.repos.d/CentOS-SCLo-scl.repo
 /etc/yum.repos.d/CentOS-SCLo-scl-rh.repo

更新gcc版本,默认为4.8.5版本,最好升级到7以上版本,此处升级到9,升级gcc版需要先更新yum源

 vi /etc/yum.repos.d/CentOS-SCLo-scl.repo

修改此部分的baseurl为阿里云源

 [centos-sclo-sclo]
 name=CentOS-7 - SCLo sclo
 baseurl=https://mirrors.aliyun.com/centos/7/sclo/x86_64/sclo/
 # mirrorlist=http://mirrorlist.centos.org?arch=$basearch&release=7&repo=sclo-sclo
 gpgcheck=0
 enabled=1
 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-SCLo

还有

 vi /etc/yum.repos.d/CentOS-SCLo-scl-rh.repo

修改此部分的baseurl为阿里云源

 [centos-sclo-rh]
 name=CentOS-7 - SCLo rh
 baseurl=https://mirrors.aliyun.com/centos/7/sclo/x86_64/rh/
 # mirrorlist=http://mirrorlist.centos.org?arch=$basearch&release=7&repo=sclo-rh
 gpgcheck=0
 enabled=1
 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-SCLo

最后刷新缓存

 yum repolist
 yum clean all
 yum makecache

正式升级gcc版本

 yum install devtoolset-9-gcc* -y

启用新版gcc

 scl enable devtoolset-9 bash

使当前的终端立即生效:

 source /opt/rh/devtoolset-9/enable

(4)安装指定版本的Ruby

 CC=/opt/rh/devtoolset-9/root/usr/bin/gcc rvm install 3.2.4

查看RVM使用的当前Ruby版本

 rvm list

二、正式破解

参照:https://blog.17lai.site/posts/29a820b3/

(1)确保已安装ruby

ruby版本需要2.3或以上。

(2)生成许可证

 gem install gitlab-license

(3)创建一个rb文件

 nano license.rb
 require "openssl"
 require "gitlab/license"
 
 key_pair = OpenSSL::PKey::RSA.generate(2048)
 File.open("license_key", "w") { |f| f.write(key_pair.to_pem) }
 
 public_key = key_pair.public_key
 File.open("license_key.pub", "w") { |f| f.write(public_key.to_pem) }
 
 private_key = OpenSSL::PKey::RSA.new File.read("license_key")
 Gitlab::License.encryption_key = private_key
 
 license = Gitlab::License.new
 license.licensee = {
  "Name" => "none",
  "Company" => "none",
  "Email" => "example@test.com",
 }
 license.starts_at = Date.new(2020, 1, 1) # 开始时间
 license.expires_at = Date.new(2050, 1, 1) # 结束时间
 license.notify_admins_at = Date.new(2049, 12, 1)
 license.notify_users_at = Date.new(2049, 12, 1)
 license.block_changes_at = Date.new(2050, 1, 1)
 license.restrictions = {
  active_user_count: 10000,
 }
 
 puts "License:"
 puts license
 
 data = license.export
 puts "Exported license:"
 puts data
 File.open("GitLabBV.gitlab-license", "w") { |f| f.write(data) }
 
 public_key = OpenSSL::PKey::RSA.new File.read("license_key.pub")
 Gitlab::License.encryption_key = public_key
 
 data = File.read("GitLabBV.gitlab-license")
 $license = Gitlab::License.import(data)
 
 puts "Imported license:"
 puts $license
 
 unless $license
  raise "The license is invalid."
 end
 
 if $license.restricted?(:active_user_count)
  active_user_count = 10000
  if active_user_count > $license.restrictions[:active_user_count]
    raise "The active user count exceeds the allowed amount!"
  end
 end
 
 if $license.notify_admins?
  puts "The license is due to expire on #{$license.expires_at}."
 end
 
 if $license.notify_users?
  puts "The license is due to expire on #{$license.expires_at}."
 end
 
 module Gitlab
  class GitAccess
    def check(cmd, changes = nil)
      if $license.block_changes?
        return build_status_object(false, "License expired")
      end
    end
  end
 end
 
 puts "This instance of GitLab Enterprise Edition is licensed to:"
 $license.licensee.each do |key, value|
  puts "#{key}: #{value}"
 end
 
 if $license.expired?
  puts "The license expired on #{$license.expires_at}"
 elsif $license.will_expire?
  puts "The license will expire on #{$license.expires_at}"
 else
  puts "The license will never expire."
 end

赋予文件执行权限

 chmod +x license.rb

执行文件

 ruby license.rb

执行结果如下:

 [root@localhost ~]# ruby license.rb
 License:
 #<Gitlab::License:0x00007f63b4f04758>
 Exported license:
 eyJkYXRhIjoia25rRFVkZEhDZmxlMDR6dWcxcEhYdzd2ckQzVnJHZDB2YVJD
 ZzY2UWZ5cDAyVkpHTUdDMFUyMzFrL2VTXG5KQ0pNQXZYUkt1ZzQ5ZEx6UytM
 R0d1ak9YTU1uK1RwTzFNM21kdkxkWTFnaEJWZHNzbHpWbUZvMU5CcHJcbkYy
 K3dqZEoxbzI4NlRneFpKNnJnUWNQRnQyRzQ3ODI0MEtmdVZCbDQyWXEyc2t4
 bVhhM2J1Q04vb1M0c1xuZU50ZnEwdFlKaDlKbXhERHFEMElYUU5aTWhXZ2kw
 ZnNYVmhXbG1wODFZTWJKdHpueWxJcHlvMlhlK1hBXG5OU2M2TEFUUk56M0V6
 U2t6dkJ0cjNBcS8rMjVoZ2hXVXlJNjRwOEZsVWUrN3pPMlVzd0RsMS9CQitH
 SEdcblNZdjRCNmJpeCtob0ZSSzcvVGRWYVFRR3VINCtKOWc3dUtGdnBscUdU
 WW41ZThOYWw3anluUzB0M3BqTFxuc1dNTWRKNW5CVW8rTklFVzc0NFVRME9x
 cys0ZklLTmo2N0ltQ0xqVzgvcWVQUGdwWU84OEk2Y3kxZzM2XG5iNjMvODRU
 dHVVdVNCbmM3R09iWTFKbFBTRnd2bC91MXRrZTU2VzlFUXBCdUVvN3FlaTNE
 d0VzM0dEOFNcbm1IWGRWdHBTVW9XTXA0dnprMTF5dk5Nb0JKRlBuS0dyaFJU
 bXlCbVBsUGFxdlo2UEQxUHVhZ2w3YUp6U1xuekdrOTJMMEZMb2NPb0RXQzVK
 TjNZMmpYMmNmbmt6SWQwbVNMN2dQSlRNMnVORmM3THFKa3ZOTjFhSE1iXG4v
 bVRzblBpRWhvMUNUZHptRWJwUmFmTUgvMGdKaTl4a0dJaHlCbklGUy9yNWJa
 QmhMMTFQcDFUakdqRWFcbkxFUlNqbmdtSzNjWjNVNHZpQTVUem01Z3dFQlA0
 RStnY2Z5U0dTTmlQMTRLUmZVS1h0YW9TNVM0WFQ0VlxueGRpaGw5OXliejNw
 VkJUcEd0UEx0ZEhrZnhTdE85SXNHMWViNEh5Wm5BcFlMVEJ1NUFkUVlUYmZV
 RGFPXG5MdjFBb2pha3VRPT1cbiIsImtleSI6ImZveHkySkFSbVBYejNaSmpE
 VXViSTA0Skw5dUp2UmdXYnFBMnpqOWtiaDB5Wi9Ick5EMHowclg1akIveFxu
 SDVldStpeVRMbU5NYml1YWNEM0RtM0lBcUJaVGgyTDE3NG8xT2tnWUFhekli
 QmNCVzN0RjhpdXhYOUFVXG5DQ01Nc1QrNXZoblJrSmY1RW50blhKOExQY1Vx
 RHBhcnRHVXVDb1JvRTEyUlRWaExrYnFJcHVuUFN0Qmdcbk9qNTcvSklhVEZ0
 VWVWbENVb1BnNXJiaDFkVjBDK2dRcjlKWU9jZkZ2dXczS3BMUnZ3cFd3ZGNn
 N0gzVFxuSjkyelIwMWJSYkN3TEQ4U2FaQUhYdG1YRUJTRDlLUDluby9tQVEy
 Z09CYTI3UnZ3c0J3NHhjdHE4WW1oXG44akFzT2NOQzkwaDhPYnhxVC9NVy9u
 dGJQcDBlNUp0MnljU1ZoOVdZZXc9PVxuIiwiaXYiOiJ5ZWhhaW1qcDdhTFdo
 ZUhqdnB2SkVBPT1cbiJ9
 Imported license:
 #<Gitlab::License:0x00007f63b5022090>
 This instance of GitLab Enterprise Edition is licensed to:
 Name: none
 Company: none
 Email: example@test.com
 The license will expire on 2050-01-01

生成 GitLabBV.gitlab-license license_key license_key.pub 这三个文件。

(4)使用许可证

 docker-compose restart gitlab

license_key.pub 文件替换 /opt/gitlab/embedded/service/gitlab-rails/.license_encryption_key.pub(容器内部地址)

相当于自己生成公钥替换原有公钥,验证自己签的许可证。

注意:替换完之后,先重启容器,然后再输入许可证(私钥)验证,不然公钥还是没替换前的,验证肯定不成功。

GitLabBV.gitlab-license 即是许可证,填入 ${address}/admin/license 地址。

也就是上面执行代码后输出的私钥秘钥,在GitLab前端root账号下,打开管理员后台设置里面填入这个秘钥验证。

Gitlab EE V18.4.1破解成功

破解版风险问题

主要涉及 Service Ping / Usage Ping / Subscription sync 【可以自己禁用】

防火墙完全阻断对外出站(尤其到 version.gitlab.comcustomers.gitlab.com 等服务域名/IP)的网络流量,实例就无法发包到外网

订阅/许可证同步(license/subscription sync)【来自官网】

Your subscription data is automatically synchronized once a day between your GitLab Self-Managed instance and GitLab. 您的订阅数据每天会在您的 GitLab 自管理实例和 GitLab 之间自动同步一次。

At approximately 3:00 AM (UTC), this daily synchronization job sends subscription data to the Customers Portal. For this reason, updates and renewals might not apply immediately. 大约凌晨 3:00(UTC),此每日同步作业会发送 订阅数据已上传至客户门户。因此,更新和续订可能不会立即生效。

The data is sent securely through an encrypted HTTPS connection to customers.gitlab.com on port 443. If the job fails, it retries up to 12 times over approximately 17 hours. 数据通过加密的 HTTPS 连接安全发送到 端口 443 上的 customers.gitlab.com 。如果作业失败,它会在大约 17 小时内重试最多 12 次。

Usage / Service Ping(遥测 / 用量统计)【来自官网】

GitLab 有一套Usage Ping / Service Ping,用于收集聚合的后端使用数据(feature usage、活动计数等)

Usage statistics | GitLab Docs

破解机制—自己生成密钥对,篡改验证机制(替换公钥)

GitLab 官方许可证机制是基于 公钥签名体系

GitLab 的许可证系统(gitlab-license gem)使用 RSA 签名验证

  • 官方 GitLab 公司持有一对密钥:
    • 私钥(保密,用来签发许可证
    • 公钥(嵌入在 GitLab EE 程序中,用来验证许可证真伪

许可证签发流程:

  1. 官方用自己的私钥对许可证信息(license 内容)做签名;
  2. GitLab EE 在启动时,用内置的 公钥 验证签名;
  3. 验证通过 → 许可证合法; 验证失败 → 报 “Invalid license”。

我们是在本地生成的 license_key / license_key.pub另一对新的密钥对, 并不是 GitLab 官方那一对。


为什么能“自己生成”?

因为 GitLab 的许可证验证逻辑是开源的(在 gitlab-license gem 和 EE 源码中), 你可以用相同算法生成密钥并签名,只是默认的验证用的是官方公钥。

换句话说:

  • GitLab 的代码里会去 /opt/gitlab/embedded/service/gitlab-rails/.license_encryption_key.pub 读取验证公钥;
  • 如果你替换了这个文件(用你自己生成的 license_key.pub), 那验证过程就会变成:“用你自己的公钥验证你自己签的许可证”。

于是——验证当然能通过。 这就是为什么你能“自己生成许可证”,并且 GitLab 不会报错。

会不会被官方检测发现?

🧩 一、GitLab “是否会主动上传验证数据”

答案:不会自动上报许可证文件本身。 但它确实会在默认情况下上传统计信息(Telemetry / Service Ping),其中包含许可证摘要字段。

这些数据的关键部分在:

 /opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/usage_data.rb
 /opt/gitlab/embedded/service/gitlab-rails/lib/gitlab/usage_data/service_ping_report.rb

里面的逻辑会收集以下数据:

  • 当前版本(Community / Enterprise)
  • 激活用户数、项目数
  • 许可证信息摘要(不是许可证文件内容
  • 安装域名(hostname)
  • license_sha(许可证文件的 SHA 校验摘要)

然后通过 HTTP(S) 上报至:

 https://version.gitlab.com/

GitLab 官方称这是“Service Ping telemetry”。 默认开启,但可以在配置中禁用。


⚙️ 二、禁用 Telemetry 的配置方法(官方支持)

/etc/gitlab/gitlab.rb 中添加:

 gitlab_rails['usage_ping_enabled'] = false

然后:

 gitlab-ctl reconfigure

也可以在管理员界面关闭:

Admin → Settings → General → Metrics and profiling → “Usage statistics” → 取消勾选

这会阻止 GitLab 发送任何统计数据给官方服务器。


🧱 三、实际依据(源码与日志可验证)

你可以直接在容器内执行:

 grep -R "version.gitlab.com" /opt/gitlab/embedded/service/gitlab-rails/

你会发现它确实是通过 ServicePingWorker 异步任务发送统计的。 你也可以查看计划任务:

 gitlab-rake gitlab:usage_data

这个命令会输出它打算上传的所有字段。

你会看到有类似:

 "license_sha": "8f9b7c8b23...",
 "license_md5": "c5d...fae"

但没有原始许可证内容。

📘 结论:只要禁用 usage_ping,就不会上传任何许可证相关信息。


🧠 四、为什么 GitLab 无法“主动检测破解”

因为:

  1. GitLab 服务器端的许可证验证完全在本地 Ruby 逻辑中执行
  2. 没有“远程验证签名”步骤;
  3. 只要你禁用了 usage_ping,它就没法远程知道;
  4. GitLab 没有像 Windows、Adobe 那样的远程激活机制。

⚠️ 所以除非:

  • 你开启了 Telemetry;
  • 或者你访问了官方 SaaS 服务(gitlab.com); 否则官方服务器根本无法感知你是否修改了 .license_encryption_key.pub

🧾 五、来自实际部署经验(GitLab 社区与企业)

很多中国公司或个人自托管 GitLab EE 时, 为了避免误上传信息,都会:

  • 在配置里禁用 usage_ping
  • 禁止服务器访问外网(或仅限私有镜像源);
  • 使用私有 DNS 或防火墙阻断 version.gitlab.com

实际验证: 抓包 (tcpdumpiptables -L) 后,没有任何外发请求时,GitLab 后台是完全自循环运行的


✅ 六、总结结论(可验证的事实)

检查点说明风险
License 验证本地执行无远程检测
License 上传仅摘要随 telemetry 发送可关闭
Telemetry 开关支持关闭(配置或后台)建议关闭
远程验证机制不存在(未连接 GitLab SaaS)无风险
法律风险有(违反授权协议)⚠️ 理论上存在

⚖️ 七、最终总结一句话

自托管 GitLab EE,替换验证密钥属于本地行为; 官方默认不会检测,也不会上报许可证内容; 只要禁用 usage_ping,就不会有外部网络包发送

⚠️ 但这属于“技术可行、授权非法”行为,不建议用于企业或公网环境。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

作者

fffff@xf.nn

文章推荐