base64是一种基于用64个可打印字符来表示二进制数据的表示方法。它通常用作存储、传输一些二进制数据编码方法。

base64 编码原理:

base64 取 3byte 的输入数据,放在 24bit 的缓冲区中,从高位往低位放置。不足 3byte 的,于缓冲区剩下bit 用0补足。然后,每次取出6个bit,按照其值选择
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/中的字符作为编码后的输出不断转换,直到输入数据全部转换完成。 如果剩下两个输入数据,则编码后的结果加上一个= ;如果剩下一个输入数据,则编码后的结果加上两个=。 编码后的字符串长度是原来的4/3。

base64编码详情可看:
Base64算法原理

0x1 base64 编码

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
<?php
static $base="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
$specialchar="=";
function c_base64_encode($src){

global $base,$specialchar;
$slen=strlen($src);
$smod=($slen%3);
$snum=floor($slen/3);
$desc=array();
for($i=0;$i<$snum;$i++){
$_arr=array_map('ord',str_split(substr($src,$i*3,3)));

$_dec0=$_arr[0]>>2;
$_dec1=(($_arr[0]&3)<<4)|($_arr[1]>>4);
$_dec2=(($_arr[1]&0xF)<<2)|($_arr[2]>>6);
$_dec3=$_arr[2]&63;
$desc=array_merge($desc,array($base[$_dec0],$base[$_dec1],$base[$_dec2],$base[$_dec3]));
}
if($smod==0){
return implode("",$desc);
}
$_arr=array_map('ord',str_split(substr($src,$snum*3,3)));
$_dec0=$_arr[0]>>2;
if(!isset($_arr[1])){
$_dec1=(($_arr[0]&3)<<4);
$_dec2=$_dec3=$specialchar;
}else{
$_dec1=(($_arr[0]&3)<<4)|($_arr[1]>>4);
$_dec2=$base[($_arr[1]&7)<<2];
$_dec3=$specialchar;
}
$desc=array_merge($desc,array($base[$_dec0],$base[$_dec1],$_dec2,$_dec3));
return implode('',$desc);
}

?>

0x2 base64 解码

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
<?php 
static $base="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
$specialchar="=";
function indexOfBase($ch){
global $base,$specialchar;
if($ch==$specialchar){
return $ch;
}
return strpos($base,$ch);

}
function c_base64_decode($desc){
global $base,$specialchar;
$slen=strlen($desc);
$snum=$slen/4;
$src=array();
for($i=0;$i<$snum-1;$i++){
$_arr=array_map('indexOfBase',str_split(substr($desc,$i*4,4)));
$_src0=$_arr[0]<<2|$_arr[1]>>4;
$_src1=$_arr[1]<<4|$_arr[2]>>2;
$_src2=$_arr[2]<<6|$_arr[3];
$src=array_merge($src,array($_src0,$_src1,$_src2));
}
$_arr=array_map('indexOfBase',str_split(substr($desc,($snum-1)*4,4)));
if(in_array($specialchar,$_arr)){
$_src0=$_arr[0]<<2|$_arr[1]>>4;
if($_arr[2]==$specialchar){
$src=array_merge($src,array($_src0));
return implode("",array_map('chr',$src));

}else{
$_src1=$_arr[1]<<4|$_arr[2]>>2;
$src=array_merge($src,array($_src0,$_src1));
return implode("",array_map('chr',$src));

}

}
$_src0=$_arr[0]<<2|$_arr[1]>>4;
$_src1=$_arr[1]<<4|$_arr[2]>>2;
$_src2=$_arr[2]<<6|$_arr[3];
$src=array_merge($src,array($_src0,$_src1,$_src2));
return implode("",array_map('chr',$src));

}
?>

0x3 ctf 例题

例题1

通过观察下面编码,可以知道只是替换了base64 的对应表,以及输入数据不足3byte,编码结果添加的特殊填充值=。只要解码时,只要修改base64对应表和特殊填充值。

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
<?php
error_reporting(0);
require_once 'flag.php';

if (isset($_GET['get_string'])) {
print_r(c_base64_encode($flag_base64_more));
echo "<br/>";
if ($_GET['get_string'] === $flag_base64_more) {
echo "<br/>", "you are right", "<br/>";
}
}

