本题通过特定的脚本将flag写进了一张图片,我们的目标则是比对两张图片得到flag,
先来看看隐写的代码
1
|
random.seed(
793211
)
|
虽然用了随机数,但是用了种子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
cat
=
Image.
open
(
'1.png'
)
cat1
=
Image.new(
'L'
, cat.size)
#根据1.png的尺寸 #三个图层
cat2
=
Image.new(
'L'
, cat.size)
cat3
=
Image.new(
'L'
, cat.size)
x, y
=
cat.size
#新建图片的长和宽
bits
=
x
*
y
#总共的像素
r1, r2
=
pbl(bits), pbl(bits)
r3
=
FLAG
+
n2b(random.getrandbits((bits
-
len
(FLAG))
*
8
))
r3
=
list
(r3)
random.shuffle(r3)
#打乱列表的顺序
for
i
in
range
(x):
#对每一个像素进行异或
for
j
in
range
(y):
pix
=
cat.getpixel((i, j))
#像素的RGB值
cat1.putpixel((i, j), pix[
0
] ^ r1[i
*
y
+
j])
cat2.putpixel((i, j), pix[
1
] ^ r2[i
*
y
+
j])
cat3.putpixel((i, j), pix[
2
] ^ r3[i
*
y
+
j])
img
=
Image.new(
'RGB'
, cat.size)
img.putdata([(p1,
0
, p3)
for
p1, p3
in
zip
(cat1.getdata(), cat3.getdata())])
img.save(
'xx.png'
)
|
将图片的R,G,B分别提取的到三张图片上,然后通过对每一个像素的RGB异或上r1,r2,r3,其中r1,r2可控,r3由flag构成,所以未知,本体的最终目的就是解出r3,
由于异或可逆,我们很容易能得到乱序后的r3,所以如何回到乱序前才是本题的重点
这里尝试一个例子
1
2
3
4
5
6
7
8
9
|
import
random
random.seed(
1
)
a
=
[i
for
i
in
range
(
10
)]
random.shuffle(a)
print
(a)
#[6, 8, 9, 7, 5, 3, 0, 4, 1, 2]
random.shuffle(a)
print
(a)
#[5, 1, 9, 0, 3, 2, 6, 4, 8, 7]
|
在seed确定的情况下,random.shuffle()的打乱顺序遵循一定规律,在代码中作为第几个random被调用直接决定了它会被怎么打乱,在本题中random.shuffle()就是第3个random,所以我们可以定义一个顺序的列表也在第三个random时被打乱
1
2
|
gg
=
[i
for
i
in
range
(
27918
)]
random.shuffle(gg)
|
最后通过这个列表来对乱序的r3列表排序
1
|
result
=
[i
for
_, i
in
sorted
(
zip
(gg,r3))]
|
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
|
import
random
from
PIL
import
Image
from
Crypto.Util.number
import
long_to_bytes as n2b
random.seed(
793211
)
def
pbl(bits):
#加密
num
=
random.getrandbits(bits)
bins
=
[]
while
num:
bins.append(num &
1
)
num >>
=
1
while
len
(bins) !
=
bits:
bins.append(
0
)
return
bins
cat
=
Image.
open
(
'1.png'
)
cat1
=
Image.new(
'L'
, cat.size)
#根据1.png的尺寸 #三个图层
cat2
=
Image.new(
'L'
, cat.size)
cat3
=
Image.new(
'L'
, cat.size)
xcat
=
Image.
open
(
'xx.png'
)
xcat1
=
Image.new(
'L'
, cat.size)
xcat2
=
Image.new(
'L'
, cat.size)
xcat3
=
Image.new(
'L'
, cat.size)
x, y
=
cat.size
bits
=
x
*
y
r1, r2
=
pbl(bits), pbl(bits)
r3
=
[
0
]
*
((x
-
1
)
*
y
+
y )
for
i
in
range
(x):
#对每一个像素进行异或
for
j
in
range
(y):
pix
=
cat.getpixel((i, j))
xpix
=
xcat.getpixel((i,j))
r3[i
*
y
+
j]
=
pix[
2
] ^ xpix[
2
]
a
=
n2b(random.getrandbits((bits
-
28
)
*
8
))
gg
=
[i
for
i
in
range
(
27918
)]
random.shuffle(gg)
result
=
[i
for
_, i
in
sorted
(
zip
(gg,r3))]
fin
=
""
i
=
0
while
result[i] !
=
125
:
fin
=
fin
+
chr
(result[i])
i
=
i
+
1
print
(fin
+
'}'
)
|
题目给了一个.pyc文件,量有点大,有点吃内存,建议在跑之前清一下内存,不然可能会报MemoryError
1
|
uncompyle6
/
whatisthis.cpython
-
38.pyc
>
/
1.py
|
跑出来后python代码变量名会非常的长,难以看清它到底想干啥,所以这里可以考虑修一下代码,替换一下变量,修好后的代码部分大概就长这样
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
def
rR(key):
wW
=
list
(
range
(
256
))
Ud
=
0
for
kk
in
range
(
256
):
Ud
=
(Ud
+
wW[kk]
+
ord
(key[kk
%
len
(key)]))
%
256
wW[kk], wW[Ud]
=
wW[Ud], wW[kk]
return
wW
def
QL(p):
Qa
=
rR(
'h0lyduck'
)
kR
=
[]
kk
=
Ud
=
0
for
Fb
in
p:
kk
=
(kk
+
1
)
%
256
Ud
=
(Ud
+
Qa[kk])
%
256
Qa[kk], Qa[Ud]
=
Qa[Ud], Qa[kk]
VI
=
(Qa[kk]
+
Qa[Ud])
%
256
ff
=
Qa[VI]
kR.append(Fb ^ ff)
return
kR
exec
(marshal.loads(bytearray(QL(ys))))
|
直接看一眼运行结果:
1
2
3
4
5
|
Traceback (most recent call last):
Welcome to NotDefined World
There
is
a flag
in
here
File
'Can you'
, line
1
,
in
<find it?>
NameError: name
'Not Defined'
is
not
defined
|
老谜语人了,也不懂啥意思,那就再看看他在序列化之前是啥吧
1
|
print
(bytearray(QL(ys)))
|
输出很长,这里不做粘贴,但是可以很明显的看出这是在套娃,有很多的\n(总不能自己一个个去回车吧,呜呜呜),直接输出到新文件
1
2
3
4
5
|
f
=
open
(
"next.py"
,
"w"
)
bytearray((QL(ys)))
str
=
bytearray((QL(ys))).decode(
'utf-8'
,
'ignore'
)
f.write(
str
)
f.close()
|
得到相似的代码,把乱码部分清一下,继续输出到新文件就能看到flag辣
当然这道题还有一个比较高级的解法,可以用gdb直接调试出来
但俺就是个不懂二进制的带菜鸡,所以这里不做细述,感兴趣的大佬们可以自行尝试
更多【【HWS】两道好玩的misc】相关视频教程:www.yxfzedu.com