First, we need to write a simple Python script, and then look at which components are involved when executing commands in the system, and output the output in the form of a QR code image. Next, we also need to write another small script to read in this picture and display the result in the terminal console. We can scan this QR code directly on the mobile phone, and then we can see that the Windows directory is output.
The following is an example of a QR code:
Very good, you can see the results after scanning. So in theory, this method should also be able to establish a direct connection between the agent and the C2 server. Therefore, I decided to continue to use Python as the web server, and then use Flask to process the request parameters. The reason why I chose to use Python here is mainly to support running on multiple operating system platforms.
Next, we also need to design how to achieve data exchange. At the beginning, I planned to use the QR code to send commands from the C2 server and return the output through the proxy. Here, I studied the technology used by third-party image providers, and they all seem to use POST requests to upload images. If I submit as many pictures to Imgur as I receive, it may cause the blue team to be suspicious. Therefore, I just want to find a way to request only with GET, and encrypt it with HTTPS, so that no one can see my URI or request body. For data integrity considerations, the commands we need to execute will still be read by the agent in the form of a QR code, and the data will be encoded in Base64. In addition, the returned data must also be of the image type, because the third-party image service only regards images as a valid content type.
Below is the interface where we search for Google images by URL, here we use the web path of “img.png”:
The following figure shows the response message with a QR code picture returned by the server:
The request content captured in Burp is as follows, which contains the complete URL address pointing to the C2 server:
In order to facilitate your study and research, I have completed the code of the C2 listener and the server-side script code that interacts with the listener and the underlying SQLite database. If necessary, you can visit my GitHub repository to directly obtain [Portal]. However, I do not recommend that you use them in real scenarios, because they do cause certain security issues. The script can correctly accept the command and complete the work as expected, and can allow the user to interact with the newly added agent, and then directly execute the received terminal command and display the execution result. When we send a new command to the proxy server, our request will be Base64 encoded and converted into a QR code image, and this QR code image is hosted by the listener under a virtual path “img.png”. This can bypass the restrictions of third-party services (such as Google Images) to ensure that in addition to valid content types, valid image extensions can also be used.
I researched the commands and functions in the database repeatedly to make sure it worked as expected. Next, we need to create an agent. This proxy was originally built for direct connection, and I also added support for Google Images and Imgflip. At the time of writing this article, I have not added support for Imgur, but it is simpler than Google Images. The agent can send a ping request to an image and provide a “agent ID” with other parameters as the path. After receiving the parameters, the Flask server will update the database to display the new agent and check its validity. Then, the server will check if the agent has received the command to be executed, and if so, it will display the QR code image previously created in the previous paragraph. Once it is accessed, the QR code will be deleted, so if the same request is repeated again, everyone will see the avatar of Worker Smith in the matrix.
If the command needs to be sent back to the C2 service after execution, it will send basically the same request as the received beacon, but this time it will add the output of the command as a Base64 encoded value to the GET parameter named “response”. The C2 server will receive and decode the request information, and then display it to the user’s terminal console. I have added a random time interval between 1 and 10 seconds to the beacon here to reduce its suspiciousness.
So far, the C2 and steganographic transmission methods are working properly, but I also want to add a redirection component. I know that Google Images will be trickier here because they require cookies and other valid HTTP headers. Here, the response will also be redirected to another call, and the HTML content of the result of the image search also needs to be parsed, so that the image returned by the C2 server can be found. Therefore, we need to add a random value to modify the cache, otherwise Google will only return the image from the previous call.
The following figure shows the four-time image redirection method for C2 channel:
The following figure shows the TLSv1.3 traffic between the proxy and the Google Image server:
Finally, I want to say that this technology is basically suspiciously applicable to any online service, such as Twitter, LinkedIn, and Slack. Researchers can also modify the script code according to their needs, and publish a “picture”, using this picture can send a request like a C2 server. When the picture is opened, it will become a QR code picture with commands.