网上写了好多关于xctf MISC新手篇的base64Stego隐写的教程,但大都不太清楚,基本上都是讲了一段隐写原理,直接上代码了。但是代码是这道题的关键,代码讲了如何解码这个隐写的完整流程,这次我以一个python的源码的解释,完美解决这道题。

可能会花费你很长时间,大约一天半天,但是我们要有信心,恒心!

base64 隐写原理 + 破解隐写的代码

仔细看!!!!!!!

Tr0y's Blog baseStego

存在隐写的编码末尾都存在 = ,一个 = 隐写 2bit

隐写的编码,解码后,再编码,最后挨着 = 的字符会发生变化。

史上最完全的源码解析

真小白级此题的隐写解码的python解析,

代码分析

# -*- coding: utf-8 -*-
import base64
b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
with open('stego.txt', 'rb') as f:
bin_str = ''
for line in f.readlines():
stegb64 = str(line, "utf-8").strip("\n")
rowb64 = str(base64.b64encode(base64.b64decode(stegb64)), "utf-8").strip("\n")
offset = abs(b64chars.index(stegb64.replace('=','')[-1])-b64chars.index(rowb64.replace('=','')[-1]))
equalnum = stegb64.count('=') #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:下面,有格式要求,有缩进。

注意stego.txt要和脚本放到同一目录下。

"r" - 读取 - 默认值。打开文件进行读取,如果文件不存在则报错。

"b" - 二进制 - 二进制模式(例如图像)。

以二进制读入文件数据,也可以直接读入文本数据。

w3school 文件读写

博主 有梦就要去实现它 with open() as f:

4 隐写数据二进制字符串

bin_str = ''

用来存储,隐藏的字符flag, 在后面所有求的的隐写二进制数据都将追加到 bin_str 的尾部

5 readlines()

for line in f.readlines():

可以使用 readline() 方法返回一行:

循环读入文件,每次读取一行,下面就是对每一次读入的二进制数据的一些操作。

6 strip("\n")

stegb64 = str(line, "utf-8").strip("\n")  //将读入的二进制串编成文本串,此时和stego.txt中的base64串一样,去除了\n换行符 假!
rowb64 = 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=

    rowb64 = IHdyaXRpbmcgaGlkZGVuIG1lc3NhZ2VzIGluIHN1Y2ggYSB3YXkgdGhhdCBubyBvbmU=

    这里隐写了数据 '01'

    特别!如果没有变化,也算是一种隐写 ==->'0000' =->'00' 这个可能根据不同的隐藏方法有关。我也可以定义只有不同的
  • eg.strip()

    a=" gho stwwl\n"

    a.strip("\n") = ' gho stwwl'

    去掉一行首部和尾部的换行符,若要去一边的话还有 rstrip() lstrip()

7 offset 偏离(数字类型)

offset = abs(b64chars.index(stegb64.replace('=','')[-1])-b64chars.index(rowb64.replace('=','')[-1]))
  • abs() 返回绝对值 V的位置 - U的位置
  • stegb64.replace('=','')[-1] 去掉末尾的'=' 并且返回它的最后一个字符 V
  • rowb64.replace('=','')[-1] 去掉末尾的'=' 并且返回它的最后一个字符 U
  • index() 返回这个字符在 b64chars 中的位置

8 计算 '=' 的数量

equalnum = stegb64.count('=') #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

为了匹配 sequence 生成一个字符列表 以便用于 join();

最后,这些解码的字符就连接到一起了。

动手写一遍吧

