标签 MD5 下的文章

大家好,我是Java烘焙师。本文结合笔者的经验和思考,对灰度方案做个总结,重点介绍AB实验。

灰度在开发流程中非常普遍。先做小流量验证,确认无误后再推全,灰度过程中一旦发现系统异常、或业务指标异常,应立刻回滚。

灰度场景

  • 代码灰度:是最典型的灰度,灰度内做新逻辑,灰度外做旧逻辑

    • 既可以提供v2版本新接口给调用方服务,由调用方来做灰度切换
    • 也可以内部切灰度,做到调用方无感
  • 发版灰度:上线过程中,新版本服务实例不断增加,需考虑兼容新旧协议
  • 配置灰度:修改配置时,按服务实例灰度推送配置变更

灰度模式

  • 数字id尾号灰度:取id最后2位(百分比)、最后3位(千分比)、最后4位(万分比)等

    • 实现方式:id取模,例如 id % 100 < 灰度百分比,则命中灰度
    • 特点:简单,适用于绝大部分技术优化场景
  • 随机灰度:取一部分随机流量做灰度

    • 实现方式:ThreadLocalRandom.current().nextInt(100) < 灰度百分比
    • 之所以使用ThreadLocalRandom、而不是Random,是为了避免多线程竞争用于生成随机数的seed
  • A/B实验

    • 实现方式:分层实验、实验数据收集、离线统计
    • 特点:适用于小流量验证新业务功能的效果,整体方案相对复杂,需要技术基建

id选取

  • 业务id:如用户id、商品id等
  • 设备id:未注册/未登录用户,此时没有用户id,只能取设备的唯一标识

下面重点介绍一下A/B实验。

A/B实验

目的

  • 小流量验证新业务功能,正向显著则推至全量,否则继续迭代优化、或下线,避免功能过于臃肿
  • 用数据作为依据,避免想当然、拍脑袋决策

分层实验

主要目的是为了同时做多个实验,而不是给每个实验均分一部分流量。因为当同时进行的实验变多时,组合数量成倍增加,每个实验分到的流量就很少了。
有这几层结构:实验层、实验、分组

  • 实验层之间正交,可同时进行多个实验层的实验
  • 同一实验层的实验之间互斥,比如命中了实验1-1,就不会命中实验1-2。实验持有0到多个分桶,根据业务id可计算出桶号,进而知道命中哪个实验
  • 同一实验内有多个分组,包括1个对照组,和1到多个实验组,只会命中其中一个分组。分组持有0到多个分桶,根据业务id可计算出桶号,进而知道命中哪个分组

实验层、实验举例:

  • 展示实验层:根据页面进行划分,如首页、搜索页、推荐页、详情页等。每个页面作为一个实验层,每个实验层里可同时做多个展示实验
  • 算法实验层:根据场景进行划分,如相似推荐、搭配购推荐、个性化推荐、搜索排序、广告排序等。每个场景作为一个实验层,每个实验层里可同时做多个算法实验

image

哈希算法打散

要同时支持多个分层实验,核心在于通过哈希算法将每一层的流量打散,用于实现“均匀分流”和“层间正交”,使得流量在各个实验的效果正负抵消,才能得到真实的对比结果。
以下是计算实验层桶号的代码示例,实验桶号同理:

import com.google.common.hash.Hashing;
import java.nio.charset.StandardCharsets;

public class ABTestRouter {

    /**
     * 根据用户ID和实验层ID(实验层ID充当盐的角色),计算桶号 (0-99)
     */
    public static int getBucket(String userId, String layerId) {
        // 1. 拼接 Key: "layerId:userId"
        String key = layerId + ":" + userId;

        // 2. 使用 MurmurHash3 (32-bit)
        // Guava 的 murmur3_32_fixed 是线程安全的
        int hash = Hashing.murmur3_32_fixed()
                .hashString(key, StandardCharsets.UTF_8)
                .asInt();

        // 3. 取模并确保结果为正数
        // Math.abs(Integer.MIN_VALUE) 会返回负数,所以推荐使用位运算去除符号位
        return (hash & Integer.MAX_VALUE) % 100;
    }

