抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

如果你问我人生梦想是什么?

我可能会说:有什么天天嫖麦当劳优惠券狠狠吃更棒的事了呢😋

QQ图片20230211161756

本文所谈及技术只为网络安全人员进行服务器检测或维护参考,仅供学习交流,请勿用于违法用途。

(碰壁了很多次,js代码经过混淆的可读性很差,代码量太大期间火狐崩溃了好几次😭)

页面: aHR0cHM6Ly9jZG4ubWNkLmNuL2Ntcy9wYWdlcy9RUXdhbGxldC5odG1s

首先抓取一键领取的数据包进行分析

image-20230211142133997

image-20230211142210032

  • 尝试修改receiveQuantity为2,返回领取失败

对比两次请求可以发现,payload没有发生变化,改变的是请求头的NonceStSign参数,而且容易看出St参数是时间戳,Nonce参数是时间戳拼接了一段字符串

image-20230211142648570

而请求前并未有GetSign相关请求,因此考虑是js本地进行Sign的生成,定位Onclick过程的js

image-20230211143940188

  • 尝试搜索请求的url:/bff/member/coupon/bind,缩短为/coupon/bind搜索,发现couponsBind函数(后续弯弯绕绕没有发现有用信息)

image-20230211150434753

尝试搜索:sign,结果太多;搜索.sign,设置断点调试,得出Object(i.sign)(t,{})i.sign是个函数对象,对 t 进行处理,返回了sign

image-20230211152011752

image-20230211152205363

发现c(e)里调用了u(n,t)进行处理,继续断点调试,我们深入到该函数,发现调用了e(b)

image-20230211153057317

image-20230211153219409

我们将所有相关的函数全部扒到本地,并把一些固定字符串列表的索引给直接取出字符串来赋值(x = test[1] -> x = ‘helloworld’)

// "e0a803e042c3f658cf31d9b09454f914"
var n =
{
    wordsToBytes: function (e) {
    for (var t = [
    ], n = 0; n < 32 * e.length; n += 8) t.push(e[n >>> 5] >>> 24 - n % 32 & 255);
    return t
  },
    bytesToHex: function (e) {
    for (var t = [
    ], n = 0; n < e.length; n++) t.push((e[n] >>> 4).toString(16)),
    t.push((15 & e[n]).toString(16));
    return t.join('')
  },
}
function a(e) {
    var t = [
    ];
    for (var n in e) t.push(n);
    return t
}
function r(e) {
    var t = [
    ];
    for (var n in e) t.push(e[n]);
    return t
}
function e(e, t) {
    if (null == e) throw new Error('Illegal argument ' + e);
    var n = r.wordsToBytes(u(e, t));
    return t && t.asBytes ? n : t && t.asString ? a.bytesToString(n) : r.bytesToHex(n)
}
var u = function (o) {
    var i = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {
    },
    u = {
        "data": {
          "channelCode": "03",
          "coupons": [
            {
              "couponId": "156BBFBC389F9EA666E2FACD40BC5605",
              "receiveQuantity": 1,
              "newUserFlag": 0
            },
            {
              "couponId": "45F09AFEE6E455A7175B1085C5012321",
              "receiveQuantity": 1,
              "newUserFlag": 0
            }
          ],
          "pageId": "lRLlag9R"
        },
        "params": {},
        "path": [],
        "headers": {
          "ct": "ct=10",
          "nonce": "nonce=1676061464467544235",
          "sid": "sid=c9643a4402552c67ca7a5a75cdee70b4_",
          "st": "st=1676061464"
        },
        "url": "https://api.mcd.cn/bff/member/coupon/bind"
    };
    u.headers.ct = u.headers.ct || 10;
    var c = u.headers.ct,
    s = o.env,
    l = '71d414c0-8fe1-495d-ac55-207414632479';
    // s || (s = u.url.match(/-dev\./) ? 'dev' : u.url.match(/-sit\./) ? 'sit' : u.url.match(/-uat\./) ? 'uat' : u.url.match(/-pt\./) ? 'pt' : 'prd'),
    n[s] && (l = n[s][c] || t[c]),
    Array.isArray(u.path) || (u.path = [
    ]);
    var f = {
    };
    a(u.params).sort().forEach((function (e) {
      (0 === u.params[e] || !0 === u.params[e] || !1 === u.params[e] || u.params[e]) && (!0 === u.params[e] ? f[e] = e + '=true' : !1 === u.params[e] ? f[e] = e + '=false' : f[e] = e + '=' + u.params[e])
    })),
    u.params = f;
    var d = {
    },
    p = [
      'ct',
      'language',
      'ov',
      'p',
      'sid',
      'token',
      'v',
      'st',
      'nonce'
    ];
    a(u.headers).sort().filter((function (e) {
      (0 === u.headers[e] || u.headers[e]) && p.includes(e) && (d[e] = e + '=' + u.headers[e])
    })),
    u.headers = d;
    var h = [
    ],
    v = 101 === c || 102 === c ? '#' : '&';
    if ('#' === v && h.push(r(u.headers).join(v)), u.data) {
      var y = "{\"channelCode\":\"03\",\"coupons\":[{\"couponId\":\"156BBFBC389F9EA666E2FACD40BC5605\",\"receiveQuantity\":1,\"newUserFlag\":0},{\"couponId\":\"45F09AFEE6E455A7175B1085C5012321\",\"receiveQuantity\":1,\"newUserFlag\":0}],\"pageId\":\"lRLlag9R\"}";
      '{}' !== y && h.push(y)
    }
    var m,
    g = r(u.params).join(v);
    if (g && h.push(g), h.push(u.path.join(',')), '&' === v && h.push(r(u.headers).join(v)), (h = h.filter((function (e) {
      return e && '{}' !== e
    }))).length > 0) {
      l ? h.push('key=' + l) : console.warn('[WARN] ct='.concat(c, ' is not in pre-defined keys.'));
      var b = h.join(v);
    //   i.debug && console.log('[DEBUG] @omc/api-signer - plainText: ', b),
      m = e(b)
    }
    return m
  };
