General Penetration Testing Approaches for AES+SM4 Encryption
Article originally published on: Zgao’s blog

In a recent penetration testing project, the website’s traffic utilized the AES+SM4 dual-layer encryption algorithm for secure transmission. When encountering a website with encrypted transmission, it is usually impossible to perform vulnerability scanning. Manual testing is inefficient, hence the exploration of general penetration testing solutions under encrypted transmission scenarios.
How to Encrypt and Decrypt Transmission Traffic?
There are typically two methods to achieve this.
Reimplementing the Encryption and Decryption Algorithm in Python
If the website’s encryption algorithm is a standard such as AES, it can be implemented natively using Python’s pycrypto module. For relatively simple encryption algorithms, one can also extract the encryption and decryption code from JavaScript and execute it in Python using execJs to get results.
For example, the manual implementation of the website’s encryption and decryption code in Python is as follows:

This method can only implement simple encryption algorithms and requires writing code, which can be relatively cumbersome.
JSRPC Forwarding of Encryption and Decryption Functions
When encountering complex encryption and decryption algorithms, such as those that are modified versions of standard algorithms, it may not be possible to extract key code from JavaScript. In such cases, the jsrpc method is very suitable for directly invoking the encryption and decryption functions in the browser.
https://github.com/jxhczhl/JsRpc

Since the website’s transmission content is encrypted, it is necessary to decrypt the traffic before it enters the passive scanner.
Using Mitmproxy for Traffic Encryption and Decryption
Mitmproxy is a proxy used for Man-in-the-Middle (MITM) attacks. A proxy for MITM will forward requests like a normal proxy while also inspecting and recording the intercepted data or modifying it to trigger specific behaviors on the server or client. Unlike packet capture tools such as Fiddler or Wireshark, Mitmproxy not only intercepts requests to assist developers in viewing and analyzing but also allows for secondary development through custom scripts.
As mentioned earlier, Python can be used to reimplement the encryption and decryption algorithms, but before the traffic reaches the passive scanner, a man-in-the-middle is needed to perform the encryption and decryption operations, and Mitmproxy serves this role. The Python code for encryption and decryption can be run in Mitmproxy, and by installing a trusted Mitmproxy certificate in the system, Mitmproxy can decrypt HTTPS traffic before performing secondary decryption.
Mitmproxy Command Line
The first Mitmproxy command line needs to set the upstream proxy to the IP and port that Xray is listening on.
mitmdump -s code.py -p 8010 --set block_global=false --mode upstream:http://xray-ip:port --ssl-insecure
The second Mitmproxy command line is for directly forwarding to the target website.
mitmdump -s code.py -p 8020 --set block_global=false --ssl-insecure
Mitmproxy Code Template
Since the process involves four instances of Mitmproxy for encryption and decryption, two Mitmproxy listening ports need to be opened to forward traffic.
First Traffic Encryption and Decryption Code Template
from mitmproxy import http
# The encryption and decryption functions can be reimplemented in Python or forwarded directly using jsrpc
# Decryption function
def myEncrypt(data): pass
# Decryption function
def myDecrypt(data): pass
# Decrypting the request content from the browser and forwarding to the scanner
def request(flow: http.HTTPFlow) -> None: if flow.request.pretty_host != "target.com": return # If not the target domain, forward without any operation try: param = flow.request.content.decode() decryptData = myDecrypt(param)
print("First request decryption:\n"+decryptData)
# Replace the encrypted message with the decrypted message flow.request.content = decryptData
except Exception as e: print(f"Message decryption failed: {e}")
# Encrypting the response content from the scanner and forwarding to the browser
def response(flow: http.HTTPFlow) -> None: if flow.request.pretty_host != "target.com": return # If not the target domain, forward without any operation try: param = flow.response.content.decode() encryptData = myEncrypt(param)
print("First response encryption:\n" + encryptData)
# Replace the plaintext message with the encrypted message flow.response.content = encryptData
except Exception as e: print(f"Message encryption failed: {e}")
Second Traffic Encryption and Decryption Code Template
from mitmproxy import http
# The encryption and decryption functions can be reimplemented in Python or forwarded directly using jsrpc
# Decryption function
def myEncrypt(data): pass
# Decryption function
def myDecrypt(data): pass
# Encrypting the request content from the scanner and forwarding to the website
def request(flow: http.HTTPFlow) -> None: if flow.request.pretty_host != "target.com": return # If not the target domain, forward without any operation try: param = flow.request.content.decode() encryptData = myEncrypt(param)
print("Second request encryption:\n" + encryptData)
# Replace the plaintext message with the encrypted message flow.request.content = encryptData
except Exception as e: print(f"Message encryption failed: {e}")
# Decrypting the response content from the website and forwarding to the scanner
def response(flow: http.HTTPFlow) -> None: if flow.response.pretty_host != "target.com": return # If not the target domain, forward without any operation try: param = flow.response.content.decode() decryptData = myDecrypt(param)
print("Second request decryption:\n"+decryptData)
# Replace the encrypted message with the plaintext message flow.response.content = decryptData
except Exception as e: print(f"Message decryption failed: {e}")
Modifying Xray Configuration
Since Mitmproxy is performing encryption and decryption on both sides of Xray, only the upstream proxy needs to be configured in Xray. However, two configurations need to be modified, both http and upstream_proxy should be changed to Mitmproxy’s IP and port.


Practical Testing

Although the penetration testing process under encrypted transmission scenarios is relatively complex, the traffic itself is encrypted, and WAF cannot intercept it, which saves some trouble.
In practice, using the Mitmproxy template I provided above and replacing the encryption and decryption functions allows for direct vulnerability scanning of websites with encrypted transmission. That’s it!
The technologies, ideas, and tools discussed in articles published or reposted by Heibai Zhidao are for educational exchange purposes only, and should not be used for illegal or profit-making purposes. Otherwise, the consequences will be borne by the individual!
If there is any infringement, please contact us to delete the article.
END