CTF-Misc Guide

Contents

This is a simple Guide for CTF in Misc Area.

Misc Guide

最开始接触CTF时,学的最多的就是Misc,各种编码各种加密还有各种软件的使用…

但无奈MIsc涉及的范围实在太广了,于是就萌生了一边学习一边记录的想法,甚至还想为此写一本指南。

一些奇奇怪怪的经历:

1、一段字符串,用base64异或脚本跑,找正常的字符串

2、rockstar 编程语言,在github上面可以找到,然后在本地用pip安装库

​ 把rock文件转换为py文件,运行即可得到flag

3、给你一个.exe安装包文件,flag藏在安装之前的一大串协议中

4、实在做不出来的时候,可以把flag的格式转其他的编码和题目中的信息比对找规律

5、给你一个gpx文件,在线网站https://www.gpsvisualizer.com/map_input解密

然后地名的首字母连起来就是flag

Linux(kali)的各种命令:

1
2
3
4
5
1、 fls +镜像文件       列出镜像中的文件和目录名并可以显示使用给定名称的目录最近              删除的文件的文件名
2、file+文件名      查看文件类型
3、binwalk+文件名  查看文件类型
4、各种文件的解压命令
	7z:7z x +filename.7z

Linux如何配置环境变量

1
2
3
4
sudo vim /etc/profile
export PATH=/usr/local/volatility:$PATH
or
export PATH=/usr/lib/python2.7/dist-packages/volatility:$PATH

各种加密/编码:

可以试试直接用ciphey或者CyberChef跑

1
2
#ciphey在windows和wsl里都可以用
ciphey -t "aGVsbG8gbXkgbmFtZSBpcyBiZWU="

base家族

详细请看:https://www.cnblogs.com/0yst3r-2046/p/11962942.html

