General Penetration Testing Approaches for AES+SM4 Encryption

General Penetration Testing Approaches for AES+SM4 Encryption

General Penetration Testing Approaches for AES+SM4 Encryption

Article originally published on: Zgao’s blog

General Penetration Testing Approaches for AES+SM4 Encryption

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:

General Penetration Testing Approaches for AES+SM4 Encryption

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
General Penetration Testing Approaches for AES+SM4 Encryption

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.

General Penetration Testing Approaches for AES+SM4 Encryption
General Penetration Testing Approaches for AES+SM4 Encryption

Practical Testing

General Penetration Testing Approaches for AES+SM4 Encryption

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

Leave a Comment