The third question of the second semester of Apemanology (vmp confusion)

If you think the article is good, please give it a like! ! ! Kowtow! ! !

Article Table of Contents

statement:

Reverse goal:

Reverse process:

result:

Statement:

All content in this article is for learning and communication only. Packet capture content, sensitive URLs, and data interfaces have been desensitized. Commercial and illegal use is strictly prohibited. Otherwise, all consequences arising therefrom will have nothing to do with the author. If there is any infringement, please contact me to delete it immediately!

Reverse target:

  • Goal: The third question of the 2nd Ape Man Web Defense Competition: VMP with obvious encryption traces
  • Links: 3 – Shou Xin – The 2nd Ape Man Science Web Offensive and Defense Competition

Reverse process:

Open the F12 debugging window, refresh the page, and see that the request parameters require page and token.

Set an xhr breakpoint in the source panel and successfully break at line 646. You can see that our token value has appeared. At the same time, observing the value on the right, we find that keywords such as SM3 have appeared. We might as well infer that the token is obtained through SM3 encryption.

By comparing standard SM3 encryption and browser SM3 encryption on the Internet, you can determine that the browser has magically modified the standard SM3 encryption.

Make a log breakpoint (recording point) at line 645. Fe is the calling function and all the parameters passed in, and we[1] is the name of the called function.

Refresh the page again, wait for the log output to be completed, look up the sm3Digest function and observe the incoming parameters. This parameter is the timestamp + page number.

The next step is to compare the logs to find the differences. First, find a standard SM3 algorithm. Here I use the one from this article, just copy it.

Set a conditional breakpoint at line 645, compare it with the standard SM3 algorithm and find that the initial value of reg in the reset function is different, and change it to the browser value.

Observe the log again to locate the strToBytes function. This function forwards the string into Unicode encoding. Comparing the local value and the browser value multiple times, we can see that the even values are the same, and the odd values are reduced by one.

Just add an if statement when the value is added to the list.

Observe the _t function and return value. Here it magically changes the return value of the function, replacing the local value with the browser value.

Reposition the _compress function and change these three values to 4244635647, 4294967290, and 4289724415 respectively. Because there is no log output for these three, it is troublesome to single-step debugging, so I won’t explain too much here.

/**
 * National secret SM3 encryption {JS implementation}
 *
 * Reference https://blog.csdn.net/Shen_yuanjia/article/details/111879819
 *
 * @returns
 */
function SM3() {
if (!(this instanceof SM3)) {
return new SM3();
}

this.reg = new Array(8);
this.chunk = [];
this.size = 0;

this.reset();
}

SM3.prototype.reset = function() {
this.reg[0] = 1937770108;
this.reg[1] = 1983173321;
this.reg[2] = 385893078;
this.reg[3] = 3666375988;
this.reg[4] = 2701930684;
this.reg[5] = 353449901;
this.reg[6] = 3816598093;
this.reg[7] = 4008382286;
this.chunk = [];
this.size = 0;
};

/**
 * Convert string to byte array
 */
SM3.prototype.strToBytes= function (s) {
  var ch, st, re = [];
  for (var i = 0; i < s.length; i + + ) {
    ch = s.charCodeAt(i);
if ((ch % 2) != 0){
ch -= 1
}
    st = [];
    do {
      st.push( ch & amp; 0xFF );
      ch = ch >> 8;
    }
    while(ch);
    re = re.concat( st.reverse() );
  }
  return re;
};

SM3.prototype.write = function(msg) {
var m = (typeof msg === 'string') ? this.strToBytes(msg) : msg;
this.size + = m.length;
var i = 64 - this.chunk.length;
if (m.length < i) {
this.chunk = this.chunk.concat(m);
return;
}

this.chunk = this.chunk.concat(m.slice(0, i));
while (this.chunk.length >= 64) {
this._compress(this.chunk);
if (i < m.length) {
this.chunk = m.slice(i, Math.min(i + 64, m.length));
} else {
this.chunk = [];
}
i + = 64;
}
};

/**
 * Calculate hash value
 */
SM3.prototype.sum = function(msg, enc) {
if (msg) {
this.reset();
this.write(msg);
}

this._fill();
for (var i = 0; i <this.chunk.length; i + = 64) {
this._compress(this.chunk.slice(i, i + 64));
}

var digest = null;
if (enc == 'hex') {
digest = "";
for (var i = 0; i < 8; i + + ) {
digest + = this.reg[i].toString(16);
}
} else {
var digest = new Array(32);
for (var i = 0; i < 8; i + + ) {
var h;
h = this.reg[i];
digest[i * 4 + 3] = (h & 0xff) >>> 0;
h >>>= 8;
digest[i * 4 + 2] = (h & amp; 0xff) >>> 0;
h >>>= 8;
digest[i * 4 + 1] = (h & 0xff) >>> 0;
h >>>= 8;
digest[i * 4] = (h & 0xff) >>> 0;
}
}

this.reset();
return digest;
};

