base64隐写(转)

  1. 1 声明
  2. 2 背景
  3. 3 原理
  4. 4 示例
    1. 4.1 解码
    2. 4.2 加解密程序
    3. 4.3 具体题目
      1. SXMgdGhpcyBiYXNlPw==
        1. 题目描述:
        2. 解题思路:

1 声明

本文的base64部分参考了下面的文章

https://www.jianshu.com/p/48fe4dd3e5ce

2 背景

圣诞节前做了北京工业大学的CTF,其中有一道base64隐写的题目,这里记录一下原理,以供日后方便查看。

3 原理

  • base64是怎么编码的?
  1. 字符对应ASCII转换成八位二进制( base64的基础单位是 38bit的二进制,若是不够38bit则在后面添加0字节(padding)直至满足)(例如:字符A–>八位二进制01000001不够38即不够24位后面补0直到满足38即 01000001 00000000 00000000)
  2. 38bit的二进制转换成46bit的二进制(01000001 00000000 00000000–>010000 010000 000000 000000)
  3. 4*6bit的二进制转换成十进制(010000 010000 000000 000000–>16 16 0 0)(注意后面的两个0在下一步不会变成base64对照表里的A而是你自己加上去的要变成等号(=))
  4. 对照base64表把十进制转换成字符(16 16 0 0–>Q Q = = )
    就是说3个字符的字符串base64编码之后会转成4个字符的base64编码
  • base64是怎么解码
  1. 检查base64编码后面有几个等于号
  2. 把字符串按照base64表转换成4*6的倍数位数二进制
  3. 删除等于号的个数*8的bit
  4. 按照6个bit一组转成字符

关键就是,解码的时候,会删除等于号的个数 8的bit,而且我们只用6个bit表示一个等于号(000000),那么,意思就是我们可以控制等于号2bit的字符
看图片上的两个例子:

base64隐写

如图,那么我们就可以在加粗的0的位子用二进制隐写(改成其他的二进制数)。这样子做,不影响原文的还原(因为解码的时候加粗位置被改的数是要被删除的),唯一的区别就是,上图的QQ==中第二个Q会变化,QkM=的M会变化,所以base64可以用于隐写

4 示例

4.1 解码

下面的代码是对 UX==(X取A到Z)进行base64解码(python2.7)

1
2
3
4
5
6
import base64
b = ''
for i in range(26):
b = 'U' + chr(65 + i) + '=='
print b
print base64.b64decode(b)

显示的结果如下

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
E:\App\py_workspace\venv\Scripts\python.exe E:/App/py_workspace/asdf.py
UA==
P
UB==
P
UC==
P
UD==
P
UE==
P
UF==
P
UG==
P
UH==
P
UI==
P
UJ==
P
UK==
P
UL==
P
UM==
P
UN==
P
UO==
P
UP==
P
UQ==
Q
UR==
Q
US==
Q
UT==
Q
UU==
Q
UV==
Q
UW==
Q
UX==
Q
UY==
Q
UZ==
Q

看出来啥了没
如果我要发给你一个Q那么我发UZ==可以,但是发UY==也可以,
看代码↓

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
65
66
67
68
# coding:UTF8
# import base64
import string


def decode(flag1): # 把需要隐藏的密文变成二进制字符串
list_flag1 = list(flag1) # 把密文转为list例如:['I', ' ', 'a', 'm', ' ', 'a', ' ', 'C', 'T', 'F', 'e', 'r']
list_dec_flag1 = [] # 十进制密文例如:[73, 32, 97, 109, 32, 97, 32, 67, 84, 70, 101, 114]
for j in range(len(list_flag1)): # 把ascii码密文转换为十进制密文list
list_dec_flag1.append(ord(list_flag1[j]))
list_bin_flag1 = []
# 二进制密文例如:['1001001', '100000', '1100001', '1101101', '100000', '1100001', '100000', '1000011','1010100'...]
for j in range(len(list_dec_flag1)): # 把十进制密文转化为二进制密文
list_bin_flag1.append((bin(list_dec_flag1[j])[2:]).zfill(8))
str_bin_flag1 = ''.join(list_bin_flag1) # 把二进制密文list拼接成str
# 例如:010010010010000001100001011011010010000001100001001000000100001101010100010001100110010101110010
list_bin_every_flag1 = list(str_bin_flag1) # 把str二进制密文转换成list
# 例如:['1', '0', '0', '1', '0', '0', '1', '1', '0', '0', '0', '0', '0', '1', '1', '0', '0', '0', '0', '1'...]
return list_bin_every_flag1