function c_base64_encode($src){
static $base="1234567890-+!@#$%^&*()_+QWERTYUIOP{}|qwertyuiopASDFGHJKL:zxcvbnm";
$slen=strlen($src);
$smod = ($slen%3);
$snum = floor($slen/3);
$desc = array();
for($i=0;$i<$snum;$i++)
{
$_arr = array_map('ord',str_split(substr($src,$i*3,3)));
$_dec0= $_arr[0]>>2;
$_dec1= (($_arr[0]&3)<<4)|($_arr[1]>>4);
$_dec2= (($_arr[1]&0xF)<<2)|($_arr[2]>>6);
$_dec3= $_arr[2]&63;
$desc = array_merge($desc,array($base[$_dec0],$base[$_dec1],$base[$_dec2],$base[$_dec3]));
}
if($smod==0) return implode('',$desc);
$_arr = array_map('ord',str_split(substr($src,$snum*3,3)));
$_dec0= $_arr[0]>>2;
if(!isset($_arr[1]))
{
$_dec1= (($_arr[0]&3)<<4);
$_dec2=$_dec3="?";
}
else
{
$_dec1= (($_arr[0]&3)<<4)|($_arr[1]>>4);
$_dec2= $base[($_arr[1]&7)<<2];
$_dec3="?";
}
$desc = array_merge($desc,array($base[$_dec0],$base[$_dec1],$_dec2,$_dec3));
return implode('',$desc);
}

highlight_file(__FILE__);
?>

例题2

题目链接
http://111.230.11.183:44444/encode_encrypt_hash/base64/base64_harder.php

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
<?php
error_reporting(0);
require_once 'flag.php';

if (isset($_GET['get_string'])) {
print_r(c_base64_encode($flag_base64_harder));
echo "<br/>";
if (isset($_GET['code'])) {
echo "<br/>", c_base64_encode($_GET['code']), "<br/>";
}
if (isset($_GET['flag'])) {
if ($_GET['flag'] === $flag_base64_harder) {
echo "Good Luck!";
}
}
}

function c_base64_encode($src){
global $table_harder;
$base = $table_harder;
$slen=strlen($src);
$smod = ($slen%3);
$snum = floor($slen/3);
$desc = array();
for($i=0;$i<$snum;$i++)
{
$_arr = array_map('ord',str_split(substr($src,$i*3,3)));
$_dec0= $_arr[0]>>2;
$_dec1= (($_arr[0]&3)<<4)|($_arr[1]>>4);
$_dec2= (($_arr[1]&0xF)<<2)|($_arr[2]>>6);
$_dec3= $_arr[2]&63;
$desc = array_merge($desc,array($base[$_dec0],$base[$_dec1],$base[$_dec2],$base[$_dec3]));
}
if($smod==0) return implode('',$desc);
$_arr = array_map('ord',str_split(substr($src,$snum*3,3)));
$_dec0= $_arr[0]>>2;
if(!isset($_arr[1]))
{
$_dec1= (($_arr[0]&3)<<4);
$_dec2=$_dec3="?";
}
else
{
$_dec1= (($_arr[0]&3)<<4)|($_arr[1]>>4);
$_dec2= $base[($_arr[1]&7)<<2];
$_dec3="?";
}
$desc = array_merge($desc,array($base[$_dec0],$base[$_dec1],$_dec2,$_dec3));
return implode('',$desc);
}

highlight_file(__FILE__);
?>

从源码中,我们不知道base64对应的转换表,但可以控制参数code参数,输入任意数据得到加密的结果,即知道明文和密文,猜解base64转换表。

详情可看此文章:

爆破非默认Base64编码表

此题的破解脚本如下:

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
#coding:utf-8
import requests
import re

dicts={}

def getDesc():
global dicts
base64table=""
url="http://111.230.11.183:44444/encode_encrypt_hash/base64/base64_harder.php?get_string=&code={}"
pattern=re.compile(r"<br/><br/>(.*?)<br/>")
for i in range(0x0,0x7f):
for j in range(0x0,0x7f):
for k in range(0x0,0x7f):
payload=chr(i)+chr(j)+chr(k)
current_url=url.format(payload)
content=requests.get(current_url)
desc=pattern.search(content.text).group(1)
print(payload)
base64Table(payload,desc)
if len(dicts)==64:
print(dicts)
for i in range(64):
base64table=base64table+dicts[i]
print(base64table)
exit(0)

def base64Table(src,desc):
global dicts
src0=ord(src[0])
src1=ord(src[1])
src2=ord(src[2])
if '?' not in desc:
desc0=src0>>2
desc1=((src0&3)<<4 )|(src1>>4)
desc2=((src1&15)<<2 )|(src2>>6)
desc3=src2&63
dicts.update({desc0:desc[0]})
dicts.update({desc1:desc[1]})
dicts.update({desc2:desc[2]})
dicts.update({desc3:desc[3]})
getDesc()

参考文章:

Base64算法原理

爆破非默认Base64编码表