Introduction to CryptoHack

ASCII

ASCII is a 7-bit encoding standard which allows the representation of text using the integers 0-127.
ASCII 是一种 7 位编码标准,允许使用 0 至 127 的整数来表示文本。

Using the below integer array, convert the numbers to their corresponding ASCII characters to obtain a flag.
使用下方的整数数组,将数字转换为对应的 ASCII 字符以获取一个标志。

1
[99, 114, 121, 112, 116, 111, 123, 65, 83, 67, 73, 73, 95, 112, 114, 49, 110, 116, 52, 98, 108, 51, 125]  

 In Python, the chr() function can be used to convert an ASCII ordinal number to a character (the ord() function does the opposite).
在 Python 中,可以使用 chr() 函数将 ASCII 序数转换为字符( ord() 函数则执行相反操作)。

sollution

1
2
3
src = [99, 114, 121, 112, 116, 111, 123, 65, 83, 67, 73, 73, 95, 112, 114, 49, 110, 116, 52, 98, 108, 51, 125]  
for i in src:
print(chr(i), end='')

image.png

Hex

When we encrypt something the resulting ciphertext commonly has bytes which are not printable ASCII characters. If we want to share our encrypted data, it’s common to encode it into something more user-friendly and portable across different systems.
当我们对某些内容进行加密时,生成的密文通常包含不可打印的 ASCII 字符。如果我们需要共享加密数据,通常会将其编码为更用户友好且能在不同系统间便携传输的形式。

Hexadecimal can be used in such a way to represent ASCII strings. First each letter is converted to an ordinal number according to the ASCII table (as in the previous challenge). Then the decimal numbers are converted to base-16 numbers, otherwise known as hexadecimal. The numbers can be combined together, into one long hex string.
十六进制可以这样用来表示 ASCII 字符串。首先根据 ASCII 表将每个字母转换为对应的序号数字(如先前挑战所示)。然后将这些十进制数字转换为基数为 16 的数字,即十六进制。这些数字可以组合在一起,形成一个长十六进制字符串。

Included below is a flag encoded as a hex string. Decode this back into bytes to get the flag.
下方包含一个以十六进制字符串编码的标志。将其解码回字节即可获得该标志。

1
63727970746f7b596f755f77696c6c5f62655f776f726b696e675f776974685f6865785f737472696e67735f615f6c6f747d

 In Python, the bytes.fromhex() function can be used to convert hex to bytes. The .hex() instance method can be called on byte strings to get the hex representation.
 在 Python 中, bytes.fromhex() 方法可用于将十六进制转换为字节。可以在字节字符串上调用 .hex() 实例方法来获取其十六进制表示形式。

Resources:
  - ASCII table
  - Wikipedia: Hexadecimal

sollution

1
2
3
4
5
6
7
src = '63727970746f7b596f755f77696c6c5f62655f776f726b696e675f776974685f6865785f737472696e67735f615f6c6f747d'  
# First step: hex_strings to bytes
hex_byte = (bytes.fromhex(src))
# Second step: bytes to ascii
res = print(hex_byte.decode('utf-8'))
# or:
# res = print(hex_byte.decode('ascii'))

image.png 因为计算机处理原始数据时(如加密算法、网络传输、文件存储等)都需要使用字节(bytes)这种二进制格式。所以必须先将字符串转换为字节序列。

Base64

Another common encoding scheme is Base64, which allows us to represent binary data as an ASCII string using an alphabet of 64 characters. One character of a Base64 string encodes 6 binary digits (bits), and so 4 characters of Base64 encode three 8-bit bytes.
另一种常见的编码方案是 Base64,它允许我们使用 64 个字符的字母表将二进制数据表示为 ASCII 字符串。Base64 字符串的一个字符编码 6 个二进制数字(位),因此 4 个 Base64 字符可以编码三个 8 位字节。

Base64 is most commonly used online, so binary data such as images can be easily included into HTML or CSS files.
Base64 最常用于在线场景,因此像图像这样的二进制数据可以轻松地包含在 HTML 或 CSS 文件中。

Take the below hex string, decode it into bytes and then encode it into Base64.
将下面的十六进制字符串解码为字节,然后将其编码为 Base64。

1
72bca9b68fc16ac7beeb8f849dca1d8a783e8acf9679bf9269f7bf

 In Python, after importing the base64 module with import base64, you can use the base64.b64encode() function. Remember to decode the hex first as the challenge description states.
 在 Python 中,使用 import base64 导入 base64 模块后,你可以使用 base64.b64encode() 函数。记得按照挑战描述先对十六进制进行解码。

sollution

1
2
3
4
5
6
7
8
import base64  

src = '72bca9b68fc16ac7beeb8f849dca1d8a783e8acf9679bf9269f7bf'
# First step: hex_strings to bytes
hex_byte = (bytes.fromhex(src))
# Second step: bytes to base64
res = base64.b64encode(hex_byte)
print(res)

image.png

Bytes and Big Integers

Cryptosystems like RSA works on numbers, but messages are made up of characters. How should we convert our messages into numbers so that mathematical operations can be applied?
像 RSA 这样的加密系统基于数字运算,但消息由字符组成。我们应如何将消息转换为数字,以便应用数学运算?

The most common way is to take the ordinal bytes of the message, convert them into hexadecimal, and concatenate. This can be interpreted as a base-16/hexadecimal number, and also represented in base-10/decimal.
最常见的方法是提取消息的字节序,将其转换为十六进制并拼接。这可以视为一个基数为 16 的十六进制数,也可以用基数为 10 的十进制表示。

To illustrate:  例如:

1
2
3
4
5
message: HELLO  
ascii bytes: [72, 69, 76, 76, 79]
hex bytes: [0x48, 0x45, 0x4c, 0x4c, 0x4f]
base-16: 0x48454c4c4f
base-10: 310400273487

 Python’s PyCryptodome library implements this with the methods bytes_to_long() and long_to_bytes(). You will first have to install PyCryptodome and import it with from Crypto.Util.number import *. For more details check the FAQ.
 Python 的 PyCryptodome 库通过方法 bytes_to_long() 和 long_to_bytes() 实现此功能。首先需安装 PyCryptodome 并使用 from Crypto.Util.number import * 导入。更多详情请查阅常见问题解答。

Convert the following integer back into a message:
将以下整数转换回消息:

1
11515195063862318899931685488813747395775516287289682636499965282714637259206269

sollution

1
pip install PyCryptodome
1
2
3
4
5
6
7
from Crypto.Util.number import *  
src = 11515195063862318899931685488813747395775516287289682636499965282714637259206269
# First step: long int to bytes
byte_data = long_to_bytes(src)
# Second step: bytes to strings
res = byte_data.decode('ascii')
print(res)

image.png

XOR Starter

XOR is a bitwise operator which returns 0 if the bits are the same, and 1 otherwise. In textbooks the XOR operator is denoted by , but in most challenges and programming languages you will see the caret ^ used instead.
异或是一种按位运算符,当两个位相同时返回 0,否则返回 1。在教科书中,异或运算符用表示,但在大多数挑战和编程语言中,你会看到用脱字符 ^ 代替。

A B Output
0 0 0
0 1 1
1 0 1
1 1 0

For longer binary numbers we XOR bit by bit: 0110 ^ 1010 = 1100. We can XOR integers by first converting the integer from decimal to binary. We can XOR strings by first converting each character to the integer representing the Unicode character.
对于较长的二进制数,我们逐位进行异或运算: 0110 ^ 1010 = 1100 。可以通过先将十进制整数转换为二进制来对整数进行异或。对于字符串,可以先将每个字符转换为表示 Unicode 字符的整数再进行异或。

Given the string label, XOR each character with the integer 13. Convert these integers back to a string and submit the flag as crypto{new_string}.
给定字符串 label ,将每个字符与整数 13 进行异或运算。将这些整数转换回字符串后,以 crypto{new_string} 格式提交标志。

sollution

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# way1-pure  
# src = 'label'
# res = [] # empty_list
# for char in src:
# # str -> ascii -> xor 13 -> new_str
# xor_res = chr(ord(char) ^ 13)
# res.append(xor_res)
# print(f"crypto{{{''.join(res)}}}")

# way2-xor()
from pwn import xor
# pip install pwntools
src = 'label'
# str to byte,then xor
res_bytes = xor(src.encode(), 13)
# new_bytes to new_str
res_str = res_bytes.decode()
print(f"crypto{{res_str}}")

image.png

XOR Properties

In the last challenge, you saw how XOR worked at the level of bits. In this one, we’re going to cover the properties of the XOR operation and then use them to undo a chain of operations that have encrypted a flag. Gaining an intuition for how this works will help greatly when you come to attacking real cryptosystems later, especially in the block ciphers category.
在上一个挑战中,你已经了解了异或(XOR)在比特层面的运作方式。这一次,我们将探讨异或运算的特性,并利用它们来解构一系列加密了旗帜的操作链。理解其工作原理将极大地帮助你在后续攻击实际加密系统时,尤其是在区块密码类别中。

There are four main properties we should consider when we solve challenges using the XOR operator
当我们使用异或运算符解决挑战时,需要考虑四个主要特性 Commutative: A ⊕ B = B ⊕ A 交换律: Associative: A ⊕ (B ⊕ C) = (A ⊕ B) ⊕ C 结合律: Identity: A ⊕ 0 = A 恒等性: Self-Inverse: A ⊕ A = 0 自反性:

Let’s break this down. Commutative means that the order of the XOR operations is not important. Associative means that a chain of operations can be carried out without order (we do not need to worry about brackets). The identity is 0, so XOR with 0 “does nothing”, and lastly something XOR’d with itself returns zero.
让我们逐一解析。交换律意味着异或操作的顺序不重要;结合律表示操作链可以无序执行(无需担心括号);单位元是 0,因此与 0 异或“不产生任何效果”;最后,任何数与自身异或将返回零。

Let’s put this into practice! Below is a series of outputs where three random keys have been XOR’d together and with the flag. Use the above properties to undo the encryption in the final line to obtain the flag.
让我们将其付诸实践!以下是三个随机密钥经过异或运算并与标志位结合后的一系列输出结果。利用上述特性,在最后一行撤销加密操作以获取标志位。

1
2
3
4
KEY1 = a6c8b6733c9b22de7bc0253266a3867df55acde8635e19c73313  
KEY2 ^ KEY1 = 37dcb292030faa90d07eec17e3b1c6d8daf94c35d4c9191a5e1e
KEY2 ^ KEY3 = c1545756687e7573db23aa1c3452a098b71a7fbf0fddddde5fc1
FLAG ^ KEY1 ^ KEY3 ^ KEY2 = 04ee9855208a2cd59091d04767ae47963170d1660df7f56f5faf

 Before you XOR these objects, be sure to decode from hex to bytes.
 在对这些对象进行异或操作前,请确保先将十六进制解码为字节形式。

sollution

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
"""  
Way1:
flag ^ key1 ^ key3 ^ key2 = flag ^ key1 ^ key2 ^ key3 = flag ^ key1 ^ (key2 ^ 0) ^ (key3 ^ 0)
= flag ^ key1 ^ (key2 ^ (key1 ^ key1)) ^ (key3 ^ (key2 ^ key2))
= flag ^ key1 ^ ((key2 ^ key1) ^ key1) ^ ((key2 ^ key3) ^ key2)
= flag ^ key1 ^ (key2 ^ key2) ^ (key1 ^ key1) ^ key23
= flag ^ key1 ^ key23 = <value>

So: flag = <value> ^ key1 ^ key23
"""

"""
Way2:
flag ^ key1 ^ key3 ^ key2 = flag ^ key1 ^ key2 ^ key3 = <value>
Cuz commutative means that the order of the XOR operations is not important,so:

flag = key1 ^ key2 ^ key3 ^ <value> = key1 ^ key23 ^ flag_key132
"""
from pwn import xor
key1 = bytes.fromhex('a6c8b6733c9b22de7bc0253266a3867df55acde8635e19c73313')
key21 = bytes.fromhex('37dcb292030faa90d07eec17e3b1c6d8daf94c35d4c9191a5e1e')
key23 = bytes.fromhex('c1545756687e7573db23aa1c3452a098b71a7fbf0fddddde5fc1')
flag_key132 = bytes.fromhex('04ee9855208a2cd59091d04767ae47963170d1660df7f56f5faf')
# flag = xor(flag_key132, key1, key23) # Way1
flag = xor(key1, key23, flag_key132) # Way2

print(flag)

image.png image.png 第一种计算方式比较复杂,并且看起来没有任何必要,因为这题只需要用到xor其中的部分特性就能快速解决,但第一种方式的思路几乎把xor的所有特性都包含到了,有助于我们加强对xor特性的运用,具有参考意义。

另外,除了上述用脚本的方式,还可以采用Cyberchef工具来完成,可参考Cesar师傅的文章

Favourite byte

For the next few challenges, you’ll use what you’ve just learned to solve some more XOR puzzles.
接下来的几个挑战中,你将运用刚学到的知识解决更多异或谜题。

I’ve hidden some data using XOR with a single byte, but that byte is a secret. Don’t forget to decode from hex first.
我用单个字节作为密钥对数据进行了异或加密,但该字节是保密的。别忘了先进行十六进制解码。

1
73626960647f6b206821204f21254f7d694f7624662065622127234f726927756d

sollution