if __name__ == '__main__':
dic = string.uppercase+string.lowercase+string.digits+'+/'
# a = raw_input()
flag = 'I am a CTFer'
list_bin_every_flag = decode(flag) # list二进制密文
# print len(list_bin_every_flag)
# 例如:['1', '0', '0', '1', '0', '0', '1', '1', '0', '0', '0', '0', '0', '1', '1', '0', '0', '0', '0', '1'...]
tip = 0 # 定义一个指针指向要写入base64的list二进制密文
# tt = 0
with open('hello.txt', 'rb') as h: # 打开明文
file_lines = h.readlines() # 把明文读取成一行
# 例如:['#include <stdio.h>\r\n', '#include <stdlib.h>\r\n', 'main(){int i,n[]={(((1 <<1)<< (1<<1)...]
for line in file_lines: # 接下来是正文了
normal_line = line.replace('\r\n', '') # 每一行的明文
# print normal_line
# 例如:#include <stdio.h>\r
equal_sign_num = 3 - (len(normal_line) % 3) # 每行base64加密后的等号数量
if equal_sign_num == 3: # 如果是3的倍数说明这一句没法进行隐写
equal_sign_num = 0 # 设其等号数量为0
# print 'equal_sign_num', equal_sign_num
# tt += equal_sign_num * 2
# print tt, 'tt'
list_normal_line = decode(normal_line) # 把明文也装换为list_bin_every_明文
# print list_normal_line
if equal_sign_num == 1: # 一个等号
for i in range(2):
# print 'tip', tip, 'list_bin_every_flag[tip]',list_bin_every_flag[tip]
list_normal_line.append(list_bin_every_flag[tip])
tip += 1
# print list_normal_line
elif equal_sign_num == 2: # 两个等号
for i in range(4):
# print 'tip', tip, 'list_bin_every_flag[tip]', list_bin_every_flag[tip]
list_normal_line.append(list_bin_every_flag[tip])
tip += 1
# print list_normal_line
# print tt
str_bin_normal_line = ''.join(list_normal_line)
# print str_bin_normal_line
b64 = ''
for i in range(0, len(str_bin_normal_line), 6):
b64 += dic[int(str_bin_normal_line[i: i+6], 2)] # 以6位为单位对照base64编码表
if equal_sign_num == 1:
b64 += '='
elif equal_sign_num == 2:
b64 += '=='
print b64

