-
-
[原创]KCTF 2024 第四题 神秘信号wp
-
发表于: 2024-8-21 14:53 3531
-
实际耗时:9:30-14:30
注意到是个pyinstaller打包的PE文件,于是直接上手pyinstxtractor解包
解完之后看到main.pyc,反编译之后如下
嘛
然后……事情就变得奇妙了起来
先是在PYZ-00.pyz中没有找到CrackMe这个包,以为是解包中出现了问题
返回头去调试PE文件,更新pyinstxtractor版本
甚至重新配置了pyinstaller的环境,自己打了个包bindiff,以为是在这个工具上做出了什么奇妙的操作
不出意外的,没找到任何破局点
于是,想着,反正是个python打包的进程,我直接调用你运行中的python.dll,运行我的代码算了,然后试图使用frida
所幸,午饭时间将我的这个念想打消了(其实是发现我不会用win环境下的frida)
研究了一阵子pyinstaller打包的PE中的python的执行过程之后,突然发现了盲点
PyEval_EvalCode和PyMarshal_ReadObjectFromString
在这种打包方法的Python的执行过程中,先由PyMarshal_ReadObjectFromString读入PE文件中的pyc文件,并将其转化为py_code_object,然后交由PyEval_EvalCode执行
暂且不关注具体的执行过程的话,在PE文件完全可控的情况下,这个pyc文件内容也是完全可控的,我完全可以控制这个文件的内容是什么,于是,在下断点确定读取的pyc文件内容后,我开始了我的操作
构造一个size与原本的main.pyc完全相同的hack.pyc
大概实现以下功能:
就可以看到如下返回值
于是,可以确定这个加密函数是通过base64.pyc中的某个地方完成的构造,将其反编译可以看到如下内容(通过......隐藏了部分过于庞大的内容)
然后,就可以通过import base64的方式,直接使用这个pyc文件,来进行下一步的工作
首先,我尝试爆破字符转换行为
但是发现返回值完全不符合预期,但又有种莫名的base64的感觉,还是个换表的base64
而尝试输入KCTF后产生的返回值也与注入的pyc文件的输出不同
而同时,想exec(input())的测试失败之后,我将目光移到了input函数身上
这下直接学精了,在注入的pyc中做了点手脚,我每次就直接看看每一个函数调用后的结果
while true前的三次print,分别打印了大致正确的key、爆破CrackMe.main所使用的base64基准字符、占位符(保证pyc文件大小相同)
这下终于让我抓住了马脚
每次不同的输入后,input得到的内容也是不同的,但是最后的加密还是稳妥的base64,那就好办了,我直接写个映射表爆破就好了
最终得到flag:
KCTF:Hello World!KCTF
并实现keygen如下:
import
CrackMe
while
True
:
print
(
'(账号密码由字母大小写、数字、!、空格组成)'
)
print
(
'请输入账号:'
)
h
=
input
()
z
=
CrackMe.main(h)
if
len
(z) <
20
:
key
=
'dZpKdrsiB6cndrGY'
+
z
else
:
key
=
z[
0
:
4
]
+
'dZpK'
+
z[
4
:
8
]
+
'drsi'
+
z[
8
:
12
]
+
'B6cn'
+
z[
12
:
16
]
+
'drGY'
+
z[
16
:]
print
(
'请输入验证码:'
)
h
=
input
()
m
=
CrackMe.main(h)
if
key
=
=
m:
print
(
'Success'
)
break
print
(
'Fail'
)
import
CrackMe
while
True
:
print
(
'(账号密码由字母大小写、数字、!、空格组成)'
)
print
(
'请输入账号:'
)
h
=
input
()
z
=
CrackMe.main(h)
if
len
(z) <
20
:
key
=
'dZpKdrsiB6cndrGY'
+
z
else
:
key
=
z[
0
:
4
]
+
'dZpK'
+
z[
4
:
8
]
+
'drsi'
+
z[
8
:
12
]
+
'B6cn'
+
z[
12
:
16
]
+
'drGY'
+
z[
16
:]
print
(
'请输入验证码:'
)
h
=
input
()
m
=
CrackMe.main(h)
if
key
=
=
m:
print
(
'Success'
)
break
print
(
'Fail'
)
import
CrackMe
print
(CrackMe.__dict__)
import
CrackMe
print
(CrackMe.__dict__)
'__spec__'
: ModuleSpec(name
=
'base64'
, loader
=
<pyimod02_importers.PyiFrozenImporter
object
at
0x000002388FAA0220
>, origin
=
'...\\main\\_internal\\base64.pyc'
),
'__cached__'
:
'...\\main\\_internal\\base64.pyc'
,
'__builtins__'
: {
'__name__'
:
'builtins'
,
'__doc__'
:
"Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices."
,
'__package__'
: '',
'__loader__'
: <
class
'_frozen_importlib.BuiltinImporter'
>,
'__spec__'
: ModuleSpec(name
=
'base64'
, loader
=
<pyimod02_importers.PyiFrozenImporter
object
at
0x000002388FAA0220
>, origin
=
'...\\main\\_internal\\base64.pyc'
),
'__cached__'
:
'...\\main\\_internal\\base64.pyc'
,
'__builtins__'
: {
'__name__'
:
'builtins'
,
'__doc__'
:
"Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices."
,
'__package__'
: '',
'__loader__'
: <
class
'_frozen_importlib.BuiltinImporter'
>,
co_posonlyargcount
=
main.__code__.replace(
(
1
, (),
b
'......'
,
None
, '
', 0, '
base64(....)
', b'
', 85, 1, '
little
', 3, compile('
', '
', '
exec
').replace(
1
, (), b
'......'
, (
'08b'
,
None
), '
', co_kwonlyargcount=19, co_lnotab=115, co_name=(), co_names=0, co_nlocals=b'
', co_posonlyargcount='
', co_stacksize=('
format
',), co_varnames=('
to_bytes
', '
range
', '
len
', '
join
', '
int
'),
12
=
12
,
0
=
0
,
7
=
7
,
data
=
(
'data'
,
'encoded_str'
,
'padding'
,
'base64_chars'
,
'ww'
,
'i'
,
'chunk'
,
'binary_str'
,
'j'
,
'six_bits'
,
'a'
,
'b'
, b
'......'
, '
', '
base64(....)')
)))
co_posonlyargcount
=
main.__code__.replace(
(
1
, (),
b
'......'
,
None
, '
', 0, '
base64(....)
', b'
', 85, 1, '
little
', 3, compile('
', '
', '
exec
').replace(
1
, (), b
'......'
, (
'08b'
,
None
), '
', co_kwonlyargcount=19, co_lnotab=115, co_name=(), co_names=0, co_nlocals=b'
', co_posonlyargcount='
', co_stacksize=('
format
',), co_varnames=('
to_bytes
', '
range
', '
len
', '
join
', '
int
'),
12
=
12
,
0
=
0
,
7
=
7
,
data
=
(
'data'
,
'encoded_str'
,
'padding'
,
'base64_chars'
,
'ww'
,
'i'
,
'chunk'
,
'binary_str'
,
'j'
,
'six_bits'
,
'a'
,
'b'
, b
'......'
, '
', '
base64(....)')
)))
import
base64
print
(base64.main(b
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789! "
))
import
base64
print
(base64.main(b
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789! "
))
input
(
"KCTF"
):
QQMlP7!!
base64.main(b
"KCTF"
)
nBQ6P7!!
input
(
"KCTF"
):
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!