密码学base64stego还不懂base64的隐写?详解12⾏代码带你领
本⽂主要讲述密码学 base64隐写的python脚本解密的⽅法,以及⼀些python函数的⽤法。
隐写是密码学的⼀个概念,现代,我们可以把数据藏到⼀张图⽚中,⼀段⽂字中。隐写对于数据取证,数据隐藏有着⼗分重要的价值,主要⽤于军⼯,和安全⽅⾯。
⽹上写了很多多关于xctf MISC新⼿篇的base64Stego隐写的教程,但⼤都不太清楚,基本上都是讲了⼀段隐写原理,直接上代码了。但是代码是这道题的关键,代码讲了如何解码这个隐写的完整流程,
这次我以⼀个python的源码的解释,实现隐写过程的解释。
可能会花费你很长时间,⼤约⼀天半天,但是我们要有信⼼,恒⼼!
base64 隐写原理 + 破解隐写的代码
仔细看
存在隐写的编码末尾都存在 = ,⼀个 = 隐写 2bit
隐写的编码,解码后,再编码,最后挨着 = 的字符会发⽣变化。
史上最完全的源码解析
真⼩⽩级此题的隐写解码的python解析,
代码分析
# -*- coding: utf-8 -*-
import base64
b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
with open('', 'rb') as f:
bin_str = ''
for line adlines():
stegb64 = str(line, "utf-8").strip("\n")
tureb64 =  str(base64.b64encode(base64.b64decode(stegb64)), "utf-8").strip("\n")
offset = abs(b64chars.place('=','')[-1])-b64chars.place('=','')[-1]))
equalnum = unt('=') #no equalnum no offset
if equalnum:
bin_str += bin(offset)[2:].zfill(equalnum * 2)
print(''.join([chr(int(bin_str[i:i + 8], 2)) for i in range(0, len(bin_str), 8)]))
1 python 3.8.⽆法保存
# -*- coding: utf-8 -*-
在 python 3.8 IDE编写的程序⽂件⽆法保存存在中⽂字符的代码,也就⽆法运⾏,加上这⼀⾏就可以了保存了。
2 这⼀⾏为后⾯求隐写数据提供了标尺,后⾯再解释
b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
3 python ⽂件读写
with open('1.txt', 'rb') as f:
python提供的打开⽂件的⽅法,不需要关闭⽂件,即不需要写 f.close() ,但要注意⽂件操作的代码都写到 f:下⾯,有格式要求,有缩进。
注意要和脚本放到同⼀⽬录下。
"r" - 读取 - 默认值。打开⽂件进⾏读取,如果⽂件不存在则报错。
"b" - ⼆进制 - ⼆进制模式(例如图像)。
以⼆进制读⼊⽂件数据,也可以直接读⼊⽂本数据。
4 隐写数据⼆进制字符串
bin_str = ''
⽤来存储,隐藏的字符flag, 在后⾯所有求出的隐写⼆进制数据都将追加到 bin_str 的尾部
5 readlines()
for line adlines():
到底⼆进制读出来的line是什么呢!
源数据:IHdyaXRpbmcgaGlkZGVuIG1lc3NhZ2VzIGluIHN1Y2ggYSB3YXkgdGhhdCBubyBvbmV=\n
print(line):b'IHdyaXRpbmcgaGlkZGVuIG1lc3NhZ2VzIGluIHN1Y2ggYSB3YXkgdGhhdCBubyBvbmV=\n' class 'bytes'
可以使⽤ readlines() ⽅法返回所有⾏:
循环读⼊⽂件,每次读取⼀⾏,下⾯就是对每⼀次读⼊的⼆进制数据的⼀些操作。
6 strip("\n")
stegb64 = str(line, "utf-8").strip("\n")  //将读⼊的⼆进制串编成⽂本串,此时和中的base64隐写串⼀样,去除了\n换⾏符假!
tureb64 =  str(base64.b64encode(base64.b64decode(stegb64)), "utf-8").strip("\n")  //解码后的⼜编码的base64串,即原来的base64 真!
可以理解为 utf-8的英⽂字符和 ASCII的英⽂字符 编码是⼀致的。 在任何⼀种编码格式中 0-127所代表的字符都是⼀样的
在base64隐写中,如果存在隐写的数据,隐写数据后的base64 和没有隐写数据的base64 在最后⼀个字符会发⽣变化,即=后⾯
⼀个 = 隐藏 2bit数据。集齐8bit,就可以拼出⼀个字符串
eg.程序数据中的隐写
stegb64 = IHdyaXRpbmcgaGlkZGVuIG1lc3NhZ2VzIGluIHN1Y2ggYSB3YXkgdGhhdCBubyBvbmV=
tureb64 = IHdyaXRpbmcgaGlkZGVuIG1lc3NhZ2VzIGluIHN1Y2ggYSB3YXkgdGhhdCBubyBvbmU=
str(bytes, encoding, errors)这个很重要
str(line)
b'IHdyaXRpbmcgaGlkZGVuIG1lc3NhZ2VzIGluIHN1Y2ggYSB3YXkgdGhhdCBubyBvbmU=\n'
str(line,'utf-8')
IHdyaXRpbmcgaGlkZGVuIG1lc3NhZ2VzIGluIHN1Y2ggYSB3YXkgdGhhdCBubyBvbmU=
如果既没有给出encoding也没有给出errors, str(object)返回object.__str__(),这是object的“⾮正式”或可打印的字符串表⽰。对于字符串对象,这是字符串本⾝。如果object没有__str__()⽅法,则str()返回repr(object)。
如果⾄少给出了encoding或errors中的⼀个,object应该是bytes-like object(例如bytes或bytearray)。在这种情况下,如果object是⼀个bytes(或bytearray)对象,则str(bytes, encoding, errors)等价于bytes.decode(encoding, errors)
这⾥隐写了数据 '01'
特别!如果没有变化,也算是⼀种隐写 ==->'0000' =->'00' 这个可能根据不同的隐藏⽅法有关。我们也可以定义只有不同的base64真假编码可以藏数据。但这⾥是只要有 = 就有隐写!
eg.strip()
a=" gho stwwl\n"
a.strip("\n") = ' gho stwwl'
去掉⼀⾏⾸部和尾部的换⾏符,若要去⼀边的话还有 rstrip() lstrip()
7 offset 偏离(数字类型)
offset = abs(b64chars.place('=','')[-1])-b64chars.index(
(place('=','')[-1]))
abs() 返回绝对值 V的位置 - U的位置
equalnum = unt('=') #no equalnum no offset
if equalnum:
bin_str += bin(offset)[2:].zfill(equalnum * 2)
如果存在等号表⽰隐藏了数据,我们把隐藏的数据转换成⼆进制存到 bin_str 中以追加的⽅式
bin(x) 返回⼀个整数 int 或者长整数 long int 的⼆进制表⽰。
bin(1)='0b1' 上⾯的例⼦就是这个(U V)
bin(2)='0b10'
bin(4)='0b100'
因为返回的字符串都有 '0b' 但我们只要⼆进制数据
[2:] 从 '0b' 之后截取我们取到'1'
但是这个隐写了 2bit 所以⽤到了 zfill()
.zfill(equalnum * 2) ⽅法返回指定长度的字符串,原字符串右对齐,前⾯填充0。
str = '1'
str.zfill(2) = '01'
str.zfill(4) = '0001'
经过这次的转换我们求解了 '01' 的隐藏数据
经过⼏个循环
IHdyaXRpbmcgaGlkZGVuIG1lc3NhZ2VzIGluIHN1Y2ggYSB3YXkgdGhhdCBubyBvbmV= '01' LCBhcGFydCBmcm9tIHRoZSBzZW5kZXIgYW5kIGludGVuZGVkIHJlY2lwaWVudCwgc3VzcGU= '00' Y3RzIHRoZSBleGlzdGVuY2Ugb2YgdGhlIG1lc3M= '00'
YWdlLCBhIGZvcm0gb2Ygc2VjdXJpdHkgdGhyb3VnaCBvYnNjdXJpdHkuIFS= '11'
我们得到了 B 0100 0011 这是码ascii
字符串截取不改变原字符串输出
print(''.join([chr(int(bin_str[i:i + 8], 2)) for i in range(0, len(bin_str), 8)]))
int() 函数⽤于将⼀个字符串或数字转换为整型。
int(x, base=10)
x -- 字符串或数字。
base -- 进制数,默认⼗进制。
join()
Python join() ⽅法⽤于将序列中的元素以指定的字符连接⽣成⼀个新的字符串。
str.join(sequence)
sequence -- 要连接的元素序列。
str = "-";
seq = ("a", "b", "c"); # 字符串序列
print str.join( seq );
结果: a-b-c
在Python中函数是⼀类公民
def create_adder(x):
def adder(y):
return x + y
return adder
add_10 = create_adder(10)
add_10(3)
13
匿名函数
(lambda x: x > 2)(3)
True
(lambda x, y: x ** 2 + y ** 2)(2, 1)
5
⾼阶函数
list(map(add_10, [1, 2, 3]))
[11, 12, 13]
list(map(max, [1, 2, 3], [4, 2, 1]))
[4, 2, 3]
list(filter(lambda x: x > 5, [3, 4, 5, 6, 7]))
[6, 7]
列表推导是map和filter的语法糖,请你⾃⼰出对照关系
[.. for in range(10)]
[add_10(i) for i in [1, 2, 3]]
[11, 12, 13]
[x for x in [3, 4, 5, 6, 7] if x > 5]
[6, 7]
列表推导也可以⽤在集合和字典上
{x for x in 'abcddeef' if x not in 'abc'}
{'d', 'e', 'f'}
{x: x**2 for x in range(5)}
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
为了匹配 sequence ⽣成⼀个字符列表以便⽤于 join();
最后,这些解码的字符就连接到⼀起了。并且,每读⼀⾏数据,加⼯后输出⼀次隐写数据。懂(mei)了(dong)吗

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。