效果如下

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
E:\App\py_workspace\venv\Scripts\python.exe E:/App/py_workspace/mybase64隐写.py
I2luY2x1ZGU8c3RkaW8uaD5=
I2luY2x1ZGUgPHN0ZGxpYi5oPi==
bWFpbigpe2ludCBpLG5bXT17KCgoMSA8PDEpPDwoMTw8MSk8PCgxPDx=
ICAgICAgIDEpPDwoMTw8KDE+PjEpKSkrKCgxPDwxKTw8KDE8PDEpKSksICgoKDE=
ICAgICAgIDw8MSk8PCgxPDwxKTw8KDE8PDEpPDwoMTw8MSkpLSgoMTw8MSk8PCi=
ICAgIAkxPDwxKTw8KDE8PDEpKSsoKDE8PDEpPDwoMTw8KDE+PjEpKSkrKDE8PCgxPj4xKSkpLA==
ICAgICAgICgoKDE8PDEpPDwoMTw8MSk8PCgxPDwxKTw8KDE8PDEpKS0oKDEgPDwxKW==
ICAgICAgIDw8KDE8PDEpIDw8KDE8PCgxPj4xKSkpLSgoMTw8MSk8PCgxPDwoMT4+MSkpKSkgLB==
ICAgICAgICgoKDE8PDEpPDwoMTw8MSk8PCgxPDwxKTw8KCAxPDwxKSktKCgxIDw8MSk8PG==
ICAgICAgICAoMTw8MSk8PCgxIDw8KDE+PjEpKSktKCgxPDwxKTw8KDE8PCgxPj4xKSkpKSAgLN==
ICAgICAgICAoKCgxPDwxKTw8KDE8PDEpPDwoMTw8MSk8PCgxPDwxKSktKCgxPDwxKSA8PC==
ICAgICAgICAoMTw8MSk8PCgxPDwoMT4+MSkpKS0oMTw8KDE+PjEpKSksKCgoMTw8MSk8PA==
ICAgICAgICAoMTw8MSk8PCgxPDwxKSkrKCgxPDwxKTw8KDE8PDEpPDwoMTw8KDE+PjEpKSkgLW==
ICAgICAgICAoKDE8PDEpPDwoMTw8KDE+PjEpKSkpLCgoMTw8MSk8PCgxPDwxKTw8KDE8PDEpKR==
ICAgICAgICwoKCgxPDwxKTw8KDE8PDEpPDwoMTw8MSk8PCgxPDwxKSktKCgxPDwxKTw8KDE8PDEpKS==
ICAgICAgIC0oMTw8KDE+PjEpKSksKCgoMTw8MSk8PCgxPDwxKTw8KDE8PDEpPDwoMTw8MSkpLSgoMQ==
ICAgICAgIDw8MSk8PCgxPDwxKTw8KDE8PCgxPj4xKSkpLSgxPDwoMT4+MSkpKSwgICgoKDE8PDF=
ICAgICAgICk8PCgxPDwxKTw8KDE8PDEpPDwoMTw8MSkpLSgoMTw8MSk8PCAoMQ==
ICAgICAgIDw8MSk8PCgxPDwoMT4+MSkpKSsoMTw8MSkpLCgoKDE8PDEpPDwoMTw8MSAgKd==
ICAgICAgIDw8KDE8PDEpPDwoMTw8MSkpLSgoMTw8MSk8PCgxPDwxKTw8KDE8PCgxPj4xKSkpLV==
ICAgICAgICgoMTw8MSk8PCgxPDwoMT4+MSkpKSksKCgoMTw8MSk8PCgxPDwxKSA8PCgxPDwxKR==
ICAgICAgIDw8KDE8PDEpKS0oKDE8PDEpPDwoMTw8MSk8PCgxPDwxKSkrICgoMR==
ICAgICAgIDw8MSk8PCgxPDwoMT4+MSkpKSksKCgoMTw8MSk8PCgxPDwxKSAgPDwoMZ==
ICAgICAgIDw8MSkpKygxPDwoMT4+MSkpKSwoKCgxPDwxKTw8KDE8PDEpKSAgKygoMZ==
ICAgICAgIDw8MSk8PCAoMTw8KDE+PjEpKSkgKygxPDwgKDE+PjEpKSl9O2Zvcl==
ICAgICAgIChpPSgxPj4xKTtpPCgoKDE8PDEpPDwoMTw8MSkpKygoMSAgPDwxKTw8KM==
ICAgICAgIDE8PCgxPj4xKSkpKygxPDwxKSk7aSsrKSAgIHByaW50ZigiJWMiLG5baV0pO32=

Process finished with exit code 0

4.2 加解密程序

附送大家一个输出hello,world的c语言程序

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
#include<stdio.h>
#include <stdlib.h>
main(){int i,n[]={(((1 <<1)<<(1<<1)<<(1<<
1)<<(1<<(1>>1)))+((1<<1)<<(1<<1))), (((1
<<1)<<(1<<1)<<(1<<1)<<(1<<1))-((1<<1)<<(
1<<1)<<(1<<1))+((1<<1)<<(1<<(1>>1)))+(1<<(1>>1))),
(((1<<1)<<(1<<1)<<(1<<1)<<(1<<1))-((1 <<1)
<<(1<<1) <<(1<<(1>>1)))-((1<<1)<<(1<<(1>>1)))) ,
(((1<<1)<<(1<<1)<<(1<<1)<<( 1<<1))-((1 <<1)<<
(1<<1)<<(1 <<(1>>1)))-((1<<1)<<(1<<(1>>1)))) ,
(((1<<1)<<(1<<1)<<(1<<1)<<(1<<1))-((1<<1) <<
(1<<1)<<(1<<(1>>1)))-(1<<(1>>1))),(((1<<1)<<
(1<<1)<<(1<<1))+((1<<1)<<(1<<1)<<(1<<(1>>1))) -
((1<<1)<<(1<<(1>>1)))),((1<<1)<<(1<<1)<<(1<<1))
,(((1<<1)<<(1<<1)<<(1<<1)<<(1<<1))-((1<<1)<<(1<<1))
-(1<<(1>>1))),(((1<<1)<<(1<<1)<<(1<<1)<<(1<<1))-((1
<<1)<<(1<<1)<<(1<<(1>>1)))-(1<<(1>>1))), (((1<<1
)<<(1<<1)<<(1<<1)<<(1<<1))-((1<<1)<< (1
<<1)<<(1<<(1>>1)))+(1<<1)),(((1<<1)<<(1<<1 )
<<(1<<1)<<(1<<1))-((1<<1)<<(1<<1)<<(1<<(1>>1)))-
((1<<1)<<(1<<(1>>1)))),(((1<<1)<<(1<<1) <<(1<<1)
<<(1<<1))-((1<<1)<<(1<<1)<<(1<<1))+ ((1
<<1)<<(1<<(1>>1)))),(((1<<1)<<(1<<1) <<(1
<<1))+(1<<(1>>1))),(((1<<1)<<(1<<1)) +((1
<<1)<< (1<<(1>>1))) +(1<< (1>>1)))};for
(i=(1>>1);i<(((1<<1)<<(1<<1))+((1 <<1)<<(
1<<(1>>1)))+(1<<1));i++) printf("%c",n[i]);}

