CRC背后的故事

admin 2021年1月23日00:00:50评论44 views字数 3059阅读10分11秒阅读模式


本文为翻译文章,笔者翻译水平有限,原文详见Understanding CRC

http://www.secmem.org/blog/2020/08/19/Understanding-CRC/

介绍

去年的时候,在一些CTF赛事中出现了与CRC相关的问题。问题的关键就是找到一个x使得flag{x}CRC值为x。在解题的过程中,我们发现大多数人并不了解CRC的性质。实际在网络应用中,通常使用CRC作为冗余校验码,但是也仅限于使用现有的函数接口计算文件或数据的CRC值,而没有深入了解CRC的性质。

我对CRC的本质也不太理解,于是我重新学习并写下了这篇文章。

背景知识

Finite Field

CRC背后的故事

有限域的更多性质详见[有限域]:https://zh.wikipedia.org/wiki/%E6%9C%89%E9%99%90%E5%9F%9F

CRC背后的故事

CRC

CRC背后的故事

unsigned int crc32b(unsigned char *message) {
   int i, j;
   unsigned int byte, crc, mask;

   i = 0;
   crc = 0xFFFFFFFF;
   while (message[i] != 0) {
      byte = message[i];            // Get next byte.
      crc = crc ^ byte;
      for (j = 7; j >= 0; j--) {    // Do eight times.
         mask = -(crc & 1);
         crc = (crc >> 1) ^ (0xEDB88320 & mask);
      }
      i = i + 1;
   }
   return ~crc;
}

CRC背后的故事

Playing With CRC

CRC背后的故事

poly = 0x104C11DB7

def normalize(x):
    while x.bit_length() > 32:
        x ^= poly << (x.bit_length() - 33)
    return x

def mult(x, y):
    res = 0
    for i in range(32):
        if y & (1 << i) != 0:
            res ^= (x << i)
    return normalize(res)

def bytes_to_gf32(s):
    val = 0
    for c in s:
        rev = int(format(c, '08b')[::-1], 2)
        val = (val << 8) | rev
    return normalize(val)

def crc32(s):
    l = len(s)
    m = bytes_to_gf32(s)
    return normalize((m << 32) ^ (0xFFFFFFFF << (8 * l)) ^ 0xFFFFFFFF)

def crc32b(message):
    crc = 0xFFFFFFFF
    for i in range(len(message)):
        byte = message[i]
        crc = crc ^ byte
        for j in range(8):
            if crc & 1:
                crc = (crc >> 1) ^ 0xEDB88320
            else:
                crc >>= 1
    return crc ^ 0xFFFFFFFF

message = b"test"

crc1 = crc32(message)
crc2 = crc32b(message)

print(format(crc1, '032b'))
print(format(crc2, '032b')[::-1])

CRC背后的故事

> python .test.py
00110000011111101111111000011011
00110000011111101111111000011011

CRC背后的故事

代码:

def pow(x, y):
    if y == 0:
        return 1
    elif y == 1:
        return x
    else:
        res = pow(x, y // 2)
        res = mult(res, res)
        if y & 1:
            res = mult(res, x)
        return res

def inverse(x):
    return pow(x, 2 ** 32 - 2)

const = crc32(b"flag{}")
coef = normalize((1 << 40) ^ 1)
x = mult(const, inverse(coef))

print(format(x, '032b')[::-1])

# 01110011 10011011 01000101 00000111

#     0x73     0x9b     0x45     0x07

print(hex(x))
print(hex(bytes_to_gf32(b"x07x45x9bx73")))
print(hex(crc32(b"flag{x07x45x9bx73}")))
print(hex(crc32b(b"flag{x07x45x9bx73}")))

输出结果为:

python .test.py
01110011100110110100010100000111
0xe0a2d9ce
0xe0a2d9ce
0xe0a2d9ce
0x739b4507

于是预期的xx07x45x9bx73

总结

我们花了一些时间来了解CRC的数学基础,并深入了解了CRC,并找出了某些字符串的CRC值等于字符串自身情况。除了CRC以外,有限域本身也是一个经常在其他地方使用的概念,因此希望在以后出现混淆的时候可以参考这篇文章。

参考资料

  1. https://en.wikipedia.org/wiki/Finite_field
  2. https://en.wikipedia.org/wiki/Cyclic_redundancy_check
  3. https://stackoverflow.com/questions/21001659/crc32-algorithm-implementation-in-c-without-a-look-up-table-and-with-a-public-li
  4. https://zh.wikipedia.org/wiki/%E6%9C%89%E9%99%90%E5%9F%9F

由于公式问题展示最好的方式就是截图,也可以进行下载pdf进行阅读

https://github.com/ChaMd5Team/Venom-WP/blob/main/CRC背后的故事.pdf

查看以下链接或点击文末阅读原文

CRC背后的故事

结束


招新小广告

ChaMd5 Venom 招收大佬入圈

新成立组IOT+工控+样本分析 长期招新

欢迎联系[email protected]



CRC背后的故事

本文始发于微信公众号(ChaMd5安全团队):CRC背后的故事

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年1月23日00:00:50
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   CRC背后的故事http://cn-sec.com/archives/250783.html

发表评论

匿名网友 填写信息