SM3.prototype._compress = function(m) {
if (m < 64) {
console.error("compress error: not enough data");
return;
}
var w = this._expand(m);
var r = this.reg.slice(0);
for (var j = 0; j < 64; j + + ) {
var ss1 = this._rotl(r[0], 12) + r[4] + this._rotl(this._t(j), j)
ss1 = (ss1 & amp; 4244635647) >>> 0;
ss1 = this._rotl(ss1, 7);
var ss2 = (ss1 ^ this._rotl(r[0], 12)) >>> 0;
var tt1 = this._ff(j, r[0], r[1], r[2]);
tt1 = tt1 + r[3] + ss2 + w[j + 68];
tt1 = (tt1 & amp; 4294967290) >>> 0;
var tt2 = this._gg(j, r[4], r[5], r[6]);
tt2 = tt2 + r[7] + ss1 + w[j];
tt2 = (tt2 & amp; 4289724415) >>> 0;
r[3] = r[2];
r[2] = this._rotl(r[1], 9);
r[1] = r[0];
r[0] = tt1;
r[7] = r[6]
r[6] = this._rotl(r[5], 19);
r[5] = r[4];
r[4] = (tt2 ^ this._rotl(tt2, 9) ^ this._rotl(tt2, 17)) >>> 0;
}
for (var i = 0; i < 8; i + + ) {
this.reg[i] = (this.reg[i] ^ r[i]) >>> 0;
}
};

SM3.prototype._fill = function() {
var l = this.size * 8;
var len = this.chunk.push(0x80) % 64;
if (64 - len < 8) {
len -= 64;
}
for (; len < 56; len + + ) {
this.chunk.push(0x00);
}

for (var i = 0; i < 4; i + + ) {
var hi = Math.floor(l / 0x100000000);
this.chunk.push((hi >>> ((3 - i) * 8)) & amp; 0xff);
}
for (var i = 0; i < 4; i + + ) {
this.chunk.push((l >>> ((3 - i) * 8)) & amp; 0xff);
}
};

SM3.prototype._expand = function(b) {
var w = new Array(132);
for (var i = 0; i < 16; i + + ) {
w[i] = b[i * 4] << 24;
w[i] |= b[i * 4 + 1] << 16;
w[i] |= b[i * 4 + 2] << 8;
w[i] |= b[i * 4 + 3];
w[i] >>>= 0;
}

for (var j = 16; j < 68; j + + ) {
var x;
x = w[j - 16] ^ w[j - 9] ^ this._rotl(w[j - 3], 15);
x = x ^ this._rotl(x, 15) ^ this._rotl(x, 23);
w[j] = (x ^ this._rotl(w[j - 13], 7) ^ w[j - 6]) >>> 0;
}

for (var j = 0; j < 64; j + + ) {
w[j + 68] = (w[j] ^ w[j + 4]) >>> 0;
}

return w;
};

SM3.prototype._rotl = function(x, n) {
n %= 32;
return ((x << n) | (x >>> (32 - n))) >>> 0;
};

SM3.prototype._t = function(j) {
if (0 <= j & amp; & amp; j < 16) {
return 2044544281;
} else if (16 <= j & amp; & amp; j < 64) {
return 2081922442;
} else {
console.error("invalid j for constant Tj");
}
};

SM3.prototype._ff = function(j, x, y, z) {
if (0 <= j & amp; & amp; j < 16) {
return (x ^ y ^ z) >>> 0;
} else if (16 <= j & amp; & amp; j < 64) {
return ((x & amp; y) | (x & amp; z) | (y & amp; z)) >>> 0;
} else {
console.error("invalid j for bool function FF");
return 0;
}
};

SM3.prototype._gg = function(j, x, y, z) {
if (0 <= j & amp; & amp; j < 16) {
return (x ^ y ^ z) >>> 0;
} else if (16 <= j & amp; & amp; j < 64) {
return ((x & amp; y) | (~x & amp; z)) >>> 0;
} else {
console.error("invalid j for bool function GG");
return 0;
}
};

/**
 * Equivalent to Array.from for browser compatibility Array.from is not supported by IE browser
 */
SM3.prototype.toArray = function(s, f){
var a = [];
for(var i=0; i<s.length; i + + ){
var t = s[i];
if(f){
t = f(t);
}
a.push(t);
}
return a;
};

/**
 * SM3 encryption main function
 *
 * @param msg
 * @returns
 */
function sm3Digest(msg){
var _sm3 = new SM3();
    var digest = _sm3.sum(msg);
    var hashHex = _sm3.toArray(digest, function(byte) {return ('0' + (byte & amp; 0xFF).toString(16)).slice(-2);}).join('');
    return hashHex;
}

Note: The accept-time parameter in the headers needs to be added during the request for verification. This parameter needs to be consistent with the timestamp of the token generation.

result:

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. Algorithm skill tree Home page Overview 55,433 people are learning the system