1
2
3
4
5
6
7
8
1、base16                       flag         666C6167
2、base32[A-Z2-7]               flag         MZWGCZY=
3、base36                       flag         727432
4、base58                       flag         3cr9Ae
5、base64                       flag         Zmxh
6、base85                       flag         Ao(mg
7、base91                       flag         @iH<Z
8、base92                       flag         F#S<I

base64还可以换表(表中的字符要求不重复)编码,例如

1
2
3
4
sQ+3ja02RchXLUFmNSZoYPlr8e/HVqxwfWtd7pnTADK15Evi9kGOMgbuIzyB64CJ
SjaoNgS0xgagUTpwe3QwHn4MrbkD/OUwqOQG/bpveg6Mqa4WH0k46
第一行是表,第二行是编码后的密文
cyberchef解密即可得到flag

Tips:base64可以与其他文件格式互相转换(比如图片[会有很多行的base64]),使用在线网站或者随波逐流转换即可 如果出现了很多层乱七八糟的base编码,连CyberChef都识别不出来的话,可以试试用BaseCrack这个开源工具 输入 python basecrack.py -m 运行即可

basecrack

MD5加密

1
2
3
4
5
6
明文:admin
32位小写21232f297a57a5a743894a0e4a801fc3 
32位大写21232F297A57A5A743894A0E4A801FC3 
16位小写7a57a5a743894a0e 
16位大写7A57A5A743894A0E 
Tips:十六位其实就是取32位的8-24位

MD5 加密后的密文应该是 纯数字+纯字符

有些 MD5 的 HASH 值可以直接在 somd5 或者 cmd5 上查

python中str类型和byte类型:

1
2
3
4
5
6
7
8
\>>> a = '寒鸦小站'
\>>> type(a)
<class 'str'>
\>>> b = a.encode()
\>>> b
b'\xe5\xaf\x92\xe9\xb8\xa6\xe5\xb0\x8f\xe7\xab\x99'
\>>> type(b)
<class 'bytes'>

emoji-aes编码:

https://aghorler.github.io/emoji-aes/

词频分析:

一堆文字,看着什么编码都不像的,可能是词频分析,用在线网站跑https://quipqiup.com/

字频分析:

用随波逐流直接分析

摩斯电码:

1
#第一种情况,只有.-或者只有01
1
2
#第二种情况,加入/或者空格来替换换行符
.--/./.-../-.-./---/--/./-/---/-./-.-/-.-./-/..-./--..--/-/...././.--./.-/.../.../.--/---/.-./-../../.../.----/-..../-.../-.--/-/./.../.-./.-/-./-../---/--/.-../-.--/--././-././.-./.-/-/./-../--..-

vigenere(维吉尼亚)密码:

1.给了密文和Key

直接拉到cyberchef中解密即可

2.给了密文,没给密钥,但是知道目标明文的格式

先用B神的脚本爆破出Key,然后再把这个Key放到cyberchef中解密

3.根据对照表,手搓密钥的前几位

vigenere

希尔密码:

解密网站:http://www.metools.info/code/hillcipher243.html

已知密文和密钥,并且密钥(key)是一个网址,如http://www.verymuch.net

已知密文和密钥,并且密钥是四个数字

1
2
密文:ymyvzjtxswwktetpyvpfmvcdgywktetpyvpfuedfnzdjsiujvpwktetpyvnzdjpfkjssvacdgywktetpyvnzdjqtincduedfpfkjssne
密钥:3 4 19 11

Rabbi密码:

已知密文和密钥,密文有点像base64编码的(可能有+号)

云隐密码:

特征是:密文只由01248组成

用随波逐流或者CTFD中的脚本直接跑

差分曼彻斯特编码:

ID为0x8893CA58的温度传感器的未解码报文为:3EAAAAA56A69AA55A95995A569AA95565556

直接用CTFD中的脚本跑(要去掉开头的3E)

社会主义核心价值观密码:

解密网址:http://www.hiencode.com/cvencode.html

公正民主公正文明公正和谐:abc

outguess解密图片:

在kali中下载outguess:outguess -k ‘abc’ -r mmm.jpg -t flag.txt

outguess -k ‘key’ -r 加密后的图片.jpg -t 明文.txt

盲文:

使用https://www.qqxiuzi.cn/bianma/wenbenjiami.php?s=mangwen在线翻译

base64隐写:

直接用CTFD中的脚本跑出答案就行

文本加密为音乐符号:

eg:♭♯♪‖¶♬♭♭♪♭‖‖♭♭♬‖♫♪‖♩♬‖♬♬♭♭♫‖♩♫‖♬♪♭♭♭‖¶∮‖‖‖‖♩♬‖♬♪‖♩♫♭♭♭♭♭§‖♩♩♭♭♫♭♭♭‖♬♭‖¶§♭♭♯‖♫∮‖♬¶‖¶∮‖♬♫‖♫♬‖♫♫§=

直接用在线网站解密:https://www.qqxiuzi.cn/bianma/wenbenjiami.php?s=yinyue

敲击码:

敲击码

….. ../… ./… ./… ../ 5,2 3,1 3,1 3,2 W L L M

Polybius密码(详见CTFwiki)

类似于11,22,11,24这样的

去逗号改成空格,拉入随波逐流直接解密

AES加密(需要key)

不需要填IV的情况

  1. 可以用这个网站:http://tools.bugscaner.com/cryptoaes/

![NO_IV.png](../../../../../../../../images/CTF——Misc Guide_2023-11-03-20-02-41.png)

  1. 可以使用cyberchef,将IV设置为\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00

密钥不足16字节的情况(需补齐16byte)

  1. 可以使用这个网站:https://www.sojson.com/encrypt_aes.html

  2. /posts/1ad9200/imgs/aes1.png

  3. 可以将密文和key拉入CaptfEncoder-win-x64-1.3.0解密

/posts/1ad9200/imgs/aes2.png

也可能是Base64+AES-128混合加密,直接用厨子解密 要注意使用ECB mode并且把Input改为raw (key不足16位的话就在后面补0)

埃特巴什码(Atbash)

类似于:(+w)v&LdG_FhgKhdFfhgahJfKcgcKdc_eeIJ_gFN

拉入厨子直接解密

1
flag{ ==> Atbash加密 ==> UOZT{

DNA编码

1
AATTCAACAACATGCTGC

1、使用CTFD中的DNAcode脚本解密

https://github.com/omemishra/DNA-Genetic-Python-Scripts-CTF

2、网上找的脚本(红明谷杯2023——hacker)

1
2
3
4
5
6
7
8
table = 'ACGT'
dic = {'AAA': 'a', 'AAC': 'b', 'AAG': 'c',
       'AAT': 'd', 'ACA': 'e', 'ACC': 'f', 'ACG': 'g', 'ACT': 'h', 'AGA': 'i', 'AGC': 'j', 'AGG': 'k', 'AGT': 'l', 'ATA': 'm', 'ATC': 'n', 'ATG': 'o', 'ATT': 'p', 'CAA': 'q', 'CAC': 'r', 'CAG': 's', 'CAT': 't', 'CCA': 'u', 'CCC': 'v', 'CCG': 'w', 'CCT': 'x', 'CGA': 'y', 'CGC': 'z', 'CGG': 'A', 'CGT': 'B', 'CTA': 'C', 'CTC': 'D', 'CTG': 'E', 'CTT': 'F', 'GAA': 'G', 'GAC': 'H', 'GAG': 'I', 'GAT': 'J', 'GCA': 'K', 'GCC': 'L', 'GCG': 'M', 'GCT': 'N', 'GGA': 'O', 'GGC': 'P', 'GGG': 'Q', 'GGT': 'R', 'GTA': 'S', 'GTC': 'T', 'GTG': 'U', 'GTT': 'V', 'TAA': 'W', 'TAC': 'X', 'TAG': 'Y', 'TAT': 'Z', 'TCA': '1', 'TCC': '2', 'TCG': '3', 'TCT': '4', 'TGA': '5', 'TGC': '6', 'TGG': '7', 'TGT': '8', 'TTA': '9', 'TTC': '0', 'TTG': ' '}
cipher = 'TCATCAACAAAT'
plain = ''
for i in range(0, len(cipher), 3):
    plain += dic[cipher[i:i+3]]
print(plain)

Text Encoding Brute Force

如果赛博厨子转完两次Hex后依然是乱码,可以用Text Encoding Brute Force爆破试试看

例子:红明谷杯2023——阿尼亚

Decabit编码

正常的 Decabit编码 是十个字符一组的,如果不是十个一组,就很可能不是 Decabit编码

+-+-++–+- ++—+-++- -+–++-++- +–++-++– –+++++— ++-++—+- +++-+-+— +-+-+—++ —+++-++- -+–++-++- -+–+++-+- -+–++-++- -+–++-++- ++-+-+-+– -+–+++-+- ++-++—+- -++++—+- -+–++-++- ++-+-+-+– +-+++—+- +++-++—- —+++-++- +-+-+—++ ++-+-+-+– +-+-+–++- ++–+–++- -++++—+- +—+++-+- ++-+-+-+– -++++—+- -+–+++-+- +–+-+-++- +++-+-+— +-+++—+- -+–+-+++- -+–++-++- —+++-++- ++++—-+- -++++—+- -+–+++-+- -+–++-++- —-+++++-

直接使用 在线网站 解密即可

如果不是Decabit编码,可以试试看把+-分别用01替换 [2023 楚慧杯-Easy_zip]

仿射密码

有两个key,key-a为必须是(1,3,5,7,9,11,15,17,19,21,23,25)中的一个,key-b是0~25的数字

可以使用在线网站CTF在线工具-在线仿射密码加密|在线仿射密码解密|仿射密码算法|Affine Cipher (hiencode.com)或者随波逐流解密

1
2
3
gezx{j13p5oznp_1t_z_900y_k3z771h_k001}
key-a=17	key-b=77
flag{w13e5hake_1s_a_900d_t3a771c_t001}

BrainFuck编码

可以直接使用在线网站解码,但是flag可能会藏在内存中然后被删去导致无法输出flag,因此可以用下面这个代码输出之前放在内存中的flag

 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
69
70
71
72
73
74
75
#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
char s[30000]={0};
char code[2000];
int len = 0;
int stack[10000];
int stack_len=0;
int main()
{
    char c;
    int i=0,j,k,x=0;
    FILE* f;
    char* p=s+10000;
    f=fopen("./bf.txt","r");
    while(fread(&code[len],1,1,f)==1)
	{
        len++;
    }
    setbuf(stdout,NULL);
    while(i<len) {
        switch(code[i]) {
            case '+':
                (*p)++;
                break;
            case '-':
                (*p)--;
                break;
            case '>':
                p++;
                break;
            case '<':
                p--;
                break;
            case '.':
                putchar((int)(*p));
                break;
            case ',':
                *p=getchar();
                break;
            case '[':
                if(*p) {
                    stack[stack_len++]=i;
                } else {
                    for(k=i,j=0;k<len;k++) {
                        code[k]=='['&&j++;
                        code[k]==']'&&j--;
                        if(j==0)break;
                    }
                    if(j==0)
                        i=k;
                    else {
                        fprintf(stderr,"%s:%dn",__FILE__,__LINE__);
                        return 3;
                    }
                }
                break;
            case ']':
                i=stack[stack_len-- - 1]-1;
                break;
            default:
                break;
        }
        i++;
        x++;
    }
    for(int i = 0; i < stack_len; i++) {
		printf("%c", stack[i]);
	}
    printf("\n");
    for(int i = 0; i < 30000; i++) {
		printf("%c", s[i]);
	}
    return 0;
}

Gronsfeld密码

1
2
3
4
5
6
7
8
# 解密脚本
from pycipher import Gronsfeld

cipher = 'TGLBOMSJNSRAJAZDEZXGHSJNZWHG'
key = [1,50,61,8,9,20,63,41]
secret = Gronsfeld(key).decipher(cipher)

print(secret)

UUencode编码

看起来有点像base85,直接使用在线网站解密即可

1
2
=8S4U,3DR8SDY,C`S-F5F-C(S,S<R-C`Q9F8S87T`
# c55192c992036ef623372601ff3a}

AAencode编码

XXencode编码

随波逐流直接解密即可 [2023 浙江省赛决赛]

无字天书(whitespace)&snow隐写

一个文件打开都是空白字符

可以使用在线网站解密:https://vii5ard.github.io/whitespace/ 复制进去直接run即可

snow隐写,到snowdos32工具目录下运行 SNOW.EXE -C -p password flag.txt 命令即可

中文电报(中文电码)

类似于下面这种四位数一组的编码,直接在线网站解码即可

5337 5337 2448 2448 0001 2448 0001 2161 1721 1869 6671 0008 3296 4430 0001 3945 0260 3945 1869 4574 5337 0344 2448 0037 5337 5337 0260 0668 5337 6671 0008 3296 1869 6671 0008 3296 1869 2161 1721

Quote-Printable编码

类似于下面这样的编码,直接使用 在线网站 解密即可

flag{ichunqiu_=E6=8A=80=E6=9C=AF=E6=9C=89=E6=B8=A9=E5=BA=A6}

flag{ichunqiu_技术有温度}

中文ascii码

1
27880 30693 25915 21892 38450 23454 39564 23460 21457 36865 112 108 98 99 116 102 33719 21462 21069 27573 102 108 97 103 20851 27880 79 110 101 45 70 111 120 23433 20840 22242 38431 22238 22797 112 108 98 99 116 102 33719 21462 21518 27573 102 108 97 103

加上&#和分号,直接 CyberChef 或者 在线网站 解密即可

1
&#27880;&#30693;&#25915;&#21892;&#38450;&#23454;&#39564;&#23460;&#21457;&#36865;&#112;&#108;&#98;&#99;&#116;&#102;&#33719;&#21462;&#21069;&#27573;&#102;&#108;&#97;&#103;&#20851;&#27880;&#79;&#110;&#101;&#45;&#70;&#111;&#120;&#23433;&#20840;&#22242;&#38431;&#22238;&#22797;&#112;&#108;&#98;&#99;&#116;&#102;&#33719;&#21462;&#21518;&#27573;&#102;&#108;&#97;&#103;

培根密码

由 a、b 或者 A、B 或者 0、1 组成的密文,密文中只有两种字符,可以直接使用 随波逐流 解密

Tips:CyberChef 的培根密码解密可能会有点问题,这里建议用随波逐流解密

锟斤拷

这个东西的成因是 Unicode 的替换字符(Replacement Character,�)于 UTF-8 编码下的结果 EF BF BD 重复,在 GBK 编码中被解释为汉字 “锟斤拷”(EF BF BD EF BF BD)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import os

a = input('请选择你的功能(1、加密 2、解密):')
if a == "1":
    s = input('请输入你要加密的话:')
    utf = s.encode('utf')
    gbk = s.encode('utf').decode('gbk', errors='ignore')
    if len(s)%2 == 1:
        gbk = gbk + "�"
    print(gbk)
    os.system("pause")
if a == "2":
    s = input('请输入你要解密的话:')
    gbk = s.encode('gbk')
    utf = s.encode('gbk').decode('utf-8', errors='ignore')
    print(utf)
    os.system("pause")

键盘坐标密码

1
2
3
4
  1 2 3 4 5 6 7 8 9 0
1 Q W E R T Y U I O P
2 A S D F G H J K L
3 Z X C V B N M

例题-i春秋-misc3

1
2
flag{11 21 31 18 27 33 34}
flag{QAZIJCV}

福尔摩斯密码

1
·-· ·-· ·-· ·-· ·-· ·-· ·

直接网上查找福尔摩斯密码对照表即可 flag{RRRRRRE}

手机九宫格键盘密码

参考链接:https://blog.csdn.net/qq_55011640/article/details/123626280

下面举个栗子就理解了: 82  73  42  31  22  31  33  41  32 U   R   H   D  B   D   F   G   E

利用编程代码画图

  1. LOGO编程语言【例题-[RCTF2019]draw 】 在线编译器:https://www.calormen.com/jslogo/
  2. CFRS编程语言【例题-2024宁波市赛初赛 Misc2】 在线画图网站:https://susam.net/cfrs.html

各种文件头/尾:

这里要注意,出题人可能会把文件头的小写字母偷偷改成大写,例如:Rar -> RAR

 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
.zip的文件头:50 4B 03 04 14 00 08 00
.rar的文件头:52 61 72 21
.rar的文件尾:C4 3D 7B 00 40 07 00
.pyc的文件头:03 F3 0D 0A
.jpg的文件头:FF D8 FF
.png的文件头:89 50 4e 47 0d 0a 1a 0a   文件尾:49 45 4E 44 AE 42 60 82
.gif的文件头:47 49 46 38 39 61(GIF89A)或 47 49 46 38 37 61(GIF87A)
.gif的文件尾:00 3B
.gz的文件头:1F 8B 08 00
.pyc的文件头:03 F3 0D 0A
.psd的文件头:38 42 50 53
TIFF (tif),文件头:49492A00
Windows [Bitmap](https://so.csdn.net/so/search?q=Bitmap&spm=1001.2101.3001.7020) (bmp),文件头:424D
CAD (dwg),文件头:41433130
Adobe Photoshop (psd),文件头:38425053
Rich Text Format (rtf),文件头:7B5C727466
XML (xml),文件头:3C3F786D6C
HTML (html),文件头:68746D6C3E
Email [thorough only] (eml),文件头:44656C69766572792D646174653A
Outlook Express (dbx),文件头:CFAD12FEC5FD746F
Outlook (pst),文件头:2142444E
MS Word/Excel (xls.or.doc),文件头:D0CF11E0
MS Access (mdb),文件头:5374616E64617264204A
WordPerfect (wpd),文件头:FF575043
Postscript (eps.or.ps),文件头:252150532D41646F6265
Adobe Acrobat (pdf),文件头:255044462D312E
Quicken (qdf),文件头:AC9EBD8F
Windows Password (pwl),文件头:E3828596
Wave (wav),文件头:57415645
AVI (avi),文件头:41564920
Real Audio (ram),文件头:2E7261FD
Real Media (rm),文件头:2E524D46
MPEG (mpg),文件头:000001BA
MPEG (mpg),文件头:000001B3
Quicktime (mov),文件头:6D6F6F76
Windows Media (asf),文件头:3026B2758E66CF11
MIDI (mid),文件头:4D546864
M4a,文件头:00000018667479704D3441
1
2
#Tips
1.PNG文件的前16字节是已知的:89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52

Misc——流量分析

详见作者博客中的 Network Traffic Analysis 这篇文章

MIsc——图片题思路:

Tips:各种隐写可以先拉入一键梭哈网站解析一下:https://aperisolve.fr/

通用思路

1、查看图片属性的详细信息(可能关键信息就在里面)

2、拉入010,查看文件头尾,可能会有不同类型文件文件头混用

3、foremost 或者 binwalk

如果 foremost 没有提取出东西,可以用 binwalk 试一下,可能 binwalk可以提取出东西

例题 - i春秋 CTF Misc class10

4、盲水印隐写(可能是一张图片或者两张图片)

一张图片的情况

可以使用 隐形水印工具V1.2 或者 WaterMark 来提取水印

/posts/1ad9200/imgs/bw1.png

两张图片的情况

1
2
3
先把要处理的图片拉入BlindWaterMark-master文件夹,然后使用如下命令
py bwmforpy3.py decode day1.png day2.png flag.png --oldseed
Tips:这里还会出现FFT(傅里叶盲水印):直接运行CTFD中的FFT.py

5、图片的分离和拼接

(1)可以用kali的convert分离和montage拼接命令

1
2
3
4
5
6
分解GIF的命令:convert glance.gif flag.png
水平镜像翻转图片:convert -flop reverse.jpg reversed.jpg
垂直镜像翻转图片:convert -flip reverse.jpg reversed.jpg
合成图片的命令:montage flag*.png -tile x1 -geometry +0+0 flag.png
-tile是拼接时每行和每列的图片数,这里用x1,就是只一行
-geometry是首选每个图和边框尺寸,我们边框为0,图照原始尺寸即可

(2)使用在线网站分解:https://tu.sioe.cn/gj/fenjie/

(3)用py脚本跑

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import os
from PIL import Image
im = Image.new('RGB', (2*201, 600))  # new(mode,size) size is long and width
PATH = 'E:/ctf/glance.gif'
FILE_NAME = [i for i in os.listdir(PATH)]
width = 0
for i in FILE_NAME:
    im.paste(Image.open(PATH+i), (width, 0, width+2, 600))  # box is 左,上,右,下
    width += 2
im.show()

6、像素点合成

注:Linux wc命令用于计算字数。

-l或–lines 显示行数。

-w或–words 只显示字数。

-c或–bytes或–chars 只显示Bytes数。

可以改个标题后用在线网站将txt转换为ppm文件

7、Image conbiner(两张图片)

两张图片可能有部分残缺(可以互补)

给了两张图片时,用Stegsolve.jar,打开其中一张,

然后再Analyze-Image conbiner打开另一张图片

还有可能是给了两张二维码,需要两个二维码每个像素亦或,直接用CTFD中的像素亦或脚本即可

8、OurSecret隐写

拉入OurSecret,输入密码解密,得到隐藏文件

9、拼图题

碎图片合成一张图片

1
2
3
#在Windows中使用imagemagick处理
magick.exe montage *.png -tile 18x10 -geometry 125x125+0+0 flag.jpg
magick montage *.png -tile 40x22 -geometry +0+0 flag-0.png
1
2
3
4
5
6
7
#在kali中处理
拉入kali里处理,如果是碎的图片,
先使用 montage *.PNG -tile 12x12 -geometry +0+0 out.png合成一张图片
*.png表示匹配所有图片
-tile表示图片的张数
-geometry +0+0表示每张图片的间距为0
合成后要先查看图片的宽高(宽高要相等,不相等要用PS调整)

然后把上面合成好的图片使用 Puzzle-Merak 工具进行智能拼图

/posts/1ad9200/imgs/puzzles1.png

/posts/1ad9200/imgs/puzzles2.png

这里只需要输入 generation、population、size 并用分号分开即可开始自动拼图

也可以使用gaps智能拼图(在kali和wsl里使用都可以)

1
2
3
4
5
6
7
8
gaps --image=out.png --generation=30 --population=144 --size=30 --save 

--image 指向拼图的路径
--size 拼图块的像素尺寸
--generations 遗传算法的代的数量
--population 个体数量
--verbose 每一代训练结束后展示最佳结果
--save 将拼图还原为图像
1
2
3
4
5
6
gaps --image=flag.jpg --generations=50 --population=180 --size=125 --verbose

-generations 你要迭代多少次
-population 你有多少个小拼图
--size 每张小图,也就是拼图小块的大小
--verbose 实时显示

10、近邻法缩放图片

在PS中打开图片,然后在更改图像大小中,将宽高调成指定像素并将重新采样选项选为邻近(硬边缘)

11、pixeljihad(有密码)

直接使用在线网站解密即可:PixelJihad (sekao.net)

12、隐写文本可能藏在原图片和隐写文件的中间

直接在010中搜索IEND,然后查看后面有没有额外内容即可

13、提取图片中等距的像素点得到隐写的图片

在windows的终端wt中运行CTFD中的Get_Pixels.py

1
2
3
4
py main.py -f arcaea.png -p 0x0+3828x2148 -n 12x12
py main.py -f 要解密的图片 -p 第一个像素点的XY坐标+最后一个像素点的XY坐标 -n 两个等距像素点的XY距离的差值
如果是等距离提取整张图片中所有像素点,要注意右下角那个点的位置XY都要减去一倍的距离
Tips:在PS中按F8就可以看到每个像素点的具体坐标了

14、silenteye隐写

特征:放大图像后会有行列不对齐的小灰块

直接用 silenteye 打开输入密钥decode即可,默认密钥是 silenteye

15、图片报错改宽高后图片无变化,可以再 foremost 一下

16、DeEgger Embedder隐写

可以直接使用 DeEgger Embedder 工具 extract files

17、flag可能藏在 exif 中

直接在 WSL 中输入以下命令查看即可,如果偷懒也可以直接使用 破空 flag 查找工具 进行查找

1
exiftool 3.jpg

PNG思路

1、CRC错误(不能乱改),改宽高,17~20是宽,21~24是高(可用Pictools脚本快速爆破)

2、LSB(最低有效位)隐写:

没有密钥的情况

1
2
3
4
# 用zsteg快速查看
zsteg -a (文件名)  #查看各个通道的lsb
-b的位数是从1开始的 zsteg zlib.bmp -b 1 -o xy -v
提取文件并导出 zsteg -e b1,r,lsb,xy 3.png > 123.jpg

信息藏在图片中有时候会看不出来,所以还是要用stegsolve.jar过一遍

有密钥的情况(cloacked-pixel)

lsb隐写的可能是加密后的数据,i春秋最喜欢的cloacked-pixel

拉到kali/WSL里用cloacked-pixel命令解密出数据

1
python2 cloacked-pixel-master/lsb.py extract 0.png out.data f78dcd383f1b574b

0.png是隐写后的图片;out.data是隐写内容保存的位置;f78dcd383f1b574b是密钥

3、LSB低位隐写

用CTFD中的脚本跑出隐藏的图片

4、IDAT块隐写

拉到kali里用pngcheck -v 0.png检查IDAT

(1) 解压zlib获得原始数据

然后用010提取数据扔进zlib脚本解压获得原始数据

将异常的IDAT数据块斩头去尾之后使用脚本解压,在python2代码如下:

1
2
3
4
5
6
import zlib
import binascii
IDAT = "789C5D91011280400802BF04FFFF5C75294B5537738A21A27D1E49CFD17DB3937A92E7E603880A6D485100901FB0410153350DE83112EA2D51C54CE2E585B15A2FC78E8872F51C6FC1881882F93D372DEF78E665B0C36C529622A0A45588138833A170A2071DDCD18219DB8C0D465D8B6989719645ED9C11C36AE3ABDAEFCFC0ACF023E77C17C7897667".decode('hex')
result = binascii.hexlify(zlib.decompress(IDAT))
print (result.decode('hex'))
print (len(result.decode('hex')))

(2) 加上文件头爆破宽高得到新的图片(2023安洵杯-dacongのsecret)

一般出问题的 IDAT Chunk 大小都是比正常的小的,很可能在图片末尾

如果不确定是哪一个有问题,可以尝试都提取出来,一个一个分析

可以使用 tweakpng 辅助分析,但是一般用010的模板提取分析就够了

5、png数据末尾藏zip

补上压缩包的文件头,然后提取出来,解压(可用stegpy得到解压密码)。

或者直接foremost提取

6、apngdis_gui

一张png图片还可能是apng,直接用apngdis_gui跑一下,可以分出两张相似的png

7、CVE-2023-28303 截图工具漏洞

可以使用Github上大佬写好的工具一把梭,前提是需要知道原图的分辨率

8、stegpy隐写

stegpy 开源地址 下载好后直接用WSL输入以下命令并输入密码解密即可

也可以直接用 pip 安装: pip3 install stegpy

1
stegpy 1.png -p

JPG思路

1、可以试试用stegdectet看看是什么加密:

.\stegdetect.exe -t jopi -s 10.0 .\0.jpg

stegdectet

出现三颗星不一定就代表一定是这种加密方式

2、JPHS隐写

有可能会有密码

导出步骤 Select File –> seek –> demo.txt –> Save the file

3、steghide隐写

1
2
#如果密码已经知道了
steghide extract -sf filename -p passwd

在WSL或者kali里用Stegseek跑(字典在wordlist里)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#如果密码未知
可以用下面这个脚本爆破
#bruteStegHide.sh
#!/bin/bash

for line in `cat $2`;do
    steghide extract -sf $1 -p $line > /dev/null 2>&1
    if [[ $? -eq 0 ]];then
        echo 'password is: '$line
        exit
    fi
done
1
2
#或者在WSL或者kali里用Stegseek跑(字典在wordlist里)
stegseek filename rockyou.txt

4、outguess隐写

1
2
3
outguess -k "abc" -r mmm.jpg flag.txt
#-k 后面跟的是解密的密钥
#flag.txt是解密后数据保存的位置

5、F5-steganography-master

把要解密的图片拉到F5文件夹中

1
2
3
4
5
#有密码的情况
java Extract beautiful.jpg -p passwd
#无密码的情况
java Extract beautiful.jpg
#解密出来的数据会放到F5文件夹下的output.txt中

BMP思路

1、bmp宽高爆破:

删除文件头,并保存为文件名.data,然后用GIMP打开修改宽高(这个比较方便)

或者直接用bmp爆破脚本跑 python script.py -f filename.bmp

1
#用这个脚本要注意对图片一个个使用
 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
import os
import time
import math
import argparse


parser = argparse.ArgumentParser()
parser.add_argument("-f", type=str, default=None, required=True,
                    help="输入同级目录下图片的名称")
args = parser.parse_args()

SAVE_DIR = os.getcwd()


def save_img(data, width=None, height=None, sqrt_num=None):
    with open(os.path.join(SAVE_DIR, "fix_width.bmp"), "wb") as f:
        f.write(data[:0x12] + width.to_bytes(4,
                byteorder="little", signed=False) + data[0x16:])

    with open(os.path.join(SAVE_DIR, "fix_height.bmp"), "wb") as f:
        f.write(data[:0x16] + height.to_bytes(4,
                byteorder="little", signed=False) + data[0x1a:])

    with open(os.path.join(SAVE_DIR, "fix_sqrt.bmp"), "wb") as f:
        f.write(data[:0x12] + sqrt_num.to_bytes(4,
                byteorder="little", signed=False) * 2 + data[0x1a:])


def get_pixels_size(data):
    bfSize = int.from_bytes(data[0x2:0x2+4], byteorder="little", signed=False)
    bfOffBits = int.from_bytes(
        data[0xa:0xa+4], byteorder="little", signed=False)
    biBitCount = int.from_bytes(
        data[0x1c:0x1c+2], byteorder="little", signed=False)
    channel = biBitCount // 8
    # 由于宽高都会被修改,所以我计算出来的Padding_size也不是正确的,没有意义
    # padding_size = (4 - col * channel % 4) * row if col * channel % 4 != 0 else 0
    # pixels_size = (bfSize - bfOffBits - padding_size) // channel
    return (bfSize - bfOffBits) // channel


if __name__ == '__main__':
    file_path = os.path.abspath(args.f)
    if os.path.splitext(args.f)[-1] != ".bmp":
        print("您的文件后缀名不为BMP!")
        time.sleep(1)
        exit(-1)

    with open(file_path, "rb") as f:
        data = f.read()
    col = abs(int.from_bytes(data[0x12:0x12+4],
              byteorder="little", signed=True))
    row = abs(int.from_bytes(data[0x16:0x16+4],
              byteorder="little", signed=True))
    pixels_size = get_pixels_size(data)

    width, height = pixels_size // row, pixels_size // col
    sqrt_num = int(math.sqrt((pixels_size)))
    save_img(data, width=width, height=height, sqrt_num=sqrt_num)

    print("温馨提示:由于填充字节的问题,所以可能会偏差几个像素!")
    print(f"1.修复宽度: {width}")
    print(f"2.修复高度: {height}")
    print(f"3.修复宽度高度为: {sqrt_num}")
    time.sleep(1)

2、wbStego4open隐写

用wbStego4open直接decode

GIF思路

1、GIF图片可能要分帧提取(在线网站或者工具)

1
2
# 在Windows或者WSL中执行以下命令进行分离
ffmpeg -i filename.gif frame%04d.png

然后GIF可能会还有时间轴隐写(每帧时间不同),因此需要乘以倍数,当然也可能会有空间轴隐写

Webp思路

webp文件用电脑自带的图片看可能会有点问题,建议用浏览器打开这种文件

webp可能是动图,可以用下面这个脚本分离webp中的每帧图片

1
2
3
4
5
6
7
from PIL import Image

img = Image.open('killer.webp')
n_frame = img.n_frames
for i in range(n_frame):
    img.seek(i)
    img.save(f'img/{i}.png')

RAW、ARW文件思路

1、RAW的LSB隐写

ARW文件是 Sony 相机的原始数据格式

可以使用 rawpy 模块读取图片的像素数据,查看是否存在LSB隐写【例:2024 L3HCTF RAWatermark】

示例脚本如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import rawpy
import numpy as np
import libnum

with rawpy.imread('image.ARW') as raw:
    # 从 raw 对象中获取可见的 Bayer 格式图像数据
    bayer_visible = raw.raw_image_visible
    # print(bayer_visible)
    # 用 bitwise_and() 函数将 bayer_visible 中的每个像素值与 1 进行按位与操作,以提取每个像素的最低有效位(LSB)
    lsb_array = np.bitwise_and(bayer_visible, 1)
    # print(lsb_array)
    # 使用 NumPy 数组的 flatten() 方法将 lsb_array 数组展平成一维数组
    lsb_array_flat = lsb_array.flatten()
    # print(lsb_array_flat)
    hidden_message = ''.join(map(str, lsb_array_flat))
    # 将隐写的数据转为十六进制,便于查看文件头
    hex_data = hex(int(hidden_message, 2))
    # print(hex_data[:10]) # 0x504b0304
    # 将二进制数据转换为byte类型数据
    data = libnum.b2s(hidden_message)

with open('flag.zip', 'wb') as f:
    f.write(data)

2、直接改后缀为.data,然后拖入Gimp即可

二维码思路

1、bmp转二维码

2、16进制转pyc

3、字符串制作二维码

1
2
3
直接右键使用B神的脚本制作二维码,制作前注意要把字符串的长度手动修正为平方数
1.0 1制作二维码
2.00 11制作二维码

4、四个TTL值转换一个字节的二进制数

5、Aztec code、DataMatrix、GridMatrix、汉信码、PDF417code等

我们平常见的最多的二维码就是QRcode,但是实际上还有很多不同类型的二维码,这里就简单举几个例子:

/posts/1ad9200/imgs/azteccode.gif

/posts/1ad9200/imgs/DataMatrix.png

/posts/1ad9200/imgs/GridMatrix.png

/posts/1ad9200/imgs/%E6%B1%89%E4%BF%A1%E7%A0%81.png

/posts/1ad9200/imgs/PDF417code.png

这里要注意的是,出题人可能会把图片反相导致无法直接扫描,因此我们可以先将图片拉入 PS 先进行反相处理

Misc——PDF题思路:

1、直接binwalk或者foremost解出隐藏文件

2、可能是wbStego4open隐写,用wbStego4open直接decode

3、PDF中可能携带了什么文件,可以在Firefox或者别的PDF软件中打开并提取

4、PDF中可能有透明的文字,直接全选复制然后粘贴到记事本中查看即可

5、DeEgger Embedder隐写

可以直接使用 DeEgger Embedder 工具 extract files

Misc——MS-Office题思路

Excel文件:.xls .xlsx

1、拉入010或者记事本,查找flag 2、取消隐藏先前隐藏的行和列 3、条件格式里设置突出显示某些单元格(黑白后可能会有图案) 4、要先将数据按照行列排序后再进行处理

Word文件:.doc .docx

1、直接foremost出隐藏文件

2、与宏有关系的各种攻击与隐写

分析word中的宏需要用到这样一个工具:oletools

这个工具直接在pip中安装即可使用: pip3 install oletools

doc格式可以不需要文档密码直接提取其中的vba宏代码

安装好oletools后直接运行以下代码提取即可,可能加密文档的加密算法就在期中

1
olevba .\attachment.doc > test.txt

3、利用行距来隐写(例:ISCC2023-汤姆历险记)

word中可能有一段是1倍行距,可能又有一段是1.5倍行距,需要根据不同行距敲出摩斯电码(单倍转为.多倍转为-空行转为空格或者分隔符)

Misc——txt题思路:

1、 有可能是ntfs,直接用NtfsStreamsEditor2扫描所在文件夹,然后导出可疑文件【如果是压缩包,一定要用winrar解压】

2、可能是wbStego4open隐写,用wbStego4open直接decode

3、如果是那种文件夹套文件夹的题目,可以直接把路径粘贴到everything中,让everything一把梭

4、无字天书(whitespace)&snow隐写

一个文件打开都是空白字符 可以使用在线网站解密:https://vii5ard.github.io/whitespace/ 复制进去直接run即可 snow隐写,到snowdos32工具目录下运行 SNOW.EXE -C -p password flag.txt 命令即可

Misc——html题思路:

1、可能是wbStego4open隐写,用wbStego4open直接decode

Misc——压缩包思路:

Tips:压缩包的密码可以是中英文字符和符号 ​没有思路时可以直接纯数字/字母暴力爆破一下

zip文件结构

三部分:压缩文件源数据区 + 压缩源文件目录区 + 压缩源文件目录结束标志

文件源数据区

HEX 数据 描述 010Editor 模板数据
50 4B 03 04 zip 文件头标记,看文本的话就是 PK 开头 char frSignature[4]
0A 00 解压文件所需 pkware 版本 ushort frVersion
00 00 全局方式位标记(有无加密),头文件标记后 2bytes ushort frFlags
00 00 压缩方式 enum COMPTYPE frCompression
E8 A6 最后修改文件时间 DOSTIME frFileTime
32 53 最后修改文件日期 DOSDATE frFileDate
0C 7E 7F D8 CRC-32 校验 uint frCrc

文件目录区

HEX 数据 描述 010Editor 模板数据
50 4B 01 02 目录中文件文件头标记 char deSignature[4]
3F 00 压缩使用的 pkware 版本 ushort deVersionMadeBy
0A 00 解压文件所需 pkware 版本 ushort deVersionToExtract
00 00 全局方式位标记(有无加密),目录文件标记后 4bytes ushort frFlags
00 00 压缩方式 enum COMPTYPE frCompression
E8 A6 最后修改文件时间 DOSTIME frFileTime
32 53 最后修改文件日期 DOSDATE frFileDate
0C 7E 7F D8 CRC-32 校验 uint frCrc

文件目录结束

50 4B 05 06 目录结束标记 char elSignature[4]
00 00 当前磁盘编号 ushort elDiskNumber
00 00 目录区开始磁盘编号 ushort elStartDiskNumber

rar文件结构

HEX 数据 描述 010Editor 模板数据
52 61 72 21 1A 07 00 rar 文件头标记,文本为 Rar!

Main block

HEX 数据 描述 010Editor 模板数据
33 92 B5 E5 全部块的 CRC32 值 uint32 HEAD_CRC
0A 块大小 struct uleb128 HeadSize
01 块类型 struct uleb128 HeadType
05 阻止标志 struct uleb128 HeadFlag

File Header

HEX 数据 描述 010Editor 模板数据
43 06 35 17 单独块的 CRC32 值 uint32 HEAD_CRC
55 块大小 struct uleb128 HeadSize
02 块类型 struct uleb128 HeadType
03 阻止标志 struct uleb128 HeadFlag

Terminator

HEX 数据 描述 010Editor 模板数据
1D 77 56 51 固定的 CRC32 值 uint32 HEAD_CRC
03 块大小 struct uleb128 HeadSize
05 块类型 struct uleb128 HeadType
04 00 阻止标志 struct uleb128 HeadFlag

1、压缩包伪加密

zip文件:

可以直接用ZipCenOp.jar修复:

java -jar ZipCenOp.jar r screct.zip

WinRAR打开、010改标志位、binwalk直接分离

如果压缩文件已损坏,则尝试用winrar打开,工具-修复压缩包

压缩源文件数据区:7-8位表示有无加密

压缩源文件目录区:9-10位表示是否是伪加密

一般这俩地方都是09 00的,大概率就是伪加密了(直接把第二个PK后的09改了就行)

rar文件:

第24个字节尾数为4表示加密,0表示无加密,将尾数改为0即可破解伪加密

2、CRC爆破(压缩包中文件比较小的时候)

使用CRC爆破需要文件大小小于等于18个字节

参考文章:https://blog.csdn.net/mochu7777777/article/details/110206427

可以使用CTFD中的两种脚本爆破一下(速度不同)

3、明文攻击

已知所有的明文或三段密钥

使用Advanced Archive Password Recovery破解

有和压缩包中的一样(CRC值一样)的文件时,压缩然后用AAPR进行明文攻击,这个攻击的过程可能需要几分钟

有了完整的三段密钥也可以使用这个工具破解密码

使用pkcrack破解

1
2
#将pkcrack作为系统命令使用
cp pkcrack /usr/sbin/pkcrack
1
pkcrack -c "README.txt" -p README.txt -C flag.zip -P README.zip
1
2
3
4
-C:要破解的目标文件(含路径)
-c:破解文件中的明文文件的名字(其路径不包括系统路径,从zip文件一层开始)
-P:压缩后的明文文件
-p:压缩的明文文件中明文文件的名字(也就是readme.txt在readme.zip中的位置)

已知部分明文

利用bkcrack进行攻击

参考资料

1
2
https://www.freebuf.com/articles/network/255145.html
https://byxs20.github.io/posts/30731.html#%E6%80%BB%E7%BB%93

该利用方法的具体要求如下:

1
2
3
4
至少已知明文的12个字节及偏移,其中至少8字节需要连续。
明文对应的文件加密方式为ZipCrypto Store
Tips:进行明文攻击前要判断制作压缩包的压缩工具,然后对已知明文使用特定工具进行压缩,再进行明文攻击
例子:bkcrack -C \$R9EG7XR.zip -c flag.txt -k 958597ea b9f7740b 622aed5e -d flag.txt

如何判断压缩工具(参考自B神的博客)

压缩攻击 VersionMadeBy(压缩所用版本)
Bandzip 7.06 20
Windows自带 20
WinRAR 4.20 31
WinRAR 5.70 31
7-Zip 63

bkcrack常用参数

1
2
3
4
5
6
7
8
9
-c 要解密的文件
-P 已知明文所在的压缩包
-p 已知的明文部分
-x 压缩包内目标文件的偏移地址  部分已知明文值
-C 加密压缩包
-o offset  -p参数指定的明文在压缩包内目标文件的偏移量
-k 后面加破解出的三段密钥
-d 后面加解密后数据的保存位置
-U 修改压缩包密码并导出	bkcrack -C flag.zip -c hint.jpg -k afb9fee3 f8795353 f6de1d4e -U out.zip 114514

例题:

1
2
3
4
#Tips:
xxd // xxd 命令用于用二进制或十六进制显示文件的内容
-r // 把xxd的十六进制输出内容转换回原文件的二进制内容
-ps // 以 postscript的连续十六进制转储输出,这也叫做纯十六进制转储
1)简单的加密文本压缩包破解
1
flag{16e371fa-0555-47fc-b343-74f6754f6c01}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#攻击步骤如下:
#准备已知明文
echo -n "lag{16e3" > plain1.txt   #连续的8明文
echo -n "74f6" | xxd             #额外明文的十六进制格式,37346636
#攻击,-o是偏移量
bkcrack -C flag_360.zip -c flag.txt -p plain1.txt -o 1 -x 29 37346636
#由于时间较长,为防止终端终端导致破解中断,可以加点小技巧
bkcrack -C flag_360.zip -c flag.txt -p plain1.txt -o 1 -x 29 37346636 > 1.log& 
#后台运行,结果存入1.log
#加上time参数方便计算爆破时间
time bkcrack -C flag_360.zip -c flag.txt -p plain1.txt -o 1 -x 29 37346636 > 1.log&
#查看爆破进度
tail -f 1.log
#使用该秘钥进行解密:
bkcrack -C flag_360.zip -c flag.txt  -k b21e5df4 ab9a9430 8c336475 -d flag.txt
1
2
#-p 指定的明文不需要转换,-x 指定的明文需要转成十六进制
#提到的偏移都是指 “已知明文在加密前文件中的偏移”。
2)利用PNG图片文件头破解
1
2
3
4
5
6
#准备已知明文
echo 89504E470D0A1A0A0000000D49484452 | xxd -r -ps > png_header
#攻击
time bkcrack -C png4.zip -c 2.png -p png_header -o 0 >1.log&
tail -f 1.log
time bkcrack -C png4.zip -c flag.txt -k e0be8d5d 70bb3140 7e983fff -d flag.txt
3)利用压缩包格式破解
1
2
3
4
5
将一个名为flag.txt的文件打包成ZIP压缩包后,发现文件名称会出现在压缩包文件头中,且偏移固定为30。且默认情况下,flag.zip也会作为该压缩包的名称。
已知的明文片段有:
“flag.txt”  8个字节,偏移30
ZIP本身文件头:50 4B 03 04 ,4字节
满足12字节的要求
1
2
3
4
5
6
7
8
9
echo -n "flag.txt" > plain1.txt #-n参数避免换行,不然文件中会出现换行符,导致攻击失效
time bkcrack -C test5.zip -c flag.zip -p plain1.txt -o 30  -x 0 504B0304 >1.log&
tail -f 1.log
bkcrack -C test5.zip -c flag.zip -k b21e5df4 ab9a9430 8c336475  -d flag.zip
#但若想解密2.png,由于是ZipCrypto deflate加密的
#使用deflate算法压缩的文件,解码出来的是Deflate的数据流
#所以解密后需要bkcrack/tool内的inflate.py脚本再次处理
bkcrack -C test5.zip -c 2.png -k b21e5df4 ab9a9430 8c336475  -d 2.png
python3 inflate.py < 2.png > 2_out.png

Tips:如果这里用"XXXXX.txt"作为plaint1.txt无法破解出密钥,可以试试直接去掉后缀再作为plaint1.txt

例如:NKCTF2023——五年Misc,三年模拟

1
2
3
#echo -n "handsome.txt" > plain1.txt 破解失败
echo -n "handsome" > plain1.txt
time bkcrack -C test5.zip -c handsome.zip -p plain1.txt -o 30  -x 0 504B0304 >1.log&
4)EXE文件格式破解
1
2
EXE文件默认加密情况下,不太会以store方式被加密,但它文件格式中的的明文及其明显,长度足够。如果加密ZIP压缩包出现以store算法存储的EXE格式文件,很容易进行破解。
大部分exe中都有这相同一段,且偏移固定为64:

img

1
2
3
4
echo -n "0E1FBA0E00B409CD21B8014CCD21546869732070726F6772616D2063616E6E6F742062652072756E20696E20444F53206D6F64652E0D0D0A2400000000000000" | xxd -r -ps > mingwen
time bkcrack -C nc64.zip -c nc64.exe -p mingwen -o64  >1.log&
tail -f 1.log
bkcrack -C nc64.zip -c nc64.exe -k b21e5df4 ab9a9430 8c336475  -d nc64.exe
5)流量包pcapng格式解密
1
2
3
echo -n "00004D3C2B1A01000000FFFFFFFFFFFFFFFF" | xxd -r -ps > pcap_plain1
time bkcrack -C 3.zip -c capture.pcapng -p pcap_plain1 -o 6
bkcrack -C 3.zip -c capture.pcapng  -k e33a580c  c0c96a81 1246d892  -d out.pcapng
6)网站相关文件破解
1
2
3
robots.txt的文件开头内容通常是User-agent: * 
html文件开头通常是 <!DOCTYPE html>
xml文件开头通常是<?xml version="1.0" encoding="UTF-8"?>
1
2
3
echo -n '<?xml version="1.0" encoding="UTF-8"?>' > xml_plain
time bkcrack -C xml.zip -c 123/web.xml -p xml_plain -o 0  //注意相对路径
bkcrack -C xml.zip -c 123/web.xml  -k e0be8d5d 70bb3140 7e983fff  -d web.xml
7)SVG文件格式破解
1
2
3
4
5
6
7
8
9
#SVG是一种基于XML的图像文件格式
echo -n '<?xml version="1.0" ' > plain.txt
bkcrack -C secrets.zip -c spiral.svg -p plain.txt -o 0
#解密 Store算法  直接解密即可
bkcrack -C secrets.zip -c spiral.svg -k c4038591 d5ff449d d3b0c696 -d spiral_deciphered.svg
#解密 deflate算法
bkcrack -C secrets.zip -c advice.jpg -k c4038591 d5ff449d d3b0c696 -d out.jpg
#该文件使用了deflate算法压缩的,解码出来的是Deflate的数据流,因此须将其解压缩。
python3 inflate.py < out.jpge > flag.jpg
8)VMDK文件格式破解
1
2
3
echo -n "4B444D560100000003000000" | xxd -r -ps > plain2
time bkcrack -C Easy_VMDK.zip -c flag.vmdk -p plain2 -o 0
time bkcrack -C Easy_VMDK.zip -c flag.vmdk -k xxx xxx xxx -d flag.vmdk

有时候直接给你部分明文的情况(2023 DASCTFxCBCTF)

直接在bkcrack中使用以下命令即可,key是题目给的压缩包中被压缩文件的部分明文

1
bkcrack -C purezip.zip -c 'secret key.zip' -p key

直接给了加密压缩包中部分文件的情况

例题1 - 2023 古剑山-幸运饼干

  • 可以先把该文件用压缩软件压缩成一个压缩包,然后用 Advanced Archive Password Recovery 明文攻击试试看

  • 用压缩软件把该文件压缩成一个压缩包,然后使用 bkcrack 进行明文攻击

    为什么需要压缩成压缩包呢?因为如果不带上压缩包进行明文攻击的话会报下面这个错误

    1
    2
    3
    
    $ bkcrack -C flag.zip -c 'hint.jpg' -p hint.jpg
    bkcrack 1.5.0 - 2023-03-08
    Data error: ciphertext is smaller than plaintext.

    用 -P 参数带上压缩包后即可正确解密出密钥

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    $ bkcrack -C flag.zip -c hint.jpg -p hint.jpg -P hint.zip
    bkcrack 1.5.0 - 2023-03-08
    [14:37:27] Z reduction using 25761 bytes of known plaintext
    100.0 % (25761 / 25761)
    [14:37:29] Attack on 289 Z values at index 21821
    Keys: afb9fee3 f8795353 f6de1d4e
    100.0 % (289 / 289)
    [14:37:29] Keys
    afb9fee3 f8795353 f6de1d4e

    因此这种情况一定要记得将已有的文件用适当的压缩方法压缩成压缩包,然后用-P参数带上这个压缩包

例题1 - 2023 铁三决赛-baby_jpg

我们先从部分伪加密的压缩包中分离出了 serect.pdf,然后从PDF中 foremost 出了加密压缩包中的 sha512.txt

将 sha512.txt 压缩成 sha512.zip,然后使用下面的命令进行明文攻击即可:

其中 -C 后是要破解的压缩包,-c 后是压缩包中我们要破解的文件,-P 后是我们压缩好的压缩包,-p 后是我们已得的文件

1
2
3
4
5
6
7
8
9
$ bkcrack -C 00000218.zip -c 'sha512.txt' -P sha512.zip -p sha512.txt
bkcrack 1.5.0 - 2023-03-08
[16:14:25] Z reduction using 78 bytes of known plaintext
100.0 % (78 / 78)
[16:14:25] Attack on 104916 Z values at index 6
Keys: ed3fb6a9 1c4a7211 c07461ed
59.9 % (62867 / 104916)
[16:14:52] Keys
ed3fb6a9 1c4a7211 c07461ed

破解出密钥后,用 -U 参数修改压缩包密码并导出

1
2
3
4
5
$ bkcrack -C 00000218.zip -k ed3fb6a9 1c4a7211 c07461ed -U out.zip 111
bkcrack 1.5.0 - 2023-03-08
[16:15:44] Writing unlocked archive out.zip with password "111"
100.0 % (3 / 3)
Wrote unlocked archive.

在比赛中的使用记录

2022 西湖论剑zipeasy

1
bkcrack -C zipeasy.zip -c dasflow.zip -x 30 646173666c6f772e706361706e67 -x 0 504B0304 > 1.log &

2023 DASCTFxCBCTF

利用bkcrack反向爆破密钥

1
2
3
4
5
6
7
bkcrack -k e48d3828 5b7223cc 71851fb0 -r 3 \?b
#bkcrack 1.5.0 - 2023-03-08
#[17:47:50] Recovering password
#length 0-6...
#[17:47:50] Password
#as bytes: 8b e7 dc
#as text: ���

然后如果要对得到的密钥进行MD5加密,可以使用CyberChef(From Hex + MD5)

/posts/1ad9200/imgs/MD5.png

4、暴力破解(爆破时注意限制长度)

可以使用 Advanced Archive Password Recovery 进行爆破

(1) 如果知道部分的密码,可以使用掩码攻击,例如:????LiHua

(2) 没啥思路的时候可以直接用纯数字密码爆破看看,也可以用字典爆破

(3) 如果爆破的速度很慢,可以用 Passware Kit Forensic 2021 v1 (64-bit) 来爆破(也可以自定义字典)

5、连环套压缩包

可以用fcrackzip进行爆破或者使用CTFD中的脚本爆破

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import zipfile
import re
file_name = 'pic/' + 'f932f55b83fa493ab024390071020088.zip'
while True:
  try:
     zf = zipfile.ZipFile(file_name)
     re_result = re.search('[0-9]*', zf.namelist()[0])
     passwd = re_result.group()
     zf.extractall(path='pic/', pwd=re_result.group().encode('ascii'))
     file_name = 'pic/' + zf.namelist()[0]
  except:
     print("get the result")

6、未知后缀的压缩包

可以多用几个压缩软件试试,比如Winrar 7z

7、分卷压缩包合并

1
copy /B topic.zip.001 + topic.zip.002+topic.zip.003+topic.zip.004+topic.zip.005+topic.zip.006 topic.zip

8、压缩包炸弹

很小的压缩文件,解压出来会占据巨大的空间,甚至撑爆磁盘 处理方法:010中直接编辑压缩包文件,看看是否藏有另一个压缩包

9、根据010中的模板修改了某些参数

有些题目可能会修改源数据中压缩包文件中被压缩文件的文件名的长度

源数据中被压缩文件名字的长度对不上也会导致解压后文件无法打开

所以…010的模板功能真的非常非常的好用!

/posts/1ad9200/imgs/010.png

10、压缩包密码是不可见字符

字节数很短的情况

直接写个Python脚本爆破即可

 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
import zipfile
import libnum

def solve():
    # 在ASCII编码中,一个字符占用8位(1字节)
    for i in range(256):
        for j in range(256):
            fz = zipfile.ZipFile('secret key.zip', 'r')
            password = libnum.n2s(i) + libnum.n2s(j)
            print(f"[+]正在尝试密码{password}")
            try:
                fz.extractall(pwd=password)
                fz.close()
                return password
            except:
                fz.close()
                continue
    return None

if __name__ == "__main__":
    password = solve()
    if password:
        print(f"[+]压缩包解压成功,密码是{password}")
    else:
        print(f"[+]在该范围内找不到压缩包密码,压缩包解压失败")

字节数较长的情况

需要先把密码base64编码一下,然后再base64解码成byte类型作为密码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import base64
import pyzipper

target_zip = '1.zip'
outfile = './solved'

pwd = base64.b64decode(b'aEXigItjVOKAjEbigI8=')
# b'hE\xe2\x80\x8bcT\xe2\x80\x8cF\xe2\x80\x8f'
with pyzipper.AESZipFile(target_zip, 'r') as f:
    f.pwd = pwd
    f.extractall(outfile)

Misc——视频题思路:

1、可能有音频隐写,用mkvtool分离出音频,再拉入Au看频谱图

2、可能是视频中的每一帧图片都有LSB隐写(2023 WMCTF)

3、循环读取视频每一帧图像中指定列的指定像素(2023 极客大挑战)

 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
import cv2
from PIL import Image

# 创建一个视频读取对象,读取名为'kira.mp4'的视频文件。
video = cv2.VideoCapture('kira.mp4')  # type: ignore

# # 设置要提取的帧数,如现在指定的是第100帧
# video.set(cv2.CAP_PROP_POS_FRAMES, 100)
# # 读取视频的指定帧
# ret, frame = video.read()
# # 保存提取的帧为图像文件
# cv2.imwrite('1.png', frame)
# # 释放视频对象
# video.release()

# 定义视频的尺寸为1920x1080
video_size = [1920, 1080]
# 设置起始像素为5
start_pixel = 5
# 设置每个像素块的大小为10
size = 10
# 创建一个新的图像对象,大小为视频尺寸除以像素块大小,即原视频的帧的抽样结果
out = Image.new('RGB', (video_size[0] // size, video_size[1]//size))
# 初始化帧率计数为0
fps_count = 0
# 循环读取每一帧图像中指定列的指定像素
while True:
    print(f"[+] 当前正在读取视频的第{fps_count}帧")
    # 从视频文件中读取一帧,success为是否成功读取帧的结果,frame为读取的帧
    success, frame = video.read()
    # 如果读取失败,跳出循环
    if not success:
        print(f"[X] 视频的第{fps_count}帧读取失败")
        break
    # 对每一行像素进行遍历,从视频的高度减去起始像素并除以像素块大小,得到需要遍历的行数
    for y in range((video_size[1]-start_pixel)//size):
        try:
            # 从当前行中获取一个像素,使用getpixel方法获取指定坐标处的像素,并将其转换为PIL图像格式
            pixel = Image.fromarray(frame).getpixel(
                (start_pixel+fps_count*size, start_pixel+y*size))
            # 将获取的像素值设置为抽样图像的对应像素位置的值
            out.putpixel((fps_count, y), pixel)
        except:
            pass
    # 帧率计数加1,准备下一帧的处理
    fps_count += 1

# 将抽样图像保存为'out.png'文件
out.save('out.png')
out.show()

4、DeEgger Embedder隐写

可以直接使用 DeEgger Embedder 工具 extract files

例题-攻防世界 PyHaHa

Misc——音频题思路:

1、波形图分析:摩斯电码

2、频谱图分析(有时要调高最高频率):

3、LSB(最低有效位隐写):用silenteye解密

4、SSTV慢扫描电视:

Windows中使用RX-SSTV

使用前还要安装虚拟声卡 Virtual Audio Cable

1
2
3
4
5
#使用步骤:
1.点击Setup-Sound Control and Devices将默认输入设备和输出设备都设置为虚拟声卡line1
2.用VLC播放音频(最好不要用Au播放)
3.如果扫描出来的图片有错位,可以点击slant手动修改
4.退出RX-SSTV前要注意把默认的输入/输出设备改回原来的参数

拉入kali用qsstv(有时候要用到反向和反相)

5、电话音分析

用在线网站:http://www.dialabc.com/sound/detect/

或者在dtmf2num.exe里使用dtmf2num -o C:\Desktop\1.wav命令

6、 WAV[RIFF]的隐写(有 deepsound 和 silenteye 或者其他):

先用deepsound 试一下,如果需要密码说明就是 deepsound 隐写

如果是deepsound隐写,就先用脚本获取wav文件的哈希值(注释里有使用方法),

然后拉入kali用john爆破hash(如果编码有误,可以先用notepad另存为一下)

执行:john 1.txt

7、wav可能是业余无线电文件:

先用sox把wav转为raw:

sox -t wav latlong.wav -esigned-integer -b16 -r 22050 -t raw latlong.raw

再用multimon-ng分析:

multimon-ng -t raw -a AFSK1200 latlong.raw

8、steghide

1
2
#如果密码已经知道了
steghide extract -sf filename -p passwd

在WSL或者kali里用Stegseek跑(字典在wordlist里)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#如果密码未知
可以用下面这个脚本爆破
#bruteStegHide.sh
#!/bin/bash

for line in `cat $2`;do
    steghide extract -sf $1 -p $line > /dev/null 2>&1
    if [[ $? -eq 0 ]];then
        echo 'password is: '$line
        exit
    fi
done
1
2
#或者在WSL或者kali里用Stegseek跑(字典在wordlist里)
stegseek filename rockyou.txt

9、MP3音频隐写

MP3stego

使用前需要先把要处理的文件放到MP3stego目录下

1
2
3
4
5
6
7
8
#Encode
encode -E data.txt -P pass sound.wav sound.mp3    
data.txt里面放要隐写的txt信息 pass是解密时需要的密码
#Decode
decode -X -P pass sound.mp3   
-X 是提取出隐写的文件
pass是解密时需要的密码 
sound.mp3是待处理的MP3文件

10、WAV还可能是OpenPuff隐写(有密码)

直接用OpenPuff.exe解密即可

11、提取并分析左右声道的差值

 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
# 导入模块wavfile
import scipy.io.wavfile as wavfile
# 读取音频文件的采样率和数据
sample_rate, data = wavfile.read("1.wav")
# print(sample_rate, data)
# 创建两个列表来存储左右两声道的数据
left = []
right = []

for item in data:
    # print(item)
    # 第一列的数据是左声道,第二列是右声道
    left.append(item[0])
    right.append(item[1])

diff = [str(left-right) for left, right in zip(left, right)]
res = ''
for item in diff:
    if item == '2':
        res += '1'
    elif item == '1':
        res += '0'
    else:
        continue
with open('res.txt', 'w') as f:
    f.write(res)

12、使用脚本提取数据进行分析

 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
# 2023 DASCTFxCBCTF
import numpy as np
import wave
import scipy.fftpack as fftpack

SAMPLE_RATE = 44100 # 表示采样率,即每秒钟有多少采样点
SAMPLE_TIME = 0.1 # 表示一个样本的时间,即0.1秒
SAMPLE_NUM = int(SAMPLE_RATE * SAMPLE_TIME) # 计算在SAMPLE_TIME时间内的采样点数
LIST = [800, 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700]   


def get_len():
    with wave.open('1.wav','rb') as f:
        # 使用numpy从音频文件中读取所有的帧并将其转换为int16数据类型的数组
        wav_data = np.frombuffer(f.readframes(-1),dtype=np.int16)
        N = len(wav_data)
        print(N)
    #这实际上计算了wav文件的总时长(以0.1秒为单位)
    a = (N/(44100*0.1)) / 189
    print(a)

# 傅立叶变换函数。给定时域数据,该函数返回其频域形式的前半部分
def fft(data):
    N = len(data)                                   #获取数据长度
    fft_data = fftpack.fft(data)                    #得到频域信号                      
    abs_fft = np.abs(fft_data)                      #计算幅值    
    abs_fft = abs_fft/(N/2)                             
    half_fft = abs_fft[range(N//2)]                 #取频域信号的前半部分

    return half_fft

# 此函数旨在解码100ms的音频数据。它首先对音频数据进行FFT变换,然后检查LIST中的每个频率,以确定哪些频率具有明显的活动(幅值大于0.8)  
def dec_100ms(wave_data_100_ms):
    fft_ret = fft(wave_data_100_ms)
    for index, freq in enumerate(LIST):
        if np.max(fft_ret[int(freq*SAMPLE_TIME) - 2 : int(freq*SAMPLE_TIME) + 2]) > 0.8:
            print(freq, 'Hz有值',end=" ")
            return index

# 解码整个音频文件中的句子。它首先确定音频中有多少个100ms的段,然后每次解码两个段来生成一个两位数的索引,该索引用于查找与之对应的字符
def dec_sentence(wav_data):
    _100ms_count = len(wav_data) // SAMPLE_NUM    
    # print(_100ms_count) 
    print('待解码音频包含', _100ms_count // 2, '个字')    
    ret = ''
    for i in range(0, _100ms_count, 2):              
        index = 0
        for k in range(2):
            index = index*10 + dec_100ms(wav_data[i*SAMPLE_NUM + k*SAMPLE_NUM : i*SAMPLE_NUM + (k+1)*SAMPLE_NUM])
        print('序号:', index)
        ret += string[index]
    return ret

if __name__ == '__main__':
    # get_len()
    # 题目给了一个字符串序列,所以就是从音频中提取出index,然后根据index找到对应的字符
    string ="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_}{-?!"
    with wave.open('1.wav', 'rb') as f:          #读取为数组
        wav_data = np.frombuffer(f.readframes(-1), dtype=np.int16)
    print(dec_sentence(wav_data))
    # DASCTF{Wh1stling_t0_Convey_informat1on!!!}

13、stegpy隐写

stegpy 开源地址 下载好后直接用WSL输入以下命令并输入密码解密即可

也可以直接用 pip 安装: pip3 install stegpy

1
stegpy 1.wav -p

14、DeEgger Embedder隐写

可以直接使用 DeEgger Embedder 工具 extract files

15、Silenteye隐写

音频文件也可能是 silenteye 隐写,可以拿默认密码 silenteye 解密试试看

Misc——取证题思路:

详解请查看我的另一篇 博客Misc——取证类题目详解

Git文件泄露:

1、利用命令git stash show 显示做了哪些改动

2、利用命令git stash apply导出改动之前的文件

OSINT

1.用yandex识图

Others:

字节序

字节的排列方式有两个通用规则:

1
2
大端序(Big-Endian)将数据的低位字节存放在内存的高位地址,高位字节存放在低位地址。这种排列方式与数据用字节表示时的书写顺序一致,符合人类的阅读习惯。
小端序(Little-Endian),将一个多位数的低位放在较小的地址处,高位放在较大的地址处,则称小端序。小端序与人类的阅读习惯相反,但更符合计算机读取内存的方式,因为CPU读取内存中的数据时,是从低地址向高地址方向进行读取的。

例子:

1
2
3
4
5
6
整型数值168496141 需要4个字节
对应的16进制表示是0X0A0B0C0D
大端序:
0x0A 0x0B 0x0C 0x0D
小端序:
0x0D 0x0C 0xB 0xA

为何要有字节序

1
因为计算机电路先处理低位字节,效率比较高,因为计算都是从低位开始的。所以,计算机的内部处理都是小端字节序。在计算机内部,小端序被广泛应用于现代 CPU 内部存储数据;而在其他场景,比如网络传输和文件存储则使用大端序。

使用Python中的struct模块来处理大小端序

 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
import struct

def display_binary(data):
    #将字节数据转化为十六进制表示形式
    # return ' '.join(['{:02x}'.format(byte) for byte in data])
    return ' '.join([f"{byte:02x}" for byte in data])

# 定义要打包的数据
int_data = 10240099
float_data = 123.456

# 使用默认端序(小端序)打包
packed_int_little = struct.pack('I', int_data)
packed_float_little = struct.pack('f', float_data)

# 使用大端序打包
packed_int_big = struct.pack('>I', int_data)
packed_float_big = struct.pack('>f', float_data)

# 打印打包的结果,display_binary()是以十六进制的形式显示
print("Packed data (Little Endian):")
print(packed_int_little)
print("Int:", display_binary(packed_int_little))
print(packed_float_little)
print("Float:", display_binary(packed_float_little))

print("\nPacked data (Big Endian):")
print(packed_int_big)
print("Int:", display_binary(packed_int_big))
print(packed_float_big)
print("Float:", display_binary(packed_float_big))

# 解包数据,由于返回的是一个元组,所以需要[0]
unpacked_int_little = struct.unpack('I', packed_int_little)[0]
unpacked_float_little = struct.unpack('f', packed_float_little)[0]

unpacked_int_big = struct.unpack('>I', packed_int_big)[0]
unpacked_float_big = struct.unpack('>f', packed_float_big)[0]

# 打印解包的结果
print("\nUnpacked data (Little Endian):")
print("Int:", unpacked_int_little)
print("Float:", unpacked_float_little)

print("\nUnpacked data (Big Endian):")
print("Int:", unpacked_int_big)
print("Float:", unpacked_float_big)

# 验证打包和解包是否保持数据的完整性(float类型的数据先打包再解包后可能会有误差)
assert int_data == unpacked_int_little
# assert float_data == unpacked_float_little

assert int_data == unpacked_int_big
# assert float_data == unpacked_float_big

print("\nData integrity maintained!")

十六进制数据大小端序转换

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
hex_data = """0x00006c66 0x00006761 0x0000617b 0x00006168 0x00005f21 0x00006f79 0x00005f75 0x00006f66 0x00006e75 0x00005f64 0x00007469 0x00007d21 0x00000000 """

def swap_endianness(hex_string):
    hex_bytes = bytes.fromhex(hex_string[2:])
    # 直接使用 bytes 类型的数据翻转即可
    swapped_bytes = hex_bytes[::-1]
    swapped_hex = swapped_bytes.hex()
    swapped_hex = '0x' + swapped_hex
    return swapped_hex


def solved():
    flag = ""
    # hex_data = input("请输入待转换的数据\n")
    hex_list = hex_data.split()
    for hex_num in hex_list:
        swapped_hex = swap_endianness(hex_num)
        print(swapped_hex)
        flag += bytes.fromhex(swapped_hex[2:]).decode()
    print(flag)


if __name__ == "__main__":
    solved()

Linux tar命令

打包压缩

1
2
3
4
5
6
7
#打包单独的文件
tar -cvf target.tar filename.txt
#打包整个目录
tar -cvf target.tar directory
#-c 表示创建新的tar包
#-v 表示显示详细信息
#-f 表示指定目标文件名

解压提取

1
2
3
4
#把压缩包中的所有文件解压到当前目录
tar -xvf target.tar
#把压缩包解压到指定目录
tar -xvf target.tar -C path

不同的键盘布局

Qwerty、Qwertz、Azerty

Dvorak

Colemak

例题-Black Mamba

0%