    public static void main(String[] args) {
        String uid = "user_123456";
        
        // 不同层的流量是正交的(打散重新分配)
        System.out.println("展示层桶号: " + getBucket(uid, "layer_ui"));
        System.out.println("算法层桶号: " + getBucket(uid, "layer_algo"));
    }
}

之所以用murmurhash,而非md5,是因为md5是加密算法,计算开销更大,在AB实验中仅需均匀打散即可,无需担心根据哈希结果反推原文。
之所以把实验层id作为盐,是因为微小的输入差异都会导致哈希结果相差巨大,实现打散的效果。

实验数据收集

实验数据收集流程如下:

  • 在AB实验管理系统中配置实验信息:如实验盐值、桶号与实验组的映射关系等,可动态修改
  • 代码逻辑开发:

    • 引入实验sdk,sdk在启动、或配置变更时拉取实验信息,本地计算业务id的桶号,进而得到命中的分组
    • 对照组做当前逻辑,实验组1做逻辑1,实验组2做逻辑2
  • 在正式开始AB实验之前,先做AA分桶实验,模拟实验组、对照组的结果,判断是否均匀,避免分桶不均匀带来错误的实验结果
  • 实验开始,后端埋点:sdk发出后端埋点消息

    • 消息格式举例:业务id, 实验层id, 实验id, 分组id, 桶号, 触发时间
  • 实验过程:实验持续时间至少一周,覆盖工作日、周末/假期,避免受时间周期带来的波动影响
  • 离线统计实验效果:

    • 后端埋点数据导入曝光事件hive表
    • 业务DB数据导入行为事件hive表,如注册、登录、浏览、点击、收藏、加购、下单、支付等,取决于实验关注的业务指标
    • 把曝光事件、行为事件join起来,对比实验组、对照组的业务指标差异

image

以下是sql示例,代表从实验曝光后24小时内各个分组的转化率对比。

SELECT 
    e.group_id,
    COUNT(DISTINCT e.user_id) as exposed_users,
    COUNT(DISTINCT a.user_id) as converted_users,
    COUNT(DISTINCT a.user_id) / COUNT(DISTINCT e.user_id) as conversion_rate
FROM exposure_events e
LEFT JOIN action_events a ON e.user_id = a.user_id 
    AND a.event_time BETWEEN e.event_time AND (e.event_time + INTERVAL 24 HOUR)
WHERE e.experiment_id = 'ui_test_001'
GROUP BY e.group_id;

实验报表分析

评估实验结果是否正向、是否显著。了解统计学里的核心概念,能看懂实验报表即可。

p值

