Hacking Book | Free Online Hacking Learning


on the framework and design of distributed infiltration framework

Posted by forbes at 2020-03-25

This article discusses some topics about the architecture and design of distributed penetration framework, and shares some of my humble opinions, hoping to inspire you. This paper is divided into three topics. It is suggested to read them in order. In the three topics, the author describes two pain points (architecture design and communication) in detail.

Topic - what is penetration testing framework


Now many large and small manufacturers or many private teams are doing or have mature scanners, open source or internal use. All to solve some practical problems:

In short, the penetration testing framework can make some of your penetration testing processes simpler, assist business completion, and simplify some business logic. Of course, for the framework, its basic function is to ensure the normal operation of plug-ins. When he has a lot of plug-ins, the value will really show.


Penetration testing framework is not a particularly advanced thing. Compared with the micro service architecture in e-commerce system, the infrastructure may not be as complex as it is, or even in comparison, it can be said to be insignificant. However, penetration testing framework is not suitable for comparison with microservice architecture because it is more flexible. Some advanced development concepts (distributed / microservice) are not particularly suitable for it. A penetration testing framework / scanner can be very concise, even as a flexible script engine, but at the same time, there are many large-scale penetration frameworks / scanning frameworks (Nessus / OpenVAS). The complexity of these frameworks is much higher than that of ordinary script engines. The essence of penetration testing framework / scanner is not very good. According to its characteristics, what kind of program is it

Problems solved

Unsolvable problems

Rules of universality

For such a framework, simplify and simplify the model again, and it will eventually become a framework for RPC (remote procedure call) to call multiple programs (functional units). Of course, this is not a specific RPC Protocol, but a general concept of RPC; or a framework for directly calling multiple programs (functional units).

The biggest difference between RPC and normal RPC is that there are various types of tasks, tasks may be updated, and the execution environment is very complex. And the framework itself needs to support highly flexible functional units (plug-ins). Or in other words, the called program (function module) is very loose for the framework, and even failure / obsolescence will not affect the operation of any framework.

In this way, it can't be simply called an RPC. Based on the above situation, when he designs, he excludes later module registration and other mechanisms. The framework itself can't actively know how many kinds and how many programs he will have, and what the basic interfaces of these programs are at the same time. So RPC is not particularly appropriate.

So, what is the best way to describe a framework? Of course, everyone has their own opinions. I prefer to use loose master slave architecture as the architecture model of this kind of framework: natural slave represents functional unit or called program, master represents controller / caller or node of overall transaction logic processing, and loose represents slave and master The relationship and interdependence between them are not particularly strong. Other mechanisms can be used to maintain the relationship between them, such as registration or subscription mechanism.

Additional explanation

Of course, the framework is different from the penetration testing tools. The tools can directly use the layered architecture, or even do not pay much attention to the project model and structure related parts, directly implement some specific functions for the process, or use the microkernel architecture partially or as a whole to provide some flexibility.

Model classification of current mainstream scanners / frameworks

In the next topic, we will discuss the architecture design of distributed penetration framework / scanner.

Topic - requirement analysis and architecture design


In short, the task of this framework is to receive tasks, distribute tasks, execute tasks, and process results. Therefore, the distributed penetration testing framework is much simpler than the micro service architecture of e-commerce platform, because the transaction of the penetration testing framework is relatively simpler, or even the concept of transaction is diluted. But it is also a task intensive application. To some extent, there is a certain demand for high concurrency and high availability.

We can sort out the whole process from the beginning. Master gets a task. The task is divided into several atomic tasks, which are sent to different workers according to the type. After the task is executed, the result is sent to master for transaction summary.

Although the whole process is not very complex, we still need to analyze what we need to make a reasonable architecture design according to the requirements


After thinking about many methods of requirement description, we have no way to describe exactly what functions our system needs from one point of view, which is like we have OOP, but the emergence of AOP makes a very good supplement to OOP, and of course, SOP (state oriented programming) also makes a good supplement to OOP. Ah, the topic is far away. After some thinking, we discuss our needs from the perspectives of space and time (process / logic).

Space demand

From the perspective of functional entities, we need something like this:



Time / process / logic requirements

Of course, this refers to a series of mechanisms or possible processes or logics needed to solve problems in this framework

There is a scheduling system that allows modules to work together.


According to our requirements, the simplest is that our overall architecture should be a loose master slave architecture. Master does not rely on any slave, but slave can work only when it depends on master.

In the following description, we first agree on several concepts to appear in our framework:

OK, let's use the following diagram to illustrate the structure

At the same time, the overall framework is not enough for us to describe the whole framework, and it seems very perfunctory, so it is necessary for us to elaborate in detail:

Master split services and subfunctions

Master is a huge collection of functions, but it's not a "cow". Master is composed of many services, so it's very necessary for us to separate master into specific services to elaborate their uses.

Slave split services and subfunctions

