CRC(Cyclic Redundancy Check)校验实用程序库在数据存储和数据通讯领域,为了保证数据的正确,就不得不采用检错的手段。在诸多检错手段中,CRC是最著名的一种。CRC的全称是循环冗余校验。
每个文件都有唯一的CRC32值,即便数据发生很微小的变化,都会导致CRC32的值变化。假设知道段数据的长度和CRC32值,那么便可穷举数据,与其CRC32的值比较匹配,这样就可以达到暴力破解的目的。但是这么做缺点也很明显,就是只适用于数据内容较小的文件。
注意:一般数据内容小于5Bytes(<=4Bytes)即可尝试通过爆破CRC32穷举数据内容
获取文件的CRC值
因为压缩包软件显示的文件CRC值不可复制,所以手抄比较麻烦,而且容易出错,所以使用脚本和获取比较方便
import zipfile
file_handler = zipfile.ZipFile('./password.zip')#指定压缩包
name_list = file_handler.namelist()#使用一个列表获取压缩包内所有的文件名
crc_list = []
print('-------------Filename CRC Info-------------')
for name in name_list:
name_info = file_handler.getinfo(name)
crc_list.append(hex(name_info.CRC))
print('[+] {0}: {1}'.format(name,hex(name_info.CRC)))
print('-------------------------------------------')
print(crc_list)#根据情况获取,有时并压缩包内可能还有其他文件,可能需要切片,所以择情况选取
注意:这里获取的列表结果中是带单引号的字符,需要去掉单引号,也不需要十六进制补高,如下:
crc_list = [0xef347b51, 0xa8f1b31e, 0x3c053787, 0xbbe0a1b]
内容为1Byte的CRC爆破
首先我们先构造一个zip压缩包,里面存放四个大小为1Byte
的文件
4个1Byte
文件内容如下:
编写脚本,开始爆破
import binascii
import string
def crack_crc():
print('-------------Start Crack CRC-------------')
crc_list = [0xda6fd2a0, 0xf6a70, 0x70659eff, 0x862575d]#文件的CRC32值列表,注意顺序
comment = ''
chars = string.printable
for crc_value in crc_list:
for char1 in chars:
char_crc = binascii.crc32(char1.encode())#获取遍历字符的CRC32值
calc_crc = char_crc & 0xffffffff#将获取到的字符的CRC32值与0xffffffff进行与运算
if calc_crc == crc_value:#将每个字符的CRC32值与每个文件的CRC32值进行匹配
print('[+] {}: {}'.format(hex(crc_value),char1))
comment += char1
print('-----------CRC Crack Completed-----------')
print('Result: {}'.format(comment))
if __name__ == '__main__':
crack_crc()
可以看到通过爆破CRC我们成功获取到了文件的内容
内容为2Byte的CRC爆破
与前面同样的条件,只是增加了文件内容,大小变为2Byte
的文件
4个2Byte
文件内容如下:
import binascii
import string
def crack_crc():
print('-------------Start Crack CRC-------------')
crc_list = [0xef347b51, 0xa8f1b31e, 0x3c053787, 0xbbe0a1b]#文件的CRC32值列表,注意顺序
comment = ''
chars = string.printable
for crc_value in crc_list:
for char1 in chars:
for char2 in chars:
res_char = char1 + char2#获取遍历的任意2Byte字符
char_crc = binascii.crc32(res_char.encode())#获取遍历字符的CRC32值
calc_crc = char_crc & 0xffffffff#将获取到的字符的CRC32值与0xffffffff进行与运算
if calc_crc == crc_value:#将获取字符的CRC32值与每个文件的CRC32值进行匹配
print('[+] {}: {}'.format(hex(crc_value),res_char))
comment += res_char
print('-----------CRC Crack Completed-----------')
print('Result: {}'.format(comment))
if __name__ == '__main__':
crack_crc()
内容为3Byte的CRC爆破
import binascii
import string
def crack_crc():
print('-------------Start Crack CRC-------------')
crc_list = [0x2b17958, 0xafa8f8df, 0xcc09984b, 0x242026cf]#文件的CRC32值列表,注意顺序
comment = ''
chars = string.printable
for crc_value in crc_list:
for char1 in chars:
for char2 in chars:
for char3 in chars:
res_char = char1 + char2 + char3#获取遍历的任意3Byte字符
char_crc = binascii.crc32(res_char.encode())#获取遍历字符的CRC32值
calc_crc = char_crc & 0xffffffff#将遍历的字符的CRC32值与0xffffffff进行与运算
if calc_crc == crc_value:#将获取字符的CRC32值与每个文件的CRC32值进行匹配
print('[+] {}: {}'.format(hex(crc_value),res_char))
comment += res_char
print('-----------CRC Crack Completed-----------')
print('Result: {}'.format(comment))
if __name__ == '__main__':
crack_crc()
内容为4Byte的CRC爆破
import binascii
import string
def crack_crc():
print('-------------Start Crack CRC-------------')
crc_list = [0xc0a3a573, 0x3cb6ab1c, 0x85bb0ad4, 0xf4fde00b]#文件的CRC32值列表,注意顺序
comment = ''
chars = string.printable
for crc_value in crc_list:
for char1 in chars:
for char2 in chars:
for char3 in chars:
for char4 in chars:
res_char = char1 + char2 + char3 + char4#获取遍历的任意4Byte字符
char_crc = binascii.crc32(res_char.encode())#获取遍历字符的CRC32值
calc_crc = char_crc & 0xffffffff#将遍历的字符的CRC32值与0xffffffff进行与运算
if calc_crc == crc_value:#将获取字符的CRC32值与每个文件的CRC32值进行匹配
print('[+] {}: {}'.format(hex(crc_value),res_char))
comment += res_char
print('-----------CRC Crack Completed-----------')
print('Result: {}'.format(comment))
if __name__ == '__main__':
crack_crc()
可以看到这里爆破4Byte
的内容的CRC跟前面的相比已经非常耗时间了(174.025s
),当然也只是当前脚本的爆破的方式太简单了,导致耗时间
所以4Byte-6Byte
的CRC32爆破推荐使用:https:///theonlypwner/crc32
PS D:\Tools\Misc\crc32> python .\crc32.py reverse 0xc0a3a573
4 bytes: {0x54, 0x39, 0x5e, 0x6e}
verification checksum: 0xc0a3a573 (OK)
alternative: DgQUDh (OK)
alternative: JhNexf (OK)
alternative: cqeRUF (OK)
alternative: p1gRfQ (OK)
alternative: t5zSg2 (OK)
alternative: uYHOxo (OK)
PS D:\Tools\Misc\crc32> php -r "var_dump(hex2bin('54395e6e'));"
Command line code:1:
string(4) "T9^n"
PS D:\Tools\Misc\crc32> python .\crc32.py reverse 0x3cb6ab1c
4 bytes: {0x6d, 0x50, 0x33, 0x21}
verification checksum: 0x3cb6ab1c (OK)
alternative: 0CKdyP (OK)
alternative: 22cGME (OK)
alternative: 4GVex3 (OK)
alternative: 6FB7Iv (OK)
alternative: 9USjou (OK)
alternative: A2Vm_A (OK)
alternative: EZ8AZf (OK)
alternative: GGcOj7 (OK)
alternative: PNQs5K (OK)
alternative: RrTmlV (OK)
alternative: VvIlm5 (OK)
alternative: YeX1K6 (OK)
alternative: cLMwPQ (OK)
alternative: dUJIzz (OK)
alternative: gHPvQ2 (OK)
alternative: i7s7hl (OK)
alternative: jZUyFt (OK)
alternative: mCRGl_ (OK)
alternative: o2zdXJ (OK)
alternative: vyzUV0 (OK)
PS D:\Tools\Misc\crc32> php -r "var_dump(hex2bin('6d503321'));"
Command line code:1:
string(4) "mP3!"
PS D:\Tools\Misc\crc32> python .\crc32.py reverse 0x85bb0ad4
4 bytes: {0x23, 0x55, 0x67, 0x35}
verification checksum: 0x85bb0ad4 (OK)
alternative: 4fFpEk (OK)
alternative: Ff2kLv (OK)
alternative: GfsZWo (OK)
alternative: Iiljka (OK)
alternative: NpkTAJ (OK)
alternative: RnU49V (OK)
alternative: VWYyPm (OK)
alternative: VjH585 (OK)
alternative: XXFIlc (OK)
alternative: _AAwFH (OK)
alternative: e96P13 (OK)
alternative: if_SPd (OK)
alternative: xWupWf (OK)
PS D:\Tools\Misc\crc32> php -r "var_dump(hex2bin('23556735'));"
Command line code:1:
string(4) "#Ug5"
PS D:\Tools\Misc\crc32> python .\crc32.py reverse 0xf4fde00b
4 bytes: {0x77, 0x32, 0x58, 0x40}
verification checksum: 0xf4fde00b (OK)
alternative: 7gGtPB (OK)
alternative: 9hXDlL (OK)
alternative: Eg3oY_ (OK)
alternative: MqjPTc (OK)
alternative: RO_Coo (OK)
alternative: bmH4Ie (OK)
alternative: cqFYSh (OK)
alternative: dhAgyC (OK)
alternative: zV5EYV (OK)
PS D:\Tools\Misc\crc32> php -r "var_dump(hex2bin('77325840'));"
Command line code:1:
string(4) "w2X@"
PS D:\Tools\Misc\crc32>
字节数量更多的爆破
这里只是讲笔者在CTF题目中碰到的一种情况,需要爆破的内容字节数>4Byte
,但题目就是通过爆破CRC来猜测文件内容。一般碰到这种情况,只有一种可能能使用CRC爆破文件内容,那就是文件内容的字符范围不大
,例如内容是全数字
或者特定的一些字符范围
。因为上述我们的爆破字符范围非常大(所有可打印字符
),所以通过上述这种脚本的爆破方式,4Byte
已经是极限了。但是如果知道文件内容的字符范围或猜测文件内容字符范围不大,即可爆破字节数更多的内容。