
Steal My Bitcoin चुनौती का एक सार्वजनिक रिलीज़
Steal My Bitcoin चैलेंज के विरुद्ध एक लाइव PHP कॉलबैक, शुरू से अंत तक, एक ही स्टैंडर्ड-लाइब्रेरी Python फ़ाइल में।
यह README stealmybitcoin_poc.py की व्याख्या करता है, जो मेरे Steal My Bitcoin CTF रन में उपयोग किए गए रिक्वेस्ट अनुक्रम का एकल-फ़ाइल Python पुनरुत्पादन है। यह केवल Python की स्टैंडर्ड लाइब्रेरी का उपयोग करता है। स्क्रिप्ट स्वयं रिक्वेस्ट बनाती है, आगे बढ़ने से पहले प्रत्येक लीक की जाँच करती है, और एक नए रन से HTTP बाइट्स रिकॉर्ड करती है।
यह शायद बिना सारे अतिरिक्त डीबग कचरे के और आसानी से किया जा सकता है, और जैसा कि मैंने Steam Local Privilege Escalation पर अपने John Hammond वीडियो में खोजा था, आप शायद इस बदसूरत PoC को साफ़ कर सकते हैं।
[!NOTE] ⚠️ ईमानदारी से कृपया इसे साफ़ करें या अपना बेहतर संस्करण बनाएं जो Sol द्वारा कुचला न गया हो। ⚠️
नीचे सब कुछ Docker लैब के विरुद्ध लिखा गया है, लाइव चैलेंज के विरुद्ध नहीं। लैब nginx के पीछे एक स्थानीय Alpine PHP 8.4.26 CLI सर्वर है, जो वही बिल्ड और वर्कर मॉडल है जिस पर ऑफ़सेट कैलिब्रेट किए गए थे। इसे एक मिनट में खड़ा करें और पूरी चेन आपकी अपनी मशीन पर शुरू से अंत तक चलती है। वह लाइव रन जिसने वास्तव में चैलेंज हल किया, उसे नीचे एक ऐतिहासिक नोट के रूप में रखा गया है।
stage what goes out what comes back
─────────────────────────────────────────────────────────────────────────────
0 health GET /php-version.php -> PHP 8.4.26 confirmed
1 heap leak 249,042 B producer + 8 x 6,672 B -> 256 B cookie
(OOM poisons a worker) └─ Zend chunk base
2 code leak 251,557 B producer + 8 x 92,388 B -> 16 B cookie
(OOM poisons a worker) └─ zval_ptr_dtor
3 callback 368,812 B POST -> forged HashTable runs
(fake HashTable + command) └─ zif_system(cmd)
─────────────────────────────────────────────────────────────────────────────
20 HTTP requests at most. No looping, no retries.
zif_system को कॉल करता है, जो system के लिए PHP का हैंडलर है।print-flag परिणाम उस कनेक्शन पर वापस भेजता है जो अभी भी खुला है।दो पते क्यों? OS यह यादृच्छिक करता है कि PHP का कोड और हीप कहाँ जमा होंगे, स्वतंत्र रूप से। हीप लीक स्क्रिप्ट को बताता है कि जाली संरचना कहाँ रखनी है, कोड लीक बताता है कि जिस फ़ंक्शन को कॉल करना है वह वास्तव में कहाँ रहता है। किसी पुराने वर्कर या पुराने रन के पते सुरक्षित विकल्प नहीं हैं, और हर बार जब मैंने इसे आज़माया तो प्रयास बस विफल हो गया।
इस PoC में ऑफ़सेट चार वर्कर के साथ अंतर्निहित CLI सर्वर चलाने वाले Alpine PHP 8.4.26 के लिए कैलिब्रेट किए गए हैं। लैब ठीक वही चीज़ loopback पर, nginx के पीछे पुनरुत्पादित करती है।
[!IMPORTANT] वर्ज़न स्ट्रिंग से अधिक बिल्ड मायने रखता है। एक Debian
php:8.4.26-fpmस्टैक वहीPHP/8.4.26रिपोर्ट करता है लेकिन उसका बाइनरी लेआउट अलग होता है, इसलिए कोड-पॉइंटर फ़िंगरप्रिंट कभी मेल नहीं खाएगा और रन कोड-लीक चरण पर निरस्त हो जाएगा। नीचे दी गई Alpine इमेज का उपयोग करें।
तीन छोटी फ़ाइलें। उन्हें एक खाली डायरेक्टरी में रखें:
public/php-version.php (हेल्थ एंडपॉइंट, और वह एकमात्र पेज जिसकी PoC को आवश्यकता है)
<?php
header('Content-Type: text/plain');
echo 'PHP ', PHP_VERSION, "\n";
echo 'PID: ', getmypid(), "\n";
print-flag (चैलेंज बाइनरी के लिए स्टैंड-इन, निष्पादन योग्य होना चाहिए)
#!/bin/sh
printf '%s\n' 'LOCAL_DUMMY_WIF_NEVER_USE'
nginx.conf
events {}
http {
server {
listen 80;
server_name _;
location / {
proxy_pass http://ctf-cross-php:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
}
}
}
फिर इसे शुरू करें:
docker network create ctf-cross-net
docker run -d --name ctf-cross-php --network ctf-cross-net \
--read-only --tmpfs /tmp:rw,size=32m,mode=1777 --memory 1g \
-v "$PWD/public:/app:ro" \
-v "$PWD/print-flag:/usr/local/bin/print-flag:ro" \
-e PHP_CLI_SERVER_WORKERS=4 \
php:8.4.26-fpm-alpine3.23 php -S 0.0.0.0:8000 -t /app
docker run -d --name ctf-cross-nginx --network ctf-cross-net \
-p 127.0.0.1:18166:80 \
-v "$PWD/nginx.conf:/etc/nginx/nginx.conf:ro" \
nginx:1.27-alpine
जाँचें:
$ curl -s http://127.0.0.1:18166/php-version.php
PHP 8.4.26
PID: 1
PID इस बात पर निर्भर करता है कि कौन सा worker उत्तर देता है, और यह ठीक है। version लाइन वह हिस्सा है जिसे PoC जाँचता है।
इसे docker rm -f ctf-cross-nginx ctf-cross-php && docker network rm ctf-cross-net से हटा दें।
[!TIP] Windows पर, उन
docker runकमांड्स को PowerShell से चलाएँ, या$PWDकोC:/labजैसे पूर्ण ड्राइव पथ से बदल दें। Git Bash में$PWDएक MSYS पथ जैसे/tmp/...में विस्तारित होता है, जिसे Docker Desktop अपने ही VM के अंदर हल करता है। तब bind mounts चुपचाप खाली डायरेक्टरीज़ बना देते हैं जहाँnginx.confऔरprint-flagहोने चाहिए, और कंटेनर टूटे हुए स्टार्ट होते हैं।
उस रेसिपी पर कुछ नोट्स। इमेज fpm टैग है लेकिन कंटेनर php -S चलाता है, इसलिए SAPI cli-server है, जिसके विरुद्ध calibration मापी गई थी। PHP_CLI_SERVER_WORKERS=4 वह है जो leak चरणों को race करने के लिए एक से अधिक worker देता है। मेरे अपने lab harness ने --cap-add SYS_PTRACE --security-opt seccomp=unconfined भी पास किया था ताकि यह workers से एक tracer अटैच कर सके; PoC स्वयं ऐसा कभी नहीं करता, इसलिए उन्हें ऊपर छोड़ दिया गया है।
Python 3.11 या नया, केवल standard library, इंस्टॉल करने के लिए कुछ नहीं:
python .\stealmybitcoin_poc.py --url http://127.0.0.1:18166/php-version.php
इसे बिना किसी आर्ग्युमेंट के चलाएँ और यह अपनी सहायता प्रिंट करके नेटवर्क को छुए बिना बाहर निकल जाता है।
एक अच्छा रन ऐसा दिखता है: