赞
踩
本题为:CTFSHOW的36D杯 misc ez-qrcode
和攻防世界的qr-easy解法基本一模一样。
用ps稍微处理一下:
此二维码的大小为 29x29,版本V的大小为N × N,N = 17 + 4V,所以这是版本 3。
图中两处红色方框,表示二维码的格式信息,前面7位,后面8位。
后面8位的格式信息为:11100111
,前7位我们不清楚,所以我们的信息字符串为:???????11100111
所有格式信息字符串的列表
ECC 级别 | 掩码图案 | 类型信息比特 |
---|---|---|
L | 0 | 111011111000100 |
L | 1 | 111001011110011 |
L | 2 | 111110110101010 |
L | 3 | 111100010011101 |
L | 4 | 110011000101111 |
L | 5 | 110001100011000 |
L | 6 | 110110001000001 |
L | 7 | 110100101110110 |
M | 0 | 101010000010010 |
M | 1 | 101000100100101 |
M | 2 | 101111001111100 |
M | 3 | 101101101001011 |
M | 4 | 100010111111001 |
M | 5 | 100000011001110 |
M | 6 | 100111110010111 |
M | 7 | 100101010100000 |
Q | 0 | 011010101011111 |
Q | 1 | 011000001101000 |
Q | 2 | 011111100110001 |
Q | 3 | 011101000000110 |
Q | 4 | 010010010110100 |
Q | 5 | 010000110000011 |
Q | 6 | 010111011011010 |
Q | 7 | 010101111101101 |
H | 0 | 001011010001001 |
H | 1 | 001001110111110 |
H | 2 | 001110011100111 |
H | 3 | 001100111010000 |
H | 4 | 000011101100010 |
H | 5 | 000001001010101 |
H | 6 | 000110100001100 |
H | 7 | 000100000111011 |
根据二维的信息字符串???????11100111
再结合所有格式信息字符串的列表或者上图表格。
很容易得到这个二维码的ECC级别为H和掩码模式为2。
掩码号 | 如果下面的公式对于给定的行/列坐标为真,则切换该坐标处的位 |
---|---|
0 | (行 + 列) mod 2 == 0 |
1 | (行) mod 2 == 0 |
2 | (列) mod 3 == 0 |
3 | (行 + 列) mod 3 == 0 |
4 | (floor(行 / 2) + floor(列 / 3)) mod 2 == 0 |
5 | ((行 * 列) mod 2) + ((行 * 列) mod 3) == 0 |
6 | ( ((行 * 列) mod 2) + ((行 * 列) mod 3) ) mod 2 == 0 |
7 | ( ((行 + 列) mod 2) + ((行 * 列) mod 3) ) mod 2 == 0 |
根据QR Mask Patterns Explained,也就是上面的表格,2 号掩码有公式(列) mod 3 == 0
。注意列号是从0开始的,所以我们要切换坐标为0,3,6,9, … ,27的列的位。
二维码也有固定的图案,所以我们只需要切换数据部分的位即可。查看数据区和位顺序。
(通过wikipedia.org)
所以,原始的 D1-D26 是:
D1 = 00010100 D14 = 10100010 D2 = 00110011 D15 = 00010001 D3 = 00110011 D16 = 01110110 D4 = 11000110 D17 = 01010111 D5 = 00010110 D18 = 01000100 D6 = 11011101 D19 = 00101100 D7 = 00011111 D20 = 01011110 D8 = 00011100 D21 = 00000010 D9 = 00100001 D22 = 01100110 D10 = 00110110 D23 = 01010111 D11 = 00010110 D24 = 11010000 D12 = 11100110 D25 = 11101101 D13 = 10110011 D26 = 01000100
去掉掩码后,(列) mod 3 == 0
D1 = 01000001 D14 = 11110111 D2 = 01100110 D15 = 01000100 D3 = 01100110 D16 = 01110110 D4 = 11000110 D17 = 01010111 D5 = 00010110 D18 = 01000100 D6 = 01110111 D19 = 10000110 D7 = 10110101 D20 = 11110111 D8 = 01000110 D21 = 01010111 D9 = 01110100 D22 = 00110110 D10 = 00110110 D23 = 01010111 D11 = 00010110 D24 = 11010000 D12 = 11100110 D25 = 11101100 D13 = 11100110 D26 = 00010001
解码有模式指示符:
0001
:数字模式(每 3 位 10 位)0010
:字母数字模式(每 2 个字符 11 位)0100
:字节模式(每个字符 8 位)1000
:汉字模式(每个字符 13 位)0111
: ECI 模式字符计数指示符跟在模式指示符之后。
查看每种模式的编码过程:
让我们从上面的数据 D1-D26 开始:
data = '01000001' \ '01100110' \ '01100110' \ '11000110' \ '00010110' \ '01110111' \ '10110101' \ '01000110' \ '01110100' \ '00110110' \ '00010110' \ '11100110' \ '11100110' \ '11110111' \ '01000100' \ '01110110' \ '01010111' \ '01000100' \ '10000110' \ '11110111' \ '01010111' \ '00110110' \ '01010111' \ '11010000' \ '11101100' \ '00010001' alphanumeric = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:'.chars def read(str, size) str.slice!(0, size) end def kanji(num) if num >= 0x1740 (0xC140 + num / 0xC0 * 0x100 + num % 0xC0) .chr(Encoding::Shift_JIS).encode(Encoding::UTF_8) else (0x8140 + num / 0xC0 * 0x100 + num % 0xC0) .chr(Encoding::Shift_JIS).encode(Encoding::UTF_8) end end loop do case mode = read(data, 4) when '0010' # Alphanumeric count = read(data, 9).to_i(2) (count / 2).times do chunk = read(data, 11).to_i(2) print alphanumeric[chunk / 45] + alphanumeric[chunk % 45] end print alphanumeric[read(data, 11).to_i(2)] if count.odd? when '0100' # Byte count = read(data, 8).to_i(2) count.times do print read(data, 8).to_i(2).chr end when '1000' # Kanji count = read(data, 8).to_i(2) count.times do print kanji(read(data, 13).to_i(2)) end when '0000' # Terminate break else fail "Unhandled mode #{mode}" end end
Ruby在线网站运行即可得到
flag{TgCannotGetHouse}
Python代码同样也没有问题:
# D1-D26:
data = ['01000001', '01100110', '01100110', '11000110', '00010110', '01110111', '10110101', '01000110', '01110100', '00110110', '00010110', '11100110', '11100110', '11110111', '01000100', '01110110', '01010111', '01000100', '10000110', '11110111', '01010111', '00110110', '01010111', '11010000', '11101100', '00010001']
data = "".join(data)
data = data[4:]
for i in range(0, len(data), 8):
print(chr(int(data[i:i+8], 2)), end="")
运行效果如下:
flag{TgCannotGetHouse}
拜拜!
https://yous.be/2014/12/07/seccon-ctf-2014-qr-easy-write-up/
https://www.zhihu.com/question/65253283
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。