n = {
    "params": {
      "putChannel": "03",
      "pageId": "lRLlag9R",
      "cityCode": "310100",
      "sid": "c9643a4402552c67ca7a5a75cdee70b4_"
    },
    "headers": {
      "common": {
        "Accept": "application/json, text/plain, */*"
      },
      "delete": {},
      "get": {},
      "head": {},
      "post": {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      "put": {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      "patch": {
        "Content-Type": "application/x-www-form-urlencoded"
      },
      "tid": "00003TuM",
      "sid": "c9643a4402552c67ca7a5a75cdee70b4_",
      "sv": "v3",
      "nonce": "1676058630105631320",
      "st": 1676058630,
      "ct": 10
    },
    "url": "https://api.mcd.cn/bff/member/page/coupon/customer/getable"
  };
bgg = "{\"channelCode\":\"03\",\"coupons\":[{\"couponId\":\"156BBFBC389F9EA666E2FACD40BC5605\",\"receiveQuantity\":1,\"newUserFlag\":0},{\"couponId\":\"45F09AFEE6E455A7175B1085C5012321\",\"receiveQuantity\":1,\"newUserFlag\":0}],\"pageId\":\"lRLlag9R\"}&ct=10&nonce=1676060716058879900&sid=c9643a4402552c67ca7a5a75cdee70b4_&st=1676060716&key=71d414c0-8fe1-495d-ac55-207414632479"
// "cityCode=310100&pageId=lRLlag9R&putChannel=03&sid=c9643a4402552c67ca7a5a75cdee70b4_&ct=10&nonce=1676058630105631320&sid=c9643a4402552c67ca7a5a75cdee70b4_&st=1676058630&key=71d414c0-8fe1-495d-ac55-207414632479"
console.log(e(bgg));

尝试运行,结果栈溢出报错,因为发生了死循环

image-20230211154011725

  • 补充nonce和st的获取
  • image-20230211160113556

经过分析,我们发现,u(e,t)并不是前面所提到的u,而是一个新的函数。而且关键性的,我们发现了该函数下存在1732584193等幻数,这些是MD5加密的特征

image-20230211154505128

所以e(b)本质就是将 b 进行了MD5加密,我们断点调试截获 b 来验证一下

image-20230211155415536

image-20230211155952042

成功破解sign的加密逻辑🎉🎉

后续:尝试写个python脚本

import time
import random
import hashlib
import requests

st = int(time.time())
nonce = str(st) + str(round(999999 * random.random())) + '000'
m = f"cityCode=310100&pageId=lRLlag9R&putChannel=03&sid=b4ccde8d6f2e6256ddfce3b3f4ef3dca_&ct=10&nonce={nonce}&sid=b4ccde8d6f2e6256ddfce3b3f4ef3dca_&st={st}&key=71d414c0-8fe1-495d-ac55-207414632479"
sign = hashlib.md5(m.encode('UTF-8')).hexdigest()
print(st, nonce, sign)

data = {"channelCode": "03", "coupons": [{"couponId": "156BBFBC389F9EA666E2FACD40BC5605", "receiveQuantity": 1, "newUserFlag": 0}, {
    "couponId": "45F09AFEE6E455A7175B1085C5012321", "receiveQuantity": 1, "newUserFlag": 0}], "pageId": "lRLlag9R"}
url = 'https://api.mcd.cn/bff/member/coupon/bind'
headers = {
    'Host': 'api.mcd.cn',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0',
    'Accept': 'application/json, text/plain, */*',
    'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
    'Accept-Encoding': 'gzip, deflate',
    'Content-Type': 'application/json',
    'tid': '00003TuM',
    'sid': 'b4ccde8d6f2e6256ddfce3b3f4ef3dca_',
    'sv': 'v3',
    'nonce': f'{nonce}',
    'st': f'{st}',
    'ct': '10',
    'sign': f'{sign}',
    'Content-Length': '220',
    'Origin': 'https://cdn.mcd.cn',
    'Referer': 'https://cdn.mcd.cn/',
    'Sec-Fetch-Dest': 'empty',
    'Sec-Fetch-Mode': 'cors',
    'Sec-Fetch-Site': 'same-site',
    'Te': 'trailers',
    'Connection': 'close'
}
# res = requests.get('https://api.mcd.cn/bff/member/page/coupon/customer/getable?putChannel=03&pageId=lRLlag9R&cityCode=310100&sid=b4ccde8d6f2e6256ddfce3b3f4ef3dca_',headers=headers)
res = requests.post(url=url, headers=headers, data=data)
print(res.text)

草,竟然报错显示缺少参数,怎么回事呢😢(在Burp-Proxy截获的数据包中success,Burp-Repeater则不行)

{"success":false,"code":400,"message":"缺少参数","datetime":"2023-02-11 16:04:17","traceId":"3563b509-808d-4582-907d-19fe5a2feb6e","data":null}

看来无法实现自动发包领取了,然后就狠狠的进行了脚本录制🥬给两个号都嫖了四百张券(

image-20230211161407478

QQ图片20230211161756

后续:第二天已修复(火速)🐶😡

评论