前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于Base64隐写那点事儿

关于Base64隐写那点事儿

作者头像
L1near
发布2022-11-11 20:22:17
1.4K0
发布2022-11-11 20:22:17
举报
文章被收录于专栏:CTF-WP

咕咕咕的我又回来了,学校这几天在放“五一七天小长假”,加上今天的ISCC有点奇奇怪怪,所以来更一篇博客吧!今天我们来讲关于base64隐写那点事儿……

前言

在了解base64隐写之前,我们先来了解一下base64编码。

base64编码是现在网络上最常见的用于传输8Bit字节码的编码方式之一。在最初有的网络并不支持所有的字节,比如某些系统只支持可见字符的传送,比如图片二进制流的每个字节不可能全部是可见字符,所以就传送不了。所以由于不能传送ASCII的控制字符,它的用途就受到了很大的限制。

而Base64旨在通过一种方法,把所有的字符都用64个特定的可打印字符表示来实现传送。选定的64个字符如下:

索引

对应字符

索引

对应字符

索引

对应字符

索引

对应字符

0

A

17

R

34

i

51

z

1

B

18

S

35

j

52

0

2

C

19

T

36

k

53

1

3

D

20

U

37

l

54

2

4

E

21

V

38

m

55

3

5

F

22

W

39

n

56

4

6

G

23

X

40

o

57

5

7

H

24

Y

41

p

58

6

8

I

25

Z

42

q

59

7

9

J

26

a

43

r

60

8

10

K

27

b

44

s

61

9

11

L

28

c

45

t

62

+

12

M

29

d

46

u

63

/

13

N

30

e

47

v

14

O

31

f

48

w

15

P

32

g

49

x

16

Q

33

h

50

y

加密过程

由于只用到了64个字符,所以使用6个二进制位(2^6 = 64)完全可以把所有的字符表示出来,于是原来的1个字节8位在base64编码中变成了1个字节6位。

换言之:把原本的3个字节变成现在的4个字节,因为(3*8 == 4*6)

所以在加密的时候首先写出原字符ASCII码对应的二进制数字,每个字符都可以得到一个8位的01串,再把该01串重新按照每6位一组划分即可得到一个新的数字,对照上图给出的表格可以得到一个新的字符。

但是这里有一个问题了:如果明文的字节数刚好是3的倍数那没有问题,按照6位一组划分肯定是刚刚好的;但是如果明文的字节数不是3的倍数,那按照6位一组划分不是就有剩余了吗?具体可见下图:

这样是没有剩余的:

而这样是有剩余的:

而base64给出的解决方法是在二进制数串后面加0,一直到二进制数串变成8和6的公倍数,然后把只有0的字节编码成"=",如下图:

所以LoV3被编码成了TG9WMw== ,同时base64编码后面最多只可能出现2个==

解密过程

解密的过程可视作加密的逆过程

由于"="是最后为了补齐填充的,所以解密的时候首先把"="删去,然后写出二进制数串,然后从左往右每8位一组,剩余的不足8位丢掉,然后根据转换表获得相应字符:

以上图为例,TG9WMw==首先变成了TG9WMw,对照上图的表写出来二进制数串:

然后每8位一组,剩余不足的丢弃:

所以这里牵涉到了一个地方,由上面的过程我们可以看成,TG9WMw在解密回LoV3的时候,按每8位一组剩余的丢弃来算,最后的110000中的0000是没有用到的。所以换句话说,这剩下的4位无论是0000还是1111,都是要被丢弃的,所以这就提供了一个可以隐藏信息的地方:

TG9WMx==解密后依然是LoV3,但已经隐藏进了一个1进去,那么这就是base64隐写

那么,在平时我们如何判断有没有信息被隐藏进去了呢

最简单的就是你是否隐藏信息,解密得到的明文是不变的,那么你重新按照正确的加密流程计算一遍,如果发现结果不一样,那么就说明隐藏进了信息。

一般CTF题目中出现一大堆base64编码字符串的时候,更需要考虑base64隐写

这里附上一个base64提取隐藏信息的脚本:

代码语言:javascript
复制
b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
with open('flag_encode.txt', 'rb') as f:
    bin_str = ''
    for line in f.readlines():
        stegb64 = ''.join(line.split())
        rowb64 =  ''.join(stegb64.decode('base64').encode('base64').split())
        offset = abs(b64chars.index(stegb64.replace('=','')[-1])-b64chars.index(rowb64.replace('=','')[-1]))
        equalnum = stegb64.count('=')
        if equalnum:
            bin_str += bin(offset)[2:].zfill(equalnum * 2)
        print ''.join([chr(int(bin_str[i:i + 8], 2)) for i in xrange(0, len(bin_str), 8)])

感谢中南大学极光网安实验室,部分图片源自其公众号:bowtie:

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-05-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 加密过程
  • 解密过程
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档