base64stego 还不懂base64的隐写,详解15行代码带你领略的更多相关文章

  1. base64文件隐写脚本

    base64文件隐写脚本 base64 可以在文件中隐藏信息,记录一下提取脚本 ''' base64文件隐写脚本 import re import base64 b64chars = 'ABCDEFG ...

  2. SQL Server 表的管理_关于事务的处理的详解(案例代码)

    SQL Server 表的管理_关于事务的处理的详解(案例代码) 一.SQL 事务 1.1SQL 事务 ●事务是在数据库上按照一定的逻辑顺序执行的任务序列,既可以由用户手动执行,也可以由某种数据库程序 ...

  3. 代码详解:TensorFlow Core带你探索深度神经网络“黑匣子”

    来源商业新知网,原标题:代码详解:TensorFlow Core带你探索深度神经网络“黑匣子” 想学TensorFlow?先从低阶API开始吧~某种程度而言,它能够帮助我们更好地理解Tensorflo ...

  4. SQL Server 表的管理_关于数据增删查改的操作的详解(案例代码)

    SQL Server 表的管理_关于数据增删查改的操作的详解(案例代码)-DML 1.SQL INSERT INTO 语句(在表中插入) INSERT INTO 语句用于向表中插入新记录. SQL I ...

  5. SQL Server 表的管理_关于事务操作的详解(案例代码)

    SQL Server 表的管理_关于事务操作的详解(案例代码) 1.概念 事务(transaction): 是将多个修改语句组合在一起的方法,这个方法中的所有语句只有全部执行才能正确完成功能.即要么全 ...

  6. SQL Server 表的管理_关于表的操作增删查改的操作的详解(案例代码)

    SQL Server 表的管理_关于表的操作增删查改的操作的详解(案例代码) 概述: 表由行和列组成,每个表都必须有个表名. SQL CREATE TABLE 语法 CREATE TABLE tabl ...

  7. http500:服务器内部错误案例详解(服务器代码语法错误或者逻辑错误)

    http500:服务器内部错误案例详解(服务器代码语法错误或者逻辑错误) 一.总结 服务器内部错误可能是服务器中代码运行的时候的语法错误或者逻辑错误 二.http500:服务器内部错误案例详解 只是一 ...

  8. Notepad2(C语言+Windows消息写的,24592行代码)

    C语言+Windows消息写的,24592行代码 http://www.flos-freeware.ch/

  9. scala 隐式详解(implicit关键字)

    掌握implicit的用法是阅读spark源码的基础,也是学习scala其它的开源框架的关键,implicit 可分为: 隐式参数 隐式转换类型 隐式调用函数 1.隐式参数 当我们在定义方法时,可以把 ...

随机推荐

  1. PTA 统计二叉树度为2的结点个数

    6-4 统计二叉树度为2的结点个数 (11 分)   本题要求实现一个函数,可统计二叉树中度为2的结点个数. 函数接口定义: int NodeCount ( BiTree T); T是二叉树树根指针, ...

  2. ElasticSearch实战系列十: ElasticSearch冷热分离架构

    前言 本文主要介绍ElasticSearch冷热分离架构以及实现. 冷热分离架构介绍 冷热分离是目前ES非常火的一个架构,它充分的利用的集群机器的优劣来实现资源的调度分配.ES集群的索引写入及查询速度 ...

  3. elasticsearch 7.7 配置文件:elasticsearch.yml

    # ======================== Elasticsearch Configuration ========================= # # NOTE: Elasticse ...

  4. ionic3 StatusBar 不显示问题

    import { StatusBar } from '@ionic-native/status-bar'; constructor(private statusBar: StatusBar) { } ...

  5. Java(100-113)【类与对象、封装、构造方法】

    1.对象的创建以及使用 Student stu =new Student(); 根据一个类创建一个对象 导包.创建.使用 2.手机练习 有main才能run Phone.java package cn ...

  6. shell 使用 cat 配合 EOF 创建文件并写入多行内容

    之前折腾 GtiHub Actions 想实现提交 issue 后将 issue 的内容生成一个 Markdown 文件提交到仓库,从而实现自动发布到 GitHub Pages 的目的.倒是有一些现成 ...

  7. 18. VUE created 方法作用

    一般可以在created函数中调用ajax获取页面初始化所需的数据. 实例的生命周期: 每个 Vue 实例在被创建之前都要经过一系列的初始化过程.例如,实例需要配置数据观测(data observer ...

  8. Magicodes.IE.ASPNETCore之多样化接口使用

    1.安装包 Install-Package Magicodes.IE.AspNetCore 2.开始配置 在Startup.cs的Configure()方法中,在UseRouting()中间件之后,注 ...

  9. Day01_12_Java的类型转换

    Java类型转换 实例 public class 类型转换 { public static void main(String[] args) { int i =128; byte b= (byte) ...

  10. Laravel结构生成器

    简介 Laravel 的 Schema 类提供了一种与数据库无关的方式维护表.它和 Laravel 所支持的所有数据库都能很好的工作,并且提供了统一的接口. 创建和删除表 使用 Schema::cre ...