The False Oracle — Azure Functions Padding Oracle Issue

Introduction

Overview

On my previous Function Docker Escape post published in Intezer’s website, I described how I set up Azure Function so I could investigate its environment. In a nutshell, I hosted a reverse shell over the Function environment. After publishing that research, I continued exploring the Function environment and I noticed interesting environment variables such as CONTAINER_START_CONTEXT_SAS_URI which linked to a file in the azcontainers blob storage belonging to wawstorageproddm1157 — a storage account belonging to Microsoft.

  1. An attacker with code execution on an Azure Function is able to escalate privileges using the SCM_RUN_FROM_PACKAGE environment variable. This URL redirected to the Azure Function package but its SAS token had a ‘write’ permission (marked in blue), meaning it can be used to overwrite the Azure Function package. This meant an would have been able to overwrite the Function code package with their own code (Escalation of Privileges). If done thoughtfully, the user would not have noticed this change and the attacker would have been able to plant a backdoor which would have run in every Function invocation. This is the first vulnerability.
  2. The Azure Function had access to a storage blob belonging to ‘wasstorageproddm1157’ storage account, which belongs to Microsoft (marked in red).

Azure Padding Oracle

If you are unfamiliar with Padding Oracle attacks, I suggest going over this video, as it is too bit a lengthy subject for this blog post. However, in a nutshell, a padding oracle enables an attacker to decrypt any encrypted message passed to it provided it was encrypted with the matching key in the oracle server.

func init_server_pkg_encryption_pkcs7Unpad(data []byte) (byte[], error) {
// Check that last byte isn’t zero
if data[len(data)-1] != 0 {
// Check that last byte is bigger than message total length
data[len(data)-1] > len(data) {
return nil
}
}
return fmt.Errorf(“Padding is invalid”)
}
func Unpad(data []byte, blockSize uint) ([]byte, error) {
if blockSize < 1 {
return nil, fmt.Errorf(“Block size looks wrong”)
}
if uint(len(data))%blockSize != 0 {
return nil, fmt.Errorf(“Data isn’t aligned to blockSize”)
}
if len(data) == 0 {
return nil, fmt.Errorf(“Data is empty”)
}
paddingLength := int(data[len(data)-1])
for _, el := range data[len(data)-paddingLength:] {
if el != byte(paddingLength) {
return nil, fmt.Errorf(“Padding had malformed entries. Have ‘%x’, expected ‘%x’”, paddingLength, el)
}
}
return data[:len(data)-paddingLength], nil
}

Afterword

To summarize my findings, I discovered an escalation of privileges vulnerability in Linux Azure Function instances and information disclosure through being able to download arbitrary Functions’ encrypted configuration. I hoped to use the Padding Oracle to mount a crypto attack and decrypt this configuration, however I soon found out that the padding algorithm was flawed. The attack still required matching the oracle (the Function url) to its configuration which probably would have limited the impact of the attack should I have been successful.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store