解密的脚本如下

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
def get_base64_diff_value(s1, s2):
base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
res = 0
for i in xrange(len(s2)):
if s1[i] != s2[i]:
return abs(base64chars.index(s1[i]) - base64chars.index(s2[i]))
return res


def solve_stego():
with open('3.txt', 'rb') as f:
file_lines = f.readlines()
bin_str = ''
for line in file_lines:
steg_line = line.replace('\n', '')
norm_line = line.replace('\n', '').decode('base64').encode('base64').replace('\n', '')
diff = get_base64_diff_value(steg_line, norm_line)
print diff
pads_num = steg_line.count('=')
if diff:
bin_str += bin(diff)[2:].zfill(pads_num * 2)
else:
bin_str += '0' * pads_num * 2
print goflag(bin_str)


def goflag(bin_str):
res_str = ''
for i in xrange(0, len(bin_str), 8):
res_str += chr(int(bin_str[i:i + 8], 2))
return res_str


if __name__ == '__main__':
solve_stego()

效果↓

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
E:\App\py_workspace\venv\Scripts\python.exe E:/App/py_workspace/Tools/base64隐写解密.py
1

2

1
I
0
I
2
I�
0
I
6
I �
1
I a
6
I a�
13
I am
2
I am�
0
I am
6
I am �
1
I am a
2
I am a�
0
I am a
1
I am a �
0
I am a �
13
I am a C�
5
I am a C�
1
I am a CT�
1
I am a CT�
9
I am a CTF�
9
I am a CTF�
5
I am a CTFe�
12
I am a CTFe�
2
I am a CTFer

Process finished with exit code 0

4.3 具体题目

SXMgdGhpcyBiYXNlPw==

题目描述:

解题思路:

题目base64解密之后的结果如下所示

题目解密

然后,对它进行base64解密,得到的是莫扎特的一首音乐歌词,有兴趣的朋友可以听听看!

莫扎特歌曲

关于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
def get_base64_diff_value(s1, s2):
base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
res = 0
for i in xrange(len(s2)):
if s1[i] != s2[i]:
return abs(base64chars.index(s1[i]) - base64chars.index(s2[i]))
return res

def solve_stego():
with open('D:/bjutCTF/MISC/flag.txt', 'rb') as f:
file_lines = f.readlines()
bin_str = ''
for line in file_lines:
steg_line = line.replace('\n', '')
norm_line = line.replace('\n', '').decode('base64').encode('base64').replace('\n', '')
diff = get_base64_diff_value(steg_line, norm_line)
print diff
pads_num = steg_line.count('=')
if diff:
bin_str += bin(diff)[2:].zfill(pads_num * 2)
else:
bin_str += '0' * pads_num * 2
print goflag(bin_str)

def goflag(bin_str):
res_str = ''
for i in xrange(0, len(bin_str), 8):
res_str += chr(int(bin_str[i:i + 8], 2))
return res_str

if __name__ == '__main__':
solve_stego()

得到flag

得到flag


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达,可以邮件至 xingshuaikun@163.com。

×

喜欢就点赞,疼爱就打赏