Other equipment

Process design

Design corresponding to requirements, we still need to design the important process, which is different from the above service / function split, but it can also describe the process of framework work well. So it is very necessary for me to make some explanations from this perspective.

Transaction flow

Transaction processing plays a very important role in the microservice architecture of various portals and e-commerce microservice architecture:

Transaction exists to ensure the integrity and accuracy of task execution. For example, it is necessary to illustrate the existence of transaction: when your task begins to execute, but due to node crash or network reasons, there is no way to successfully execute this operation. After receiving the signal of execution failure, the transaction will roll back to the previous safe state, so as to avoid pending This Schrodinger state is also an embodiment or implementation method of final consistency (of course, if we only set one transaction control center here, there is no need for strong synchronization of data in multiple transaction control centers)

When we design this framework, we intend to introduce the concept of transaction into our framework, and use the final consistency to process transactions

Functional unit life cycle

Of course, all functional entities should have a state machine, but due to space limitations, let's take a simple example. The life cycle state diagram of functional units is as follows

After the function unit is started, it first enters the initial state for initialization. If the initialization succeeds, it enters the prepared state. If the initialization fails and causes the function unit to crash, it enters the crash processing flow.

In the prepared state, the function unit automatically initiates registration to the master. If the registration succeeds, the status changes to registered. If the registration fails, the function unit enters unregistered.

The registered state directly enters the working state. In the working state, the heartbeat (or other mechanisms) will be sent regularly to ensure the connection with the master. In case of multiple disconnection, it will enter the unregistered state. At the same time, transactions are processed in the working state (omitted). If the program encounters an unsolvable crash during the transaction, it enters the crashed state.

In the crashed state, we need to reset the function unit to decide whether to stop or restart the function unit.

Unregistered status will automatically close the functional unit, because unregistered is a unit that marks the normal end of the functional unit.

In the previous topic, we didn't give much description about message queuing (Communication). Next, we will elaborate on the problem of node communication in the next topic.

Topic - Communication and message queuing

This part briefly discusses the relationship between the framework and message queue and the design of message queue.

Message queuing Foundation


Is message queuing really necessary for our penetration testing system? My personal answer is necessary.

Main features: solve service (module) communication problems

Communication is more than just "I send, you receive". From the overall architecture of this framework, it is a master / slaves architecture mode, that is to say, a master and multiple slaves communicate at the same time, of course, the types of communication are also diverse:

Secondary characteristics: reliability / safety

As for a reliable message queue, it has a complete set of mechanisms to ensure that messages are reliable from one end to the other. You don't have to worry about losing your messages in the process of communication / in the message queue (because of machine restart or other unexpected factors). Let's take rabbitmq as an example to illustrate some of rabbitmq's work on data reliability and consistency:

At the ConsumerIn the event of network failure (or a node crashing), messages can be duplicated, and consumers must be prepared to handle them. If possible, The simple way to handle this is to ensure that your consumers handle messages in an independent way rather than explicitly deal with duplication. If you want to solve this problem, the easiest way is to use idempotence (rather than deal with it directly).

If a message is delivered to a consumer and then requeued (because it was not acknowledged before the consumer connection dropped, for example) then RabbitMQ will set the redeliveredflag on it when it is delivered again (whether to the same consumer or a different one).... Conversely if the redelivered flag is not set then it is guaranteed that the message has not been seen before. Therefore if a consumer finds it more expensive to deduplicate messages or process them in an idempotent manner, It can do this only for messages with the redeliveredflag set Redeliveredflag, if so, your receiver will receive the message without ack again On the other hand, if the redelivered flag is not set, you can ensure that no duplicate message will be sent to your receiver. Therefore, we do not have to use idempotent method in the application business layer. We can simply use this feature of message queuing.

Model selection (programmable protocol - rabbitmq)

Here, we choose rabbitmq as our message queue support. Next, combining the characteristics of rabbitmq and our framework features, we can try to simply design the key message queue structure. In fact, for our rabbitmq, the design of message queue will also be quite pleasant. Our sender doesn't know the specific message queue of the receiver. In fact, message queue is only a concept existing in the receiver. At the sender, there is only the concept of switch and route. So we can use different kinds of switches to cooperate with the routing.


In rabbitmq, there are four types of switches:

According to these four types of switches, we can easily design our communication system. (when used in practice, we will not choose all)

Here is a brief description of several switches in turn:

Among them, task distribution and result collection belong to transaction (task) management service, and control / notification / feedback switch belongs to node (function unit) management service. In this way, management and business can be separated perfectly through message queuing.

The above describes some parts of a distributed penetration framework, but limited to space, we can not describe the design ideas of each part clearly. The author's ability is limited. If there is any mistake in the article, I hope the readers will give me some advice.

PS: Zhihu's editor somehow the particle state eats the tab of the list, resulting in a format bug in the list. I can't fix it after trying?