用来衡量实验结果是否显著,p值的含义是:假设实验组与对照组没有区别,此时观察到实验有差异的概率。一般要求 p < 0.05,也就是说实验结果显著的概率大于95%(1 - 0.05 = 95%

置信区间

在显著的前提下,用来衡量实验结果是否正向,代表业务指标的可能范围分布。
比如:实验结果里业务指标提升了1%,95%置信区间在[0.8%, 1.2%],则代表有95%的把握可以把业务指标提升至少0.8%、至多1.2%,效果正向。如果置信区间的下界是负数,就有可能是负向效果了,需要警惕。

以上就是灰度方案的总结了,欢迎讨论交流。

题目来源polar靶场

简单题

RE

逆向愈发重要,我们通过题目快速建立逆向的基础

顺便熟悉一下各个方向的基础知识,因为后续要求的知识栈很宽广

第一题:shell

这个题目的话应该是base加密

额,是upx壳,呃呃呃

我们通过main进行溯源,成功找到main函数

这个题其实可以直接看出来,我们通过动调获取flag也是后知后觉

image-20251218190139015.png

第二题:PE结构

这里我们还是直接尝试脱壳,结果发现不行

⚡Lenovo ❯❯ upx -d 'PE结构.exe'
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2025
UPX 5.0.0 Markus Oberhumer, Laszlo Molnar & John Reiser Feb 20th 2025

upx: PE结构.exe: NotPackedException: not packed by UPX

Unpacked 0 files.

我们拖入010editor

DOS头 和 NT头 就是 PE 文件中两个重要的文件头

一个 WORD 类型,值是一个常数 0x4D5A,用文本编辑器查看该值位‘MZ’,可执行文件必须都是'MZ'开头

这里是发现是DOS头被调改了

image-20251218190557580.png

我们修改成4D然后点击保存运行即可

第三题:拼接

用记事本打开看看

image-20251218191027165.png

然后我们改一下后缀打开看看

今年我们来看一下这个函数

image-20251218191408713.png

依旧是动调直接出flag

第四题:加加减减

这个好像有个反调试,我们不能直接运行过去

我们分析逻辑,就是讲输入的每一个字符减一,然后再与一开始的字符串比较

我们一开始用下面这个方式写的

然后我们用下面这个方式去写

多上一步使用Unicode去转化,就是进入到单纯的数值层级与计算

第五题:康师傅

这个是比较的加密的,我们没法直接获取flag

我们需要异或一下输入

这个比我们平时做的简单多了

第六题:另辟蹊径

这个题是提供了GUI界面的一个题目

我们拖进去ida找字符串没找到flag

这个看其他的wp说是需要用到一改值的工具,我们不去弄了

第七题:use_jadx_open_it

apk文件,用jadx打开,进入MainActivity

然后我们直接看最后的结果比较就行

第八题:re2

这个也是很简单,直接给flag

第九题:layout

这个我们直接提交flag不行,然后想到题目名字是layout,我们直接去layout那里去看看

我们全局搜索flag即可

第十题:Why32

这个有点怪

下面这个是主函数

这个也是对输入加密,进行加密之间的比较

我们让输入的数值加上2即可,减去2,这里被惯性误导了

由于数据为32位,且只有数字和字母,猜测经过了md5加密,到在线网站解密

还原出来时md5,然后还需要进行md5解密

第十一题:?64

递归加1

这个看起来很像是base加密

我们这样打印发现明显不是,然后我们推测和上一题是一个类型的题目

MD5 - CyberChef

用这个网站在线解密即可

第十二题:Sign Up

我们用的是ida9.1,这个自动把字符串打印出来

这个题目设置了分割符,特意留下了两位

然后md5解密即可

中等题

re

第一题:JunkCode

上来先来一个花指令

这个我们来去除一下花指令

花指令大概是在这个位置

但00411AC4为花指令,后面的内容无法被正常识别和解析,导致反编译失败

具体的操作方法是:选中内存地址00411AC4,

按U键进行undefine

image-20251218204328982.png

我们这样进行patch一下

按U键进行undefine

再选中00411AC5处按C键MakeCode

最后到函数头位置按P构建函数

然后我们成功还原,这里注意顺序不能错

先u,然后c,然后patch,然后再c,然后再p

这样之后花指令就还原出来了

这个我们没法动调,我们只能去还原一下这个逻辑了

第二题:RevMethod

我们通过字符串来追踪flag

全是flag我们看到

这个不是我们想要的

这个我们缺失了dll链接库,导致我们运行不了,然后我们缺失的好像也正好是那个部分

不是,我们这个题目的话提交最后flag就行了

第三题:逆一下子

这个题目一打开就是flag

然后我们跟进这个函数

这个需要Resource Hacker这个工具

这个我们没有工具,直接找答案

第四题:可以为师

这个题目直接给main函数就很舒服

这个迷宫题是我们第一次去做,想出一个迷宫pwn

如果它用的是 _getch()(常见于 Windows 控制台程序),那么 pwntools 无法交互,因为 _getch() 不走 stdin/stdout 管道。

所以我们pwntools的交互成功失败了

但在 Windows 上,完全自动化捕获 _getch() 程序的输出并响应非常困难。不过,我们可以采用一个 半自动但高效的爆破策略

_getch() 不接受管道输入 → 无法用 subprocess 控制

Windows 控制台程序的输出虽然可通过 subprocess 捕获(如果没重定向),但输入无法注入

真正的“爆破”(尝试所有路径)会因路径长度指数爆炸而不可行(你的路径已是最短)

起点 (1,1)

终点 $ 在 (14,6)

路径已通过 BFS 找到

这个交给ai给我写个就能出,原理的以后再去学习

sssssdddddwwaawwdddwddsssddwwddssdss

第六题:混淆Code?

奇偶分开处理

这个函数对于处理好的数值再次进行处理

这个函数是最后的检查,就是对后面的字节清零,然后和我们的输入比较,我们来逆推一下输入

首先我们先解决一下异或的问题,很长时间不写生疏了太多了

这里的话可以进行ida的动调,在动调中是可以看数值的,动调查看的话图片如下

image-20251227162429247.png

然后我们计算好md5提交上即可

腾讯云这个社区也是挺不错的

国内外常用的MD5在线解密网站-腾讯云开发者社区-腾讯云

第七题:Java_tools

题目给出一个jar包,对输入的数值进行了下述的加密

一个是add

一个是re1

这里的xor没有调用,我们逐步分析一下

首先对于每一位+3

然后加上了一个交换的颠倒的算法

写python逆向的时候遇到一些问题

str 类型是不可变的,也就是说你不能通过索引直接修改字符串中的某个字符,比如 str[i] = 'x' 是不允许的。

第八题:PY_RE

解密比较,这里说明不能通过动调的方式直接出flag

判断代码如下

加密代码如下,一开始看成endata了,看错了

打印出来我们的dict,其实这里的逻辑的话也不能,主要是忘了Dict这个了

字典长度26

然后丢给ai分析,牵扯字符映射之类的,今天很累,先不去纠结了。

高等题

下面一开始刷错了,刷成all了

misc

第一题:broken_hash

题目给了我们两个附件,一个是png,一个是tip

我们用010打开png发现末位存在flag

binwalk分离之后得到提示7bf21a26cd6

爆破密码即可

第二题:deep

题目给了我们提示,这里是运行之后的数据的结果存放的地方

然后题目还给了我们一个源代码

这个是用c++写的,简单的分析一下逻辑,取数组内的数值,4个4个叠加,只打印出来原先索引位置是4的数值

还有注意的是这里ide单位的转化,所以说这里不是一个个输入的,而是一组组的输入的,我们将其转化成字符的形式应该会有flag

然后我们还原的时候用上按位与,chr和ord这个底层的数值转化即可

之后将获取到的flag提交即可

第三题:爱你

打开一看,是一个png图片,然后进入misc的领域

cyndi-stego.png

我们用Stegsolve.jar这个工具,红绿蓝0位通道可看到压缩文件格式开头的十六进制文本

然后我们用010editor可以弄到一个加密的压缩包,压缩包里有部分提示

我们解密一下

然后解压压缩包即可获得flag

flag{01e979f6dd21cd325e05fc1405e76bfd}

第四题:caigou

这个是个压缩包爆破的题目,密码爆破之后如下

zaqqaz

用随波逐流梭一下就行了

flag{ae7e960d8e7ce40e2157285680e2a5e4}

第五题:东北话是最好的语言

这个是给了一个look.txt文件

这里开始是逆向的题目

我们base64解码之后可以获得一个图片

然后我们用010editor打开后看到base64:xxxx

然后我们将结果转化成纯字符,最后套上md5即可

flag{4d5193eaeb2b18aa7e4357078b7550f3}

re

第一题:test

这个题目是安卓逆向,安卓逆向和java逆向还是有很大的不同的

这里是第一个活动,是一个密码,这个其实不用管

这里是第二个活动,将图片改成压缩包了

然后我们将解压后的打开会发现有个安装包,然后改成图片打开会有一个flag

第二题:高卢战记

这个题目给了一个没见过的obj后缀,这个的话拖进ida是仍然可以分析的,我们ida识别出来汇编

根据沪这里的特殊的字符,我们推断是有凯撒加密,因为里面出现了一组非常“刻意”的字符 —— :、<、以及 d e f g,这几类刚好都可以由 十六进制字符集(0-9a-f)整体 ASCII +3 得到。

写一个ord和chr组成的脚本就行

第三题:逢七则变

这个我都打不开,解析的正确,和那个proxy的题目是一个情况,我们怀疑是有了加壳

工具对应的链接如下

XVolkolak 0.22 静态脱壳神器汉化版 - 吾爱破解 - 52pojie.cn

脱壳之后的效果如下

第四题:android

apk文件,我们用jadx打开,然后分析主函数

我们看到这里的有一部分加密是调用了so,我们需要分析so库的judge函数

这里需要注意一点,DES加密部分 "64781852" 和密钥 "123!@#zaqXSWqwer" 与实际的验证流程完全无关,只是独立的日志记录代码的加密

我们打开so文件

从下面这个图我们可以确定judge函数是sub_7D0函数

加密的算法如下,这里aes加密

这个是用AES S-Box加密的算法,解密的脚本如下

第五题:动态库

这个题目考的是反调试的相关知识

这个是给了一个dll的动态链接库,其中有个函数名是GetFlag

我们写个idapython提取一下unk_100166BC这个地址,idapython如下

提取之后的结果如下

然后我们将这个结果打印一下即可获取到最后的flag

然后我们将这里的可打印的拼组起来就是flag的形式

flag{84649ac8ca256511a52fc9359fa367a1}

第七题:最短路

这段就是个“手动走图计权重”的题:Path[u][v] 里存了边权,你每次输入一对 (a, b) 就把这条边的权重加到 sum,直到你输入的 b == 15 为止(最后那条到 15 的边在循环外再加一次)。

Judge() 里要求 sum == 26 才算对,并提示 Shortest path。

把给定的边列一下(有向边):

1→2=2,1→3=3

2→3=5,2→4=3,2→10=20

3→5=6,3→8=5

4→5=7

5→8=1,5→9=4

8→11=5,8→15=21

9→12=5

12→15=9

11→15=13

7→14=6,14→15=7(6→7=3)

这里的凑值我们直接交给ai分析

要凑到 26,最明显的一条(而且正好是最短路)是:

1 → 3 → 8 → 11 → 15
权重:3 + 5 + 5 + 13 = 26

所以你在程序里依次输入这几行就行:

1381115

第八题:Cre

这个题目对文件类型进行了魔改,导致我们的ida不能正常的的分析,我们需要给他改回去

之后就能看到主函数

我们还原出的dp如下

用 0-based 坐标 (行,列) 表示:

对应移动串(R=右,D=下):
R D R R R D D D D D R R R D

这里最大的金币是75,然后我们md5加密之后即可获得flag

web

第一题:swp

我们用我们存在g盘的扫描一下网站的目录发现了一个index.php文件

我们访问.index.php.swp之后可以看到网站源码

这里需要参数又匹配/sys.*nb/is,又要求这个参数含有sys nb,还不能是数组

这里我们传递足够长的数据失效,我们使用PCRE回溯次数限制绕过

flag{4560b3bfea9683b050c730cd72b3a099}

第二题:简单rce

打开时候看到php源码

image-20260114101945447.png

第三题:上传

image-20260114104216524.png

这里我们不能直接上传php文件,我们需要先尝试上传.htaccess

这里我们上传还是不行,我们.htaccess和base64编码的木马,之后我们可以获取flag

也可以用其他的方法,传一个
php_value auto_append_file .htaccess
#

第四题:php是世界上最好的语言

题目直接给源码

题目提示flag在$flag这个变量中

两处变量覆盖,$POST的值要在第一处就覆盖好

最后传参的时候用504[SYS.COM

image-20260114113648310.png

第五题:非常好绕的命令执行

也是直接给了php源码

if (!preg_match($blacklist,$evil) and !ctype_space($evil) and ctype_graph($evil)) 这一行是一个条件判断语句,检查拼接的恶意代码是否通过了黑名单检查,且不是纯空格字符,且是可打印的字符。

image-20260114114130473.png

第六题:这又是一个上传

这个重复写了

第七题:网站被黑

image-20260114114735224.png

有个base编码,解码后/n0_0ne_f1nd_m3/

之后我们获得php源码

image-20260114115356470.png

第八题:ezjava

我们最后一个练手看看java

题目给了一个提示

我们用jadx打开一下附件分析

image-20260114153936920.png

sqel注入

最后我们需要构造payload如下

然后我们编码一下

image-20260114154651506.png

第九题:veryphp

题目直接给了我们源码

这个题目我们先获得提示看看,通过提示我们可以写个脚本

image-20260114164110683.png

爆破出来之后是21475 ,然后我们可以成功过去flag的数值,至此成功获得flag

image-20260114164841027.png

第十题:Unserialize_Escape

仍然是直接给了php代码

字符串逃逸

传上这个payload

username=Z3r4yxxxxxxxxxxxxxxxxxxxx";i:1;s:6:"123456";}

然后就有flag

image-20260114165747343.png

第十一题:这又是一个上传

我们看页面源代码,发现是把检测程序的上传的安全机制写在前端js里面了

我们找到调试程序这里关闭js调试

image-20260114170531360.png

关闭之后我们就能成功的上传了,然后我们链接上shell,发现有个这个

/opt/polkit-0.105/src/programs/.libs/pkexec这是一个允许授权用户以其他用户(通常是 root)身份执行命令的程序。系统

自带的 pkexec 通常在 /usr/bin/ 下。这里它出现在 /opt 下的源码编译目

录中,说明这是出题人特意为我们准备的利用点。

用上面这个和文件,然后编译之后运行就能完成提权。

crypto

我们还差最后30积分,我们用密码来凑

第一题:babyrsa

这个扔进去可以直接锁掉

image-20260114172338022.png

第二题:easyrsa

ai直接就能出

image-20260114171945483.png

第三题:classic

这个题目题目给的很少

只给了下面这个内容

FGAFDAXAGXDGDXAXAGDDAFDAAFFGFDAFGX

第四题:分段解密

crypto的内容如下

[[3202805436L, 509716930L], [3140667873L, 1667141091L], [3173275598L, 2248305098L], [709283154L, 3416762332L]]

加密脚本如下

然后写个解密脚本

换个位置就行了

翻转一下就能获得flag

flag{1UHSUW_IJNIL_1s_galf}

第五题:数学大师

给了一个很大的程序,点进去是不断闯关,需要过三关

丢给ai之后就能通过,最后flag如下

第六题:堂吉诃德走入猪圈

txt文件

得到答案用MD532位小写加密套上flag{}
压缩包密码为数字

7c4e8e8bb3cebddba7cb7f70cdf8d1c.jpg

堂吉诃德分别对应” 678 5 56 67 “,找笔画,找出来是5748

md加密之后提交即可

第七题:大主教的猪

给我的提示很有限

大主教开的猪圈里的所有猪都不见了,你能帮大主教找到他们在哪吗?
hint:得到的结果小写套上flag{}提交。

大主教的猪.png

变种猪圈密码

3574224-20241227131108153-24878728.png

对照得出结果即可获得flag

flag{they_are_on_the_truck}
至此,我们polar的杯子到手了